]> mj.ucw.cz Git - home-hw.git/commitdiff
SSR MQTT: Gateway works, still need USB error handling & logging
authorMartin Mares <mj@ucw.cz>
Sat, 11 Aug 2018 13:57:51 +0000 (15:57 +0200)
committerMartin Mares <mj@ucw.cz>
Sat, 11 Aug 2018 13:57:51 +0000 (15:57 +0200)
ssr/turris/burrow-ssrd.c

index 6d15e36714684997e8d75c8ae01aec290ac5ffd0..8132225510704c53f932af3117f3713259f11382 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *     A Control Daemon for the Solid State Relay module
+ *     A MQTT Gateway Daemon for the Solid State Relay module
  *
  *     (c) 2018 Martin Mares <mj@ucw.cz>
  */
@@ -7,12 +7,13 @@
 #include <ucw/lib.h>
 #include <ucw/mainloop.h>
 #include <ucw/opt.h>
+#include <ucw/strtonum.h>
 #include <ucw/unaligned.h>
 
+#include <stdarg.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <unistd.h>
 #include <time.h>
 
 #include <libusb-1.0/libusb.h>
 struct libusb_context *usb_ctxt;
 struct libusb_device_handle *devh;
 
+struct mosquitto *mosq;
+
+static u32 ssr_state;
+
 void open_device(void)
 {
        int err;
@@ -78,9 +83,79 @@ static int transaction(uint req_len, uint resp_len)
        return received;
 }
 
+static void set_relays(void)
+{
+       msg(L_INFO, "Setting relays to %02x", ssr_state);
+       put_u32_be(req, 1);
+       put_u32_be(req+4, ssr_state);
+       transaction(8, 4);
+}
+
+static void mqtt_publish(const char *topic, const char *fmt, ...)
+{
+       va_list args;
+       va_start(args, fmt);
+       char m[256];
+       int l = vsnprintf(m, sizeof(m), fmt, args);
+       if (mosquitto_publish(mosq, NULL, topic, l, m, 0, true) != MOSQ_ERR_SUCCESS)
+               msg(L_ERROR, "Mosquitto: publish failed");
+       va_end(args);
+}
+
+static void mqtt_log_callback(struct mosquitto *mosq UNUSED, void *obj UNUSED, int level, const char *message)
+{
+       // msg(L_INFO, "MQTT(%d): %s", level, message);
+}
+
+static void mqtt_msg_callback(struct mosquitto *mosq UNUSED, void *obj UNUSED, const struct mosquitto_message *m)
+{
+       char val[256];
+       if (m->payloadlen >= sizeof(val) - 1) {
+               msg(L_ERROR, "Invalid value for topic %s", m->topic);
+               return;
+       }
+       memcpy(val, m->payload, m->payloadlen);
+       val[m->payloadlen] = 0;
+       msg(L_INFO, "MQTT < %s %s", m->topic, val);
+
+       if (!strcmp(m->topic, "burrow/loft/fan")) {
+               uint x;
+               const char *err;
+               if ((err = str_to_uint(&x, val, NULL, 10 | STN_WHOLE)) || x >= 4) {
+                       msg(L_ERROR, "Received invalid fan setting %s: %s", val, err);
+                       x = 0;
+               }
+               msg(L_INFO, "Setting fan level to %u", x);
+               ssr_state &= ~7U;
+               switch (x) {
+                       case 1:
+                               ssr_state |= 4;
+                               break;
+                       case 2:
+                               ssr_state |= 2;
+                               break;
+                       case 3:
+                               ssr_state |= 1;
+                               break;
+               }
+               set_relays();
+       } else if (!strcmp(m->topic, "burrow/loft/circulation")) {
+               uint x;
+               const char *err;
+               if ((err = str_to_uint(&x, val, NULL, 10 | STN_WHOLE)) || x >= 2) {
+                       msg(L_ERROR, "Received invalid circulation setting %s: %s", val, err);
+                       x = 0;
+               }
+               msg(L_INFO, "Setting circulation to %u", x);
+               ssr_state &= ~8U;
+               if (x)
+                       ssr_state |= 8;
+       }
+}
+
 static struct opt_section options = {
        OPT_ITEMS {
-               OPT_HELP("A daemon for controlling the solid state relay module"),
+               OPT_HELP("A daemon for controlling the solid state relay module via MQTT"),
                OPT_HELP(""),
                OPT_HELP("Options:"),
                OPT_HELP_OPTION,
@@ -98,20 +173,26 @@ int main(int argc UNUSED, char **argv)
                die("Cannot initialize libusb: error %d", err);
        libusb_set_debug(usb_ctxt, 3);
        open_device();
+       set_relays();
 
        mosquitto_lib_init();
-       struct mosquitto *mosq = mosquitto_new("ssrd", 1, NULL);
+       mosq = mosquitto_new("ssrd", 1, NULL);
        if (!mosq)
                die("Mosquitto: initialization failed");
 
+       mosquitto_log_callback_set(mosq, mqtt_log_callback);
+       mosquitto_message_callback_set(mosq, mqtt_msg_callback);
+
        if (mosquitto_will_set(mosq, "burrow/loft/status", 4, "dead", 0, true) != MOSQ_ERR_SUCCESS)
                die("Mosquitto: unable to set will");
 
        if (mosquitto_connect(mosq, "127.0.0.1", 1883, 60) != MOSQ_ERR_SUCCESS)
                die("Mosquitto: connect failed");
 
-       if (mosquitto_publish(mosq, NULL, "burrow/loft/status", 2, "ok", 0, true) != MOSQ_ERR_SUCCESS)
-               msg(L_ERROR, "Mosquitto: publish failed");
+       if (mosquitto_subscribe(mosq, NULL, "burrow/loft/#", 1) != MOSQ_ERR_SUCCESS)
+               die("Mosquitto: subscribe failed");
+
+       mqtt_publish("burrow/loft/status", "ok");
 
        time_t next_run = 0;
        for (;;) {
@@ -130,14 +211,7 @@ int main(int argc UNUSED, char **argv)
                int t = get_u32_be(resp+4);
                msg(L_DEBUG, "Measured raw temperature %d", t);
 
-               byte mbuf[16];
-               int mlen = snprintf(mbuf, sizeof(mbuf), "%.3f", t / 1000.);
-               if (mosquitto_publish(mosq, NULL, "burrow/loft/temperature", mlen, mbuf, 0, true) != MOSQ_ERR_SUCCESS)
-                       msg(L_ERROR, "Mosquitto: publish failed");
-
-               byte tbuf[16];
-               int tlen = snprintf(tbuf, sizeof(tbuf), "%u", (int) now);
-               if (mosquitto_publish(mosq, NULL, "burrow/loft/timestamp", tlen, tbuf, 0, true) != MOSQ_ERR_SUCCESS)
-                       msg(L_ERROR, "Mosquitto: publish failed");
+               mqtt_publish("burrow/loft/temperature", "%.3f", t / 1000.);
+               mqtt_publish("burrow/loft/timestamp", "%u", (int) now);
        }
 }