Mon, 08 Apr 2024 10:57:12 +0200
Removed lcd-buffer create logmessage. Combined Keys and Delay states.
/***************************************************************************** * Copyright (C) 2014-2024 * * 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 "pid.h" #include "futil.h" #include "xutil.h" int debug = FALSE; int foreground = FALSE; sys_config Config; /* System configuration */ extern pthread_mutex_t mutexes[5]; #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 UNITSTAGE[4][12] = { "PRIMARY", "SECONDARY", "TERTIARY", "CARBONATION" }; 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" }; int parseSteps(xmlDocPtr doc, xmlNodePtr cur, prof_step **step); void killconfig(void) { units_list *tmp2, *oldtmp2; prof_step *step, *oldstep; devices_list *device, *olddev; #ifdef USE_SIMULATOR simulator_list *simulator, *oldsim; #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_hum_idx = 0; Config.temp_address = Config.hum_address = NULL; Config.temp_value = 20000; Config.temp_state = Config.hum_state = 1; // missing Config.hum_value = 50000; if (Config.mqtt_host) free(Config.mqtt_host); Config.mqtt_host = NULL; Config.mqtt_port = 1883; if (Config.mqtt_username) free(Config.mqtt_username); Config.mqtt_username = NULL; if (Config.mqtt_password) free(Config.mqtt_password); Config.mqtt_password = NULL; if (Config.uuid) free(Config.uuid); Config.uuid = NULL; for (tmp2 = Config.units; tmp2; tmp2 = oldtmp2) { oldtmp2 = tmp2->next; if (tmp2->uuid) free(tmp2->uuid); if (tmp2->product_uuid) free(tmp2->product_uuid); if (tmp2->product_code) free(tmp2->product_code); if (tmp2->product_name) free(tmp2->product_name); if (tmp2->air_address) free(tmp2->air_address); if (tmp2->beer_address) free(tmp2->beer_address); if (tmp2->beer_address2) free(tmp2->beer_address2); if (tmp2->chiller_address) free(tmp2->chiller_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_uuid) free(tmp2->profile_uuid); if (tmp2->profile_name) free(tmp2->profile_name); if (tmp2->profile_steps) { for (step = tmp2->profile_steps; step; step = oldstep) { if (step->name) free(step->name); oldstep = step->next; free(step); } } if (tmp2->PID_cool) free(tmp2->PID_cool); if (tmp2->PID_heat) free(tmp2->PID_heat); free(tmp2); } Config.units = NULL; for (device = Config.devices; device; device = olddev) { olddev = 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 = oldsim) { oldsim = simulator->next; if (simulator->uuid) free(simulator->uuid); if (simulator->name) free(simulator->name); free(simulator); } Config.simulators = NULL; #endif Config.lcd_cols = 16; Config.lcd_rows = 2; } int do_wrconfig(void); int do_wrconfig(void) { int rc = 0; FILE *fp; char *mypath = NULL; xmlTextWriterPtr writer; xmlBufferPtr buf; units_list *tmp3; 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 UTF-8 and the default for the standalone declaration. */ xmlTextWriterStartDocument(writer, NULL, MY_ENCODING, NULL); /* * Start an element named "THERMFERM". Since thist is the first * element, this will be the root element of the document. */ xmlTextWriterStartElement(writer, BAD_CAST "THERMFERM"); xmlTextWriterWriteFormatElement(writer, BAD_CAST "NAME", "%s", Config.name); xmlTextWriterWriteFormatElement(writer, BAD_CAST "UUID", "%s", Config.uuid); xmlTextWriterWriteFormatElement(writer, BAD_CAST "LISTEN_PORT", "%d", Config.my_port); xmlTextWriterWriteFormatElement(writer, BAD_CAST "TEMPFORMAT", "%c", Config.tempFormat); xmlTextWriterWriteFormatElement(writer, BAD_CAST "TEMP_ADDRESS", "%s", Config.temp_address); xmlTextWriterWriteFormatElement(writer, BAD_CAST "TEMP_STATE", "%d", Config.temp_state); xmlTextWriterWriteFormatElement(writer, BAD_CAST "TEMP_VALUE", "%d", Config.temp_value); xmlTextWriterWriteFormatElement(writer, BAD_CAST "HUM_ADDRESS", "%s", Config.hum_address); xmlTextWriterWriteFormatElement(writer, BAD_CAST "HUM_STATE", "%d", Config.hum_state); xmlTextWriterWriteFormatElement(writer, BAD_CAST "HUM_VALUE", "%d", Config.hum_value); xmlTextWriterWriteFormatElement(writer, BAD_CAST "TEMP_HUM_IDX", "%d", Config.temp_hum_idx); xmlTextWriterWriteFormatElement(writer, BAD_CAST "NEXT_UNIT", "%d", Config.next_unit); xmlTextWriterWriteFormatElement(writer, BAD_CAST "MQTT_HOST", "%s", Config.mqtt_host); xmlTextWriterWriteFormatElement(writer, BAD_CAST "MQTT_PORT", "%d", Config.mqtt_port); if (Config.mqtt_username && Config.mqtt_password) { xmlTextWriterWriteFormatElement(writer, BAD_CAST "MQTT_USER", "%s", Config.mqtt_username); xmlTextWriterWriteFormatElement(writer, BAD_CAST "MQTT_PASS", "%s", Config.mqtt_password); } /* * Start an element named "LCDS" as child of THERMFERM. */ xmlTextWriterStartElement(writer, BAD_CAST "LCDS"); /* * Start one LCD. It is possible to connect 7 LCD displays on the i2c bus. * However this program doesn't use more then one yet. */ xmlTextWriterStartElement(writer, BAD_CAST "LCD"); xmlTextWriterWriteFormatElement(writer, BAD_CAST "ADDRESS", "0x%x", Config.lcd_address); xmlTextWriterWriteFormatElement(writer, BAD_CAST "COLUMNS", "%d", Config.lcd_cols); xmlTextWriterWriteFormatElement(writer, BAD_CAST "ROWS", "%d", Config.lcd_rows); xmlTextWriterEndElement(writer); // close LCD xmlTextWriterEndElement(writer); // close LCDS /* * Fermenter units */ if (Config.units) { xmlTextWriterStartElement(writer, BAD_CAST "FERMENTERS"); for (tmp3 = Config.units; tmp3; tmp3 = tmp3->next) { xmlTextWriterStartElement(writer, BAD_CAST "FERMENTER"); xmlTextWriterWriteFormatElement(writer, BAD_CAST "UUID", "%s", tmp3->uuid); xmlTextWriterWriteFormatElement(writer, BAD_CAST "PRODUCT_UUID", "%s", tmp3->product_uuid); xmlTextWriterWriteFormatElement(writer, BAD_CAST "PRODUCT_CODE", "%s", tmp3->product_code); xmlTextWriterWriteFormatElement(writer, BAD_CAST "PRODUCT_NAME", "%s", tmp3->product_name); xmlTextWriterWriteFormatElement(writer, BAD_CAST "ALIAS", "%s", tmp3->alias); xmlTextWriterWriteFormatElement(writer, BAD_CAST "VOLUME", "%.1f", tmp3->volume); if (tmp3->air_address) { xmlTextWriterWriteFormatElement(writer, BAD_CAST "AIR_ADDRESS", "%s", tmp3->air_address); xmlTextWriterWriteFormatElement(writer, BAD_CAST "AIR_STATE", "%d", tmp3->air_state); xmlTextWriterWriteFormatElement(writer, BAD_CAST "AIR_TEMPERATURE", "%d", tmp3->air_temperature); xmlTextWriterWriteFormatElement(writer, BAD_CAST "AIR_IDX", "%d", tmp3->air_idx); } if (tmp3->beer_address) { xmlTextWriterWriteFormatElement(writer, BAD_CAST "BEER_ADDRESS", "%s", tmp3->beer_address); xmlTextWriterWriteFormatElement(writer, BAD_CAST "BEER_STATE", "%d", tmp3->beer_state); xmlTextWriterWriteFormatElement(writer, BAD_CAST "BEER_TEMPERATURE", "%d", tmp3->beer_temperature); xmlTextWriterWriteFormatElement(writer, BAD_CAST "BEER_IDX", "%d", tmp3->beer_idx); if (tmp3->beer_address2) { xmlTextWriterWriteFormatElement(writer, BAD_CAST "BEER_ADDRESS2", "%s", tmp3->beer_address2); } } if (tmp3->chiller_address) { xmlTextWriterWriteFormatElement(writer, BAD_CAST "CHILLER_ADDRESS", "%s", tmp3->chiller_address); xmlTextWriterWriteFormatElement(writer, BAD_CAST "CHILLER_STATE", "%d", tmp3->chiller_state); xmlTextWriterWriteFormatElement(writer, BAD_CAST "CHILLER_TEMPERATURE", "%d", tmp3->chiller_temperature); xmlTextWriterWriteFormatElement(writer, BAD_CAST "CHILLER_IDX", "%d", tmp3->chiller_idx); } if (tmp3->heater_address) { xmlTextWriterWriteFormatElement(writer, BAD_CAST "HEATER_ADDRESS", "%s", tmp3->heater_address); xmlTextWriterWriteFormatElement(writer, BAD_CAST "HEATER_STATE", "%d", tmp3->heater_state); xmlTextWriterWriteFormatElement(writer, BAD_CAST "HEATER_DELAY", "%d", tmp3->heater_delay); xmlTextWriterWriteFormatElement(writer, BAD_CAST "HEATER_USAGE", "%d", tmp3->heater_usage); xmlTextWriterWriteFormatElement(writer, BAD_CAST "HEATER_IDX", "%d", tmp3->heater_idx); } if (tmp3->cooler_address) { xmlTextWriterWriteFormatElement(writer, BAD_CAST "COOLER_ADDRESS", "%s", tmp3->cooler_address); xmlTextWriterWriteFormatElement(writer, BAD_CAST "COOLER_STATE", "%d", tmp3->cooler_state); xmlTextWriterWriteFormatElement(writer, BAD_CAST "COOLER_DELAY", "%d", tmp3->cooler_delay); xmlTextWriterWriteFormatElement(writer, BAD_CAST "COOLER_USAGE", "%d", tmp3->cooler_usage); xmlTextWriterWriteFormatElement(writer, BAD_CAST "COOLER_IDX", "%d", tmp3->cooler_idx); } if (tmp3->fan_address) { xmlTextWriterWriteFormatElement(writer, BAD_CAST "FAN_ADDRESS", "%s", tmp3->fan_address); xmlTextWriterWriteFormatElement(writer, BAD_CAST "FAN_STATE", "%d", tmp3->fan_state); xmlTextWriterWriteFormatElement(writer, BAD_CAST "FAN_DELAY", "%d", tmp3->fan_delay); xmlTextWriterWriteFormatElement(writer, BAD_CAST "FAN_USAGE", "%d", tmp3->fan_usage); xmlTextWriterWriteFormatElement(writer, BAD_CAST "FAN_IDX", "%d", tmp3->fan_idx); } if (tmp3->light_address) { xmlTextWriterWriteFormatElement(writer, BAD_CAST "LIGHT_ADDRESS", "%s", tmp3->light_address); xmlTextWriterWriteFormatElement(writer, BAD_CAST "LIGHT_STATE", "%d", tmp3->light_state); xmlTextWriterWriteFormatElement(writer, BAD_CAST "LIGHT_DELAY", "%d", tmp3->light_delay); xmlTextWriterWriteFormatElement(writer, BAD_CAST "LIGHT_USAGE", "%d", tmp3->light_usage); xmlTextWriterWriteFormatElement(writer, BAD_CAST "LIGHT_IDX", "%d", tmp3->light_idx); } if (tmp3->door_address) { xmlTextWriterWriteFormatElement(writer, BAD_CAST "DOOR_ADDRESS", "%s", tmp3->door_address); xmlTextWriterWriteFormatElement(writer, BAD_CAST "DOOR_STATE", "%d", tmp3->door_state); xmlTextWriterWriteFormatElement(writer, BAD_CAST "DOOR_IDX", "%d", tmp3->door_idx); } if (tmp3->psu_address) { xmlTextWriterWriteFormatElement(writer, BAD_CAST "PSU_ADDRESS", "%s", tmp3->psu_address); xmlTextWriterWriteFormatElement(writer, BAD_CAST "PSU_STATE", "%d", tmp3->psu_state); xmlTextWriterWriteFormatElement(writer, BAD_CAST "PSU_IDX", "%d", tmp3->psu_idx); } xmlTextWriterWriteFormatElement(writer, BAD_CAST "MODE", "%s", UNITMODE[tmp3->mode] ); xmlTextWriterWriteFormatElement(writer, BAD_CAST "STAGE", "%s", UNITSTAGE[tmp3->stage] ); xmlTextWriterWriteFormatElement(writer, BAD_CAST "BEER_SET_LO", "%.1f", tmp3->beer_set_lo); xmlTextWriterWriteFormatElement(writer, BAD_CAST "BEER_SET_HI", "%.1f", tmp3->beer_set_hi); xmlTextWriterWriteFormatElement(writer, BAD_CAST "FRIDGE_SET_LO", "%.1f", tmp3->fridge_set_lo); xmlTextWriterWriteFormatElement(writer, BAD_CAST "FRIDGE_SET_HI", "%.1f", tmp3->fridge_set_hi); xmlTextWriterWriteFormatElement(writer, BAD_CAST "TEMP_SET_MIN", "%.1f", tmp3->temp_set_min); xmlTextWriterWriteFormatElement(writer, BAD_CAST "TEMP_SET_MAX", "%.1f", tmp3->temp_set_max); xmlTextWriterWriteFormatElement(writer, BAD_CAST "YEAST_LO", "%.1f", tmp3->yeast_lo); xmlTextWriterWriteFormatElement(writer, BAD_CAST "YEAST_HI", "%.1f", tmp3->yeast_hi); if (tmp3->profile_uuid) { xmlTextWriterWriteFormatElement(writer, BAD_CAST "PROFILE_UUID", "%s", tmp3->profile_uuid); xmlTextWriterWriteFormatElement(writer, BAD_CAST "PROFILE_NAME", "%s", tmp3->profile_name); xmlTextWriterWriteFormatElement(writer, BAD_CAST "PROFILE_INITTEMP_LO", "%.1f", tmp3->profile_inittemp_lo); xmlTextWriterWriteFormatElement(writer, BAD_CAST "PROFILE_INITTEMP_HI", "%.1f", tmp3->profile_inittemp_hi); xmlTextWriterWriteFormatElement(writer, BAD_CAST "PROFILE_FRIDGE_MODE", "%d", tmp3->profile_fridge_mode); xmlTextWriterWriteFormatElement(writer, BAD_CAST "PROFILE_DURATION", "%d", tmp3->profile_duration); xmlTextWriterWriteFormatElement(writer, BAD_CAST "PROFILE_TOTALSTEPS", "%d", tmp3->profile_totalsteps); if (tmp3->profile_steps) { xmlTextWriterStartElement(writer, BAD_CAST "PROFILE_STEPS"); for (tmp5 = tmp3->profile_steps; tmp5; tmp5 = tmp5->next) { xmlTextWriterStartElement(writer, BAD_CAST "PROFILE_STEP"); if (tmp5->name) xmlTextWriterWriteFormatElement(writer, BAD_CAST "NAME", "%s", tmp5->name); xmlTextWriterWriteFormatElement(writer, BAD_CAST "RESTTIME", "%d", tmp5->resttime); xmlTextWriterWriteFormatElement(writer, BAD_CAST "STEPTIME", "%d", tmp5->steptime); xmlTextWriterWriteFormatElement(writer, BAD_CAST "TARGET_LO", "%.1f", tmp5->target_lo); xmlTextWriterWriteFormatElement(writer, BAD_CAST "TARGET_HI", "%.1f", tmp5->target_hi); xmlTextWriterWriteFormatElement(writer, BAD_CAST "FRIDGE_MODE", "%d", tmp5->fridge_mode); xmlTextWriterEndElement(writer); // close PROFILE_STEP } xmlTextWriterEndElement(writer); // close PROFILE_STEPS } xmlTextWriterWriteFormatElement(writer, BAD_CAST "PROF_STARTED", "%d", (unsigned int)tmp3->prof_started); xmlTextWriterWriteFormatElement(writer, BAD_CAST "PROF_PAUSED", "%d", (unsigned int)tmp3->prof_paused); xmlTextWriterWriteFormatElement(writer, BAD_CAST "PROF_STATE", "%s", PROFSTATE[tmp3->prof_state] ); xmlTextWriterWriteFormatElement(writer, BAD_CAST "PROF_PEAK_ABS", "%.3f", tmp3->prof_peak_abs); xmlTextWriterWriteFormatElement(writer, BAD_CAST "PROF_PEAK_REL", "%.3f", tmp3->prof_peak_rel); xmlTextWriterWriteFormatElement(writer, BAD_CAST "PROF_PRIMARY_DONE", "%d", (unsigned int)tmp3->prof_primary_done); } if (tmp3->PID_cool) { xmlTextWriterWriteFormatElement(writer, BAD_CAST "PIDC_IMAX", "%.2f", tmp3->PID_cool->iMax); xmlTextWriterWriteFormatElement(writer, BAD_CAST "PIDC_IGAIN", "%.3f", tmp3->PID_cool->iGain); xmlTextWriterWriteFormatElement(writer, BAD_CAST "PIDC_PGAIN", "%.3f", tmp3->PID_cool->pGain); xmlTextWriterWriteFormatElement(writer, BAD_CAST "PIDC_DGAIN", "%.3f", tmp3->PID_cool->dGain); xmlTextWriterWriteFormatElement(writer, BAD_CAST "PIDC_IDLERANGE", "%.2f", tmp3->PID_cool->idleRange); xmlTextWriterWriteFormatElement(writer, BAD_CAST "PIDC_INPUT", "%.2f", tmp3->PID_cool->Input); xmlTextWriterWriteFormatElement(writer, BAD_CAST "PIDC_ERR", "%.2f", tmp3->PID_cool->Err); xmlTextWriterWriteFormatElement(writer, BAD_CAST "PIDC_ISTATE", "%.2f", tmp3->PID_cool->iState); xmlTextWriterWriteFormatElement(writer, BAD_CAST "PIDC_SETP", "%.2f", tmp3->PID_cool->SetP); xmlTextWriterWriteFormatElement(writer, BAD_CAST "PIDC_OUTP", "%.2f", tmp3->PID_cool->OutP); xmlTextWriterWriteFormatElement(writer, BAD_CAST "PIDC_MODE", "%s", PIDMODE[tmp3->PID_cool->Mode]); xmlTextWriterWriteFormatElement(writer, BAD_CAST "PIDC_TYPE", "COOL"); } if (tmp3->PID_heat) { xmlTextWriterWriteFormatElement(writer, BAD_CAST "PIDH_IMAX", "%.2f", tmp3->PID_heat->iMax); xmlTextWriterWriteFormatElement(writer, BAD_CAST "PIDH_IGAIN", "%.3f", tmp3->PID_heat->iGain); xmlTextWriterWriteFormatElement(writer, BAD_CAST "PIDH_PGAIN", "%.3f", tmp3->PID_heat->pGain); xmlTextWriterWriteFormatElement(writer, BAD_CAST "PIDH_DGAIN", "%.3f", tmp3->PID_heat->dGain); xmlTextWriterWriteFormatElement(writer, BAD_CAST "PIDH_IDLERANGE", "%.2f", tmp3->PID_heat->idleRange); xmlTextWriterWriteFormatElement(writer, BAD_CAST "PIDH_INPUT", "%.2f", tmp3->PID_heat->Input); xmlTextWriterWriteFormatElement(writer, BAD_CAST "PIDH_ERR", "%.2f", tmp3->PID_heat->Err); xmlTextWriterWriteFormatElement(writer, BAD_CAST "PIDH_ISTATE", "%.2f", tmp3->PID_heat->iState); xmlTextWriterWriteFormatElement(writer, BAD_CAST "PIDH_SETP", "%.2f", tmp3->PID_heat->SetP); xmlTextWriterWriteFormatElement(writer, BAD_CAST "PIDH_OUTP", "%.2f", tmp3->PID_heat->OutP); xmlTextWriterWriteFormatElement(writer, BAD_CAST "PIDH_MODE", "%s", PIDMODE[tmp3->PID_heat->Mode]); xmlTextWriterWriteFormatElement(writer, BAD_CAST "PIDH_TYPE", "HEAT"); } xmlTextWriterEndElement(writer); // close FERMENTER } xmlTextWriterEndElement(writer); // close FERMENTERS } if (Config.devices) { xmlTextWriterStartElement(writer, BAD_CAST "DEVICES"); pthread_mutex_lock(&mutexes[LOCK_DEVICES]); for (device = Config.devices; device; device = device->next) { xmlTextWriterStartElement(writer, BAD_CAST "DEVICE"); xmlTextWriterWriteFormatElement(writer, BAD_CAST "UUID", "%s", device->uuid); xmlTextWriterWriteFormatElement(writer, BAD_CAST "TYPE", "%s", DEVTYPE[device->type]); xmlTextWriterWriteFormatElement(writer, BAD_CAST "DIRECTION", "%s", DEVDIR[device->direction]); xmlTextWriterWriteFormatElement(writer, BAD_CAST "VALUE", "%d", device->value); xmlTextWriterWriteFormatElement(writer, BAD_CAST "OFFSET", "%d", device->offset); xmlTextWriterWriteFormatElement(writer, BAD_CAST "PRESENT", "%s", DEVPRESENT[device->present]); xmlTextWriterWriteFormatElement(writer, BAD_CAST "ADDRESS", "%s", device->address); xmlTextWriterWriteFormatElement(writer, BAD_CAST "SUBDEVICE", "%d", device->subdevice); xmlTextWriterWriteFormatElement(writer, BAD_CAST "GPIOPIN", "%d", device->gpiopin); xmlTextWriterWriteFormatElement(writer, BAD_CAST "DESCRIPTION", "%s", device->description); xmlTextWriterWriteFormatElement(writer, BAD_CAST "INUSE", "%d", device->inuse); xmlTextWriterWriteFormatElement(writer, BAD_CAST "COMMENT", "%s", device->comment); xmlTextWriterWriteFormatElement(writer, BAD_CAST "TIMESTAMP", "%d", (int)device->timestamp); xmlTextWriterEndElement(writer); // close DEVICE } pthread_mutex_unlock(&mutexes[LOCK_DEVICES]); xmlTextWriterEndElement(writer); // close DEVICES } #ifdef USE_SIMULATOR if (Config.simulators) { xmlTextWriterStartElement(writer, BAD_CAST "SIMULATORS"); for (simulator = Config.simulators; simulator; simulator = simulator->next) { xmlTextWriterStartElement(writer, BAD_CAST "SIMULATOR"); xmlTextWriterWriteFormatElement(writer, BAD_CAST "UUID", "%s", simulator->uuid); xmlTextWriterWriteFormatElement(writer, BAD_CAST "NAME", "%s", simulator->name); xmlTextWriterWriteFormatElement(writer, BAD_CAST "VOLUME_AIR", "%d", simulator->volume_air); xmlTextWriterWriteFormatElement(writer, BAD_CAST "VOLUME_BEER", "%d", simulator->volume_beer); xmlTextWriterWriteFormatElement(writer, BAD_CAST "ROOM_TEMPERATURE", "%.1f", simulator->room_temperature); xmlTextWriterWriteFormatElement(writer, BAD_CAST "ROOM_HUMIDITY", "%.1f", simulator->room_humidity); xmlTextWriterWriteFormatElement(writer, BAD_CAST "AIR_TEMPERATURE", "%f", simulator->air_temperature); xmlTextWriterWriteFormatElement(writer, BAD_CAST "BEER_TEMPERATURE", "%f", simulator->beer_temperature); xmlTextWriterWriteFormatElement(writer, BAD_CAST "CHILLER_TEMPERATURE", "%f", simulator->chiller_temperature); xmlTextWriterWriteFormatElement(writer, BAD_CAST "COOLER_TEMP", "%f", simulator->cooler_temp); xmlTextWriterWriteFormatElement(writer, BAD_CAST "COOLER_TIME", "%d", simulator->cooler_time); xmlTextWriterWriteFormatElement(writer, BAD_CAST "COOLER_SIZE", "%.3f", simulator->cooler_size); xmlTextWriterWriteFormatElement(writer, BAD_CAST "HEATER_TEMP", "%f", simulator->heater_temp); xmlTextWriterWriteFormatElement(writer, BAD_CAST "HEATER_TIME", "%d", simulator->heater_time); xmlTextWriterWriteFormatElement(writer, BAD_CAST "HEATER_SIZE", "%.3f", simulator->heater_size); xmlTextWriterWriteFormatElement(writer, BAD_CAST "HEATER_STATE", "%d", simulator->heater_state); xmlTextWriterWriteFormatElement(writer, BAD_CAST "COOLER_STATE", "%d", simulator->cooler_state); xmlTextWriterWriteFormatElement(writer, BAD_CAST "FRIGO_ISOLATION", "%.3f", simulator->frigo_isolation); xmlTextWriterWriteFormatElement(writer, BAD_CAST "S_YEAST_HEAT", "%f", simulator->s_yeast_heat); xmlTextWriterWriteFormatElement(writer, BAD_CAST "S_YEAST_STARTED", "%d", (int)simulator->s_yeast_started); xmlTextWriterWriteFormatElement(writer, BAD_CAST "S_COOL_TEMP", "%f", simulator->s_cool_temp); xmlTextWriterWriteFormatElement(writer, BAD_CAST "S_HEAT_TEMP", "%f", simulator->s_heat_temp); xmlTextWriterWriteFormatElement(writer, BAD_CAST "S_COOL_CHANGED", "%d", (int)simulator->s_cool_changed); xmlTextWriterWriteFormatElement(writer, BAD_CAST "S_HEAT_CHANGED", "%d", (int)simulator->s_heat_changed); xmlTextWriterEndElement(writer); } xmlTextWriterEndElement(writer); } #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) syslog(LOG_NOTICE, "Writing %s", mypath); if ((fp = fopen(mypath, "w")) == NULL) { syslog(LOG_NOTICE, "could not rewrite %s", mypath); free(mypath); return 1; } free(mypath); fprintf(fp, "%s", (const char *) buf->content); fclose(fp); xmlBufferFree(buf); return 0; } int wrconfig(void) { int rc = do_wrconfig(); syslog(LOG_NOTICE, "Rewritten configuration, rc=%d", rc); return rc; } /* * Parse one LCD display */ 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; } /* * Parse a fermenter unit */ int parseUnit(xmlDocPtr doc, xmlNodePtr cur/* , int number */) { xmlChar *key; int i, ival; float val; units_list *unit, *tmp; unit = (units_list *)malloc(sizeof(units_list)); unit->next = NULL; unit->uuid = unit->product_uuid = unit->product_code = unit->product_name = unit->event_msg = \ unit->alias = unit->air_address = unit->beer_address = unit->beer_address2 = unit->chiller_address = \ unit->heater_address = unit->cooler_address = unit->fan_address = unit->door_address = \ unit->light_address = unit->psu_address = unit->profile_uuid = unit->profile_name = NULL; unit->volume = unit->prof_peak_abs = unit->prof_peak_rel = 0.0; unit->air_temperature = unit->beer_temperature = unit->chiller_temperature = unit->beer_set_lo = unit->beer_set_hi = \ unit->fridge_set_lo = unit->fridge_set_hi = unit->profile_inittemp_lo = unit->profile_inittemp_hi = 20.0; unit->air_state = unit->beer_state = unit->chiller_state = 1; // missing unit->heater_state = unit->cooler_state = unit->fan_state = unit->door_state = \ unit->light_state = unit->light_timer = unit->psu_state = unit->mode = unit->prof_state = unit->stage = 0; unit->air_idx = unit->beer_idx = unit->chiller_idx = unit->heater_idx = unit->cooler_idx = unit->fan_idx = \ unit->door_idx = unit->light_idx = unit->psu_idx = unit->profile_fridge_mode = \ unit->profile_duration = unit->profile_totalsteps = 0; unit->profile_steps = NULL; unit->heater_delay = unit->cooler_delay = unit->fan_delay = 20; /* 5 minutes delay */ unit->light_delay = 1; /* 15 seconds delay */ unit->heater_wait = unit->cooler_wait = unit->fan_wait = unit->light_wait = 0; unit->heater_usage = unit->cooler_usage = unit->fan_usage = unit->light_usage = 0; unit->temp_set_min = 1.0; unit->temp_set_max = 45.0; unit->yeast_lo = 12.0; unit->yeast_hi = 24.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 *)"UUID"))) { unit->uuid = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); } if ((!xmlStrcmp(cur->name, (const xmlChar *)"PRODUCT_UUID"))) { unit->product_uuid = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); } if ((!xmlStrcmp(cur->name, (const xmlChar *)"PRODUCT_CODE"))) { unit->product_code = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); } if ((!xmlStrcmp(cur->name, (const xmlChar *)"PRODUCT_NAME"))) { unit->product_name = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); } if ((!xmlStrcmp(cur->name, (const xmlChar *)"ALIAS"))) { unit->alias = (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_IDX"))) { key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); if (sscanf((const char *)key, "%d", &ival) == 1) unit->air_idx = 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_ADDRESS2"))) { unit->beer_address2 = (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_IDX"))) { key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); if (sscanf((const char *)key, "%d", &ival) == 1) unit->beer_idx = 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 *)"CHILLER_ADDRESS"))) { unit->chiller_address = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); } if ((!xmlStrcmp(cur->name, (const xmlChar *)"CHILLER_STATE"))) { key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); if (sscanf((const char *)key, "%d", &ival) == 1) unit->chiller_state = ival; xmlFree(key); } if ((!xmlStrcmp(cur->name, (const xmlChar *)"CHILLER_IDX"))) { key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); if (sscanf((const char *)key, "%d", &ival) == 1) unit->chiller_idx = ival; xmlFree(key); } if ((!xmlStrcmp(cur->name, (const xmlChar *)"CHILLER_TEMPERATURE"))) { key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); if (sscanf((const char *)key, "%d", &ival) == 1) unit->chiller_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_IDX"))) { key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); if (sscanf((const char *)key, "%d", &ival) == 1) unit->heater_idx = 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_IDX"))) { key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); if (sscanf((const char *)key, "%d", &ival) == 1) unit->cooler_idx = 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_IDX"))) { key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); if (sscanf((const char *)key, "%d", &ival) == 1) unit->fan_idx = 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_IDX"))) { key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); if (sscanf((const char *)key, "%d", &ival) == 1) unit->light_idx = 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 *)"DOOR_IDX"))) { key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); if (sscanf((const char *)key, "%d", &ival) == 1) unit->door_idx = ival; xmlFree(key); } if ((!xmlStrcmp(cur->name, (const xmlChar *)"PSU_ADDRESS"))) { unit->psu_address = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); } if ((!xmlStrcmp(cur->name, (const xmlChar *)"PSU_IDX"))) { key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); if (sscanf((const char *)key, "%d", &ival) == 1) unit->psu_idx = ival; 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 *)"STAGE"))) { key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); for (i = 0; i < 4; i++) { if (! xmlStrcmp(key, (const xmlChar *)UNITSTAGE[i])) { unit->stage = i; break; } } xmlFree(key); } if ((!xmlStrcmp(cur->name, (const xmlChar *)"BEER_SET"))) { // Remove in 2020. key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); if (sscanf((const char *)key, "%f", &val) == 1) unit->beer_set_lo = unit->beer_set_hi = val; xmlFree(key); } if ((!xmlStrcmp(cur->name, (const xmlChar *)"BEER_SET_LO"))) { key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); if (sscanf((const char *)key, "%f", &val) == 1) unit->beer_set_lo = val; xmlFree(key); } if ((!xmlStrcmp(cur->name, (const xmlChar *)"BEER_SET_HI"))) { key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); if (sscanf((const char *)key, "%f", &val) == 1) unit->beer_set_hi = val; xmlFree(key); } if ((!xmlStrcmp(cur->name, (const xmlChar *)"FRIDGE_SET"))) { // Remove in 2020 key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); if (sscanf((const char *)key, "%f", &val) == 1) unit->fridge_set_lo = unit->fridge_set_hi = val; xmlFree(key); } if ((!xmlStrcmp(cur->name, (const xmlChar *)"FRIDGE_SET_LO"))) { key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); if (sscanf((const char *)key, "%f", &val) == 1) unit->fridge_set_lo = val; xmlFree(key); } if ((!xmlStrcmp(cur->name, (const xmlChar *)"FRIDGE_SET_HI"))) { key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); if (sscanf((const char *)key, "%f", &val) == 1) unit->fridge_set_hi = 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 *)"YEAST_LO"))) { key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); if (sscanf((const char *)key, "%f", &val) == 1) unit->yeast_lo = val; xmlFree(key); } if ((!xmlStrcmp(cur->name, (const xmlChar *)"YEAST_HI"))) { key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); if (sscanf((const char *)key, "%f", &val) == 1) unit->yeast_hi = val; 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_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_ISTATE"))) { key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); if (sscanf((const char *)key, "%f", &val) == 1) unit->PID_cool->iState = 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_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_ISTATE"))) { key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); if (sscanf((const char *)key, "%f", &val) == 1) unit->PID_heat->iState = 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_UUID"))) { unit->profile_uuid = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); } if ((!xmlStrcmp(cur->name, (const xmlChar *)"PROFILE_NAME"))) { unit->profile_name = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); } if ((!xmlStrcmp(cur->name, (const xmlChar *)"PROFILE_INITTEMP_LO"))) { key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); if (sscanf((const char *)key, "%f", &val) == 1) unit->profile_inittemp_lo = val; xmlFree(key); } if ((!xmlStrcmp(cur->name, (const xmlChar *)"PROFILE_INITTEMP_HI"))) { key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); if (sscanf((const char *)key, "%f", &val) == 1) unit->profile_inittemp_hi = val; xmlFree(key); } if ((!xmlStrcmp(cur->name, (const xmlChar *)"PROFILE_FRIDGE_MODE"))) { key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); if (sscanf((const char *)key, "%d", &ival) == 1) unit->profile_fridge_mode = ival; xmlFree(key); } if ((!xmlStrcmp(cur->name, (const xmlChar *)"PROFILE_DURATION"))) { key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); if (sscanf((const char *)key, "%d", &ival) == 1) unit->profile_duration = ival; xmlFree(key); } if ((!xmlStrcmp(cur->name, (const xmlChar *)"PROFILE_TOTALSTEPS"))) { key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); if (sscanf((const char *)key, "%d", &ival) == 1) unit->profile_totalsteps = ival; xmlFree(key); } if ((!xmlStrcmp(cur->name, (const xmlChar *)"PROFILE_STEPS"))) { parseSteps(doc, cur, &(unit)->profile_steps); } if ((!xmlStrcmp(cur->name, (const xmlChar *)"PROF_STARTED"))) { key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); if (sscanf((const char *)key, "%d", &ival) == 1) 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) { // Accept the wrong UNIT name as well as FERMENTER if ((!xmlStrcmp(cur->name, (const xmlChar *)"UNIT")) || (!xmlStrcmp(cur->name, (const xmlChar *)"FERMENTER"))) { parseUnit(doc, cur); } cur = cur->next; } 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->name = NULL; step->steptime = step->resttime = step->fridge_mode = 0; step->target_lo = step->target_hi = 20.0; cur = cur->xmlChildrenNode; while (cur != NULL) { if ((!xmlStrcmp(cur->name, (const xmlChar *)"NAME"))) { step->name = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); } 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_LO"))) { key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); if (sscanf((const char *)key, "%f", &val) == 1) step->target_lo = val; xmlFree(key); } if ((!xmlStrcmp(cur->name, (const xmlChar *)"TARGET_HI"))) { key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); if (sscanf((const char *)key, "%f", &val) == 1) step->target_hi = val; xmlFree(key); } if ((!xmlStrcmp(cur->name, (const xmlChar *)"FRIDGE_MODE"))) { key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); if (sscanf((const char *)key, "%d", &ival) == 1) step->fridge_mode = ival; 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 *)"PROFILE_STEP"))) { parseStep(doc, cur, step); } 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->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 *)"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->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->chiller_temperature = 1.5; simulator->room_humidity = 49.2; 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 *)"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 *)"ROOM_GUMIDITY"))) { key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); if (sscanf((const char *)key, "%f", &fval) == 1) simulator->room_humidity= 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 *)"CHILLER_TEMPERATURE"))) { key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); if (sscanf((const char *)key, "%f", &fval) == 1) simulator->chiller_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; char *mypath; 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) { /* * No config file, create a fresh one */ syslog(LOG_NOTICE, "rdconfig: %s not found, creating", mypath); wrconfig(); if ((doc = xmlParseFile(mypath)) == NULL) { syslog(LOG_NOTICE, "rdconfig: could not create %s", mypath); free(mypath); return 1; } } syslog(LOG_NOTICE, "rdconfig: using %s", mypath); Config.mqtt_host = xstrcpy((char *)"localhost"); Config.mqtt_port = 1883; Config.next_unit = 1; 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 *)"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); } if ((!xmlStrcmp(cur->name, (const xmlChar *)"TEMP_HUM_IDX"))) { key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); if (sscanf((const char *)key, "%d", &ival) == 1) Config.temp_hum_idx = ival; xmlFree(key); } if ((!xmlStrcmp(cur->name, (const xmlChar *)"NEXT_UNIT"))) { key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); if (sscanf((const char *)key, "%d", &ival) == 1) Config.next_unit = ival; xmlFree(key); } if ((!xmlStrcmp(cur->name, (const xmlChar *)"MQTT_HOST"))) { if (Config.mqtt_host) free(Config.mqtt_host); Config.mqtt_host = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); } if ((!xmlStrcmp(cur->name, (const xmlChar *)"MQTT_PORT"))) { key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); if (sscanf((const char *)key, "%d", &ival) == 1) Config.mqtt_port = ival; xmlFree(key); } if ((!xmlStrcmp(cur->name, (const xmlChar *)"MQTT_USER"))) { Config.mqtt_username = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); } if ((!xmlStrcmp(cur->name, (const xmlChar *)"MQTT_PASS"))) { Config.mqtt_password = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); } if ((!xmlStrcmp(cur->name, (const xmlChar *)"UUID"))) { Config.uuid= (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); } if ((!xmlStrcmp(cur->name, (const xmlChar *)"LCDS"))) { parseLCDs(doc, cur); } if ((!xmlStrcmp(cur->name, (const xmlChar *)"FERMENTERS"))) { parseFermenters(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; /* * If the system uuid is not set, do it now. */ if (Config.uuid && ! strcmp((char *)"(null)", Config.uuid)) { free(Config.uuid); Config.uuid = NULL; } if (Config.uuid == NULL) { uuid_t uu; Config.uuid = malloc(37); uuid_generate(uu); uuid_unparse(uu, Config.uuid); } return rc; }