]> mj.ucw.cz Git - home-hw.git/commitdiff
SSR: Rudiments of MQTT <-> SSR gateway
authorMartin Mares <mj@ucw.cz>
Sat, 11 Aug 2018 13:14:58 +0000 (15:14 +0200)
committerMartin Mares <mj@ucw.cz>
Sat, 11 Aug 2018 13:14:58 +0000 (15:14 +0200)
ssr/turris/Makefile
ssr/turris/burrow-ssrd.c [new file with mode: 0644]

index dd71f4a8ab8380023045b5a543c602c04b28f214..35bccce01efdfb20a8d1d5499e106bb0cc6bfa1a 100644 (file)
@@ -13,13 +13,14 @@ export PATH=$(TARGET_PATH_PKG)
 CC=$(TARGET_CC_NOCACHE)
 LD=$(TARGET_LD_NOCACHE)
 CFLAGS=$(TARGET_CFLAGS) $(USB_CFLAGS) $(UCW_CFLAGS) -std=gnu99
-LDFLAGS=$(TARGET_LDFLAGS) $(USB_LDFLAGS) $(UCW_LDFLAGS)
+LDFLAGS=$(TARGET_LDFLAGS) $(USB_LDFLAGS) $(UCW_LDFLAGS) -lmosquitto
 
-all: ssr-control upload
+all: ssr-control burrow-ssrd upload
 
 ssr-control: ssr-control.c
+burrow-ssrd: burrow-ssrd.c
 
 upload:
-       rsync -av ssr-control micac:
+       rsync -av ssr-control burrow-ssrd micac:
 
 .PHONY: upload
diff --git a/ssr/turris/burrow-ssrd.c b/ssr/turris/burrow-ssrd.c
new file mode 100644 (file)
index 0000000..6d15e36
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+ *     A Control Daemon for the Solid State Relay module
+ *
+ *     (c) 2018 Martin Mares <mj@ucw.cz>
+ */
+
+#include <ucw/lib.h>
+#include <ucw/mainloop.h>
+#include <ucw/opt.h>
+#include <ucw/unaligned.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <time.h>
+
+#include <libusb-1.0/libusb.h>
+#include <mosquitto.h>
+
+struct libusb_context *usb_ctxt;
+struct libusb_device_handle *devh;
+
+void open_device(void)
+{
+       int err;
+       libusb_device **devlist;
+       ssize_t devn = libusb_get_device_list(usb_ctxt, &devlist);
+       if (devn < 0)
+               die("Cannot enumerate USB devices: error %d", (int) devn);
+
+       for (ssize_t i=0; i<devn; i++) {
+               struct libusb_device_descriptor desc;
+               libusb_device *dev = devlist[i];
+               if (!libusb_get_device_descriptor(dev, &desc)) {
+                       if (desc.idVendor == 0x4242 && desc.idProduct == 0x0002) {
+                               msg(L_INFO, "Found SSR module at usb%d.%d\n", libusb_get_bus_number(dev), libusb_get_device_address(dev));
+
+                               if (err = libusb_open(dev, &devh))
+                                       die("Cannot open device: error %d", err);
+                               libusb_reset_device(devh);
+                               if (err = libusb_claim_interface(devh, 0))
+                                       die("Cannot claim interface: error %d", err);
+
+                               libusb_free_device_list(devlist, 1);
+                               return;
+                       }
+               }
+       }
+
+       libusb_free_device_list(devlist, 1);
+       die("Device not found");
+}
+
+static byte req[64], resp[64];
+
+static int transaction(uint req_len, uint resp_len)
+{
+       int err, transferred;
+       if (err = libusb_bulk_transfer(devh, 0x01, req, req_len, &transferred, 2000))
+               die("Transfer failed: error %d\n", err);
+       // printf("Transferred %d bytes\n", transferred);
+
+       int received;
+       if (err = libusb_bulk_transfer(devh, 0x82, resp, 64, &received, 2000))
+               die("Receive failed: error %d\n", err);
+       // printf("Received %d bytes\n", received);
+
+       if ((uint) received < resp_len)
+               die("Received short packet (%u out of %u bytes)", received, resp_len);
+
+       if (received >= 4) {
+               uint status = get_u32_be(resp);
+               if (status)
+                       die("Received error status %08x", status);
+       }
+
+       return received;
+}
+
+static struct opt_section options = {
+       OPT_ITEMS {
+               OPT_HELP("A daemon for controlling the solid state relay module"),
+               OPT_HELP(""),
+               OPT_HELP("Options:"),
+               OPT_HELP_OPTION,
+               OPT_CONF_OPTIONS,
+               OPT_END
+       }
+};
+
+int main(int argc UNUSED, char **argv)
+{
+       opt_parse(&options, argv+1);
+
+       int err;
+       if (err = libusb_init(&usb_ctxt))
+               die("Cannot initialize libusb: error %d", err);
+       libusb_set_debug(usb_ctxt, 3);
+       open_device();
+
+       mosquitto_lib_init();
+       struct mosquitto *mosq = mosquitto_new("ssrd", 1, NULL);
+       if (!mosq)
+               die("Mosquitto: initialization failed");
+
+       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");
+
+       time_t next_run = 0;
+       for (;;) {
+               time_t now = time(NULL);
+               if (now < next_run) {
+                       int err = mosquitto_loop(mosq, (next_run - now) * 1000, 1);
+                       if (err != MOSQ_ERR_SUCCESS)
+                               msg(L_ERROR, "Mosquitto: loop returned error %d", err);
+                       continue;
+               }
+
+               next_run = now + 5;
+
+               put_u32_be(req, 2);
+               transaction(8, 8);
+               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");
+       }
+}