-UCWCF:=$(shell PKG_CONFIG_PATH=$(LIBUCW)/lib/pkgconfig pkg-config --cflags libucw)
-UCWLF:=$(shell PKG_CONFIG_PATH=$(LIBUCW)/lib/pkgconfig pkg-config --libs libucw)
+TOPDIR=/root/turris
-CFLAGS=-std=gnu99 -O2 -Wall -Wextra -Wno-parentheses $(UCWCF)
-LDLIBS=-lusb-1.0 $(UCWLF)
+include $(TOPDIR)/rules.mk
+include $(TOPDIR)/include/package.mk
-all: test
+PC := PATH=$(STAGING_DIR_HOST)/bin:$(PATH) PKG_CONFIG_PATH=$(PKG_CONFIG_PATH) PKG_CONFIG_LIBDIR=$(PKG_CONFIG_PATH) STAGING_PREFIX=$(STAGING_DIR)/usr $(PKG_CONFIG)
+USB_CFLAGS := $(shell $(PC) --cflags libusb-1.0)
+USB_LDFLAGS := $(shell $(PC) --libs libusb-1.0)
+UCW_CFLAGS := $(shell $(PC) --cflags libucw)
+UCW_LDFLAGS := $(shell $(PC) --libs libucw)
-test: test.c
+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) -lmosquitto
+
+all: ssr-control burrow-ssrd upload
+
+ssr-control: ssr-control.c
+burrow-ssrd: burrow-ssrd.c
+
+upload:
+ rsync -av ssr-control burrow-ssrd micac:burrow/
+
+.PHONY: upload
--- /dev/null
+/*
+ * A MQTT Gateway Daemon for the Solid State Relay module
+ *
+ * (c) 2018 Martin Mares <mj@ucw.cz>
+ */
+
+#include <ucw/lib.h>
+#include <ucw/log.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 <syslog.h>
+#include <time.h>
+
+#include <libusb-1.0/libusb.h>
+#include <mosquitto.h>
+
+struct libusb_context *usb_ctxt;
+struct libusb_device_handle *devh;
+
+struct mosquitto *mosq;
+
+static u32 ssr_state;
+
+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", 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 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_setup(void)
+{
+ if (mosquitto_subscribe(mosq, NULL, "burrow/loft/#", 1) != MOSQ_ERR_SUCCESS)
+ die("Mosquitto: subscribe failed");
+
+ mqtt_publish("burrow/loft/status", "ok");
+}
+
+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_DEBUG, "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 int use_daemon;
+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(""),
+ OPT_HELP("Options:"),
+ OPT_BOOL('d', "debug", use_debug, 0, "\tLog debugging messages"),
+ OPT_BOOL(0, "daemon", use_daemon, 0, "\tDaemonize"),
+ OPT_HELP_OPTION,
+ OPT_CONF_OPTIONS,
+ OPT_END
+ }
+};
+
+int main(int argc UNUSED, char **argv)
+{
+ log_init(argv[0]);
+ opt_parse(&options, argv+1);
+
+ if (use_daemon) {
+ struct log_stream *ls = log_new_syslog("daemon", LOG_PID);
+ log_set_default_stream(ls);
+ }
+ if (!use_debug)
+ log_default_stream()->levels &= ~(1U << L_DEBUG);
+
+ int err;
+ if (err = libusb_init(&usb_ctxt))
+ die("Cannot initialize libusb: error %d", err);
+ if (use_debug)
+ libusb_set_debug(usb_ctxt, 3);
+ open_device();
+ set_relays();
+
+ mosquitto_lib_init();
+ 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");
+
+ mqtt_setup();
+
+ 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_NO_CONN) {
+ err = mosquitto_reconnect(mosq);
+ if (err == MOSQ_ERR_SUCCESS)
+ mqtt_setup();
+ else
+ msg(L_ERROR, "Mosquitto: cannot reconnect, error %d", err);
+ } else 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);
+
+ mqtt_publish("burrow/loft/temperature", "%.3f", t / 1000.);
+ mqtt_publish("burrow/loft/timestamp", "%u", (int) now);
+ }
+}
--- /dev/null
+/*
+ * Control utility for the Solid State Relay module
+ *
+ * (c) 2018 Martin Mares <mj@ucw.cz>
+ */
+
+#include <ucw/lib.h>
+#include <ucw/unaligned.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <time.h>
+
+#include <libusb-1.0/libusb.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) {
+ printf("Found device 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 void usage(void)
+{
+ fprintf(stderr, "Usage: ssr-control [-t] [-s <mask>]\n");
+ exit(1);
+}
+
+int main(int argc, char **argv)
+{
+ int get_temp = 0;
+ int set_relays = -1;
+
+ int opt;
+ while ((opt = getopt(argc, argv, "ts:")) >= 0) {
+ switch (opt) {
+ case 't':
+ get_temp = 1;
+ break;
+ case 's':
+ set_relays = atoi(optarg);
+ break;
+ default:
+ usage();
+ }
+ }
+ if (optind < argc)
+ usage();
+
+ int err;
+ if (err = libusb_init(&usb_ctxt))
+ die("Cannot initialize libusb: error %d", err);
+ libusb_set_debug(usb_ctxt, 3);
+ open_device();
+
+ if (get_temp) {
+ put_u32_be(req, 2);
+ transaction(8, 8);
+ int t = get_u32_be(resp+4);
+ printf("Temp: %d\n", t);
+ }
+
+ if (set_relays >= 0) {
+ put_u32_be(req, 1);
+ put_u32_be(req+4, set_relays);
+ transaction(8, 4);
+ }
+
+ return 0;
+}
+++ /dev/null
-#include <ucw/lib.h>
-#include <ucw/unaligned.h>
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include <unistd.h>
-#include <time.h>
-#include <libusb-1.0/libusb.h>
-
-struct libusb_context *usb_ctxt;
-struct libusb_device_handle *devh;
-
-static libusb_device *find_device(void)
-{
- libusb_device **devlist;
- ssize_t devn = libusb_get_device_list(usb_ctxt, &devlist);
- if (devn < 0)
- {
- fprintf(stderr, "Cannot enumerate USB devices: error %d\n", (int) devn);
- exit(1);
- }
-
- 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)
- {
- printf("Found device at usb%d.%d\n", libusb_get_bus_number(dev), libusb_get_device_address(dev));
- // FIXME: Free device list
- return dev;
- }
- }
- }
-
- libusb_free_device_list(devlist, 1);
- fprintf(stderr, "Device not found\n");
- exit(1);
-}
-
-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;
-}
-
-int main(void)
-{
- int err;
- if (err = libusb_init(&usb_ctxt))
- {
- fprintf(stderr, "Cannot initialize libusb: error %d\n", err);
- exit(1);
- }
- libusb_set_debug(usb_ctxt, 3);
-
- libusb_device *dev = find_device();
-
- if (err = libusb_open(dev, &devh))
- {
- fprintf(stderr, "Cannot open device: error %d\n", err);
- exit(1);
- }
- libusb_reset_device(devh);
- if (err = libusb_claim_interface(devh, 0))
- {
- fprintf(stderr, "Cannot claim interface: error %d\n", err);
- exit(1);
- }
-
-#if 1
- put_u32_be(req, 2);
- transaction(8, 8);
- int t = get_u32_be(resp+4);
- printf("Temp: %d\n", t);
-#endif
-
- int x = 0;
- scanf("%d", &x);
-
- put_u32_be(req, 1);
- put_u32_be(req+4, x);
- transaction(8, 4);
-
- return 0;
-}
--- /dev/null
+UCWCF:=$(shell PKG_CONFIG_PATH=$(LIBUCW)/lib/pkgconfig pkg-config --cflags libucw)
+UCWLF:=$(shell PKG_CONFIG_PATH=$(LIBUCW)/lib/pkgconfig pkg-config --libs libucw)
+
+CFLAGS=-std=gnu99 -O2 -Wall -Wextra -Wno-parentheses $(UCWCF)
+LDLIBS=-lusb-1.0 $(UCWLF)
+
+all: test
+
+test: test.c
--- /dev/null
+#include <ucw/lib.h>
+#include <ucw/unaligned.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <time.h>
+#include <libusb-1.0/libusb.h>
+
+struct libusb_context *usb_ctxt;
+struct libusb_device_handle *devh;
+
+static libusb_device *find_device(void)
+{
+ libusb_device **devlist;
+ ssize_t devn = libusb_get_device_list(usb_ctxt, &devlist);
+ if (devn < 0)
+ {
+ fprintf(stderr, "Cannot enumerate USB devices: error %d\n", (int) devn);
+ exit(1);
+ }
+
+ 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)
+ {
+ printf("Found device at usb%d.%d\n", libusb_get_bus_number(dev), libusb_get_device_address(dev));
+ // FIXME: Free device list
+ return dev;
+ }
+ }
+ }
+
+ libusb_free_device_list(devlist, 1);
+ fprintf(stderr, "Device not found\n");
+ exit(1);
+}
+
+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;
+}
+
+int main(void)
+{
+ int err;
+ if (err = libusb_init(&usb_ctxt))
+ {
+ fprintf(stderr, "Cannot initialize libusb: error %d\n", err);
+ exit(1);
+ }
+ libusb_set_debug(usb_ctxt, 3);
+
+ libusb_device *dev = find_device();
+
+ if (err = libusb_open(dev, &devh))
+ {
+ fprintf(stderr, "Cannot open device: error %d\n", err);
+ exit(1);
+ }
+ libusb_reset_device(devh);
+ if (err = libusb_claim_interface(devh, 0))
+ {
+ fprintf(stderr, "Cannot claim interface: error %d\n", err);
+ exit(1);
+ }
+
+#if 1
+ put_u32_be(req, 2);
+ transaction(8, 8);
+ int t = get_u32_be(resp+4);
+ printf("Temp: %d\n", t);
+#endif
+
+ int x = 0;
+ scanf("%d", &x);
+
+ put_u32_be(req, 1);
+ put_u32_be(req+4, x);
+ transaction(8, 4);
+
+ return 0;
+}
+++ /dev/null
-TOPDIR=/root/turris
-
-include $(TOPDIR)/rules.mk
-include $(TOPDIR)/include/package.mk
-
-PC := PATH=$(STAGING_DIR_HOST)/bin:$(PATH) PKG_CONFIG_PATH=$(PKG_CONFIG_PATH) PKG_CONFIG_LIBDIR=$(PKG_CONFIG_PATH) STAGING_PREFIX=$(STAGING_DIR)/usr $(PKG_CONFIG)
-USB_CFLAGS := $(shell $(PC) --cflags libusb-1.0)
-USB_LDFLAGS := $(shell $(PC) --libs libusb-1.0)
-UCW_CFLAGS := $(shell $(PC) --cflags libucw)
-UCW_LDFLAGS := $(shell $(PC) --libs libucw)
-
-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) -lmosquitto
-
-all: ssr-control burrow-ssrd upload
-
-ssr-control: ssr-control.c
-burrow-ssrd: burrow-ssrd.c
-
-upload:
- rsync -av ssr-control burrow-ssrd micac:burrow/
-
-.PHONY: upload
+++ /dev/null
-/*
- * A MQTT Gateway Daemon for the Solid State Relay module
- *
- * (c) 2018 Martin Mares <mj@ucw.cz>
- */
-
-#include <ucw/lib.h>
-#include <ucw/log.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 <syslog.h>
-#include <time.h>
-
-#include <libusb-1.0/libusb.h>
-#include <mosquitto.h>
-
-struct libusb_context *usb_ctxt;
-struct libusb_device_handle *devh;
-
-struct mosquitto *mosq;
-
-static u32 ssr_state;
-
-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", 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 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_setup(void)
-{
- if (mosquitto_subscribe(mosq, NULL, "burrow/loft/#", 1) != MOSQ_ERR_SUCCESS)
- die("Mosquitto: subscribe failed");
-
- mqtt_publish("burrow/loft/status", "ok");
-}
-
-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_DEBUG, "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 int use_daemon;
-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(""),
- OPT_HELP("Options:"),
- OPT_BOOL('d', "debug", use_debug, 0, "\tLog debugging messages"),
- OPT_BOOL(0, "daemon", use_daemon, 0, "\tDaemonize"),
- OPT_HELP_OPTION,
- OPT_CONF_OPTIONS,
- OPT_END
- }
-};
-
-int main(int argc UNUSED, char **argv)
-{
- log_init(argv[0]);
- opt_parse(&options, argv+1);
-
- if (use_daemon) {
- struct log_stream *ls = log_new_syslog("daemon", LOG_PID);
- log_set_default_stream(ls);
- }
- if (!use_debug)
- log_default_stream()->levels &= ~(1U << L_DEBUG);
-
- int err;
- if (err = libusb_init(&usb_ctxt))
- die("Cannot initialize libusb: error %d", err);
- if (use_debug)
- libusb_set_debug(usb_ctxt, 3);
- open_device();
- set_relays();
-
- mosquitto_lib_init();
- 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");
-
- mqtt_setup();
-
- 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_NO_CONN) {
- err = mosquitto_reconnect(mosq);
- if (err == MOSQ_ERR_SUCCESS)
- mqtt_setup();
- else
- msg(L_ERROR, "Mosquitto: cannot reconnect, error %d", err);
- } else 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);
-
- mqtt_publish("burrow/loft/temperature", "%.3f", t / 1000.);
- mqtt_publish("burrow/loft/timestamp", "%u", (int) now);
- }
-}
+++ /dev/null
-/*
- * Control utility for the Solid State Relay module
- *
- * (c) 2018 Martin Mares <mj@ucw.cz>
- */
-
-#include <ucw/lib.h>
-#include <ucw/unaligned.h>
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <stdint.h>
-#include <unistd.h>
-#include <getopt.h>
-#include <time.h>
-
-#include <libusb-1.0/libusb.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) {
- printf("Found device 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 void usage(void)
-{
- fprintf(stderr, "Usage: ssr-control [-t] [-s <mask>]\n");
- exit(1);
-}
-
-int main(int argc, char **argv)
-{
- int get_temp = 0;
- int set_relays = -1;
-
- int opt;
- while ((opt = getopt(argc, argv, "ts:")) >= 0) {
- switch (opt) {
- case 't':
- get_temp = 1;
- break;
- case 's':
- set_relays = atoi(optarg);
- break;
- default:
- usage();
- }
- }
- if (optind < argc)
- usage();
-
- int err;
- if (err = libusb_init(&usb_ctxt))
- die("Cannot initialize libusb: error %d", err);
- libusb_set_debug(usb_ctxt, 3);
- open_device();
-
- if (get_temp) {
- put_u32_be(req, 2);
- transaction(8, 8);
- int t = get_u32_be(resp+4);
- printf("Temp: %d\n", t);
- }
-
- if (set_relays >= 0) {
- put_u32_be(req, 1);
- put_u32_be(req+4, set_relays);
- transaction(8, 4);
- }
-
- return 0;
-}