]> mj.ucw.cz Git - home-hw.git/blob - usb/host/burrow-clock.c
Auto: Meditation mode turned off
[home-hw.git] / usb / host / burrow-clock.c
1 /*
2  *      MJ's desktop clock daemon
3  *
4  *      (c) 2018 Martin Mares <mj@ucw.cz>
5  */
6
7 #include <ucw/lib.h>
8 #include <ucw/log.h>
9 #include <ucw/opt.h>
10 #include <ucw/unaligned.h>
11
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <stdint.h>
15 #include <syslog.h>
16 #include <unistd.h>
17 #include <time.h>
18
19 #include <libusb-1.0/libusb.h>
20 #include <mosquitto.h>
21
22 static struct mosquitto *mosq;
23
24 struct libusb_context *usb_ctxt;
25 struct libusb_device_handle *devh;
26
27 static libusb_device *find_device(void)
28 {
29         libusb_device **devlist;
30         ssize_t devn = libusb_get_device_list(usb_ctxt, &devlist);
31         if (devn < 0) {
32                 fprintf(stderr, "Cannot enumerate USB devices: error %d\n", (int) devn);
33                 exit(1);
34         }
35
36         for (ssize_t i=0; i<devn; i++) {
37                 struct libusb_device_descriptor desc;
38                 libusb_device *dev = devlist[i];
39                 if (!libusb_get_device_descriptor(dev, &desc)) {
40                         if (desc.idVendor == 0x4242 && desc.idProduct == 0x0001) {
41                                 msg(L_INFO, "Found device at usb%d.%d", libusb_get_bus_number(dev), libusb_get_device_address(dev));
42                                 // FIXME: Free device list
43                                 return dev;
44                         }
45                 }
46         }
47
48         libusb_free_device_list(devlist, 1);
49         fprintf(stderr, "Device not found\n");
50         exit(1);
51 }
52
53 static void mqtt_publish(const char *topic, const char *fmt, ...)
54 {
55         va_list args;
56         va_start(args, fmt);
57         char m[256];
58         int l = vsnprintf(m, sizeof(m), fmt, args);
59         if (mosquitto_publish(mosq, NULL, topic, l, m, 0, true) != MOSQ_ERR_SUCCESS)
60                 msg(L_ERROR, "Mosquitto: publish failed");
61         va_end(args);
62 }
63
64 static void mqtt_conn_callback(struct mosquitto *mosq UNUSED, void *obj UNUSED, int status)
65 {
66         if (!status) {
67                 msg(L_DEBUG, "MQTT: Connection established");
68                 mqtt_publish("status/clock", "ok");
69         }
70 }
71
72 static int use_daemon;
73 static int use_debug;
74
75 static struct opt_section options = {
76         OPT_ITEMS {
77                 OPT_HELP("A daemon for controlling the solid state relay module via MQTT"),
78                 OPT_HELP(""),
79                 OPT_HELP("Options:"),
80                 OPT_BOOL('d', "debug", use_debug, 0, "\tLog debugging messages"),
81                 OPT_BOOL(0, "daemon", use_daemon, 0, "\tDaemonize"),
82                 OPT_HELP_OPTION,
83                 OPT_CONF_OPTIONS,
84                 OPT_END
85         }
86 };
87
88 int main(int argc UNUSED, char **argv)
89 {
90         log_init(argv[0]);
91         opt_parse(&options, argv+1);
92
93         if (use_daemon) {
94                 struct log_stream *ls = log_new_syslog("daemon", LOG_PID);
95                 log_set_default_stream(ls);
96         }
97         if (!use_debug)
98                 log_default_stream()->levels &= ~(1U << L_DEBUG);
99
100         mosquitto_lib_init();
101         mosq = mosquitto_new("clock", 1, NULL);
102         if (!mosq)
103                 die("Mosquitto: initialization failed");
104
105         mosquitto_connect_callback_set(mosq, mqtt_conn_callback);
106
107         if (mosquitto_will_set(mosq, "status/clock", 4, "dead", 0, true) != MOSQ_ERR_SUCCESS)
108                 die("Mosquitto: unable to set will");
109
110         if (mosquitto_connect_async(mosq, "10.32.184.5", 1883, 60) != MOSQ_ERR_SUCCESS)
111                 die("Mosquitto: connect failed");
112
113         if (mosquitto_loop_start(mosq))
114                 die("Mosquitto: cannot start service thread");
115
116         int err;
117         if (err = libusb_init(&usb_ctxt))
118                 die("Cannot initialize libusb: error %d", err);
119
120         libusb_device *dev = find_device();
121
122         if (err = libusb_open(dev, &devh))
123                 die("Cannot open device: error %d", err);
124         libusb_reset_device(devh);
125         if (err = libusb_claim_interface(devh, 0))
126                 die("Cannot claim interface: error %d", err);
127
128         uint cnt = 0;
129         for (;;) {
130                 time_t t = time(NULL);
131                 struct tm *tm = localtime(&t);
132
133                 unsigned char req[8] = {
134                         tm->tm_hour / 10,
135                         tm->tm_hour % 10,
136                         (tm->tm_sec % 2 ? 10 : 0xff),
137                         tm->tm_min / 10,
138                         tm->tm_min % 10,
139                 };
140                 int transferred;
141                 if (err = libusb_bulk_transfer(devh, 0x01, req, 8, &transferred, 2000))
142                         die("Transfer failed: error %d", err);
143
144                 unsigned char resp[64];
145                 int received;
146                 if (err = libusb_bulk_transfer(devh, 0x82, resp, 64, &received, 2000))
147                         die("Receive failed: error %d", err);
148                 // printf("Received %d bytes\n", received);
149                 if (received >= 12) {
150                         int temp = get_u32_be(resp);
151                         int press = get_u32_be(resp + 4);
152                         uint cycle = get_u32_be(resp + 8);
153                         msg(L_DEBUG, "Temperature %d ddegC, pressure %d Pa, cycle %u", temp, press, cycle);
154                         if (!(cnt % 10) && press) {
155                                 mqtt_publish("burrow/temp/clock", "%.1f %llu", temp / 10., (long long) t);
156                                 mqtt_publish("burrow/pressure/clock", "%d %llu", press, (long long) t);
157                         }
158                 }
159
160                 sleep(1);
161                 cnt++;
162         }
163
164         return 0;
165 }