# HG changeset patch # User Michiel Broek # Date 1406821490 -7200 # Node ID f1b7e2ef90beea50691173586a262fec4d63edd6 # Parent 259a018758f93ef979f17b0ba8f5da72cbff60b0 Added device configuration diff -r 259a018758f9 -r f1b7e2ef90be thermferm/Makefile --- a/thermferm/Makefile Thu Jul 31 13:43:09 2014 +0200 +++ b/thermferm/Makefile Thu Jul 31 17:44:50 2014 +0200 @@ -54,8 +54,9 @@ # DO NOT DELETE THIS LINE - MAKE DEPEND RELIES ON IT # Dependencies generated by make depend -thermferm.o: lock.h logger.h rdconfig.h sensors.h server.h thermferm.h lcd-pcf8574.h lcd-buffer.h futil.h units.h xutil.h +thermferm.o: lock.h logger.h rdconfig.h sensors.h devices.h server.h thermferm.h lcd-pcf8574.h lcd-buffer.h futil.h units.h xutil.h sensors.o: sensors.h thermferm.h xutil.h +devices.o: devices.h thermferm.h xutil.h lcd-buffer.o: thermferm.h lcd-buffer.h lcd-pcf8574.h futil.o: thermferm.h futil.h lock.o: lock.h thermferm.h diff -r 259a018758f9 -r f1b7e2ef90be thermferm/devices.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thermferm/devices.c Thu Jul 31 17:44:50 2014 +0200 @@ -0,0 +1,229 @@ +/***************************************************************************** + * Copyright (C) 2014 + * + * Michiel Broek + * + * 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 "devices.h" +#include "thermferm.h" +#include "xutil.h" + + +extern int debug; +extern sys_config Config; +extern int my_shutdown; + + + +/* + * Auto detect hotplugged or known to be present devices + */ +int devices_detect(void) +{ + struct dirent *de; +// FILE *fp; + DIR *fd; + devices_list *device, *ndev; + int found, subdevices, i, rc = 0; + char *family; + uuid_t uu; + + /* + * Scan for 1-wire devices + */ + if ((fd = opendir((char *)"/sys/bus/w1/devices"))) { + while ((de = readdir(fd))) { + if (de->d_name[0] != '.') { + found = FALSE; + for (device = Config.devices; device; device = device->next) { + if (strcmp(device->address ,de->d_name) == 0) { + found = TRUE; + break; + } + } + + if (found == FALSE) { + family = malloc(3); + strncpy(family, de->d_name, 2); + subdevices = 1; + if (strcmp(family, (char *)"29") == 0) + subdevices = 8; + if (strcmp(family, (char *)"3a") == 0) + subdevices = 2; + for (i = 0; i < subdevices; i++) { + ndev = (devices_list *)malloc(sizeof(devices_list)); + ndev->next = NULL; + ndev->version = 1; + ndev->uuid = malloc(37); + uuid_generate(uu); + uuid_unparse(uu, ndev->uuid); + ndev->type = DEVTYPE_W1; + ndev->direction = DEVDIR_UNDEF; + if (strcmp(family, (char *)"10") == 0) { + ndev->direction = DEVDIR_IN_ANALOG; + ndev->description = xstrcpy((char *)"18S20,Digital thermometer"); + } else if (strcmp(family, (char *)"28") == 0) { + ndev->direction = DEVDIR_IN_ANALOG; + ndev->description = xstrcpy((char *)"18B20,Digital thermometer"); + } else if (strcmp(family, (char *)"29") == 0) { + ndev->description = xstrcpy((char *)"2408,8 Channel addressable switch/LCD"); + } else if (strcmp(family, (char *)"3a") == 0) { + ndev->description = xstrcpy((char *)"2413,Dual channel addressable switch"); + } else if (strcmp(family, (char *)"w1") == 0) { + ndev->description = xstrcpy((char *)"Master System device"); + } else { + ndev->description = xstrcpy((char *)"Unknown device family "); + ndev->description = xstrcat(ndev->description, family); + } + ndev->value = ndev->inuse = 0; + ndev->present = DEVPRESENT_YES; + ndev->address = xstrcpy(de->d_name); + ndev->subdevice = i; + ndev->gpiopin = -1; + ndev->comment = xstrcpy((char *)"Auto detected device"); + ndev->timestamp = time(NULL); + + if (Config.devices == NULL) { + Config.devices = ndev; + } else { + for (device = Config.devices; device; device = device->next) { + if (device->next == NULL) + device->next = ndev; + break; + } + } + rc++; + } + } + } + } + } + + return rc; +} + + + +#ifdef HAVE_WIRINGPI_H +PI_THREAD (my_devices_loop) +#else +void *my_devices_loop(void *threadid) +#endif +{ + devices_list *device; +// char line[60], *p = NULL; + // FILE *fp; +// int temp, rc, deviation; + + syslog(LOG_NOTICE, "Thread my_devices_loop started"); + if (debug) + fprintf(stdout, "Thread my_devices_loop started\n"); + + /* + * Loop forever until the external shutdown variable is set. + */ + for (;;) { + + /* + * Here send our 1-wire sensors values + */ + for (device = Config.devices; device; device = device->next) { + + if (my_shutdown) + break; + + /* + * Build path to the on-wire sensor + */ +// device = xstrcpy((char *)"/sys/bus/w1/devices/"); +// device = xstrcat(device, tmp1->master); +// device = xstrcat(device, (char *)"/"); +// device = xstrcat(device, tmp1->name); +// device = xstrcat(device, (char *)"/w1_slave"); + + /* + * Read sensor data + */ +// if ((fp = fopen(device, "r"))) { + /* + * The output looks like: + * 72 01 4b 46 7f ff 0e 10 57 : crc=57 YES + * 72 01 4b 46 7f ff 0e 10 57 t=23125 + */ +// fgets(line, 50, fp); +// line[strlen(line)-1] = '\0'; +// if ((line[36] == 'Y') && (line[37] == 'E')) { + /* + * CRC is Ok, continue + */ +// fgets(line, 50, fp); +// line[strlen(line)-1] = '\0'; +// strtok(line, (char *)"="); +// p = strtok(NULL, (char *)"="); +// rc = sscanf(p, "%d", &temp); +// if ((rc == 1) && (tmp1->lastval != temp)) { + /* + * It is possible to have read errors or extreme values. + * This can happen with bad connections so we compare the + * value with the previous one. If the difference is too + * much, we don't send that value. That also means that if + * the next value is ok again, it will be marked invalid too. + * Maximum error is 20 degrees for now. + */ +// deviation = 20000; +// if ( (tmp1->lastval == 0) || +// (tmp1->lastval && (temp > (tmp1->lastval - deviation)) && (temp < (tmp1->lastval + deviation))) ) { + /* + * Temperature is changed and valid, set flag. + */ +// tmp1->update = TRUE; +// } else { +// syslog(LOG_NOTICE, "deviation error deviation=%d, old=%d new=%d", deviation, tmp1->lastval, temp); +// if (debug) { +// fprintf(stdout, "deviation error deviation=%d, old=%d new=%d\n", deviation, tmp1->lastval, temp); +// } +// } +// tmp1->lastval = temp; +// } +// } else { +// syslog(LOG_NOTICE, "sensor %s/%s CRC error", tmp1->master, tmp1->name); +// } +// fclose(fp); +// tmp1->present = 1; +// } else { +// tmp1->present = 0; +// if (debug) +// printf("sensor %s is missing\n", tmp1->name); +// } + +// free(device); +// device = NULL; + } + usleep(10000); + } + + syslog(LOG_NOTICE, "Thread my_devices_loop stopped"); + if (debug) + fprintf(stdout, "Thread my_devices_loop stopped\n"); + + return 0; +} + + + diff -r 259a018758f9 -r f1b7e2ef90be thermferm/devices.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thermferm/devices.h Thu Jul 31 17:44:50 2014 +0200 @@ -0,0 +1,13 @@ +#ifndef MY_DEVICES_H +#define MY_DEVICES_H + + +int devices_detect(void); + +#ifdef HAVE_WIRINGPI_H +PI_THREAD (my_devices_loop); +#else +void *my_devices_loop(void *); +#endif + +#endif diff -r 259a018758f9 -r f1b7e2ef90be thermferm/rdconfig.c --- a/thermferm/rdconfig.c Thu Jul 31 13:43:09 2014 +0200 +++ b/thermferm/rdconfig.c Thu Jul 31 17:44:50 2014 +0200 @@ -35,7 +35,9 @@ const char UNITMODE[5][8] = { "OFF", "NONE", "FRIDGE", "BEER", "PROFILE" }; const char UNITmode[5] = { 'o', 'n', 'f', 'b', 'p' }; const char PROFSTATE[4][6] = { "OFF", "PAUSE", "RUN", "DONE" }; - +const char DEVTYPE[7][6] = { "NA", "W1", "GPIO", "RC433", "DHT", "I2C", "SPI" }; +const char DEVPRESENT[4][6] = { "UNDEF", "NO", "YES", "ERROR" }; +const char DEVDIR[6][11] = { "UNDEF", "IN_BIN", "OUT_BIN", "IN_ANALOG", "OUT_ANALOG", "OUT_PWM" }; @@ -119,6 +121,7 @@ units_list *tmp3; profiles_list *tmp4; prof_step *tmp5; + devices_list *device; /* * Create a new XML buffer, to which the XML document will be written @@ -495,6 +498,80 @@ } } + if (Config.devices) { + if ((rc = xmlTextWriterStartElement(writer, BAD_CAST "DEVICES")) < 0) { + syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterStartElement"); + return 1; + } + 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 "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; + } + } + + if ((rc = xmlTextWriterEndElement(writer)) < 0) { + syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterEndElement"); + return 1; + } + } + /* * All done, close any open elements */ @@ -1000,6 +1077,137 @@ +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 = 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 < 7; 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 < 6; 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 *)"PRESENT"))) { + key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); + for (i = 0; i < 4; i++) { + if (! xmlStrcmp(key, (const xmlChar *)DEVDIR[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 *)"DESCRPTION"))) { + 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; +} + + + int rdconfig(void) { int rc = 0, ival; @@ -1094,6 +1302,9 @@ if ((!xmlStrcmp(cur->name, (const xmlChar *)"PROFILES"))) { parseProfiles(doc, cur); } + if ((!xmlStrcmp(cur->name, (const xmlChar *)"DEVICES"))) { + parseDevices(doc, cur); + } cur = cur->next; } xmlFreeDoc(doc); diff -r 259a018758f9 -r f1b7e2ef90be thermferm/server.c --- a/thermferm/server.c Thu Jul 31 13:43:09 2014 +0200 +++ b/thermferm/server.c Thu Jul 31 17:44:50 2014 +0200 @@ -413,7 +413,7 @@ if (unit->io2_address && (strncmp((char *)"3a", unit->io2_address, 2) == 0)) ref++; } - srv_send((char *)"%s,%d,2413,Dual channel addressable switchs", de->d_name, ref); + srv_send((char *)"%s,%d,2413,Dual channel addressable switch", de->d_name, ref); } else { srv_send((char *)"%s,0,NA,Unknown device", de->d_name); } diff -r 259a018758f9 -r f1b7e2ef90be thermferm/thermferm.c --- a/thermferm/thermferm.c Thu Jul 31 13:43:09 2014 +0200 +++ b/thermferm/thermferm.c Thu Jul 31 17:44:50 2014 +0200 @@ -24,6 +24,7 @@ #include "logger.h" #include "rdconfig.h" #include "sensors.h" +#include "devices.c" #include "server.h" #include "thermferm.h" #include "lcd-pcf8574.h" @@ -245,6 +246,14 @@ return 1; } + rc = devices_detect(); + if (rc) { + syslog(LOG_NOTICE, "Detected %d new devices", rc); + if (debug) + fprintf(stdout, "Detected %d new devices\n", rc); + wrconfig(); + } + #ifdef HAVE_WIRINGPI_H rc = piThreadCreate(my_sensors_loop); #else diff -r 259a018758f9 -r f1b7e2ef90be thermferm/thermferm.h --- a/thermferm/thermferm.h Thu Jul 31 13:43:09 2014 +0200 +++ b/thermferm/thermferm.h Thu Jul 31 17:44:50 2014 +0200 @@ -135,6 +135,46 @@ #define PROFILE_RUN 2 /* Profile is running */ #define PROFILE_DONE 3 /* Profile is finished */ +/* + * External devices like sensors, relays. + */ +typedef struct _dev_list { + struct _dev_list *next; + int version; /* Version 1 */ + char *uuid; /* UUID of this device */ + int type; /* Device type */ + int direction; /* Device direction */ + int value; /* Device value */ + int present; /* Device present */ + char *address; /* Device address */ + int subdevice; /* Device sub address */ + int gpiopin; /* Device GPIO pin or -1 */ + char *description; /* Device description */ + int inuse; /* In use counter */ + char *comment; /* What we think it is */ + time_t timestamp; /* Last updated */ +} devices_list; + +#define DEVTYPE_NA 0 /* Unknown device type */ +#define DEVTYPE_W1 1 /* 1-Wire bus */ +#define DEVTYPE_GPIO 2 /* GPIO I/O device */ +#define DEVTYPE_RC433 3 /* 433 MHz device */ +#define DEVTYPE_DHT 4 /* DHT type device on GPIO */ +#define DEVTYPE_I2C 5 /* I2C bus device */ +#define DEVTYPE_SPI 6 /* SPI bus device */ + +#define DEVPRESENT_UNDEF 0 /* Precence not testable */ +#define DEVPRESENT_NO 1 /* Device is missing */ +#define DEVPRESENT_YES 2 /* Device is detected */ +#define DEVPRESENT_ERROR 3 /* Device is in error */ + +#define DEVDIR_UNDEF 0 /* Undefined */ +#define DEVDIR_IN_BIN 1 /* Binary input */ +#define DEVDIR_OUT_BIN 2 /* Binary output */ +#define DEVDIR_IN_ANALOG 3 /* Temperature input etc. */ +#define DEVDIR_OUT_ANALOG 4 /* Analog steering */ +#define DEVDIR_OUT_PWM 5 /* PWM outout */ + typedef struct _w1_therm { struct _w1_therm *next; @@ -162,6 +202,7 @@ #endif units_list *units; /* Fermenter units */ profiles_list *profiles; /* Ferment profiles */ + devices_list *devices; /* Sensors and switches */ } sys_config;