Sat, 16 May 2015 17:39:30 +0200
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) 2008-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 "logger.h" #include "devices.h" #include "server.h" #include "lcd-buffer.h" #include "xutil.h" extern int my_shutdown; extern int debug; extern int run_pause; extern int run_hold; extern sys_config Config; extern const char UNITMODE[5][8]; extern const char TEMPSTATE[3][8]; extern const char DEVTYPE[8][6]; extern const char DEVPRESENT[4][6]; extern const char DEVDIR[7][11]; extern const char PROFSTATE[5][6]; int s; /* connected socket */ int ls; /* listen socket */ struct sockaddr_in myaddr_in; /* for local socket address */ struct sockaddr_in peeraddr_in; /* for peer socket address */ struct hostent *hp; #define SS_BUFSIZE 1024 #define SS_TIMEOUT 300 #define MAX_INTERVALS 6 const int GRAPH_INTERVAL[MAX_INTERVALS] = { 0, 1, 5, 15, 30, 60, }; const int GRAPH_DATALINES[MAX_INTERVALS] = { 0, 800, 3200, 12000, 24000, 48000, }; const char MONTH[12][4] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; typedef struct _ls_list { struct _ls_list *next; /* Next record pointer */ char d_name[256]; /* File name */ mode_t mode; /* File mode */ off_t size; /* File size */ time_t mtime; /* File modification time */ } ls_list; void tidy_lslist(ls_list **); void fill_list(ls_list **, char *, mode_t, off_t, time_t); int comp(ls_list **,ls_list **); void sort_list(ls_list **); /* * Send message to client */ int srv_send(const char *format, ...) { char out[SS_BUFSIZE]; va_list va_ptr; if (s == -1) return -1; va_start(va_ptr, format); vsnprintf(out, SS_BUFSIZE-1, format, va_ptr); va_end(va_ptr); if (debug) { syslog(LOG_NOTICE, "send: \"%s\"", out); fprintf(stdout, "send: \"%s\"\n", out); } if (send(s, out, strlen(out), 0) != strlen(out)) { syslog(LOG_NOTICE, "srv_send failed"); return -1; } if (send(s, (char *)"\r\n", 2, 0) != 2) { syslog(LOG_NOTICE, "srv_send failed"); return -1; } return 0; } /* * Argument is a buffer of size SS_BUFSIZE. * Return -1 if error, else the number of received * character. \n is line end, ignore \r. */ int srv_recv(char *buffer) { int bytesloaded = 0; ssize_t ret; unsigned char buf; socklen_t fromlen; memset(buffer, 0, SS_BUFSIZE); while(1) { /* * read a single byte */ fromlen = sizeof(peeraddr_in); ret = recvfrom(s, &buf, 1, 0, (struct sockaddr *)&peeraddr_in, &fromlen); if (ret < 1) { syslog(LOG_NOTICE, "recvfrom(): %s", strerror(errno)); srv_send((char *)"518 recfrom(): %s", strerror(errno)); return -1; /* error */ } if (buf == '\n') break; if (buf != '\r') { buffer[bytesloaded] = buf; bytesloaded++; } } if (debug) { syslog(LOG_NOTICE, "recv: %d `%s'", bytesloaded, buffer); fprintf(stdout, "recv: %d `%s'\n", bytesloaded, buffer); } return bytesloaded; } /* * Update the device inuse counter. */ void device_count(int plus, char *uuid) { devices_list *device; for (device = Config.devices; device; device = device->next) { if (strcmp(device->uuid, uuid) == 0) { #ifdef HAVE_WIRINGPI_H piLock(LOCK_DEVICES); #endif if (plus == TRUE) { device->inuse++; } else { if (device->inuse) device->inuse--; } #ifdef HAVE_WIRINGPI_H piUnlock(LOCK_DEVICES); #endif } } } int delete_Profile(char *uuid) { profiles_list *current = Config.profiles; profiles_list *previous = NULL; prof_step *step, *olds; while (current) { if (strcmp(current->uuid, uuid) == 0) { if (previous == NULL) { Config.profiles = current->next; free(current->uuid); current->uuid = NULL; free(current->name); current->name = NULL; if (current->steps) { for (step = current->steps; step; step = olds) { olds = step->next; free(step); } current->steps = NULL; } free(current); return 1; } else { free(current->uuid); current->uuid = NULL; free(current->name); current->name = NULL; if (current->steps) { for (step = current->steps; step; step = olds) { olds = step->next; free(step); } current->steps = NULL; } previous->next = current->next; free(current); current = previous->next; return 1; } } else { previous = current; current = current->next; } } return 0; } void tidy_lslist(ls_list **lap) { ls_list *tmp, *old; for (tmp = *lap; tmp; tmp = old) { old = tmp->next; free(tmp); } *lap = NULL; } void fill_list(ls_list **lap, char *name, mode_t mode, off_t size, time_t mtime) { ls_list **tmp; for (tmp = lap; *tmp; tmp = &((*tmp)->next)); *tmp = (ls_list *)malloc(sizeof(ls_list)); (*tmp)->next = NULL; strncpy((*tmp)->d_name, name, 256); (*tmp)->mode = mode; (*tmp)->size = size; (*tmp)->mtime = mtime; tmp = &((*tmp)->next); } void sort_list(ls_list **lap) { ls_list *ta, **vector; size_t n = 0, i; if (*lap == NULL) return; for (ta = *lap; ta; ta = ta->next) n++; vector = (ls_list **)malloc(n * sizeof(ls_list *)); i = 0; for (ta = *lap; ta; ta = ta->next) { vector[i++] = ta; } qsort(vector, n, sizeof(ls_list *), (int(*)(const void*, const void*))comp); (*lap) = vector[0]; i = 1; for (ta = *lap; ta; ta = ta->next) { if (i < n) ta->next = vector[i++]; else ta->next = NULL; } free(vector); return; } int comp(ls_list **lsp1, ls_list **lsp2) { return strcmp((*lsp1)->d_name, (*lsp2)->d_name); } /* * ARCHIVE DIR * ARCHIVE GET filename * ARCHIVE LOG filename * ARCHIVE HELP */ int cmd_archive(char *buf) { char *opt, *param, *name = NULL, *filename = NULL, mbits[11], tstr[24]; DIR *dd; FILE *fp; struct dirent entry, *result; ls_list *lsx = NULL, *tmp; struct stat sbuf; struct tm *tbuf; time_t ftime; opt = strtok(buf, " \0"); opt = strtok(NULL, " \0"); if (opt == NULL) { srv_send((char *)"501 Subcommand missing"); return 1; } param = strtok(NULL, "\0"); if (strcmp(opt, (char *)"HELP") == 0) { srv_send((char *)"100 Help text follows:"); srv_send((char *)"Recognized commands:"); srv_send((char *)"ARCHIVE DIR Archived logfiles directory"); srv_send((char *)"ARCHIVE GET filename Archived logfile download"); srv_send((char *)"ARCHIVE LOG filename Archived logfile data in graphsteps"); srv_send((char *)"."); return 0; } if (strcmp(opt, (char *)"DIR") == 0) { if (getenv((char *)"USER") == NULL) { name = xstrcpy((char *)"/root"); } else { name = xstrcpy(getenv((char *)"HOME")); } name = xstrcat(name, (char *)"/.thermferm/log/"); if ((dd = opendir(name))) { for (;;) { if ((readdir_r(dd, &entry, &result)) != 0) { syslog(LOG_NOTICE, "readdir_r: error=%d", errno); break; } if (result == NULL) /* End of directory */ break; if (result->d_name[0] != '.') { filename = xstrcpy(name); filename = xstrcat(filename, result->d_name); if ((stat(filename, &sbuf)) == 0) { fill_list(&lsx, result->d_name, sbuf.st_mode, sbuf.st_size, sbuf.st_mtime); } free(filename); filename = NULL; } } closedir(dd); } else { syslog(LOG_NOTICE, "opendir: \"%s\" error=%d", name, errno); } sort_list(&lsx); srv_send((char *)"212 Archive directory follows:"); for (tmp = lsx; tmp; tmp = tmp->next) { sprintf(mbits, "----------"); if (tmp->mode & S_IRUSR) mbits[1] = 'r'; if (tmp->mode & S_IWUSR) mbits[2] = 'w'; if (tmp->mode & S_IXUSR) mbits[3] = 'x'; if (tmp->mode & S_IRGRP) mbits[4] = 'r'; if (tmp->mode & S_IWGRP) mbits[5] = 'w'; if (tmp->mode & S_IXGRP) mbits[6] = 'x'; if (tmp->mode & S_IROTH) mbits[7] = 'r'; if (tmp->mode & S_IWOTH) mbits[8] = 'w'; if (tmp->mode & S_IXOTH) mbits[9] = 'x'; ftime = tmp->mtime; tbuf = localtime(&ftime); sprintf(tstr, "%02d %s %04d %02d:%02d", tbuf->tm_mday, MONTH[tbuf->tm_mon], tbuf->tm_year+1900, tbuf->tm_hour, tbuf->tm_min); srv_send((char *)"%s,%s,%d,%s", tmp->d_name, mbits, tmp->size, tstr); } srv_send((char *)"."); tidy_lslist(&lsx); free(name); name = NULL; return 1; } if (param == NULL) { srv_send((char *)"502 Parameter missing"); return 1; } if (strcmp(opt, (char *)"GET") == 0) { if (getenv((char *)"USER") == NULL) { name = xstrcpy((char *)"/root"); } else { name = xstrcpy(getenv((char *)"HOME")); } name = xstrcat(name, (char *)"/.thermferm/log/"); name = xstrcat(name, param); if ((fp = fopen(name, "r"))) { char buffer[256]; srv_send((char *)"212 Archive file follows:"); while (fgets(buffer, sizeof(buffer)-1, fp) != NULL) { int i; for (i = 0; i < strlen(buffer); i++) { if (buffer[i] == '\n') buffer[i] = '\0'; if (buffer[i] == '\r') buffer[i] = '\0'; } srv_send(buffer); } srv_send((char *)"."); fclose(fp); } else { srv_send((char *)"440 No such file"); } free(name); name = NULL; return 1; } if (strcmp(opt, (char *)"LOG") == 0) { if (getenv((char *)"USER") == NULL) { name = xstrcpy((char *)"/root"); } else { name = xstrcpy(getenv((char *)"HOME")); } name = xstrcat(name, (char *)"/.thermferm/log/"); name = xstrcat(name, param); if ((fp = fopen(name, "r"))) { char buffer[256], outbuf[256], q[5]; char *date_n, *mode_n, *air_n, *beer_n, *target_n, *heater_n, *cooler_n, *room_n; char *heater_u, *cooler_u; int lines = 0, heater_l = 0, cooler_l = 0, h = 0, c = 0, heat_used = 0, cool_used = 0, graphstep = 0; float room_t = 0.0; srv_send((char *)"212 Logfile list follows:"); while (fgets(buffer, sizeof(buffer)-1, fp) != NULL) { lines++; } fseek(fp, 0L, SEEK_SET); /* * We have counted the lines in the logfile including the header lines. * The header lines should be ignored but there are so few of them, we * just include them in the total. * Now find a reasonable interval of lines to sent to the client. */ for (graphstep = 1; graphstep <= MAX_INTERVALS; graphstep++) { if (lines < GRAPH_DATALINES[graphstep]) { break; } } syslog(LOG_NOTICE, "ARCHIVE LOG %s: lines=%d, interval=%d, graphstep=%d", param, lines, GRAPH_INTERVAL[graphstep], graphstep); while (fgets(buffer, sizeof(buffer)-1, fp) != NULL) { /* * 2014-11-15 18:39,BEER,20.312,19.750,20.0,0,NA,NA,NA,78105,NA,NA,18.000 * | | | | | | | | | | | | | * date_n | | | | | | | | | | | | * mode_n ----------+ | | | | | | | | | | | * air_n -----------------+ | | | | | | | | | | * beer_n -----------------------+ | | | | | | | | | * target_n ---------------------------+ | | | | | | | | * heater_n -------------------------------+ | | | | | | | * cooler_n ---------------------------------+ | | | | | | * not used ------------------------------------+ | | | | | * not used ---------------------------------------+ | | | | * heater_u --------------------------------------------+ | | | * cooler_u ------------------------------------------------+ | | * not used ---------------------------------------------------+ | * room_n ----------------------------------------------------------+ */ q[0] = buffer[11]; q[1] = buffer[12]; q[2] = buffer[14]; q[3] = buffer[15]; buffer[strlen(buffer) -1] = '\0'; date_n = strtok(buffer, ",\0"); /* timestamp */ mode_n = strtok(NULL, ",\0"); /* unit mode */ air_n = strtok(NULL, ",\0"); /* air temp */ beer_n = strtok(NULL, ",\0"); /* beer temp */ target_n = strtok(NULL, ",\0"); /* target temp */ heater_n = strtok(NULL, ",\0"); /* current heater state */ cooler_n = strtok(NULL, ",\0"); /* current cooler state */ heater_u = strtok(NULL, ",\0"); /* current fan state */ heater_u = strtok(NULL, ",\0"); /* current door state */ heater_u = strtok(NULL, ",\0"); /* heater use counter */ cooler_u = strtok(NULL, ",\0"); /* cooler use counter */ room_n = strtok(NULL, ",\0"); /* fan use counter */ room_n = strtok(NULL, ",\0"); /* room temperature */ if (strncmp(mode_n, (char *)"Mode", 4)) { /* * Output a line at the right intervals */ if (((graphstep == 1)) || ((graphstep == 2) && (q[3] == '0' || q[3] == '5')) || ((graphstep == 3) && ((q[2] == '0' && q[3] == '0') || (q[2] == '1' && q[3] == '5') || (q[2] == '3' && q[3] == '0') || (q[2] == '4' && q[3] == '5'))) || ((graphstep == 4) && ((q[2] == '0' && q[3] == '0') || (q[2] == '3' && q[3] == '0'))) || ((graphstep == 5) && (q[2] == '0' && q[3] == '0')) ) { heat_used = cool_used = 0; if (heater_u && strcmp(heater_u, "NA") && (sscanf(heater_u, "%d", &h) == 1)) { if (h && heater_l) { heat_used = ((h - heater_l) * 100) / (GRAPH_INTERVAL[graphstep] * 60); } } if (cooler_u && strcmp(cooler_u, "NA") && (sscanf(cooler_u, "%d", &c) == 1)) { if (c && cooler_l) { cool_used = ((c - cooler_l) * 100) / (GRAPH_INTERVAL[graphstep] * 60); } } if (room_n) sscanf(room_n, "%f", &room_t); snprintf(outbuf, 255, "%s,%s,%s,%s,%s,%s,%s,%d,%d,%.1f", date_n, mode_n, air_n, beer_n, target_n, heater_n, cooler_n, heat_used, cool_used, room_t); srv_send(outbuf); if (heater_u && h && strcmp(heater_u, "NA")) heater_l = h; if (cooler_u && c & strcmp(cooler_u, "NA")) cooler_l = c; } } } srv_send((char *)"."); fclose(fp); } else { srv_send((char *)"440 No such file"); } free(name); name = NULL; return 1; } return 0; } int delete_Device(char *uuid) { devices_list *current = Config.devices; devices_list *previous = NULL; while (current) { if (strcmp(current->uuid, uuid) == 0) { if (previous == NULL) { Config.devices = current->next; free(current->uuid); current->uuid = NULL; free(current->address); current->address = NULL; free(current->description); current->description = NULL; free(current->comment); current->comment = NULL; free(current); return 1; } else { free(current->uuid); current->uuid = NULL; free(current->address); current->address = NULL; free(current->description); current->description = NULL; free(current->comment); current->comment = NULL; previous->next = current->next; free(current); current = previous->next; return 1; } } else { previous = current; current = current->next; } } return 0; } /* * DEVICE ADD type * DEVICE DEL uuid * DEVICE LIST * DEVICE GET uuid * DEVICE PUT uuid */ int cmd_device(char *buf) { char *opt, *param, *kwd, *val, ibuf[SS_BUFSIZE]; devices_list *device, *tmpd; int i, rc, rlen, ival; uuid_t uu; opt = strtok(buf, " \0"); opt = strtok(NULL, " \0"); if (opt == NULL) { srv_send((char *)"501 Subcommand missing"); return 1; } param = strtok(NULL, "\0"); if (strcmp(opt, (char *)"LIST") == 0) { srv_send((char *)"212 Devices list follows:"); for (device = Config.devices; device; device = device->next) { srv_send((char *)"%s,%s,%d,%d,%s,%s,%d", device->uuid, device->address, device->subdevice, device->inuse, device->comment, DEVDIR[device->direction], device->value + device->offset); } srv_send((char *)"."); return 1; } if (param == NULL) { srv_send((char *)"502 Parameter missing"); return 1; } if (strcmp(opt, (char *)"ADD") == 0) { if ((strcmp(param, (char *)"RC433") == 0) || (strcmp(param, (char *)"DHT") == 0) || (strcmp(param, (char *)"I2C") == 0) || (strcmp(param, (char *)"SPI") == 0)) { device = (devices_list *)malloc(sizeof(devices_list)); device->next = NULL; device->version = 1; device->uuid = malloc(37); uuid_generate(uu); uuid_unparse(uu, device->uuid); for (i = 0; i < 8; i++) { if (strcmp(param, DEVTYPE[i]) == 0) { device->type = i; break; } } device->direction = DEVDIR_UNDEF; device->value = device->offset = device->subdevice = device->inuse = 0; device->present = DEVPRESENT_UNDEF; device->address = xstrcpy((char *)"Enter address here"); device->gpiopin = -1; device->description = xstrcpy((char *)"Describe me here"); device->comment = xstrcpy((char *)"Comment here"); #ifdef HAVE_WIRINGPI_H piLock(LOCK_DEVICES); #endif if (Config.devices == NULL) { Config.devices = device; } else { for (tmpd = Config.devices; tmpd; tmpd = tmpd->next) { if (tmpd->next == NULL) { tmpd->next = device; break; } } } #ifdef HAVE_WIRINGPI_H piUnlock(LOCK_DEVICES); #endif syslog(LOG_NOTICE, "Device %s added", device->uuid); srv_send((char *)"211 Device %s added", device->uuid); return 0; } else { srv_send((char *)"503 Parameter error"); return 1; } } if (strcmp(opt, (char *)"DEL") == 0) { #ifdef HAVE_WIRINGPI_H piLock(LOCK_DEVICES); #endif rc = delete_Device(param); #ifdef HAVE_WIRINGPI_H piUnlock(LOCK_DEVICES); #endif if (rc) { syslog(LOG_NOTICE, "Device %s deleted", param); srv_send((char *)"211 Device %s deleted", param); return 0; } else { srv_send((char *)"440 No such device"); return 1; } } if (strcmp(opt, (char *)"GET") == 0) { for (device = Config.devices; device; device = device->next) { if (strcmp(device->uuid, param) == 0) { #ifdef HAVE_WIRINGPI_H piLock(LOCK_DEVICES); #endif int my_value = device->value; int my_timestamp = (int)device->timestamp; #ifdef HAVE_WIRINGPI_H piUnlock(LOCK_DEVICES); #endif srv_send((char *)"213 Device record follows:"); srv_send((char *)"TYPE,%s", DEVTYPE[device->type]); srv_send((char *)"ADDRESS,%s", device->address); srv_send((char *)"DIRECTION,%s", DEVDIR[device->direction]); srv_send((char *)"VALUE,%d", my_value); srv_send((char *)"OFFSET,%d", device->offset); srv_send((char *)"PRESENT,%s", DEVPRESENT[device->present]); srv_send((char *)"SUBDEVICE,%d", device->subdevice); srv_send((char *)"GPIOPIN,%d", device->gpiopin); srv_send((char *)"DESCRIPTION,%s", device->description); srv_send((char *)"INUSE,%d", device->inuse); srv_send((char *)"COMMENT,%s", device->comment); srv_send((char *)"TIMESTAMP,%d", my_timestamp); srv_send((char *)"."); return 1; } } srv_send((char *)"440 No such device"); return 1; } if (strcmp(opt, (char *)"PUT") == 0) { for (device = Config.devices; device; device = device->next) { if (strcmp(device->uuid, param) == 0) { while (1) { rlen = srv_recv(ibuf); if (rlen == -1) { return 1; } if (strlen(ibuf)) { if (strcmp(ibuf, (char *)".") == 0) { srv_send((char *)"219 Accepted Device record"); return 0; } kwd = strtok(ibuf, ",\0"); val = strtok(NULL, "\0"); if (kwd && val) { if (strcmp(kwd, (char *)"TYPE") == 0) { for (i = 0; i < 8; i++) { if (strcmp(val, DEVTYPE[i]) == 0) { #ifdef HAVE_WIRINGPI_H piLock(LOCK_DEVICES); #endif if (device->type != i) syslog(LOG_NOTICE, "Device %s changed type %s to %s", device->uuid, DEVTYPE[device->type], DEVTYPE[i]); device->type = i; #ifdef HAVE_WIRINGPI_H piUnlock(LOCK_DEVICES); #endif break; } } } else if (strcmp(kwd, (char *)"DIRECTION") == 0) { for (i = 0; i < 7; i++) { if (strcmp(val, DEVDIR[i]) == 0) { #ifdef HAVE_WIRINGPI_H piLock(LOCK_DEVICES); #endif if (device->direction != i) syslog(LOG_NOTICE, "Device %s changed direction %s to %s", device->uuid, DEVDIR[device->type], DEVDIR[i]); device->direction = i; #ifdef HAVE_WIRINGPI_H piUnlock(LOCK_DEVICES); #endif break; } } } else if (strcmp(kwd, (char *)"VALUE") == 0) { if (sscanf(val, "%d", &ival) == 1) { #ifdef HAVE_WIRINGPI_H piLock(LOCK_DEVICES); #endif if (device->value != ival) syslog(LOG_NOTICE, "Device %s changed value %d to %d", device->uuid, device->value, ival); device->value = ival; #ifdef HAVE_WIRINGPI_H piUnlock(LOCK_DEVICES); #endif } } else if (strcmp(kwd, (char *)"OFFSET") == 0) { if (sscanf(val, "%d", &ival) == 1) { #ifdef HAVE_WIRINGPI_H piLock(LOCK_DEVICES); #endif if (device->offset != ival) syslog(LOG_NOTICE, "Device %s changed offset %d to %d", device->uuid, device->offset, ival); device->offset = ival; #ifdef HAVE_WIRINGPI_H piUnlock(LOCK_DEVICES); #endif } } else if (strcmp(kwd, (char *)"PRESENT") == 0) { for (i = 0; i < 4; i++) { if (strcmp(val, DEVPRESENT[i]) == 0) { #ifdef HAVE_WIRINGPI_H piLock(LOCK_DEVICES); #endif if (device->present != i) syslog(LOG_NOTICE, "Device %s changed present %s to %s", device->uuid, DEVPRESENT[device->present], DEVPRESENT[i]); device->present = i; #ifdef HAVE_WIRINGPI_H piUnlock(LOCK_DEVICES); #endif break; } } } else if (strcmp(kwd, (char *)"ADDRESS") == 0) { #ifdef HAVE_WIRINGPI_H piLock(LOCK_DEVICES); #endif if (device->address) { if (strcmp(device->address, val)) syslog(LOG_NOTICE, "Device %s changed address `%s' to `%s'", device->uuid, device->address, val); free(device->address); } device->address = xstrcpy(val); #ifdef HAVE_WIRINGPI_H piUnlock(LOCK_DEVICES); #endif } else if (strcmp(kwd, (char *)"SUBDEVICE") == 0) { if (sscanf(val, "%d", &ival) == 1) { #ifdef HAVE_WIRINGPI_H piLock(LOCK_DEVICES); #endif if (device->subdevice != ival) syslog(LOG_NOTICE, "Device %s changed subdevice %d to %d", device->uuid, device->subdevice, ival); device->subdevice = ival; #ifdef HAVE_WIRINGPI_H piUnlock(LOCK_DEVICES); #endif } } else if (strcmp(kwd, (char *)"GPIOPIN") == 0) { if (sscanf(val, "%d", &ival) == 1) { #ifdef HAVE_WIRINGPI_H piLock(LOCK_DEVICES); #endif if (device->gpiopin != ival) syslog(LOG_NOTICE, "Device %s changed gpiopin %d to %d", device->uuid, device->gpiopin, ival); device->gpiopin = ival; #ifdef HAVE_WIRINGPI_H piUnlock(LOCK_DEVICES); #endif } } else if (strcmp(kwd, (char *)"DESCRIPTION") == 0) { #ifdef HAVE_WIRINGPI_H piLock(LOCK_DEVICES); #endif if (device->description) { if (strcmp(device->description, val)) syslog(LOG_NOTICE, "Device %s changed description `%s' to `%s'", device->uuid, device->description, val); free(device->description); } device->description = xstrcpy(val); #ifdef HAVE_WIRINGPI_H piUnlock(LOCK_DEVICES); #endif } else if (strcmp(kwd, (char *)"COMMENT") == 0) { #ifdef HAVE_WIRINGPI_H piLock(LOCK_DEVICES); #endif if (device->comment) { if (strcmp(device->comment, val)) syslog(LOG_NOTICE, "Device %s changed comment `%s' to `%s'", device->uuid, device->comment, val); free(device->comment); } device->comment = xstrcpy(val); #ifdef HAVE_WIRINGPI_H piUnlock(LOCK_DEVICES); #endif } } } } } } srv_send((char *)"440 No such device"); return 1; } srv_send((char *)"504 Subcommand error"); return 1; } /* * GLOBAL GET * GLOBAL PUT */ int cmd_global(char *buf) { char *opt, *kwd, *val, ibuf[SS_BUFSIZE]; int ival, rlen; opt = strtok(buf, " \0"); opt = strtok(NULL, "\0"); if (opt == NULL) { srv_send((char *)"501 Subcommand missing"); return 1; } if (strcmp(opt, (char *)"GET") == 0) { srv_send((char *)"213 Global Settings record follows:"); srv_send((char *)"RELEASE,%s", VERSION); srv_send((char *)"NAME,%s", Config.name); srv_send((char *)"PORT,%d", Config.my_port); srv_send((char *)"TEMPFORMAT,%c", Config.tempFormat); srv_send((char *)"TEMP_ADDRESS,%s", Config.temp_address); srv_send((char *)"TEMP_STATE,%s", TEMPSTATE[Config.temp_state]); srv_send((char *)"TEMP_VALUE,%.1f", Config.temp_value / 1000.0); srv_send((char *)"HUM_ADDRESS,%s", Config.hum_address); srv_send((char *)"HUM_STATE,%s", TEMPSTATE[Config.hum_state]); srv_send((char *)"HUM_VALUE,%.0f", Config.hum_value / 1000.0); #ifdef HAVE_WIRINGPI_H srv_send((char *)"LCD_COLS,%d", Config.lcd_cols); srv_send((char *)"LCD_ROWS,%d", Config.lcd_rows); #endif srv_send((char *)"."); return 1; } if (strcmp(opt, (char *)"PUT") == 0) { while (1) { rlen = srv_recv(ibuf); if (rlen == -1) { return 1; } if (strlen(ibuf)) { if (strcmp(ibuf, (char *)".") == 0) { srv_send((char *)"219 Accepted Global record"); return 0; } kwd = strtok(ibuf, ",\0"); val = strtok(NULL, "\0"); if (kwd) { if (strcmp(kwd, (char *)"NAME") == 0) { if (val && Config.name && strcmp(val, Config.name)) syslog(LOG_NOTICE, "Global name `%s' to `%s'", Config.name, val); if (Config.name) free(Config.name); if (val) Config.name = xstrcpy(val); else Config.name = NULL; } else if (val && (strcmp(kwd, (char *)"PORT") == 0)) { if (sscanf(val, "%d", &ival) == 1) { if (Config.my_port != ival) syslog(LOG_NOTICE, "Global port %d to %d", Config.my_port, ival); Config.my_port = ival; } } else if (val && (strcmp(kwd, (char *)"TEMPFORMAT") == 0)) { if ((val[0] == 'C') || (val[0] == 'F')) { if (Config.tempFormat != val[0]) syslog(LOG_NOTICE, "Global port %c to %c", Config.tempFormat, val[0]); Config.tempFormat = val[0]; } } else if (strcmp(kwd, (char *)"TEMP_ADDRESS") == 0) { if (val && Config.temp_address && (strcmp(val, Config.temp_address))) syslog(LOG_NOTICE, "Global temperature address `%s' to `%s'", Config.temp_address, val); if (Config.temp_address) { device_count(FALSE, Config.temp_address); free(Config.temp_address); } if (val) { Config.temp_address = xstrcpy(val); device_count(TRUE, Config.temp_address); } else Config.temp_address = NULL; } else if (strcmp(kwd, (char *)"HUM_ADDRESS") == 0) { if (val && Config.hum_address && (strcmp(val, Config.hum_address))) syslog(LOG_NOTICE, "Global humidity address `%s' to `%s'", Config.hum_address, val); if (Config.hum_address) { device_count(FALSE, Config.hum_address); free(Config.hum_address); } if (val) { Config.hum_address = xstrcpy(val); device_count(TRUE, Config.hum_address); } else Config.hum_address = NULL; #ifdef HAVE_WIRINGPI_H } else if (val && (strcmp(kwd, (char *)"LCD_COLS") == 0)) { if (sscanf(val, "%d", &ival) == 1) { if (Config.lcd_cols != ival) syslog(LOG_NOTICE, "Global LCD columns %d to %d", Config.lcd_cols, ival); Config.lcd_cols = ival; } } else if (val && (strcmp(kwd, (char *)"LCD_ROWS") == 0)) { if (sscanf(val, "%d", &ival) == 1) { if (Config.lcd_rows != ival) syslog(LOG_NOTICE, "Global LCD rows %d to %d", Config.lcd_rows, ival); Config.lcd_rows = ival; } #endif } } } } } srv_send((char *)"504 Subcommand error"); return 1; } /* * LIST * LIST LOG */ int cmd_list(char *buf) { char *opt, *param, *filename, q[5], buffer[256], outbuf[256]; char *date_n, *mode_n, *air_n, *beer_n, *target_n, *heater_n, *cooler_n, *room_n; char *heater_u, *cooler_u; int heater_l = 0, cooler_l = 0, h = 0, c = 0, heat_used = 0, cool_used = 0, lines = 0, graphstep = 0; units_list *unit; FILE *fp; float room_t; opt = strtok(buf, " \0"); opt = strtok(NULL, " \0"); if (opt == NULL) { /* * Default, list available units */ srv_send((char *)"212 Fermenter list follows:"); for (unit = Config.units; unit; unit = unit->next) { srv_send((char *)"%s,%s,%s", unit->uuid, unit->name, UNITMODE[unit->mode]); } srv_send((char *)"."); return 1; } else if (strcmp(opt, (char *)"LOG") == 0) { param = strtok(NULL, "\0"); if (param == NULL) { srv_send((char *)"502 Parameter missing"); return 1; } q[0] = q[1] = q[2] = q[3] = q[4] = 'a'; for (unit = Config.units; unit; unit = unit->next) { if (strcmp(param, unit->uuid) == 0) break; } srv_send((char *)"212 Logfile list follows:"); if (getenv((char *)"USER") == NULL) { filename = xstrcpy((char *)"/root"); } else { filename = xstrcpy(getenv((char *)"HOME")); } filename = xstrcat(filename, (char *)"/.thermferm/log/"); filename = xstrcat(filename, unit->name); filename = xstrcat(filename, (char *)".log"); if ((fp = fopen(filename, "r"))) { /* * Count the lines in the logfile */ lines = 0; while (fgets(buffer, sizeof(buffer)-1, fp) != NULL) { lines++; } fseek(fp, 0L, SEEK_SET); /* * We have counted the lines in the logfile including the header lines. * The header lines should be ignored but there are so few of them, we * just include them in the total. * Now find a reasonable interval of lines to sent to the client. */ for (graphstep = 1; graphstep <= MAX_INTERVALS; graphstep++) { if (lines < GRAPH_DATALINES[graphstep]) { break; } } syslog(LOG_NOTICE, "LIST LOG %s: lines=%d, interval=%d, graphstep=%d", unit->name, lines, GRAPH_INTERVAL[graphstep], graphstep); while (fgets(buffer, sizeof(buffer)-1, fp) != NULL) { /* * 2014-11-15 18:39,BEER,20.312,19.750,20.0,0,NA,NA,NA,78105,NA,NA */ q[0] = buffer[11]; q[1] = buffer[12]; q[2] = buffer[14]; q[3] = buffer[15]; buffer[strlen(buffer) -1] = '\0'; date_n = strtok(buffer, ",\0"); /* timestamp */ mode_n = strtok(NULL, ",\0"); /* unit mode */ air_n = strtok(NULL, ",\0"); /* air temp */ beer_n = strtok(NULL, ",\0"); /* beer temp */ target_n = strtok(NULL, ",\0"); /* target temp */ heater_n = strtok(NULL, ",\0"); /* current heater state */ cooler_n = strtok(NULL, ",\0"); /* current cooler state */ heater_u = strtok(NULL, ",\0"); /* current fan state */ heater_u = strtok(NULL, ",\0"); /* current door state */ heater_u = strtok(NULL, ",\0"); /* heater use counter */ cooler_u = strtok(NULL, ",\0"); /* cooler use counter */ room_n = strtok(NULL, ",\0"); /* fan use counter */ room_n = strtok(NULL, ",\0"); /* room temperature */ if (strncmp(mode_n, (char *)"Mode", 4)) { /* * Output a line at the right intervals */ if (((graphstep == 1)) || ((graphstep == 2) && (q[3] == '0' || q[3] == '5')) || ((graphstep == 3) && ((q[2] == '0' && q[3] == '0') || (q[2] == '1' && q[3] == '5') || (q[2] == '3' && q[3] == '0') || (q[2] == '4' && q[3] == '5'))) || ((graphstep == 4) && ((q[2] == '0' && q[3] == '0') || (q[2] == '3' && q[3] == '0'))) || ((graphstep == 5) && (q[2] == '0' && q[3] == '0')) ) { heat_used = cool_used = 0; if (strcmp(heater_u, "NA") && (sscanf(heater_u, "%d", &h) == 1)) { if (h && heater_l) { heat_used = ((h - heater_l) * 100) / (GRAPH_INTERVAL[graphstep] * 60); } } if (strcmp(cooler_u, "NA") && (sscanf(cooler_u, "%d", &c) == 1)) { if (c && cooler_l) { cool_used = ((c - cooler_l) * 100) / (GRAPH_INTERVAL[graphstep] * 60); } } if (room_n) sscanf(room_n, "%f", &room_t); else room_t = 0.0; snprintf(outbuf, 255, "%s,%s,%s,%s,%s,%s,%s,%d,%d,%.1f", date_n, mode_n, air_n, beer_n, target_n, heater_n, cooler_n, heat_used, cool_used, room_t); srv_send(outbuf); if (h && strcmp(heater_u, "NA")) heater_l = h; if (c & strcmp(cooler_u, "NA")) cooler_l = c; } } } } free(filename); filename = NULL; srv_send((char *)"."); return 1; } srv_send((char *)"504 Subcommand error"); return 1; } /* * PROFILE ADD name Add a new profile * PROFILE DEL uuid Delete profile with uuid * PROFILE LIST List available profiles * PROFILE GET uuid Get profile record * PROFILE PUT uuid Put profile record * PROFILE GETS uuid Get profile steps list * PROFILE PUTS uuid Put profile steps list */ int cmd_profile(char *buf) { char ibuf[SS_BUFSIZE], *sstep, *rest, *targ, *param, *kwd, *val; int j, rlen, istep, irest; float ftarg, fval; char *opt; profiles_list *profile, *tmpp; prof_step *step, *olds; uuid_t uu; opt = strtok(buf, " \0"); opt = strtok(NULL, " \0"); if (opt == NULL) { srv_send((char *)"501 Subcommand missing"); return 1; } if (strcmp(opt, (char *)"LIST") == 0) { /* * Fermenting profiles */ srv_send((char *)"212 Profiles list follows:"); for (profile = Config.profiles; profile; profile = profile->next) { j = 0; for (step = profile->steps; step; step = step->next) j++; srv_send((char *)"%s,%s,%d,%d", profile->uuid, profile->name, j, profile->busy); } srv_send((char *)"."); return 1; } param = strtok(NULL, "\0"); if (param == NULL) { srv_send((char *)"502 Parameter missing"); return 1; } if (strcmp(opt, (char *)"ADD") == 0) { profile = (profiles_list *)malloc(sizeof(profiles_list)); profile->next = NULL; profile->version = 1; profile->uuid = malloc(37); uuid_generate(uu); uuid_unparse(uu, profile->uuid); profile->name = xstrcpy(param); profile->busy = 0; profile->inittemp = 20.0; profile->steps = NULL; if (Config.profiles == NULL) { Config.profiles = profile; } else { for (tmpp = Config.profiles; tmpp; tmpp = tmpp->next) { if (tmpp->next == NULL) { tmpp->next = profile; break; } } } syslog(LOG_NOTICE, "Profile %s added", profile->uuid); srv_send((char *)"211 Profile %s added", profile->uuid); return 0; } else if (strcmp(opt, (char *)"DEL") == 0) { if (delete_Profile(param)) { syslog(LOG_NOTICE, "Profile %s deleted", param); srv_send((char *)"211 Profile %s deleted", param); return 0; } else { srv_send((char *)"440 No such profile"); return 1; } } else if (strcmp(opt, (char *)"GET") == 0) { for (profile = Config.profiles; profile; profile = profile->next) { if (strcmp(profile->uuid, param) == 0) { srv_send((char *)"213 Profile record follows:"); srv_send((char *)"UUID,%s", profile->uuid); srv_send((char *)"NAME,%s", profile->name); srv_send((char *)"INITTEMP,%.1f", profile->inittemp); srv_send((char *)"."); return 1; } } srv_send((char *)"440 No such profile"); return 1; } else if (strcmp(opt, (char *)"PUT") == 0) { for (profile = Config.profiles; profile; profile = profile->next) { if (strcmp(profile->uuid, param) == 0) { while (1) { rlen = srv_recv(ibuf); if (rlen == -1) { return 1; } if (strlen(ibuf)) { if (strcmp(ibuf, (char *)".") == 0) { srv_send((char *)"219 Accepted Profile record"); return 0; } kwd = strtok(ibuf, ",\0"); val = strtok(NULL, "\0"); if (kwd && val) { if (strcmp(kwd, (char *)"NAME") == 0) { if (profile->name) { if (strcmp(profile->name, val)) syslog(LOG_NOTICE, "Profile %s name `%s' to `%s'", profile->uuid, profile->name, val); free(profile->name); } profile->name = xstrcpy(val); } else if (strcmp(kwd, (char *)"INITTEMP") == 0) { if (sscanf(val, "%f", &fval) == 1) { if (profile->inittemp != fval) syslog(LOG_NOTICE, "Profile %s initial temperature %.1f to %.1f", profile->uuid, profile->inittemp, fval); profile->inittemp = fval; } } } } } } } srv_send((char *)"440 No such profile"); return 1; } else if (strcmp(opt, (char *)"GETS") == 0) { for (profile = Config.profiles; profile; profile = profile->next) { if (strcmp(profile->uuid, param) == 0) { srv_send((char *)"215 Profile steps follow:"); for (step = profile->steps; step; step = step->next) { srv_send((char *)"%d,%d,%.1f", step->steptime, step->resttime, step->target); } srv_send((char *)"."); return 1; } } srv_send((char *)"440 No such profile"); return 1; } else if (strcmp(opt, (char *)"PUTS") == 0) { for (profile = Config.profiles; profile; profile = profile->next) { if (strcmp(profile->uuid, param) == 0) { if (profile->steps) { syslog(LOG_NOTICE, "PROFILE PUTS %s erased all old steps", profile->uuid); for (step = profile->steps; step; step = olds) { olds = step->next; free(step); } profile->steps = NULL; } j = 0; while (1) { rlen = srv_recv(ibuf); if (rlen == -1) { return 1; } else { if (strlen(ibuf)) { if (strcmp(ibuf, (char *)".") == 0) { srv_send((char *)"219 Accepted Profile steps"); return 0; } sstep = strtok(ibuf, ",\0"); rest = strtok(NULL, ",\0"); targ = strtok(NULL, "\0"); if ((sscanf(sstep, "%d", &istep) == 1) && (sscanf(rest, "%d", &irest) == 1) && (sscanf(targ, "%f", &ftarg) == 1)) { j++; syslog(LOG_NOTICE, "PROFILE PUTS %s add step %d: steptime=%d resttime=%d target=%.1f", profile->uuid, j, istep, irest, ftarg); step = (prof_step *)malloc(sizeof(prof_step)); step->next = NULL; step->version = 1; step->steptime = istep; step->resttime = irest; step->target = ftarg; if (profile->steps == NULL) { profile->steps = step; } else { for (olds = profile->steps; olds; olds = olds->next) { if (olds->next == NULL) { olds->next = step; break; } } } } } } } } } srv_send((char *)"440 No such profile"); return 1; } srv_send((char *)"504 Subcommand error"); return 1; } #ifdef USE_SIMULATOR int delete_Simulator(char *uuid) { simulator_list *current = Config.simulators; simulator_list *previous = NULL; while (current) { if (strcmp(current->uuid, uuid) == 0) { if (previous == NULL) { Config.simulators = current->next; free(current->uuid); current->uuid = NULL; free(current->name); current->name = NULL; free(current); return 1; } else { free(current->uuid); current->uuid = NULL; free(current->name); current->name = NULL; previous->next = current->next; free(current); current = previous->next; return 1; } } else { previous = current; current = current->next; } } return 0; } /* * SIMULATOR ADD name * SIMULATOR DEL uuid * SIMULATOR LIST * SIMULATOR GET uuid * SIMULATOR PUT uuid */ int cmd_simulator(char *buf) { char *opt, *param, *kwd, *val, ibuf[SS_BUFSIZE]; simulator_list *simulator, *tmps; int rc, rlen, ival; float fval; uuid_t uu; opt = strtok(buf, " \0"); opt = strtok(NULL, " \0"); if (opt == NULL) { srv_send((char *)"501 Subcommand missing"); return 1; } param = strtok(NULL, "\0"); if (strcmp(opt, (char *)"LIST") == 0) { srv_send((char *)"212 Simulators list follows:"); for (simulator = Config.simulators; simulator; simulator = simulator->next) { srv_send((char *)"%s,%s", simulator->uuid, simulator->name); } srv_send((char *)"."); return 1; } if (param == NULL) { srv_send((char *)"502 Parameter missing"); return 1; } if (strcmp(opt, (char *)"ADD") == 0) { /* * For now, only one simulator is allowed. */ if (Config.simulators) { srv_send((char *)"441 Maximum simulators reached"); return 1; } simulator = (simulator_list *)malloc(sizeof(simulator_list)); simulator->next = NULL; simulator->version = 1; simulator->uuid = malloc(37); uuid_generate(uu); uuid_unparse(uu, simulator->uuid); simulator->name = xstrcpy(param); simulator->volume_air = 150; simulator->volume_beer = 50; simulator->room_temperature = simulator->air_temperature = simulator->beer_temperature = simulator->s_cool_temp = simulator->s_heat_temp = 20.0; simulator->cooler_temp = -3.0; /* Cooling temperature */ simulator->cooler_time = 720; /* About 12 minutes for the cooler plate */ simulator->cooler_size = 0.8; /* 0.8 square meter cooler plate */ simulator->heater_temp = 150.0; /* Heating temperature */ simulator->heater_time = 3; /* 3 seconds to heat-up */ simulator->heater_size = 0.01; /* 0.01 square meter heater plate */ simulator->heater_state = simulator->cooler_state = 0; simulator->frigo_isolation = 0.002; simulator->s_yeast_heat = 0.0; simulator->s_yeast_started = simulator->s_cool_changed = simulator->s_heat_changed = (int)0; if (Config.simulators == NULL) { Config.simulators = simulator; } else { for (tmps = Config.simulators; tmps; tmps = tmps->next) { if (tmps->next == NULL) { tmps->next = simulator; break; } } } syslog(LOG_NOTICE, "Simulator %s added", simulator->uuid); srv_send((char *)"211 Simulator %s added", simulator->uuid); return 0; } if (strcmp(opt, (char *)"DEL") == 0) { rc = delete_Simulator(param); if (rc) { syslog(LOG_NOTICE, "Simulator %s deleted", param); srv_send((char *)"211 Simulator %s deleted", param); return 0; } else { srv_send((char *)"440 No such simulator"); return 1; } } if (strcmp(opt, (char *)"GET") == 0) { for (simulator = Config.simulators; simulator; simulator = simulator->next) { if (strcmp(simulator->uuid, param) == 0) { srv_send((char *)"213 Simulator record follows:"); srv_send((char *)"NAME,%s", simulator->name); srv_send((char *)"VOLUME_AIR,%d", simulator->volume_air); srv_send((char *)"VOLUME_BEER,%d", simulator->volume_beer); srv_send((char *)"ROOM_TEMPERATURE,%.1f", simulator->room_temperature); srv_send((char *)"AIR_TEMPERATURE,%.3f", simulator->air_temperature); srv_send((char *)"BEER_TEMPERATURE,%.3f", simulator->beer_temperature); srv_send((char *)"COOLER_TEMP,%.1f", simulator->cooler_temp); srv_send((char *)"COOLER_TIME,%d", simulator->cooler_time); srv_send((char *)"COOLER_SIZE,%.3f", simulator->cooler_size); srv_send((char *)"HEATER_TEMP,%.1f", simulator->heater_temp); srv_send((char *)"HEATER_TIME,%d", simulator->heater_time); srv_send((char *)"HEATER_SIZE,%.3f", simulator->heater_size); srv_send((char *)"HEATER_STATE,%d", simulator->heater_state); srv_send((char *)"COOLER_STATE,%d", simulator->cooler_state); srv_send((char *)"FRIGO_ISOLATION,%.3f", simulator->frigo_isolation); srv_send((char *)"."); return 1; } } srv_send((char *)"440 No such simulator"); return 1; } if (strcmp(opt, (char *)"PUT") == 0) { for (simulator = Config.simulators; simulator; simulator = simulator->next) { if (strcmp(simulator->uuid, param) == 0) { while (1) { rlen = srv_recv(ibuf); if (rlen == -1) { return 1; } if (strlen(ibuf)) { if (strcmp(ibuf, (char *)".") == 0) { srv_send((char *)"219 Accepted Simulator record"); return 0; } kwd = strtok(ibuf, ",\0"); val = strtok(NULL, "\0"); if (kwd && val) { if (strcmp(kwd, (char *)"NAME") == 0) { if (simulator->name) { if (strcmp(simulator->name, val)) syslog(LOG_NOTICE, "Simulator %s name `%s' to `%s'", simulator->uuid, simulator->name, val); free(simulator->name); } simulator->name = xstrcpy(val); } else if (strcmp(kwd, (char *)"VOLUME_AIR") == 0) { if (sscanf(val, "%d", &ival) == 1) { if (simulator->volume_air != ival) syslog(LOG_NOTICE, "Simulator %s volume air %d to %d", simulator->uuid, simulator->volume_air, ival); simulator->volume_air = ival; } } else if (strcmp(kwd, (char *)"VOLUME_BEER") == 0) { if (sscanf(val, "%d", &ival) == 1) { if (simulator->volume_beer != ival) syslog(LOG_NOTICE, "Simulator %s volume beer %d to %d", simulator->uuid, simulator->volume_beer, ival); simulator->volume_beer = ival; } } else if (strcmp(kwd, (char *)"ROOM_TEMPERATURE") == 0) { if (sscanf(val, "%f", &fval) == 1) { if (simulator->room_temperature != fval) syslog(LOG_NOTICE, "Simulator %s room temperature %.1f to %.1f", simulator->uuid, simulator->room_temperature, fval); simulator->room_temperature = fval; } } else if (strcmp(kwd, (char *)"AIR_TEMPERATURE") == 0) { if (sscanf(val, "%f", &fval) == 1) { if (simulator->air_temperature != fval) syslog(LOG_NOTICE, "Simulator %s air temperature %.1f to %.1f", simulator->uuid, simulator->air_temperature, fval); simulator->air_temperature = fval; } } else if (strcmp(kwd, (char *)"BEER_TEMPERATURE") == 0) { if (sscanf(val, "%f", &fval) == 1) { if (simulator->beer_temperature != fval) syslog(LOG_NOTICE, "Simulator %s beer temperature %.1f to %.1f", simulator->uuid, simulator->beer_temperature, fval); simulator->beer_temperature = fval; } } else if (strcmp(kwd, (char *)"COOLER_TEMP") == 0) { if (sscanf(val, "%f", &fval) == 1) { if (simulator->cooler_temp != fval) syslog(LOG_NOTICE, "Simulator %s cooler temperature %.1f to %.1f", simulator->uuid, simulator->cooler_temp, fval); simulator->cooler_temp = fval; } } else if (strcmp(kwd, (char *)"COOLER_TIME") == 0) { if (sscanf(val, "%d", &ival) == 1) { if (simulator->cooler_time != ival) syslog(LOG_NOTICE, "Simulator %s cooler time %d to %d", simulator->uuid, simulator->cooler_time, ival); simulator->cooler_time = ival; } } else if (strcmp(kwd, (char *)"COOLER_SIZE") == 0) { if (sscanf(val, "%f", &fval) == 1) { if (simulator->cooler_size != fval) syslog(LOG_NOTICE, "Simulator %s cooler size %.1f to %.1f", simulator->uuid, simulator->cooler_size, fval); simulator->cooler_size = fval; } } else if (strcmp(kwd, (char *)"HEATER_TEMP") == 0) { if (sscanf(val, "%f", &fval) == 1) { if (simulator->heater_temp != fval) syslog(LOG_NOTICE, "Simulator %s heater temperature %.1f to %.1f", simulator->uuid, simulator->heater_temp, fval); simulator->heater_temp = fval; } } else if (strcmp(kwd, (char *)"HEATER_TIME") == 0) { if (sscanf(val, "%d", &ival) == 1) { if (simulator->heater_time != ival) syslog(LOG_NOTICE, "Simulator %s heater time %d to %d", simulator->uuid, simulator->heater_time, ival); simulator->heater_time = ival; } } else if (strcmp(kwd, (char *)"HEATER_SIZE") == 0) { if (sscanf(val, "%f", &fval) == 1) { if (simulator->heater_size != fval) syslog(LOG_NOTICE, "Simulator %s heater size %.1f to %.1f", simulator->uuid, simulator->heater_size, fval); simulator->heater_size = fval; } } else if (strcmp(kwd, (char *)"HEATER_STATE") == 0) { if (sscanf(val, "%d", &ival) == 1) { if (simulator->heater_state != ival) syslog(LOG_NOTICE, "Simulator %s heater state %d to %d", simulator->uuid, simulator->heater_state, ival); simulator->heater_state = ival; } } else if (strcmp(kwd, (char *)"COOLER_STATE") == 0) { if (sscanf(val, "%d", &ival) == 1) { if (simulator->cooler_state != ival) syslog(LOG_NOTICE, "Simulator %s cooler state %d to %d", simulator->uuid, simulator->cooler_state, ival); simulator->cooler_state = ival; } } else if (strcmp(kwd, (char *)"FRIGO_ISOLATION") == 0) { if (sscanf(val, "%f", &fval) == 1) { if (simulator->frigo_isolation != fval) syslog(LOG_NOTICE, "Simulator %s frigo isolation %.1f to %.1f", simulator->uuid, simulator->frigo_isolation, fval); simulator->frigo_isolation = fval; } } } } } } } srv_send((char *)"440 No such simulator"); return 1; } srv_send((char *)"504 Subcommand error"); return 1; } #endif int delete_Unit(char *uuid) { units_list *current = Config.units; units_list *previous = NULL; while (current) { if (strcmp(current->uuid, uuid) == 0) { if (previous == NULL) { Config.units = current->next; free(current->uuid); current->uuid = NULL; free(current->name); current->name = NULL; if (current->air_address) free(current->air_address); current->air_address = NULL; if (current->beer_address) free(current->beer_address); current->beer_address = NULL; if (current->heater_address) free(current->heater_address); current->heater_address = NULL; if (current->cooler_address) free(current->cooler_address); current->cooler_address = NULL; if (current->fan_address) free(current->fan_address); current->fan_address = NULL; if (current->light_address) free(current->light_address); current->light_address = NULL; if (current->door_address) free(current->door_address); current->door_address = NULL; if (current->psu_address) free(current->psu_address); current->psu_address = NULL; if (current->profile) free(current->profile); current->profile = NULL; if (current->PID_cool) free(current->PID_cool); current->PID_cool = NULL; if (current->PID_heat) free(current->PID_heat); current->PID_heat = NULL; free(current); return 1; } else { free(current->uuid); current->uuid = NULL; free(current->name); current->name = NULL; if (current->air_address) free(current->air_address); current->air_address = NULL; if (current->beer_address) free(current->beer_address); current->beer_address = NULL; if (current->heater_address) free(current->heater_address); current->heater_address = NULL; if (current->cooler_address) free(current->cooler_address); current->cooler_address = NULL; if (current->fan_address) free(current->fan_address); current->fan_address = NULL; if (current->door_address) free(current->door_address); current->door_address = NULL; if (current->light_address) free(current->light_address); current->light_address = NULL; if (current->psu_address) free(current->psu_address); current->psu_address = NULL; if (current->profile) free(current->profile); current->profile = NULL; if (current->PID_cool) free(current->PID_cool); current->PID_cool = NULL; if (current->PID_heat) free(current->PID_heat); current->PID_heat = NULL; previous->next = current->next; free(current); current = previous->next; return 1; } } else { previous = current; current = current->next; } } return 0; } /* * UNIT ADD name * UNIT DEL uuid * UNIT LIST * UNIT GET uuid * UNIT PUT uuid */ int cmd_unit(char *buf) { char *opt, *param = NULL, *kwd, *val, ibuf[SS_BUFSIZE]; units_list *unit, *tmpu; uuid_t uu; int ival, i, rc, rlen; float fval; opt = strtok(buf, " \0"); opt = strtok(NULL, " \0"); if (opt == NULL) { srv_send((char *)"501 Subcommand missing"); return 1; } param = strtok(NULL, "\0"); if ((strcmp(opt, (char *)"LIST") == 0) && (param == NULL)) { srv_send((char *)"212 Fermenter list follows:"); for (unit = Config.units; unit; unit = unit->next) { srv_send((char *)"%s,%s,%s", unit->uuid, unit->name, UNITMODE[unit->mode]); } srv_send((char *)"."); return 1; } if (param == NULL) { srv_send((char *)"502 Parameter missing"); return 1; } if (strcmp(opt, (char *)"ADD") == 0) { unit = (units_list *)malloc(sizeof(units_list)); unit->next = NULL; unit->version = 1; unit->uuid = malloc(37); uuid_generate(uu); uuid_unparse(uu, unit->uuid); unit->name = xstrcpy(param); 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_state = unit->beer_state = 1; unit->air_temperature = unit->beer_temperature = 20000; unit->beer_set = unit->fridge_set = 20.0; unit->heater_state = unit->cooler_state = unit->fan_state = unit->door_state = unit->mode = \ unit->light_state = unit->psu_state = unit->prof_state = 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); /* * Block main process */ run_pause = TRUE; for (;;) { usleep(100000); if (run_hold) break; } if (Config.units == NULL) { Config.units = unit; } else { for (tmpu = Config.units; tmpu; tmpu = tmpu->next) { if (tmpu->next == NULL) { tmpu->next = unit; break; } } } #ifdef HAVE_WIRINGPI_H lcd_buf_reset(); #endif run_pause = FALSE; syslog(LOG_NOTICE, "Unit %s added", unit->uuid); srv_send((char *)"211 Unit %s added", unit->uuid); return 0; } if (strcmp(opt, (char *)"DEL") == 0) { /* * Block main process. */ run_pause = TRUE; for (;;) { usleep(100000); if (run_hold) break; } rc = delete_Unit(param); #ifdef HAVE_WIRINGPI_H lcd_buf_reset(); #endif run_pause = FALSE; if (rc) { syslog(LOG_NOTICE, "Unit %s deleted", param); srv_send((char *)"211 Unit %s deleted", param); return 0; } else { srv_send((char *)"440 No such unit"); return 1; } } if (strcmp(opt, (char *)"GET") == 0) { for (unit = Config.units; unit; unit = unit->next) { if (strcmp(param, unit->uuid) == 0) { srv_send((char *)"213 Unit listing follows:"); srv_send((char *)"NAME,%s", unit->name); srv_send((char *)"UUID,%s", unit->uuid); srv_send((char *)"VOLUME,%2f", unit->volume); srv_send((char *)"AIR_ADDRESS,%s", unit->air_address); srv_send((char *)"AIR_STATE,%s", TEMPSTATE[unit->air_state]); srv_send((char *)"AIR_TEMPERATURE,%.3f", unit->air_temperature / 1000.0); srv_send((char *)"BEER_ADDRESS,%s", MBSE_SS(unit->beer_address)); srv_send((char *)"BEER_STATE,%s", TEMPSTATE[unit->beer_state]); srv_send((char *)"BEER_TEMPERATURE,%.3f", unit->beer_temperature / 1000.0); srv_send((char *)"HEATER_ADDRESS,%s", unit->heater_address); srv_send((char *)"HEATER_STATE,%d", unit->heater_state); srv_send((char *)"HEATER_DELAY,%d", unit->heater_delay); srv_send((char *)"HEATER_USAGE,%d", unit->heater_usage); if (unit->PID_heat) { srv_send((char *)"PIDH_IMAX,%.1f", unit->PID_heat->iMax); srv_send((char *)"PIDH_PGAIN,%.2f", unit->PID_heat->pGain); srv_send((char *)"PIDH_IGAIN,%.2f", unit->PID_heat->iGain); srv_send((char *)"PIDH_DGAIN,%.2f", unit->PID_heat->dGain); srv_send((char *)"PIDH_IDLERANGE,%.2f", unit->PID_heat->idleRange); } srv_send((char *)"COOLER_ADDRESS,%s", unit->cooler_address); srv_send((char *)"COOLER_STATE,%d", unit->cooler_state); srv_send((char *)"COOLER_DELAY,%d", unit->cooler_delay); srv_send((char *)"COOLER_USAGE,%d", unit->cooler_usage); if (unit->PID_cool) { srv_send((char *)"PIDC_IMAX,%.1f", unit->PID_cool->iMax); srv_send((char *)"PIDC_PGAIN,%.2f", unit->PID_cool->pGain); srv_send((char *)"PIDC_IGAIN,%.2f", unit->PID_cool->iGain); srv_send((char *)"PIDC_DGAIN,%.2f", unit->PID_cool->dGain); srv_send((char *)"PIDC_IDLERANGE,%.2f", unit->PID_cool->idleRange); } srv_send((char *)"FAN_ADDRESS,%s", unit->fan_address); srv_send((char *)"FAN_STATE,%d", unit->fan_state); srv_send((char *)"FAN_DELAY,%d", unit->fan_delay); srv_send((char *)"FAN_USAGE,%d", unit->fan_usage); srv_send((char *)"LIGHT_ADDRESS,%s", unit->light_address); srv_send((char *)"LIGHT_STATE,%d", unit->light_state); srv_send((char *)"LIGHT_DELAY,%d", unit->light_delay); srv_send((char *)"LIGHT_USAGE,%d", unit->light_usage); srv_send((char *)"DOOR_ADDRESS,%s", unit->door_address); srv_send((char *)"DOOR_STATE,%d", unit->door_state); srv_send((char *)"PSU_ADDRESS,%s", unit->psu_address); srv_send((char *)"PSU_STATE,%d", unit->psu_state); srv_send((char *)"MODE,%s", UNITMODE[unit->mode]); srv_send((char *)"FRIDGE_SET,%.1f", unit->fridge_set); srv_send((char *)"BEER_SET,%.1f", unit->beer_set); srv_send((char *)"PROFILE,%s", unit->profile); srv_send((char *)"PROF_STARTED,%d", (int)unit->prof_started); if (unit->prof_state == PROFILE_RUN) { srv_send((char *)"PROF_STATE,%s %d%%", PROFSTATE[unit->prof_state], unit->prof_percent); } else { srv_send((char *)"PROF_STATE,%s", PROFSTATE[unit->prof_state]); } srv_send((char *)"PROF_TARGET,%.3f", unit->prof_target); srv_send((char *)"PROF_PEAK_ABS,%.3f", unit->prof_peak_abs); srv_send((char *)"PROF_PEAK_REL,%.3f", unit->prof_peak_rel); srv_send((char *)"PROF_PRIMARY_DONE,%d", (int)unit->prof_primary_done); srv_send((char *)"TEMP_SET_MIN,%.1f", unit->temp_set_min); srv_send((char *)"TEMP_SET_MAX,%.1f", unit->temp_set_max); srv_send((char *)"."); return 1; } } srv_send((char *)"440 No such unit"); return 1; } if (strcmp(opt, (char *)"PUT") == 0) { /* * Block main process */ run_pause = TRUE; for (;;) { usleep(100000); if (run_hold) break; } for (unit = Config.units ; unit; unit = unit->next) { if (strcmp(unit->uuid, param) == 0) { while (1) { rlen = srv_recv(ibuf); if (rlen == -1) { run_pause = FALSE; return 1; } if (strlen(ibuf)) { if (strcmp(ibuf, (char *)".") == 0) { srv_send((char *)"219 Accepted Unit record"); run_pause = FALSE; return 0; } kwd = strtok(ibuf, ",\0"); val = strtok(NULL, "\0"); if (kwd) { /* * Accept writable data. The client can sent just one line, * but may also sent everything. Simply ignore things we * don't understand. */ if (val && (strcmp(kwd, (char *)"NAME") == 0)) { if (unit->name) { if (strcmp(unit->name, val)) syslog(LOG_NOTICE, "Fermenter unit %s name `%s' to `%s'", unit->uuid, unit->name, val); free(unit->name); } unit->name = xstrcpy(val); } else if (val && (strcmp(kwd, (char *)"VOLUME") == 0)) { if (sscanf(val, "%f", &fval) == 1) { if (unit->volume != fval) syslog(LOG_NOTICE, "Fermenter unit %s volume %.3f to %.3f", unit->uuid, unit->volume, fval); unit->volume = fval; } } else if (strcmp(kwd, (char *)"AIR_ADDRESS") == 0) { if (val && unit->air_address && (strcmp(val, unit->air_address))) syslog(LOG_NOTICE, "Fermenter unit %s air address `%s' to `%s'", unit->uuid, unit->air_address, val); if (unit->air_address) { device_count(FALSE, unit->air_address); free(unit->air_address); } if (val) { unit->air_address = xstrcpy(val); device_count(TRUE, unit->air_address); } else unit->air_address = NULL; } else if (strcmp(kwd, (char *)"BEER_ADDRESS") == 0) { if (val && unit->beer_address && (strcmp(val, unit->beer_address))) syslog(LOG_NOTICE, "Fermenter unit %s beer address `%s' to `%s'", unit->uuid, unit->beer_address, val); if (unit->beer_address) { device_count(FALSE, unit->beer_address); free(unit->beer_address); } if (val) { unit->beer_address = xstrcpy(val); device_count(TRUE, unit->beer_address); } else unit->beer_address = NULL; } else if (strcmp(kwd, (char *)"HEATER_ADDRESS") == 0) { if (val && unit->heater_address && (strcmp(val, unit->heater_address))) syslog(LOG_NOTICE, "Fermenter unit %s heater address `%s' to `%s'", unit->uuid, unit->heater_address, val); if (unit->heater_address) { device_count(FALSE, unit->heater_address); free(unit->heater_address); } if (val) { unit->heater_address = xstrcpy(val); device_count(TRUE, unit->heater_address); } else unit->heater_address = NULL; } else if (val && (strcmp(kwd, (char *)"HEATER_STATE") == 0)) { if ((sscanf(val, "%d", &ival) == 1) && ((ival == 0) || (ival == 100))) { if (unit->heater_state != ival) syslog(LOG_NOTICE, "Fermenter unit %s heater state %d to %d", unit->uuid, unit->heater_state, ival); unit->heater_state = ival; } } else if (val && (strcmp(kwd, (char *)"HEATER_DELAY") == 0)) { if (sscanf(val, "%d", &ival) == 1) { if (unit->heater_delay != ival) syslog(LOG_NOTICE, "Fermenter unit %s heater delay %d to %d", unit->uuid, unit->heater_delay, ival); unit->heater_delay = ival; } } else if (strcmp(kwd, (char *)"COOLER_ADDRESS") == 0) { if (val && unit->cooler_address && (strcmp(val, unit->cooler_address))) syslog(LOG_NOTICE, "Fermenter unit %s cooler address `%s' to `%s'", unit->uuid, unit->cooler_address, val); if (unit->cooler_address) { device_count(FALSE, unit->cooler_address); free(unit->cooler_address); } if (val) { unit->cooler_address = xstrcpy(val); device_count(TRUE, unit->cooler_address); } else unit->cooler_address = NULL; } else if (val && (strcmp(kwd, (char *)"COOLER_STATE") == 0)) { if ((sscanf(val, "%d", &ival) == 1) && ((ival == 0) || (ival == 100))) { if (unit->cooler_state != ival) syslog(LOG_NOTICE, "Fermenter unit %s cooler state %d to %d", unit->uuid, unit->cooler_state, ival); unit->cooler_state = ival; } } else if (val && (strcmp(kwd, (char *)"COOLER_DELAY") == 0)) { if (sscanf(val, "%d", &ival) == 1) { if (unit->cooler_delay != ival) syslog(LOG_NOTICE, "Fermenter unit %s cooler delay %d to %d", unit->uuid, unit->cooler_delay, ival); unit->cooler_delay = ival; } } else if (strcmp(kwd, (char *)"FAN_ADDRESS") == 0) { if (val && unit->fan_address && (strcmp(val, unit->fan_address))) syslog(LOG_NOTICE, "Fermenter unit %s fan address `%s' to `%s'", unit->uuid, unit->fan_address, val); if (unit->fan_address) { device_count(FALSE, unit->fan_address); free(unit->fan_address); } if (val) { unit->fan_address = xstrcpy(val); device_count(TRUE, unit->fan_address); } else unit->fan_address = NULL; } else if (val && (strcmp(kwd, (char *)"FAN_STATE") == 0)) { if ((sscanf(val, "%d", &ival) == 1) && ((ival == 0) || (ival == 100))) { if (unit->fan_state != ival) syslog(LOG_NOTICE, "Fermenter unit %s fan state %d to %d", unit->uuid, unit->fan_state, ival); unit->fan_state = ival; } } else if (val && (strcmp(kwd, (char *)"FAN_DELAY") == 0)) { if (sscanf(val, "%d", &ival) == 1) { if (unit->fan_delay != ival) syslog(LOG_NOTICE, "Fermenter unit %s fan delay %d to %d", unit->uuid, unit->fan_delay, ival); unit->fan_delay = ival; } } else if (strcmp(kwd, (char *)"LIGHT_ADDRESS") == 0) { if (val && unit->light_address && (strcmp(val, unit->light_address))) syslog(LOG_NOTICE, "Fermenter unit %s light address `%s' to `%s'", unit->uuid, unit->light_address, val); if (unit->light_address) { device_count(FALSE, unit->light_address); free(unit->light_address); } if (val) { unit->light_address = xstrcpy(val); device_count(TRUE, unit->light_address); } else unit->light_address = NULL; } else if (val && (strcmp(kwd, (char *)"LIGHT_STATE") == 0)) { if ((sscanf(val, "%d", &ival) == 1) && ((ival == 0) || (ival == 100))) { if (unit->light_state != ival) syslog(LOG_NOTICE, "Fermenter unit %s light state %d to %d", unit->uuid, unit->light_state, ival); unit->light_state = ival; } } else if (val && (strcmp(kwd, (char *)"LIGHT_DELAY") == 0)) { if (sscanf(val, "%d", &ival) == 1) { if (unit->light_delay != ival) syslog(LOG_NOTICE, "Fermenter unit %s light delay %d to %d", unit->uuid, unit->light_delay, ival); unit->light_delay = ival; } } else if (strcmp(kwd, (char *)"DOOR_ADDRESS") == 0) { if (val && unit->door_address && (strcmp(val, unit->door_address))) syslog(LOG_NOTICE, "Fermenter unit %s door address `%s' to `%s'", unit->uuid, unit->door_address, val); if (unit->door_address) { device_count(FALSE, unit->door_address); free(unit->door_address); } if (val) { unit->door_address = xstrcpy(val); device_count(TRUE, unit->door_address); } else unit->door_address = NULL; } else if (strcmp(kwd, (char *)"PSU_ADDRESS") == 0) { if (val && unit->psu_address && (strcmp(val, unit->psu_address))) syslog(LOG_NOTICE, "Fermenter unit %s psu address `%s' to `%s'", unit->uuid, unit->psu_address, val); if (unit->psu_address) { device_count(FALSE, unit->psu_address); free(unit->psu_address); } if (val) { unit->psu_address = xstrcpy(val); device_count(TRUE, unit->psu_address); } else unit->psu_address = NULL; } else if (val && (strcmp(kwd, (char *)"MODE") == 0)) { for (i = 0; i < 5; i++) { if (strcmp(val, UNITMODE[i]) == 0) { /* Initialize log if the unit is turned on */ if ((unit->mode == UNITMODE_OFF) && (i != UNITMODE_OFF)) initlog(unit->name); syslog(LOG_NOTICE, "Fermenter unit %s mode %s to %s", unit->uuid, UNITMODE[unit->mode], UNITMODE[i]); unit->mode = i; /* Allways turn everything off after a mode change */ unit->PID_cool->OutP = unit->PID_heat->OutP = 0.0; unit->PID_cool->Mode = unit->PID_heat->Mode = PID_MODE_NONE; unit->heater_state = unit->cooler_state = unit->fan_state = unit->light_state = 0; unit->heater_wait = unit->cooler_wait = unit->fan_wait = unit->light_wait = 0; device_out(unit->heater_address, unit->heater_state); device_out(unit->cooler_address, unit->cooler_state); device_out(unit->fan_address, unit->fan_state); device_out(unit->light_address, unit->light_state); if (unit->mode == UNITMODE_PROFILE) { /* * Set a sane default until it will be overruled by the * main processing loop. */ unit->prof_target = 20.0; } break; } } } else if (val && (strcmp(kwd, (char *)"FRIDGE_SET") == 0)) { if ((sscanf(val, "%f", &fval) == 1) && (fval >= unit->temp_set_min) && (fval <= unit->temp_set_max)) { if (unit->fridge_set != fval) syslog(LOG_NOTICE, "Fermenter unit %s fridge temperature %.1f to %.1f", unit->uuid, unit->fridge_set, fval); unit->fridge_set = fval; } } else if (val && (strcmp(kwd, (char *)"BEER_SET") == 0)) { if ((sscanf(val, "%f", &fval) == 1) && (fval >= unit->temp_set_min) && (fval <= unit->temp_set_max)) { if (unit->beer_set != fval) syslog(LOG_NOTICE, "Fermenter unit %s beer temperature %.1f to %.1f", unit->uuid, unit->beer_set, fval); unit->beer_set = fval; } } else if (val && (strcmp(kwd, (char *)"PIDC_IMAX") == 0)) { if ((sscanf(val, "%f", &fval) == 1) && (fval >= 0.0)) { if (unit->PID_cool->iMax != fval) syslog(LOG_NOTICE, "Fermenter unit %s PID_cool iGain %.1f to %.1f", unit->uuid, unit->PID_cool->iMax, fval); unit->PID_cool->iMax = fval; } } else if (val && (strcmp(kwd, (char *)"PIDC_PGAIN") == 0)) { if ((sscanf(val, "%f", &fval) == 1) && (fval >= 0.0)) { if (unit->PID_cool->pGain != fval) syslog(LOG_NOTICE, "Fermenter unit %s PID_cool pGain %.2f to %.2f", unit->uuid, unit->PID_cool->pGain, fval); unit->PID_cool->pGain = fval; } } else if (val && (strcmp(kwd, (char *)"PIDC_DGAIN") == 0)) { if ((sscanf(val, "%f", &fval) == 1) && (fval >= 0.0)) { if (unit->PID_cool->dGain != fval) syslog(LOG_NOTICE, "Fermenter unit %s PID_cool dGain %.2f to %.2f", unit->uuid, unit->PID_cool->dGain, fval); unit->PID_cool->dGain = fval; } } else if (val && (strcmp(kwd, (char *)"PIDC_IGAIN") == 0)) { if ((sscanf(val, "%f", &fval) == 1) && (fval >= 0.0)) { if (unit->PID_cool->iGain != fval) syslog(LOG_NOTICE, "Fermenter unit %s PID_cool iGain %.2f to %.2f", unit->uuid, unit->PID_cool->iGain, fval); unit->PID_cool->iGain = fval; } } else if (val && (strcmp(kwd, (char *)"PIDC_IDLERANGE") == 0)) { if ((sscanf(val, "%f", &fval) == 1) && (fval >= 0.0)) { if (unit->PID_cool->idleRange != fval) syslog(LOG_NOTICE, "Fermenter unit %s PID_cool idleRange %.2f to %.2f", unit->uuid, unit->PID_cool->idleRange, fval); unit->PID_cool->idleRange = fval; } } else if (val && (strcmp(kwd, (char *)"PIDH_IMAX") == 0)) { if ((sscanf(val, "%f", &fval) == 1) && (fval >= 0.0)) { if (unit->PID_heat->iMax != fval) syslog(LOG_NOTICE, "Fermenter unit %s PID_heat iGain %.1f to %.1f", unit->uuid, unit->PID_heat->iMax, fval); unit->PID_heat->iMax = fval; } } else if (val && (strcmp(kwd, (char *)"PIDH_PGAIN") == 0)) { if ((sscanf(val, "%f", &fval) == 1) && (fval >= 0.0)) { if (unit->PID_heat->pGain != fval) syslog(LOG_NOTICE, "Fermenter unit %s PID_heat pGain %.2f to %.2f", unit->uuid, unit->PID_heat->pGain, fval); unit->PID_heat->pGain = fval; } } else if (val && (strcmp(kwd, (char *)"PIDH_DGAIN") == 0)) { if ((sscanf(val, "%f", &fval) == 1) && (fval >= 0.0)) { if (unit->PID_heat->dGain != fval) syslog(LOG_NOTICE, "Fermenter unit %s PID_heat dGain %.2f to %.2f", unit->uuid, unit->PID_heat->dGain, fval); unit->PID_heat->dGain = fval; } } else if (val && (strcmp(kwd, (char *)"PIDH_IGAIN") == 0)) { if ((sscanf(val, "%f", &fval) == 1) && (fval >= 0.0)) { if (unit->PID_heat->iGain != fval) syslog(LOG_NOTICE, "Fermenter unit %s PIH_heat iGain %.2f to %.2f", unit->uuid, unit->PID_heat->iGain, fval); unit->PID_heat->iGain = fval; } } else if (val && (strcmp(kwd, (char *)"PIDH_IDLERANGE") == 0)) { if ((sscanf(val, "%f", &fval) == 1) && (fval >= 0.0)) { if (unit->PID_heat->idleRange != fval) syslog(LOG_NOTICE, "Fermenter unit %s PID_heat idleRange %.2f to %.2f", unit->uuid, unit->PID_heat->idleRange, fval); unit->PID_heat->idleRange = fval; } } else if (strcmp(kwd, (char *)"PROFILE") == 0) { if (unit->prof_state == PROFILE_OFF) { /* * Only change profile if it is not active, else drop this one. */ if (unit->profile && val && strcmp(unit->profile, val)) syslog(LOG_NOTICE, "Fermenter unit %s profile name `%s' to `%s'", unit->uuid, unit->profile, val); if (unit->profile) free(unit->profile); if (val) unit->profile = xstrcpy(val); else unit->profile = NULL; /* * Reset all output devices */ unit->PID_cool->OutP = unit->PID_heat->OutP = 0.0; unit->PID_cool->Mode = unit->PID_heat->Mode = PID_MODE_NONE; unit->heater_state = unit->cooler_state = unit->fan_state = unit->light_state = 0; unit->heater_wait = unit->cooler_wait = unit->fan_wait = unit->light_wait = 0; device_out(unit->heater_address, unit->heater_state); device_out(unit->cooler_address, unit->cooler_state); device_out(unit->fan_address, unit->fan_state); device_out(unit->light_address, unit->light_state); } } else if (val && (strcmp(kwd, (char *)"PROF_STATE") == 0)) { for (i = 0; i < 5; i++) { if (strcmp(val, PROFSTATE[i]) == 0) { switch (i) { case PROFILE_OFF: if (unit->prof_state == PROFILE_DONE) { unit->prof_state = PROFILE_OFF; syslog(LOG_NOTICE, "Fermenter unit %s profile to OFF", unit->uuid); } break; case PROFILE_PAUSE: if (unit->prof_state == PROFILE_RUN) { unit->prof_state = PROFILE_PAUSE; syslog(LOG_NOTICE, "Fermenter unit %s profile PAUSE", unit->uuid); } else if (unit->prof_state == PROFILE_PAUSE) { unit->prof_state = PROFILE_RUN; syslog(LOG_NOTICE, "Fermenter unit %s profile RESUME", unit->uuid); } break; case PROFILE_RUN: if (unit->prof_state == PROFILE_OFF) { unit->prof_state = PROFILE_RUN; unit->prof_started = time(NULL); unit->prof_paused = unit->prof_primary_done = 0; unit->prof_peak_abs = unit->prof_peak_rel = 0.0; syslog(LOG_NOTICE, "Fermenter unit %s profile to RUN", unit->uuid); } break; case PROFILE_DONE: break; /* Command is illegal */ case PROFILE_ABORT: if ((unit->prof_state == PROFILE_RUN) || (unit->prof_state == PROFILE_PAUSE)) { unit->prof_state = PROFILE_OFF; unit->prof_started = 0; syslog(LOG_NOTICE, "Fermenter unit %s profile ABORT", unit->uuid); } break; } break; } } } else if (val && (strcmp(kwd, (char *)"TEMP_SET_MIN") == 0)) { if (sscanf(val, "%f", &fval) == 1) { if (unit->temp_set_min != fval) syslog(LOG_NOTICE, "Fermenter unit %s temperature set minimum %.1f to %.1f", unit->uuid, unit->temp_set_min, fval); unit->temp_set_min = fval; } } else if (val && (strcmp(kwd, (char *)"TEMP_SET_MAX") == 0)) { if (sscanf(val, "%f", &fval) == 1) { if (unit->temp_set_max != fval) syslog(LOG_NOTICE, "Fermenter unit %s temperature set maximum %.1f to %.1f", unit->uuid, unit->temp_set_max, fval); unit->temp_set_max = fval; } } } } } } } srv_send((char *)"440 No such unit"); run_pause = FALSE; return 1; } srv_send((char *)"504 Subcommand error"); return 1; } void cmd_server(void) { char buf[SS_BUFSIZE]; int rlen; rlen = srv_recv(buf); if (rlen != -1) { if (strlen(buf)) { /* * Process commands from the client */ if (strncmp(buf, "ARCHIVE", 7) == 0) { cmd_archive(buf); } else if (strncmp(buf, "DEVICE", 6) == 0) { if (cmd_device(buf) == 0) wrconfig(); } else if (strncmp(buf, "GLOBAL", 6) == 0) { if (cmd_global(buf) == 0) wrconfig(); } else if (strncmp(buf, "HELP", 4) == 0) { srv_send((char *)"100 Help text follows"); srv_send((char *)"Recognized commands:"); srv_send((char *)""); // 12345678901234567890123456789012345678901234567890123456789012345678901234567890 srv_send((char *)"ARCHIVE <CMD> [parameters] Archive commands"); srv_send((char *)"ARCHIVE HELP Archive help screen"); srv_send((char *)"DEVICE ADD type Add new Device type"); srv_send((char *)"DEVICE DEL uuid Delete Device by uuid"); srv_send((char *)"DEVICE LIST List Devices"); srv_send((char *)"DEVICE GET uuid Get Device record by uuid"); srv_send((char *)"DEVICE PUT uuid Put Device record by uuid"); srv_send((char *)"GLOBAL GET Get global settings"); srv_send((char *)"GLOBAL PUT Put global settings"); srv_send((char *)"LIST List all fermenter units"); srv_send((char *)"LIST LOG uuid List logfile data graphsteps"); srv_send((char *)"PING Check if server is alive"); srv_send((char *)"PROFILE uuid,name Profile rename"); srv_send((char *)"PROFILE ADD name Add new Profile with name"); srv_send((char *)"PROFILE DEL uuid Delete Profile by uuid"); srv_send((char *)"PROFILE LIST List available profiles"); srv_send((char *)"PROFILE GET uuid Get Profile record by uuid"); srv_send((char *)"PROFILE PUT uuid Put Profile record by uuid"); srv_send((char *)"PROFILE GETS uuid Profile get steps list"); srv_send((char *)"PROFILE PUTS uuid Profile put steps list"); #ifdef USE_SIMULATOR srv_send((char *)"SIMULATOR ADD name Add a new Simulator with name"); srv_send((char *)"SIMULATOR DEL uuid Delete Simulator by uuid"); srv_send((char *)"SIMULATOR LIST List all Simulators"); srv_send((char *)"SIMULATOR GET uuid Get Simulator record by uuid"); srv_send((char *)"SIMULATOR PUT uuid Put Simulator record by uuid"); #endif srv_send((char *)"UNIT ADD name Add a new Unit with name"); srv_send((char *)"UNIT DEL uuid Delete Unit by uuid"); srv_send((char *)"UNIT LIST List all Units"); srv_send((char *)"UNIT GET uuid Get Unit record by uuid"); srv_send((char *)"UNIT PUT uuid Put Unit record by uuid"); srv_send((char *)"."); } else if (strncmp(buf, "LIST", 4) == 0) { cmd_list(buf); } else if (strncmp(buf, "PING", 4) == 0) { srv_send((char *)"101 PONG"); } else if (strncmp(buf, "PROFILE", 7) == 0) { if (cmd_profile(buf) == 0) wrconfig(); #ifdef USE_SIMULATOR } else if (strncmp(buf, "SIMULATOR", 9) == 0) { if (cmd_simulator(buf) == 0) wrconfig(); #endif } else if (strncmp(buf, "UNIT", 4) == 0) { if (cmd_unit(buf) == 0) wrconfig(); } else { srv_send((char *)"500 Unknown command"); } } } close(s); } #ifdef HAVE_WIRINGPI_H PI_THREAD (my_server_loop) #else void *my_server_loop(void *threadid) #endif { socklen_t addrlen; int optval = 1; syslog(LOG_NOTICE, "Thread my_server_loop started"); if (debug) fprintf(stdout, "Thread my_server_loop started\n"); memset((char *)&myaddr_in, 0, sizeof(struct sockaddr_in)); memset((char *)&peeraddr_in, 0, sizeof(struct sockaddr_in)); myaddr_in.sin_family = AF_INET; myaddr_in.sin_addr.s_addr = INADDR_ANY; myaddr_in.sin_port = htons(Config.my_port); ls = socket(AF_INET, SOCK_STREAM, 0); if (ls == -1) { syslog(LOG_NOTICE, "Can't create listen socket: %s", strerror(errno)); fprintf(stderr, "Can't create listen socket: %s\n", strerror(errno)); return 0; } if (setsockopt(ls, SOL_SOCKET, SO_KEEPALIVE, &optval, sizeof(optval)) == -1) { syslog(LOG_NOTICE, "Can't setsockopt SO_KEEPALIVE socket: %s", strerror(errno)); close(ls); return 0; } if (setsockopt(ls, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)) == -1) { syslog(LOG_NOTICE, "Can't setsockopt SO_REUSEADDR socket: %s", strerror(errno)); close(ls); return 0; } if (bind(ls, (struct sockaddr *)&myaddr_in, sizeof(struct sockaddr_in)) == -1) { syslog(LOG_NOTICE, "Can't bind to listen socket: %s", strerror(errno)); close(ls); return 0; } if (listen(ls, 5) == -1) { syslog(LOG_NOTICE, "Can't listen on listen socket: %s", strerror(errno)); close(ls); return 0; } syslog(LOG_NOTICE, "listen socket created %d", ls); /* * Loop forever until the external shutdown variable is set. */ for (;;) { addrlen = sizeof(struct sockaddr_in); /* * This call will block until a new connection * arrives. Then it will return the address of * the connecting peer, and a new socket * descriptor, s, for that connection. */ s = accept(ls, (struct sockaddr *)&peeraddr_in, &addrlen); if (s == -1) { syslog(LOG_NOTICE, "my_server_loop accept failed %s", strerror(errno)); if (debug) fprintf(stdout, "my_server_loop accept failed %s\n", strerror(errno)); return 0; } cmd_server(); if (my_shutdown) { syslog(LOG_NOTICE, "Thread my_server_loop stopped"); if (debug) fprintf(stdout, "Thread my_server_loop stopped\n"); return 0; } } }