--- a/thermferm/websocket.c Sun Apr 14 14:41:38 2024 +0200 +++ b/thermferm/websocket.c Mon Apr 15 17:04:57 2024 +0200 @@ -26,12 +26,17 @@ #include "thermferm.h" #include "xutil.h" +#include "devices.h" #include "websocket.h" #include <libwebsockets.h> extern sys_config Config; extern int debug; +extern const char UNITMODE[5][8]; +extern const char UNITSTAGE[4][12]; +//extern const char PROFSTATE[5][6]; +//extern const char TEMPSTATE[3][8]; int my_ws_shutdown = 0; int my_ws_state = 0; @@ -63,6 +68,157 @@ +void fermenter_ws_receive(char *buf) +{ + struct json_object *val, *val2, *jobj; + units_list *unit; + bool changed; + + jobj = json_tokener_parse(buf); + json_object_object_get_ex(jobj, "unit", &val); + + for (unit = Config.units ; unit; unit = unit->next) { + if (strcmp((char *)json_object_get_string(val), unit->alias) == 0) { + /* + * Setpoints + * {"type":"fermenter","unit":"unit0","setpoint_low":20.3,"setpoint_high":20.7} + */ + if ((unit->mode == UNITMODE_FRIDGE) || (unit->mode == UNITMODE_BEER)) { + changed = false; + if (json_object_object_get_ex(jobj, "setpoint_low", &val)) { + if (unit->PID_heat->SetP != json_object_get_double(val)) { + changed = true; + syslog(LOG_NOTICE, "ws: unit %s setpoint low from %.1f to %.1f", unit->alias, unit->PID_heat->SetP, json_object_get_double(val)); + unit->PID_heat->SetP = json_object_get_double(val); + } + } + if (json_object_object_get_ex(jobj, "setpoint_high", &val)) { + if (unit->PID_cool->SetP != json_object_get_double(val)) { + changed = true; + syslog(LOG_NOTICE, "ws: unit %s setpoint high from %.1f to %.1f", unit->alias, unit->PID_cool->SetP, json_object_get_double(val)); + unit->PID_cool->SetP = json_object_get_double(val); + } + } + if (changed) { + if (unit->mode == UNITMODE_FRIDGE) { + unit->fridge_set_lo = unit->PID_heat->SetP; + unit->fridge_set_hi = unit->PID_cool->SetP; + } else { + unit->beer_set_lo = unit->PID_heat->SetP; + unit->beer_set_hi = unit->PID_cool->SetP; + } + unit->mqtt_flag |= MQTT_FLAG_DATA; + break; + } + } + + /* + * Unit mode + * {"type":"fermenter","unit":"unit0","mode":"NONE"} + */ + if (json_object_object_get_ex(jobj, "mode", &val)) { + for (int i = 0; i < 5; i++) { + if (strcmp((char *)json_object_get_string(val), UNITMODE[i]) == 0) { + if (unit->mode != i) { + 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; + } + if (i == UNITMODE_PROFILE) { + /* Do some checks and refuse profile mode cannot be set */ + if (unit->profile_uuid == NULL) { + syslog(LOG_NOTICE, "ws: unit %s refuse mode profile, not loaded", unit->alias); + break; + } + } + syslog(LOG_NOTICE, "ws: unit %s mode to %s", unit->alias, UNITMODE[i]); + unit->mode = i; + if ((unit->mode != UNITMODE_OFF) && ! unit->event_msg) + unit->event_msg = xstrcpy((char *)UNITMODE[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->profile_inittemp_lo; + unit->prof_target_hi = unit->profile_inittemp_hi;; + unit->prof_fridge_mode = 0; + 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; + } + } + break; + } + } + } + + /* + * Unit stage + * {"type":"fermenter","unit":"unit0","stage":"SECONDARY"} + */ + if (json_object_object_get_ex(jobj, "stage", &val)) { + for (int i = 0; i < 4; i++) { + if (strcmp((char *)json_object_get_string(val), UNITSTAGE[i]) == 0) { + if (unit->stage != i) { + syslog(LOG_NOTICE, "DCMD change fermenter %s: stage to %s", unit->alias, UNITSTAGE[i]); + unit->mqtt_flag |= MQTT_FLAG_DATA; + unit->stage = i; + if ((unit->mode != UNITMODE_OFF) && ! unit->event_msg) + unit->event_msg = xstrcpy((char *)UNITSTAGE[i]); + } + break; + } + } + } + + /* + * Unit heater and cooler switch + * {"type":"fermenter","unit":"unit0","heater_state":100,"cooler_state":0} + */ + if ((json_object_object_get_ex(jobj, "heater_state", &val)) && + (json_object_object_get_ex(jobj, "cooler_state", &val2)) && + (unit->mode == UNITMODE_NONE)) { + if (json_object_get_int(val) != unit->heater_state) + unit->heater_state = json_object_get_int(val); + if (json_object_get_int(val2) != unit->cooler_state) + unit->cooler_state = json_object_get_int(val2); + if (unit->heater_state || unit->cooler_state) + unit->heater_state = unit->cooler_state = 0; // Safety + unit->mqtt_flag |= MQTT_FLAG_DATA; + syslog(LOG_NOTICE, "ws: unit %s heater_state to %d, cooler_state to %d", unit->alias, unit->heater_state, unit->cooler_state); + break; + } + + /* + * Unit fan switch + * {"type":"fermenter","unit":"unit0","fan_state":0} + */ + if ((json_object_object_get_ex(jobj, "fan_state", &val)) && (unit->mode == UNITMODE_NONE)) { + if (json_object_get_int(val) != unit->fan_state) + unit->fan_state = json_object_get_int(val); + unit->mqtt_flag |= MQTT_FLAG_DATA; + syslog(LOG_NOTICE, "ws: unit %s fan_state to %d", unit->alias, unit->fan_state); + break; + } + + return; + } + } + syslog(LOG_NOTICE, "fermenter_ws_receive(%s)", buf); +} + + static int callback_ws(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len) { struct per_session_data__lws_mirror *pss = (struct per_session_data__lws_mirror *)user; @@ -123,15 +279,15 @@ * {"node":"rpi01","group_id":"fermenters","control":"reboot"} * {"node":"rpi01","group_id":"fermenters","control":"rebirth"} */ -// if (strncmp(buf, (char *)"{\"device\":\"fermenters\",", 23) == 0) { -// fermenter_ws_receive(buf); + if (strncmp(buf, (char *)"{\"type\":\"fermenter\",", 20) == 0) { + fermenter_ws_receive(buf); // } else if (strncmp(buf, (char *)"{\"device\":\"co2meters\",", 22) == 0) { // co2meter_ws_receive(buf); // } else if (strncmp(buf, (char *)"{\"device\":\"ispindels\",", 22) == 0) { // ispindel_ws_receive(buf); // } else if (strncmp(buf, (char *)"{\"node\":\"", 9) == 0) { // node_ws_receive(buf); -// } + } break;