]> mj.ucw.cz Git - home-hw.git/blobdiff - prometheus/burrow-prometheus.c
Merge branch 'master' of ssh://git.ucw.cz/home/mj/GIT/home-hw
[home-hw.git] / prometheus / burrow-prometheus.c
index fddc806c5d5caf5fcadf45adaa75402c5e4957bf..0e760e737728bdf714d14903461499cb0918a53d 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *     A gateway between MQTT and Prometheus
  *
 /*
  *     A gateway between MQTT and Prometheus
  *
- *     (c) 2018 Martin Mares <mj@ucw.cz>
+ *     (c) 2018--2019 Martin Mares <mj@ucw.cz>
  */
 
 #include <ucw/lib.h>
  */
 
 #include <ucw/lib.h>
@@ -25,6 +25,8 @@
 
 #include <mosquitto.h>
 
 
 #include <mosquitto.h>
 
+#define MEASUREMENT_TIMEOUT 120
+
 static struct mosquitto *mosq;
 
 struct attr {
 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",
                .metric = "temp_loft",
                .help = "Temperature in the loft [degC]",
                .type = "gauge",
-               .topic = "burrow/loft/temperature"
+               .topic = "burrow/temp/loft",
        },
        {
                .metric = "loft_fan",
        },
        {
                .metric = "loft_fan",
@@ -57,31 +59,157 @@ static const struct attr attr_table[] = {
                .metric = "temp_ursarium",
                .help = "Temperature in the Ursarium [degC]",
                .type = "gauge",
                .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",
        },
        {
                .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",
        },
        {
                .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",
                .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",
                .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");
 
                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)
 {
 
 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++) {
 
        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);
                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 {
 
 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"),
                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);
 
        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");
                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");
 
        if (mosquitto_connect_async(mosq, "10.32.184.5", 1883, 60) != MOSQ_ERR_SUCCESS)
                die("Mosquitto: connect failed");