New MQTT protocol

Mon, 08 May 2017 16:26:02 +0200

author
Michiel Broek <mbroek@mbse.eu>
date
Mon, 08 May 2017 16:26:02 +0200
changeset 506
cdcd07bbee30
parent 504
862de87f9f89
child 507
80344f433a78

New MQTT protocol

configure file | annotate | diff | comparison | revisions
configure.ac file | annotate | diff | comparison | revisions
thermferm/devices.c file | annotate | diff | comparison | revisions
thermferm/mqtt.c file | annotate | diff | comparison | revisions
thermferm/mqtt.h file | annotate | diff | comparison | revisions
thermferm/rdconfig.c file | annotate | diff | comparison | revisions
thermferm/server.c file | annotate | diff | comparison | revisions
thermferm/thermferm.c file | annotate | diff | comparison | revisions
thermferm/thermferm.h file | annotate | diff | comparison | revisions
www-thermferm/global.php file | annotate | diff | comparison | revisions
--- 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"
 
--- 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)
--- 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 <mbroek at mbse dot eu>
  *
@@ -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);
 			    }
 			}
--- 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 <mbroek at mbse dot eu>
  *
@@ -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
-}
-
--- 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
--- 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 <mbroek at mbse dot eu>
  *
@@ -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;
     }
--- 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 <mbroek at mbse dot eu>
  *
@@ -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);
 			}
 		    }
 		}
--- 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 <mbroek at mbse dot eu>
  *
@@ -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]);
     }
 
--- 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 <sys/stat.h>
 #include <sys/time.h>
 #include <sys/un.h>
+#include <sys/utsname.h>
 #include <time.h>
 #include <fcntl.h>
 #include <syslog.h>
@@ -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	*/
+
 
 
 /*
--- 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 @@
 <?php
 /*****************************************************************************
- * Copyright (C) 2014
+ * Copyright (C) 2014-2017
  *   
  * Michiel Broek <mbroek at mbse dot eu>
  *
@@ -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;
     }
 

mercurial