From 50187c4539f9913a2a4fffb91ab01ed61f296fa1 Mon Sep 17 00:00:00 2001 From: Martin Mares Date: Sat, 11 Aug 2018 15:57:51 +0200 Subject: [PATCH] SSR MQTT: Gateway works, still need USB error handling & logging --- ssr/turris/burrow-ssrd.c | 104 +++++++++++++++++++++++++++++++++------ 1 file changed, 89 insertions(+), 15 deletions(-) diff --git a/ssr/turris/burrow-ssrd.c b/ssr/turris/burrow-ssrd.c index 6d15e36..8132225 100644 --- a/ssr/turris/burrow-ssrd.c +++ b/ssr/turris/burrow-ssrd.c @@ -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 */ @@ -7,12 +7,13 @@ #include #include #include +#include #include +#include #include #include #include -#include #include #include @@ -21,6 +22,10 @@ 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); } } -- 2.39.2