X-Git-Url: http://mj.ucw.cz/gitweb/?a=blobdiff_plain;f=prometheus%2Fburrow-prometheus.c;h=0e760e737728bdf714d14903461499cb0918a53d;hb=228f98a7bea12a3cc18aab18f50951d3256bc5fe;hp=9cab56eaa192e5f7058dbed85ed88c964d13d8c9;hpb=a7de3e719f4786a75010d0fdc02502048cf6a918;p=home-hw.git diff --git a/prometheus/burrow-prometheus.c b/prometheus/burrow-prometheus.c index 9cab56e..0e760e7 100644 --- a/prometheus/burrow-prometheus.c +++ b/prometheus/burrow-prometheus.c @@ -1,7 +1,7 @@ /* * A gateway between MQTT and Prometheus * - * (c) 2018 Martin Mares + * (c) 2018--2019 Martin Mares */ #include @@ -25,35 +25,192 @@ #include +#define MEASUREMENT_TIMEOUT 120 + static struct mosquitto *mosq; struct attr { - const char *pm; + const char *metric; + const char *help; + const char *type; const char *topic; }; static const struct attr attr_table[] = { - { "# HELP temp_loft Temperature in the loft [degC]", NULL }, - { "# TYPE temp_loft gauge", NULL }, - { "temp_loft", "burrow/loft/temperature" }, - { "# HELP loft_fan Fan speed in the loft", NULL }, - { "# TYPE loft_fan gauge", NULL }, - { "loft_fan", "burrow/loft/fan" }, - { "# HELP temp_ursarium Temperature in the Ursarium [degC]", NULL }, - { "# TYPE temp_ursarium gauge", NULL }, - { "temp_ursarium", "burrow/arexxd/ursarium" }, - { "# HELP temp_catarium Temperature in the Catarium [degC]", NULL }, - { "# TYPE temp_catarium gauge", NULL }, - { "temp_catarium", "burrow/arexxd/catarium" }, - { "# HELP temp_machinarium Temperature in the Machinarium [degC]", NULL }, - { "# TYPE temp_machinarium gauge", NULL }, - { "temp_machinarium", "burrow/arexxd/machinarium" }, - { "# HELP temp_garage Temperature in the garage [degC]", NULL }, - { "# TYPE temp_garage gauge", NULL }, - { "temp_garage", "burrow/arexxd/garage" }, - { "# HELP rh_garage Relative humidity in the garage [%]", NULL }, - { "# TYPE rh_garage gauge", NULL }, - { "rh_garage", "burrow/arexxd/garage-rh" }, + { + .metric = "temp_loft", + .help = "Temperature in the loft [degC]", + .type = "gauge", + .topic = "burrow/temp/loft", + }, + { + .metric = "loft_fan", + .help = "Fan speed in the loft (0-3)", + .type = "gauge", + .topic = "burrow/loft/fan" + }, + { + .metric = "loft_circ", + .help = "Warm water circulation (0-1)", + .type = "gauge", + .topic = "burrow/loft/circulation" + }, + { + .metric = "temp_ursarium", + .help = "Temperature in the Ursarium [degC]", + .type = "gauge", + .topic = "burrow/temp/ursarium" + }, + { + .metric = "temp_catarium", + .help = "Temperature in the Catarium [degC]", + .type = "gauge", + .topic = "burrow/temp/catarium" + }, + { + .metric = "temp_garage", + .help = "Temperature in the garage [degC]", + .type = "gauge", + .topic = "burrow/temp/garage" + }, + { + .metric = "temp_kitchen", + .help = "Temperature in the kitchen [degC]", + .type = "gauge", + .topic = "burrow/temp/kitchen" + }, + { + .metric = "rh_ursarium", + .help = "Relative humidity in the Ursarium [%]", + .type = "gauge", + .topic = "burrow/temp/ursarium-rh" + }, + { + .metric = "temp_catarium_clock", + .help = "Temperature on Catarium clock [degC]", + .type = "gauge", + .topic = "burrow/temp/clock" + }, + { + .metric = "press_catarium_clock", + .help = "Pressure on Catarium clock [Pa]", + .type = "gauge", + .topic = "burrow/pressure/clock" + }, + { + .metric = "air_inside_intake", + .help = "Temperature of air intake from inside [degC]", + .type = "gauge", + .topic = "burrow/air/inside-intake", + }, + { + .metric = "air_inside_exhaust", + .help = "Temperature of air exhaust to inside [degC]", + .type = "gauge", + .topic = "burrow/air/inside-exhaust", + }, + { + .metric = "air_outside_intake", + .help = "Temperature of air intake from outside [degC]", + .type = "gauge", + .topic = "burrow/air/outside-intake", + }, + { + .metric = "air_outside_exhaust", + .help = "Temperature of air exhaust to outside [degC]", + .type = "gauge", + .topic = "burrow/air/outside-exhaust", + }, + { + .metric = "air_mixed", + .help = "Temperature of mixed air [degC]", + .type = "gauge", + .topic = "burrow/air/mixed", + }, + { + .metric = "air_inside_intake_avg", + .help = "Average temperature of air intake from inside [degC]", + .type = "gauge", + .topic = "burrow/avg/air/inside-intake", + }, + { + .metric = "air_outside_intake_avg", + .help = "Average temperature of air intake from outside [degC]", + .type = "gauge", + .topic = "burrow/avg/air/outside-intake", + }, + { + .metric = "air_bypass", + .help = "Heat exchanger bypass (0-1)", + .type = "gauge", + .topic = "burrow/air/bypass" + }, + { + .metric = "air_fan_pwm", + .help = "Heat exchanger fan PWM (0-255)", + .type = "gauge", + .topic = "burrow/air/exchanger-fan" + }, + { + // Common heading for all voltages + .metric = "pm_voltage", + .help = "Voltage between phases and neutral [V]", + .type = "gauge", + }, + { + .metric = "pm_voltage{phase=\"L1N\"}", + .topic = "burrow/power/voltage/l1n", + }, + { + .metric = "pm_voltage{phase=\"L2N\"}", + .topic = "burrow/power/voltage/l2n", + }, + { + .metric = "pm_voltage{phase=\"L3N\"}", + .topic = "burrow/power/voltage/l3n", + }, + { + // Common heading for all currents + .metric = "pm_current", + .help = "Current through phases [A]", + .type = "gauge", + }, + { + .metric = "pm_current{phase=\"L1\"}", + .topic = "burrow/power/current/l1", + }, + { + .metric = "pm_current{phase=\"L2\"}", + .topic = "burrow/power/current/l2", + }, + { + .metric = "pm_current{phase=\"L3\"}", + .topic = "burrow/power/current/l3", + }, + { + .metric = "pm_power", + .help = "Total power [W]", + .type = "gauge", + .topic = "burrow/power/power", + }, + { + .metric = "pm_energy", + .help = "Total energy [kWh]", + .type = "gauge", + .topic = "burrow/power/energy", + }, + { + .metric = "pm_reactive_power", + .help = "Total reactive power [VAr]", + .type = "gauge", + .topic = "burrow/power/reactive/power", + }, + { + .metric = "pm_reactive_energy", + .help = "Total reactive energy [kVArh]", + .type = "gauge", + .topic = "burrow/power/reactive/energy", + }, }; static char *attr_values[ARRAY_SIZE(attr_table)]; @@ -77,7 +234,7 @@ static void mqtt_conn_callback(struct mosquitto *mosq UNUSED, void *obj UNUSED, if (mosquitto_subscribe(mosq, NULL, "burrow/#", 1) != MOSQ_ERR_SUCCESS) die("Mosquitto: subscribe failed"); - // mqtt_publish("burrow/loft/status", "ok"); + mqtt_publish("status/prometheus", "ok"); } } @@ -203,6 +360,46 @@ static bool http_get_line(struct http *http) } } +static void http_answer(struct fastbuf *fb) +{ + char val[256], *w[2]; + time_t now = time(NULL); + + for (uint i=0; i < ARRAY_SIZE(attr_table); i++) { + const struct attr *a = &attr_table[i]; + + pthread_mutex_lock(&attr_mutex); + snprintf(val, sizeof(val), "%s", attr_values[i] ? : ""); + pthread_mutex_unlock(&attr_mutex); + + if (a->help) + bprintf(fb, "# HELP %s %s\n", a->metric, a->help); + if (a->type) + bprintf(fb, "# TYPE %s %s\n", a->metric, a->type); + + if (!val[0]) + continue; + int fields = str_wordsplit(val, w, ARRAY_SIZE(w)); + if (fields < 1) + continue; + if (fields >= 2) { + time_t t = atoll(w[1]); + if (t < now - MEASUREMENT_TIMEOUT) + continue; + } + + if (a->topic) { + bprintf(fb, "%s %s", a->metric, val); +#if 0 + // Prometheus does not like our timestamps -- why? + if (fields >= 2) + bprintf(fb, " %s", w[1]); +#endif + bputc(fb, '\n'); + } + } +} + static void http_connection(struct http *http) { http->iobuf = mp_alloc(http->mp, IOBUF_SIZE); @@ -235,15 +432,7 @@ static void http_connection(struct http *http) bprintf(fb, "HTTP/1.1 200 OK\r\n"); bprintf(fb, "Content-type: text/plain; version=0.0.4\r\n"); bprintf(fb, "\r\n"); - for (uint i=0; i < ARRAY_SIZE(attr_table); i++) { - if (attr_table[i].topic) { - pthread_mutex_lock(&attr_mutex); - bprintf(fb, "%s %s\n", attr_table[i].pm, attr_values[i] ? : ""); - pthread_mutex_unlock(&attr_mutex); - } else { - bprintf(fb, "%s\n", attr_table[i].pm); - } - } + http_answer(fb); http_send(http); } @@ -252,7 +441,7 @@ static int use_debug; static struct opt_section options = { OPT_ITEMS { - OPT_HELP("A daemon for controlling the solid state relay module via MQTT"), + OPT_HELP("A daemon for transferring MQTT data to Prometheus"), OPT_HELP(""), OPT_HELP("Options:"), OPT_BOOL('d', "debug", use_debug, 0, "\tLog debugging messages"), @@ -284,11 +473,8 @@ int main(int argc UNUSED, char **argv) mosquitto_log_callback_set(mosq, mqtt_log_callback); mosquitto_message_callback_set(mosq, mqtt_msg_callback); -#if 0 - // FIXME: Publish online/offline status - if (mosquitto_will_set(mosq, "burrow/loft/status", 4, "dead", 0, true) != MOSQ_ERR_SUCCESS) + if (mosquitto_will_set(mosq, "status/prometheus", 4, "dead", 0, true) != MOSQ_ERR_SUCCESS) die("Mosquitto: unable to set will"); -#endif if (mosquitto_connect_async(mosq, "10.32.184.5", 1883, 60) != MOSQ_ERR_SUCCESS) die("Mosquitto: connect failed");