Removed useless version marks from the xml configuration. Added DCMD profile configuration to install and delete profiles in a fermenter. Removed the old profiles configuration. Removed useless xml configuration error check because none has been triggered in five years, Removed several obsolete upgrade functions. Updated the web liveview.

Mon, 14 Jan 2019 22:46:27 +0100

author
Michiel Broek <mbroek@mbse.eu>
date
Mon, 14 Jan 2019 22:46:27 +0100
changeset 570
1e0192b295b9
parent 569
9c69d43bfb06
child 571
6f8eda55ec2c

Removed useless version marks from the xml configuration. Added DCMD profile configuration to install and delete profiles in a fermenter. Removed the old profiles configuration. Removed useless xml configuration error check because none has been triggered in five years, Removed several obsolete upgrade functions. Updated the web liveview.

thermferm/Makefile file | annotate | diff | comparison | revisions
thermferm/devices.c file | annotate | diff | comparison | revisions
thermferm/mqtt.c 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/index.php file | annotate | diff | comparison | revisions
www-thermferm/liveview.php file | annotate | diff | comparison | revisions
www-thermferm/maintenance.php file | annotate | diff | comparison | revisions
www-thermferm/profiles.php file | annotate | diff | comparison | revisions
--- a/thermferm/Makefile	Thu Jan 10 16:33:42 2019 +0100
+++ b/thermferm/Makefile	Mon Jan 14 22:46:27 2019 +0100
@@ -55,7 +55,7 @@
 # DO NOT DELETE THIS LINE - MAKE DEPEND RELIES ON IT
 # Dependencies generated by make depend
 rc-switch.o: thermferm.h xutil.h rc-switch.h
-mqtt.o: thermferm.h logger.h devices.h xutil.h mqtt.h
+mqtt.o: thermferm.h rdconfig.h logger.h devices.h xutil.h mqtt.h
 slcd.o: thermferm.h slcd.h futil.h xutil.h
 panel.o: thermferm.h lcd-pcf8574.h slcd.h panel.h
 devices.o: thermferm.h devices.h rc-switch.h panel.h xutil.h
--- a/thermferm/devices.c	Thu Jan 10 16:33:42 2019 +0100
+++ b/thermferm/devices.c	Mon Jan 14 22:46:27 2019 +0100
@@ -1,5 +1,5 @@
 /*****************************************************************************
- * Copyright (C) 2014..2018
+ * Copyright (C) 2014..2019
  *   
  * Michiel Broek <mbroek at mbse dot eu>
  *
@@ -481,7 +481,6 @@
 		    for (i = 0; i < subdevices; i++) {
 			ndev = (devices_list *)malloc(sizeof(devices_list));
 			ndev->next = NULL;
-			ndev->version = 1;
 			ndev->uuid = malloc(37);
 			uuid_generate(uu);
 			uuid_unparse(uu, ndev->uuid);
@@ -642,7 +641,6 @@
     for (i = found; i < subdevices; i++) {
 	ndev = (devices_list *)malloc(sizeof(devices_list));
 	ndev->next = NULL;
-	ndev->version = 1;
 	ndev->uuid = malloc(37);
 	uuid_generate(uu);
 	uuid_unparse(uu, ndev->uuid);
--- a/thermferm/mqtt.c	Thu Jan 10 16:33:42 2019 +0100
+++ b/thermferm/mqtt.c	Mon Jan 14 22:46:27 2019 +0100
@@ -21,6 +21,7 @@
  *****************************************************************************/
 
 #include "thermferm.h"
+#include "rdconfig.h"
 #include "logger.h"
 #include "devices.h"
 #include "xutil.h"
@@ -152,7 +153,7 @@
 
 void my_log_callback(struct mosquitto *my_mosq, void *obj, int level, const char *str)
 {
-    syslog(LOG_NOTICE, "MQTT: %s", str);
+//    syslog(LOG_NOTICE, "MQTT: %s", str);
     if (debug)
     	fprintf(stdout, "MQTT: %s\n", str);
 }
@@ -163,7 +164,8 @@
 {
     char		*message_type, *message_node, *message_alias;
     units_list		*unit;
-    struct json_object	*jobj, *metric, *val, *setpoint;
+    prof_step           *step, *oldstep;
+    struct json_object	*jobj, *metric, *val, *setpoint, *profile, *profile1, *steps, *step1;
     time_t		timestamp;
     int			timediff;
 
@@ -205,13 +207,16 @@
 			    return;
 			}
 		    }
+
+		    /*
+		     * DCMD, commands and configuration changes for a single fermenter.
+		     */
 		    if ((strcmp(message_type, "DCMD") == 0) && message_node && message_alias) {
 			syslog(LOG_NOTICE, "%s", (char *)json_object_get_string(metric));
 			for (unit = Config.units ; unit; unit = unit->next) {
 			    if (strcmp(unit->alias, message_alias) == 0) {
 				syslog(LOG_NOTICE, "MQTT: DCMD for %s/%s", (char *)message_node, (char *)message_alias);
 			    	if (json_object_object_get_ex(metric, "stage", &val)) {
-		//		    syslog(LOG_NOTICE, "Change state %s", UNITSTAGE[unit->stage]);
 				    for (int i = 0; i < 4; i++) {
 					if (strcmp((char *)json_object_get_string(val), UNITSTAGE[i]) == 0) {
 				    	    if (unit->stage != i) {
@@ -223,7 +228,7 @@
 					}
 				    }
 			    	}
-				printf("start mode\n");
+
 				if (json_object_object_get_ex(metric, "mode", &val)) {
 				    for (int i = 0; i < 4; i++) {
 					if (strcmp((char *)json_object_get_string(val), UNITMODE[i]) == 0) {
@@ -255,7 +260,7 @@
 						     */
 						    unit->prof_target_lo = unit->prof_target_hi = 20.0;
 						    unit->prof_fridge_mode = 0;
-						    if (unit->profile) {
+						    if (unit->profile_uuid) {
 							unit->mqtt_flag |= MQTT_FLAG_DATA;
 						    }
 						}
@@ -264,28 +269,25 @@
 					}
 				    }
 				}
-				printf("start setpoint\n");
+
 				if (json_object_object_get_ex(metric, "setpoint", &setpoint)) {
 				    if ((unit->mode == UNITMODE_FRIDGE) || (unit->mode == UNITMODE_BEER)) {
 					/*
-					 * Only set new setpoints if running as FRIDGE or in BEER mode.
+					 * Only set new setpoints if running in FRIDGE or in BEER mode.
 					 */
-				        if (json_object_object_get_ex(setpoint, "low", &val)) {
+				        if (json_object_object_get_ex(setpoint, "low", &val))
 					    unit->PID_heat->SetP = json_object_get_double(val);
-				    	}
-				    	if (json_object_object_get_ex(setpoint, "high", &val)) {
+				    	if (json_object_object_get_ex(setpoint, "high", &val))
 					    unit->PID_cool->SetP = json_object_get_double(val);
-				    	}
-					if (unit->mode == UNITMODE_FRIDGE) {
+					if (unit->mode == UNITMODE_FRIDGE)
 					    unit->fridge_set = unit->PID_heat->SetP + ((unit->PID_cool->SetP - unit->PID_heat->SetP) / 2);
-					} else {
+					else
 					    unit->beer_set = unit->PID_heat->SetP + ((unit->PID_cool->SetP - unit->PID_heat->SetP) / 2);
-					}
 					unit->mqtt_flag |= MQTT_FLAG_DATA;
 					syslog(LOG_NOTICE, "DCMD change fermenter %s: setpoints %.1f %.1f", message_alias, unit->PID_heat->SetP, unit->PID_cool->SetP);
 				    }
 				}
-				printf("start heater\n");
+
 				if ((json_object_object_get_ex(metric, "heater", &setpoint)) && (unit->mode == UNITMODE_NONE)) {
 				    if (json_object_object_get_ex(setpoint, "state", &val)) {
 					if (json_object_get_int(val) != unit->heater_state) {
@@ -297,6 +299,7 @@
 					}
 				    }
 				}
+
 				if ((json_object_object_get_ex(metric, "cooler", &setpoint)) && (unit->mode == UNITMODE_NONE)) {
 				    if (json_object_object_get_ex(setpoint, "state", &val)) {
 					if (json_object_get_int(val) != unit->cooler_state) {
@@ -308,6 +311,7 @@
 					}
 				    }
 				}
+
 				if ((json_object_object_get_ex(metric, "fan", &setpoint)) && (unit->mode == UNITMODE_NONE)) {
 				    if (json_object_object_get_ex(setpoint, "state", &val)) {
 					if (json_object_get_int(val) != unit->fan_state) {
@@ -317,6 +321,7 @@
 					}
 				    }
 				}
+
 				if ((json_object_object_get_ex(metric, "light", &setpoint)) && (unit->mode == UNITMODE_NONE)) {
 				    if (json_object_object_get_ex(setpoint, "state", &val)) {
 					if (json_object_get_int(val) != unit->light_state) {
@@ -326,7 +331,7 @@
 					}
 				    }
 				}
-				printf("start product\n");
+
 				if ((json_object_object_get_ex(metric, "product", &setpoint)) && (unit->mode == UNITMODE_OFF)) {
 				    if (json_object_object_get_ex(setpoint, "code", &val)) {
 					if (strcmp((char *)json_object_get_string(val), unit->product_code)) {
@@ -345,11 +350,134 @@
 					}
 				    }
 				}
+
+				if (json_object_object_get_ex(metric, "profile", &profile)) {
+				    if (json_object_object_get_ex(profile, "command", &profile1)) {
+					syslog(LOG_NOTICE, "profile command");
+
+				    } else if (json_object_object_get_ex(profile, "uuid", &profile1)) {
+//					syslog(LOG_NOTICE, "profile new profile");
+					if ((unit->prof_state == PROFILE_OFF) || (unit->prof_state == PROFILE_DONE) || (unit->prof_state == PROFILE_ABORT)) {
+					    if (unit->profile_uuid)
+						free(unit->profile_uuid);
+					    if (unit->profile_name)
+						free(unit->profile_name);
+					    if (unit->profile_steps) {
+						for (step = unit->profile_steps; step; step = oldstep) {
+						    if (step->name)
+							free(step->name);
+						    oldstep = step->next;
+						    free(step);
+						}
+					    }
+					    unit->profile_steps = NULL;
+					    unit->profile_duration = unit->profile_totalsteps = 0;
+//					    syslog(LOG_NOTICE, "profile new profile: old cleared");
+
+					    unit->profile_uuid = xstrcpy((char *)json_object_get_string(profile1));
+					    if (json_object_object_get_ex(profile, "name", &val)) {
+						unit->profile_name = xstrcpy((char *)json_object_get_string(val));
+					    }
+					    if (json_object_object_get_ex(profile, "inittemp", &setpoint)) {
+						if (json_object_object_get_ex(setpoint, "low", &val)) {
+						    unit->profile_inittemp_lo = json_object_get_double(val);
+						}
+						if (json_object_object_get_ex(setpoint, "high", &val)) {
+						    unit->profile_inittemp_hi = json_object_get_double(val);
+						}
+					    }
+					    if (json_object_object_get_ex(profile, "fridgemode", &val)) {
+						unit->profile_fridge_mode = json_object_get_int(val);
+						if (unit->profile_fridge_mode)
+						    unit->profile_fridge_mode = 100;
+					    }
+					    if (json_object_object_get_ex(profile, "steps", &steps)) {
+						int arraylen = json_object_array_length(steps);
+						syslog(LOG_NOTICE, "profile new profile: start %d steps", arraylen);
+						for (int i = 0; i < arraylen; i++) {
+						    /*
+						     * Parse the array of steps
+						     */
+						    step1 = json_object_array_get_idx(steps, i);
+						    unit->profile_totalsteps++;
+
+						    step = (prof_step *)malloc(sizeof(prof_step));
+						    step->next = NULL;
+						    step->name = NULL;
+						    step->steptime = step->resttime = step->fridge_mode = 0;
+						    step->target_lo = step->target_hi = 20.0;
+
+						    if (json_object_object_get_ex(step1, "name", &val)) {
+							step->name = xstrcpy((char *)json_object_get_string(val));
+						    }
+						    if (json_object_object_get_ex(step1, "steptime", &val)) {
+							step->steptime = json_object_get_int(val);
+							unit->profile_duration += step->steptime;
+						    }
+						    if (json_object_object_get_ex(step1, "resttime", &val)) {
+							step->resttime = json_object_get_int(val);
+							unit->profile_duration += step->resttime;
+						    }
+						    if (json_object_object_get_ex(step1, "fridgemode", &val)) {
+							step->fridge_mode = json_object_get_int(val);
+							if (step->fridge_mode)
+							    step->fridge_mode = 100;
+						    }
+						    if (json_object_object_get_ex(step1, "target_lo", &val)) {
+							step->target_lo = json_object_get_double(val);
+						    }
+						    if (json_object_object_get_ex(step1, "target_hi", &val)) {
+							step->target_hi = json_object_get_double(val);
+						    }
+
+						    syslog(LOG_NOTICE, "profile new profile: add step %d", unit->profile_totalsteps);
+						    if (unit->profile_steps == NULL) {
+							unit->profile_steps = step;
+						    } else {
+							for (oldstep = unit->profile_steps; oldstep; oldstep = oldstep->next) {
+							    if (oldstep->next == NULL) {
+								oldstep->next = step;
+								break;
+							    }
+							}
+						    }
+					    	}
+					    }
+					    unit->mqtt_flag |= MQTT_FLAG_DATA;
+					    syslog(LOG_NOTICE, "DCMD change fermenter %s: install profile `%s'", message_alias, unit->profile_name);
+					    wrconfig();
+					}
+				    } else {
+					if ((unit->prof_state == PROFILE_OFF) || (unit->prof_state == PROFILE_DONE) || (unit->prof_state == PROFILE_ABORT)) {
+					    syslog(LOG_NOTICE, "DCMD change fermenter %s: delete profile `%s'", message_alias, unit->profile_name);
+					    if (unit->profile_uuid)
+						free(unit->profile_uuid);
+					    if (unit->profile_name)
+						free(unit->profile_name);
+					    unit->profile_uuid = unit->profile_name = NULL;
+					    if (unit->profile_steps) {
+						for (step = unit->profile_steps; step; step = oldstep) {
+						    if (step->name)
+							free(step->name);
+						    oldstep = step->next;
+						    free(step);
+						}
+					    }
+					    unit->profile_steps = NULL;
+					    unit->profile_inittemp_lo = unit->profile_inittemp_hi = 20.0;
+					    unit->prof_percent = unit->profile_fridge_mode = 0;
+					    unit->prof_state = PROFILE_OFF;
+					    unit->profile_duration = unit->profile_totalsteps = 0;
+					    unit->prof_started = unit->prof_paused = unit->prof_primary_done = (time_t)0;
+					    unit->prof_peak_abs = unit->prof_peak_rel = 0.0;
+					    unit->mqtt_flag |= MQTT_FLAG_DATA;
+					    wrconfig();
+					}
+				    }
+				}
 			    }
+
 			    if (unit->mqtt_flag) {
-			    	printf("do mqtt flag\n");
-			        if (debug)
-				    fprintf(stdout, "flag value %d\n", unit->mqtt_flag);
 			    	if (unit->mqtt_flag & MQTT_FLAG_BIRTH) {
 				    publishDBirth(unit);
 			    	} else {
@@ -360,12 +488,9 @@
 			    	}
 			    	unit->mqtt_flag |= MQTT_FLAG_DLOG;      // Something to log
 			    }
-			    printf("einde unit %s\n", unit->alias);
 			}
-			printf("return\n");
 			return;
 		    }
-		    printf("metric: %s\n", (char *)json_object_get_string(metric));
 		    syslog(LOG_NOTICE, "MQTT: %s payload not understood\n", (char *)message->payload);
 		    return;
 		}
@@ -447,7 +572,6 @@
     char		*payload = NULL;
     char		buf[128];
     bool		comma = false;
-    profiles_list       *profile;
     prof_step           *pstep;
 
     payload = xstrcpy((char *)"{");
@@ -618,7 +742,7 @@
 	payload = xstrcat(payload, (char *)",\"door\":{\"address\":\"");
 	payload = xstrcat(payload, unit->door_address);
 	payload = xstrcat(payload, (char *)"\",\"state\":");
-	sprintf(buf, "%d", unit->door_state);
+	sprintf(buf, "%d", (unit->door_state) ? 0:1);
 	payload = xstrcat(payload, buf);
 	payload = xstrcat(payload, (char *)"}");
     } else {
@@ -659,59 +783,59 @@
     /*
      * Loaded profile and state
      */
-    if (unit->profile) {
-	for (profile = Config.profiles; profile; profile = profile->next) {
-	    if (strcmp(unit->profile, profile->uuid) == 0) {
-		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 *)"\",\"state\":\"");
-		payload = xstrcat(payload, (char *)PROFSTATE[unit->prof_state]);
-		payload = xstrcat(payload, (char *)"\",\"percent\":");
-		sprintf(buf, "%d", unit->prof_percent);
+    if (unit->profile_uuid) {
+	payload = xstrcat(payload, (char *)",\"profile\":{\"uuid\":\"");
+	payload = xstrcat(payload, unit->profile_uuid);
+	payload = xstrcat(payload, (char *)"\",\"name\":\"");
+	payload = xstrcat(payload, unit->profile_name);
+	payload = xstrcat(payload, (char *)"\",\"state\":\"");
+	payload = xstrcat(payload, (char *)PROFSTATE[unit->prof_state]);
+	payload = xstrcat(payload, (char *)"\",\"percent\":");
+	sprintf(buf, "%d", unit->prof_percent);
+	payload = xstrcat(payload, buf);
+	payload = xstrcat(payload, (char *)",\"inittemp\":{\"low\":");
+	sprintf(buf, "%.1f", unit->profile_inittemp_lo);
+	payload = xstrcat(payload, buf);
+	payload = xstrcat(payload, (char *)",\"high\":");
+	sprintf(buf, "%.1f", unit->profile_inittemp_hi);
+	payload = xstrcat(payload, buf);
+	payload = xstrcat(payload, (char *)"},\"fridgemode\":");
+	sprintf(buf, "%d", unit->profile_fridge_mode);
+	payload = xstrcat(payload, buf);
+	comma = false;
+	if (unit->profile_steps) {
+	    payload = xstrcat(payload, (char *)",\"steps\":[");
+	    for (pstep = unit->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 *)",\"inittemp\":{\"low\":");
-		sprintf(buf, "%.1f", profile->inittemp_lo);
+		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", profile->inittemp_hi);
+		sprintf(buf, "%.1f", pstep->target_hi);
 		payload = xstrcat(payload, buf);
 		payload = xstrcat(payload, (char *)"},\"fridgemode\":");
-		sprintf(buf, "%d", profile->fridge_mode);
+		sprintf(buf, "%d", pstep->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");
+		if (pstep->name) {
+		    payload = xstrcat(payload, (char *)",\"name\":\"");
+		    payload = xstrcat(payload, pstep->name);
+		    payload = xstrcat(payload, (char *)"\"");
 		}
 		payload = xstrcat(payload, (char *)"}");
-		break;
+		comma = true;
 	    }
+	    payload = xstrcat(payload, (char *)"]");
+	} else {
+	    payload = xstrcat(payload, (char *)",\"steps\":null");
 	}
+	payload = xstrcat(payload, (char *)"}");
     } else {
 	payload = xstrcat(payload, (char *)",\"profile\":null");
     }
--- a/thermferm/rdconfig.c	Thu Jan 10 16:33:42 2019 +0100
+++ b/thermferm/rdconfig.c	Mon Jan 14 22:46:27 2019 +0100
@@ -1,5 +1,5 @@
 /*****************************************************************************
- * Copyright (C) 2014-2018
+ * Copyright (C) 2014-2019
  *   
  * Michiel Broek <mbroek at mbse dot eu>
  *
@@ -41,11 +41,13 @@
 const char	PIDMODE[3][5] = { "NONE", "AUTO", "BOO" };
 
 
+
+int parseSteps(xmlDocPtr doc, xmlNodePtr cur, prof_step **step);
+
 void killconfig(void)
 {
     units_list		*tmp2, *oldtmp2;
-    profiles_list	*tmp3, *oldtmp3;
-    prof_step		*tmp4, *oldtmp4;
+    prof_step		*step, *oldstep;
     devices_list	*device, *olddev;
 #ifdef USE_SIMULATOR
     simulator_list	*simulator, *oldsim;
@@ -108,8 +110,18 @@
 	    free(tmp2->door_address);
 	if (tmp2->psu_address)
 	    free(tmp2->psu_address);
-	if (tmp2->profile)
-	    free(tmp2->profile);
+	if (tmp2->profile_uuid)
+	    free(tmp2->profile_uuid);
+	if (tmp2->profile_name)
+	    free(tmp2->profile_name);
+	if (tmp2->profile_steps) {
+	    for (step = tmp2->profile_steps; step; step = oldstep) {
+		if (step->name)
+		    free(step->name);
+		oldstep = step->next;
+		free(step);
+	    }
+	}
 	if (tmp2->PID_cool)
 	    free(tmp2->PID_cool);
 	if (tmp2->PID_heat)
@@ -118,22 +130,6 @@
     }
     Config.units = NULL;
 
-    for (tmp3 = Config.profiles; tmp3; tmp3 = oldtmp3) {
-	oldtmp3 = tmp3->next;
-	if (tmp3->uuid)
-	    free(tmp3->uuid);
-	if (tmp3->name)
-	    free(tmp3->name);
-	if (tmp3->steps) {
-	    for (tmp4 = tmp3->steps; tmp4; tmp4 = oldtmp4) {
-		oldtmp4 = tmp4->next;
-		free(tmp4);
-	    }
-	}
-	free(tmp3);
-    }
-    Config.profiles = NULL;
-
     for (device = Config.devices; device; device = olddev) {
 	olddev = device->next;
 	if (device->uuid)
@@ -175,7 +171,6 @@
     xmlTextWriterPtr	writer;
     xmlBufferPtr	buf;
     units_list		*tmp3;
-    profiles_list	*tmp4;
     prof_step		*tmp5;
     devices_list	*device;
 #ifdef USE_SIMULATOR
@@ -208,823 +203,253 @@
 
     /* 
      * Start the document with the xml default for the version,
-     * encoding ISO 8859-1 and the default for the standalone
-     * declaration. 
+     * encoding UTF-8 and the default for the standalone declaration. 
      */
-    if ((rc = xmlTextWriterStartDocument(writer, NULL, MY_ENCODING, NULL)) < 0) {
-	syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterStartDocument");
-	return 1;
-    }
+    xmlTextWriterStartDocument(writer, NULL, MY_ENCODING, NULL);
 
     /* 
      * Start an element named "THERMFERM". Since thist is the first
      * element, this will be the root element of the document.
      */
-    if ((rc = xmlTextWriterStartElement(writer, BAD_CAST "THERMFERM")) < 0) {
-	syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterStartElement");
-	return 1;
-    }
+    xmlTextWriterStartElement(writer, BAD_CAST "THERMFERM");
+
+    xmlTextWriterWriteFormatElement(writer, BAD_CAST "NAME", "%s", Config.name);
+    xmlTextWriterWriteFormatElement(writer, BAD_CAST "UUID", "%s", Config.uuid);
+    xmlTextWriterWriteFormatElement(writer, BAD_CAST "LISTEN_PORT", "%d", Config.my_port);
+    xmlTextWriterWriteFormatElement(writer, BAD_CAST "TEMPFORMAT", "%c", Config.tempFormat);
 
-    /* 
-     * Add an attribute with name "VERSION" and value "1" to THERMFERM. 
-     */
-    if ((rc = xmlTextWriterWriteElement(writer, BAD_CAST "VERSION", BAD_CAST "1")) < 0) {
-	syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteElement");
-	return 1;
-    }
-    if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "NAME", "%s", Config.name)) < 0) {
-	syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
-	return 1;
-    }
-    if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "UUID", "%s", Config.uuid)) < 0) {
-	syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
-	return 1;
-    }
-    if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "LISTEN_PORT", "%d", Config.my_port)) < 0) {
-	syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
-	return 1;
-    }
-    if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "TEMPFORMAT", "%c", Config.tempFormat)) < 0) {
-	syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
-	return 1;
-    }
-    if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "TEMP_ADDRESS", "%s", Config.temp_address)) < 0) {
-	syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
-	return 1;
-    }
-    if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "TEMP_STATE", "%d", Config.temp_state)) < 0) {
-	syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
-	return 1;                           
-    }
-    if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "TEMP_VALUE", "%d", Config.temp_value)) < 0) {
-	syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
-	return 1;
-    }
-    if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "HUM_ADDRESS", "%s", Config.hum_address)) < 0) {
-	syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
-	return 1;
-    }   
-    if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "HUM_STATE", "%d", Config.hum_state)) < 0) {
-	syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
-	return 1;    
-    }   
-    if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "HUM_VALUE", "%d", Config.hum_value)) < 0) {
-	syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
-	return 1;
-    }
-    if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "TEMP_HUM_IDX", "%d", Config.temp_hum_idx)) < 0) {
-	syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
-	return 1;
-    }
-    if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "NEXT_UNIT", "%d", Config.next_unit)) < 0) {
-	syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
-	return 1;
-    }
-    if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "MQTT_HOST", "%s", Config.mqtt_host)) < 0) {
-	syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
-	return 1;
-    }
-    if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "MQTT_PORT", "%d", Config.mqtt_port)) < 0) {
-	syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
-	return 1;
-    }
+    xmlTextWriterWriteFormatElement(writer, BAD_CAST "TEMP_ADDRESS", "%s", Config.temp_address);
+    xmlTextWriterWriteFormatElement(writer, BAD_CAST "TEMP_STATE", "%d", Config.temp_state);
+    xmlTextWriterWriteFormatElement(writer, BAD_CAST "TEMP_VALUE", "%d", Config.temp_value);
+    xmlTextWriterWriteFormatElement(writer, BAD_CAST "HUM_ADDRESS", "%s", Config.hum_address);
+    xmlTextWriterWriteFormatElement(writer, BAD_CAST "HUM_STATE", "%d", Config.hum_state);
+    xmlTextWriterWriteFormatElement(writer, BAD_CAST "HUM_VALUE", "%d", Config.hum_value);
+    xmlTextWriterWriteFormatElement(writer, BAD_CAST "TEMP_HUM_IDX", "%d", Config.temp_hum_idx);
+
+    xmlTextWriterWriteFormatElement(writer, BAD_CAST "NEXT_UNIT", "%d", Config.next_unit);
+
+    xmlTextWriterWriteFormatElement(writer, BAD_CAST "MQTT_HOST", "%s", Config.mqtt_host);
+    xmlTextWriterWriteFormatElement(writer, BAD_CAST "MQTT_PORT", "%d", Config.mqtt_port);
     if (Config.mqtt_username && Config.mqtt_password) {
-    	if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "MQTT_USER", "%s", Config.mqtt_username)) < 0) {
-	    syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
-	    return 1;
-	}
-    	if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "MQTT_PASS", "%s", Config.mqtt_password)) < 0) {
-	    syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
-	    return 1;
-	}
+    	xmlTextWriterWriteFormatElement(writer, BAD_CAST "MQTT_USER", "%s", Config.mqtt_username);
+    	xmlTextWriterWriteFormatElement(writer, BAD_CAST "MQTT_PASS", "%s", Config.mqtt_password);
     }
 
     /* 
      * Start an element named "LCDS" as child of THERMFERM.
      */
-    if ((rc = xmlTextWriterStartElement(writer, BAD_CAST "LCDS")) < 0) {
-	syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterStartElement");
-	return 1;
-    }
+    xmlTextWriterStartElement(writer, BAD_CAST "LCDS");
     /*
      * Start one LCD. It is possible to connect 7 LCD displays on the i2c bus.
      * However this program doesn't use more then one yet.
      */
-    if ((rc = xmlTextWriterStartElement(writer, BAD_CAST "LCD")) < 0) {
-	syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterStartElement");
-	return 1;
-    }
-    if ((rc = xmlTextWriterWriteElement(writer, BAD_CAST "VERSION", BAD_CAST "1")) < 0) {
-	syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteElement");
-	return 1;
-    }
-    if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "ADDRESS", "0x%x", Config.lcd_address)) < 0) {
-	syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
-	return 1;
-    }
-    if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "COLUMNS", "%d", Config.lcd_cols)) < 0) {
-	syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
-	return 1;
-    }
-    if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "ROWS", "%d", Config.lcd_rows)) < 0) {
-	syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
-	return 1;
-    }
-    /* 
-     * Close the element named LCD.
-     */
-    if ((rc = xmlTextWriterEndElement(writer)) < 0) {
-	syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterEndElement");
-	return 1;
-    }
-    /*
-     * Close the element LCDS.
-     */
-    if ((rc = xmlTextWriterEndElement(writer)) < 0) {
-	syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterEndElement");
-	return 1;
-    }
+    xmlTextWriterStartElement(writer, BAD_CAST "LCD");
+    xmlTextWriterWriteFormatElement(writer, BAD_CAST "ADDRESS", "0x%x", Config.lcd_address);
+    xmlTextWriterWriteFormatElement(writer, BAD_CAST "COLUMNS", "%d", Config.lcd_cols);
+    xmlTextWriterWriteFormatElement(writer, BAD_CAST "ROWS", "%d", Config.lcd_rows);
+    xmlTextWriterEndElement(writer);	// close LCD
+    xmlTextWriterEndElement(writer);	// close LCDS
 
     /*
      * Fermenter units
      */
     if (Config.units) {
-	if ((rc = xmlTextWriterStartElement(writer, BAD_CAST "FERMENTERS")) < 0) {
-	    syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterStartElement");
-	    return 1;
-	}
+	xmlTextWriterStartElement(writer, BAD_CAST "FERMENTERS");
 	for (tmp3 = Config.units; tmp3; tmp3 = tmp3->next) {
-	    /*
-	     * Only configuration items are written, measured values and states
-	     * are written to a state file.
-	     */
-	    if ((rc = xmlTextWriterStartElement(writer, BAD_CAST "UNIT")) < 0) {
-		syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterStartElement");
-		return 1;
-	    }
-	    if ((rc = xmlTextWriterWriteElement(writer, BAD_CAST "VERSION", BAD_CAST "1")) < 0) {
-		syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteElement");
-		return 1;
-	    }
-	    if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "UUID", "%s", tmp3->uuid)) < 0) {
-		syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
-		return 1;
-	    }
-	    if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PRODUCT_UUID", "%s", tmp3->product_uuid)) < 0) {
-		syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
-		return 1;
-	    }
-	    if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PRODUCT_CODE", "%s", tmp3->product_code)) < 0) {
-		syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
-		return 1;
-	    }
-	    if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PRODUCT_NAME", "%s", tmp3->product_name)) < 0) {
-		syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
-		return 1;
-	    }
-	    if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "ALIAS", "%s", tmp3->alias)) < 0) {
-		syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
-		return 1;
-	    }
-	    if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "VOLUME", "%.1f", tmp3->volume)) < 0) {
-		syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
-		return 1;
-	    }
+	    xmlTextWriterStartElement(writer, BAD_CAST "FERMENTER");
+	    xmlTextWriterWriteFormatElement(writer, BAD_CAST "UUID", "%s", tmp3->uuid);
+	    xmlTextWriterWriteFormatElement(writer, BAD_CAST "PRODUCT_UUID", "%s", tmp3->product_uuid);
+	    xmlTextWriterWriteFormatElement(writer, BAD_CAST "PRODUCT_CODE", "%s", tmp3->product_code);
+	    xmlTextWriterWriteFormatElement(writer, BAD_CAST "PRODUCT_NAME", "%s", tmp3->product_name);
+	    xmlTextWriterWriteFormatElement(writer, BAD_CAST "ALIAS", "%s", tmp3->alias);
+	    xmlTextWriterWriteFormatElement(writer, BAD_CAST "VOLUME", "%.1f", tmp3->volume);
+
 	    if (tmp3->air_address) {
-	    	if (((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "AIR_ADDRESS", "%s", tmp3->air_address)) < 0)) {
-		    syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
-		    return 1;
-	    	}
-		if (((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "AIR_STATE", "%d", tmp3->air_state)) < 0)) {
-		    syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
-		    return 1;
-		}
-		if (((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "AIR_TEMPERATURE", "%d", tmp3->air_temperature)) < 0)) {
-		    syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
-		    return 1;
-		}
-		if (((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "AIR_IDX", "%d", tmp3->air_idx)) < 0)) {
-		    syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
-		    return 1;
-		}
+	    	xmlTextWriterWriteFormatElement(writer, BAD_CAST "AIR_ADDRESS", "%s", tmp3->air_address);
+		xmlTextWriterWriteFormatElement(writer, BAD_CAST "AIR_STATE", "%d", tmp3->air_state);
+		xmlTextWriterWriteFormatElement(writer, BAD_CAST "AIR_TEMPERATURE", "%d", tmp3->air_temperature);
+		xmlTextWriterWriteFormatElement(writer, BAD_CAST "AIR_IDX", "%d", tmp3->air_idx);
 	    }
 	    if (tmp3->beer_address) {
-	    	if (((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "BEER_ADDRESS", "%s", tmp3->beer_address)) < 0)) {
-		    syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
-		    return 1;
-	    	}
-		if (((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "BEER_STATE", "%d", tmp3->beer_state)) < 0)) {
-		    syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
-		    return 1;
-		}
-		if (((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "BEER_TEMPERATURE", "%d", tmp3->beer_temperature)) < 0)) {
-		    syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
-		    return 1;
-		}
-		if (((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "BEER_IDX", "%d", tmp3->beer_idx)) < 0)) {
-		    syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
-		    return 1;
-		}
+	    	xmlTextWriterWriteFormatElement(writer, BAD_CAST "BEER_ADDRESS", "%s", tmp3->beer_address);
+		xmlTextWriterWriteFormatElement(writer, BAD_CAST "BEER_STATE", "%d", tmp3->beer_state);
+		xmlTextWriterWriteFormatElement(writer, BAD_CAST "BEER_TEMPERATURE", "%d", tmp3->beer_temperature);
+		xmlTextWriterWriteFormatElement(writer, BAD_CAST "BEER_IDX", "%d", tmp3->beer_idx);
 	    }
 	    if (tmp3->chiller_address) {
-		if (((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "CHILLER_ADDRESS", "%s", tmp3->chiller_address)) < 0)) {
-		    syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
-		    return 1;
-		}
-		if (((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "CHILLER_STATE", "%d", tmp3->chiller_state)) < 0)) {
-		    syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
-		    return 1;
-		}
-		if (((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "CHILLER_TEMPERATURE", "%d", tmp3->chiller_temperature)) < 0)) {
-		    syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
-		    return 1;
-		}
-		if (((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "CHILLER_IDX", "%d", tmp3->chiller_idx)) < 0)) {
-		    syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
-		    return 1;
-		}
+		xmlTextWriterWriteFormatElement(writer, BAD_CAST "CHILLER_ADDRESS", "%s", tmp3->chiller_address);
+		xmlTextWriterWriteFormatElement(writer, BAD_CAST "CHILLER_STATE", "%d", tmp3->chiller_state);
+		xmlTextWriterWriteFormatElement(writer, BAD_CAST "CHILLER_TEMPERATURE", "%d", tmp3->chiller_temperature);
+		xmlTextWriterWriteFormatElement(writer, BAD_CAST "CHILLER_IDX", "%d", tmp3->chiller_idx);
 	    }
 	    if (tmp3->heater_address) {
-		if (((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "HEATER_ADDRESS", "%s", tmp3->heater_address)) < 0)) {
-		    syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
-		    return 1;
-		}
-		if (((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "HEATER_STATE", "%d", tmp3->heater_state)) < 0)) {
-		    syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
-		    return 1;
-		}
-		if (((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "HEATER_DELAY", "%d", tmp3->heater_delay)) < 0)) {
-		    syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
-		    return 1;
-		}
-		if (((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "HEATER_USAGE", "%d", tmp3->heater_usage)) < 0)) {
-		    syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
-		    return 1;
-		}
-		if (((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "HEATER_IDX", "%d", tmp3->heater_idx)) < 0)) {
-		   syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
-		   return 1;
-		}
+		xmlTextWriterWriteFormatElement(writer, BAD_CAST "HEATER_ADDRESS", "%s", tmp3->heater_address);
+		xmlTextWriterWriteFormatElement(writer, BAD_CAST "HEATER_STATE", "%d", tmp3->heater_state);
+		xmlTextWriterWriteFormatElement(writer, BAD_CAST "HEATER_DELAY", "%d", tmp3->heater_delay);
+		xmlTextWriterWriteFormatElement(writer, BAD_CAST "HEATER_USAGE", "%d", tmp3->heater_usage);
+		xmlTextWriterWriteFormatElement(writer, BAD_CAST "HEATER_IDX", "%d", tmp3->heater_idx);
 	    }
 	    if (tmp3->cooler_address) {
-		if (((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "COOLER_ADDRESS", "%s", tmp3->cooler_address)) < 0)) {
-		    syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
-		    return 1;
-		}
-		if (((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "COOLER_STATE", "%d", tmp3->cooler_state)) < 0)) {
-		    syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
-		    return 1;                                   
-		}
-		if (((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "COOLER_DELAY", "%d", tmp3->cooler_delay)) < 0)) {
-		    syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
-		    return 1;
-		}
-		if (((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "COOLER_USAGE", "%d", tmp3->cooler_usage)) < 0)) {
-		    syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
-		    return 1;
-		}
-		if (((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "COOLER_IDX", "%d", tmp3->cooler_idx)) < 0)) {
-		    syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
-		    return 1;
-		}
+		xmlTextWriterWriteFormatElement(writer, BAD_CAST "COOLER_ADDRESS", "%s", tmp3->cooler_address);
+		xmlTextWriterWriteFormatElement(writer, BAD_CAST "COOLER_STATE", "%d", tmp3->cooler_state);
+		xmlTextWriterWriteFormatElement(writer, BAD_CAST "COOLER_DELAY", "%d", tmp3->cooler_delay);
+		xmlTextWriterWriteFormatElement(writer, BAD_CAST "COOLER_USAGE", "%d", tmp3->cooler_usage);
+		xmlTextWriterWriteFormatElement(writer, BAD_CAST "COOLER_IDX", "%d", tmp3->cooler_idx);
 	    }
 	    if (tmp3->fan_address) {
-		if (((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "FAN_ADDRESS", "%s", tmp3->fan_address)) < 0)) {
-		    syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
-		    return 1;
-		}
-		if (((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "FAN_STATE", "%d", tmp3->fan_state)) < 0)) {
-		    syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
-		    return 1;                                   
-		}
-		if (((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "FAN_DELAY", "%d", tmp3->fan_delay)) < 0)) {
-		    syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
-		    return 1;
-		}
-		if (((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "FAN_USAGE", "%d", tmp3->fan_usage)) < 0)) {
-		    syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
-		    return 1;
-		}
-		if (((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "FAN_IDX", "%d", tmp3->fan_idx)) < 0)) {
-		    syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
-		    return 1;
-		}
+		xmlTextWriterWriteFormatElement(writer, BAD_CAST "FAN_ADDRESS", "%s", tmp3->fan_address);
+		xmlTextWriterWriteFormatElement(writer, BAD_CAST "FAN_STATE", "%d", tmp3->fan_state);
+		xmlTextWriterWriteFormatElement(writer, BAD_CAST "FAN_DELAY", "%d", tmp3->fan_delay);
+		xmlTextWriterWriteFormatElement(writer, BAD_CAST "FAN_USAGE", "%d", tmp3->fan_usage);
+		xmlTextWriterWriteFormatElement(writer, BAD_CAST "FAN_IDX", "%d", tmp3->fan_idx);
 	    }
 	    if (tmp3->light_address) {
-		if (((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "LIGHT_ADDRESS", "%s", tmp3->light_address)) < 0)) {
-		    syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
-		    return 1;
-		}
-		if (((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "LIGHT_STATE", "%d", tmp3->light_state)) < 0)) {
-		    syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
-		    return 1;
-		}
-		if (((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "LIGHT_DELAY", "%d", tmp3->light_delay)) < 0)) {
-		    syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
-		    return 1;
-		}
-		if (((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "LIGHT_USAGE", "%d", tmp3->light_usage)) < 0)) {
-		    syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
-		    return 1;
-		}
-		if (((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "LIGHT_IDX", "%d", tmp3->light_idx)) < 0)) {
-		    syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
-		    return 1;
-		}
+		xmlTextWriterWriteFormatElement(writer, BAD_CAST "LIGHT_ADDRESS", "%s", tmp3->light_address);
+		xmlTextWriterWriteFormatElement(writer, BAD_CAST "LIGHT_STATE", "%d", tmp3->light_state);
+		xmlTextWriterWriteFormatElement(writer, BAD_CAST "LIGHT_DELAY", "%d", tmp3->light_delay);
+		xmlTextWriterWriteFormatElement(writer, BAD_CAST "LIGHT_USAGE", "%d", tmp3->light_usage);
+		xmlTextWriterWriteFormatElement(writer, BAD_CAST "LIGHT_IDX", "%d", tmp3->light_idx);
 	    }
 	    if (tmp3->door_address) {
-		if (((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "DOOR_ADDRESS", "%s", tmp3->door_address)) < 0)) {
-		    syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
-		return 1;
-		}
-		if (((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "DOOR_STATE", "%d", tmp3->door_state)) < 0)) {
-		    syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
-		return 1;
-		}
-		if (((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "DOOR_IDX", "%d", tmp3->door_idx)) < 0)) {
-		    syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
-		    return 1;
-		}
+		xmlTextWriterWriteFormatElement(writer, BAD_CAST "DOOR_ADDRESS", "%s", tmp3->door_address);
+		xmlTextWriterWriteFormatElement(writer, BAD_CAST "DOOR_STATE", "%d", tmp3->door_state);
+		xmlTextWriterWriteFormatElement(writer, BAD_CAST "DOOR_IDX", "%d", tmp3->door_idx);
 	    }
 	    if (tmp3->psu_address) {
-		if (((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PSU_ADDRESS", "%s", tmp3->psu_address)) < 0)) {
-		    syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
-		    return 1;
-		}
-		if (((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PSU_STATE", "%d", tmp3->psu_state)) < 0)) {
-		    syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
-		    return 1;
-		}
-		if (((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PSU_IDX", "%d", tmp3->psu_idx)) < 0)) {
-		    syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
-		    return 1;
-		}
-	    }
-	    if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "MODE", "%s", UNITMODE[tmp3->mode] )) < 0) {
-		syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
-		return 1;
-	    }
-	    if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "STAGE", "%s", UNITSTAGE[tmp3->stage] )) < 0) {
-		syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
-		return 1;
-	    }
-	    if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "BEER_SET", "%.1f", tmp3->beer_set)) < 0) {
-		syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
-		return 1;
-	    }
-	    if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "FRIDGE_SET", "%.1f", tmp3->fridge_set)) < 0) {
-		syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
-		return 1;
-	    }
-	    if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "TEMP_SET_MIN", "%.1f", tmp3->temp_set_min)) < 0) {
-		syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
-		return 1;
+		xmlTextWriterWriteFormatElement(writer, BAD_CAST "PSU_ADDRESS", "%s", tmp3->psu_address);
+		xmlTextWriterWriteFormatElement(writer, BAD_CAST "PSU_STATE", "%d", tmp3->psu_state);
+		xmlTextWriterWriteFormatElement(writer, BAD_CAST "PSU_IDX", "%d", tmp3->psu_idx);
 	    }
-	    if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "TEMP_SET_MAX", "%.1f", tmp3->temp_set_max)) < 0) {
-		syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
-		return 1;
-	    }
-	    if (tmp3->profile) {
-		if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PROFILE", "%s", tmp3->profile)) < 0) {
-		    syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
-		    return 1;
-		}
-		if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PROF_STARTED", "%d", (unsigned int)tmp3->prof_started)) < 0) {
-		    syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
-		    return 1;
-		}
-		if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PROF_PAUSED", "%d", (unsigned int)tmp3->prof_paused)) < 0) {
-		    syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
-		    return 1;
+	    xmlTextWriterWriteFormatElement(writer, BAD_CAST "MODE", "%s", UNITMODE[tmp3->mode] );
+	    xmlTextWriterWriteFormatElement(writer, BAD_CAST "STAGE", "%s", UNITSTAGE[tmp3->stage] );
+	    xmlTextWriterWriteFormatElement(writer, BAD_CAST "BEER_SET", "%.1f", tmp3->beer_set);
+	    xmlTextWriterWriteFormatElement(writer, BAD_CAST "FRIDGE_SET", "%.1f", tmp3->fridge_set);
+	    xmlTextWriterWriteFormatElement(writer, BAD_CAST "TEMP_SET_MIN", "%.1f", tmp3->temp_set_min);
+	    xmlTextWriterWriteFormatElement(writer, BAD_CAST "TEMP_SET_MAX", "%.1f", tmp3->temp_set_max);
+
+	    if (tmp3->profile_uuid) {
+		xmlTextWriterWriteFormatElement(writer, BAD_CAST "PROFILE_UUID", "%s", tmp3->profile_uuid);
+		xmlTextWriterWriteFormatElement(writer, BAD_CAST "PROFILE_NAME", "%s", tmp3->profile_name);
+		xmlTextWriterWriteFormatElement(writer, BAD_CAST "PROFILE_INITTEMP_LO", "%.1f", tmp3->profile_inittemp_lo);
+		xmlTextWriterWriteFormatElement(writer, BAD_CAST "PROFILE_INITTEMP_HI", "%.1f", tmp3->profile_inittemp_hi);
+		xmlTextWriterWriteFormatElement(writer, BAD_CAST "PROFILE_FRIDGE_MODE", "%d", tmp3->profile_fridge_mode);
+		xmlTextWriterWriteFormatElement(writer, BAD_CAST "PROFILE_DURATION", "%d", tmp3->profile_duration);
+		xmlTextWriterWriteFormatElement(writer, BAD_CAST "PROFILE_TOTALSTEPS", "%d", tmp3->profile_totalsteps);
+		if (tmp3->profile_steps) {
+		    xmlTextWriterStartElement(writer, BAD_CAST "PROFILE_STEPS");
+		    for (tmp5 = tmp3->profile_steps; tmp5; tmp5 = tmp5->next) {
+			xmlTextWriterStartElement(writer, BAD_CAST "PROFILE_STEP");
+			if (tmp5->name)
+			     xmlTextWriterWriteFormatElement(writer, BAD_CAST "NAME", "%s", tmp5->name);
+			xmlTextWriterWriteFormatElement(writer, BAD_CAST "RESTTIME", "%d", tmp5->resttime);
+			xmlTextWriterWriteFormatElement(writer, BAD_CAST "STEPTIME", "%d", tmp5->steptime);
+			xmlTextWriterWriteFormatElement(writer, BAD_CAST "TARGET_LO", "%.1f", tmp5->target_lo);
+			xmlTextWriterWriteFormatElement(writer, BAD_CAST "TARGET_HI", "%.1f", tmp5->target_hi);
+			xmlTextWriterWriteFormatElement(writer, BAD_CAST "FRIDGE_MODE", "%d", tmp5->fridge_mode);
+			xmlTextWriterEndElement(writer);    // close PROFILE_STEP
+		    }
+		    xmlTextWriterEndElement(writer);        // close PROFILE_STEPS
 		}
-		if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PROF_STATE", "%s", PROFSTATE[tmp3->prof_state] )) < 0) {
-		    syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
-		    return 1;
-		}
-		if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PROF_PEAK_ABS", "%.3f", tmp3->prof_peak_abs)) < 0) {
-		    syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
-		    return 1;
-		}
-		if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PROF_PEAK_REL", "%.3f", tmp3->prof_peak_rel)) < 0) {
-		    syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
-		    return 1;
-		}
-		if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PROF_PRIMARY_DONE", "%d", (unsigned int)tmp3->prof_primary_done)) < 0) {
-		    syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
-		    return 1;
-		}
+		xmlTextWriterWriteFormatElement(writer, BAD_CAST "PROF_STARTED", "%d", (unsigned int)tmp3->prof_started);
+		xmlTextWriterWriteFormatElement(writer, BAD_CAST "PROF_PAUSED", "%d", (unsigned int)tmp3->prof_paused);
+		xmlTextWriterWriteFormatElement(writer, BAD_CAST "PROF_STATE", "%s", PROFSTATE[tmp3->prof_state] );
+		xmlTextWriterWriteFormatElement(writer, BAD_CAST "PROF_PEAK_ABS", "%.3f", tmp3->prof_peak_abs);
+		xmlTextWriterWriteFormatElement(writer, BAD_CAST "PROF_PEAK_REL", "%.3f", tmp3->prof_peak_rel);
+		xmlTextWriterWriteFormatElement(writer, BAD_CAST "PROF_PRIMARY_DONE", "%d", (unsigned int)tmp3->prof_primary_done);
 	    }
 	    if (tmp3->PID_cool) {
-		if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PIDC_IMAX", "%.2f", tmp3->PID_cool->iMax)) < 0) {
-		    syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
-		    return 1;
-		}
-		if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PIDC_IGAIN", "%.3f", tmp3->PID_cool->iGain)) < 0) {
-		    syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
-		    return 1;
-		}
-	        if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PIDC_PGAIN", "%.3f", tmp3->PID_cool->pGain)) < 0) {
-		    syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
-		    return 1;
-		}
-	        if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PIDC_DGAIN", "%.3f", tmp3->PID_cool->dGain)) < 0) {
-		    syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
-		    return 1;
-		}
-		if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PIDC_IDLERANGE", "%.2f", tmp3->PID_cool->idleRange)) < 0) {
-		    syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
-		    return 1;
-		}
-		if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PIDC_INPUT", "%.2f", tmp3->PID_cool->Input)) < 0) {
-		    syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
-		    return 1;
-		}
-		if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PIDC_ERR", "%.2f", tmp3->PID_cool->Err)) < 0) {
-		    syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
-		    return 1;
-		}
-		if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PIDC_ISTATE", "%.2f", tmp3->PID_cool->iState)) < 0) {
-		    syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
-		    return 1;
-		}
-		if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PIDC_SETP", "%.2f", tmp3->PID_cool->SetP)) < 0) {
-		    syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
-		    return 1;
-		}
-		if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PIDC_OUTP", "%.2f", tmp3->PID_cool->OutP)) < 0) {
-		    syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
-		    return 1;
-		}
-		if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PIDC_MODE", "%s", PIDMODE[tmp3->PID_cool->Mode])) < 0) {
-		    syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
-		    return 1;
-		}
-		if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PIDC_TYPE", "COOL")) < 0) {
-		    syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
-		    return 1;
-		}
+		xmlTextWriterWriteFormatElement(writer, BAD_CAST "PIDC_IMAX", "%.2f", tmp3->PID_cool->iMax);
+		xmlTextWriterWriteFormatElement(writer, BAD_CAST "PIDC_IGAIN", "%.3f", tmp3->PID_cool->iGain);
+	        xmlTextWriterWriteFormatElement(writer, BAD_CAST "PIDC_PGAIN", "%.3f", tmp3->PID_cool->pGain);
+	        xmlTextWriterWriteFormatElement(writer, BAD_CAST "PIDC_DGAIN", "%.3f", tmp3->PID_cool->dGain);
+		xmlTextWriterWriteFormatElement(writer, BAD_CAST "PIDC_IDLERANGE", "%.2f", tmp3->PID_cool->idleRange);
+		xmlTextWriterWriteFormatElement(writer, BAD_CAST "PIDC_INPUT", "%.2f", tmp3->PID_cool->Input);
+		xmlTextWriterWriteFormatElement(writer, BAD_CAST "PIDC_ERR", "%.2f", tmp3->PID_cool->Err);
+		xmlTextWriterWriteFormatElement(writer, BAD_CAST "PIDC_ISTATE", "%.2f", tmp3->PID_cool->iState);
+		xmlTextWriterWriteFormatElement(writer, BAD_CAST "PIDC_SETP", "%.2f", tmp3->PID_cool->SetP);
+		xmlTextWriterWriteFormatElement(writer, BAD_CAST "PIDC_OUTP", "%.2f", tmp3->PID_cool->OutP);
+		xmlTextWriterWriteFormatElement(writer, BAD_CAST "PIDC_MODE", "%s", PIDMODE[tmp3->PID_cool->Mode]);
+		xmlTextWriterWriteFormatElement(writer, BAD_CAST "PIDC_TYPE", "COOL");
 	    }
 	    if (tmp3->PID_heat) {
-		if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PIDH_IMAX", "%.2f", tmp3->PID_heat->iMax)) < 0) {
-		    syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
-		    return 1;
-		}
-		if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PIDH_IDLERANGE", "%.2f", tmp3->PID_heat->idleRange)) < 0) {
-		    syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
-		    return 1;
-		}
-		if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PIDH_IGAIN", "%.3f", tmp3->PID_heat->iGain)) < 0) {
-		    syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
-		    return 1;
-		}
-		if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PIDH_PGAIN", "%.3f", tmp3->PID_heat->pGain)) < 0) {
-		    syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
-		    return 1;
-		}
-		if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PIDH_DGAIN", "%.3f", tmp3->PID_heat->dGain)) < 0) {
-		    syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
-		    return 1;
-		}
-		if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PIDH_INPUT", "%.2f", tmp3->PID_heat->Input)) < 0) {
-		    syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
-		    return 1;
-		}
-		if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PIDH_ERR", "%.2f", tmp3->PID_heat->Err)) < 0) {
-		    syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
-		    return 1;
-		}
-		if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PIDH_ISTATE", "%.2f", tmp3->PID_heat->iState)) < 0) {
-		    syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
-		    return 1;
-		}
-		if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PIDH_SETP", "%.2f", tmp3->PID_heat->SetP)) < 0) {
-		    syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
-		    return 1;
-		}
-		if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PIDH_OUTP", "%.2f", tmp3->PID_heat->OutP)) < 0) {
-		    syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
-		    return 1;
-		}
-		if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PIDH_MODE", "%s", PIDMODE[tmp3->PID_heat->Mode])) < 0) {
-		    syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
-		    return 1;
-		}
-		if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PIDH_TYPE", "HEAT")) < 0) {
-		    syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
-		    return 1;
-		}
-	    }
-	    if ((rc = xmlTextWriterEndElement(writer)) < 0) {
-		syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterEndElement");
-		return 1;
-	    }
-	}
-	if ((rc = xmlTextWriterEndElement(writer)) < 0) {
-	    syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterEndElement");
-	    return 1;
-	}
-    }
-
-    /*
-     * Fermenting profiles
-     */
-    if (Config.profiles) {
-	if ((rc = xmlTextWriterStartElement(writer, BAD_CAST "PROFILES")) < 0) {
-	    syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterStartElement");
-	    return 1;
-	}
-	for (tmp4 = Config.profiles; tmp4; tmp4 = tmp4->next) {
-	    if ((rc = xmlTextWriterStartElement(writer, BAD_CAST "PROFILE")) < 0) {
-		syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterStartElement");
-		return 1;
-	    }
-	    if ((rc = xmlTextWriterWriteElement(writer, BAD_CAST "VERSION", BAD_CAST "1")) < 0) {
-		syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteElement");
-		return 1;
+		xmlTextWriterWriteFormatElement(writer, BAD_CAST "PIDH_IMAX", "%.2f", tmp3->PID_heat->iMax);
+		xmlTextWriterWriteFormatElement(writer, BAD_CAST "PIDH_IGAIN", "%.3f", tmp3->PID_heat->iGain);
+		xmlTextWriterWriteFormatElement(writer, BAD_CAST "PIDH_PGAIN", "%.3f", tmp3->PID_heat->pGain);
+		xmlTextWriterWriteFormatElement(writer, BAD_CAST "PIDH_DGAIN", "%.3f", tmp3->PID_heat->dGain);
+		xmlTextWriterWriteFormatElement(writer, BAD_CAST "PIDH_IDLERANGE", "%.2f", tmp3->PID_heat->idleRange);
+		xmlTextWriterWriteFormatElement(writer, BAD_CAST "PIDH_INPUT", "%.2f", tmp3->PID_heat->Input);
+		xmlTextWriterWriteFormatElement(writer, BAD_CAST "PIDH_ERR", "%.2f", tmp3->PID_heat->Err);
+		xmlTextWriterWriteFormatElement(writer, BAD_CAST "PIDH_ISTATE", "%.2f", tmp3->PID_heat->iState);
+		xmlTextWriterWriteFormatElement(writer, BAD_CAST "PIDH_SETP", "%.2f", tmp3->PID_heat->SetP);
+		xmlTextWriterWriteFormatElement(writer, BAD_CAST "PIDH_OUTP", "%.2f", tmp3->PID_heat->OutP);
+		xmlTextWriterWriteFormatElement(writer, BAD_CAST "PIDH_MODE", "%s", PIDMODE[tmp3->PID_heat->Mode]);
+		xmlTextWriterWriteFormatElement(writer, BAD_CAST "PIDH_TYPE", "HEAT");
 	    }
-	    if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "UUID", "%s", tmp4->uuid)) < 0) {
-		syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
-		return 1;
-	    }
-	    if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "NAME", "%s", tmp4->name)) < 0) {
-		syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
-		return 1;
-	    }
-	    if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "BUSY", "%d", tmp4->busy)) < 0) {
-		syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
-		return 1;
-	    }
-	    if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "INITTEMP_LO", "%.1f", tmp4->inittemp_lo)) < 0) {
-		syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
-		return 1;
-	    }
-	    if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "INITTEMP_HI", "%.1f", tmp4->inittemp_hi)) < 0) {
-		syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
-		return 1;
-	    }
-	    if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "FRIDGE_MODE", "%d", tmp4->fridge_mode)) < 0) {
-		syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
-		return 1;
-	    }
-	    if (tmp4->steps) {
-		if ((rc = xmlTextWriterStartElement(writer, BAD_CAST "STEPS")) < 0) {
-		    syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterStartElement");
-		    return 1;
-		}
-		for (tmp5 = tmp4->steps; tmp5; tmp5 = tmp5->next) {
-		    if ((rc = xmlTextWriterStartElement(writer, BAD_CAST "STEP")) < 0) {
-			syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterStartElement");
-			return 1;
-		    }
-		    if ((rc = xmlTextWriterWriteElement(writer, BAD_CAST "VERSION", BAD_CAST "1")) < 0) {
-			syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteElement");
-			return 1;
-		    }
-		    if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "RESTTIME", "%d", tmp5->resttime)) < 0) {
-		        syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
-			return 1;
-		    }
-		    if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "STEPTIME", "%d", tmp5->steptime)) < 0) {
-			syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
-			return 1;
-		    }
-		    if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "TARGET_LO", "%.1f", tmp5->target_lo)) < 0) {
-		        syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
-			return 1;
-		    }
-		    if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "TARGET_HI", "%.1f", tmp5->target_hi)) < 0) {
-			syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
-			return 1;
-		    }
-		    if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "FRIDGE_MODE", "%d", tmp5->fridge_mode)) < 0) {
-			syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
-			return 1;
-		    }
-		    if ((rc = xmlTextWriterEndElement(writer)) < 0) {
-			syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterEndElement");
-			return 1;
-		    }
-		}
-		if ((rc = xmlTextWriterEndElement(writer)) < 0) {
-		    syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterEndElement");
-		    return 1;
-		}
-	    }
-	    if ((rc = xmlTextWriterEndElement(writer)) < 0) {
-		syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterEndElement");
-		return 1;
-	    }
+	    xmlTextWriterEndElement(writer);	// close FERMENTER
 	}
-	if ((rc = xmlTextWriterEndElement(writer)) < 0) {
-	    syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterEndElement");
-	    return 1;
-	}
+	xmlTextWriterEndElement(writer);	// close FERMENTERS
     }
 
     if (Config.devices) {
-	if ((rc = xmlTextWriterStartElement(writer, BAD_CAST "DEVICES")) < 0) {
-	    syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterStartElement");
-	    return 1;
-	}
+	xmlTextWriterStartElement(writer, BAD_CAST "DEVICES");
 #ifdef HAVE_WIRINGPI_H
 	piLock(LOCK_DEVICES);
 #endif
 	for (device = Config.devices; device; device = device->next) {
-	    if ((rc = xmlTextWriterStartElement(writer, BAD_CAST "DEVICE")) < 0) {
-		syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterStartElement");
-		return 1;
-	    }
-	    if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "VERSION", "%d", device->version)) < 0) {
-		syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteElement");
-		return 1;
-	    }
-	    if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "UUID", "%s", device->uuid)) < 0) {
-		syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
-		return 1;
-	    }
-	    if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "TYPE", "%s", DEVTYPE[device->type])) < 0) {
-		syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
-		return 1;
-	    }
-	    if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "DIRECTION", "%s", DEVDIR[device->direction])) < 0) {
-		syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
-		return 1;
-	    }
-	    if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "VALUE", "%d", device->value)) < 0) {
-		syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteElement");
-		return 1;
-	    }
-	    if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "OFFSET", "%d", device->offset)) < 0) {
-		syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteElement");
-		return 1;
-	    }
-	    if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PRESENT", "%s", DEVPRESENT[device->present])) < 0) {
-		syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
-		return 1;                           
-	    }
-	    if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "ADDRESS", "%s", device->address)) < 0) {
-		syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteElement");
-		return 1;                           
-	    }
-	    if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "SUBDEVICE", "%d", device->subdevice)) < 0) {
-		syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteElement");
-		return 1;                           
-	    }
-	    if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "GPIOPIN", "%d", device->gpiopin)) < 0) {
-		syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteElement");
-		return 1;                           
-	    }
-	    if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "DESCRIPTION", "%s", device->description)) < 0) {
-		syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteElement");
-		return 1;                           
-	    }
-	    if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "INUSE", "%d", device->inuse)) < 0) {
-		syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteElement");
-		return 1;                           
-	    }
-	    if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "COMMENT", "%s", device->comment)) < 0) {
-		syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteElement");
-		return 1;                           
-	    }
-	    if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "TIMESTAMP", "%d", (int)device->timestamp)) < 0) {
-		syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteElement");
-		return 1;                           
-	    }
-	    if ((rc = xmlTextWriterEndElement(writer)) < 0) {
-		syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterEndElement");
-		return 1;
-	    }
+	    xmlTextWriterStartElement(writer, BAD_CAST "DEVICE");
+	    xmlTextWriterWriteFormatElement(writer, BAD_CAST "UUID", "%s", device->uuid);
+	    xmlTextWriterWriteFormatElement(writer, BAD_CAST "TYPE", "%s", DEVTYPE[device->type]);
+	    xmlTextWriterWriteFormatElement(writer, BAD_CAST "DIRECTION", "%s", DEVDIR[device->direction]);
+	    xmlTextWriterWriteFormatElement(writer, BAD_CAST "VALUE", "%d", device->value);
+	    xmlTextWriterWriteFormatElement(writer, BAD_CAST "OFFSET", "%d", device->offset);
+	    xmlTextWriterWriteFormatElement(writer, BAD_CAST "PRESENT", "%s", DEVPRESENT[device->present]);
+	    xmlTextWriterWriteFormatElement(writer, BAD_CAST "ADDRESS", "%s", device->address);
+	    xmlTextWriterWriteFormatElement(writer, BAD_CAST "SUBDEVICE", "%d", device->subdevice);
+	    xmlTextWriterWriteFormatElement(writer, BAD_CAST "GPIOPIN", "%d", device->gpiopin);
+	    xmlTextWriterWriteFormatElement(writer, BAD_CAST "DESCRIPTION", "%s", device->description);
+	    xmlTextWriterWriteFormatElement(writer, BAD_CAST "INUSE", "%d", device->inuse);
+	    xmlTextWriterWriteFormatElement(writer, BAD_CAST "COMMENT", "%s", device->comment);
+	    xmlTextWriterWriteFormatElement(writer, BAD_CAST "TIMESTAMP", "%d", (int)device->timestamp);
+	    xmlTextWriterEndElement(writer);	// close DEVICE
 	}
 #ifdef HAVE_WIRINGPI_H
 	piUnlock(LOCK_DEVICES);
 #endif
-
-	if ((rc = xmlTextWriterEndElement(writer)) < 0) {
-	    syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterEndElement");
-	    return 1;
-	}
+	xmlTextWriterEndElement(writer);	// close DEVICES
     }
 
 #ifdef USE_SIMULATOR
     if (Config.simulators) {
-	if ((rc = xmlTextWriterStartElement(writer, BAD_CAST "SIMULATORS")) < 0) {
-	    syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterStartElement");
-	    return 1;
-	}
+	xmlTextWriterStartElement(writer, BAD_CAST "SIMULATORS");
 	for (simulator = Config.simulators; simulator; simulator = simulator->next) {
-    	    if ((rc = xmlTextWriterStartElement(writer, BAD_CAST "SIMULATOR")) < 0) {
-	    	syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterStartElement");
-	    	return 1;
-    	    }
-    	    if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "VERSION", "%d", simulator->version)) < 0) {
-	    	syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteElement");
-	    	return 1;
-    	    }
-	    if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "UUID", "%s", simulator->uuid)) < 0) {
-		syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
-		return 1;
-	    }
-	    if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "NAME", "%s", simulator->name)) < 0) {
-		syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
-		return 1;
-	    }
-	    if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "VOLUME_AIR", "%d", simulator->volume_air)) < 0) {
-	    	syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteElement");
-	    	return 1;
-	    }
-	    if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "VOLUME_BEER", "%d", simulator->volume_beer)) < 0) {
-	    	syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteElement");
-	    	return 1;
-	    }
-	    if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "ROOM_TEMPERATURE", "%.1f", simulator->room_temperature)) < 0) {
-	   	syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteElement");
-	   	return 1;
-	    }
-	    if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "ROOM_HUMIDITY", "%.1f", simulator->room_humidity)) < 0) {
-		syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteElement");
-		return 1;
-	    }
-	    if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "AIR_TEMPERATURE", "%f", simulator->air_temperature)) < 0) {
-	    	syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteElement");
-	    	return 1;
-	    }
-	    if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "BEER_TEMPERATURE", "%f", simulator->beer_temperature)) < 0) {
-	    	syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteElement");
-	    	return 1;
-	    }
-	    if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "CHILLER_TEMPERATURE", "%f", simulator->chiller_temperature)) < 0) {
-		syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteElement");
-		return 1;
-	    }
-	    if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "COOLER_TEMP", "%f", simulator->cooler_temp)) < 0) {
-	    	syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteElement");
-	    	return 1;
-	    }
-	    if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "COOLER_TIME", "%d", simulator->cooler_time)) < 0) {
-	    	syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteElement");
-	    	return 1;
-	    }
-	    if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "COOLER_SIZE", "%.3f", simulator->cooler_size)) < 0) {
-	    	syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteElement");
-	    	return 1;
-	    }
-	    if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "HEATER_TEMP", "%f", simulator->heater_temp)) < 0) {
-	    	syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteElement");
-	    	return 1;
-	    }
-	    if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "HEATER_TIME", "%d", simulator->heater_time)) < 0) {
-	    	syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteElement");
-	    	return 1;
-	    }
-	    if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "HEATER_SIZE", "%.3f", simulator->heater_size)) < 0) {
-	    	syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteElement");
-	    	return 1;
-	    }
-	    if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "HEATER_STATE", "%d", simulator->heater_state)) < 0) {
-	    	syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteElement");
-	    	return 1;                           
-	    }
-	    if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "COOLER_STATE", "%d", simulator->cooler_state)) < 0) {
-	    	syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteElement");
-	    	return 1;                       
-	    }
-	    if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "FRIGO_ISOLATION", "%.3f", simulator->frigo_isolation)) < 0) {
-	    	syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteElement");
-	    	return 1;
-	    }
-	    if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "S_YEAST_HEAT", "%f", simulator->s_yeast_heat)) < 0) {
-	    	syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteElement");
-	    	return 1;
-	    }
-	    if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "S_YEAST_STARTED", "%d", (int)simulator->s_yeast_started)) < 0) {
-	    	syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteElement");
-	    	return 1;
-	    }
-	    if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "S_COOL_TEMP", "%f", simulator->s_cool_temp)) < 0) {
-	    	syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteElement");
-	    	return 1;
-	    }
-	    if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "S_HEAT_TEMP", "%f", simulator->s_heat_temp)) < 0) {
-	    	syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteElement");
-	    	return 1;
-	    }
-	    if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "S_COOL_CHANGED", "%d", (int)simulator->s_cool_changed)) < 0) {
-	    	syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteElement");
-	    	return 1;
-	    }
-	    if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "S_HEAT_CHANGED", "%d", (int)simulator->s_heat_changed)) < 0) {
-	    	syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteElement");
-	    	return 1;
-	    }
-    	    if ((rc = xmlTextWriterEndElement(writer)) < 0) {
-	    	syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterEndElement");
-	    	return 1;
-    	    }
+    	    xmlTextWriterStartElement(writer, BAD_CAST "SIMULATOR");
+	    xmlTextWriterWriteFormatElement(writer, BAD_CAST "UUID", "%s", simulator->uuid);
+	    xmlTextWriterWriteFormatElement(writer, BAD_CAST "NAME", "%s", simulator->name);
+	    xmlTextWriterWriteFormatElement(writer, BAD_CAST "VOLUME_AIR", "%d", simulator->volume_air);
+	    xmlTextWriterWriteFormatElement(writer, BAD_CAST "VOLUME_BEER", "%d", simulator->volume_beer);
+	    xmlTextWriterWriteFormatElement(writer, BAD_CAST "ROOM_TEMPERATURE", "%.1f", simulator->room_temperature);
+	    xmlTextWriterWriteFormatElement(writer, BAD_CAST "ROOM_HUMIDITY", "%.1f", simulator->room_humidity);
+	    xmlTextWriterWriteFormatElement(writer, BAD_CAST "AIR_TEMPERATURE", "%f", simulator->air_temperature);
+	    xmlTextWriterWriteFormatElement(writer, BAD_CAST "BEER_TEMPERATURE", "%f", simulator->beer_temperature);
+	    xmlTextWriterWriteFormatElement(writer, BAD_CAST "CHILLER_TEMPERATURE", "%f", simulator->chiller_temperature);
+	    xmlTextWriterWriteFormatElement(writer, BAD_CAST "COOLER_TEMP", "%f", simulator->cooler_temp);
+	    xmlTextWriterWriteFormatElement(writer, BAD_CAST "COOLER_TIME", "%d", simulator->cooler_time);
+	    xmlTextWriterWriteFormatElement(writer, BAD_CAST "COOLER_SIZE", "%.3f", simulator->cooler_size);
+	    xmlTextWriterWriteFormatElement(writer, BAD_CAST "HEATER_TEMP", "%f", simulator->heater_temp);
+	    xmlTextWriterWriteFormatElement(writer, BAD_CAST "HEATER_TIME", "%d", simulator->heater_time);
+	    xmlTextWriterWriteFormatElement(writer, BAD_CAST "HEATER_SIZE", "%.3f", simulator->heater_size);
+	    xmlTextWriterWriteFormatElement(writer, BAD_CAST "HEATER_STATE", "%d", simulator->heater_state);
+	    xmlTextWriterWriteFormatElement(writer, BAD_CAST "COOLER_STATE", "%d", simulator->cooler_state);
+	    xmlTextWriterWriteFormatElement(writer, BAD_CAST "FRIGO_ISOLATION", "%.3f", simulator->frigo_isolation);
+	    xmlTextWriterWriteFormatElement(writer, BAD_CAST "S_YEAST_HEAT", "%f", simulator->s_yeast_heat);
+	    xmlTextWriterWriteFormatElement(writer, BAD_CAST "S_YEAST_STARTED", "%d", (int)simulator->s_yeast_started);
+	    xmlTextWriterWriteFormatElement(writer, BAD_CAST "S_COOL_TEMP", "%f", simulator->s_cool_temp);
+	    xmlTextWriterWriteFormatElement(writer, BAD_CAST "S_HEAT_TEMP", "%f", simulator->s_heat_temp);
+	    xmlTextWriterWriteFormatElement(writer, BAD_CAST "S_COOL_CHANGED", "%d", (int)simulator->s_cool_changed);
+	    xmlTextWriterWriteFormatElement(writer, BAD_CAST "S_HEAT_CHANGED", "%d", (int)simulator->s_heat_changed);
+    	    xmlTextWriterEndElement(writer);
 	}
-	if ((rc = xmlTextWriterEndElement(writer)) < 0) {
-	    syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterEndElement");
-	    return 1;
-	}
+	xmlTextWriterEndElement(writer);
     }
 #endif
 
@@ -1070,9 +495,7 @@
 
 int wrconfig(void)
 {
-    int		rc;
-
-    rc = do_wrconfig();
+    int rc = do_wrconfig();
     syslog(LOG_NOTICE, "Rewritten configuration, rc=%d", rc);
     return rc;
 }
@@ -1141,18 +564,20 @@
 
     unit = (units_list *)malloc(sizeof(units_list));
     unit->next = NULL;
-    unit->version = 1;
     unit->uuid = unit->product_uuid = unit->product_code = unit->product_name = unit->event_msg = \
 		 unit->alias = unit->air_address = unit->beer_address = unit->chiller_address = unit->heater_address = \
 		 unit->cooler_address = unit->fan_address = unit->door_address = \
-		 unit->light_address = unit->psu_address = unit->profile = NULL;
+		 unit->light_address = unit->psu_address = unit->profile_uuid = unit->profile_name  = NULL;
     unit->volume = unit->prof_peak_abs = unit->prof_peak_rel = 0.0;
-    unit->air_temperature = unit->beer_temperature = unit->chiller_temperature = unit->beer_set = unit->fridge_set = 20.0;
+    unit->air_temperature = unit->beer_temperature = unit->chiller_temperature = unit->beer_set = \
+			    unit->fridge_set = unit->profile_inittemp_lo = unit->profile_inittemp_hi = 20.0;
     unit->air_state = unit->beer_state = unit->chiller_state = 1; // missing
     unit->heater_state = unit->cooler_state = unit->fan_state = unit->door_state = \
 			 unit->light_state = unit->psu_state = unit->mode = unit->prof_state = unit->stage = 0;
     unit->air_idx = unit->beer_idx = unit->chiller_idx = unit->heater_idx = unit->cooler_idx = unit->fan_idx = \
-		    unit->door_idx = unit->light_idx = unit->psu_idx = 0;
+		    unit->door_idx = unit->light_idx = unit->psu_idx = unit->profile_fridge_mode = \
+		    unit->profile_duration = unit->profile_totalsteps = 0;
+    unit->profile_steps = NULL;
     unit->heater_delay = unit->cooler_delay = unit->fan_delay = 20;	/* 5 minutes delay */
     unit->light_delay = 1;						/* 15 seconds delay	*/
     unit->heater_wait = unit->cooler_wait = unit->fan_wait = unit->light_wait = 0;
@@ -1168,31 +593,9 @@
 
     cur = cur->xmlChildrenNode;
     while (cur != NULL) {
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"VERSION"))) {
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (xmlStrcmp(key, (const xmlChar *)"1")) {
-		xmlFree(key);
-		return 1;
-	    }
-	    unit->version = 1;
-	    xmlFree(key);
-	}
 	if ((!xmlStrcmp(cur->name, (const xmlChar *)"UUID"))) {
 	    unit->uuid = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
 	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"NAME"))) {
-	    /*
-	     * Upgrade to product code and name
-	     */
-	    char  *oldname =  (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (strstr(oldname, (char *)" ")) {
-		unit->product_code = xstrcpy(strtok(oldname, " "));
-		unit->product_name = xstrcpy(strtok(NULL, "\0"));
-	    } else {
-		unit->product_code = xstrcpy((char *)"000000");
-		unit->product_name = xstrcpy(oldname);
-	    }
-	}
 	if ((!xmlStrcmp(cur->name, (const xmlChar *)"PRODUCT_UUID"))) {
 	    unit->product_uuid = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
 	}
@@ -1420,24 +823,24 @@
 		unit->temp_set_max = val;
 	    xmlFree(key);
 	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"PID_KP"))) {
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (sscanf((const char *)key, "%f", &val) == 1)
-		unit->PID_cool->pGain = unit->PID_heat->pGain = val;	/* Upgrade config	*/
-	    xmlFree(key);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"PID_KD"))) {
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (sscanf((const char *)key, "%f", &val) == 1)
-		unit->PID_cool->dGain = unit->PID_heat->dGain = val;	/* Upgrade config       */
-	    xmlFree(key);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"PID_KI"))) {
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (sscanf((const char *)key, "%f", &val) == 1)
-		unit->PID_cool->iGain = unit->PID_heat->iGain = val;	/* Upgrade config       */
-	    xmlFree(key);
-	}
+//	if ((!xmlStrcmp(cur->name, (const xmlChar *)"PID_KP"))) {
+//	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
+//	    if (sscanf((const char *)key, "%f", &val) == 1)
+//		unit->PID_cool->pGain = unit->PID_heat->pGain = val;	/* Upgrade config	*/
+//	    xmlFree(key);
+//	}
+//	if ((!xmlStrcmp(cur->name, (const xmlChar *)"PID_KD"))) {
+//	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
+//	    if (sscanf((const char *)key, "%f", &val) == 1)
+//		unit->PID_cool->dGain = unit->PID_heat->dGain = val;	/* Upgrade config       */
+//	    xmlFree(key);
+//	}
+//	if ((!xmlStrcmp(cur->name, (const xmlChar *)"PID_KI"))) {
+//	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
+//	    if (sscanf((const char *)key, "%f", &val) == 1)
+//		unit->PID_cool->iGain = unit->PID_heat->iGain = val;	/* Upgrade config       */
+//	    xmlFree(key);
+//	}
 	if ((!xmlStrcmp(cur->name, (const xmlChar *)"PIDC_IMAX"))) {
 	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
 	    if (sscanf((const char *)key, "%f", &val) == 1)
@@ -1578,9 +981,46 @@
 	    }
 	    xmlFree(key);
 	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"PROFILE"))) {
-	    unit->profile = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
+	if ((!xmlStrcmp(cur->name, (const xmlChar *)"PROFILE_UUID"))) {
+	    unit->profile_uuid = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
+	}
+	if ((!xmlStrcmp(cur->name, (const xmlChar *)"PROFILE_NAME"))) {
+	    unit->profile_name = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
+	}
+	if ((!xmlStrcmp(cur->name, (const xmlChar *)"PROFILE_INITTEMP_LO"))) {
+	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
+	    if (sscanf((const char *)key, "%f", &val) == 1)
+		unit->profile_inittemp_lo = val;
+	    xmlFree(key);
+	}
+	if ((!xmlStrcmp(cur->name, (const xmlChar *)"PROFILE_INITTEMP_HI"))) {
+	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
+	    if (sscanf((const char *)key, "%f", &val) == 1)
+		unit->profile_inittemp_hi = val;
+	    xmlFree(key);
 	}
+	if ((!xmlStrcmp(cur->name, (const xmlChar *)"PROFILE_FRIDGE_MODE"))) {
+	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
+	    if (sscanf((const char *)key, "%d", &ival) == 1)
+		unit->profile_fridge_mode = ival;
+	    xmlFree(key);
+	}
+	if ((!xmlStrcmp(cur->name, (const xmlChar *)"PROFILE_DURATION"))) {
+	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
+	    if (sscanf((const char *)key, "%d", &ival) == 1)
+		unit->profile_duration = ival;
+	    xmlFree(key);
+	}
+	if ((!xmlStrcmp(cur->name, (const xmlChar *)"PROFILE_TOTALSTEPS"))) {
+	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
+	    if (sscanf((const char *)key, "%d", &ival) == 1)
+	    	unit->profile_totalsteps = ival;
+	    xmlFree(key);
+	}
+	if ((!xmlStrcmp(cur->name, (const xmlChar *)"PROFILE_STEPS"))) {
+	    parseSteps(doc, cur, &(unit)->profile_steps);
+	}
+
 	if ((!xmlStrcmp(cur->name, (const xmlChar *)"PROF_STARTED"))) {
 	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
 	    if (sscanf((const char *)key, "%d", &ival) == 1)
@@ -1644,7 +1084,8 @@
 {
     cur = cur->xmlChildrenNode;
     while (cur != NULL) {
-        if ((!xmlStrcmp(cur->name, (const xmlChar *)"UNIT"))) {
+	// Accept the wrong UNIT name as well as FERMENTER
+        if ((!xmlStrcmp(cur->name, (const xmlChar *)"UNIT")) || (!xmlStrcmp(cur->name, (const xmlChar *)"FERMENTER"))) {
             parseUnit(doc, cur);
         }
         cur = cur->next;
@@ -1663,20 +1104,14 @@
 
     step = (prof_step *)malloc(sizeof(prof_step));
     step->next = NULL;
-    step->version = 1;
+    step->name = NULL;
     step->steptime = step->resttime = step->fridge_mode = 0;
     step->target_lo = step->target_hi = 20.0;
 
     cur = cur->xmlChildrenNode;
     while (cur != NULL) {
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"VERSION"))) {
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (xmlStrcmp(key, (const xmlChar *)"1")) {
-		xmlFree(key);
-		return 1;
-	    }
-	    step->version = 1;
-	    xmlFree(key);
+	if ((!xmlStrcmp(cur->name, (const xmlChar *)"NAME"))) {
+	    step->name = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
 	}
 	if ((!xmlStrcmp(cur->name, (const xmlChar *)"RESTTIME"))) {
 	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
@@ -1690,14 +1125,6 @@
 		step->steptime = ival;
 	    xmlFree(key);
 	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"TARGET"))) {	/* Upgrade from single values */
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (sscanf((const char *)key, "%f", &val) == 1) {
-		step->target_lo = val - 0.2;
-		step->target_hi = val + 0.2;
-	    }
-	    xmlFree(key);
-	}
 	if ((!xmlStrcmp(cur->name, (const xmlChar *)"TARGET_LO"))) {
 	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
 	    if (sscanf((const char *)key, "%f", &val) == 1)
@@ -1738,7 +1165,7 @@
 {
     cur = cur->xmlChildrenNode;
     while (cur != NULL) {
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"STEP"))) {
+	if ((!xmlStrcmp(cur->name, (const xmlChar *)"PROFILE_STEP"))) {
 	    parseStep(doc, cur, step);
 	}
 	cur = cur->next;
@@ -1748,106 +1175,6 @@
 
 
 
-int parseProfile(xmlDocPtr doc, xmlNodePtr cur)
-{
-    xmlChar     	*key;
-    profiles_list	*profile, *tmp;
-    int			ival;
-    float		fval;
-
-    profile = (profiles_list *)malloc(sizeof(profiles_list));
-    profile->next = NULL;
-    profile->version = 1;
-    profile->uuid = profile->name = NULL;
-    profile->busy = profile->fridge_mode = 0;
-    profile->inittemp_lo = profile->inittemp_hi = 20.0;
-    profile->steps = NULL;
-
-    cur = cur->xmlChildrenNode;
-    while (cur != NULL) {
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"VERSION"))) {
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (xmlStrcmp(key, (const xmlChar *)"1")) {
-		xmlFree(key);
-		return 1;
-	    }
-	    profile->version = 1;
-	    xmlFree(key);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"UUID"))) {
-	    profile->uuid = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"NAME"))) {
-	    profile->name = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"BUSY"))) {
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (sscanf((const char *)key, "%d", &ival) == 1)
-		profile->busy = ival;
-	    xmlFree(key);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"INITTEMP"))) {	/* Upgrade from single temp */
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (sscanf((const char *)key, "%f", &fval) == 1) {
-		profile->inittemp_lo = fval - 0.2;
-		profile->inittemp_hi = fval + 0.2;
-	    }
-	    xmlFree(key);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"INITTEMP_LO"))) {
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (sscanf((const char *)key, "%f", &fval) == 1)
-		profile->inittemp_lo = fval;
-	    xmlFree(key);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"INITTEMP_HI"))) {
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (sscanf((const char *)key, "%f", &fval) == 1)
-		profile->inittemp_hi = fval;
-	    xmlFree(key);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"FRIDGE_MODE"))) {
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (sscanf((const char *)key, "%d", &ival) == 1)
-		profile->fridge_mode = ival;
-	    xmlFree(key);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"STEPS"))) {
-	    parseSteps(doc, cur, &(profile)->steps);
-	}
-	cur = cur->next;
-    }
-
-    if (Config.profiles == NULL) {
-	Config.profiles = profile;
-    } else {
-	for (tmp = Config.profiles; tmp; tmp = tmp->next) {
-	    if (tmp->next == NULL) {
-		tmp->next = profile;
-		break;
-	    }
-	}
-    }
-
-    return 0;
-}
-
-
-
-int parseProfiles(xmlDocPtr doc, xmlNodePtr cur)
-{
-    cur = cur->xmlChildrenNode;
-    while (cur != NULL) {
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"PROFILE"))) {
-	    parseProfile(doc, cur);
-	}
-	cur = cur->next;
-    }
-    return 0;
-}
-
-
-
 int parseDevice(xmlDocPtr doc, xmlNodePtr cur)
 {
     xmlChar             *key;
@@ -1856,7 +1183,6 @@
 
     device = (devices_list *)malloc(sizeof(devices_list));
     device->next = NULL;
-    device->version = 1;
     device->uuid = device->address = device->description = device->comment = NULL;
     device->type = device->direction = device->present = device->subdevice = device->inuse = device->offset = 0;
     device->gpiopin = -1;
@@ -1864,15 +1190,6 @@
 
     cur = cur->xmlChildrenNode;
     while (cur != NULL) {
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"VERSION"))) {
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (xmlStrcmp(key, (const xmlChar *)"1")) {
-		xmlFree(key);
-		return 1;
-	    }
-	    device->version = 1;
-	    xmlFree(key);
-	}
 	if ((!xmlStrcmp(cur->name, (const xmlChar *)"UUID"))) {
 	    device->uuid = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
 	}
@@ -1995,7 +1312,6 @@
 
     simulator = (simulator_list *)malloc(sizeof(simulator_list));
     simulator->next = NULL;
-    simulator->version = 1;
     simulator->uuid = simulator->name = NULL;
     simulator->volume_air = simulator->volume_beer = 0;
     simulator->room_temperature = simulator->air_temperature = simulator->beer_temperature = simulator->s_cool_temp = simulator->s_heat_temp = 20.0;
@@ -2008,15 +1324,6 @@
 
     cur = cur->xmlChildrenNode;
     while (cur != NULL) {
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"VERSION"))) {
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (xmlStrcmp(key, (const xmlChar *)"1")) {
-		xmlFree(key);
-		return 1;
-	    }
-	    simulator->version = 1;
-	    xmlFree(key);
-	}
 	if ((!xmlStrcmp(cur->name, (const xmlChar *)"UUID"))) {
 	    simulator->uuid = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
 	}
@@ -2248,15 +1555,6 @@
      */
     cur = cur->xmlChildrenNode;
     while (cur != NULL) {
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"VERSION"))) {
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (xmlStrcmp(key, (const xmlChar *)"1")) {
-		xmlFree(key);
-		syslog(LOG_NOTICE, "XML file %s is not a valid version", mypath);
-		return 1;
-	    }
-	    xmlFree(key);
-	}
 	if ((!xmlStrcmp(cur->name, (const xmlChar *)"NAME"))) {
 	    Config.name = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
 	}
@@ -2315,9 +1613,6 @@
 	if ((!xmlStrcmp(cur->name, (const xmlChar *)"FERMENTERS"))) {
 	    parseFermenters(doc, cur);
 	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"PROFILES"))) {
-	    parseProfiles(doc, cur);
-	}
 	if ((!xmlStrcmp(cur->name, (const xmlChar *)"DEVICES"))) {
 	    parseDevices(doc, cur);
 	}
--- a/thermferm/server.c	Thu Jan 10 16:33:42 2019 +0100
+++ b/thermferm/server.c	Mon Jan 14 22:46:27 2019 +0100
@@ -1,5 +1,5 @@
 /*****************************************************************************
- * Copyright (C) 2008-2018
+ * Copyright (C) 2008-2019
  *   
  * Michiel Broek <mbroek at mbse dot eu>
  *
@@ -185,57 +185,6 @@
 
 
 
-int delete_Profile(char *uuid)
-{
-    profiles_list	*current = Config.profiles;
-    profiles_list	*previous = NULL;
-    prof_step		*step, *olds;
-
-    while (current) {
-	if (strcmp(current->uuid, uuid) == 0) {
-	    if (previous == NULL) {
-		Config.profiles = current->next;
-		free(current->uuid);
-		current->uuid = NULL;
-		free(current->name);
-		current->name = NULL;
-		if (current->steps) {
-		    for (step = current->steps; step; step = olds) {
-			olds = step->next;
-			free(step);
-		    }
-		    current->steps = NULL;
-		}
-		free(current);
-		return 1;
-	    } else {
-		free(current->uuid);
-		current->uuid = NULL;
-		free(current->name);
-		current->name = NULL;
-		if (current->steps) {
-		    for (step = current->steps; step; step = olds) {
-			olds = step->next;
-			free(step);
-		    }
-		    current->steps = NULL;
-		}
-		previous->next = current->next;
-		free(current);
-		current = previous->next;
-		return 1;
-	    }
-	} else {
-	    previous = current;
-	    current = current->next;
-	}
-    }
-
-    return 0;
-}
-
-
-
 void tidy_lslist(ls_list **lap)
 {
     ls_list     *tmp, *old;
@@ -699,7 +648,6 @@
 
 	    device = (devices_list *)malloc(sizeof(devices_list));
 	    device->next = NULL;
-	    device->version = 1;
 	    device->uuid = malloc(37);
 	    uuid_generate(uu);
 	    uuid_unparse(uu, device->uuid);
@@ -1200,266 +1148,6 @@
 
 
 
-/*
- * PROFILE ADD name	Add a new profile
- * PROFILE DEL uuid	Delete profile with uuid
- * PROFILE LIST		List available profiles
- * PROFILE GET uuid     Get profile record
- * PROFILE PUT uuid     Put profile record
- * PROFILE GETS uuid	Get profile steps list
- * PROFILE PUTS uuid	Put profile steps list
- */
-int cmd_profile(char *buf)
-{
-    char                ibuf[SS_BUFSIZE], *sstep, *rest, *tlarg, *tharg, *frarg, *param, *kwd, *val;
-    int                 j, ival, rlen, istep, irest, ifrarg;
-    float		ftlarg, ftharg, fval;
-    char		*opt;
-    profiles_list	*profile, *tmpp;
-    prof_step		*step, *olds;
-    uuid_t		uu;
-
-    opt = strtok(buf, " \0");
-    opt = strtok(NULL, " \0");
-
-    if (opt == NULL) {
-	srv_send((char *)"501 Subcommand missing");
-	return 0;
-    }
-
-    if (strcmp(opt, (char *)"HELP") == 0) {
-	srv_send((char *)"100 Help text follows:");
-	srv_send((char *)"Recognized commands:");
-	srv_send((char *)"PROFILE uuid,name             Profile rename");
-	srv_send((char *)"PROFILE ADD name              Add new Profile with name");
-	srv_send((char *)"PROFILE DEL uuid              Delete Profile by uuid");
-	srv_send((char *)"PROFILE LIST                  List available profiles");
-	srv_send((char *)"PROFILE GET uuid              Get Profile record by uuid");
-	srv_send((char *)"PROFILE PUT uuid              Put Profile record by uuid");
-	srv_send((char *)"PROFILE GETS uuid             Profile get steps list");
-	srv_send((char *)"PROFILE PUTS uuid             Profile put steps list");
-	srv_send((char *)".");
-	return 0;
-    }
-
-    if (strcmp(opt, (char *)"LIST") == 0) {
-	/*
-	 * Fermenting profiles
-	 */
-	srv_send((char *)"212 Profiles list follows:");
-	for (profile = Config.profiles; profile; profile = profile->next) {
-	    j = 0;
-	    for (step = profile->steps; step; step = step->next)
-		j++;
-	    srv_send((char *)"%s,%s,%d,%d", profile->uuid, profile->name, j, profile->busy);
-	}
-	srv_send((char *)".");
-	return 0;
-    }
-
-    param = strtok(NULL, "\0");
-    if (param == NULL) {
-	srv_send((char *)"502 Parameter missing");
-	return 0;
-    }
-
-    if (strcmp(opt, (char *)"ADD") == 0) {
-	profile = (profiles_list *)malloc(sizeof(profiles_list));
-	profile->next = NULL;
-	profile->version = 1;
-	profile->uuid = malloc(37);
-	uuid_generate(uu);
-	uuid_unparse(uu, profile->uuid);
-	profile->name = xstrcpy(param);
-	profile->busy = profile->fridge_mode = 0;
-	profile->inittemp_lo = 19.8;
-	profile->inittemp_hi = 20.2;
-	profile->steps = NULL;
-	if (Config.profiles == NULL) {
-	    Config.profiles = profile;
-	} else {
-	    for (tmpp = Config.profiles; tmpp; tmpp = tmpp->next) {
-		if (tmpp->next == NULL) {
-		    tmpp->next = profile;
-		    break;
-		}
-	    }
-	}
-
-	syslog(LOG_NOTICE, "Profile %s added", profile->uuid);
-	srv_send((char *)"211 Profile %s added", profile->uuid);
-	return 1;
-
-
-    } else if (strcmp(opt, (char *)"DEL") == 0) {
-	if (delete_Profile(param)) {
-	    syslog(LOG_NOTICE, "Profile %s deleted", param);
-	    srv_send((char *)"211 Profile %s deleted", param);
-	    return 1;
-	} else {
-	    srv_send((char *)"440 No such profile");
-	    return 0;
-	}
-    
-    } else if (strcmp(opt, (char *)"GET") == 0) {
-	for (profile = Config.profiles; profile; profile = profile->next) {
-	    if (strcmp(profile->uuid, param) == 0) {
-		srv_send((char *)"213 Profile record follows:");
-		srv_send((char *)"UUID,%s", profile->uuid);
-		srv_send((char *)"NAME,%s", profile->name);
-		srv_send((char *)"INITTEMP_LO,%.1f", profile->inittemp_lo);
-		srv_send((char *)"INITTEMP_HI,%.1f", profile->inittemp_hi);
-		srv_send((char *)"FRIDGE_MODE,%d", profile->fridge_mode);
-		srv_send((char *)".");
-		return 0;
-	    }
-	}
-	srv_send((char *)"440 No such profile");
-	return 0;
-
-    } else if (strcmp(opt, (char *)"PUT") == 0) {
-	for (profile = Config.profiles; profile; profile = profile->next) {
-	    if (strcmp(profile->uuid, param) == 0) {
-		while (1) {
-		    rlen = srv_recv(ibuf);
-		    if (rlen == -1) {
-			return 0;
-		    }
-		    if (strlen(ibuf)) {
-			if (strcmp(ibuf, (char *)".") == 0) {
-			    srv_send((char *)"219 Accepted Profile record");
-			    return 1;
-			}
-			kwd = strtok(ibuf, ",\0");
-			val = strtok(NULL, "\0");
-			if (kwd && val) {
-			    if (strcmp(kwd, (char *)"NAME") == 0) {
-				if (profile->name) {
-				    if (strcmp(profile->name, val))
-					syslog(LOG_NOTICE, "Profile %s name `%s' to `%s'", profile->uuid, profile->name, val);
-				    free(profile->name);
-				}
-				profile->name = xstrcpy(val);
-			    } else if (strcmp(kwd, (char *)"INITTEMP_LO") == 0) {
-				if (sscanf(val, "%f", &fval) == 1) {
-				    if (profile->inittemp_lo != fval)
-					syslog(LOG_NOTICE, "Profile %s initial temperature low %.1f to %.1f", profile->uuid, profile->inittemp_lo, fval);
-				    profile->inittemp_lo = fval;
-				}
-			    } else if (strcmp(kwd, (char *)"INITTEMP_HI") == 0) {
-				if (sscanf(val, "%f", &fval) == 1) {
-				    if (profile->inittemp_hi != fval)
-					syslog(LOG_NOTICE, "Profile %s initial temperature high %.1f to %.1f", profile->uuid, profile->inittemp_hi, fval);
-				    profile->inittemp_hi = fval;
-				}
-			    } else if (strcmp(kwd, (char *)"FRIDGE_MODE") == 0) {
-				if (sscanf(val, "%d", &ival) == 1) {
-				    if (profile->fridge_mode != ival)
-					syslog(LOG_NOTICE, "Profile %s fridge mode %d to %d", profile->uuid, profile->fridge_mode, ival);
-				    profile->fridge_mode = ival;
-				}
-			    }
-			}
-		    }
-		}
-	    }               
-	}
-	srv_send((char *)"440 No such profile");
-	return 0;
-
-    } else if (strcmp(opt, (char *)"GETS") == 0) {
-
-	for (profile = Config.profiles; profile; profile = profile->next) {
-	    if (strcmp(profile->uuid, param) == 0) {
-		srv_send((char *)"215 Profile steps follow:");
-		for (step = profile->steps; step; step = step->next) {
-		    srv_send((char *)"%d,%d,%.1f,%.1f,%d", step->steptime, step->resttime, step->target_lo, step->target_hi, step->fridge_mode);
-		}
-		srv_send((char *)".");
-		return 0;
-	    }
-	}
-
-	srv_send((char *)"440 No such profile");
-	return 0;
-
-    } else if (strcmp(opt, (char *)"PUTS") == 0) {
-
-	for (profile = Config.profiles; profile; profile = profile->next) {
-	    if (strcmp(profile->uuid, param) == 0) {
-
-		if (profile->steps) {
-		    syslog(LOG_NOTICE, "PROFILE PUTS %s erased all old steps", profile->uuid);
-		    for (step = profile->steps; step; step = olds) {
-			olds = step->next;
-			free(step);
-		    }
-		    profile->steps = NULL;		    
-		}
-
-		j = 0;
-            	while (1) {	
-		    rlen = srv_recv(ibuf);
-	    	    if (rlen == -1) {
-		    	return 0;
-	    	    } else {
-	    	    	if (strlen(ibuf)) {
-		    	    if (strcmp(ibuf, (char *)".") == 0) {
-
-		    	    	srv_send((char *)"219 Accepted Profile steps");
-		    	    	return 1;
-		    	    }
-			    sstep = strtok(ibuf, ",\0");
-			    rest = strtok(NULL, ",\0");
-			    tlarg = strtok(NULL, ",\0");
-			    tharg = strtok(NULL, ",\0");
-			    frarg = strtok(NULL, "\0");
-
-			    if ((sscanf(sstep, "%d", &istep) == 1) &&
-				(sscanf(rest, "%d", &irest) == 1) &&
-				(sscanf(tlarg, "%f", &ftlarg) == 1) && 
-				(sscanf(tharg, "%f", &ftharg) == 1) &&
-				(sscanf(frarg, "%d", &ifrarg) == 1)) {
-
-				j++;
-				syslog(LOG_NOTICE, "PROFILE PUTS %s add step %d: steptime=%d resttime=%d target=%.1f..%.1f fridge_mode=%d", 
-						profile->uuid, j, istep, irest, ftlarg, ftharg, ifrarg);
-				step = (prof_step *)malloc(sizeof(prof_step));
-				step->next = NULL;
-				step->version = 1;
-				step->steptime = istep;
-				step->resttime = irest;
-				step->target_lo = ftlarg;
-				step->target_hi = ftharg;
-				step->fridge_mode = ifrarg;
-
-				if (profile->steps == NULL) {
-				    profile->steps = step;
-				} else {
-				    for (olds = profile->steps; olds; olds = olds->next) {
-					if (olds->next == NULL) {
-					    olds->next = step;
-					    break;
-					}
-				    }
-				}
-			    }
-		    	}
-	    	    }
-		}
-	    }
-	}
-
-	srv_send((char *)"440 No such profile");
-	return 0;
-    }
-
-    srv_send((char *)"504 Subcommand error");
-    return 0;
-}
-
-
-
 #ifdef USE_SIMULATOR
 int delete_Simulator(char *uuid)
 {
@@ -1558,7 +1246,6 @@
 
 	simulator = (simulator_list *)malloc(sizeof(simulator_list));
 	simulator->next = NULL;
-	simulator->version = 1;
 	simulator->uuid = malloc(37);
 	uuid_generate(uu);
 	uuid_unparse(uu, simulator->uuid);
@@ -1794,6 +1481,7 @@
 {
     units_list  *current = Config.units;
     units_list	*previous = NULL;
+    prof_step	*step, *olds;
 
     while (current) {
 	if (strcmp(current->uuid, uuid) == 0) {
@@ -1837,15 +1525,25 @@
 		if (current->psu_address)
 		    free(current->psu_address);
 		current->psu_address = NULL;
-		if (current->profile)
-		    free(current->profile);
-		current->profile = NULL;
+		if (current->profile_uuid)
+		    free(current->profile_uuid);
+		current->profile_uuid = NULL;
+		if (current->profile_name)
+		    free(current->profile_name);
+		current->profile_name = NULL;
 		if (current->PID_cool)
 		    free(current->PID_cool);
 		current->PID_cool = NULL;
 		if (current->PID_heat)
 		    free(current->PID_heat);
 		current->PID_heat = NULL;
+		if (current->profile_steps) {
+		    for (step = current->profile_steps; step; step = olds) {
+			olds = step->next;
+			free(step);
+		    }
+		    current->profile_steps = NULL;
+		}
 		free(current);
 		return 1;
 	    } else {
@@ -1887,15 +1585,25 @@
 		if (current->psu_address)
 		    free(current->psu_address);
 		current->psu_address = NULL;
-		if (current->profile)
-		    free(current->profile);
-		current->profile = NULL;
+		if (current->profile_uuid)
+		    free(current->profile_uuid);
+		current->profile_uuid = NULL;
+		if (current->profile_name)
+		    free(current->profile_name);
+		current->profile_name = NULL;
 		if (current->PID_cool)
 		    free(current->PID_cool);
 		current->PID_cool = NULL;
 		if (current->PID_heat)
 		    free(current->PID_heat);
 		current->PID_heat = NULL;
+		if (current->profile_steps) {
+		    for (step = current->profile_steps; step; step = olds) {
+			olds = step->next;
+			free(step);
+		    }
+		    current->profile_steps = NULL;
+		}
 		previous->next = current->next;
 		free(current);
 		current = previous->next;
@@ -1972,7 +1680,6 @@
 	Config.next_unit++;
 	unit = (units_list *)malloc(sizeof(units_list));
 	unit->next = NULL;
-	unit->version = 1;
 	unit->uuid = malloc(37);
 	uuid_generate(uu);
 	uuid_unparse(uu, unit->uuid);
@@ -1982,13 +1689,15 @@
 	unit->alias = xstrcpy(an);
 	unit->air_address = unit->beer_address = unit->chiller_address = unit->heater_address = unit->cooler_address = \
 			    unit->fan_address = unit->door_address = unit->light_address = \
-			    unit->psu_address = unit->profile = NULL;
+			    unit->psu_address = unit->profile_uuid = unit->profile_name = NULL;
 	unit->air_idx = unit->beer_idx = unit->chiller_idx = unit->heater_idx = unit->cooler_idx = unit->fan_idx = \
-			unit->door_idx = unit->light_idx = unit->psu_idx = 0;
+			unit->door_idx = unit->light_idx = unit->psu_idx = unit->profile_fridge_mode = \
+			unit->profile_duration = unit->profile_totalsteps = 0;
+	unit->profile_steps = NULL;
 	unit->volume = unit->prof_peak_abs = unit->prof_peak_rel = 0.0;
 	unit->air_state = unit->beer_state = unit->chiller_state = 1;
 	unit->air_temperature = unit->beer_temperature = unit->chiller_temperature = 20000;
-	unit->beer_set = unit->fridge_set = 20.0;
+	unit->beer_set = unit->fridge_set = unit->profile_inittemp_lo = unit->profile_inittemp_hi =20.0;
 	unit->heater_state = unit->cooler_state = unit->fan_state = unit->door_state = unit->mode = \
 			     unit->light_state = unit->psu_state = unit->prof_state = unit->stage = 0;
 	unit->heater_delay = unit->cooler_delay = unit->fan_delay = 20;	/* 5 minutes delay	*/
@@ -2124,19 +1833,27 @@
 		srv_send((char *)"PSU_IDX,%d", unit->psu_idx);
 		srv_send((char *)"FRIDGE_SET,%.1f", unit->fridge_set);
 		srv_send((char *)"BEER_SET,%.1f", unit->beer_set);
-		srv_send((char *)"PROFILE,%s", unit->profile);
-		srv_send((char *)"PROF_STARTED,%d", (int)unit->prof_started);
-		if (unit->prof_state == PROFILE_RUN) {
-		    srv_send((char *)"PROF_STATE,%s %d%%", PROFSTATE[unit->prof_state], unit->prof_percent);
-		} else {
-		    srv_send((char *)"PROF_STATE,%s", PROFSTATE[unit->prof_state]);
+		if (unit->profile_uuid) {
+		    srv_send((char *)"PROFILE_UUID,%s", unit->profile_uuid);
+		    srv_send((char *)"PROFILE_NAME,%s", unit->profile_name);
+		    srv_send((char *)"PROFILE_INITTEMP_LO,%.1f", unit->profile_inittemp_lo);
+		    srv_send((char *)"PROFILE_INITTEMP_HI,%.1f", unit->profile_inittemp_hi);
+		    srv_send((char *)"PROFILE_FRIDGE_MODE,%d", unit->profile_fridge_mode);
+		    srv_send((char *)"PROFILE_DURATION,%d", unit->profile_duration);
+		    srv_send((char *)"PROFILE_TOTALSTEPS,%d", unit->profile_totalsteps);
+		    srv_send((char *)"PROF_STARTED,%d", (int)unit->prof_started);
+		    if (unit->prof_state == PROFILE_RUN) {
+		    	srv_send((char *)"PROF_STATE,%s %d%%", PROFSTATE[unit->prof_state], unit->prof_percent);
+		    } else {
+		    	srv_send((char *)"PROF_STATE,%s", PROFSTATE[unit->prof_state]);
+		    }
+		    srv_send((char *)"PROF_TARGET_LO,%.3f", unit->prof_target_lo);
+		    srv_send((char *)"PROF_TARGET_HI,%.3f", unit->prof_target_hi);
+		    srv_send((char *)"PROF_FRIDGE_MODE,%d", unit->prof_fridge_mode);
+		    srv_send((char *)"PROF_PEAK_ABS,%.3f", unit->prof_peak_abs);
+		    srv_send((char *)"PROF_PEAK_REL,%.3f", unit->prof_peak_rel);
+		    srv_send((char *)"PROF_PRIMARY_DONE,%d", (int)unit->prof_primary_done);
 		}
-		srv_send((char *)"PROF_TARGET_LO,%.3f", unit->prof_target_lo);
-		srv_send((char *)"PROF_TARGET_HI,%.3f", unit->prof_target_hi);
-		srv_send((char *)"PROF_FRIDGE_MODE,%d", unit->prof_fridge_mode);
-		srv_send((char *)"PROF_PEAK_ABS,%.3f", unit->prof_peak_abs);
-		srv_send((char *)"PROF_PEAK_REL,%.3f", unit->prof_peak_rel);
-		srv_send((char *)"PROF_PRIMARY_DONE,%d", (int)unit->prof_primary_done);
 		srv_send((char *)"TEMP_SET_MIN,%.1f", unit->temp_set_min);
 		srv_send((char *)"TEMP_SET_MAX,%.1f", unit->temp_set_max);
 		srv_send((char *)"ALARM,%d", unit->alarm_flag);
@@ -2499,7 +2216,7 @@
 					     */
 					    unit->prof_target_lo = unit->prof_target_hi = 20.0;
 					    unit->prof_fridge_mode = 0;
-					    if (unit->profile) {
+					    if (unit->profile_uuid) {
 						unit->mqtt_flag |= MQTT_FLAG_DATA;
 					    }
 					}
@@ -2593,35 +2310,7 @@
 				    unit->PID_heat->idleRange = fval;
 				}
 
-			    } else if (strcmp(kwd, (char *)"PROFILE") == 0) {
-				if (unit->prof_state == PROFILE_OFF) {
-				    /*
-				     * Only change profile if it is not active, else drop this one.
-				     */
-				    if (unit->profile && val && strcmp(unit->profile, val))
-					syslog(LOG_NOTICE, "Fermenter unit %s profile name `%s' to `%s'", unit->uuid, unit->profile, val);
-				    if (unit->profile)
-				    	free(unit->profile);
-
-				    if (val)
-				    	unit->profile = xstrcpy(val);
-				    else
-				    	unit->profile = NULL;
-				    /*
-				     * Reset all output devices
-				     */
-				    unit->PID_cool->OutP = unit->PID_heat->OutP = 0.0;
-				    unit->PID_cool->Mode = unit->PID_heat->Mode = PID_MODE_NONE;
-				    unit->heater_state = unit->cooler_state = unit->fan_state = unit->light_state = 0;
-				    unit->heater_wait = unit->cooler_wait = unit->fan_wait = unit->light_wait = 0;
-				    device_out(unit->heater_address, unit->heater_state);
-				    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_DATA;
-				}
-
-			    } else if (val && (strcmp(kwd, (char *)"PROF_STATE") == 0)) {
+			    } else if (val && (strcmp(kwd, (char *)"PROF_STATE") == 0) && unit->profile_uuid) {
 				for (i = 0; i < 5; i++) {
 				    if (strcmp(val, PROFSTATE[i]) == 0) {
 					switch (i) {
@@ -2649,7 +2338,8 @@
 						case PROFILE_DONE:	break;	/* Command is illegal */
 						case PROFILE_ABORT:	if ((unit->prof_state == PROFILE_RUN) || (unit->prof_state == PROFILE_PAUSE)) {
 									    unit->prof_state = PROFILE_OFF;
-									    unit->prof_started = 0;
+									    unit->prof_started = 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 ABORT", unit->uuid);
 									}
 									break;
@@ -2739,8 +2429,6 @@
 		srv_send((char *)"LIST <CMD> [parameters]       List commands");
 		srv_send((char *)"LIST HELP                     List help screen");
 		srv_send((char *)"PING                          Check if server is alive");
-		srv_send((char *)"PROFILE <CMD> [parameters]    Profile commands");
-		srv_send((char *)"PROFILE HELP                  Profile help screen");
 #ifdef USE_SIMULATOR
 		srv_send((char *)"SIMULATOR <CMD> [parameters]  Simulator commands");
 		srv_send((char *)"SIMULATOR HELP                Simulator help screen");
@@ -2755,10 +2443,6 @@
 	    } else if (strncmp(buf, "PING", 4) == 0) {
 		srv_send((char *)"101 PONG");
 
-	    } else if (strncmp(buf, "PROFILE", 7) == 0) {
-		if (cmd_profile(buf))
-		    wrconfig();
-
 #ifdef USE_SIMULATOR
 	    } else if (strncmp(buf, "SIMULATOR", 9) == 0) {
 		if (cmd_simulator(buf))
--- a/thermferm/thermferm.c	Thu Jan 10 16:33:42 2019 +0100
+++ b/thermferm/thermferm.c	Mon Jan 14 22:46:27 2019 +0100
@@ -49,7 +49,6 @@
 extern int		slcdHandle;
 int			setupmenu = MENU_NONE;
 units_list		*current_unit = NULL;		/* In panel editor this points to the current unit. */
-profiles_list		*current_profile = NULL;
 float			temp_temp = 20.0;
 
 #ifndef HAVE_WIRINGPI_H
@@ -274,18 +273,7 @@
 				slcdPuts(slcdHandle, "New mode PROFILE");
 				break;
 
-	case MENU_PROFILE_SELECT:	snprintf(buf, Config.lcd_cols, "%s", current_profile->name);
-#ifdef HAVE_WIRINGPI_H
-					lcdPuts(lcdHandle, buf);
-					lcdPosition(lcdHandle, 0, 1);
-					lcdPuts(lcdHandle, "Select profile");
-#endif
-					slcdPuts(slcdHandle, buf);
-					slcdPosition(slcdHandle, 0, 1);
-					slcdPuts(slcdHandle, "Select profile");
-					break;
-	
-	case MENU_PROFILE_START:	snprintf(buf, Config.lcd_cols, "%s", current_profile->name);
+	case MENU_PROFILE_START:	snprintf(buf, Config.lcd_cols, "%s", current_unit->profile_name);
 #ifdef HAVE_WIRINGPI_H
 					lcdPuts(lcdHandle, buf);
 					lcdPosition(lcdHandle, 0, 1);
@@ -296,7 +284,7 @@
 					slcdPuts(slcdHandle, "Start profile");
 					break;
 	
-	case MENU_PROFILE_PAUSE:	snprintf(buf, Config.lcd_cols, "%s", current_profile->name);
+	case MENU_PROFILE_PAUSE:	snprintf(buf, Config.lcd_cols, "%s", current_unit->profile_name);
 #ifdef HAVE_WIRINGPI_H
 					lcdPuts(lcdHandle, buf);
 					lcdPosition(lcdHandle, 0, 1);
@@ -307,7 +295,7 @@
 					slcdPuts(slcdHandle, "Pause profile");
 					break;
 
-	case MENU_PROFILE_ABORT:	snprintf(buf, Config.lcd_cols, "%s", current_profile->name);
+	case MENU_PROFILE_ABORT:	snprintf(buf, Config.lcd_cols, "%s", current_unit->profile_name);
 #ifdef HAVE_WIRINGPI_H
 					lcdPuts(lcdHandle, buf);
 					lcdPosition(lcdHandle, 0, 1);
@@ -318,7 +306,7 @@
 					slcdPuts(slcdHandle, "Abort profile");
 					break;
 
-	case MENU_PROFILE_RESUME:	snprintf(buf, Config.lcd_cols, "%s", current_profile->name);
+	case MENU_PROFILE_RESUME:	snprintf(buf, Config.lcd_cols, "%s", current_unit->profile_name);
 #ifdef HAVE_WIRINGPI_H
 					lcdPuts(lcdHandle, buf);
 					lcdPosition(lcdHandle, 0, 1);
@@ -329,7 +317,7 @@
 					slcdPuts(slcdHandle, "Resume profile");
 					break;
 
-	case MENU_PROFILE_GOOFF:	snprintf(buf, Config.lcd_cols, "%s", current_profile->name);
+	case MENU_PROFILE_GOOFF:	snprintf(buf, Config.lcd_cols, "%s", current_unit->profile_name);
 #ifdef HAVE_WIRINGPI_H
 					lcdPuts(lcdHandle, buf);
 					lcdPosition(lcdHandle, 0, 1);
@@ -342,10 +330,10 @@
 
 	case MENU_TOP_SYS:	
 #ifdef HAVE_WIRINGPI_H
-				lcdPuts(lcdHandle, "System menu");
+					lcdPuts(lcdHandle, "System menu");
 #endif
-				slcdPuts(slcdHandle, "System menu");
-				break;
+					slcdPuts(slcdHandle, "System menu");
+					break;
 
 	case MENU_SYS_HALT:	
 #ifdef HAVE_WIRINGPI_H				
@@ -413,8 +401,8 @@
 	 * Set a sane default until it will be overruled by the
 	 * main processing loop.
 	 */
-	current_unit->prof_target_lo = 19.8;
-	current_unit->prof_target_hi = 20.2;
+	current_unit->prof_target_lo = 20.0;
+	current_unit->prof_target_hi = 20.0;
 	current_unit->prof_fridge_mode = 0;
     }
 }
@@ -427,7 +415,6 @@
 void panel_key_events(int key)
 {
     units_list		*unit;
-    profiles_list	*profile;
     int			rc;
 
     switch (setupmenu) {
@@ -505,8 +492,12 @@
 			    go_menu(MENU_UNITS);
 			if (key == KEY_DOWN)
 			    go_menu(MENU_MODE_NONE);
-			if (key == KEY_UP)
-			    go_menu(MENU_MODE_PROFILE);
+			if (key == KEY_UP) {
+			    if (current_unit->profile_uuid)
+			    	go_menu(MENU_MODE_PROFILE);
+			    else
+				go_menu(MENU_MODE_BEER);
+			}
 			if (key == KEY_ENTER) {
 			    change_mode(UNITMODE_OFF);
 			    go_menu(MENU_MODE_OFF);
@@ -622,8 +613,12 @@
 	case MENU_MODE_BEER:
 			if (key == KEY_ESCAPE)
 			    go_menu(MENU_UNITS);
-			if (key == KEY_DOWN)
-			    go_menu(MENU_MODE_PROFILE);
+			if (key == KEY_DOWN) {
+			    if (current_unit->profile_uuid)
+			    	go_menu(MENU_MODE_PROFILE);
+			    else
+				go_menu(MENU_MODE_OFF);
+			}
 			if (key == KEY_UP)
 			    go_menu(MENU_MODE_FRIDGE);
 			if (key == KEY_ENTER) {
@@ -661,14 +656,6 @@
 			break;
 
 	case MENU_MODE_PROFILE:
-			if (current_unit->profile) {
-			    for (current_profile = Config.profiles; current_profile; current_profile = current_profile->next) {
-				if (strcmp(current_profile->uuid, current_unit->profile) == 0)
-				    break;
-			    }
-			} else {
-			    current_profile = NULL;
-			}
 			if (key == KEY_ESCAPE)
 			    go_menu(MENU_UNITS);
 			if (key == KEY_DOWN)
@@ -678,10 +665,7 @@
 			if (key == KEY_ENTER) {
 			    if (current_unit->mode == UNITMODE_PROFILE) {
 				switch (current_unit->prof_state) {
-				    case PROFILE_OFF:	if (current_unit->profile)
-							    go_menu(MENU_PROFILE_START);
-							else
-					    		    go_menu(MENU_PROFILE_SELECT);
+				    case PROFILE_OFF:	go_menu(MENU_PROFILE_START);
 							break;
 				    case PROFILE_PAUSE:	go_menu(MENU_PROFILE_RESUME);
 							break;
@@ -697,39 +681,9 @@
 			}
 			break;
 
-	case MENU_PROFILE_SELECT:
-			if (key == KEY_ESCAPE)
-			    go_menu(MENU_MODE_PROFILE);
-			if (key == KEY_DOWN) {
-			    if (current_profile->next) {
-			    	current_profile = current_profile->next;
-			    	go_menu(MENU_PROFILE_SELECT);
-			    } else {
-			    	go_menu(MENU_PROFILE_START);
-			    }
-			}
-			if (key == KEY_UP) {
-			    for (profile = Config.profiles; profile; profile = profile->next) {
-				if (profile->next && profile->next == current_profile) {
-				    current_profile = profile;
-				    go_menu(MENU_PROFILE_SELECT);
-				    break;
-				}
-			    }
-			    go_menu(MENU_PROFILE_START);
-			}
-			if (key == KEY_ENTER) {
-			    current_unit->profile = current_profile->uuid;
-			    syslog(LOG_NOTICE, "Profile %s selected from panel", current_profile->name);
-			    go_menu(MENU_PROFILE_START);
-			}
-			break;
-
 	case MENU_PROFILE_START:
 			if (key == KEY_ESCAPE)
 			    go_menu(MENU_MODE_PROFILE);
-			if ((key == KEY_DOWN) || (key == KEY_UP))
-			    go_menu(MENU_PROFILE_SELECT);
 			if (key == KEY_ENTER) {
 			    current_unit->prof_state = PROFILE_RUN;
 			    current_unit->prof_started = time(NULL);
@@ -981,7 +935,6 @@
     char		use_heater[40], use_cooler[40], use_fan[40], room_temp[40];
     time_t		now, last = (time_t)0, ndata = (time_t)0;;
     units_list		*unit;
-    profiles_list	*profile;
     prof_step		*step;
     int			row, rc, run = 1, seconds = 0, minutes = 0, temp, deviation;
     int			run_seconds, run_minutes, run_hours, tot_minutes, key;
@@ -1078,7 +1031,7 @@
 	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;
 	if (unit->mode == UNITMODE_PROFILE) {
-	    if (!unit->profile)
+	    if (!unit->profile_uuid)
 		syslog(LOG_NOTICE, "Starting unit `%s' in profile mode, no profile defined.", unit->alias);
 	    else {
 	    	syslog(LOG_NOTICE, "Starting unit `%s' in profile state %s.", unit->alias, PROFSTATE[unit->prof_state]);
@@ -1390,9 +1343,8 @@
 		/*
 		 * Handle profile
 		 */
-		if ((unit->mode == UNITMODE_PROFILE) && (unit->profile)) {
+		if ((unit->mode == UNITMODE_PROFILE) && (unit->profile_uuid)) {
 		    /*
-		     * unit->profile		- uuid of the selected profile.
 		     * unit->prof_started	- start time or 0 if not yet running.
 		     * unit->prof_state		- PROFILE_OFF|PROFILE_PAUSE|PROFILE_RUN|PROFILE_DONE
 		     * unit->prof_target	- Calculated target temperature.
@@ -1401,171 +1353,174 @@
 		     * unit->prof_peak_rel	- Peak temperature between beer and fridge.
 		     * unit->prof_primary_done	- time when primary fermentation was over the peak.
 		     */
-		    for (profile = Config.profiles; profile; profile = profile->next) {
-			if (strcmp(unit->profile, profile->uuid) == 0) {
 
-			    /*
-			     * Safe defaults
-			     */
-			    unit->prof_target_lo = profile->inittemp_lo;
-			    unit->prof_target_hi = profile->inittemp_hi;
-			    unit->prof_fridge_mode = 0;
+		    /*
+		     * Safe defaults
+		     */
+		    unit->prof_target_lo = unit->profile_inittemp_lo;
+		    unit->prof_target_hi = unit->profile_inittemp_hi;
+		    unit->prof_fridge_mode = 0;
 
-			    switch (unit->prof_state) {
-				case PROFILE_OFF:
-						unit->prof_percent = 0;
-						break;
-				case PROFILE_PAUSE:
-						/*
-						 * Keep current temperature, measure pause time. For
-						 * temperature fall thru.
-						 */
-						unit->prof_paused++;
-				case PROFILE_RUN:
+		    switch (unit->prof_state) {
+			case PROFILE_OFF:
+					unit->prof_percent = 0;
+					break;
+			case PROFILE_PAUSE:
+					/*
+					 * Keep current temperature, measure pause time. For
+					 * temperature fall thru.
+					 */
+					unit->prof_paused++;
+			case PROFILE_RUN:
+					/*
+					 * Calculate current profile step and desired temperature.
+					 * When all steps are done, set state to PROFILE_DONE.
+					 */
+					previous_target_lo = unit->profile_inittemp_lo;
+					previous_target_hi = unit->profile_inittemp_hi;
+					previous_fridge_mode = unit->profile_fridge_mode;
+					time_until_now = current_step = 0;
+					run_seconds = (int)(now - unit->prof_started - unit->prof_paused);
+					run_minutes = run_seconds / 60;
+					run_hours = run_minutes / 60;
+					if (debug)
+					    fprintf(stdout, "run_HMS=%d,%d,%d ", run_hours, run_minutes, run_seconds);
+
+					/*
+					 * Primary fermentation tests
+					 */
+					if ((unit->beer_temperature / 1000.0) > unit->prof_peak_abs)
+					    unit->prof_peak_abs = unit->beer_temperature / 1000.0;
+					if (((unit->beer_temperature - unit->air_temperature) / 1000.0) > unit->prof_peak_rel)
+					    unit->prof_peak_rel = (unit->beer_temperature - unit->air_temperature) / 1000.0;
+					if (unit->prof_primary_done == 0) {
+					    if (unit->cooler_address) {
 						/*
-						 * Calculate current profile step and desired temperature.
-						 * When all steps are done, set state to PROFILE_DONE.
-						 */
-						previous_target_lo = profile->inittemp_lo;
-						previous_target_hi = profile->inittemp_hi;
-						previous_fridge_mode = profile->fridge_mode;
-						time_until_now = current_step = 0;
-						run_seconds = (int)(now - unit->prof_started - unit->prof_paused);
-						run_minutes = run_seconds / 60;
-						run_hours = run_minutes / 60;
-						if (debug)
-						    fprintf(stdout, "run_HMS=%d,%d,%d ", run_hours, run_minutes, run_seconds);
-
-						/*
-						 * Primary fermentation tests
-						 */
-						if ((unit->beer_temperature / 1000.0) > unit->prof_peak_abs)
-						    unit->prof_peak_abs = unit->beer_temperature / 1000.0;
-						if (((unit->beer_temperature - unit->air_temperature) / 1000.0) > unit->prof_peak_rel)
-						    unit->prof_peak_rel = (unit->beer_temperature - unit->air_temperature) / 1000.0;
-						if (unit->prof_primary_done == 0) {
-						    if (unit->cooler_address) {
-							/*
-							 * There is a cooler. If the difference between the beer and air temperature
-							 * drops we assume the primary fermentation is done.
-							 */
-							if (((unit->beer_temperature - unit->air_temperature) / 1000.0) < (unit->prof_peak_rel - 0.5)) {
-							    unit->prof_primary_done = time(NULL);
-							    syslog(LOG_NOTICE, "Profile `%s' primary fermentation is ready (cooler mode)", profile->name);
-							}
-						    } else {
-						    	/*
-						    	 * 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)) {
-							    unit->prof_primary_done = time(NULL);
-							    syslog(LOG_NOTICE, "Profile `%s' primary fermentation is ready (free rise mode)", profile->name);
-						    	}
-						    }
-						}
-
-						/*
-						 * See how long this profile will take
+						 * There is a cooler. If the difference between the beer and air temperature
+						 * drops we assume the primary fermentation is done.
 						 */
-						tot_minutes = 0;
-						for (step = profile->steps; step; step = step->next) {
-						    tot_minutes += ((step->steptime + step->resttime) * 60);
+						if (((unit->beer_temperature - unit->air_temperature) / 1000.0) < (unit->prof_peak_rel - 0.5)) {
+						    unit->prof_primary_done = time(NULL);
+						    syslog(LOG_NOTICE, "Profile `%s' primary fermentation is ready (cooler mode)", unit->profile_name);
 						}
+					    } else {
+					    	/*
+					    	 * 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)) {
+						    unit->prof_primary_done = time(NULL);
+						    syslog(LOG_NOTICE, "Profile `%s' primary fermentation is ready (free rise mode)", unit->profile_name);
+					    	}
+					    }
+					}
+
+					/*
+					 * See how long this profile will take
+					 */
+					tot_minutes = 0;
+					for (step = unit->profile_steps; step; step = step->next) {
+					    tot_minutes += ((step->steptime + step->resttime) * 60);
+					}
+					if ((tot_minutes == 0) && unit->profile_totalsteps) {
+					    syslog(LOG_NOTICE, "Profile `%s' steps disappeared", unit->profile_name);
+					    unit->prof_state = PROFILE_OFF;
+					    break;
+					}
 
-						valid_step = FALSE;
-						for (step = profile->steps; step; step = step->next) {
-						    /*
-						     * step->steptime
-						     * step->resttime
-						     * step->target
-						     */
-						    current_step++;
-						    if ((run_hours >= time_until_now) && (run_hours < (time_until_now + step->steptime + step->resttime))) {
-							/*
-							 * This is our current step
-							 */
-							valid_step = TRUE;
-							if (debug)
-							    fprintf(stdout, "step=%d step_pos=%d step=%d/%d target=%.1f..%.1f ", 
-									    current_step, run_hours - time_until_now,
-									    step->steptime, step->resttime, step->target_lo, step->target_hi);
-							if ((run_hours - time_until_now) < step->steptime) {
-							    unit->prof_target_lo = previous_target_lo + (((run_minutes - (time_until_now * 60.0)) / (step->steptime * 60.0)) * (step->target_lo - previous_target_lo));
-							    unit->prof_target_hi = previous_target_hi + (((run_minutes - (time_until_now * 60.0)) / (step->steptime * 60.0)) * (step->target_hi - previous_target_hi));
-							    if (step->fridge_mode > previous_fridge_mode) {
-							    	unit->prof_fridge_mode = (((run_minutes - (time_until_now * 60)) * 100) / (step->steptime * 60));
-							    } else if (step->fridge_mode < previous_fridge_mode) {
-								unit->prof_fridge_mode = 100 - (((run_minutes - (time_until_now * 60)) * 100) / (step->steptime * 60));
-							    } else {
-								unit->prof_fridge_mode = step->fridge_mode;
-							    }
-							    if (debug)
-								fprintf(stdout, "tempshift=%.1f..%.1f  minutes=%d duration=%d temp_move=%.3f..%.3f ", 
-										step->target_lo - previous_target_lo,
-										step->target_hi - previous_target_hi,
-										run_minutes - (time_until_now * 60), 
-										step->steptime * 60, unit->prof_target_lo, unit->prof_target_hi);
-							} else {
-							    unit->prof_target_lo = step->target_lo;
-							    unit->prof_target_hi = step->target_hi;
-							    unit->prof_fridge_mode = step->fridge_mode;
-							    if (debug)
-							    	fprintf(stdout, "resting target=%.1f..%.1f ", step->target_lo, step->target_hi);
-							}
-							break;
+					valid_step = FALSE;
+					for (step = unit->profile_steps; step; step = step->next) {
+					    /*
+					     * step->steptime
+					     * step->resttime
+					     * step->target
+					     */
+					    current_step++;
+					    if ((run_hours >= time_until_now) && (run_hours < (time_until_now + step->steptime + step->resttime))) {
+						/*
+						 * This is our current step
+						 */
+						valid_step = TRUE;
+			//			if (debug)
+			//			    fprintf(stdout, "step=%d step_pos=%d step=%d/%d target=%.1f..%.1f ", 
+			//					    current_step, run_hours - time_until_now,
+			//					    step->steptime, step->resttime, step->target_lo, step->target_hi);
+						if ((run_hours - time_until_now) < step->steptime) {
+						    unit->prof_target_lo = previous_target_lo + (((run_minutes - (time_until_now * 60.0)) / (step->steptime * 60.0)) * (step->target_lo - previous_target_lo));
+						    unit->prof_target_hi = previous_target_hi + (((run_minutes - (time_until_now * 60.0)) / (step->steptime * 60.0)) * (step->target_hi - previous_target_hi));
+						    if (step->fridge_mode > previous_fridge_mode) {
+						    	unit->prof_fridge_mode = (((run_minutes - (time_until_now * 60)) * 100) / (step->steptime * 60));
+						    } else if (step->fridge_mode < previous_fridge_mode) {
+							unit->prof_fridge_mode = 100 - (((run_minutes - (time_until_now * 60)) * 100) / (step->steptime * 60));
+						    } else {
+							unit->prof_fridge_mode = step->fridge_mode;
 						    }
-						    time_until_now += step->steptime + step->resttime;
-						    previous_target_lo = step->target_lo;
-						    previous_target_hi = step->target_hi;
-						    previous_fridge_mode = step->fridge_mode;
-						}
-						if (debug)
-						    fprintf(stdout, " %s %02d:%02d\n", valid_step ? "TRUE":"FALSE", minutes, seconds);
-
-						if (valid_step == TRUE) {
-						    unit->prof_percent = (100 * run_minutes) / tot_minutes;
-						    if (((minutes == 10) || (minutes == 40)) && (seconds == 1)) {
-						    	syslog(LOG_NOTICE, "Profile `%s' running %dd %02d:%02d in step %d, %d%% done, target %s %.3f..%.3f degrees", 
-								profile->name, run_hours / 24, run_hours % 24, run_minutes % 60, current_step, 
-								unit->prof_percent, unit->prof_fridge_mode ? (char *)"air":(char *)"beer",
-								unit->prof_target_lo, unit->prof_target_hi);
-							unit->mqtt_flag |= MQTT_FLAG_DATA;
-						    }
+						    if (debug)
+							fprintf(stdout, "prof_fridge_mode=%d run_minutes=%d steptime=%d time_until_now=%d\n",
+									unit->prof_fridge_mode, run_minutes, step->steptime, time_until_now);
+			//			    if (debug)
+			//				fprintf(stdout, "tempshift=%.1f..%.1f  minutes=%d duration=%d temp_move=%.3f..%.3f ", 
+			//						step->target_lo - previous_target_lo,
+			//						step->target_hi - previous_target_hi,
+			//						run_minutes - (time_until_now * 60), 
+			//						step->steptime * 60, unit->prof_target_lo, unit->prof_target_hi);
 						} else {
-						    /*
-						     * No more steps to do
-						     */
-						    unit->prof_state = PROFILE_DONE;
-						    unit->prof_percent = 100;
-						    syslog(LOG_NOTICE, "Profile `%s' is done", profile->name);
-						    unit->mqtt_flag |= MQTT_FLAG_DATA;
+						    unit->prof_target_lo = step->target_lo;
+						    unit->prof_target_hi = step->target_hi;
+						    unit->prof_fridge_mode = step->fridge_mode;
+			//			    if (debug)
+			//			    	fprintf(stdout, "resting target=%.1f..%.1f ", step->target_lo, step->target_hi);
 						}
 						break;
+					    }
+					    time_until_now += step->steptime + step->resttime;
+					    previous_target_lo = step->target_lo;
+					    previous_target_hi = step->target_hi;
+					    previous_fridge_mode = step->fridge_mode;
+					}
+			//		if (debug)
+			//		    fprintf(stdout, " %s %02d:%02d\n", valid_step ? "TRUE":"FALSE", minutes, seconds);
 
-				case PROFILE_DONE:
-						/*
-						 * Keep this state, set target temperature to the last step.
-						 */
-						previous_target_lo = profile->inittemp_lo;
-						previous_target_hi = profile->inittemp_hi;
-						previous_fridge_mode = profile->fridge_mode;
-						for (step = profile->steps; step; step = step->next) {
-						    if ((step->steptime + step->resttime) == 0)
-							break;
-						    previous_target_lo = step->target_lo;
-						    previous_target_hi = step->target_hi;
-						    previous_fridge_mode = step->fridge_mode;
+					if (valid_step == TRUE) {
+					    unit->prof_percent = (100 * run_minutes) / tot_minutes;
+					    if (((minutes == 10) || (minutes == 40)) && (seconds == 1)) {
+					    	syslog(LOG_NOTICE, "Profile `%s' running %dd %02d:%02d in step %d, %d%% done, target %s %.3f..%.3f degrees", 
+							unit->profile_name, run_hours / 24, run_hours % 24, run_minutes % 60, current_step, 
+							unit->prof_percent, unit->prof_fridge_mode ? (char *)"air":(char *)"beer",
+							unit->prof_target_lo, unit->prof_target_hi);
+						unit->mqtt_flag |= MQTT_FLAG_DATA;
+					    }
+					} else {
+					    /*
+					     * No more steps to do
+					     */
+					    unit->prof_state = PROFILE_DONE;
+					    unit->prof_percent = 100;
+					    syslog(LOG_NOTICE, "Profile `%s' is done", unit->profile_name);
+					    unit->mqtt_flag |= MQTT_FLAG_DATA;
+					}
+					break;
 
-						}
-						unit->prof_target_lo = previous_target_lo;
-						unit->prof_target_hi = previous_target_hi;
-						unit->prof_fridge_mode = previous_fridge_mode;
-						unit->prof_percent = 100;
+			case PROFILE_DONE:
+					/*
+					 * Keep this state, set target temperature to the last step.
+					 */
+					previous_target_lo = unit->profile_inittemp_lo;
+					previous_target_hi = unit->profile_inittemp_hi;
+					previous_fridge_mode = unit->profile_fridge_mode;
+					for (step = unit->profile_steps; step; step = step->next) {
+					    if ((step->steptime + step->resttime) == 0)
 						break;
-			    } /* switch */
-			}
-		    }
+					    previous_target_lo = step->target_lo;
+					    previous_target_hi = step->target_hi;
+					    previous_fridge_mode = step->fridge_mode;
+					}
+					unit->prof_target_lo = previous_target_lo;
+					unit->prof_target_hi = previous_target_hi;
+					unit->prof_fridge_mode = previous_fridge_mode;
+					unit->prof_percent = 100;
+					break;
+		    } /* switch */
 		} else {
 		    /*
 		     * Set some sane values
@@ -1628,8 +1583,8 @@
 		     */
 		    unit->PID_cool->Mode = unit->PID_heat->Mode = PID_MODE_NONE;
 		    if (unit->mode == UNITMODE_FRIDGE) {
-			unit->PID_cool->SetP = unit->fridge_set; // + unit->PID_cool->idleRange;
-			unit->PID_heat->SetP = unit->fridge_set; // - unit->PID_heat->idleRange;
+			unit->PID_cool->SetP = unit->fridge_set;
+			unit->PID_heat->SetP = unit->fridge_set;
 			unit->PID_cool->Input = unit->PID_heat->Input = unit->air_temperature / 1000.0;
 			unit->PID_cool->Mode = unit->PID_heat->Mode = PID_MODE_BOO;
 		    } else if (unit->mode == UNITMODE_BEER) {
@@ -1794,9 +1749,6 @@
 			    device_out(unit->cooler_address, 0);
 			}
 		    }
-//		    if (debug)
-//			fprintf(stdout, "Final: PIDheat=%.2f PWRheat=%d  PIDcool=%.2f PWRcool=%d\n", 
-//					unit->PID_heat->OutP, unit->heater_state, unit->PID_cool->OutP, unit->cooler_state);
 
 		    /*
 		     * If there is a fan, and the unit door is closed, and the unit should be doing
--- a/thermferm/thermferm.h	Thu Jan 10 16:33:42 2019 +0100
+++ b/thermferm/thermferm.h	Mon Jan 14 22:46:27 2019 +0100
@@ -81,7 +81,6 @@
 #define MENU_MODE_FRIDGE	214
 #define MENU_FRIDGE_TEMP	2141
 #define MENU_MODE_PROFILE	215
-#define	MENU_PROFILE_SELECT	2151
 #define	MENU_PROFILE_START	2152
 #define	MENU_PROFILE_PAUSE	2153
 #define	MENU_PROFILE_ABORT	2154
@@ -120,6 +119,21 @@
 
 
 /*
+ * Fermenting steps
+ */
+typedef struct _prof_step {
+    struct _prof_step   *next;
+    char                *name;                  /* Description of this step     */
+    int                 steptime;               /* Step time to target in hours */
+    int                 resttime;               /* Rest time on target in hours */
+    float               target_lo;              /* Low Target temperature       */
+    float               target_hi;              /* High target temperature      */
+    int                 fridge_mode;            /* Fridge or beer mode          */
+} prof_step;
+
+
+
+/*
  * Fermenter units. These units are connected via the 1-wire bus.
  * Each unit can have:
  *  a DS18B20 sensor to measure the air temperature inside the unit.
@@ -128,7 +142,6 @@
  */
 typedef struct _units_list {
     struct _units_list	*next;
-    int			version;		/* Record version		*/
     char		*uuid;			/* uid code			*/
     char		*product_uuid;		/* Beer product uuid		*/
     char		*product_code;		/* Beer product code		*/
@@ -182,7 +195,14 @@
     float		fridge_set;		/* Fridge temperature setting	*/
     float		temp_set_min;		/* Minimum temperature		*/
     float		temp_set_max;		/* Maximum temperature		*/
-    char		*profile;		/* Active profile uuid		*/
+    char		*profile_uuid;		/* Profile uuid or NULL		*/
+    char		*profile_name;		/* Profile name			*/
+    float		profile_inittemp_lo;	/* Profile initial temp low	*/
+    float		profile_inittemp_hi;	/* Profile initial temp high	*/
+    int			profile_fridge_mode;	/* Profile initial fridge mode	*/
+    int			profile_duration;	/* Profile duration in hours	*/
+    int			profile_totalsteps;	/* Profile number of steps	*/
+    prof_step		*profile_steps;		/* Profile steps                */
     time_t		prof_started;		/* Profile start time		*/
     int			prof_state;		/* Profile OFF|PAUSE|RUN|DONE	*/
     float		prof_target_lo;		/* Profile current target low	*/
@@ -228,35 +248,6 @@
 #define	ALARM_FLAG_CHILLER	0x0100		/* Chiller too warm		*/
 
 
-
-/*
- * Fermenting steps
- */
-typedef struct _prof_step {
-    struct _prof_step	*next;
-    int			version;		/* Version 1			*/
-    int			steptime;		/* Step time to target in hours	*/
-    int			resttime;		/* Rest time on target in hours	*/
-    float		target_lo;		/* Low Target temperature	*/
-    float		target_hi;		/* High target temperature	*/
-    int			fridge_mode;		/* Fridge or beer mode		*/
-} prof_step;
-
-/*
- * Fermenting profiles
- */
-typedef struct _prof_list {
-    struct _prof_list	*next;
-    int			version;		/* Version 1			*/
-    char		*uuid;			/* Profile uuid			*/
-    char		*name;			/* Profile name			*/
-    int			busy;			/* Profile busy == 1, free == 0	*/
-    float		inittemp_lo;		/* Low target before start	*/
-    float		inittemp_hi;		/* High target before start	*/
-    int			fridge_mode;		/* Fridge or beer mode		*/
-    prof_step		*steps;			/* Profile steps		*/
-} profiles_list;
-
 #define PROFILE_OFF		0		/* Profile not active		*/
 #define	PROFILE_PAUSE		1		/* Profile pause		*/
 #define	PROFILE_RUN		2		/* Profile is running		*/
@@ -269,7 +260,6 @@
  */
 typedef struct _dev_list {
     struct _dev_list	*next;
-    int			version;		/* Version 1			*/
     char		*uuid;			/* UUID of this device		*/
     int			type;			/* Device type			*/
     int			direction;		/* Device direction		*/
@@ -319,7 +309,6 @@
  */
 typedef struct _simulator {
     struct _simulator	*next;
-    int			version;		/* Version of this record	*/
     char		*uuid;			/* Simulator uuid		*/
     char		*name;			/* Simulator name		*/
     int			volume_air;		/* Volume air of the frigo	*/
@@ -368,7 +357,7 @@
     int			lcd_address;		/* LCD display i2c address	*/
     int			next_unit;		/* Next unit alias name		*/
     units_list		*units;			/* Fermenter units		*/
-    profiles_list	*profiles;		/* Ferment profiles		*/
+//    profiles_list	*profiles;		/* Ferment profiles		*/
     devices_list	*devices;		/* Sensors and switches		*/
 #ifdef USE_SIMULATOR
     simulator_list	*simulators;		/* Simulators			*/
--- a/www-thermferm/index.php	Thu Jan 10 16:33:42 2019 +0100
+++ b/www-thermferm/index.php	Mon Jan 14 22:46:27 2019 +0100
@@ -1,6 +1,6 @@
 <?php
 /*****************************************************************************
- * Copyright (C) 2014-2017
+ * Copyright (C) 2014-2019
  *   
  * Michiel Broek <mbroek at mbse dot eu>
  *
@@ -87,9 +87,7 @@
 if (isset($_POST['SetProfile']) && isset($_POST['key']) && isset($_POST['UUID'])) {
 
     $cmd = array('UNIT PUT '.$_POST['UUID']);
-    if ($_POST['key'] == "Set")
-	$cmd[] = 'PROFILE,'.$_POST['SetProfile'];
-    else if ($_POST['key'] == "Start")
+    if ($_POST['key'] == "Start")
 	$cmd[] = 'PROF_STATE,RUN';
     else if (($_POST['key'] == "Pause") || ($_POST['key'] == "Resume"))
 	$cmd[] = 'PROF_STATE,PAUSE';
--- a/www-thermferm/liveview.php	Thu Jan 10 16:33:42 2019 +0100
+++ b/www-thermferm/liveview.php	Mon Jan 14 22:46:27 2019 +0100
@@ -1,6 +1,6 @@
 <?php
 /*****************************************************************************
- * Copyright (C) 2014-2018
+ * Copyright (C) 2014-2019
  *   
  * Michiel Broek <mbroek at mbse dot eu>
  *
@@ -42,7 +42,7 @@
 	$air_temperature = "NA";
 	$beer_temperature = "NA";
 	$chiller_temperature = "NA";
-	$profile = "";
+	$profile_uuid = $profile_name = "";
 	$producr_code = "";
 	$product_name = "";
 	$prof_state = "OFF";
@@ -51,6 +51,7 @@
 	$heater_state = $cooler_state = $fan_state = 0;
 
 	foreach($arr as $l) {
+//	    syslog(LOG_NOTICE, $l);
 	    $vals = explode(",", $l);
 	    if (strcmp($vals[0], "MODE") == 0) {
 		$mode = $vals[1];
@@ -99,8 +100,11 @@
 	    if (strcmp($vals[0], "FAN_STATE") == 0) {
 		$fan_state = $vals[1];
 	    }
-	    if (strcmp($vals[0], "PROFILE") == 0) {
-		$profile = $vals[1];
+	    if (strcmp($vals[0], "PROFILE_UUID") == 0) {
+		$profile_uuid = $vals[1];
+	    }
+	    if (strcmp($vals[0], "PROFILE_NAME") == 0) {
+		$profile_name = $vals[1];
 	    }
 	    if (strcmp($vals[0], "PROF_STATE") == 0) {
 		$prof_state = $vals[1];
@@ -275,69 +279,24 @@
 	    $outstr .= '       </form>'.PHP_EOL;
 	}
 	if ($mode == "PROFILE") {
-	    /*
-	     * First, load a list with available profiles.
-	     */
-	    $answer = send_cmd("PROFILE LIST");
-	    $reply = explode("\r\n", $answer);
-
-	    /*
-	     * Show loaded profile.
-	     */
-	    if ($profile == "(null)") {
-		$prof_name = "None";
-	    }else {
-		if (startsWith($reply[0], "212")) {
-		    $i = 1;
-		    while (1) {
-			if (strcmp($reply[$i], ".") == 0)
-			    break;
-			$f = explode(",", $reply[$i]);
-			if ($f[0] == $profile) {
-			    $prof_name = $f[1];
-			    break;
-			}
-			$i++;
-		    }
-		}
-	    }
-	    $outstr .= '       <div style="color: blue; width: 148px; height: 23px; overflow: hidden;">Profile: '.$prof_name.'</div>'.PHP_EOL;
+	    $outstr .= '       <div style="color: blue; width: 148px; height: 23px; overflow: hidden;">Profile: '.$profile_name.'</div>'.PHP_EOL;
 	    $outstr .= '       <div id="prof_state_'.$unr.'" style="color: blue; width: 148px; height: 23px; overflow: hidden;">State: '.$prof_state.'</div>'.PHP_EOL;
 
 	    $outstr .= '       <form id="set_profile_'.$unr.'" action="index.php" method="post">'.PHP_EOL;
 	    if ($prof_state == "OFF") {
-	    	$outstr .= '        <select name="SetProfile" style="width: 130px;">'.PHP_EOL;
-	    	$outstr .= '         <option value="">None</option>'.PHP_EOL;
-	    	if (startsWith($reply[0], "212")) {
-		    $i = 1;
-		    while (1) {
-			if (strcmp($reply[$i], ".") == 0)
-			    break;
-			$f = explode(",", $reply[$i]);
-			if ($f[2] > 0) {
-			    ($f[0] == $profile) ? $se = " selected" : $se = "";
-			    $outstr .= '         <option value="'.$f[0].'"'.$se.'>'.$f[1].'</option>'.PHP_EOL;
-			}
-			$i++;
-		    }
-	    	}
-		$outstr .= '        </select>'.PHP_EOL;
-		$outstr .= '        <input type="submit" value="Set" name="key">'.PHP_EOL;
-		if ($profile != "(null)")
+		if ($profile_name != "")
 		    $outstr .= '        <input type="submit" value="Start" name="key">'.PHP_EOL;
 
 	    } else if (startsWith($prof_state, "RUN")) {
-		$outstr .= '        <input type="hidden" value="'.$profile.'" name="SetProfile">'.PHP_EOL;
 		$outstr .= '        <input type="submit" value="Pause" name="key">'.PHP_EOL;
 		$outstr .= '        <input type="submit" value="Abort" name="key">'.PHP_EOL;
 	    } else if ($prof_state == "PAUSE") {
-		$outstr .= '        <input type="hidden" value="'.$profile.'" name="SetProfile">'.PHP_EOL;
 		$outstr .= '        <input type="submit" value="Resume" name="key">'.PHP_EOL;
 		$outstr .= '        <input type="submit" value="Abort" name="key">'.PHP_EOL;
 	    } else if ($prof_state == "DONE") {
-		$outstr .= '        <input type="hidden" value="'.$profile.'" name="SetProfile">'.PHP_EOL;
 		$outstr .= '        <input type="submit" value="Off" name="key">'.PHP_EOL;
 	    }
+	    $outstr .= '        <input type="hidden" value="'.$profile_uuid.'" name="SetProfile">'.PHP_EOL;	// Only to select the right form.
 	    $outstr .= '        <input type="hidden" value="'.$unit.'" name="UUID">'.PHP_EOL;
 	    $outstr .= '       </form>'.PHP_EOL;
 	}
--- a/www-thermferm/maintenance.php	Thu Jan 10 16:33:42 2019 +0100
+++ b/www-thermferm/maintenance.php	Mon Jan 14 22:46:27 2019 +0100
@@ -1,6 +1,6 @@
 <?php
 /*****************************************************************************
- * Copyright (C) 2014-2015
+ * Copyright (C) 2014-2019
  *   
  * Michiel Broek <mbroek at mbse dot eu>
  *
@@ -74,21 +74,18 @@
 $outstr .= '     </div>'.PHP_EOL;
 $outstr .= '     <div id="menu_left">'.PHP_EOL;
 $outstr .= '      <form action="global.php" style="margin:20px;">'.PHP_EOL;
-$outstr .= '       <input type="submit" class="jqx-button" style="width: 200px; height: 25px;" value="Global Setup" />'.PHP_EOL;
+$outstr .= '       <input type="submit" id="global" value="Global Setup" />'.PHP_EOL;
 $outstr .= '      </form>'.PHP_EOL;
 $outstr .= '      <form action="devices.php" style="margin:20px;">'.PHP_EOL;
-$outstr .= '       <input type="submit" class="jqx-button" style="width: 200px; height: 25px;" value="Devices Setup" />'.PHP_EOL;
+$outstr .= '       <input type="submit" id="devices" value="Devices Setup" />'.PHP_EOL;
 $outstr .= '      </form>'.PHP_EOL;
 $outstr .= '      <form action="archives.php" style="margin:20px;">'.PHP_EOL;
-$outstr .= '       <input type="submit" class="jqx-button" style="width: 200px; height: 25px;" value="Archives" />'.PHP_EOL;
+$outstr .= '       <input type="submit" id="archives" value="Archives" />'.PHP_EOL;
 $outstr .= '      </form>'.PHP_EOL;
 $outstr .= '     </div>'.PHP_EOL;
 $outstr .= '     <div id="menu_right">'.PHP_EOL;
-$outstr .= '      <form action="profiles.php" style="margin:20px;">'.PHP_EOL;
-$outstr .= '       <input type="submit" class="jqx-button" style="width: 200px; height: 25px;" value="Fermentation Profiles" />'.PHP_EOL;
-$outstr .= '      </form>'.PHP_EOL;
 $outstr .= '      <form action="units.php" style="margin:20px;">'.PHP_EOL;
-$outstr .= '       <input type="submit" class="jqx-button" style="width: 200px; height: 25px;" value="Fermentation Units" />'.PHP_EOL;
+$outstr .= '       <input type="submit" id="units" value="Fermentation Units" />'.PHP_EOL;
 $outstr .= '      </form>'.PHP_EOL;
 /*
  * See if the server supports simulators
@@ -103,6 +100,10 @@
 $outstr .= '    <script type="text/javascript">'.PHP_EOL;
 $outstr .= '     $(document).ready(function () {'.PHP_EOL;
 $outstr .= '      $("#maintenance").jqxButton({ width: 150, height: 25, theme: \'ui-redmond\' });'.PHP_EOL;
+$outstr .= '      $("#global").jqxButton({ width: 200, height: 25, theme: \'ui-redmond\' });'.PHP_EOL;
+$outstr .= '      $("#archives").jqxButton({ width: 200, height: 25, theme: \'ui-redmond\' });'.PHP_EOL;
+$outstr .= '      $("#devices").jqxButton({ width: 200, height: 25, theme: \'ui-redmond\' });'.PHP_EOL;
+$outstr .= '      $("#units").jqxButton({ width: 200, height: 25, theme: \'ui-redmond\' });'.PHP_EOL;
 $outstr .= '     });'.PHP_EOL;
 $outstr .= '    </script>'.PHP_EOL;
 $outstr .= build_footer();
--- a/www-thermferm/profiles.php	Thu Jan 10 16:33:42 2019 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,596 +0,0 @@
-<?php
-/*****************************************************************************
- * Copyright (C) 2014-2015
- *   
- * Michiel Broek <mbroek at mbse dot eu>
- *
- * This file is part of ThermFerm
- *
- * This is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2, or (at your option) any
- * later version.
- *
- * ThermFerm is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- * 
- * You should have received a copy of the GNU General Public License
- * along with ThermFerm; see the file COPYING.  If not, write to the Free
- * Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- *****************************************************************************/
-
-require_once('utilities.php');
-$my_style = 'ui-redmond';
-
-
-/*
- * Each time this page is loaded, get the profiles from the server.
- * $arr contains the complete reply of he PROFILE LIST command.
- */
-$answer = send_cmd("PROFILE LIST");
-$arr = explode("\r\n", $answer);
-
-
-
-if (isset($_GET['action'])) {
-    switch ($_GET['action']) {
-	case 'edit':		profile_edit();
-				break;
-	case 'esteps':		profile_steps();
-				break;
-	default:		break;
-    }
-} elseif (isset($_POST['action'])) {
-    switch ($_POST['action']) {
-	case 'testdata':	testdata();
-				break;
-	case 'teststeps':	teststeps();
-				break;
-	default:		break;
-    }
-} else {
-    profile_list();
-}
-
-exit;
-
-
-
-/*
- * Profile steps
- */
-function profile_steps()
-{
-    global $arr;
-    $UUID = $_GET['UUID'];
-    
-    /*
-     * $steps contains all steps of a profile
-     */
-    $steps = array (
-	1  => array("steptime" => 0, "resttime" => 0, "target_lo" => 19.8, "target_hi" => 20.2, "fridge_mode" => 0 ),
-	2  => array("steptime" => 0, "resttime" => 0, "target_lo" => 19.8, "target_hi" => 20.2, "fridge_mode" => 0 ),
-	3  => array("steptime" => 0, "resttime" => 0, "target_lo" => 19.8, "target_hi" => 20.2, "fridge_mode" => 0 ),
-	4  => array("steptime" => 0, "resttime" => 0, "target_lo" => 19.8, "target_hi" => 20.2, "fridge_mode" => 0 ),
-	5  => array("steptime" => 0, "resttime" => 0, "target_lo" => 19.8, "target_hi" => 20.2, "fridge_mode" => 0 ),
-	6  => array("steptime" => 0, "resttime" => 0, "target_lo" => 19.8, "target_hi" => 20.2, "fridge_mode" => 0 ),
-	7  => array("steptime" => 0, "resttime" => 0, "target_lo" => 19.8, "target_hi" => 20.2, "fridge_mode" => 0 ),
-	8  => array("steptime" => 0, "resttime" => 0, "target_lo" => 19.8, "target_hi" => 20.2, "fridge_mode" => 0 ),
-    );
-
-    $answer = send_cmd("PROFILE GETS ".$UUID);
-    $psteps = explode("\r\n", $answer);
-
-    if (startsWith($arr[0], "212")) {
-	$j = 1;
-	while (1) {
-	    if (strcmp($psteps[$j], ".") == 0)
-		break;
-	    $f = explode(",", $psteps[$j]);
-	    $steps[$j]["steptime"] = $f[0];
-	    $steps[$j]["resttime"] = $f[1];
-	    $steps[$j]["target_lo"] = $f[2];
-	    $steps[$j]["target_hi"] = $f[3];
-	    $steps[$j]["fridge_mode"] = $f[4];
-	    $j++;
-	}
-    }
-
-    edit_steps($UUID, $steps, "", "ThermFerm - Edit Profile Steps");
-}
-
-
-function edit_steps($UUID, $steps, $error_message, $heading)
-{
-    $outstr  = build_header($heading);
-    $outstr .= '    <div id="errors">'.PHP_EOL;
-    $outstr .= '     '.$error_message.PHP_EOL;
-    $outstr .= '    </div> <!-- errors -->'.PHP_EOL;
-    $outstr .= '    <div id="etable">'.PHP_EOL;
-    $outstr .= '     <form method="POST" action="profiles.php">'.PHP_EOL;
-    $outstr .= '      <table class="editor">'.PHP_EOL;
-    $outstr .= '       <tr class="trhead">'.PHP_EOL;
-    $outstr .= '        <td>Step</td>'.PHP_EOL;
-    $outstr .= '        <td>Steptime</td>'.PHP_EOL;
-    $outstr .= '        <td>Resttime</td>'.PHP_EOL;
-    $outstr .= '        <td>Temp low</td>'.PHP_EOL;
-    $outstr .= '        <td>Temp high</td>'.PHP_EOL;
-    $outstr .= '        <td>Fridge mode</td>'.PHP_EOL;
-    $outstr .= '       </tr>'.PHP_EOL;
-
-    for ($i = 1; $i <= 8; $i++) {
-    	$outstr .= '       <tr class="editor">'.PHP_EOL;
-    	$outstr .= '        <td>Step '.$i.'</td>'.PHP_EOL;
-    	$outstr .= '        <td><input type="text" name="steptime'.$i.'" size="4" value="'.$steps[$i]["steptime"].'"></td>'.PHP_EOL;
-    	$outstr .= '        <td><input type="text" name="resttime'.$i.'" size="4" value="'.$steps[$i]["resttime"].'"></td>'.PHP_EOL;
-	$outstr .= '        <td><input type="text" name="target_lo'.$i.'" size="4" value="'.$steps[$i]["target_lo"].'"></td>'.PHP_EOL;
-	$outstr .= '        <td><input type="text" name="target_hi'.$i.'" size="4" value="'.$steps[$i]["target_hi"].'"></td>'.PHP_EOL;
-	$outstr .= '        <td><input type="hidden" name="fridge_mode'.$i.'" value="0"><input type="checkbox" name="fridge_mode'.$i.'" value="100"';
-	if ($steps[$i]["fridge_mode"] > 0)
-	    $outstr .= ' checked';
-	$outstr .= '></td>'.PHP_EOL;
-    	$outstr .= '       </tr>'.PHP_EOL;
-    }
-
-    $outstr .= '       <tr class="editor">'.PHP_EOL;
-    $outstr .= '        <td class="editname">&nbsp;</td>'.PHP_EOL;
-    $outstr .= '        <td class="editname"><input type="submit" value="Save" name="key"></td>'.PHP_EOL;
-    $outstr .= '        <td class="editname"><input type="submit" value="Cancel" name="key">';
-    $outstr .= '<input type="hidden" value="teststeps" name="action">';
-    $outstr .= '<input type="hidden" value="'.$UUID.'" name="UUID"></td>'.PHP_EOL;
-    $outstr .= '        <td class="editname">&nbsp;</td>'.PHP_EOL;
-    $outstr .= '       </tr>'.PHP_EOL;
-    $outstr .= '      </table>'.PHP_EOL;
-    $outstr .= '     </form>'.PHP_EOL;
-    $outstr .= '    </div> <!-- etable -->'.PHP_EOL;
-    $outstr .= '    <div id="atable" style="margin-left: 100px; width:780px;">'.PHP_EOL;
-    $outstr .= '    The steptime is the time to go from the previous to the target temperature.'.PHP_EOL;
-    $outstr .= '    The resttime is the time in this step holding the target temperature.'.PHP_EOL;
-    $outstr .= '    The duration of the step is steptime + resttime.'.PHP_EOL;
-    $outstr .= '    Steps are valid if the steptime or resttime is greater then zero.'.PHP_EOL;
-    $outstr .= '    Order is important.'.PHP_EOL;
-    $outstr .= '    Lines with a zero steptime and zero resttime are ignored.'.PHP_EOL;
-    $outstr .= '    The step- and resttimes are in hours.'.PHP_EOL;
-    $outstr .= '    </div> <!-- atable -->'.PHP_EOL;
-    $outstr .= '    <script type="text/javascript">'.PHP_EOL;
-    $outstr .= '     $(document).ready(function () {'.PHP_EOL;
-    $outstr .= '      $("#maintenance").jqxButton({ width: 150, height: 25, theme: \'ui-redmond\' });'.PHP_EOL;
-    $outstr .= '     });'.PHP_EOL;
-    $outstr .= '    </script>'.PHP_EOL;
-    $outstr .= build_footer();
-    echo $outstr;
-}
-
-
-
-
-/*
- * Profile add
- *
- * @param string $_POST['Name'] The rpofile name
- */
-function profile_add() {
-
-    if ($_POST['key'] == 'Add') {
-	send_cmd("PROFILE ADD ".$_POST['Name']);
-    }
-    unset($_POST['UUID']);
-    unset($_POST['Name']);
-    unset($_POST['Steps']);
-    unset($_POST['key']);
-    unset($_POST['command']);
-    load('profiles.php');
-}
-
-
-
-/*
- * Profile update or delete
- *
- * @param string $_POST['UUID'] The profile UUID
- * @param string $_POST['Name'] The profile name
- * @param string $_POST['Inittemp_lo'] The profile initial temperature low
- * @param string $_POST['Inittemp_hi'] The profile initial temperature high
- * @param string $_POST['Fridge_mode'] The profile fridge/beer mode
- * @param string $_POST['key'] The button pressed.
- */
-function profile_update() {
-    /*
-     * Build the update command
-     */
-    if ($_POST['key'] == 'Delete') {
-	send_cmd("PROFILE DEL ".$_POST['UUID']);
-    }
-
-    if ($_POST['key'] == 'Save') {
-	$cmd = array("PROFILE PUT ".$_POST['UUID']);
-	$cmd[] = "NAME,".$_POST['Name'];
-	$cmd[] = "INITTEMP_LO,".$_POST['Inittemp_lo'];
-	$cmd[] = "INITTEMP_HI,".$_POST['Inittemp_hi'];
-	$cmd[] = "FRIDGE_MODE,".$_POST['Fridge_mode'];
-	$cmd[] = ".";
-	send_array($cmd);
-    }
-
-    unset($_POST['UUID']);
-    unset($_POST['Name']);
-    unset($_POST['Inittemp_lo']);
-    unset($_POST['Inittemp_hi']);
-    unset($_POST['Fridge_mode']);
-    unset($_POST['key']);
-    unset($_POST['command']);
-    load('profiles.php');
-}
-
-
-
-/*
- * Test input of a modified or new profile.
- *
- * @param string $_POST['UUID'] Unique record UUID
- * @param int $_POST['steptime'n] Profile steptime
- * @param int $_POST['resttime'n] Profile resttime
- * @param float $_POST['target_lo'n] Profile target temperature low
- * @param float $_POST['target_hi'n] Profile target temperature high
- * @param int $_POST['fridge_mode'n] Profile fridge mode
- * @param string $_POST['key'] Key choice, Save or Cancel
- *
- * Return: 0 = Ok
- *         1 = Missing data
- *         3 = A target temperature out of range
- *        99 = Cancel key
- */
-function test_thesteps() {
-
-    global $arr;
-
-    for ($i = 1; $i <= 8; $i++) {
-	if ((! isset($_POST['steptime'.$i])) || (! isset($_POST['resttime'.$i])) || (! isset($_POST['target_lo'.$i])) || (! isset($_POST['target_hi'.$i])) || (! isset($_POST['fridge_mode'.$i])))
-		return 1;
-	if ((strlen($_POST['steptime'.$i]) == 0) || (strlen($_POST['resttime'.$i]) == 0) || (strlen($_POST['target_lo'.$i]) == 0) || (strlen($_POST['target_hi'.$i]) == 0) || (strlen($_POST['fridge_mode'.$i]) == 0))
-		return 1;
-    }
-
-    if (isset($_POST['UUID']) && isset($_POST['key'])) {
-
-        if ($_POST['key'] == 'Cancel')
-            return 99;
-
-	for ($i = 1; $i <= 8; $i++) {
-
-	    if (($_POST['target_lo'.$i] < -5) || ($_POST['target_lo'.$i] > 30))
-		    return 3;
-	    if (($_POST['target_hi'.$i] < -5) || ($_POST['target_hi'.$i] > 30))
-		    return 3;
-	    if ($_POST['target_lo'.$i] > $_POST['target_hi'.$i])
-		    return 3;
-	}
-    } else {
-        return 1;
-    }
-
-    return 0;
-}
-
-
-
-/*
- * Test result from edit_steps screen and do next action
- */
-function teststeps() {
-
-    $result = test_thesteps();
-    $error = '';
-
-    switch ($result) {
-        case 0: $cmd = array("PROFILE PUTS ".$_POST['UUID']);
-		for ($i = 1; $i <= 8; $i++) {
-			if (($_POST['steptime'.$i] > 0) || ($_POST['resttime'.$i] > 0)) {
-			    $cmd[] = $_POST['steptime'.$i].','.$_POST['resttime'.$i].','.$_POST['target_lo'.$i].','.$_POST['target_hi'.$i].','.$_POST['fridge_mode'.$i];
-		    }
-		    unset($_POST['steptime'.$i]);
-		    unset($_POST['resttime'.$i]);
-		    unset($_POST['target_lo'.$i]);
-		    unset($_POST['target_hi'.$i]);
-		    unset($_POST['fridge_mode'.$i]);
-		}
-		$cmd[] = ".";
-		send_array($cmd);
-		unset($_POST['UUID']);
-		unset($_POST['key']);
-		load('profiles.php');
-		return;
-		break;
-        case 1: $error = 'Missing data';
-		break;
-	case 2: $error = 'A resttime is shorter then the steptime';
-		break;
-	case 3:	$error = 'A target temperature is out of range';
-		break;
-        case 99:
-                load('profiles.php');
-                break;
-    }
-
-    $steps = array (
-	1  => array("steptime" => $_POST['steptime1'], "resttime" => $_POST['resttime1'], "target_lo" => $_POST['target_lo1'], "target_hi" => $_POST['target_hi1'], "fridge_mode" => $_POST['mode_fridge1'] ),
-	2  => array("steptime" => $_POST['steptime2'], "resttime" => $_POST['resttime2'], "target_lo" => $_POST['target_lo2'], "target_hi" => $_POST['target_hi2'], "fridge_mode" => $_POST['mode_fridge2'] ),
-	3  => array("steptime" => $_POST['steptime3'], "resttime" => $_POST['resttime3'], "target_lo" => $_POST['target_lo3'], "target_hi" => $_POST['target_hi3'], "fridge_mode" => $_POST['mode_fridge3'] ),
-	4  => array("steptime" => $_POST['steptime4'], "resttime" => $_POST['resttime4'], "target_lo" => $_POST['target_lo4'], "target_hi" => $_POST['target_hi4'], "fridge_mode" => $_POST['mode_fridge4'] ),
-	5  => array("steptime" => $_POST['steptime5'], "resttime" => $_POST['resttime5'], "target_lo" => $_POST['target_lo5'], "target_hi" => $_POST['target_hi5'], "fridge_mode" => $_POST['mode_fridge5'] ),
-	6  => array("steptime" => $_POST['steptime6'], "resttime" => $_POST['resttime6'], "target_lo" => $_POST['target_lo6'], "target_hi" => $_POST['target_hi6'], "fridge_mode" => $_POST['mode_fridge6'] ),
-	7  => array("steptime" => $_POST['steptime7'], "resttime" => $_POST['resttime7'], "target_lo" => $_POST['target_lo7'], "target_hi" => $_POST['target_hi7'], "fridge_mode" => $_POST['mode_fridge7'] ),
-	8  => array("steptime" => $_POST['steptime8'], "resttime" => $_POST['resttime8'], "target_lo" => $_POST['target_lo8'], "target_hi" => $_POST['target_hi8'], "fridge_mode" => $_POST['mode_fridge8'] ),
-    );
-    
-    edit_steps($_POST['UUID'], $steps, $error, "ThermFerm - Edit Profile Steps");
-}
-
-
-
-/*
- * Test input of a modified or new profile.
- *
- * @param string $_POST['UUID'] Unique record UUID
- * @param string $_POST['Name'] Profile name
- * @param float $_POST['Inittemp_lo'] Profile initial temperature
- * @param float $_POST['Inittemp_hi'] Profile initial temperature
- * @param float $_POST['Fridge_mode'] Profile fridge mode
- * @param string $_POST['key'] Key choice, Save or Cancel
- * @param string $_POST['command'] Command used, 'add' or 'update'
- *
- * Return: 0 = Ok
- *         1 = Missing data
- *         2 = Name field too short
- *         3 = Name already in use
- *        99 = Cancel key
- */
-function test_thedata() {
-
-    global $arr;
-
-    if (isset($_POST['UUID']) && isset($_POST['Name']) && isset($_POST['Inittemp_lo']) && isset($_POST['Inittemp_hi']) && isset($_POST['key']) && isset($_POST['command'])) {
-
-	if ($_POST['key'] == 'Cancel')
-	    return 99;
-
-	if (strlen($_POST['Name']) < 2)
-	    return 2;
-
-	if (startsWith($arr[0], "212")) {
-	    $j = 1;
-	    while (1) {
-		if (strcmp($arr[$j], ".") == 0)
-		    break;
-		$f = explode(",", $arr[$j]);
-		if (strcmp($f[0], $_POST['UUID']) && (strcmp($f[1], $_POST['Name']) == 0)) {
-		    return 3;
-		}
-		$j++;
-	    }
-	}
-
-    } else {
-	return 1;
-    }
-
-    return 0;
-}
-
-
-
-/*
- * Test result from edit screen and do next action
- */
-function testdata() {
-
-    $result = test_thedata();
-    $error = '';
-
-    switch ($result) {
-	case 0:	if ($_POST['command'] == 'add') {
-		    profile_add();
-		    return;
-	        } else if ($_POST['command'] == 'update') {
-		    profile_update();
-		    return;
-		}
-		break;
-	case 1:	$error = 'Missing data';
-		break;
-	case 2:	$error = 'The name is too short';
-		break;
-	case 3:	$error = 'The name is already in use, choose another one';
-		break;
-	case 99:	
-		load('profiles.php');
-		break;
-    }
-
-    if ($_POST['command'] == 'add') {
-	$heading = 'ThermFerm - Add Profile';
-    } else {
-	$heading = 'ThermFerm - Edit Profile';
-    }
-
-    edit_screen($_POST['UUID'], $_POST['command'], $heading, $error);
-}
-
-
-
-/*
- * Profiles edit screen. Used by profile_edit(), profile_add() and testdata()
- *
- * @param string $UUID The record UUID (fixed).
- * @param string $Name The Profile Name.
- * @param string $command 'add' or 'update'
- * @param string $heading Pagina heading title.
- * @Param string $error_message Blank or previous error.
- */
-function edit_screen($UUID, $command, $heading, $error_message) {
-
-    /*
-     * Get current profile data
-     */
-    $answer = send_cmd("PROFILE GET ".$UUID);
-    $reply = explode("\r\n", $answer);
-
-    $outstr  = build_header($heading);
-    $outstr .= '    <div id="errors">'.PHP_EOL;
-    $outstr .= '     '.$error_message.PHP_EOL;
-    $outstr .= '    </div> <!-- errors -->'.PHP_EOL;
-    $outstr .= '    <div id="etable">'.PHP_EOL;
-    $outstr .= '     <form method="POST" action="profiles.php">'.PHP_EOL;
-    $outstr .= '      <table class="editor">'.PHP_EOL;
-
-    if (startsWith($reply[0], "213")) {
-	$i = 1;
-	while (1) {
-	    if (strcmp($reply[$i], ".") == 0)
-		break;
-	    $f = explode(",", $reply[$i]);
-
-    	    if ($f[0] == "NAME") {
-    		$outstr .= '       <tr class="editor">'.PHP_EOL;
-    		$outstr .= '        <td class="editname">Profile Name</td>'.PHP_EOL;
-    		$outstr .= '        <td class="editfield"><input type="text" name="Name" size="50" value="'.$f[1].'"></td>'.PHP_EOL;
-    		$outstr .= '       </tr>'.PHP_EOL;
-	    }
-	    if ($f[0] == "INITTEMP_LO") {
-		$outstr .= '       <tr class="editor">'.PHP_EOL;
-		$outstr .= '        <td class="editname">Initial temperature low</td>'.PHP_EOL;
-		$outstr .= '        <td class="editfield"><input type="text" name="Inittemp_lo" size="5" value="'.$f[1].'"></td>'.PHP_EOL;
-		$outstr .= '       </tr>'.PHP_EOL;
-	    }
-	    if ($f[0] == "INITTEMP_HI") {
-		$outstr .= '       <tr class="editor">'.PHP_EOL;
-		$outstr .= '        <td class="editname">Initial temperature high</td>'.PHP_EOL;
-		$outstr .= '        <td class="editfield"><input type="text" name="Inittemp_hi" size="5" value="'.$f[1].'"></td>'.PHP_EOL;
-		$outstr .= '       </tr>'.PHP_EOL;
-	    }
-	    if ($f[0] == "FRIDGE_MODE") {
-		$outstr .= '       <tr class="editor">'.PHP_EOL;
-		$outstr .= '        <td class="editname">Fridge mode</td>'.PHP_EOL;
-		$outstr .= '        <td class="editfield"><input type="hidden" name="Fridge_mode" value="0"><input type="checkbox" name="Fridge_mode" value="100"';
-		if ($f[1] > 0)
-		    $outstr .= " checked";
-		$outstr .= '></td>'.PHP_EOL;
-		$outstr .= '       </tr>'.PHP_EOL;
-	    }
-
-	    $i++;
-	}
-    }
-    $outstr .= '       <tr class="editor">'.PHP_EOL;
-    $outstr .= '        <td class="editname"><input type="submit" value="Save" name="key"></td>'.PHP_EOL;
-    $outstr .= '        <td class="editfield"><input type="submit" value="Cancel" name="key">';
-    $outstr .= '<input type="submit" value="Delete" name="key" style="margin-left: 100px;">';
-    $outstr .= '<input type="hidden" value="testdata" name="action">';
-    $outstr .= '<input type="hidden" value="'.$command.'" name="command">';
-    $outstr .= '<input type="hidden" value="'.$UUID.'" name="UUID"></td>'.PHP_EOL;
-    $outstr .= '       </tr>'.PHP_EOL;
-    $outstr .= '      </table>'.PHP_EOL;
-    $outstr .= '     </form>'.PHP_EOL;
-    $outstr .= '    </div> <!-- etable -->'.PHP_EOL;
-    $outstr .= '    <script type="text/javascript">'.PHP_EOL;
-    $outstr .= '     $(document).ready(function () {'.PHP_EOL;
-    $outstr .= '      $("#maintenance").jqxButton({ width: 150, height: 25, theme: \'ui-redmond\' });'.PHP_EOL;
-    $outstr .= '     });'.PHP_EOL;
-    $outstr .= '    </script>'.PHP_EOL;
-    $outstr .= build_footer();
-    echo $outstr;
-}
-
-
-
-/*
- * Edit a Profile. Fetches the record data and shows the edit screen.
- *
- * @param string $_GET['action'] Must be 'edit'.
- * @param string $_GET['UUID'] The UUID of the Profile.
- */
-function profile_edit() {
-    if ($_GET['action'] == 'edit') {
-	edit_screen($_GET['UUID'], 'update', 'ThermFerm - Edit Profile', '');
-	return;
-    } else {
-	load('profiles.php');
-    }
-}
-
-
-
-/*
- * @link Edit profile
- * @link Add profile
- */
-function profile_list() {
-
-    global $arr;
-
-    $outstr  = build_header("ThermFerm - Profiles");
-
-    $outstr .= '    <div id="errors">'.PHP_EOL;
-    $outstr .= '    </div> <!-- errors -->'.PHP_EOL;
-    $outstr .= '    <div id="etable">'.PHP_EOL;
-    $outstr .= '     <table class="setup">'.PHP_EOL;
-    $outstr .= '      <tr class="trhead">'.PHP_EOL;
-    $outstr .= '       <td class="setup" style="width: 300px;">UUID</td>'.PHP_EOL;
-    $outstr .= '       <td class="setup" style="width: 300px;">Name</td>'.PHP_EOL;
-    $outstr .= '       <td class="setup" style="width: 40px;">Steps</td>'.PHP_EOL;
-    $outstr .= '       <td class="setup" style="width: 40px;">Edit</td>'.PHP_EOL;
-    $outstr .= '      </tr>'.PHP_EOL;
-
-    if (startsWith($arr[0], "212")) {
-    	$j = 1;
-    	while (1) {
-	    if (strcmp($arr[$j], ".") == 0)
-	    	break;
-	    $f = explode(",", $arr[$j]);
-	    $outstr .= '      <tr class="setup">'.PHP_EOL;
-	    $outstr .= '       <td class="setup">'.$f[0].'</td>'.PHP_EOL;
-	    $outstr .= '       <td class="setup">'.$f[1].'</td>'.PHP_EOL;
-	    if ($f[3] == 1) {
-		$outstr .= '       <td class="setup">'.$f[2].'</td>'.PHP_EOL;
-	    	$outstr .= '       <td class="setup">Busy</td>'.PHP_EOL;
-	    } else {
-		$outstr .= '       <td class="setup"><a href="profiles.php?action=esteps&amp;UUID='.$f[0].'">'.$f[2].'</a></td>'.PHP_EOL;
-		$outstr .= '       <td class="setup"><a href="profiles.php?action=edit&amp;UUID='.$f[0].'">Edit</a></td>'.PHP_EOL;
-	    }
-	    $outstr .= '      </tr>'.PHP_EOL;
-	    $j++;
-    	}
-    }
-
-    $outstr .= '     </table>'.PHP_EOL;
-    $outstr .= '    </div> <!-- etable -->'.PHP_EOL;
-    $outstr .= '    <div id="atable">'.PHP_EOL;
-
-    $outstr .= '     <form method="POST" action="profiles.php">'.PHP_EOL;
-    $outstr .= '      <table class="editor">'.PHP_EOL;
-    $outstr .= '      <tr class="trhead"><td colspan="3">Add new profile</td></tr>'.PHP_EOL;
-    $outstr .= '       <tr class="editor">'.PHP_EOL;
-    $outstr .= '        <td class="editname">Profile Name</td>'.PHP_EOL;
-    $outstr .= '        <td class="editfield"><input type="text" name="Name" size="50" value=""></td>'.PHP_EOL;
-    $outstr .= '        <td class="editsub"><input type="submit" value="Add" name="key"></td>'.PHP_EOL;
-    $outstr .= '<input type="hidden" value="testdata" name="action">';
-    $outstr .= '<input type="hidden" value="add" name="command">';
-    $outstr .= '<input type="hidden" value="00000000-0000-0000-0000-000000000000" name="UUID">';
-    $outstr .= '<input type="hidden" value="19.8" name="Inittemp_lo"></td>';
-    $outstr .= '<input type="hidden" value="20.2" name="Inittemp_hi"></td>';
-    $outstr .= '       </tr>'.PHP_EOL;
-    $outstr .= '      </table>'.PHP_EOL;
-    $outstr .= '     </form>'.PHP_EOL;
-
-    $outstr .= '    </div> <!-- atable -->'.PHP_EOL;
-    $outstr .= '    <script type="text/javascript">'.PHP_EOL;
-    $outstr .= '     $(document).ready(function () {'.PHP_EOL;
-    $outstr .= '      $("#maintenance").jqxButton({ width: 150, height: 25, theme: \'ui-redmond\' });'.PHP_EOL;
-    $outstr .= '     });'.PHP_EOL;
-    $outstr .= '    </script>'.PHP_EOL;
-    $outstr .= build_footer();
-    echo $outstr;
-}
-

mercurial