thermferm/rdconfig.c

Sat, 16 May 2015 17:39:30 +0200

author
Michiel Broek <mbroek@mbse.eu>
date
Sat, 16 May 2015 17:39:30 +0200
changeset 362
c92651a54969
parent 313
8448fcf3d799
child 363
468ec0d96cce
permissions
-rw-r--r--

Made the client-server protocol more robust. When a change to a unit is made using the web interface, the main process is stopped during the update. Splitted the PID in two PID's, one for heating and one for cooling. Adjusted the web edit scrreen for this, but there are still rough edges. Replaced the PID code, maybe this one works better for our purpose. The simulator air temperature changes on the simulator heater and cooler, but it is not realistic at all. This is a development version, do not use in production. The version is 0.3.0

/*****************************************************************************
 * Copyright (C) 2014-2015
 *   
 * Michiel Broek <mbroek at mbse dot eu>
 *
 * This file is part of the mbsePi-apps
 *
 * 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.
 *
 * mbsePi-apps 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.
 *****************************************************************************/

#include "rdconfig.h"
#include "thermferm.h"
#include "futil.h"
#include "xutil.h"

int		debug = FALSE;
static char	*mypath;
sys_config	Config;			/* System configuration		*/

#define MY_ENCODING "utf-8"

const char	TEMPSTATE[3][8] = { "OK", "MISSING", "ERROR" };
const char      UNITMODE[5][8]	= { "OFF", "NONE", "FRIDGE", "BEER", "PROFILE" };
const char	PROFSTATE[5][6]	= { "OFF", "PAUSE", "RUN", "DONE", "ABORT" };
const char	DEVTYPE[8][6] = { "NA", "W1", "GPIO", "RC433", "DHT", "I2C", "SPI", "SIM" };
const char	DEVPRESENT[4][6] = { "UNDEF", "NO", "YES", "ERROR" };
const char	DEVDIR[7][11] = { "UNDEF", "IN_BIN", "OUT_BIN", "IN_ANALOG", "OUT_ANALOG", "OUT_PWM", "INTERN" };
const char	PIDMODE[3][5] = { "NONE", "AUTO", "BOO" };


void killconfig(void)
{
    units_list		*tmp2;
    profiles_list	*tmp3;
    prof_step		*tmp4;
    devices_list	*device;
#ifdef USE_SIMULATOR
    simulator_list	*simulator;
#endif

    if (Config.name)
	free(Config.name);
    Config.name = NULL;

    Config.my_port = 6554;
    Config.tempFormat = 'C';
    if (Config.temp_address)
	free(Config.temp_address);
    if (Config.hum_address)
	free(Config.hum_address);
    Config.temp_address = Config.hum_address = NULL;
    Config.temp_value = 20000;
    Config.temp_state = Config.hum_state = 1;	// missing
    Config.hum_value = 50000;

    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->heater_address)
	    free(tmp2->heater_address);
	if (tmp2->cooler_address)
	    free(tmp2->cooler_address);
	if (tmp2->fan_address)
	    free(tmp2->fan_address);
	if (tmp2->light_address)
	    free(tmp2->light_address);
	if (tmp2->door_address)
	    free(tmp2->door_address);
	if (tmp2->psu_address)
	    free(tmp2->psu_address);
	if (tmp2->profile)
	    free(tmp2->profile);
	free(tmp2);
    }
    Config.units = NULL;

    for (tmp3 = Config.profiles; tmp3; tmp3 = tmp3->next) {
	if (tmp3->uuid)
	    free(tmp3->uuid);
	if (tmp3->name)
	    free(tmp3->name);
	if (tmp3->steps) {
	    for (tmp4 = tmp3->steps; tmp4; tmp4 = tmp4->next) {
		free(tmp4);
	    }
	}
	free(tmp3);
    }
    Config.profiles = NULL;

    for (device = Config.devices; device; device = device->next) {
	if (device->uuid)
	    free(device->uuid);
	if (device->address)
	    free(device->address);
	if (device->description)
	    free(device->description);
	if (device->comment)
	    free(device->comment);
	free(device);
    }
    Config.devices = NULL;

#ifdef USE_SIMULATOR
    for (simulator = Config.simulators; simulator; simulator = simulator->next) {
	if (simulator->uuid)
	    free(simulator->uuid);
	if (simulator->name)
	    free(simulator->name);
	free(simulator);
    }
    Config.simulators = NULL;
#endif

#ifdef HAVE_WIRINGPI_H
    Config.lcd_cols = 16;
    Config.lcd_rows = 2;
#endif
}



int do_wrconfig(void);
int do_wrconfig(void)
{
    int			rc = 0;
    FILE		*fp;
    xmlTextWriterPtr	writer;
    xmlBufferPtr	buf;
    units_list		*tmp3;
    profiles_list	*tmp4;
    prof_step		*tmp5;
    devices_list	*device;
#ifdef USE_SIMULATOR
    simulator_list	*simulator;
#endif

    /* 
     * Create a new XML buffer, to which the XML document will be written
     */
    if ((buf = xmlBufferCreate()) == NULL) {
	syslog(LOG_NOTICE, "wrconfig: error creating the xml buffer");
	return 1;
    }

    /* 
     * Create a new XmlWriter for memory, with no compression.
     */
    if ((writer = xmlNewTextWriterMemory(buf, 0)) == NULL) {
	syslog(LOG_NOTICE, "wrconfig: error creating the xml writer");
	return 1;
    }

    /*
     * Use indentation instead of one long line
     */
    if ((rc = xmlTextWriterSetIndent(writer, 2)) < 0) {
	syslog(LOG_NOTICE, "wrconfig: error setting Indent");
	return 1;
    }

    /* 
     * Start the document with the xml default for the version,
     * encoding ISO 8859-1 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;
    }

    /* 
     * 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;
    }

    /* 
     * 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 "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;
    }

#ifdef HAVE_WIRINGPI_H
    /* 
     * 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;
    }
    /*
     * 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;
    }
#endif

    /*
     * Fermenter units
     */
    if (Config.units) {
	if ((rc = xmlTextWriterStartElement(writer, BAD_CAST "FERMENTERS")) < 0) {
	    syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterStartElement");
	    return 1;
	}
	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 "NAME", "%s", tmp3->name)) < 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;
	    }
	    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 (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 (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 (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 (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 (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 (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 (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 "MODE", "%s", UNITMODE[tmp3->mode] )) < 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;
	    }
	    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;
		}
		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;
		}
	    }
	    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", "%.2f", tmp3->PID_cool->iGain)) < 0) {
		    syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
		    return 1;
		}
	        if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PIDC_PGAIN", "%.2f", tmp3->PID_cool->pGain)) < 0) {
		    syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
		    return 1;
		}
	        if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PIDC_DGAIN", "%.2f", 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_INPUTD", "%.2f", tmp3->PID_cool->InputD)) < 0) {
		    syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
		    return 1;
		}
		if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PIDC_INPUTLAST", "%.2f", tmp3->PID_cool->InputLast)) < 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_ERRLAST", "%.2f", tmp3->PID_cool->ErrLast)) < 0) {
		    syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
		    return 1;
		}
		if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PIDC_ERRLASTLAST", "%.2f", tmp3->PID_cool->ErrLastLast)) < 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;
		}
	    }
	    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", "%.2f", tmp3->PID_heat->iGain)) < 0) {
		    syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
		    return 1;
		}
		if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PIDH_PGAIN", "%.2f", tmp3->PID_heat->pGain)) < 0) {
		    syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
		    return 1;
		}
		if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PIDH_DGAIN", "%.2f", 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_INPUTD", "%.2f", tmp3->PID_heat->InputD)) < 0) {
		    syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
		    return 1;
		}
		if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PIDH_INPUTLAST", "%.2f", tmp3->PID_heat->InputLast)) < 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_ERRLAST", "%.2f", tmp3->PID_heat->ErrLast)) < 0) {
		    syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
		    return 1;
		}
		if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PIDH_ERRLASTLAST", "%.2f", tmp3->PID_heat->ErrLastLast)) < 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;
	    }
	    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", "%.1f", tmp4->inittemp)) < 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", "%.1f", tmp5->target)) < 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;
	    }
	}
	if ((rc = xmlTextWriterEndElement(writer)) < 0) {
	    syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterEndElement");
	    return 1;
	}
    }

    if (Config.devices) {
	if ((rc = xmlTextWriterStartElement(writer, BAD_CAST "DEVICES")) < 0) {
	    syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterStartElement");
	    return 1;
	}
#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;
	    }
	}
#ifdef HAVE_WIRINGPI_H
	piUnlock(LOCK_DEVICES);
#endif

	if ((rc = xmlTextWriterEndElement(writer)) < 0) {
	    syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterEndElement");
	    return 1;
	}
    }

#ifdef USE_SIMULATOR
    if (Config.simulators) {
	if ((rc = xmlTextWriterStartElement(writer, BAD_CAST "SIMULATORS")) < 0) {
	    syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterStartElement");
	    return 1;
	}
	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 "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 "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;
    	    }
	}
	if ((rc = xmlTextWriterEndElement(writer)) < 0) {
	    syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterEndElement");
	    return 1;
	}
    }
#endif

    /*
     * All done, close any open elements
     */
    if ((rc = xmlTextWriterEndDocument(writer)) < 0) {
	syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterEndDocument");
	return 1;
    }
    xmlFreeTextWriter(writer);

    /*
     * Now write the XML configuration
     */
    if (getenv((char *)"USER") == NULL) {
	mypath = xstrcpy((char *)"/root");
    } else {
	mypath = xstrcpy(getenv((char *)"HOME"));
    }
    mypath = xstrcat(mypath, (char *)"/.thermferm/etc/");
    mkdirs(mypath, 0755);
    mypath = xstrcat(mypath, (char *)"thermferm.xml");

    if (debug)
	fprintf(stdout, "Writing %s\n", mypath);

    if ((fp = fopen(mypath, "w")) == NULL) {
	syslog(LOG_NOTICE, "could not rewrite %s", mypath);
	return 1;
    }

    fprintf(fp, "%s", (const char *) buf->content);
    fclose(fp);
    xmlBufferFree(buf);

    return 0;
}



int wrconfig(void)
{
    int		rc;

    rc = do_wrconfig();
    syslog(LOG_NOTICE, "Rewritten configuration, rc=%d", rc);
    return rc;
}



/*
 * 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



/*
 * 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->version = 1;
    unit->uuid = unit->name = unit->air_address = unit->beer_address = unit->heater_address = \
		 unit->cooler_address = unit->fan_address = unit->door_address = \
		 unit->light_address = unit->psu_address = unit->profile = NULL;
    unit->volume = unit->prof_peak_abs = unit->prof_peak_rel = 0.0;
    unit->air_temperature = unit->beer_temperature = unit->beer_set = unit->fridge_set = 20.0;
    unit->air_state = unit->beer_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 = 0;
    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;
    unit->heater_usage = unit->cooler_usage = unit->fan_usage = unit->light_usage = 0;
    unit->temp_set_min = 1.0;
    unit->temp_set_max = 30.0;
    unit->prof_started = unit->prof_paused = unit->prof_primary_done = (time_t)0;
    unit->prof_percent = 0;
    unit->PID_cool = (pid_var *)malloc(sizeof(pid_var));
    unit->PID_heat = (pid_var *)malloc(sizeof(pid_var));
    InitPID(unit->PID_cool, PID_TYPE_COOL);
    InitPID(unit->PID_heat, PID_TYPE_HEAT);

    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"))) {
	    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 *)"AIR_STATE"))) {
	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	    if (sscanf((const char *)key, "%d", &ival) == 1)
		unit->air_state = ival;
	    xmlFree(key);
	}
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"AIR_TEMPERATURE"))) {
	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	    if (sscanf((const char *)key, "%d", &ival) == 1)
		unit->air_temperature = ival;
	    xmlFree(key);                           
	}
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"BEER_ADDRESS"))) {
	    unit->beer_address = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	}
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"BEER_STATE"))) {
	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	    if (sscanf((const char *)key, "%d", &ival) == 1)
		unit->beer_state = ival;
	    xmlFree(key);
	}
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"BEER_TEMPERATURE"))) {
	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	    if (sscanf((const char *)key, "%d", &ival) == 1)
		unit->beer_temperature = ival;
	    xmlFree(key);
	}
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"HEATER_ADDRESS"))) {
	    unit->heater_address = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	}
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"HEATER_DELAY"))) {
	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	    if (sscanf((const char *)key, "%d", &ival) == 1)
		unit->heater_delay = ival;
	    xmlFree(key);
	}
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"HEATER_USAGE"))) {
	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	    if (sscanf((const char *)key, "%d", &ival) == 1)
		unit->heater_usage = ival;
	    xmlFree(key);
	}
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"COOLER_ADDRESS"))) {
	    unit->cooler_address = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	}
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"COOLER_DELAY"))) {
	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	    if (sscanf((const char *)key, "%d", &ival) == 1)
		unit->cooler_delay = ival;
	    xmlFree(key);
	}
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"COOLER_USAGE"))) {
	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	    if (sscanf((const char *)key, "%d", &ival) == 1)
		unit->cooler_usage = ival;
	    xmlFree(key);
	}
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"FAN_ADDRESS"))) {
	    unit->fan_address = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	}
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"FAN_DELAY"))) {
	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	    if (sscanf((const char *)key, "%d", &ival) == 1)
		unit->fan_delay = ival;
	    xmlFree(key);                           
	}
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"FAN_USAGE"))) {
	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	    if (sscanf((const char *)key, "%d", &ival) == 1)
		unit->fan_usage = ival;
	    xmlFree(key);
	}
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"LIGHT_ADDRESS"))) {
	    unit->light_address = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	}
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"LIGHT_DELAY"))) {
	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	    if (sscanf((const char *)key, "%d", &ival) == 1)
		unit->light_delay = ival;
	    xmlFree(key);
	}
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"LIGHT_USAGE"))) {
	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	    if (sscanf((const char *)key, "%d", &ival) == 1)
		unit->light_usage = ival;
	    xmlFree(key);
	}
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"DOOR_ADDRESS"))) {
	    unit->door_address = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	}
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"PSU_ADDRESS"))) {
	    unit->psu_address = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	}
	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 *)"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)
		unit->PID_cool->iMax = val;
	    xmlFree(key);
	}
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"PIDC_IDLERANGE"))) {
	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	    if (sscanf((const char *)key, "%f", &val) == 1)
		unit->PID_cool->idleRange = val;
	    xmlFree(key);
	}
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"PIDC_IGAIN"))) {
	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	    if (sscanf((const char *)key, "%f", &val) == 1)
		unit->PID_cool->iGain = val;
	    xmlFree(key);
	}
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"PIDC_PGAIN"))) {
	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	    if (sscanf((const char *)key, "%f", &val) == 1)
		unit->PID_cool->pGain = val;
	    xmlFree(key);
	}
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"PIDC_DGAIN"))) {
	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	    if (sscanf((const char *)key, "%f", &val) == 1)
		unit->PID_cool->dGain = val;
	    xmlFree(key);
	}
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"PIDC_INPUT"))) {
	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	    if (sscanf((const char *)key, "%f", &val) == 1)
		unit->PID_cool->Input = val;
	    xmlFree(key);
	}
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"PIDC_INPUTD"))) {
	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	    if (sscanf((const char *)key, "%f", &val) == 1)
		unit->PID_cool->InputD = val;
	    xmlFree(key);
	}
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"PIDC_INPUTLAST"))) {
	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	    if (sscanf((const char *)key, "%f", &val) == 1)
		unit->PID_cool->InputLast = val;
	    xmlFree(key);
	}
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"PIDC_ERR"))) {
	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	    if (sscanf((const char *)key, "%f", &val) == 1)
		unit->PID_cool->Err = val;
	    xmlFree(key);
	}
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"PIDC_ERRLAST"))) {
	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	    if (sscanf((const char *)key, "%f", &val) == 1)
		unit->PID_cool->ErrLast = val;
	    xmlFree(key);
	}
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"PIDC_ERRLASTLAST"))) {
	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	    if (sscanf((const char *)key, "%f", &val) == 1)
		unit->PID_cool->ErrLastLast = val;
	    xmlFree(key);
	}
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"PIDC_SETP"))) {
	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	    if (sscanf((const char *)key, "%f", &val) == 1)
		unit->PID_cool->SetP = val;
	    xmlFree(key);
	}
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"PIDC_OUTP"))) {
	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	    if (sscanf((const char *)key, "%f", &val) == 1)
		unit->PID_cool->OutP = val;
	    xmlFree(key);
	}
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"PIDC_MODE"))) {
	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	    for (i = 0; i < 3; i++) {
		if (! xmlStrcmp(key, (const xmlChar *)PIDMODE[i])) {
		    unit->PID_cool->Mode = i;
		    break;
	    	}
	    }
	    xmlFree(key);
	}
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"PIDH_IMAX"))) {
	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	    if (sscanf((const char *)key, "%f", &val) == 1)
		unit->PID_heat->iMax = val;
	    xmlFree(key);
	}
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"PIDH_IDLERANGE"))) {
	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	    if (sscanf((const char *)key, "%f", &val) == 1)
		unit->PID_heat->idleRange = val;
	    xmlFree(key);
	}
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"PIDH_IGAIN"))) {
	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	    if (sscanf((const char *)key, "%f", &val) == 1)
		unit->PID_heat->iGain = val;
	    xmlFree(key);
	}
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"PIDH_PGAIN"))) {
	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	    if (sscanf((const char *)key, "%f", &val) == 1)
		unit->PID_heat->pGain = val;
	    xmlFree(key);
	}
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"PIDH_DGAIN"))) {
	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	    if (sscanf((const char *)key, "%f", &val) == 1)
		unit->PID_heat->dGain = val;
	    xmlFree(key);
	}
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"PIDH_INPUT"))) {
	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	    if (sscanf((const char *)key, "%f", &val) == 1)
		unit->PID_heat->Input = val;
	    xmlFree(key);
	}
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"PIDH_INPUTD"))) {
	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	    if (sscanf((const char *)key, "%f", &val) == 1)
		unit->PID_heat->InputD = val;
	    xmlFree(key);
	}
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"PIDH_INPUTLAST"))) {
	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	    if (sscanf((const char *)key, "%f", &val) == 1)
		unit->PID_heat->InputLast = val;
	    xmlFree(key);
	}
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"PIDH_ERR"))) {
	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	    if (sscanf((const char *)key, "%f", &val) == 1)
		unit->PID_heat->Err = val;
	    xmlFree(key);
	}
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"PIDH_ERRLAST"))) {
	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	    if (sscanf((const char *)key, "%f", &val) == 1)
		unit->PID_heat->ErrLast = val;
	    xmlFree(key);
	}
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"PIDH_ERRLASTLAST"))) {
	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	    if (sscanf((const char *)key, "%f", &val) == 1)
		unit->PID_heat->ErrLastLast = val;
	    xmlFree(key);
	}
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"PIDH_SETP"))) {
	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	    if (sscanf((const char *)key, "%f", &val) == 1)
		unit->PID_heat->SetP = val;
	    xmlFree(key);
	}
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"PIDH_OUTP"))) {
	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	    if (sscanf((const char *)key, "%f", &val) == 1)
		unit->PID_heat->OutP = val;
	    xmlFree(key);
	}
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"PIDH_MODE"))) {
	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	    for (i = 0; i < 3; i++) {
		if (! xmlStrcmp(key, (const xmlChar *)PIDMODE[i])) {
		    unit->PID_heat->Mode = i;
		    break;
		}
	    }
	    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);
	}
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"PROF_PAUSED"))) {
	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	    if (sscanf((const char *)key, "%d", &ival) == 1)
		unit->prof_paused = ival;
	    xmlFree(key);
	}
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"PROF_STATE"))) {
	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	    for (i = 0; i < 5; i++) {
		if (! xmlStrcmp(key, (const xmlChar *)PROFSTATE[i])) {
		    unit->prof_state = i;
		    break;
		}
	    }
	    xmlFree(key);
	}
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"PROF_PEAK_ABS"))) {
	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	    if (sscanf((const char *)key, "%f", &val) == 1)
		unit->prof_peak_abs = val;
	    xmlFree(key);
	}
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"PROF_PEAK_REL"))) {
	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	    if (sscanf((const char *)key, "%f", &val) == 1)
		unit->prof_peak_rel = val;
	    xmlFree(key);
	}
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"PROF_PRIMARY_DONE"))) {
	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	    if (sscanf((const char *)key, "%d", &ival) == 1)
		unit->prof_primary_done = 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 parseStep(xmlDocPtr doc, xmlNodePtr cur, prof_step **profstep)
{
    xmlChar     *key;
    int         ival;
    float       val;
    prof_step	*step, *tmp;

    step = (prof_step *)malloc(sizeof(prof_step));
    step->next = NULL;
    step->version = 1;
    step->steptime = step->resttime = 0;
    step->target = 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 *)"RESTTIME"))) {
	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	    if (sscanf((const char *)key, "%d", &ival) == 1)
		step->resttime = ival;
	    xmlFree(key);
	}
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"STEPTIME"))) {
	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	    if (sscanf((const char *)key, "%d", &ival) == 1)
		step->steptime = ival;
	    xmlFree(key);
	}
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"TARGET"))) {
	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	    if (sscanf((const char *)key, "%f", &val) == 1)
		step->target = val;
	    xmlFree(key);
	}
	cur = cur->next;
    }

    if (*profstep == NULL) {
	*profstep = step;
    } else {
	for (tmp = *profstep; tmp; tmp = tmp->next) {
	    if (tmp->next == NULL) {
		tmp->next = step;
		break;
	    }
	}
    }
    return 0;
}



int parseSteps(xmlDocPtr doc, xmlNodePtr cur, prof_step **step)
{
    cur = cur->xmlChildrenNode;
    while (cur != NULL) {
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"STEP"))) {
	    parseStep(doc, cur, step);
	}
	cur = cur->next;
    }
    return 0;
}



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 = 0;
    profile->inittemp = 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"))) {
	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	    if (sscanf((const char *)key, "%f", &fval) == 1)
		profile->inittemp = fval;
	    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;
    devices_list	*device, *tmp;
    int                 i, ival;

    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;
    device->timestamp = (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;
	    }
	    device->version = 1;
	    xmlFree(key);
	}
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"UUID"))) {
	    device->uuid = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	}
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"TYPE"))) {
	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	    for (i = 0; i < 8; i++) {
		if (! xmlStrcmp(key, (const xmlChar *)DEVTYPE[i])) {
		    device->type = i;
		    break;
		}
	    }
	    xmlFree(key);
	}
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"DIRECTION"))) {
	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	    for (i = 0; i < 7; i++) {
		if (! xmlStrcmp(key, (const xmlChar *)DEVDIR[i])) {
		    device->direction = i;
		    break;
		}
	    }
	    xmlFree(key);
	}
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"VALUE"))) {
		key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
		if (sscanf((const char *)key, "%d", &ival) == 1)
			device->value = ival;
		xmlFree(key);
	}
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"OFFSET"))) {
	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	    if (sscanf((const char *)key, "%d", &ival) == 1)
		device->offset = ival;
	    xmlFree(key);
	}
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"PRESENT"))) {
	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	    for (i = 0; i < 4; i++) {
		if (! xmlStrcmp(key, (const xmlChar *)DEVPRESENT[i])) {
		    device->present = i;
		    break;
		}
	    }
	    xmlFree(key);                           
	}
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"ADDRESS"))) {
	    device->address = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	}
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"SUBDEVICE"))) {
	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	    if (sscanf((const char *)key, "%d", &ival) == 1)
		device->subdevice = ival;
	    xmlFree(key);
	}
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"GPIOPIN"))) {
	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	    if (sscanf((const char *)key, "%d", &ival) == 1)
		device->gpiopin = ival;
	    xmlFree(key);                                       
	}
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"DESCRIPTION"))) {
	    device->description = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	}
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"INUSE"))) {
	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	    if (sscanf((const char *)key, "%d", &ival) == 1)
		device->inuse = ival;
	    xmlFree(key);                                       
	}
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"COMMENT"))) {
	    device->comment = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	}
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"TIMESTAMP"))) {
	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	    if (sscanf((const char *)key, "%d", &ival) == 1)
		device->timestamp = (time_t)ival;
	    xmlFree(key);                                   
	}

	cur = cur->next;
    }

    if (Config.devices == NULL) {
	Config.devices = device;
    } else {
	for (tmp = Config.devices; tmp; tmp = tmp->next) {
	    if (tmp->next == NULL) {
		tmp->next = device;
		break;
	    }
	}
    }

    return 0;
}



int parseDevices(xmlDocPtr doc, xmlNodePtr cur)
{
    cur = cur->xmlChildrenNode;
    while (cur != NULL) {
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"DEVICE"))) {
	    parseDevice(doc, cur);
	}
	cur = cur->next;
    }
    return 0;
}



#ifdef USE_SIMULATOR
int parseSimulator(xmlDocPtr doc, xmlNodePtr cur)
{
    xmlChar             *key;
    simulator_list      *simulator, *tmp;
    int                 ival;
    float		fval;

    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;
    simulator->cooler_temp = simulator->cooler_size = simulator->heater_temp = simulator->heater_size = simulator->frigo_isolation = 0.0;
    simulator->cooler_time = simulator->heater_time = simulator->cooler_state = simulator->heater_state = 0;
    simulator->s_yeast_started = simulator->s_cool_changed = simulator->s_heat_changed = (time_t)0;
    simulator->s_yeast_heat = simulator->s_cool_temp = simulator->s_heat_temp = 0.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;
	    }
	    simulator->version = 1;
	    xmlFree(key);
	}
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"UUID"))) {
	    simulator->uuid = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	}
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"NAME"))) {
	    simulator->name = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	}
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"VOLUME_AIR"))) {
	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	    if (sscanf((const char *)key, "%d", &ival) == 1)
		simulator->volume_air = ival;
	    xmlFree(key);
	}
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"VOLUME_BEER"))) {
	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	    if (sscanf((const char *)key, "%d", &ival) == 1)
		simulator->volume_beer = ival;
	    xmlFree(key);
	}
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"ROOM_TEMPERATURE"))) {
	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	    if (sscanf((const char *)key, "%f", &fval) == 1)
		simulator->room_temperature = fval;
	    xmlFree(key);
	}
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"AIR_TEMPERATURE"))) {
	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	    if (sscanf((const char *)key, "%f", &fval) == 1)
		simulator->air_temperature = fval;
	    xmlFree(key);
	}
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"BEER_TEMPERATURE"))) {
	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	    if (sscanf((const char *)key, "%f", &fval) == 1)
		simulator->beer_temperature = fval;
	    xmlFree(key);
	}
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"COOLER_TEMP"))) {
	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	    if (sscanf((const char *)key, "%f", &fval) == 1)
		simulator->cooler_temp = fval;
	    xmlFree(key);
	}
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"COOLER_TIME"))) {
	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	    if (sscanf((const char *)key, "%d", &ival) == 1)
		simulator->cooler_time = ival;
	    xmlFree(key);
	}
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"COOLER_SIZE"))) {
	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	    if (sscanf((const char *)key, "%f", &fval) == 1)
		simulator->cooler_size = fval;
	    xmlFree(key);
	}
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"HEATER_TEMP"))) {
	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	    if (sscanf((const char *)key, "%f", &fval) == 1)
		simulator->heater_temp = fval;
	    xmlFree(key);
	}
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"HEATER_TIME"))) {
	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	    if (sscanf((const char *)key, "%d", &ival) == 1)
		simulator->heater_time = ival;
	    xmlFree(key);
	}
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"HEATER_SIZE"))) {
	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	    if (sscanf((const char *)key, "%f", &fval) == 1)
		simulator->heater_size = fval;
	    xmlFree(key);
	}
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"HEATER_STATE"))) {
	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	    if (sscanf((const char *)key, "%d", &ival) == 1)
		simulator->heater_state = ival;
	    xmlFree(key);
	}
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"COOLER_STATE"))) {
	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	    if (sscanf((const char *)key, "%d", &ival) == 1)
		simulator->cooler_state = ival;
	    xmlFree(key);
	}
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"FRIGO_ISOLATION"))) {
	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	    if (sscanf((const char *)key, "%f", &fval) == 1)
		simulator->frigo_isolation = fval;
	    xmlFree(key);
	}

	if ((!xmlStrcmp(cur->name, (const xmlChar *)"S_YEAST_HEAT"))) {
	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	    if (sscanf((const char *)key, "%f", &fval) == 1)
		simulator->s_yeast_heat = fval;
	    xmlFree(key);
	}
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"S_YEAST_STARTED"))) {
	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	    if (sscanf((const char *)key, "%d", &ival) == 1)
		simulator->s_yeast_started = (time_t)ival;
	    xmlFree(key);
	}
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"S_COOL_TEMP"))) {
	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	    if (sscanf((const char *)key, "%f", &fval) == 1)
		simulator->s_cool_temp = fval;
	    xmlFree(key);
	}
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"S_HEAT_TEMP"))) {
	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	    if (sscanf((const char *)key, "%f", &fval) == 1)
		simulator->s_heat_temp = fval;
	    xmlFree(key);
	}
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"S_COOL_CHANGED"))) {
	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	    if (sscanf((const char *)key, "%d", &ival) == 1)
		simulator->s_cool_changed = (time_t)ival;
	    xmlFree(key);
	}
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"S_HEAT_CHANGED"))) {
	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	    if (sscanf((const char *)key, "%d", &ival) == 1)
		simulator->s_heat_changed = (time_t)ival;
	    xmlFree(key);
	}

	cur = cur->next;
    }

    if (Config.simulators == NULL) {
	Config.simulators = simulator;
    } else {
	for (tmp = Config.simulators; tmp; tmp = tmp->next) {
	    if (tmp->next == NULL) {
		tmp->next = simulator;
		break;
	    }
	}
    }

    return 0;
}



int parseSimulators(xmlDocPtr doc, xmlNodePtr cur)
{
    cur = cur->xmlChildrenNode;
    while (cur != NULL) {
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"SIMULATOR"))) {
	    parseSimulator(doc, cur);
	}
	cur = cur->next;
    }
    return 0;
}
#endif



int rdconfig(void) 
{
    int		rc = 0, ival;
    xmlDocPtr	doc;
    xmlNodePtr	cur;
    xmlChar	*key;

    killconfig();
    syslog(LOG_NOTICE, "HOME='%s' USER='%s' LOGNAME='%s'", MBSE_SS(getenv((char *)"HOME")), MBSE_SS(getenv((char *)"USER")), MBSE_SS(getenv((char *)"LOGNAME")));

    /*
     * Search config file
     */
    if (getenv((char *)"USER") == NULL) {
	mypath = xstrcpy((char *)"/root");
    } else {
    	mypath = xstrcpy(getenv((char *)"HOME"));
    }
    mypath = xstrcat(mypath, (char *)"/.thermferm/etc/");
    mkdirs(mypath, 0755);
    mypath = xstrcat(mypath, (char *)"thermferm.xml");
    if ((doc = xmlParseFile(mypath)) == NULL) {
	/*
	 * Not in the users home directory
	 */
	free(mypath);
	mypath = xstrcpy((char *)"/etc/mbsepi-apps/thermferm.xml");
	if ((doc = xmlParseFile(mypath)) == NULL) {
	    /*
	     * Try /usr/local/etc
	     */
	    free(mypath);
	    mypath = xstrcpy((char *)"/usr/local/etc/mbsepi-apps/thermferm.xml");
	    if ((doc = xmlParseFile(mypath)) == NULL) {
		syslog(LOG_NOTICE, "rdconfig: could not find thermferm.xml");
		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.", mypath);
	xmlFreeDoc(doc);
	return 1;
    }

    /*
     * Parse configuration
     */
    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);
	}
	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);
	}
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"TEMP_ADDRESS"))) {
	    Config.temp_address = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	}
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"HUM_ADDRESS"))) {
	    Config.hum_address = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	}
#ifdef HAVE_WIRINGPI_H
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"LCDS"))) {
	    parseLCDs(doc, cur);
	}
#endif
	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);
	}
#ifdef USE_SIMULATOR
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"SIMULATORS"))) {
	    parseSimulators(doc, cur);
	}
#endif
	cur = cur->next;
    }
    xmlFreeDoc(doc);

    free(mypath);
    mypath = NULL;

    return rc;
}


mercurial