va_end(args);
}
+static void mqtt_publish_ephemeral(const char *topic, const char *fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+
+ if (mqtt_connected) {
+ char m[256];
+ int l = vsnprintf(m, sizeof(m), fmt, args);
+ int err = mosquitto_publish(mosq, NULL, topic, l, m, 0, false);
+ if (err != MOSQ_ERR_SUCCESS)
+ msg(L_ERROR, "Mosquitto: Publish failed, error=%d", err);
+ }
+
+ va_end(args);
+}
+
static void mqtt_conn_callback(struct mosquitto *mosq UNUSED, void *obj UNUSED, int status)
{
if (!status) {
msg(L_DEBUG, "MQTT: Connection established");
- mqtt_publish("status/bsb", "ok");
mqtt_connected = true;
+ mqtt_publish("status/bsb", "ok");
} else if (mqtt_connected) {
msg(L_DEBUG, "MQTT: Connection lost");
mqtt_connected = false;
va_list args;
va_start(args, msg);
ucw_vmsg(L_ERROR, msg, args);
- fputc('\n', stderr);
va_end(args);
if (devh) {
#undef P
};
+static int get_s16_be(const byte *x)
+{
+ int val = get_u16_be(x);
+ if (val >= 0x8000)
+ return val - 0x10000;
+ else
+ return val;
+}
+
static void process_stats(time_t t, byte *resp, uint len)
{
for (uint i=0; i < ARRAY_SIZE(stat_names) && 4*i + 3 < (uint) len; i++) {
char item[64];
- snprintf(item, sizeof(item), "burrow/bsb/stats/%s", stat_names[i]);
- mqtt_publish(item, "%u", (uint) get_u32_le(resp+4*i), t);
+ snprintf(item, sizeof(item), "bsb/stats/%s", stat_names[i]);
+ mqtt_publish(item, "%u %lld", (uint) get_u32_le(resp+4*i), (long long) t);
}
}
-static void process_info(byte *p, uint len)
+static void process_info(time_t t, byte *p, uint len)
{
if (len < 4)
return;
len -= 4;
switch (addr) {
+ case 0x0500006b:
+ if (len >= 2) {
+ int err = get_u16_be(p);
+ mqtt_publish("burrow/heating/error", "%d %lld", err, (long long) t);
+ }
+ break;
+ case 0x0500006c:
+ if (len >= 7) {
+ mqtt_publish("burrow/heating/clock", "%04d-%02d-%02dT%02d:%02d %lld",
+ get_u16_be(p) + 1900, p[2], p[3],
+ p[5], p[6],
+ (long long) t);
+ }
+ break;
case 0x05000219:
if (len >= 4) {
- uint temp = get_u16_be(p);
+ int temp = get_s16_be(p);
uint press = get_u16_be(p + 2);
- mqtt_publish("burrow/heating/outside-temp", "%.2f", temp / 64.);
- mqtt_publish("burrow/heating/water-pressure", "%.1f", press / 10.);
+ mqtt_publish("burrow/heating/outside-temp", "%.2f %lld", temp / 64., (long long) t);
+ mqtt_publish("burrow/heating/water-pressure", "%.1f %lld", press / 10., (long long) t);
}
break;
case 0x05000229:
// AGU.2 status
if (len >= 2) {
- uint temp = get_u16_be(p);
- mqtt_publish("burrow/heating/circuit1/mix-temp", "%.2f", temp / 64.);
+ int temp = get_s16_be(p);
+ mqtt_publish("burrow/heating/circuit1/mix-temp", "%.2f %lld", temp / 64., (long long) t);
}
break;
case 0x05040227:
// AGU.2 control
- if (len >= 2) {
+ if (len >= 4) {
uint m = get_u16_be(p);
- mqtt_publish("burrow/heating/circuit1/mix-valve", "%u", m);
+ mqtt_publish("burrow/heating/circuit1/mix-valve", "%u %lld", m, (long long) t);
+ mqtt_publish("burrow/heating/circuit1/pump", "%u %lld", (p[3] == 3), (long long) t);
+ }
+ break;
+ case 0x2d000211:
+ // Circuit 1 status
+ if (len >= 10) {
+ mqtt_publish("burrow/heating/circuit1/active", "%u %lld", (p[8] != 0), (long long) t);
+ }
+ break;
+ case 0x2e000211:
+ // Circuit 2 status
+ if (len >= 10) {
+ mqtt_publish("burrow/heating/circuit2/active", "%u %lld", (p[8] != 0), (long long) t);
+ }
+ break;
+ case 0x31000212:
+ // Hot water status
+ if (len >= 3) {
+ mqtt_publish("burrow/heating/water/active", "%u %lld", (p[1] != 0), (long long) t);
}
break;
case 0x3d2d0215:
// Room 1 status
if (len >= 2) {
- uint temp = get_u16_be(p);
- mqtt_publish("burrow/heating/circuit1/room-temp", "%.2f", temp / 64.);
+ int temp = get_s16_be(p);
+ mqtt_publish("burrow/heating/circuit1/room-temp", "%.2f %lld", temp / 64., (long long) t);
}
break;
case 0x3e2e0215:
// Room 2 status
if (len >= 2) {
- uint temp = get_u16_be(p);
- mqtt_publish("burrow/heating/circuit2/room-temp", "%.2f", temp / 64.);
+ int temp = get_s16_be(p);
+ mqtt_publish("burrow/heating/circuit2/room-temp", "%.2f %lld", temp / 64., (long long) t);
}
break;
}
}
-static void process_answer(byte *p, uint len)
+static void process_answer(time_t t, byte *p, uint len)
{
if (len < 4)
return;
char hex[3*len + 1];
mem_to_hex(hex, pkt, len, ' ');
- mqtt_publish("bsb/frame", "%s", hex, t);
+ mqtt_publish_ephemeral("bsb/frame", "%s", hex, t);
msg(L_DEBUG, "<< %s", hex);
- byte *params = pkt + BF_PARAMS;
- uint param_len = len - BF_PARAMS - 2; // 2 for CRC
+ byte *body = pkt + BF_BODY;
+ uint body_len = len - BF_BODY - 2; // 2 for CRC
switch (pkt[BF_OP]) {
case BSB_OP_INFO:
- process_info(params, param_len);
+ process_info(t, body, body_len);
break;
case BSB_OP_ANSWER:
- process_answer(params, param_len);
+ process_answer(t, body, body_len);
break;
}
}