Switched to xml configuration

Thu, 26 Jun 2014 20:00:00 +0200

author
Michiel Broek <mbroek@mbse.eu>
date
Thu, 26 Jun 2014 20:00:00 +0200
changeset 80
81bf78a7618e
parent 79
eb9dd60aa791
child 81
547bbe344886

Switched to xml configuration

thermferm/rdconfig.c file | annotate | diff | comparison | revisions
thermferm/sensors.c file | annotate | diff | comparison | revisions
thermferm/server.c file | annotate | diff | comparison | revisions
thermferm/thermferm.c file | annotate | diff | comparison | revisions
--- a/thermferm/rdconfig.c	Wed Jun 25 19:42:03 2014 +0200
+++ b/thermferm/rdconfig.c	Thu Jun 26 20:00:00 2014 +0200
@@ -73,6 +73,7 @@
 void killconfig(void)
 {
     w1_therm	*tmp1, *old1;
+    units_list	*tmp2;
 
     if (Config.name)
 	free(Config.name);
@@ -90,6 +91,26 @@
     }
     Config.w1therms = NULL;
     Config.my_port = 6554;
+    Config.tempFormat = 'C';
+
+    for (tmp2 = Config.units; tmp2; tmp2 = tmp2->next) {
+	if (tmp2->uuid)
+	    free(tmp2->uuid);
+	if (tmp2->name)
+	    free(tmp2->name);
+	if (tmp2->air_address)
+	    free(tmp2->air_address);
+	if (tmp2->beer_address)
+	    free(tmp2->beer_address);
+	if (tmp2->io1_address)
+	    free(tmp2->io1_address);
+	if (tmp2->io2_address)
+	    free(tmp2->io2_address);
+	if (tmp2->profile)
+	    free(tmp2->profile);
+	free(tmp2);
+    }
+    Config.units = NULL;
 
 #ifdef HAVE_WIRINGPI_H
     Config.lcd_cols = 16;
@@ -347,7 +368,7 @@
 		syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
 		return 1;
 	    }
-	    if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "NAME", "%s", MBSE_SS(tmp3->name))) < 0) {
+	    if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "NAME", "%s", tmp3->name)) < 0) {
 		syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
 		return 1;
 	    }
@@ -355,19 +376,19 @@
 		syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
 		return 1;
 	    }
-	    if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "AIR_ADDRESS", "%s", MBSE_SS(tmp3->air_address))) < 0) {
+	    if (tmp3->air_address && ((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 "BEER_ADDRESS", "%s", MBSE_SS(tmp3->beer_address))) < 0) {
+	    if (tmp3->beer_address && ((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 "IO1_ADDRESS", "%s", MBSE_SS(tmp3->io1_address))) < 0) {
+	    if (tmp3->io1_address && ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "IO1_ADDRESS", "%s", tmp3->io1_address)) < 0)) {
 		syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
 		return 1;
 	    }
-	    if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "IO2_ADDRESS", "%s", MBSE_SS(tmp3->io2_address))) < 0) {
+	    if (tmp3->io2_address && ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "IO2_ADDRESS", "%s", tmp3->io2_address)) < 0)) {
 		syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
 		return 1;
 	    }
@@ -469,11 +490,299 @@
 
 
 
+/*
+ * Parse one LCD display
+ */
+#ifdef HAVE_WIRINGPI_H
+int parseLCD(xmlDocPtr doc, xmlNodePtr cur)
+{
+    xmlChar	*key;
+    int		ival;
+
+    cur = cur->xmlChildrenNode;
+    while (cur != NULL) {
+	if ((!xmlStrcmp(cur->name, (const xmlChar *)"COLUMNS"))) {
+	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
+	    if (sscanf((const char *)key, "%d", &ival) == 1)
+	        Config.lcd_cols = ival;
+	    xmlFree(key);
+	}
+	if ((!xmlStrcmp(cur->name, (const xmlChar *)"ROWS"))) {
+	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
+	    if (sscanf((const char *)key, "%d", &ival) == 1)
+		Config.lcd_rows = ival;
+	    xmlFree(key);
+	}
+	if ((!xmlStrcmp(cur->name, (const xmlChar *)"ADDRESS"))) {
+	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
+	    if (sscanf((const char *)key, "%x", &ival) == 1)
+		Config.lcd_address = ival;
+	    xmlFree(key);
+	}
+	cur = cur->next;
+    }
+
+    return 0;
+}
+
+
+
+int parseLCDs(xmlDocPtr doc, xmlNodePtr cur)
+{
+    cur = cur->xmlChildrenNode;
+    while (cur != NULL) {
+	if ((!xmlStrcmp(cur->name, (const xmlChar *)"LCD"))) {
+	    parseLCD(doc, cur);
+	}
+	cur = cur->next;
+    }
+    return 0;
+}
+#endif
+
+
+
+int parseW1therm(xmlDocPtr doc, xmlNodePtr cur)
+{
+    xmlChar     *key;
+    int         ival;
+    w1_therm	*w1therm, *tmp;
+
+    w1therm = (w1_therm *)malloc(sizeof(w1_therm));
+    w1therm->next = NULL;
+    w1therm->master = w1therm->name = w1therm->alias = NULL;
+    w1therm->bus = w1therm->present = w1therm->lastval = w1therm->update = 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;
+	    }
+	    xmlFree(key);
+	}
+	if ((!xmlStrcmp(cur->name, (const xmlChar *)"MASTER"))) {
+	    w1therm->master = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
+	}
+	if ((!xmlStrcmp(cur->name, (const xmlChar *)"BUS"))) {
+	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
+	    if (sscanf((const char *)key, "%d", &ival) == 1)
+		w1therm->bus = ival;
+	    xmlFree(key);
+	}
+	if ((!xmlStrcmp(cur->name, (const xmlChar *)"NAME"))) {
+	    w1therm->name = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
+	}
+	if ((!xmlStrcmp(cur->name, (const xmlChar *)"ALIAS"))) {
+	    w1therm->alias = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
+	}
+	cur = cur->next;
+    }
+
+    if (Config.w1therms == NULL) {
+	Config.w1therms = w1therm;
+    } else {
+	for (tmp = Config.w1therms; tmp; tmp = tmp->next) {
+	    if (tmp->next == NULL) {
+		tmp->next = w1therm;
+		break;
+	    }
+	}
+    }
+
+    return 0;
+}
+
+
+
+int parseW1therms(xmlDocPtr doc, xmlNodePtr cur)
+{
+    cur = cur->xmlChildrenNode;
+    while (cur != NULL) {
+	if ((!xmlStrcmp(cur->name, (const xmlChar *)"W1TERM"))) {
+	    parseW1therm(doc, cur);
+	}
+	cur = cur->next;
+    }
+    return 0;
+}
+
+
+
+/*
+ * Parse a fermenter unit
+ */
+int parseUnit(xmlDocPtr doc, xmlNodePtr cur)
+{
+    xmlChar     *key;
+    int         i, ival;
+    float	val;
+    units_list	*unit, *tmp;
+
+    unit = (units_list *)malloc(sizeof(units_list));
+    unit->next = NULL;
+    unit->uuid = unit->name = unit->air_address = unit->beer_address = unit->io1_address = unit->io2_address = unit->profile = NULL;
+    unit->volume = 0.0;
+    unit->heater_available = unit->cooler_available = unit->fan_available = FALSE;
+    unit->air_temp = unit->beer_temp = unit->beer_set = unit->fridge_set = 20.0;
+    unit->heater_state = unit->cooler_state = unit->fan_state = unit->door_state = unit->mode = 0;
+    unit->temp_set_min = 1.0;
+    unit->temp_set_max = 30.0;
+    unit->idle_rangeH = 1.0;
+    unit->idle_rangeL = -1.0;
+    unit->prof_started = (time_t)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;
+	    }
+	    xmlFree(key);
+	}
+	if ((!xmlStrcmp(cur->name, (const xmlChar *)"UUID"))) {
+	    unit->uuid = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
+	}
+	if ((!xmlStrcmp(cur->name, (const xmlChar *)"NAME"))) {
+	    unit->name = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
+	}
+	if ((!xmlStrcmp(cur->name, (const xmlChar *)"VOLUME"))) {
+	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
+	    if (sscanf((const char *)key, "%f", &val) == 1)
+		unit->volume = val;
+		xmlFree(key);
+	}
+	if ((!xmlStrcmp(cur->name, (const xmlChar *)"AIR_ADDRESS"))) {
+	    unit->air_address = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
+	}
+	if ((!xmlStrcmp(cur->name, (const xmlChar *)"BEER_ADDRESS"))) {
+	    unit->beer_address = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
+	}
+	if ((!xmlStrcmp(cur->name, (const xmlChar *)"IO1_ADDRESS"))) {
+	    unit->io1_address = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
+	}
+	if ((!xmlStrcmp(cur->name, (const xmlChar *)"IO2_ADDRESS"))) {
+	    unit->io2_address = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
+	}
+	if ((!xmlStrcmp(cur->name, (const xmlChar *)"HEATER"))) {
+	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
+	    if (! xmlStrcmp(key, (const xmlChar *)"TRUE"))
+		unit->heater_available = TRUE;
+	    xmlFree(key);
+	}
+	if ((!xmlStrcmp(cur->name, (const xmlChar *)"COOLER"))) {
+	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
+	    if (! xmlStrcmp(key, (const xmlChar *)"TRUE"))
+		unit->cooler_available = TRUE;
+	    xmlFree(key);
+	}
+	if ((!xmlStrcmp(cur->name, (const xmlChar *)"FAN"))) {
+	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
+	    if (! xmlStrcmp(key, (const xmlChar *)"TRUE"))
+		unit->fan_available = TRUE;
+	    xmlFree(key);
+	}
+	if ((!xmlStrcmp(cur->name, (const xmlChar *)"MODE"))) {
+	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
+	    for (i = 0; i < 5; i++) {
+	    	if (! xmlStrcmp(key, (const xmlChar *)UNITMODE[i])) {
+	   	    unit->mode = i;
+		    break;
+		}
+	    }
+	    xmlFree(key);
+	}
+	if ((!xmlStrcmp(cur->name, (const xmlChar *)"BEER_SET"))) {
+	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
+	    if (sscanf((const char *)key, "%f", &val) == 1)
+		unit->beer_set = val;
+	    xmlFree(key);
+	}
+	if ((!xmlStrcmp(cur->name, (const xmlChar *)"FRIDGE_SET"))) {
+	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
+	    if (sscanf((const char *)key, "%f", &val) == 1)
+		unit->fridge_set = val;
+	    xmlFree(key);
+	}
+	if ((!xmlStrcmp(cur->name, (const xmlChar *)"TEMP_SET_MIN"))) {
+	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
+	    if (sscanf((const char *)key, "%f", &val) == 1)
+		unit->temp_set_min = val;
+	    xmlFree(key);
+	}
+	if ((!xmlStrcmp(cur->name, (const xmlChar *)"TEMP_SET_MAX"))) {
+	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
+	    if (sscanf((const char *)key, "%f", &val) == 1)
+		unit->temp_set_max = val;
+	    xmlFree(key);
+	}
+	if ((!xmlStrcmp(cur->name, (const xmlChar *)"IDLE_RANGE_L"))) {
+	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
+	    if (sscanf((const char *)key, "%f", &val) == 1)
+		unit->idle_rangeL = val;
+	    xmlFree(key);
+	}
+	if ((!xmlStrcmp(cur->name, (const xmlChar *)"IDLE_RANGE_H"))) {
+	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
+	    if (sscanf((const char *)key, "%f", &val) == 1)
+		unit->idle_rangeH = val;
+	    xmlFree(key);
+	}
+	if ((!xmlStrcmp(cur->name, (const xmlChar *)"PROFILE"))) {
+	    unit->profile = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
+	}
+	if ((!xmlStrcmp(cur->name, (const xmlChar *)"PROF_STARTED"))) {
+	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
+	    if (sscanf((const char *)key, "%d", &ival) == 1)
+		unit->prof_started = ival;
+	    xmlFree(key);
+	}
+	cur = cur->next;
+    }
+
+    if (Config.units == NULL) {
+	Config.units = unit;
+    } else {
+	for (tmp = Config.units; tmp; tmp = tmp->next) {
+	    if (tmp->next == NULL) {
+		tmp->next = unit;
+		break;
+	    }
+	}
+    }
+
+    return 0;
+}
+
+
+
+int parseFermenters(xmlDocPtr doc, xmlNodePtr cur)
+{
+    cur = cur->xmlChildrenNode;
+    while (cur != NULL) {
+	if ((!xmlStrcmp(cur->name, (const xmlChar *)"UNIT"))) {
+	    parseUnit(doc, cur);
+	}
+	cur = cur->next;
+    }
+    return 0;
+}
+
+
+
 int rdconfig(char *config) 
 {
-    char	buf[256], *p;
-    FILE	*fp;
-    int		i, rc = 0;
+//    char	buf[256], *p;
+//    FILE	*fp;
+//    int		i, rc = 0;
+    int		rc = 0, ival;
+    xmlDocPtr	doc;
+    xmlNodePtr	cur;
+    xmlChar	*key;
 
     killconfig();
 
@@ -489,28 +798,78 @@
     }
     mypath = xstrcat(mypath, (char *)"/mbsepi-apps/");
     mypath = xstrcat(mypath, config);
-    if ((fp = fopen(mypath, "r")) == NULL) {
+    if ((doc = xmlParseFile(mypath)) == NULL) {
+    //if ((fp = fopen(mypath, "r")) == NULL) {
 	/*
 	 * Not in the users home directory
 	 */
 	free(mypath);
 	mypath = xstrcpy((char *)"/etc/mbsepi-apps/");
 	mypath = xstrcat(mypath, config);
-	if ((fp = fopen(mypath, "r")) == NULL) {
+	if ((doc = xmlParseFile(mypath)) == NULL) {
+	//if ((fp = fopen(mypath, "r")) == NULL) {
 	    /*
 	     * Try /usr/local/etc
 	     */
 	    free(mypath);
 	    mypath = xstrcpy((char *)"/usr/local/etc/mbsepi-apps/");
 	    mypath = xstrcat(mypath, config);
-	    if ((fp = fopen(mypath, "r")) == NULL) {
-		syslog(LOG_NOTICE, "rdconfig: could find %s", config);
+	    if ((doc = xmlParseFile(mypath)) == NULL) {
+	    //if ((fp = fopen(mypath, "r")) == NULL) {
+		syslog(LOG_NOTICE, "rdconfig: could not parse %s", config);
 		return 1;
 	    }
 	}
     }
     syslog(LOG_NOTICE, "rdconfig: using %s", mypath);
 
+    if ((cur = xmlDocGetRootElement(doc)) == NULL) {
+	syslog(LOG_NOTICE, "XML file %s empty.", mypath);
+	xmlFreeDoc(doc);
+	return 1;
+    }
+    if (xmlStrcmp(cur->name, (const xmlChar*)"THERMFERM")) {
+	syslog(LOG_NOTICE, "XML file %s is not a valid configuration file.\n", mypath);
+	xmlFreeDoc(doc);
+	return 1;
+    }
+
+    /*
+     * Parse configuration
+     */
+    cur = cur->xmlChildrenNode;
+    while (cur != NULL) {
+	    // VERSION LISTEN_PORT TEMPFORMAT LCDS FERMENTERS
+//	if ((!xmlStrcmp(cur->name, (const xmlChar *)"VERSION"))) {
+//	    recipe->name = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
+//	}
+	if ((!xmlStrcmp(cur->name, (const xmlChar *)"LISTEN_PORT"))) {
+	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
+	    if (sscanf((const char *)key, "%d", &ival) == 1)
+		Config.my_port = ival;
+	    xmlFree(key);
+	}
+	if ((!xmlStrcmp(cur->name, (const xmlChar *)"TEMPFORMAT"))) {
+	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
+	    Config.tempFormat = key[0];
+	    xmlFree(key);
+	}
+#ifdef HAVE_WIRINGPI_H
+	if ((!xmlStrcmp(cur->name, (const xmlChar *)"LCDS"))) {
+	    parseLCDs(doc, cur);
+	}
+#endif
+	if ((!xmlStrcmp(cur->name, (const xmlChar *)"W1TERMS"))) {
+	    parseW1therms(doc, cur);
+	}
+	if ((!xmlStrcmp(cur->name, (const xmlChar *)"FERMENTERS"))) {
+	    parseFermenters(doc, cur);
+	}
+	cur = cur->next;
+    }
+    xmlFreeDoc(doc);
+
+    /*
     linecnt = 0;
     while (fgets(buf, sizeof(buf) -1, fp)) {
 	linecnt++;
@@ -552,6 +911,7 @@
 
     }
     fclose(fp);
+    */
 
     free(mypath);
     mypath = NULL;
--- a/thermferm/sensors.c	Wed Jun 25 19:42:03 2014 +0200
+++ b/thermferm/sensors.c	Thu Jun 26 20:00:00 2014 +0200
@@ -128,6 +128,7 @@
 	    free(device);
 	    device = NULL;
     	}
+	usleep(10000);
     }
 }
 
--- a/thermferm/server.c	Wed Jun 25 19:42:03 2014 +0200
+++ b/thermferm/server.c	Thu Jun 26 20:00:00 2014 +0200
@@ -70,44 +70,6 @@
 
 
 
-int unit_add(char *name)
-{
-    units_list	*unit, *tmp;
-    uuid_t	uu;
-
-    unit = (units_list *)malloc(sizeof(units_list));
-    unit->next = NULL;
-    unit->uuid = malloc(37);
-    uuid_generate(uu);
-    uuid_unparse(uu, unit->uuid);
-    unit->name = xstrcpy(name);
-    unit->air_address = unit->beer_address = unit->io1_address = unit->io2_address = unit->profile = NULL;
-    unit->volume = 0.0;
-    unit->heater_available = unit->cooler_available = unit->fan_available = FALSE;
-    unit->air_temp = unit->beer_temp = unit->beer_set = unit->fridge_set = 20.0;
-    unit->heater_state = unit->cooler_state = unit->fan_state = unit->door_state = unit->mode = 0;
-    unit->temp_set_min = 1.0;
-    unit->temp_set_max = 30.0;
-    unit->idle_rangeH = 1.0;
-    unit->idle_rangeL = -1.0;
-    unit->prof_started = (time_t)0;
-
-
-    if (Config.units == NULL) {
-	Config.units = unit;
-    } else {
-	for (tmp = Config.units; tmp; tmp = tmp->next) {
-	    if (tmp->next == NULL) {
-		tmp->next = unit;
-		break;
-	    }
-	}
-    }
-    return 0;
-}
-
-
-
 /*
  * Send message to client
  */
@@ -124,7 +86,7 @@
     va_end(va_ptr);
 
     if (debug) {
-    	syslog(LOG_NOTICE, "send: \"%s\"", out);
+	syslog(LOG_NOTICE, "send: \"%s\"", out);
 	fprintf(stdout, "send: \"%s\"\n", out);
     }
 
@@ -132,7 +94,7 @@
 	syslog(LOG_NOTICE, "srv_send failed");
 	return -1;
     }
-
+    
     if (send(s, (char *)"\r\n", 2, 0) != 2) {
 	syslog(LOG_NOTICE, "srv_send failed");
 	return -1;
@@ -143,11 +105,56 @@
 
 
 
-void cmd_die(int onsig)
+int unit_add(char *buf)
 {
-    syslog(LOG_NOTICE, "Server process die on signal %d", onsig);
-    close(s);
-    exit(0);
+    units_list	*unit, *tmp;
+    uuid_t	uu;
+    char	*cmd, *opt;
+    int		id = 1;
+
+    cmd = strtok(buf, " \0");
+    opt = strtok(NULL, "\0");
+    if (opt == NULL) {
+	srv_send((char *)"501 Parameter missing");
+	return 1;
+    }
+
+    if (debug)
+	fprintf(stdout, "cmd: '%s' opt: '%s'\n", MBSE_SS(cmd), MBSE_SS(opt));
+
+    unit = (units_list *)malloc(sizeof(units_list));
+    unit->next = NULL;
+    unit->uuid = malloc(37);
+    uuid_generate(uu);
+    uuid_unparse(uu, unit->uuid);
+    unit->name = xstrcpy(opt);
+    unit->air_address = unit->beer_address = unit->io1_address = unit->io2_address = unit->profile = NULL;
+    unit->volume = 0.0;
+    unit->heater_available = unit->cooler_available = unit->fan_available = FALSE;
+    unit->air_temp = unit->beer_temp = unit->beer_set = unit->fridge_set = 20.0;
+    unit->heater_state = unit->cooler_state = unit->fan_state = unit->door_state = unit->mode = 0;
+    unit->temp_set_min = 1.0;
+    unit->temp_set_max = 30.0;
+    unit->idle_rangeH = 1.0;
+    unit->idle_rangeL = -1.0;
+    unit->prof_started = (time_t)0;
+
+    if (Config.units == NULL) {
+	Config.units = unit;
+    } else {
+	for (tmp = Config.units; tmp; tmp = tmp->next) {
+	    id++;
+	    if (tmp->next == NULL) {
+		tmp->next = unit;
+		break;
+	    }
+	}
+    }
+
+    syslog(LOG_NOTICE, "Unit %d with uuid %s added", id, unit->uuid);
+    srv_send((char *)"211 Unit %d with uuid %s added", id, unit->uuid);
+    current_unit = id;
+    return 0;
 }
 
 
@@ -180,6 +187,12 @@
 	    if (buf[i] == '\r')
 	    	buf[i] = '\0';
 	}
+	for (i = strlen(buf) -1; i > 0; i--) {
+	    if (buf[i] == ' ')
+		buf[i] = '\0';
+	    else
+		break;
+	}
 	if (strlen(buf)) {
 	    if (debug) {
 		syslog(LOG_NOTICE, "recv: \"%s\"", buf);
@@ -189,10 +202,13 @@
 	    /*
 	     * Process commands from the client
 	     */
-	    if (strncmp(buf, "HELP", 4) == 0) {
+	    if (strncmp(buf, "ADD", 3) == 0) {
+		unit_add(buf);
+	    } else if (strncmp(buf, "HELP", 4) == 0) {
 		srv_send((char *)"100 Help text follows");
 		srv_send((char *)"Recognized commands:");
 		srv_send((char *)"");
+		srv_send((char *)"ADD name                  Add a new unit with \"name\"");
 		srv_send((char *)"LCD                       Get LCD screen (allways 4 rows of 20 characters)");
 		srv_send((char *)".");
 	    } else if (strncmp(buf, "LCD", 3) == 0) {
--- a/thermferm/thermferm.c	Wed Jun 25 19:42:03 2014 +0200
+++ b/thermferm/thermferm.c	Thu Jun 26 20:00:00 2014 +0200
@@ -125,7 +125,7 @@
     if (debug)
 	fprintf(stdout, "mbsePi-apps thermferm v%s starting\n", VERSION);
 
-    if (rdconfig((char *)"thermferm.conf")) {
+    if (rdconfig((char *)"thermferm.xml")) {
 	fprintf(stderr, "Error reading configuration\n");
 	syslog(LOG_NOTICE, "halted");
 	return 1;

mercurial