# HG changeset patch # User Michiel Broek # Date 1494253562 -7200 # Node ID cdcd07bbee30eefd20077270e0367d6df877fac7 # Parent 862de87f9f89d61bfff36360ab7273f15f21d339 New MQTT protocol diff -r 862de87f9f89 -r cdcd07bbee30 configure --- a/configure Sat Apr 29 17:07:36 2017 +0200 +++ b/configure Mon May 08 16:26:02 2017 +0200 @@ -2035,7 +2035,7 @@ PACKAGE="mbsePi-apps" -VERSION="0.5.8" +VERSION="0.5.9" COPYRIGHT="Copyright (C) 2014-2017 Michiel Broek, All Rights Reserved" CYEARS="2014-2017" diff -r 862de87f9f89 -r cdcd07bbee30 configure.ac --- a/configure.ac Sat Apr 29 17:07:36 2017 +0200 +++ b/configure.ac Mon May 08 16:26:02 2017 +0200 @@ -8,7 +8,7 @@ dnl General settings dnl After changeing the version number, run autoconf! PACKAGE="mbsePi-apps" -VERSION="0.5.8" +VERSION="0.5.9" COPYRIGHT="Copyright (C) 2014-2017 Michiel Broek, All Rights Reserved" CYEARS="2014-2017" AC_SUBST(PACKAGE) diff -r 862de87f9f89 -r cdcd07bbee30 thermferm/devices.c --- a/thermferm/devices.c Sat Apr 29 17:07:36 2017 +0200 +++ b/thermferm/devices.c Mon May 08 16:26:02 2017 +0200 @@ -1,5 +1,5 @@ /***************************************************************************** - * Copyright (C) 2014..2015 + * Copyright (C) 2014..2017 * * Michiel Broek * @@ -659,11 +659,11 @@ ndev->address = xstrcpy((char *)"SimBeerTemp"); ndev->description = xstrcpy((char *)"Simulated beer temperature"); break; - case 3: ndev->direction = DEVDIR_OUT_ANALOG; + case 3: ndev->direction = DEVDIR_OUT_BIN; ndev->address = xstrcpy((char *)"SimHeater"); ndev->description = xstrcpy((char *)"Simulated heater"); break; - case 4: ndev->direction = DEVDIR_OUT_ANALOG; + case 4: ndev->direction = DEVDIR_OUT_BIN; ndev->address = xstrcpy((char *)"SimCooler"); ndev->description = xstrcpy((char *)"Simulated cooler"); break; @@ -932,10 +932,10 @@ device->value = (int)((int)(simulator->room_temperature * 1000) / 500) * 500; device->timestamp = time(NULL); } else if (device->subdevice == 1) { - device->value = (int)((int)(simulator->air_temperature * 1000) / 125) * 125; + device->value = (int)((int)(simulator->air_temperature * 1000) / 62.5) * 62.5; device->timestamp = time(NULL); } else if (device->subdevice == 2) { - device->value = (int)((int)(simulator->beer_temperature * 1000) / 125) * 125; + device->value = (int)((int)(simulator->beer_temperature * 1000) / 62.5) * 62.5; device->timestamp = time(NULL); } } diff -r 862de87f9f89 -r cdcd07bbee30 thermferm/mqtt.c --- a/thermferm/mqtt.c Sat Apr 29 17:07:36 2017 +0200 +++ b/thermferm/mqtt.c Mon May 08 16:26:02 2017 +0200 @@ -1,5 +1,5 @@ /***************************************************************************** - * Copyright (C) 2016 + * Copyright (C) 2016-2017 * * Michiel Broek * @@ -26,6 +26,12 @@ extern sys_config Config; extern int debug; +extern const char UNITMODE[5][8]; +extern const char PROFSTATE[5][6]; +extern const char TEMPSTATE[3][8]; + +int Sequence = 0; + #ifdef HAVE_MOSQUITTO_H @@ -48,17 +54,58 @@ char my_hostname[256]; + +char *payload_header(void) +{ + char *tmp, buf[128]; + + tmp = xstrcpy((char *)"{\"timestamp\":"); + sprintf(buf, "%ld", time(NULL)); + tmp = xstrcat(tmp, buf); + tmp = xstrcat(tmp, (char *)",\"seq\":"); + sprintf(buf, "%d", Sequence++); + tmp = xstrcat(tmp, buf); + tmp = xstrcat(tmp, (char *)",\"metric\":"); + return tmp; +} + + + +char *topic_base(char *msgtype) +{ + char *tmp; + + tmp = xstrcpy((char *)"mbv1.0/fermenters/"); + tmp = xstrcat(tmp, msgtype); + tmp = xstrcat(tmp, (char *)"/"); + tmp = xstrcat(tmp, my_hostname); + return tmp; +} + + + void my_connect_callback(struct mosquitto *my_mosq, void *obj, int result) { + char *topic = NULL; + if (mqtt_connect_lost) { - mqtt_connect_lost = FALSE; - syslog(LOG_NOTICE, "MQTT: reconnect: %s", mosquitto_connack_string(result)); + mqtt_connect_lost = FALSE; + syslog(LOG_NOTICE, "MQTT: reconnect: %s", mosquitto_connack_string(result)); } if (!result) { - mqtt_status = STATUS_CONNACK_RECVD; + topic = topic_base((char *)"NCMD"); + topic = xstrcat(topic, (char *)"/#"); + mosquitto_subscribe(mosq, NULL, topic, 0); + free(topic); + topic = topic_base((char *)"DCMD"); + topic = xstrcat(topic, (char *)"/#"); + mosquitto_subscribe(mosq, NULL, topic, 0); + free(topic); + topic = NULL; + mqtt_status = STATUS_CONNACK_RECVD; } else { - syslog(LOG_NOTICE, "MQTT: my_connect_callback: %s\n", mosquitto_connack_string(result)); + syslog(LOG_NOTICE, "MQTT: my_connect_callback: %s\n", mosquitto_connack_string(result)); } } @@ -87,6 +134,18 @@ +void my_subscribe_callback(struct mosquitto *my_mosq, void *userdata, int mid, int qos_count, const int *granted_qos) +{ + int i; + + syslog(LOG_NOTICE, "Subscribed (mid: %d): %d", mid, granted_qos[0]); + for (i = 1; i < qos_count; i++) { + syslog(LOG_NOTICE, " %d", granted_qos[i]); + } +} + + + void my_log_callback(struct mosquitto *my_mosq, void *obj, int level, const char *str) { syslog(LOG_NOTICE, "MQTT: %s", str); @@ -96,15 +155,389 @@ +void my_message_callback(struct mosquitto *my_mosq, void *userdata, const struct mosquitto_message *message) +{ + if (message->payloadlen) { + syslog(LOG_NOTICE, "MQTT: message callback %s :: %d", message->topic, message->payloadlen); + // TODO: process subscribed topics here. + + } else { + syslog(LOG_NOTICE, "MQTT: message callback %s (null)", message->topic); + } +} + + + +void publisher(struct mosquitto *my_mosq, char *topic, char *payload, bool retain) { + // publish the data + if (payload) + mosquitto_publish(my_mosq, &mqtt_mid_sent, topic, strlen(payload), payload, mqtt_qos, retain); + else + mosquitto_publish(my_mosq, &mqtt_mid_sent, topic, 0, NULL, mqtt_qos, retain); +} + + + +char *unit_data(units_list *unit, bool birth) +{ + char *payload = NULL; + char buf[128]; + bool comma = false; + profiles_list *profile; + prof_step *pstep; + + payload = xstrcat(payload, (char *)"{"); + if (birth || unit->mqtt_flag & MQTT_FLAG_MODE) { + // Also send these on mode change + payload = xstrcat(payload, (char *)"\"uuid\":\""); + payload = xstrcat(payload, unit->uuid); + payload = xstrcat(payload, (char *)"\",\"alias\":\""); + payload = xstrcat(payload, unit->alias); + payload = xstrcat(payload, (char *)"\",\"name\":\""); + payload = xstrcat(payload, unit->name); + payload = xstrcat(payload, (char *)"\""); + comma = true; + } + if (birth || unit->mqtt_flag & MQTT_FLAG_AIR) { + if (comma) + payload = xstrcat(payload, (char *)","); + if (unit->air_address) { + payload = xstrcat(payload, (char *)"\"air\":{\"address\":\""); + payload = xstrcat(payload, unit->air_address); + payload = xstrcat(payload, (char *)"\",\"state\":\""); + payload = xstrcat(payload, (char *)TEMPSTATE[unit->air_state]); + payload = xstrcat(payload, (char *)"\",\"temperature\":"); + sprintf(buf, "%.3f", unit->air_temperature / 1000.0); + payload = xstrcat(payload, buf); + payload = xstrcat(payload, (char *)"}"); + } else { + payload = xstrcat(payload, (char *)"\"air\":null"); + } + comma = true; + } + if (birth || unit->mqtt_flag & MQTT_FLAG_BEER) { + if (comma) + payload = xstrcat(payload, (char *)","); + if (unit->beer_address) { + payload = xstrcat(payload, (char *)"\"beer\":{\"address\":\""); + payload = xstrcat(payload, unit->beer_address); + payload = xstrcat(payload, (char *)"\",\"state\":\""); + payload = xstrcat(payload, (char *)TEMPSTATE[unit->beer_state]); + payload = xstrcat(payload, (char *)"\",\"temperature\":"); + sprintf(buf, "%.3f", unit->beer_temperature / 1000.0); + payload = xstrcat(payload, buf); + payload = xstrcat(payload, (char *)"}"); + } else { + payload = xstrcat(payload, (char *)"\"beer\":null"); + } + comma = true; + } + if (birth || unit->mqtt_flag & MQTT_FLAG_HEATER) { + if (comma) + payload = xstrcat(payload, (char *)","); + if (unit->heater_address) { + payload = xstrcat(payload, (char *)"\"heater\":{\"address\":\""); + payload = xstrcat(payload, unit->heater_address); + payload = xstrcat(payload, (char *)"\",\"state\":"); + sprintf(buf, "%d", unit->heater_state); + payload = xstrcat(payload, buf); + payload = xstrcat(payload, (char *)"}"); + } else { + payload = xstrcat(payload, (char *)"\"heater\":null"); + } + comma = true; + } + if (birth || unit->mqtt_flag & MQTT_FLAG_COOLER) { + if (comma) + payload = xstrcat(payload, (char *)","); + if (unit->cooler_address) { + payload = xstrcat(payload, (char *)"\"cooler\":{\"address\":\""); + payload = xstrcat(payload, unit->cooler_address); + payload = xstrcat(payload, (char *)"\",\"state\":"); + sprintf(buf, "%d", unit->cooler_state); + payload = xstrcat(payload, buf); + payload = xstrcat(payload, (char *)"}"); + } else { + payload = xstrcat(payload, (char *)"\"cooler\":null"); + } + comma = true; + } + if (birth || unit->mqtt_flag & MQTT_FLAG_FAN) { + if (comma) + payload = xstrcat(payload, (char *)","); + if (unit->fan_address) { + payload = xstrcat(payload, (char *)"\"fan\":{\"address\":\""); + payload = xstrcat(payload, unit->fan_address); + payload = xstrcat(payload, (char *)"\",\"state\":"); + sprintf(buf, "%d", unit->fan_state); + payload = xstrcat(payload, buf); + payload = xstrcat(payload, (char *)"}"); + } else { + payload = xstrcat(payload, (char *)"\"fan\":null"); + } + comma = true; + } + if (birth || unit->mqtt_flag & MQTT_FLAG_DOOR) { + if (comma) + payload = xstrcat(payload, (char *)","); + if (unit->door_address) { + payload = xstrcat(payload, (char *)"\"door\":{\"address\":\""); + payload = xstrcat(payload, unit->door_address); + payload = xstrcat(payload, (char *)"\",\"state\":"); + sprintf(buf, "%d", unit->door_state); + payload = xstrcat(payload, buf); + payload = xstrcat(payload, (char *)"}"); + } else { + payload = xstrcat(payload, (char *)"\"door\":null"); + } + comma = true; + } + if (birth || unit->mqtt_flag & MQTT_FLAG_LIGHT) { + if (comma) + payload = xstrcat(payload, (char *)","); + if (unit->light_address) { + payload = xstrcat(payload, (char *)"\"light\":{\"address\":\""); + payload = xstrcat(payload, unit->light_address); + payload = xstrcat(payload, (char *)"\",\"state\":"); + sprintf(buf, "%d", unit->light_state); + payload = xstrcat(payload, buf); + payload = xstrcat(payload, (char *)"}"); + } else { + payload = xstrcat(payload, (char *)"\"light\":null"); + } + comma = true; + } + if (birth || unit->mqtt_flag & MQTT_FLAG_PSU) { + if (comma) + payload = xstrcat(payload, (char *)","); + if (unit->psu_address) { + payload = xstrcat(payload, (char *)"\"psu\":{\"address\":\""); + payload = xstrcat(payload, unit->psu_address); + payload = xstrcat(payload, (char *)"\",\"state\":"); + sprintf(buf, "%d", unit->psu_state); + payload = xstrcat(payload, buf); + payload = xstrcat(payload, (char *)"}"); + } else { + payload = xstrcat(payload, (char *)"\"psu\":null"); + } + comma = true; + } + if (birth || unit->mqtt_flag & MQTT_FLAG_MODE) { + if (comma) + payload = xstrcat(payload, (char *)","); + payload = xstrcat(payload, (char *)"\"mode\":\""); + payload = xstrcat(payload, (char *)UNITMODE[unit->mode]); + payload = xstrcat(payload, (char *)"\""); + comma = true; + } + if (birth || unit->mqtt_flag & MQTT_FLAG_SP) { + if (unit->mode != UNITMODE_OFF) { + if (comma) + payload = xstrcat(payload, (char *)","); + payload = xstrcat(payload, (char *)"\"setpoint\":{\"low\":"); + sprintf(buf, "%.1f", unit->PID_heat->SetP); + payload = xstrcat(payload, buf); + payload = xstrcat(payload, (char *)",\"high\":"); + sprintf(buf, "%.1f", unit->PID_cool->SetP); + payload = xstrcat(payload, buf); + payload = xstrcat(payload, (char *)"}"); + comma = true; + } + } + if (birth || unit->mqtt_flag & MQTT_FLAG_PROFILE || unit->mqtt_flag & MQTT_FLAG_PERCENT) { + if (unit->mode == UNITMODE_PROFILE && unit->profile) { + for (profile = Config.profiles; profile; profile = profile->next) { + if (strcmp(unit->profile, profile->uuid) == 0) { + if (comma) + payload = xstrcat(payload, (char *)","); + payload = xstrcat(payload, (char *)"\"profile\":{\"uuid\":\""); + payload = xstrcat(payload, unit->profile); + payload = xstrcat(payload, (char *)",\"name\":\""); + payload = xstrcat(payload, profile->name); + payload = xstrcat(payload, (char *)"\",\"inittemp\":{\"low\":"); + sprintf(buf, "%.1f", profile->inittemp_lo); + payload = xstrcat(payload, buf); + payload = xstrcat(payload, (char *)",\"high\":"); + sprintf(buf, "%.1f", profile->inittemp_hi); + payload = xstrcat(payload, buf); + payload = xstrcat(payload, (char *)"},\"fridgemode\":"); + sprintf(buf, "%d", profile->fridge_mode); + payload = xstrcat(payload, buf); + comma = false; + if (profile->steps) { + payload = xstrcat(payload, (char *)",\"steps\":["); + for (pstep = profile->steps; pstep; pstep = pstep->next) { + if (comma) + payload = xstrcat(payload, (char *)","); + payload = xstrcat(payload, (char *)"{\"resttime\":"); + sprintf(buf, "%d", pstep->resttime); + payload = xstrcat(payload, buf); + payload = xstrcat(payload, (char *)",\"steptime\":"); + sprintf(buf, "%d", pstep->steptime); + payload = xstrcat(payload, buf); + payload = xstrcat(payload, (char *)",\"target\":{\"low\":"); + sprintf(buf, "%.1f", pstep->target_lo); + payload = xstrcat(payload, buf); + payload = xstrcat(payload, (char *)",\"high\":"); + sprintf(buf, "%.1f", pstep->target_hi); + payload = xstrcat(payload, buf); + payload = xstrcat(payload, (char *)"},\"fridgemode\":"); + sprintf(buf, "%d", pstep->fridge_mode); + payload = xstrcat(payload, buf); + payload = xstrcat(payload, (char *)"}"); + comma = true; + } + payload = xstrcat(payload, (char *)"]"); + } else { + payload = xstrcat(payload, (char *)",\"steps\":null"); + } + payload = xstrcat(payload, (char *)"}"); + break; + } + } + } else { + if (comma) + payload = xstrcat(payload, (char *)","); + payload = xstrcat(payload, (char *)"\"profile\":null"); + } + } + payload = xstrcat(payload, (char *)"}"); + + return payload; +} + + + +void publishDBirth(void) +{ + char *payload = NULL; + units_list *unit; + int comma = FALSE; + + payload = payload_header(); + payload = xstrcat(payload, (char *)"{\"units\":["); + for (unit = Config.units; unit; unit = unit->next) { + if (comma) + payload = xstrcat(payload, (char *)","); + payload = xstrcat(payload, unit_data(unit, true)); + comma = TRUE; + } + payload = xstrcat(payload, (char *)"]}}"); + publisher(mosq, topic_base((char *)"DBIRTH"), payload, true); + free(payload); + payload = NULL; +} + #endif +void publishDData(units_list *unit) +{ +#ifdef HAVE_MOSQUITTO_H + + char *payload = NULL, *topic = NULL; + + if (mqtt_use) { + payload = payload_header(); + payload = xstrcat(payload, unit_data(unit, false)); + payload = xstrcat(payload, (char *)"}"); + topic = xstrcat(topic_base((char *)"DDATA"), (char *)"/"); + topic = xstrcat(topic, unit->alias); + publisher(mosq, topic, payload, false); + free(payload); + payload = NULL; + free(topic); + topic = NULL; + } +#endif +} + + + +void publishNData(bool birth, int flag) +{ +#ifdef HAVE_MOSQUITTO_H + char *payload = NULL, buf[64]; + struct utsname ubuf; + bool comma = false; + + payload = payload_header(); + payload = xstrcat(payload, (char *)"{"); + + if (birth || flag & MQTT_NODE_CONTROL) { + payload = xstrcat(payload, (char *)"\"nodecontrol\":{\"reboot\":false,\"rebirth\":false,\"nextserver\":false,\"scanrate\":3000}"); + comma = true; + } + + if (birth) { + if (comma) + payload = xstrcat(payload, (char *)","); + payload = xstrcat(payload, (char *)"\"properties\":{\"hardwaremake\":\"Unknown\",\"hardwaremodel\":\"Unknown\""); + if (uname(&ubuf) == 0) { + payload = xstrcat(payload, (char *)",\"os\":\""); + payload = xstrcat(payload, ubuf.sysname); + payload = xstrcat(payload, (char *)"\",\"os_version\":\""); + payload = xstrcat(payload, ubuf.release); + payload = xstrcat(payload, (char *)"\""); + } else { + payload = xstrcat(payload, (char *)",\"os\":\"Unknown\",\"os_version\":\"Unknown\""); + } + + payload = xstrcat(payload, (char *)",\"FW\":\""); + payload = xstrcat(payload, (char *)VERSION); + payload = xstrcat(payload, (char *)"\"}"); + comma = true; + } + + if (birth || flag & MQTT_NODE_HT) { + if (Config.temp_address || Config.hum_address) { + if (comma) + payload = xstrcat(payload, (char *)","); + payload = xstrcat(payload, (char *)"\"HT\":{"); + if (Config.temp_address) { + payload = xstrcat(payload, (char *)"\"temperature\":"); + sprintf(buf, "%.1f", Config.temp_value / 1000.0); + payload = xstrcat(payload, buf); + } + if (Config.temp_address && Config.hum_address) + payload = xstrcat(payload, (char *)","); + if (Config.hum_address) { + payload = xstrcat(payload, (char *)"\"humidity\":"); + sprintf(buf, "%.1f", Config.hum_value / 1000.0); + payload = xstrcat(payload, buf); + } + payload = xstrcat(payload, (char *)"}"); + } + } + payload = xstrcat(payload, (char *)"}}"); + + if (birth) + publisher(mosq, topic_base((char *)"NBIRTH"), payload, true); + else + publisher(mosq, topic_base((char *)"NDATA"), payload, false); + + free(payload); + payload = NULL; +#endif +} + + + +void publishBirth(void) +{ + publishNData(true, 0); + publishDBirth(); +} + + + + void mqtt_connect(void) { #ifdef HAVE_MOSQUITTO_H - char *id = NULL; - char err[1024]; - int rc; + char *id = NULL; + char err[1024]; + int rc; /* * Initialize mosquitto communication @@ -134,32 +567,23 @@ return; } - if (debug) { - mosquitto_log_callback_set(mosq, my_log_callback); - } - /* * Set our will */ - state = xstrcpy((char *)"clients/"); - state = xstrcat(state, my_hostname); - state = xstrcat(state, (char *)"/thermferm/state"); - if ((rc = mosquitto_will_set(mosq, state, 1, (char *)"0", mqtt_qos, TRUE))) { - if (rc == MOSQ_ERR_INVAL) { - syslog(LOG_NOTICE, "MQTT: mosquitto_will_set: input parameters invalid"); - } else if (rc == MOSQ_ERR_NOMEM) { - syslog(LOG_NOTICE, "MQTT: mosquitto_will_set: Out of Memory"); - } else if (rc == MOSQ_ERR_PAYLOAD_SIZE) { - syslog(LOG_NOTICE, "MQTT: mosquitto_will_set: invalid payload size"); - } + if ((rc = mosquitto_will_set(mosq, topic_base((char *)"NDEATH"), 0, NULL, mqtt_qos, false))) { + if (rc > MOSQ_ERR_SUCCESS) + syslog(LOG_NOTICE, "MQTT: mosquitto_will_set: %s", mosquitto_strerror(rc)); mosquitto_lib_cleanup(); return; } + mosquitto_log_callback_set(mosq, my_log_callback); mosquitto_max_inflight_messages_set(mosq, max_inflight); mosquitto_connect_callback_set(mosq, my_connect_callback); mosquitto_disconnect_callback_set(mosq, my_disconnect_callback); mosquitto_publish_callback_set(mosq, my_publish_callback); + mosquitto_message_callback_set(mosq, my_message_callback); + mosquitto_subscribe_callback_set(mosq, my_subscribe_callback); if ((rc = mosquitto_connect(mosq, Config.mqtt_host, Config.mqtt_port, keepalive))) { if (rc == MOSQ_ERR_ERRNO) { @@ -178,7 +602,7 @@ * Initialise is complete, report our presence state */ mosquitto_loop_start(mosq); - mosquitto_publish(mosq, &mqtt_mid_sent, state, 1, (char *)"1", mqtt_qos, 1); + publishBirth(); } #endif } @@ -189,7 +613,6 @@ { #ifdef HAVE_MOSQUITTO_H int rc; - char buf[128]; if (mqtt_use) { /* @@ -197,9 +620,8 @@ * After that, remove the retained topic. */ syslog(LOG_NOTICE, "MQTT disconnecting"); - sprintf(buf, "0"); - mosquitto_publish(mosq, &mqtt_mid_sent, state, strlen(buf), buf, mqtt_qos, true); - mosquitto_publish(mosq, &mqtt_mid_sent, state, 0, NULL, mqtt_qos, true); + publisher(mosq, topic_base((char *)"DBIRTH"), NULL, true); + publisher(mosq, topic_base((char *)"NBIRTH"), NULL, true); mqtt_last_mid = mqtt_mid_sent; mqtt_status = STATUS_WAITING; mqtt_my_shutdown = TRUE; @@ -220,6 +642,7 @@ mosquitto_loop_stop(mosq, FALSE); mosquitto_destroy(mosq); mosquitto_lib_cleanup(); + mqtt_use = FALSE; syslog(LOG_NOTICE, "MQTT disconnected"); } #endif @@ -227,60 +650,3 @@ -void mqtt_publish_int(char *uuid, char *tail, int value) -{ -#ifdef HAVE_MOSQUITTO_H - char topic[1024], buf[128]; - - if (mqtt_use) { - snprintf(topic, 1023, "fermenter/%s/%s/%s", my_hostname, uuid, tail); - snprintf(buf, 127, "%d", value); - mosquitto_publish(mosq, &mqtt_mid_sent, topic, strlen(buf), buf, mqtt_qos, 1); - } -#endif -} - - - -void mqtt_publish_float(char *uuid, char *tail, float value, int decimals) -{ -#ifdef HAVE_MOSQUITTO_H - char topic[1024], buf[128]; - - if (mqtt_use) { - snprintf(topic, 1023, "fermenter/%s/%s/%s", my_hostname, uuid, tail); - snprintf(buf, 127, "%.*f", decimals, value); - mosquitto_publish(mosq, &mqtt_mid_sent, topic, strlen(buf), buf, mqtt_qos, 1); - } -#endif -} - - - -void mqtt_publish_str(char *uuid, char *tail, char *value) -{ -#ifdef HAVE_MOSQUITTO_H - char topic[1024], buf[128]; - - if (mqtt_use) { - snprintf(topic, 1023, "fermenter/%s/%s/%s", my_hostname, uuid, tail); - snprintf(buf, 127, "%s", value); - mosquitto_publish(mosq, &mqtt_mid_sent, topic, strlen(buf), buf, mqtt_qos, 1); - } -#endif -} - - - -void mqtt_publish_clear(char *uuid, char *tail) -{ -#ifdef HAVE_MOSQUITTO_H - char topic[1024]; - - if (mqtt_use) { - snprintf(topic, 1023, "bmsd/%s/%s/%s", my_hostname, uuid, tail); - mosquitto_publish(mosq, &mqtt_mid_sent, topic, 0, NULL, mqtt_qos, 1); - } -#endif -} - diff -r 862de87f9f89 -r cdcd07bbee30 thermferm/mqtt.h --- a/thermferm/mqtt.h Sat Apr 29 17:07:36 2017 +0200 +++ b/thermferm/mqtt.h Mon May 08 16:26:02 2017 +0200 @@ -14,9 +14,7 @@ */ void mqtt_connect(void); void mqtt_disconnect(void); -void mqtt_publish_int(char *, char *, int); -void mqtt_publish_float(char *, char *, float, int); -void mqtt_publish_str(char *, char *, char *); -void mqtt_publish_clear(char *, char *); +void publishDData(units_list *); +void publishNData(bool, int); #endif diff -r 862de87f9f89 -r cdcd07bbee30 thermferm/rdconfig.c --- a/thermferm/rdconfig.c Sat Apr 29 17:07:36 2017 +0200 +++ b/thermferm/rdconfig.c Mon May 08 16:26:02 2017 +0200 @@ -1,5 +1,5 @@ /***************************************************************************** - * Copyright (C) 2014-2016 + * Copyright (C) 2014-2017 * * Michiel Broek * @@ -1022,7 +1022,7 @@ /* * Parse a fermenter unit */ -int parseUnit(xmlDocPtr doc, xmlNodePtr cur, int number) +int parseUnit(xmlDocPtr doc, xmlNodePtr cur/* , int number */) { xmlChar *key; int i, ival; @@ -1416,11 +1416,11 @@ /* * If there is no alias name, create it. */ - if (unit->alias == NULL) { - char an[128]; - sprintf(an, "unit%d", number); - unit->alias = xstrcpy(an); - } +// if (unit->alias == NULL) { +// char an[128]; +// sprintf(an, "unit%d", number); +// unit->alias = xstrcpy(an); +// } if (Config.units == NULL) { Config.units = unit; @@ -1443,8 +1443,8 @@ cur = cur->xmlChildrenNode; while (cur != NULL) { if ((!xmlStrcmp(cur->name, (const xmlChar *)"UNIT"))) { - parseUnit(doc, cur, Config.next_unit); - Config.next_unit++; + parseUnit(doc, cur/* , Config.next_unit*/); +// Config.next_unit++; } cur = cur->next; } diff -r 862de87f9f89 -r cdcd07bbee30 thermferm/server.c --- a/thermferm/server.c Sat Apr 29 17:07:36 2017 +0200 +++ b/thermferm/server.c Mon May 08 16:26:02 2017 +0200 @@ -1,5 +1,5 @@ /***************************************************************************** - * Copyright (C) 2008-2015 + * Copyright (C) 2008-2017 * * Michiel Broek * @@ -2166,6 +2166,7 @@ for (unit = Config.units ; unit; unit = unit->next) { if (strcmp(unit->uuid, param) == 0) { while (1) { + unit->mqtt_flag = 0; rlen = srv_recv(ibuf); if (rlen == -1) { run_pause = FALSE; @@ -2180,6 +2181,7 @@ kwd = strtok(ibuf, ",\0"); val = strtok(NULL, "\0"); if (kwd) { + unit->mqtt_flag = 0; /* * Accept writable data. The client can sent just one line, * but may also sent everything. Simply ignore things we @@ -2189,11 +2191,11 @@ if (unit->name) { if (strcmp(unit->name, val)) { syslog(LOG_NOTICE, "Fermenter unit %s name `%s' to `%s'", unit->uuid, unit->name, val); - mqtt_publish_str(unit->alias, (char *)"name", val); } free(unit->name); } unit->name = xstrcpy(val); + unit->mqtt_flag |= (MQTT_FLAG_MODE); } else if (val && (strcmp(kwd, (char *)"VOLUME") == 0)) { if (sscanf(val, "%f", &fval) == 1) { @@ -2214,6 +2216,7 @@ device_count(TRUE, unit->air_address); } else unit->air_address = NULL; + unit->mqtt_flag |= MQTT_FLAG_AIR; } else if (strcmp(kwd, (char *)"BEER_ADDRESS") == 0) { if (val && unit->beer_address && (strcmp(val, unit->beer_address))) @@ -2227,6 +2230,7 @@ device_count(TRUE, unit->beer_address); } else unit->beer_address = NULL; + unit->mqtt_flag |= MQTT_FLAG_BEER; } else if (strcmp(kwd, (char *)"HEATER_ADDRESS") == 0) { if (val && unit->heater_address && (strcmp(val, unit->heater_address))) @@ -2240,12 +2244,14 @@ device_count(TRUE, unit->heater_address); } else unit->heater_address = NULL; + unit->mqtt_flag |= MQTT_FLAG_HEATER; } else if (val && (strcmp(kwd, (char *)"HEATER_STATE") == 0)) { if ((sscanf(val, "%d", &ival) == 1) && ((ival == 0) || (ival == 100))) { if (unit->heater_state != ival) syslog(LOG_NOTICE, "Fermenter unit %s heater state %d to %d", unit->uuid, unit->heater_state, ival); unit->heater_state = ival; + unit->mqtt_flag |= MQTT_FLAG_HEATER; } } else if (val && (strcmp(kwd, (char *)"HEATER_DELAY") == 0)) { @@ -2267,12 +2273,14 @@ device_count(TRUE, unit->cooler_address); } else unit->cooler_address = NULL; + unit->mqtt_flag |= MQTT_FLAG_COOLER; } else if (val && (strcmp(kwd, (char *)"COOLER_STATE") == 0)) { if ((sscanf(val, "%d", &ival) == 1) && ((ival == 0) || (ival == 100))) { if (unit->cooler_state != ival) syslog(LOG_NOTICE, "Fermenter unit %s cooler state %d to %d", unit->uuid, unit->cooler_state, ival); unit->cooler_state = ival; + unit->mqtt_flag |= MQTT_FLAG_COOLER; } } else if (val && (strcmp(kwd, (char *)"COOLER_DELAY") == 0)) { @@ -2294,12 +2302,14 @@ device_count(TRUE, unit->fan_address); } else unit->fan_address = NULL; + unit->mqtt_flag |= MQTT_FLAG_FAN; } else if (val && (strcmp(kwd, (char *)"FAN_STATE") == 0)) { if ((sscanf(val, "%d", &ival) == 1) && ((ival == 0) || (ival == 100))) { if (unit->fan_state != ival) syslog(LOG_NOTICE, "Fermenter unit %s fan state %d to %d", unit->uuid, unit->fan_state, ival); unit->fan_state = ival; + unit->mqtt_flag |= MQTT_FLAG_FAN; } } else if (val && (strcmp(kwd, (char *)"FAN_DELAY") == 0)) { @@ -2321,12 +2331,14 @@ device_count(TRUE, unit->light_address); } else unit->light_address = NULL; + unit->mqtt_flag |= MQTT_FLAG_LIGHT; } else if (val && (strcmp(kwd, (char *)"LIGHT_STATE") == 0)) { if ((sscanf(val, "%d", &ival) == 1) && ((ival == 0) || (ival == 100))) { if (unit->light_state != ival) syslog(LOG_NOTICE, "Fermenter unit %s light state %d to %d", unit->uuid, unit->light_state, ival); unit->light_state = ival; + unit->mqtt_flag |= MQTT_FLAG_LIGHT; } } else if (val && (strcmp(kwd, (char *)"LIGHT_DELAY") == 0)) { @@ -2361,6 +2373,7 @@ device_count(TRUE, unit->psu_address); } else unit->psu_address = NULL; + unit->mqtt_flag |= MQTT_FLAG_PSU; } else if (val && (strcmp(kwd, (char *)"MODE") == 0)) { for (i = 0; i < 5; i++) { @@ -2392,18 +2405,6 @@ unit->mqtt_flag |= MQTT_FLAG_SP; } } - if (unit->heater_address) - mqtt_publish_int(unit->alias, (char *)"heater", 0); - else - mqtt_publish_clear(unit->alias, (char *)"heater"); - if (unit->cooler_address) - mqtt_publish_int(unit->alias, (char *)"cooler", 0); - else - mqtt_publish_clear(unit->alias, (char *)"cooler"); - if (unit->fan_address) - mqtt_publish_int(unit->alias, (char *)"fan", 0); - else - mqtt_publish_clear(unit->alias, (char *)"fan"); break; } } @@ -2519,19 +2520,7 @@ device_out(unit->cooler_address, unit->cooler_state); device_out(unit->fan_address, unit->fan_state); device_out(unit->light_address, unit->light_state); - if (unit->heater_address) - mqtt_publish_int(unit->alias, (char *)"heater", 0); - else - mqtt_publish_clear(unit->alias, (char *)"heater"); - if (unit->cooler_address) - mqtt_publish_int(unit->alias, (char *)"cooler", 0); - else - mqtt_publish_clear(unit->alias, (char *)"cooler"); - if (unit->fan_address) - mqtt_publish_int(unit->alias, (char *)"fan", 0); - else - mqtt_publish_clear(unit->alias, (char *)"fan"); - unit->mqtt_flag |= (MQTT_FLAG_PROFILE | MQTT_FLAG_SP); + unit->mqtt_flag |= (MQTT_FLAG_PROFILE | MQTT_FLAG_SP | MQTT_FLAG_HEATER | MQTT_FLAG_COOLER | MQTT_FLAG_FAN); } } else if (val && (strcmp(kwd, (char *)"PROF_STATE") == 0)) { @@ -2541,17 +2530,14 @@ case PROFILE_OFF: if (unit->prof_state == PROFILE_DONE) { unit->prof_state = PROFILE_OFF; syslog(LOG_NOTICE, "Fermenter unit %s profile to OFF", unit->uuid); - mqtt_publish_str(unit->alias, (char *)"profile/state", (char *)PROFSTATE[i]); } break; case PROFILE_PAUSE: if (unit->prof_state == PROFILE_RUN) { unit->prof_state = PROFILE_PAUSE; syslog(LOG_NOTICE, "Fermenter unit %s profile PAUSE", unit->uuid); - mqtt_publish_str(unit->alias, (char *)"profile/state", (char *)PROFSTATE[i]); } else if (unit->prof_state == PROFILE_PAUSE) { unit->prof_state = PROFILE_RUN; syslog(LOG_NOTICE, "Fermenter unit %s profile RESUME", unit->uuid); - mqtt_publish_str(unit->alias, (char *)"profile/state", (char *)PROFSTATE[PROFILE_RUN]); } break; case PROFILE_RUN: if (unit->prof_state == PROFILE_OFF) { @@ -2560,7 +2546,6 @@ unit->prof_paused = unit->prof_primary_done = 0; unit->prof_peak_abs = unit->prof_peak_rel = 0.0; syslog(LOG_NOTICE, "Fermenter unit %s profile to RUN", unit->uuid); - mqtt_publish_str(unit->alias, (char *)"profile/state", (char *)PROFSTATE[i]); } break; case PROFILE_DONE: break; /* Command is illegal */ @@ -2568,7 +2553,6 @@ unit->prof_state = PROFILE_OFF; unit->prof_started = 0; syslog(LOG_NOTICE, "Fermenter unit %s profile ABORT", unit->uuid); - mqtt_publish_str(unit->alias, (char *)"profile/state", (char *)PROFSTATE[i]); } break; } @@ -2592,6 +2576,8 @@ } } + if (unit->mqtt_flag) + publishDData(unit); } } } diff -r 862de87f9f89 -r cdcd07bbee30 thermferm/thermferm.c --- a/thermferm/thermferm.c Sat Apr 29 17:07:36 2017 +0200 +++ b/thermferm/thermferm.c Mon May 08 16:26:02 2017 +0200 @@ -1,5 +1,5 @@ /***************************************************************************** - * Copyright (C) 2014-2016 + * Copyright (C) 2014-2017 * * Michiel Broek * @@ -1065,44 +1065,19 @@ /* * Safety, turn everything off */ - unit->mqtt_flag = MQTT_FLAG_MODE; + unit->mqtt_flag = 0; unit->heater_state = unit->cooler_state = unit->fan_state = unit->door_state = unit->light_state = 0; unit->heater_wait = unit->cooler_wait = unit->fan_wait = unit->light_wait = 0; - mqtt_publish_int(unit->alias, (char *)"state", (unit->mode != UNITMODE_OFF) ? 1 : 0); - if (unit->name) - mqtt_publish_str(unit->alias, (char *)"name", unit->name); - else - mqtt_publish_clear(unit->alias, (char *)"name"); - if (unit->heater_address) - mqtt_publish_int(unit->alias, (char *)"heater", 0); - else - mqtt_publish_clear(unit->alias, (char *)"heater"); - if (unit->cooler_address) - mqtt_publish_int(unit->alias, (char *)"cooler", 0); - else - mqtt_publish_clear(unit->alias, (char *)"cooler"); - if (unit->fan_address) - mqtt_publish_int(unit->alias, (char *)"fan", 0); - else - mqtt_publish_clear(unit->alias, (char *)"fan"); - if (unit->air_address) - unit->mqtt_flag |= MQTT_FLAG_AIR; - if (unit->beer_address) - unit->mqtt_flag |= MQTT_FLAG_BEER; if (unit->mode == UNITMODE_PROFILE) { if (!unit->profile) syslog(LOG_NOTICE, "Starting unit `%s' in profile mode, no profile defined.", unit->name); else { syslog(LOG_NOTICE, "Starting unit `%s' in profile state %s.", unit->name, PROFSTATE[unit->prof_state]); - unit->mqtt_flag |= MQTT_FLAG_SP; - unit->mqtt_flag |= MQTT_FLAG_PROFILE; } } else if (unit->mode == UNITMODE_BEER) { syslog(LOG_NOTICE, "Starting unit `%s' beer cooler at %.1f degrees", unit->name, unit->beer_set); - unit->mqtt_flag |= MQTT_FLAG_SP; } else if (unit->mode == UNITMODE_FRIDGE) { syslog(LOG_NOTICE, "Starting unit `%s' as refridgerator at %.1f degrees", unit->name, unit->fridge_set); - unit->mqtt_flag |= MQTT_FLAG_SP; } else if (unit->mode == UNITMODE_NONE) { syslog(LOG_NOTICE, "Starting unit `%s' in inactive state", unit->name); } else { @@ -1184,11 +1159,12 @@ #ifdef HAVE_WIRINGPI_H piUnlock(LOCK_LCD); #endif + bool updateHT = false; if (Config.temp_address) { rc = device_in(Config.temp_address, &temp); if (rc == DEVPRESENT_YES) { if (Config.temp_value != temp) - mqtt_publish_float((char *)"room", (char *)"temperature", temp / 1000.0, 1); + updateHT = true; Config.temp_value = temp; Config.temp_state = 0; #ifdef HAVE_WIRINGPI_H @@ -1218,7 +1194,7 @@ rc = device_in(Config.hum_address, &temp); if (rc == DEVPRESENT_YES) { if (Config.hum_value != temp) - mqtt_publish_float((char *)"room", (char *)"humidity", temp / 1000.0, 1); + updateHT = true; Config.hum_value = temp; Config.hum_state = 0; #ifdef HAVE_WIRINGPI_H @@ -1235,10 +1211,14 @@ } } row++; + if (updateHT) + publishNData(false, MQTT_NODE_HT); LCDunit = 0; for (unit = Config.units; unit; unit = unit->next) { LCDunit++; + unit->mqtt_flag = 0; + if (unit->air_address) { rc = device_in(unit->air_address, &temp); if (rc == DEVPRESENT_YES) { @@ -1297,13 +1277,13 @@ if (unit->door_state == 0) { syslog(LOG_NOTICE, "Unit `%s' door closed", unit->name); unit->door_state = 1; - mqtt_publish_str(unit->alias, (char *)"door", (char *)"closed"); + unit->mqtt_flag |= MQTT_FLAG_DOOR; } } else { if (unit->door_state) { syslog(LOG_NOTICE, "Unit `%s' door opened", unit->name); unit->door_state = 0; - mqtt_publish_str(unit->alias, (char *)"door", (char *)"open"); + unit->mqtt_flag |= MQTT_FLAG_DOOR; } } } else { @@ -1323,13 +1303,13 @@ if (unit->psu_state == 0) { syslog(LOG_NOTICE, "Unit `%s' PSU (12 volt) is on", unit->name); unit->psu_state = 1; - mqtt_publish_str(unit->alias, (char *)"12volt", (char *)"on"); + unit->mqtt_flag |= MQTT_FLAG_PSU; } } else { if (unit->psu_state) { syslog(LOG_NOTICE, "Unit `%s' PSU (12 volt) is off", unit->name); unit->psu_state = 0; - mqtt_publish_str(unit->alias, (char *)"12volt", (char *)"off"); + unit->mqtt_flag |= MQTT_FLAG_PSU; } } } else { @@ -1410,7 +1390,7 @@ } } else { /* - * This method works if the unit has no cooling or if the profile allowd the + * This method works if the unit has no cooling or if the profile allowed the * beer temperature to rise freely. */ if ((unit->beer_temperature / 1000.0) < (unit->prof_peak_abs - 0.5)) { @@ -1561,11 +1541,13 @@ } else { unit->light_state = 0; syslog(LOG_NOTICE, "Unit `%s' lights On => Off", unit->name); + unit->mqtt_flag |= MQTT_FLAG_LIGHT; } } if (!unit->door_state && !unit->light_state) { unit->light_wait = unit->light_delay; /* No delay to turn lights on */ unit->light_state = 1; + unit->mqtt_flag |= MQTT_FLAG_LIGHT; syslog(LOG_NOTICE, "Unit `%s' lights Off => On", unit->name); } device_out(unit->light_address, unit->light_state); @@ -1670,7 +1652,7 @@ syslog(LOG_NOTICE, "Unit `%s' heater %d%% => %d%%", unit->name, unit->heater_state, power); unit->heater_state = power; if (unit->heater_address) - mqtt_publish_int(unit->alias, (char *)"heater", unit->heater_state); + unit->mqtt_flag |= MQTT_FLAG_HEATER; } } } else { @@ -1681,7 +1663,7 @@ syslog(LOG_NOTICE, "Unit `%s' heater On => Off", unit->name); unit->heater_state = 0; if (unit->heater_address) - mqtt_publish_int(unit->alias, (char *)"heater", 0); + unit->mqtt_flag |= MQTT_FLAG_HEATER; } } } @@ -1701,7 +1683,7 @@ syslog(LOG_NOTICE, "Unit `%s' cooler %d%% => %d%%", unit->name, unit->cooler_state, power); unit->cooler_state = power; if (unit->cooler_address) - mqtt_publish_int(unit->alias, (char *)"cooler", unit->cooler_state); + unit->mqtt_flag |= MQTT_FLAG_COOLER; } } } else { @@ -1712,7 +1694,7 @@ syslog(LOG_NOTICE, "Unit `%s' cooler On => Off", unit->name); unit->cooler_state = 0; if (unit->cooler_address) - mqtt_publish_int(unit->alias, (char *)"cooler", 0); + unit->mqtt_flag |= MQTT_FLAG_COOLER; } } } @@ -1738,7 +1720,7 @@ syslog(LOG_NOTICE, "Unit `%s' Fan Off => On", unit->name); unit->fan_state = 100; if (unit->fan_address) - mqtt_publish_int(unit->alias, (char *)"fan", 100); + unit->mqtt_flag |= MQTT_FLAG_FAN; } } } else { @@ -1749,7 +1731,7 @@ syslog(LOG_NOTICE, "Unit `%s' Fan On => Off", unit->name); unit->fan_state = 0; if (unit->fan_address) - mqtt_publish_int(unit->alias, (char *)"fan", 0); + unit->mqtt_flag |= MQTT_FLAG_FAN; } } } @@ -1809,33 +1791,9 @@ /* * Publish MQTT messages set in flag */ - if (unit->mqtt_flag & MQTT_FLAG_SP) { - mqtt_publish_float(unit->alias, (char *)"setpoint/high", LCDspH, 1); - mqtt_publish_float(unit->alias, (char *)"setpoint/low", LCDspL, 1); - } - if (unit->mqtt_flag & MQTT_FLAG_AIR) { - mqtt_publish_float(unit->alias, (char *)"air/temperature", unit->air_temperature / 1000.0, 3); - } - if (unit->mqtt_flag & MQTT_FLAG_BEER) { - mqtt_publish_float(unit->alias, (char *)"beer/temperature", unit->beer_temperature / 1000.0, 3); - } - if (unit->mqtt_flag & MQTT_FLAG_MODE) { - mqtt_publish_str(unit->alias, (char *)"mode", (char *)UNITMODE[unit->mode]); + if (unit->mqtt_flag) { + publishDData(unit); } - if (unit->mqtt_flag & MQTT_FLAG_PROFILE) { - mqtt_publish_str(unit->alias, (char *)"profile/uuid", unit->profile); - mqtt_publish_str(unit->alias, (char *)"profile/state", (char *)PROFSTATE[unit->prof_state]); - for (profile = Config.profiles; profile; profile = profile->next) { - if (strcmp(unit->profile, profile->uuid) == 0) { - mqtt_publish_str(unit->alias, (char *)"profile/name", profile->name); - mqtt_publish_int(unit->alias, (char *)"profile/fridgemode", profile->fridge_mode); - } - } - } - if (unit->mqtt_flag & MQTT_FLAG_PERCENT) { - mqtt_publish_int(unit->alias, (char *)"profile/percent", unit->prof_percent); - } - unit->mqtt_flag = 0; } /* for units */ #ifdef HAVE_WIRINGPI_H @@ -1948,40 +1906,6 @@ * Stop units processing in a neat way */ for (unit = Config.units; unit; unit = unit->next) { - - if (unit->mode != UNITMODE_OFF) { - if (unit->heater_address) { - mqtt_publish_int(unit->alias, (char *)"heater", 0); - mqtt_publish_clear(unit->alias, (char *)"heater"); - } - if (unit->cooler_address) { - mqtt_publish_int(unit->alias, (char *)"cooler", 0); - mqtt_publish_clear(unit->alias, (char *)"cooler"); - } - if (unit->fan_address) { - mqtt_publish_int(unit->alias, (char *)"fan", 0); - mqtt_publish_clear(unit->alias, (char *)"fan"); - } - mqtt_publish_int(unit->alias, (char *)"state", 0); - mqtt_publish_clear(unit->alias, (char *)"state"); - } - mqtt_publish_clear(unit->alias, (char *)"air/temperature"); - mqtt_publish_clear(unit->alias, (char *)"air"); - mqtt_publish_clear(unit->alias, (char *)"beer/temperature"); - mqtt_publish_clear(unit->alias, (char *)"beer"); - mqtt_publish_clear(unit->alias, (char *)"setpoint/high"); - mqtt_publish_clear(unit->alias, (char *)"setpoint/low"); - mqtt_publish_clear(unit->alias, (char *)"setpoint"); - mqtt_publish_clear(unit->alias, (char *)"door"); - mqtt_publish_clear(unit->alias, (char *)"name"); - mqtt_publish_clear(unit->alias, (char *)"mode"); - mqtt_publish_clear(unit->alias, (char *)"12volt"); - mqtt_publish_clear(unit->alias, (char *)"profile/uuid"); - mqtt_publish_clear(unit->alias, (char *)"profile/state"); - mqtt_publish_clear(unit->alias, (char *)"profile/name"); - mqtt_publish_clear(unit->alias, (char *)"profile/fridgemode"); - mqtt_publish_clear(unit->alias, (char *)"profile/percent"); - /* * Turn everything off */ @@ -1991,6 +1915,8 @@ device_out(unit->cooler_address, unit->cooler_state); device_out(unit->fan_address, unit->fan_state); device_out(unit->light_address, unit->light_state); + unit->mqtt_flag = MQTT_FLAG_HEATER | MQTT_FLAG_COOLER | MQTT_FLAG_FAN | MQTT_FLAG_LIGHT; + publishDData(unit); syslog(LOG_NOTICE, "Unit `%s' stopped in mode %s", unit->name, UNITMODE[unit->mode]); } diff -r 862de87f9f89 -r cdcd07bbee30 thermferm/thermferm.h --- a/thermferm/thermferm.h Sat Apr 29 17:07:36 2017 +0200 +++ b/thermferm/thermferm.h Mon May 08 16:26:02 2017 +0200 @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -194,8 +195,18 @@ #define MQTT_FLAG_AIR 0x0002 /* Show air temperature */ #define MQTT_FLAG_BEER 0x0004 /* Show beer temperature */ #define MQTT_FLAG_MODE 0x0008 /* Show unit mode */ -#define MQTT_FLAG_PROFILE 0x0010 /* Show profile settings */ -#define MQTT_FLAG_PERCENT 0x0020 /* Show profile percent */ +#define MQTT_FLAG_HEATER 0x0010 /* Show heater state */ +#define MQTT_FLAG_COOLER 0x0020 /* Show cooler state */ +#define MQTT_FLAG_FAN 0x0040 /* Show fan state */ +#define MQTT_FLAG_DOOR 0x0080 /* Show door state */ +#define MQTT_FLAG_LIGHT 0x0100 /* Show light state */ +#define MQTT_FLAG_PSU 0x0200 /* Show PSU state */ +#define MQTT_FLAG_PROFILE 0x0400 /* Show profile settings */ +#define MQTT_FLAG_PERCENT 0x0800 /* Show profile percent */ + +#define MQTT_NODE_CONTROL 0x0001 /* Show node control */ +#define MQTT_NODE_HT 0x0002 /* Show node humidity/temp */ + /* diff -r 862de87f9f89 -r cdcd07bbee30 www-thermferm/global.php --- a/www-thermferm/global.php Sat Apr 29 17:07:36 2017 +0200 +++ b/www-thermferm/global.php Mon May 08 16:26:02 2017 +0200 @@ -1,6 +1,6 @@ * @@ -63,7 +63,7 @@ unset($_POST['LCDcols']); unset($_POST['LCDrows']); unset($_POST['key']); - load('global.php'); + load('maintenance.php'); } @@ -108,7 +108,7 @@ case 3: $error = 'LCD rows must be 2 or 4'; break; case 99: - load('global.php'); + load('maintenance.php'); break; }