Thu, 25 Apr 2024 14:26:47 +0200
Version 0.9.19a6. Fixes after a short trial on the production controller. Fixed json for alternate beer termperature sensor. Fixed division by 1000 for the room temperature and humidity values. The dropdown list for devices shows the address instead of description in the list.
/***************************************************************************** * Copyright (C) 2008-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 "delay.h" #include "one-wire.h" #include "devices.h" #include "server.h" #include "lcd-buffer.h" #include "xutil.h" #include "mqtt.h" extern int debug; extern int run_pause; extern int run_hold; extern sys_config Config; extern w1_list *w1_devices; extern const char UNITMODE[5][8]; extern const char UNITSTAGE[4][12]; extern const char DEVTYPE[8][6]; extern const char DEVPRESENT[4][6]; extern const char DEVDIR[7][11]; extern const char PROFSTATE[5][6]; extern pthread_mutex_t mutexes[5]; int my_server_state = 0; /* Thread running state */ int my_server_shutdown = 0; /* Thread shutdown */ 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 4096 #define SS_TIMEOUT 300 #define MAX_INTERVALS 10 const int GRAPH_INTERVAL[MAX_INTERVALS] = { 0, 1, 5, 15, 30, 60, 120, 240, 480, 960 }; const int GRAPH_DATALINES[MAX_INTERVALS] = { 0, 800, 3200, 12000, 24000, 48000, 96000, 192000, 384000, 768000 }; 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(int s, 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); // } 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; } /* * Send unlimited size message */ int large_send(int s, char *out) { if (s == -1) return -1; if (send(s, out, strlen(out), 0) != strlen(out)) { syslog(LOG_NOTICE, "large_send failed"); return -1; } if (send(s, (char *)"\r\n", 2, 0) != 2) { syslog(LOG_NOTICE, "large_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(int s, 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 < 0) { syslog(LOG_NOTICE, "recvfrom(): %s", strerror(errno)); return -1; /* error */ } else if (ret == 0) { return -1; /* no data */ } if (buf == '\n') break; if (buf != '\r') { buffer[bytesloaded] = buf; bytesloaded++; } } // if (debug) { // syslog(LOG_NOTICE, "recv: %d `%s'", 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) { pthread_mutex_lock(&mutexes[LOCK_DEVICES]); if (plus == TRUE) { device->inuse++; } else { if (device->inuse) device->inuse--; } pthread_mutex_unlock(&mutexes[LOCK_DEVICES]); } } } 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, 255); (*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); } 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 JSON * DEVICE GET uuid * DEVICE PUT uuid * DEVICE JSON uuid */ int cmd_device(int s, 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(s, (char *)"501 Subcommand missing"); return 0; } param = strtok(NULL, "\0"); if (strcmp(opt, (char *)"HELP") == 0) { srv_send(s, (char *)"100 Help text follows:"); srv_send(s, (char *)"Recognized commands:"); srv_send(s, (char *)"DEVICE ADD type Add device (RC433/DHT/I2C/SPI)"); srv_send(s, (char *)"DEVICE DEL uuid Delete device by uuid"); srv_send(s, (char *)"DEVICE LIST List all devices"); srv_send(s, (char *)"DEVICE GET uuid Read device by uuid parameters"); srv_send(s, (char *)"DEVICE PUT uuid Write device by uuid parameters"); srv_send(s, (char *)"DEVICE JSON <uuid> Json list all or a single device"); srv_send(s, (char *)"."); return 0; } if (strcmp(opt, (char *)"LIST") == 0) { srv_send(s, (char *)"212 Devices list follows:"); for (device = Config.devices; device; device = device->next) { srv_send(s, (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(s, (char *)"."); return 0; } if (strcmp(opt, (char *)"JSON") == 0) { char *payload = NULL, *payloadu = NULL, vbuf[64]; bool comma = false; if (param == NULL) { srv_send(s, (char *)"212 Devices json list follows:"); payload = xstrcpy((char *)"["); for (device = Config.devices; device; device = device->next) { if (comma) payload = xstrcat(payload, (char *)","); payloadu = device_json(device); payload = xstrcat(payload, payloadu); comma = true; free(payloadu); payloadu = NULL; } payload = xstrcat(payload, (char *)"]"); large_send(s, payload); srv_send(s, (char *)"."); free(payload); payload = NULL; return 0; } else { for (device = Config.devices; device; device = device->next) { if (strcmp(device->uuid, param) == 0) { payload = xstrcpy((char *)"{\"type\":\"device\",\"unit\":\""); snprintf(vbuf, 63, "%d", device->subdevice); payload = xstrcat(payload, device->address); payload = xstrcat(payload, (char *)"-"); payload = xstrcat(payload, vbuf); payload = xstrcat(payload, (char *)"\",\"metric\":"); payloadu = device_json(device); payload = xstrcat(payload, payloadu); free(payloadu); payloadu = NULL; payload = xstrcat(payload, (char *)"}"); srv_send(s, (char *)"213 Device json record follows:"); large_send(s, payload); free(payload); payload = NULL; srv_send(s, (char *)"."); return 0; } } srv_send(s, (char *)"{}"); srv_send(s, (char *)"440 No such device"); return 0; } } if (param == NULL) { srv_send(s, (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->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"); device->timestamp = time(NULL); pthread_mutex_lock(&mutexes[LOCK_DEVICES]); if (Config.devices == NULL) { Config.devices = device; } else { for (tmpd = Config.devices; tmpd; tmpd = tmpd->next) { if (tmpd->next == NULL) { tmpd->next = device; break; } } } pthread_mutex_unlock(&mutexes[LOCK_DEVICES]); syslog(LOG_NOTICE, "Device %s added", device->uuid); srv_send(s, (char *)"211 Device %s added", device->uuid); return 1; } else { srv_send(s, (char *)"503 Parameter error"); return 0; } } if (strcmp(opt, (char *)"DEL") == 0) { pthread_mutex_lock(&mutexes[LOCK_DEVICES]); rc = delete_Device(param); pthread_mutex_unlock(&mutexes[LOCK_DEVICES]); if (rc) { syslog(LOG_NOTICE, "Device %s deleted", param); srv_send(s, (char *)"211 Device %s deleted", param); return 1; } else { srv_send(s, (char *)"440 No such device"); return 0; } } if (strcmp(opt, (char *)"GET") == 0) { for (device = Config.devices; device; device = device->next) { if (strcmp(device->uuid, param) == 0) { pthread_mutex_lock(&mutexes[LOCK_DEVICES]); int my_value = device->value; int my_timestamp = (int)device->timestamp; pthread_mutex_unlock(&mutexes[LOCK_DEVICES]); srv_send(s, (char *)"213 Device record follows:"); srv_send(s, (char *)"TYPE,%s", DEVTYPE[device->type]); srv_send(s, (char *)"ADDRESS,%s", device->address); srv_send(s, (char *)"DIRECTION,%s", DEVDIR[device->direction]); srv_send(s, (char *)"VALUE,%d", my_value); srv_send(s, (char *)"OFFSET,%d", device->offset); srv_send(s, (char *)"PRESENT,%s", DEVPRESENT[device->present]); srv_send(s, (char *)"SUBDEVICE,%d", device->subdevice); srv_send(s, (char *)"GPIOPIN,%d", device->gpiopin); srv_send(s, (char *)"DESCRIPTION,%s", device->description); srv_send(s, (char *)"INUSE,%d", device->inuse); srv_send(s, (char *)"COMMENT,%s", device->comment); srv_send(s, (char *)"TIMESTAMP,%d", my_timestamp); srv_send(s, (char *)"."); return 0; } } srv_send(s, (char *)"440 No such device"); return 0; } 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(s, ibuf); if (rlen == -1) { return 0; } if (strlen(ibuf)) { if (strcmp(ibuf, (char *)".") == 0) { srv_send(s, (char *)"219 Accepted Device record"); return 1; } 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) { pthread_mutex_lock(&mutexes[LOCK_DEVICES]); if (device->type != i) syslog(LOG_NOTICE, "Device %s changed type %s to %s", device->uuid, DEVTYPE[device->type], DEVTYPE[i]); device->type = i; pthread_mutex_unlock(&mutexes[LOCK_DEVICES]); break; } } } else if (strcmp(kwd, (char *)"DIRECTION") == 0) { for (i = 0; i < 7; i++) { if (strcmp(val, DEVDIR[i]) == 0) { pthread_mutex_lock(&mutexes[LOCK_DEVICES]); if (device->direction != i) syslog(LOG_NOTICE, "Device %s changed direction %s to %s", device->uuid, DEVDIR[device->type], DEVDIR[i]); device->direction = i; pthread_mutex_unlock(&mutexes[LOCK_DEVICES]); break; } } } else if (strcmp(kwd, (char *)"VALUE") == 0) { if (sscanf(val, "%d", &ival) == 1) { pthread_mutex_lock(&mutexes[LOCK_DEVICES]); if (device->value != ival) syslog(LOG_NOTICE, "Device %s changed value %d to %d", device->uuid, device->value, ival); device->value = ival; pthread_mutex_unlock(&mutexes[LOCK_DEVICES]); } } else if (strcmp(kwd, (char *)"OFFSET") == 0) { if (sscanf(val, "%d", &ival) == 1) { pthread_mutex_lock(&mutexes[LOCK_DEVICES]); if (device->offset != ival) syslog(LOG_NOTICE, "Device %s changed offset %d to %d", device->uuid, device->offset, ival); device->offset = ival; pthread_mutex_unlock(&mutexes[LOCK_DEVICES]); } } else if (strcmp(kwd, (char *)"PRESENT") == 0) { for (i = 0; i < 4; i++) { if (strcmp(val, DEVPRESENT[i]) == 0) { pthread_mutex_lock(&mutexes[LOCK_DEVICES]); if (device->present != i) syslog(LOG_NOTICE, "Device %s changed present %s to %s", device->uuid, DEVPRESENT[device->present], DEVPRESENT[i]); device->present = i; pthread_mutex_unlock(&mutexes[LOCK_DEVICES]); break; } } } else if (strcmp(kwd, (char *)"ADDRESS") == 0) { pthread_mutex_lock(&mutexes[LOCK_DEVICES]); 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); pthread_mutex_unlock(&mutexes[LOCK_DEVICES]); } else if (strcmp(kwd, (char *)"SUBDEVICE") == 0) { if (sscanf(val, "%d", &ival) == 1) { pthread_mutex_lock(&mutexes[LOCK_DEVICES]); if (device->subdevice != ival) syslog(LOG_NOTICE, "Device %s changed subdevice %d to %d", device->uuid, device->subdevice, ival); device->subdevice = ival; pthread_mutex_unlock(&mutexes[LOCK_DEVICES]); } } else if (strcmp(kwd, (char *)"GPIOPIN") == 0) { if (sscanf(val, "%d", &ival) == 1) { pthread_mutex_lock(&mutexes[LOCK_DEVICES]); if (device->gpiopin != ival) syslog(LOG_NOTICE, "Device %s changed gpiopin %d to %d", device->uuid, device->gpiopin, ival); device->gpiopin = ival; pthread_mutex_unlock(&mutexes[LOCK_DEVICES]); } } else if (strcmp(kwd, (char *)"DESCRIPTION") == 0) { pthread_mutex_lock(&mutexes[LOCK_DEVICES]); 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); pthread_mutex_unlock(&mutexes[LOCK_DEVICES]); } else if (strcmp(kwd, (char *)"COMMENT") == 0) { pthread_mutex_lock(&mutexes[LOCK_DEVICES]); 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); pthread_mutex_unlock(&mutexes[LOCK_DEVICES]); } } } } } } srv_send(s, (char *)"440 No such device"); return 0; } srv_send(s, (char *)"504 Subcommand error"); return 0; } /* * ONEWIRE JSON */ int cmd_onewire(int s, char *buf) { char *opt, *param; w1_list *dev_w1; opt = strtok(buf, " \0"); opt = strtok(NULL, " \0"); if (opt == NULL) { srv_send(s, (char *)"501 Subcommand missing"); return 0; } param = strtok(NULL, "\0"); if (strcmp(opt, (char *)"HELP") == 0) { srv_send(s, (char *)"100 Help text follows:"); srv_send(s, (char *)"Recognized commands:"); srv_send(s, (char *)"ONEWIRE JSON Json list all or a single one-wire device"); srv_send(s, (char *)"."); return 0; } if (strcmp(opt, (char *)"JSON") == 0) { char *payload = NULL, *payloadu = NULL; bool comma = false; if (param == NULL) { srv_send(s, (char *)"212 One-wire json list follows:"); payload = xstrcpy((char *)"["); for (dev_w1 = w1_devices; dev_w1; dev_w1 = dev_w1->next) { if (comma) payload = xstrcat(payload, (char *)","); payloadu = one_wire_json(dev_w1); payload = xstrcat(payload, payloadu); comma = true; free(payloadu); payloadu = NULL; } payload = xstrcat(payload, (char *)"]"); large_send(s, payload); srv_send(s, (char *)"."); free(payload); payload = NULL; return 0; } } srv_send(s, (char *)"504 Subcommand error"); return 0; } /* * GLOBAL GET * GLOBAL PUT * GLOBAL JSON */ int cmd_global(int s, 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(s, (char *)"501 Subcommand missing"); return 0; } if (strcmp(opt, (char *)"HELP") == 0) { srv_send(s, (char *)"100 Help text follows:"); srv_send(s, (char *)"Recognized commands:"); srv_send(s, (char *)"GLOBAL GET Get global settings"); srv_send(s, (char *)"GLOBAL PUT Put global settings"); srv_send(s, (char *)"GLOBAL JSON Get global json settings"); srv_send(s, (char *)"."); return 0; } if (strcmp(opt, (char *)"GET") == 0) { srv_send(s, (char *)"213 Global Settings record follows:"); srv_send(s, (char *)"RELEASE,%s", VERSION); srv_send(s, (char *)"NAME,%s", Config.name); srv_send(s, (char *)"UUID,%s", Config.uuid); srv_send(s, (char *)"PORT,%d", Config.server_port); srv_send(s, (char *)"TEMP_UUID,%s", Config.temp_uuid); srv_send(s, (char *)"TEMP_STATE,%s", DEVPRESENT[Config.temp_state]); srv_send(s, (char *)"TEMP_VALUE,%.1f", Config.temp_value / 1000.0); srv_send(s, (char *)"HUM_UUID,%s", Config.hum_uuid); srv_send(s, (char *)"HUM_STATE,%s", DEVPRESENT[Config.hum_state]); srv_send(s, (char *)"HUM_VALUE,%.1f", Config.hum_value / 1000.0); srv_send(s, (char *)"TEMP_HUM_IDX,%d", Config.temp_hum_idx); srv_send(s, (char *)"LCD_COLS,%d", Config.lcd_cols); srv_send(s, (char *)"LCD_ROWS,%d", Config.lcd_rows); srv_send(s, (char *)"NEXT_UNIT,%d", Config.next_unit); srv_send(s, (char *)"MQTT_HOST,%s", Config.mqtt_host); srv_send(s, (char *)"MQTT_PORT,%d", Config.mqtt_port); srv_send(s, (char *)"MQTT_USER,%s", Config.mqtt_username); srv_send(s, (char *)"MQTT_PASS,%s", Config.mqtt_password); srv_send(s, (char *)"WEBSOCKET_PORT,%d", Config.websocket_port); srv_send(s, (char *)"."); return 0; } if (strcmp(opt, (char *)"JSON") == 0) { char *payload = NULL; payload = global_json(); srv_send(s, (char *)"213 Global json data follows:"); srv_send(s, payload); srv_send(s, (char *)"."); free(payload); payload = NULL; return 0; } if (strcmp(opt, (char *)"PUT") == 0) { int mqtt_reconnect = 0; while (1) { rlen = srv_recv(s, ibuf); if (rlen == -1) { return 0; } if (strlen(ibuf)) { if (strcmp(ibuf, (char *)".") == 0) { srv_send(s, (char *)"219 Accepted Global record"); if (mqtt_reconnect) mqtt_connect(); return 1; } 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.server_port != ival) syslog(LOG_NOTICE, "Global server port %d to %d", Config.server_port, ival); Config.server_port = ival; } } else if (strcmp(kwd, (char *)"TEMP_UUID") == 0) { if (val && Config.temp_uuid && (strcmp(val, Config.temp_uuid))) syslog(LOG_NOTICE, "Global temperature uuid `%s' to `%s'", Config.temp_uuid, val); if (Config.temp_uuid) { device_count(FALSE, Config.temp_uuid); free(Config.temp_uuid); } if (val) { Config.temp_uuid = xstrcpy(val); device_count(TRUE, Config.temp_uuid); } else Config.temp_uuid = NULL; } else if (strcmp(kwd, (char *)"HUM_UUID") == 0) { if (val && Config.hum_uuid && (strcmp(val, Config.hum_uuid))) syslog(LOG_NOTICE, "Global humidity uuid `%s' to `%s'", Config.hum_uuid, val); if (Config.hum_uuid) { device_count(FALSE, Config.hum_uuid); free(Config.hum_uuid); } if (val) { Config.hum_uuid = xstrcpy(val); device_count(TRUE, Config.hum_uuid); } else Config.hum_uuid = NULL; } else if (val && (strcmp(kwd, (char *)"TEMP_HUM_IDX") == 0)) { if (sscanf(val, "%d", &ival) == 1) { if (Config.temp_hum_idx != ival) syslog(LOG_NOTICE, "Global Temp/Humidity idx %d to %d", Config.temp_hum_idx, ival); Config.temp_hum_idx = ival; } } else if (val && (strcmp(kwd, (char *)"LCD_ADDRESS") == 0)) { if (sscanf(val, "%d", &ival) == 1) { if (Config.lcd_address != ival) syslog(LOG_NOTICE, "Global LCD address %d to %d", Config.lcd_address, ival); Config.lcd_address = ival; } } 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; } } else if (strcmp(kwd, (char *)"MQTT_HOST") == 0) { if (val && Config.mqtt_host && (strcmp(val, Config.mqtt_host))) syslog(LOG_NOTICE, "Global MQTT host `%s' to `%s'", Config.mqtt_host, val); mqtt_disconnect(); mqtt_reconnect = 1; if (Config.mqtt_host) free(Config.mqtt_host); if (val) Config.mqtt_host = xstrcpy(val); else Config.mqtt_host = NULL; } else if (val && (strcmp(kwd, (char *)"MQTT_PORT") == 0)) { if (sscanf(val, "%d", &ival) == 1) { if (Config.mqtt_port != ival) { syslog(LOG_NOTICE, "Global MQTT port %d to %d", Config.mqtt_port, ival); mqtt_disconnect(); mqtt_reconnect = 1; Config.mqtt_port = ival; } } } else if (strcmp(kwd, (char *)"MQTT_USER") == 0) { if (val && Config.mqtt_username && (strcmp(val, Config.mqtt_username))) syslog(LOG_NOTICE, "Global MQTT username `%s' to `%s'", Config.mqtt_username, val); mqtt_disconnect(); mqtt_reconnect = 1; if (Config.mqtt_username) free(Config.mqtt_username); if (val) Config.mqtt_username = xstrcpy(val); else Config.mqtt_username = NULL; } else if (strcmp(kwd, (char *)"MQTT_PASS") == 0) { if (val && Config.mqtt_password && (strcmp(val, Config.mqtt_password))) syslog(LOG_NOTICE, "Global MQTT password `%s' to `%s'", Config.mqtt_password, val); mqtt_disconnect(); mqtt_reconnect = 1; if (Config.mqtt_password) free(Config.mqtt_password); if (val) Config.mqtt_password = xstrcpy(val); else Config.mqtt_password = NULL; } else if (val && (strcmp(kwd, (char *)"WEBSOCKET_PORT") == 0)) { if (sscanf(val, "%d", &ival) == 1) { if (Config.websocket_port != ival) { syslog(LOG_NOTICE, "Global Websocket port %d to %d", Config.websocket_port, ival); Config.websocket_port = ival; } } } } } } } srv_send(s, (char *)"504 Subcommand error"); return 0; } /* * LIST */ int cmd_list(int s, char *buf) { char *opt; units_list *unit; opt = strtok(buf, " \0"); opt = strtok(NULL, " \0"); if (opt == NULL) { /* * Default, list available units */ srv_send(s, (char *)"212 Fermenter list follows:"); for (unit = Config.units; unit; unit = unit->next) { srv_send(s, (char *)"%s,%s,%s", unit->uuid, unit->alias, UNITMODE[unit->mode]); } srv_send(s, (char *)"."); return 0; } else if (strcmp(opt, (char *)"HELP") == 0) { srv_send(s, (char *)"100 Help text follows:"); srv_send(s, (char *)"Recognized commands:"); srv_send(s, (char *)"LIST List available units"); srv_send(s, (char *)"."); return 0; } srv_send(s, (char *)"504 Subcommand error"); return 0; } #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(int s, 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(s, (char *)"501 Subcommand missing"); return 0; } param = strtok(NULL, "\0"); if (strcmp(opt, (char *)"HELP") == 0) { srv_send(s, (char *)"100 Help text follows:"); srv_send(s, (char *)"Recognized commands:"); srv_send(s, (char *)"SIMULATOR ADD name Add a new Simulator with name"); srv_send(s, (char *)"SIMULATOR DEL uuid Delete Simulator by uuid"); srv_send(s, (char *)"SIMULATOR LIST List all Simulators"); srv_send(s, (char *)"SIMULATOR GET uuid Get Simulator record by uuid"); srv_send(s, (char *)"SIMULATOR PUT uuid Put Simulator record by uuid"); srv_send(s, (char *)"."); return 0; } if (strcmp(opt, (char *)"LIST") == 0) { srv_send(s, (char *)"212 Simulators list follows:"); for (simulator = Config.simulators; simulator; simulator = simulator->next) { srv_send(s, (char *)"%s,%s", simulator->uuid, simulator->name); } srv_send(s, (char *)"."); return 0; } if (param == NULL) { srv_send(s, (char *)"502 Parameter missing"); return 0; } if (strcmp(opt, (char *)"ADD") == 0) { /* * For now, only one simulator is allowed. */ if (Config.simulators) { srv_send(s, (char *)"441 Maximum simulators reached"); return 0; } simulator = (simulator_list *)malloc(sizeof(simulator_list)); simulator->next = NULL; 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->room_humidity = 48.6; simulator->chiller_temperature = 1.5; /* Chiller temperature */ simulator->cooler_temp = 1.5; /* 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(s, (char *)"211 Simulator %s added", simulator->uuid); return 1; } if (strcmp(opt, (char *)"DEL") == 0) { rc = delete_Simulator(param); if (rc) { syslog(LOG_NOTICE, "Simulator %s deleted", param); srv_send(s, (char *)"211 Simulator %s deleted", param); return 1; } else { srv_send(s, (char *)"440 No such simulator"); return 0; } } if (strcmp(opt, (char *)"GET") == 0) { for (simulator = Config.simulators; simulator; simulator = simulator->next) { if (strcmp(simulator->uuid, param) == 0) { srv_send(s, (char *)"213 Simulator record follows:"); srv_send(s, (char *)"NAME,%s", simulator->name); srv_send(s, (char *)"VOLUME_AIR,%d", simulator->volume_air); srv_send(s, (char *)"VOLUME_BEER,%d", simulator->volume_beer); srv_send(s, (char *)"ROOM_TEMPERATURE,%.1f", simulator->room_temperature); srv_send(s, (char *)"ROOM_HUMIDITY,%.1f", simulator->room_humidity); srv_send(s, (char *)"AIR_TEMPERATURE,%.3f", simulator->air_temperature); srv_send(s, (char *)"BEER_TEMPERATURE,%.3f", simulator->beer_temperature); srv_send(s, (char *)"CHILLER_TEMPERATURE,%.3f", simulator->chiller_temperature); srv_send(s, (char *)"COOLER_TEMP,%.1f", simulator->cooler_temp); srv_send(s, (char *)"COOLER_TIME,%d", simulator->cooler_time); srv_send(s, (char *)"COOLER_SIZE,%.3f", simulator->cooler_size); srv_send(s, (char *)"HEATER_TEMP,%.1f", simulator->heater_temp); srv_send(s, (char *)"HEATER_TIME,%d", simulator->heater_time); srv_send(s, (char *)"HEATER_SIZE,%.3f", simulator->heater_size); srv_send(s, (char *)"HEATER_STATE,%d", simulator->heater_state); srv_send(s, (char *)"COOLER_STATE,%d", simulator->cooler_state); srv_send(s, (char *)"FRIGO_ISOLATION,%.3f", simulator->frigo_isolation); srv_send(s, (char *)"."); return 0; } } srv_send(s, (char *)"440 No such simulator"); return 0; } 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(s, ibuf); if (rlen == -1) { return 0; } if (strlen(ibuf)) { if (strcmp(ibuf, (char *)".") == 0) { srv_send(s, (char *)"219 Accepted Simulator record"); return 1; } 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 *)"ROOM_HUMIDITY") == 0) { if (sscanf(val, "%f", &fval) == 1) { if (simulator->room_humidity != fval) syslog(LOG_NOTICE, "Simulator %s room hunidity %.1f to %.1f", simulator->uuid, simulator->room_humidity, fval); simulator->room_humidity = 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 *)"CHILLER_TEMPERATURE") == 0) { if (sscanf(val, "%f", &fval) == 1) { if (simulator->chiller_temperature != fval) syslog(LOG_NOTICE, "Simulator %s chiller temperature %.1f to %.1f", simulator->uuid, simulator->chiller_temperature, fval); simulator->chiller_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(s, (char *)"440 No such simulator"); return 0; } srv_send(s, (char *)"504 Subcommand error"); return 0; } #endif int delete_Unit(char *uuid) { units_list *current = Config.units; units_list *previous = NULL; prof_step *step, *olds; while (current) { if (strcmp(current->uuid, uuid) == 0) { if (previous == NULL) { Config.units = current->next; free(current->uuid); current->uuid = NULL; if (current->product_uuid) free(current->product_uuid); current->product_uuid = NULL; if (current->product_code) free(current->product_code); current->product_code = NULL; if (current->product_name) free(current->product_name); current->product_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->beer_address2) free(current->beer_address2); current->beer_address2 = NULL; if (current->chiller_address) free(current->chiller_address); current->chiller_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_uuid) free(current->profile_uuid); current->profile_uuid = NULL; if (current->profile_name) free(current->profile_name); current->profile_name = 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; if (current->profile_steps) { for (step = current->profile_steps; step; step = olds) { olds = step->next; free(step); } current->profile_steps = NULL; } free(current); return 1; } else { free(current->uuid); current->uuid = NULL; if (current->product_uuid) free(current->product_uuid); current->product_uuid = NULL; if (current->product_code) free(current->product_code); current->product_code = NULL; if (current->product_name) free(current->product_name); current->product_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->beer_address2) free(current->beer_address2); current->beer_address2 = NULL; if (current->chiller_address) free(current->chiller_address); current->chiller_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_uuid) free(current->profile_uuid); current->profile_uuid = NULL; if (current->profile_name) free(current->profile_name); current->profile_name = 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; if (current->profile_steps) { for (step = current->profile_steps; step; step = olds) { olds = step->next; free(step); } current->profile_steps = 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(int s, 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(s, (char *)"501 Subcommand missing"); return 0; } param = strtok(NULL, "\0"); if (strcmp(opt, (char *)"HELP") == 0) { srv_send(s, (char *)"100 Help text follows:"); srv_send(s, (char *)"Recognized commands:"); srv_send(s, (char *)"UNIT ADD name Add a new Unit with name"); srv_send(s, (char *)"UNIT DEL uuid Delete Unit by uuid"); srv_send(s, (char *)"UNIT LIST List all Units"); srv_send(s, (char *)"UNIT GET uuid Get Unit record by uuid"); srv_send(s, (char *)"UNIT PUT uuid Put Unit record by uuid"); srv_send(s, (char *)"UNIT JSON uuid Get Unit record in json"); srv_send(s, (char *)"."); return 0; } if ((strcmp(opt, (char *)"LIST") == 0) && (param == NULL)) { srv_send(s, (char *)"212 Fermenter list follows:"); for (unit = Config.units; unit; unit = unit->next) { if (strlen(unit->product_code) && strlen(unit->product_name)) { srv_send(s, (char *)"%s,%s %s,%s", unit->uuid, unit->product_code, unit->product_name, UNITMODE[unit->mode]); } else { srv_send(s, (char *)"%s,%s,%s", unit->uuid, unit->alias, UNITMODE[unit->mode]); } } srv_send(s, (char *)"."); return 0; } if (strcmp(opt, (char *)"JSON") == 0) { char *payload = NULL, *payloadu = NULL; bool comma = false; if (param == NULL) { srv_send(s, (char *)"212 Units json list follows:"); payload = xstrcpy((char *)"["); for (unit = Config.units; unit; unit = unit->next) { if (comma) payload = xstrcat(payload, (char *)","); payloadu = unit_data(unit, true); payload = xstrcat(payload, payloadu); comma = true; free(payloadu); payloadu = NULL; } payload = xstrcat(payload, (char *)"]"); large_send(s, payload); srv_send(s, (char *)"."); free(payload); payload = NULL; return 0; } else { syslog(LOG_NOTICE, "UNIT JSON %s", param); for (unit = Config.units; unit; unit = unit->next) { if (strcmp(param, unit->uuid) == 0) { srv_send(s, (char *)"213 Unit json data follows:"); payload = xstrcpy((char *)"{\"type\":\"fermenter\",\"unit\":\""); payload = xstrcat(payload, unit->alias); payload = xstrcat(payload, (char *)"\",\"metric\":"); payloadu = unit_data(unit, false); payload = xstrcat(payload, payloadu); payload = xstrcat(payload, (char *)"}"); large_send(s, payload); free(payload); free(payloadu); payload = payloadu = NULL; srv_send(s, (char *)"."); return 0; } } srv_send(s, (char *)"440 No such unit"); return 0; } } if (param == NULL) { srv_send(s, (char *)"502 Parameter missing"); return 0; } if (strcmp(opt, (char *)"ADD") == 0) { char an[128]; sprintf(an, "unit%d", Config.next_unit); Config.next_unit++; unit = (units_list *)malloc(sizeof(units_list)); unit->next = NULL; unit->uuid = malloc(37); uuid_generate(uu); uuid_unparse(uu, unit->uuid); unit->product_uuid = NULL; unit->product_code = xstrcpy((char *)"FAKE0000"); unit->product_name = xstrcpy(param); unit->alias = xstrcpy(an); 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->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->prof_peak_abs = unit->prof_peak_rel = 0.0; unit->air_state = unit->beer_state = unit->chiller_state = DEVPRESENT_NO; unit->air_temperature = unit->beer_temperature = unit->chiller_temperature = 20000; 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->heater_state = unit->cooler_state = unit->fan_state = unit->door_state = unit->mode = \ unit->light_state = unit->light_timer = unit->psu_state = unit->prof_state = unit->stage = 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 = 45.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); unit->PID_heat->pGain = unit->PID_cool->pGain = 5000.0; unit->PID_heat->iGain = unit->PID_cool->iGain = 25.0; unit->PID_heat->dGain = unit->PID_cool->dGain = 5.0; /* * Block main process */ run_pause = TRUE; for (;;) { mDelay(100); 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; } } } lcd_buf_reset(); run_pause = FALSE; syslog(LOG_NOTICE, "Unit %s added", unit->uuid); srv_send(s, (char *)"211 Unit %s added", unit->uuid); return 1; } if (strcmp(opt, (char *)"DEL") == 0) { /* * Block main process. */ run_pause = TRUE; for (;;) { mDelay(100); if (run_hold) break; } rc = delete_Unit(param); lcd_buf_reset(); run_pause = FALSE; if (rc) { syslog(LOG_NOTICE, "Unit %s deleted", param); srv_send(s, (char *)"211 Unit %s deleted", param); return 1; } else { srv_send(s, (char *)"440 No such unit"); return 0; } } if (strcmp(opt, (char *)"GET") == 0) { for (unit = Config.units; unit; unit = unit->next) { if (strcmp(param, unit->uuid) == 0) { srv_send(s, (char *)"213 Unit listing follows:"); srv_send(s, (char *)"UUID,%s", unit->uuid); srv_send(s, (char *)"ALIAS,%s", unit->alias); srv_send(s, (char *)"PRODUCT_NAME,%s", unit->product_name); srv_send(s, (char *)"PRODUCT_CODE,%s", unit->product_code); srv_send(s, (char *)"MODE,%s", UNITMODE[unit->mode]); srv_send(s, (char *)"STAGE,%s", UNITSTAGE[unit->stage]); srv_send(s, (char *)"AIR_ADDRESS,%s", unit->air_address); srv_send(s, (char *)"AIR_STATE,%s", DEVPRESENT[unit->air_state]); srv_send(s, (char *)"AIR_TEMPERATURE,%.3f", unit->air_temperature / 1000.0); srv_send(s, (char *)"AIR_IDX,%d", unit->air_idx); srv_send(s, (char *)"BEER_ADDRESS,%s", MBSE_SS(unit->beer_address)); srv_send(s, (char *)"BEER_ADDRESS2,%s", MBSE_SS(unit->beer_address2)); srv_send(s, (char *)"BEER_STATE,%s", DEVPRESENT[unit->beer_state]); srv_send(s, (char *)"BEER_TEMPERATURE,%.3f", unit->beer_temperature / 1000.0); srv_send(s, (char *)"BEER_IDX,%d", unit->beer_idx); srv_send(s, (char *)"CHILLER_ADDRESS,%s", MBSE_SS(unit->chiller_address)); srv_send(s, (char *)"CHILLER_STATE,%s", DEVPRESENT[unit->chiller_state]); srv_send(s, (char *)"CHILLER_TEMPERATURE,%.3f", unit->chiller_temperature / 1000.0); srv_send(s, (char *)"CHILLER_IDX,%d", unit->chiller_idx); srv_send(s, (char *)"HEATER_ADDRESS,%s", unit->heater_address); srv_send(s, (char *)"HEATER_STATE,%d", unit->heater_state); srv_send(s, (char *)"HEATER_DELAY,%d", unit->heater_delay); srv_send(s, (char *)"HEATER_USAGE,%d", unit->heater_usage); srv_send(s, (char *)"HEATER_IDX,%d", unit->heater_idx); if (unit->PID_heat) { srv_send(s, (char *)"PIDH_IMAX,%.1f", unit->PID_heat->iMax); srv_send(s, (char *)"PIDH_IDLERANGE,%.2f", unit->PID_heat->idleRange); srv_send(s, (char *)"PIDH_PGAIN,%.3f", unit->PID_heat->pGain); srv_send(s, (char *)"PIDH_IGAIN,%.3f", unit->PID_heat->iGain); srv_send(s, (char *)"PIDH_DGAIN,%.3f", unit->PID_heat->dGain); srv_send(s, (char *)"PIDH_SV,%.2f", unit->PID_heat->SetP); } srv_send(s, (char *)"COOLER_ADDRESS,%s", unit->cooler_address); srv_send(s, (char *)"COOLER_STATE,%d", unit->cooler_state); srv_send(s, (char *)"COOLER_DELAY,%d", unit->cooler_delay); srv_send(s, (char *)"COOLER_USAGE,%d", unit->cooler_usage); srv_send(s, (char *)"COOLER_IDX,%d", unit->cooler_idx); if (unit->PID_cool) { srv_send(s, (char *)"PIDC_IMAX,%.1f", unit->PID_cool->iMax); srv_send(s, (char *)"PIDC_IDLERANGE,%.2f", unit->PID_cool->idleRange); srv_send(s, (char *)"PIDC_PGAIN,%.3f", unit->PID_cool->pGain); srv_send(s, (char *)"PIDC_IGAIN,%.3f", unit->PID_cool->iGain); srv_send(s, (char *)"PIDC_DGAIN,%.3f", unit->PID_cool->dGain); srv_send(s, (char *)"PIDC_SV,%.2f", unit->PID_cool->SetP); } srv_send(s, (char *)"FAN_ADDRESS,%s", unit->fan_address); srv_send(s, (char *)"FAN_STATE,%d", unit->fan_state); srv_send(s, (char *)"FAN_DELAY,%d", unit->fan_delay); srv_send(s, (char *)"FAN_USAGE,%d", unit->fan_usage); srv_send(s, (char *)"FAN_IDX,%d", unit->fan_idx); srv_send(s, (char *)"LIGHT_ADDRESS,%s", unit->light_address); srv_send(s, (char *)"LIGHT_STATE,%d", unit->light_state); srv_send(s, (char *)"LIGHT_DELAY,%d", unit->light_delay); srv_send(s, (char *)"LIGHT_USAGE,%d", unit->light_usage); srv_send(s, (char *)"LIGHT_IDX,%d", unit->light_idx); srv_send(s, (char *)"DOOR_ADDRESS,%s", unit->door_address); srv_send(s, (char *)"DOOR_STATE,%d", unit->door_state); srv_send(s, (char *)"DOOR_IDX,%d", unit->door_idx); srv_send(s, (char *)"PSU_ADDRESS,%s", unit->psu_address); srv_send(s, (char *)"PSU_STATE,%d", unit->psu_state); srv_send(s, (char *)"PSU_IDX,%d", unit->psu_idx); srv_send(s, (char *)"FRIDGE_SET_LO,%.1f", unit->fridge_set_lo); srv_send(s, (char *)"FRIDGE_SET_HI,%.1f", unit->fridge_set_hi); srv_send(s, (char *)"BEER_SET_LO,%.1f", unit->beer_set_lo); srv_send(s, (char *)"BEER_SET_HI,%.1f", unit->beer_set_hi); if (unit->profile_uuid) { srv_send(s, (char *)"PROFILE_UUID,%s", unit->profile_uuid); srv_send(s, (char *)"PROFILE_NAME,%s", unit->profile_name); srv_send(s, (char *)"PROFILE_INITTEMP_LO,%.1f", unit->profile_inittemp_lo); srv_send(s, (char *)"PROFILE_INITTEMP_HI,%.1f", unit->profile_inittemp_hi); srv_send(s, (char *)"PROFILE_FRIDGE_MODE,%d", unit->profile_fridge_mode); srv_send(s, (char *)"PROFILE_DURATION,%d", unit->profile_duration); srv_send(s, (char *)"PROFILE_TOTALSTEPS,%d", unit->profile_totalsteps); srv_send(s, (char *)"PROF_STARTED,%d", (int)unit->prof_started); if (unit->prof_state == PROFILE_RUN) { srv_send(s, (char *)"PROF_STATE,%s %d%%", PROFSTATE[unit->prof_state], unit->prof_percent); } else { srv_send(s, (char *)"PROF_STATE,%s", PROFSTATE[unit->prof_state]); } srv_send(s, (char *)"PROF_TARGET_LO,%.3f", unit->prof_target_lo); srv_send(s, (char *)"PROF_TARGET_HI,%.3f", unit->prof_target_hi); srv_send(s, (char *)"PROF_FRIDGE_MODE,%d", unit->prof_fridge_mode); srv_send(s, (char *)"PROF_PEAK_ABS,%.3f", unit->prof_peak_abs); srv_send(s, (char *)"PROF_PEAK_REL,%.3f", unit->prof_peak_rel); srv_send(s, (char *)"PROF_PRIMARY_DONE,%d", (int)unit->prof_primary_done); } srv_send(s, (char *)"TEMP_SET_MIN,%.1f", unit->temp_set_min); srv_send(s, (char *)"TEMP_SET_MAX,%.1f", unit->temp_set_max); srv_send(s, (char *)"ALARM,%d", unit->alarm_flag); srv_send(s, (char *)"."); return 0; } } srv_send(s, (char *)"440 No such unit"); return 0; } if (strcmp(opt, (char *)"PUT") == 0) { /* * Block main process */ run_pause = TRUE; for (;;) { mDelay(100); if (run_hold) break; } for (unit = Config.units ; unit; unit = unit->next) { if (strcmp(unit->uuid, param) == 0) { while (1) { unit->mqtt_flag = 0; rlen = srv_recv(s, ibuf); if (rlen == -1) { run_pause = FALSE; return 0; } if (strlen(ibuf)) { if (strcmp(ibuf, (char *)".") == 0) { srv_send(s, (char *)"219 Accepted Unit record"); run_pause = FALSE; return 1; } kwd = strtok(ibuf, ",\0"); val = strtok(NULL, "\0"); if (kwd) { unit->mqtt_flag = 0; /* * 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 *)"PRODUCT_CODE") == 0)) { if (unit->product_code) { if (strcmp(unit->product_code, val)) { syslog(LOG_NOTICE, "Fermenter unit %s name `%s' to `%s'", unit->uuid, unit->product_code, val); } free(unit->product_code); } unit->product_code = xstrcpy(val); unit->mqtt_flag |= MQTT_FLAG_DATA; } else if (val && (strcmp(kwd, (char *)"PRODUCT_NAME") == 0)) { if (unit->product_name) { if (strcmp(unit->product_name, val)) { syslog(LOG_NOTICE, "Fermenter unit %s name `%s' to `%s'", unit->uuid, unit->product_name, val); } free(unit->product_name); } unit->product_name = xstrcpy(val); unit->mqtt_flag |= MQTT_FLAG_DATA; } 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; unit->mqtt_flag |= MQTT_FLAG_DATA; } else if (val && (strcmp(kwd, (char *)"AIR_IDX") == 0)) { if (sscanf(val, "%d", &ival) == 1) { if (unit->air_idx != ival) syslog(LOG_NOTICE, "Fermenter unit %s air idx %d to %d", unit->uuid, unit->air_idx, ival); unit->air_idx = ival; } } 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; unit->mqtt_flag |= MQTT_FLAG_DATA; } else if (strcmp(kwd, (char *)"BEER_ADDRESS2") == 0) { if (val && unit->beer_address2 && (strcmp(val, unit->beer_address2))) syslog(LOG_NOTICE, "Fermenter unit %s beer address alt `%s' to `%s'", unit->uuid, unit->beer_address2, val); if (unit->beer_address2) { device_count(FALSE, unit->beer_address2); free(unit->beer_address2); } if (val) { unit->beer_address2 = xstrcpy(val); device_count(TRUE, unit->beer_address2); } else unit->beer_address2 = NULL; unit->mqtt_flag |= MQTT_FLAG_DATA; } else if (val && (strcmp(kwd, (char *)"BEER_IDX") == 0)) { if (sscanf(val, "%d", &ival) == 1) { if (unit->beer_idx != ival) syslog(LOG_NOTICE, "Fermenter unit %s beer idx %d to %d", unit->uuid, unit->beer_idx, ival); unit->beer_idx = ival; } } else if (strcmp(kwd, (char *)"CHILLER_ADDRESS") == 0) { if (val && unit->chiller_address && (strcmp(val, unit->chiller_address))) syslog(LOG_NOTICE, "Fermenter unit %s chiller address `%s' to `%s'", unit->uuid, unit->chiller_address, val); if (unit->chiller_address) { device_count(FALSE, unit->chiller_address); free(unit->chiller_address); } if (val) { unit->chiller_address = xstrcpy(val); device_count(TRUE, unit->chiller_address); } else unit->chiller_address = NULL; unit->mqtt_flag |= MQTT_FLAG_DATA; } else if (val && (strcmp(kwd, (char *)"CHILLER_IDX") == 0)) { if (sscanf(val, "%d", &ival) == 1) { if (unit->chiller_idx != ival) syslog(LOG_NOTICE, "Fermenter unit %s chiller idx %d to %d", unit->uuid, unit->chiller_idx, ival); unit->chiller_idx = ival; } } 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; unit->mqtt_flag |= MQTT_FLAG_DATA; } 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; unit->mqtt_flag |= MQTT_FLAG_DATA; } } else if (val && (strcmp(kwd, (char *)"HEATER_IDX") == 0)) { if (sscanf(val, "%d", &ival) == 1) { if (unit->heater_idx != ival) syslog(LOG_NOTICE, "Fermenter unit %s heater idx %d to %d", unit->uuid, unit->heater_idx, ival); unit->heater_idx = 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; unit->mqtt_flag |= MQTT_FLAG_DATA; } 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; unit->mqtt_flag |= MQTT_FLAG_DATA; } } 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 (val && (strcmp(kwd, (char *)"COOLER_IDX") == 0)) { if (sscanf(val, "%d", &ival) == 1) { if (unit->cooler_idx != ival) syslog(LOG_NOTICE, "Fermenter unit %s cooler idx %d to %d", unit->uuid, unit->cooler_idx, ival); unit->cooler_idx = 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; unit->mqtt_flag |= MQTT_FLAG_DATA; } 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; unit->mqtt_flag |= MQTT_FLAG_DATA; } } 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 (val && (strcmp(kwd, (char *)"FAN_IDX") == 0)) { if (sscanf(val, "%d", &ival) == 1) { if (unit->fan_idx != ival) syslog(LOG_NOTICE, "Fermenter unit %s fan idx %d to %d", unit->uuid, unit->fan_idx, ival); unit->fan_idx = 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; unit->mqtt_flag |= MQTT_FLAG_DATA; } 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; unit->mqtt_flag |= MQTT_FLAG_DATA; } } 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 (val && (strcmp(kwd, (char *)"LIGHT_IDX") == 0)) { if (sscanf(val, "%d", &ival) == 1) { if (unit->light_idx != ival) syslog(LOG_NOTICE, "Fermenter unit %s light idx %d to %d", unit->uuid, unit->light_idx, ival); unit->light_idx = 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 (val && (strcmp(kwd, (char *)"DOOR_IDX") == 0)) { if (sscanf(val, "%d", &ival) == 1) { if (unit->door_idx != ival) syslog(LOG_NOTICE, "Fermenter unit %s door idx %d to %d", unit->uuid, unit->door_idx, ival); unit->door_idx = ival; } } 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; unit->mqtt_flag |= MQTT_FLAG_DATA; } else if (val && (strcmp(kwd, (char *)"PSU_IDX") == 0)) { if (sscanf(val, "%d", &ival) == 1) { if (unit->psu_idx != ival) syslog(LOG_NOTICE, "Fermenter unit %s psu idx %d to %d", unit->uuid, unit->psu_idx, ival); unit->psu_idx = ival; } } else if (val && (strcmp(kwd, (char *)"STAGE") == 0)) { for (i = 0; i < 4; i++) { if (strcmp(val, UNITSTAGE[i]) == 0) { if (i != unit->stage) { syslog(LOG_NOTICE, "Fermenter unit %s stage %s to %s", unit->uuid, UNITSTAGE[unit->stage], UNITSTAGE[i]); unit->mqtt_flag |= MQTT_FLAG_DATA; } unit->stage = i; break; } } } else if (val && (strcmp(kwd, (char *)"MODE") == 0)) { for (i = 0; i < 5; i++) { if (strcmp(val, UNITMODE[i]) == 0) { unit->mqtt_flag |= MQTT_FLAG_DATA; /* Initialize log if the unit is turned on */ if ((unit->mode == UNITMODE_OFF) && (i != UNITMODE_OFF)) { unit->mqtt_flag |= MQTT_FLAG_BIRTH; } 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 = unit->light_timer = 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_lo = unit->prof_target_hi = 20.0; unit->prof_fridge_mode = 0; if (unit->profile_uuid) { unit->mqtt_flag |= MQTT_FLAG_DATA; } } break; } } } else if (val && (strcmp(kwd, (char *)"FRIDGE_SET_LO") == 0)) { if ((sscanf(val, "%f", &fval) == 1) && (fval >= unit->temp_set_min) && (fval <= unit->temp_set_max)) { if (unit->fridge_set_lo != fval) syslog(LOG_NOTICE, "Fermenter unit %s fridge temp low %.1f to %.1f", unit->uuid, unit->fridge_set_lo, fval); unit->fridge_set_lo = fval; unit->mqtt_flag |= MQTT_FLAG_DATA; } } else if (val && (strcmp(kwd, (char *)"FRIDGE_SET_HI") == 0)) { if ((sscanf(val, "%f", &fval) == 1) && (fval >= unit->temp_set_min) && (fval <= unit->temp_set_max)) { if (unit->fridge_set_hi != fval) syslog(LOG_NOTICE, "Fermenter unit %s fridge temp high %.1f to %.1f", unit->uuid, unit->fridge_set_hi, fval); unit->fridge_set_hi = fval; unit->mqtt_flag |= MQTT_FLAG_DATA; } } else if (val && (strcmp(kwd, (char *)"BEER_SET_LO") == 0)) { if ((sscanf(val, "%f", &fval) == 1) && (fval >= unit->temp_set_min) && (fval <= unit->temp_set_max)) { if (unit->beer_set_lo != fval) syslog(LOG_NOTICE, "Fermenter unit %s beer temp low %.1f to %.1f", unit->uuid, unit->beer_set_lo, fval); unit->beer_set_lo = fval; unit->mqtt_flag |= MQTT_FLAG_DATA; } } else if (val && (strcmp(kwd, (char *)"BEER_SET_HI") == 0)) { if ((sscanf(val, "%f", &fval) == 1) && (fval >= unit->temp_set_min) && (fval <= unit->temp_set_max)) { if (unit->beer_set_hi != fval) syslog(LOG_NOTICE, "Fermenter unit %s beer temp high %.1f to %.1f", unit->uuid, unit->beer_set_hi, fval); unit->beer_set_hi = fval; unit->mqtt_flag |= MQTT_FLAG_DATA; } } 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 %.3f to %.3f", 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 %.3f to %.3f", 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 %.3f to %.3f", 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 %.3f to %.3f", 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 %.3f to %.3f", 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 %.3f to %.3f", 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 (val && (strcmp(kwd, (char *)"PROF_STATE") == 0) && unit->profile_uuid) { 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 = 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 ABORT", unit->uuid); } break; } unit->mqtt_flag |= MQTT_FLAG_DATA; 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; } } if (unit->mqtt_flag) { if (unit->mqtt_flag & MQTT_FLAG_BIRTH) { publishDBirth(unit); } else { publishDData(unit); } if (unit->mqtt_flag & MQTT_FLAG_DEATH) { publishDDeath(unit); } } } } } } } srv_send(s, (char *)"440 No such unit"); run_pause = FALSE; return 0; } srv_send(s, (char *)"504 Subcommand error"); return 0; } void cmd_server(int s) { char buf[SS_BUFSIZE]; int rlen; rlen = srv_recv(s, buf); if (rlen != -1) { if (strlen(buf)) { /* * Process commands from the client */ if (strncmp(buf, "DEVICE", 6) == 0) { if (cmd_device(s, buf)) wrconfig(); } else if (strncmp(buf, "GLOBAL", 6) == 0) { if (cmd_global(s, buf)) wrconfig(); } else if (strncmp(buf, "HELP", 4) == 0) { srv_send(s, (char *)"100 Help text follows"); srv_send(s, (char *)"Recognized commands:"); srv_send(s, (char *)""); // 12345678901234567890123456789012345678901234567890123456789012345678901234567890 srv_send(s, (char *)"DEVICE <CMD> [parameters] Device commands"); srv_send(s, (char *)"DEVICE HELP Device help screen"); srv_send(s, (char *)"GLOBAL <CMD> [parameters] Global commands"); srv_send(s, (char *)"GLOBAL HELP Global help screen"); srv_send(s, (char *)"LIST <CMD> [parameters] List commands"); srv_send(s, (char *)"LIST HELP List help screen"); srv_send(s, (char *)"ONEWIRE <CMD> [parameters] One-wire commands"); srv_send(s, (char *)"ONEWIRE HELP One-wire help screen"); srv_send(s, (char *)"PING Check if server is alive"); #ifdef USE_SIMULATOR srv_send(s, (char *)"SIMULATOR <CMD> [parameters] Simulator commands"); srv_send(s, (char *)"SIMULATOR HELP Simulator help screen"); #endif srv_send(s, (char *)"UNIT <CMD> [parameters] Unit commands"); srv_send(s, (char *)"UNIT HELP Unit help screen"); srv_send(s, (char *)"."); } else if (strncmp(buf, "LIST", 4) == 0) { cmd_list(s, buf); } else if (strncmp(buf, "ONEWIRE", 7) == 0) { cmd_onewire(s, buf); } else if (strncmp(buf, "PING", 4) == 0) { srv_send(s, (char *)"101 PONG"); #ifdef USE_SIMULATOR } else if (strncmp(buf, "SIMULATOR", 9) == 0) { if (cmd_simulator(s, buf)) wrconfig(); #endif } else if (strncmp(buf, "UNIT", 4) == 0) { if (cmd_unit(s, buf)) wrconfig(); } else { srv_send(s, (char *)"500 Unknown command"); } } } close(s); } static void cleanup_handler(void *arg) { syslog(LOG_NOTICE, "Thread my_server_loop stopped (cleanup_handler)"); close(ls); my_server_state = 0; } void *my_server_loop(void *threadid) { socklen_t addrlen; int s, optval = 1; my_server_state = 1; syslog(LOG_NOTICE, "Thread my_server_loop started"); /* * Prepare thread to stop in blocking accept() call. */ pthread_cleanup_push(cleanup_handler, NULL); pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); 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.server_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)); my_server_state = 0; 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); my_server_state = 0; 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); // my_server_state = 0; // 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); my_server_state = 0; return 0; } if (listen(ls, 5) == -1) { syslog(LOG_NOTICE, "Can't listen on listen socket: %s", strerror(errno)); close(ls); my_server_state = 0; 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); // syslog(LOG_NOTICE, "my_server_loop accept socket %d", s); if (s == -1) { syslog(LOG_NOTICE, "my_server_loop accept failed %s", strerror(errno)); break; } if (my_server_shutdown) break; cmd_server(s); if (my_server_shutdown) break; mDelay(100); } close(ls); pthread_cleanup_pop(my_server_state); syslog(LOG_NOTICE, "Thread my_server_loop stopped"); my_server_state = 0; return 0; }