Fri, 19 Apr 2024 20:56:55 +0200
Create global_json() for all and expanded the data to the complete setup. Added design for the global setup.
/***************************************************************************** * 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 "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 const char UNITMODE[5][8]; extern const char UNITSTAGE[4][12]; 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]; 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; } /* * 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 *)"]"); srv_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:"); srv_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"); 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; } /* * 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 *)"PORT,%d", Config.my_port); srv_send(s, (char *)"TEMPFORMAT,%c", Config.tempFormat); srv_send(s, (char *)"TEMP_ADDRESS,%s", Config.temp_address); srv_send(s, (char *)"TEMP_STATE,%s", TEMPSTATE[Config.temp_state]); srv_send(s, (char *)"TEMP_VALUE,%.1f", Config.temp_value / 1000.0); srv_send(s, (char *)"HUM_ADDRESS,%s", Config.hum_address); srv_send(s, (char *)"HUM_STATE,%s", TEMPSTATE[Config.hum_state]); srv_send(s, (char *)"HUM_VALUE,%.0f", 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.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; } 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_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 (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->volume = unit->prof_peak_abs = unit->prof_peak_rel = 0.0; unit->air_state = unit->beer_state = unit->chiller_state = 1; 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); /* * 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 *)"VOLUME,%2f", unit->volume); srv_send(s, (char *)"AIR_ADDRESS,%s", unit->air_address); srv_send(s, (char *)"AIR_STATE,%s", TEMPSTATE[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", TEMPSTATE[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", TEMPSTATE[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 *)"JSON") == 0) { syslog(LOG_NOTICE, "UNIT JSON %s", param); for (unit = Config.units; unit; unit = unit->next) { if (strcmp(param, unit->uuid) == 0) { char *payload, *payloadu; 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 *)"}"); srv_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 (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 (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; 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 *)"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, "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.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)); 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; }