X-Git-Url: http://mj.ucw.cz/gitweb/?a=blobdiff_plain;ds=inline;f=prometheus%2Fburrow-prometheus.c;h=0e760e737728bdf714d14903461499cb0918a53d;hb=fef910220f1ee04d6a572996bcc11ce7715b04d5;hp=fddc806c5d5caf5fcadf45adaa75402c5e4957bf;hpb=0a8ffabffaed625e624be35a24b62e27389843f1;p=home-hw.git diff --git a/prometheus/burrow-prometheus.c b/prometheus/burrow-prometheus.c index fddc806..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,6 +25,8 @@ #include +#define MEASUREMENT_TIMEOUT 120 + static struct mosquitto *mosq; struct attr { @@ -39,7 +41,7 @@ static const struct attr attr_table[] = { .metric = "temp_loft", .help = "Temperature in the loft [degC]", .type = "gauge", - .topic = "burrow/loft/temperature" + .topic = "burrow/temp/loft", }, { .metric = "loft_fan", @@ -57,31 +59,157 @@ static const struct attr attr_table[] = { .metric = "temp_ursarium", .help = "Temperature in the Ursarium [degC]", .type = "gauge", - .topic = "burrow/arexxd/ursarium" + .topic = "burrow/temp/ursarium" }, { .metric = "temp_catarium", .help = "Temperature in the Catarium [degC]", .type = "gauge", - .topic = "burrow/arexxd/catarium" + .topic = "burrow/temp/catarium" }, { .metric = "temp_garage", .help = "Temperature in the garage [degC]", .type = "gauge", - .topic = "burrow/arexxd/garage" + .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 = "temp_machinarium", - .help = "Temperature in the Machinarium [degC]", + .metric = "pm_reactive_power", + .help = "Total reactive power [VAr]", .type = "gauge", - .topic = "burrow/arexxd/machinarium" + .topic = "burrow/power/reactive/power", }, { - .metric = "rh_garage", - .help = "Relative humidity in the garage [%]", + .metric = "pm_reactive_energy", + .help = "Total reactive energy [kVArh]", .type = "gauge", - .topic = "burrow/arexxd/garage-rh" + .topic = "burrow/power/reactive/energy", }, }; @@ -106,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"); } } @@ -234,20 +362,40 @@ static bool http_get_line(struct http *http) static void http_answer(struct fastbuf *fb) { - char val[256]; + 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 (val[0]) { - const struct attr *a = &attr_table[i]; - 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); - // FIXME: Add timestamp if known - bprintf(fb, "%s %s\n", a->metric, val); + + 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'); } } } @@ -293,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"), @@ -325,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");