diff -r 14322825cb3d -r 48f8f3fce7c0 bmsd/fermenters.c --- a/bmsd/fermenters.c Thu May 14 14:38:20 2020 +0200 +++ b/bmsd/fermenters.c Mon May 18 11:00:59 2020 +0200 @@ -27,6 +27,7 @@ #include "xutil.h" #include "fermenters.h" #include "mysql.h" +#include "mqtt.h" #include "websocket.h" @@ -36,15 +37,401 @@ extern sys_config Config; +void fermenter_ws_send(sys_fermenter_list *fermenter) +{ + char *msg = NULL, buf[65]; + + msg = xstrcpy((char *)"{\"device\":\"fermenters\",\"node\":\""); + msg = xstrcat(msg, fermenter->node); + msg = xstrcat(msg, (char *)"\",\"unit\":\""); + msg = xstrcat(msg, fermenter->alias); + msg = xstrcat(msg, (char *)"\",\"online\":"); + msg = xstrcat(msg, fermenter->online ? (char *)"1":(char *)"0"); + msg = xstrcat(msg, (char *)",\"mode\":\""); + msg = xstrcat(msg, fermenter->mode); + msg = xstrcat(msg, (char *)"\",\"beeruuid\":\""); + msg = xstrcat(msg, fermenter->beeruuid); + msg = xstrcat(msg, (char *)"\",\"beercode\":\""); + msg = xstrcat(msg, fermenter->beercode); + msg = xstrcat(msg, (char *)"\",\"beername\":\""); + msg = xstrcat(msg, fermenter->beername); + msg = xstrcat(msg, (char *)"\",\"yeast_lo\":"); + snprintf(buf, 64, "%.3f", fermenter->yeast_lo); + msg = xstrcat(msg, buf); + msg = xstrcat(msg, (char *)",\"yeast_hi\":"); + snprintf(buf, 64, "%.3f", fermenter->yeast_hi); + msg = xstrcat(msg, buf); + if (fermenter->air_address) { + msg = xstrcat(msg, (char *)",\"air_state\":\""); + msg = xstrcat(msg, fermenter->air_state); + msg = xstrcat(msg, (char *)"\",\"air_temperature\":"); + snprintf(buf, 64, "%.3f", fermenter->air_temperature); + msg = xstrcat(msg, buf); + } + if (fermenter->beer_address) { + msg = xstrcat(msg, (char *)",\"beer_state\":\""); + msg = xstrcat(msg, fermenter->beer_state); + msg = xstrcat(msg, (char *)"\",\"beer_temperature\":"); + snprintf(buf, 64, "%.3f", fermenter->beer_temperature); + msg = xstrcat(msg, buf); + } + if (fermenter->chiller_address) { + msg = xstrcat(msg, (char *)",\"chiller_state\":\""); + msg = xstrcat(msg, fermenter->chiller_state); + msg = xstrcat(msg, (char *)"\",\"chiller_temperature\":"); + snprintf(buf, 64, "%.3f", fermenter->chiller_temperature); + msg = xstrcat(msg, buf); + } + if (fermenter->heater_address) { + msg = xstrcat(msg, (char *)",\"heater_state\":"); + snprintf(buf, 64, "%d", fermenter->heater_state); + msg = xstrcat(msg, buf); + } + if (fermenter->cooler_address) { + msg = xstrcat(msg, (char *)",\"cooler_state\":"); + snprintf(buf, 64, "%d", fermenter->cooler_state); + msg = xstrcat(msg, buf); + } + if (fermenter->fan_address) { + msg = xstrcat(msg, (char *)",\"fan_state\":"); + snprintf(buf, 64, "%d", fermenter->fan_state); + msg = xstrcat(msg, buf); + } + if (fermenter->light_address) { + msg = xstrcat(msg, (char *)",\"light_address\":\""); + msg = xstrcat(msg, fermenter->light_address); + msg = xstrcat(msg, (char *)"\",\"light_state\":"); + snprintf(buf, 64, "%d", fermenter->light_state); + msg = xstrcat(msg, buf); + } + if (fermenter->door_address) { + msg = xstrcat(msg, (char *)",\"door_address\":\""); + msg = xstrcat(msg, fermenter->door_address); + msg = xstrcat(msg, (char *)"\",\"door_state\":"); + snprintf(buf, 64, "%d", fermenter->door_state); + msg = xstrcat(msg, buf); + } + if (fermenter->psu_address) { + msg = xstrcat(msg, (char *)",\"psu_address\":\""); + msg = xstrcat(msg, fermenter->psu_address); + msg = xstrcat(msg, (char *)"\",\"psu_state\":"); + snprintf(buf, 64, "%d", fermenter->psu_state); + msg = xstrcat(msg, buf); + } + msg = xstrcat(msg, (char *)",\"setpoint_low\":"); + snprintf(buf, 64, "%.3f", fermenter->setpoint_low); + msg = xstrcat(msg, buf); + msg = xstrcat(msg, (char *)",\"setpoint_high\":"); + snprintf(buf, 64, "%.3f", fermenter->setpoint_high); + msg = xstrcat(msg, buf); + msg = xstrcat(msg, (char *)",\"alarm\":"); + snprintf(buf, 64, "%d", fermenter->alarm); + msg = xstrcat(msg, buf); + msg = xstrcat(msg, (char *)",\"stage\":\""); + msg = xstrcat(msg, fermenter->stage); + msg = xstrcat(msg, (char *)"\""); + + if (fermenter->profile_uuid) { + msg = xstrcat(msg, (char *)",\"profile_uuid\":\""); + msg = xstrcat(msg, fermenter->profile_uuid); + msg = xstrcat(msg, (char *)"\",\"profile_name\":\""); + msg = xstrcat(msg, fermenter->profile_name); + msg = xstrcat(msg, (char *)"\",\"profile_state\":\""); + msg = xstrcat(msg, fermenter->profile_state); + msg = xstrcat(msg, (char *)"\",\"profile_percent\":"); + snprintf(buf, 64, "%d", fermenter->profile_percent); + msg = xstrcat(msg, buf); + msg = xstrcat(msg, (char *)",\"profile_inittemp_high\":"); + snprintf(buf, 64, "%.3f", fermenter->profile_inittemp_high); + msg = xstrcat(msg, buf); + msg = xstrcat(msg, (char *)",\"profile_inittemp_low\":"); + snprintf(buf, 64, "%.3f", fermenter->profile_inittemp_low); + msg = xstrcat(msg, buf); + msg = xstrcat(msg, (char *)",\"profile_steps\":"); + msg = xstrcat(msg, fermenter->profile_steps); + } + + msg = xstrcat(msg, (char *)",\"webcam_url\":\""); + msg = xstrcat(msg, fermenter->webcam_url); + msg = xstrcat(msg, (char *)"\",\"webcam_light\":"); + snprintf(buf, 64, "%d", fermenter->webcam_light); + msg = xstrcat(msg, buf); + msg = xstrcat(msg, (char *)"}"); + ws_broadcast(msg); + free(msg); + msg = NULL; +} + + + +char *fermenter_paybase(void) +{ + static char *tmp; + char buf[33]; + + tmp = xstrcpy((char *)"{\"timestamp\":"); + snprintf(buf, 32, "%ld", time(NULL)); + tmp = xstrcat(tmp, buf); + tmp = xstrcat(tmp, (char *)",\"metric\":"); + return tmp; +} + + +void fermenter_ws_receive(char *payload) +{ + struct json_object *jobj, *pobj, *iobj, *val; + char *node = NULL, *alias = NULL, *beeruuid = NULL, *beercode = NULL, *beername = NULL; + char *mode = NULL, *stage = NULL, *profile = NULL, *profile_uuid = NULL, *profile_name = NULL, *profile_steps = NULL; + char *topic = NULL, *pay = NULL, buf[75], *profile_command = NULL; + float setpoint_low = 0, setpoint_high = 0, yeast_lo = 0, yeast_hi = 0, inittemp_lo = 0, inittemp_hi = 0; + int heater_state = -1, cooler_state = -1, fan_state = -1, profile_fridgemode = -1; + + syslog(LOG_NOTICE, "fermenter_ws_receive(%s)", payload); + + /* + * Process the JSON formatted payload. + */ + jobj = json_tokener_parse(payload); + if (json_object_object_get_ex(jobj, "node", &val)) + node = xstrcpy((char *)json_object_get_string(val)); + if (json_object_object_get_ex(jobj, "unit", &val)) + alias = xstrcpy((char *)json_object_get_string(val)); + if (json_object_object_get_ex(jobj, "beeruuid", &val)) + beeruuid = xstrcpy((char *)json_object_get_string(val)); + if (json_object_object_get_ex(jobj, "beercode", &val)) + beercode = xstrcpy((char *)json_object_get_string(val)); + if (json_object_object_get_ex(jobj, "beername", &val)) + beername = xstrcpy((char *)json_object_get_string(val)); + if (json_object_object_get_ex(jobj, "mode", &val)) + mode = xstrcpy((char *)json_object_get_string(val)); + if (json_object_object_get_ex(jobj, "stage", &val)) + stage = xstrcpy((char *)json_object_get_string(val)); + if (json_object_object_get_ex(jobj, "setpoint_low", &val)) + setpoint_low = json_object_get_double(val); + if (json_object_object_get_ex(jobj, "setpoint_high", &val)) + setpoint_high = json_object_get_double(val); + if (json_object_object_get_ex(jobj, "yeast_lo", &val)) + yeast_lo = json_object_get_double(val); + if (json_object_object_get_ex(jobj, "yeast_hi", &val)) + yeast_hi = json_object_get_double(val); + if (json_object_object_get_ex(jobj, "heater_state", &val)) + heater_state = json_object_get_int(val); + if (json_object_object_get_ex(jobj, "cooler_state", &val)) + cooler_state = json_object_get_int(val); + if (json_object_object_get_ex(jobj, "fan_state", &val)) + fan_state = json_object_get_int(val); + if (json_object_object_get_ex(jobj, "profile", &pobj)) { + profile = xstrcpy((char *)json_object_get_string(pobj)); + if (profile == NULL) { // clear profile request + profile = xstrcpy((char *)"null"); + } + if (json_object_object_get_ex(pobj, "uuid", &val)) { + profile_uuid = xstrcpy((char *)json_object_get_string(val)); + syslog(LOG_NOTICE, "profile uuid"); + } + if (json_object_object_get_ex(pobj, "name", &val)) + profile_name = xstrcpy((char *)json_object_get_string(val)); + if (json_object_object_get_ex(pobj, "inittemp", &iobj)) { + + if (json_object_object_get_ex(iobj, "low", &val)) + inittemp_lo = json_object_get_double(val); + if (json_object_object_get_ex(iobj, "high", &val)) + inittemp_hi = json_object_get_double(val); + } + if (json_object_object_get_ex(pobj, "fridgemode", &val)) + profile_fridgemode = json_object_get_int(val); + if (json_object_object_get_ex(pobj, "steps", &val)) + profile_steps = xstrcpy((char *)json_object_get_string(val)); + if (json_object_object_get_ex(pobj, "command", &val)) { + profile_command = xstrcpy((char *)json_object_get_string(val)); + syslog(LOG_NOTICE, "profile command %s", profile_command); + } + } + json_object_put(jobj); + + /* + * Prepare MQTT topic + */ + topic = xstrcpy((char *)"mbv1.0/fermenters/DCMD/"); + topic = xstrcat(topic, node); + topic = xstrcat(topic, (char *)"/"); + topic = xstrcat(topic, alias); + + if (node && alias) { + if (mode) { + syslog(LOG_NOTICE, "Set fermenter %s/%s mode %s", node, alias, mode); + pay = fermenter_paybase(); + pay = xstrcat(pay, (char *)"{\"mode\":\""); + pay = xstrcat(pay, mode); + pay = xstrcat(pay, (char *)"\"}}"); + mqtt_publish(topic, pay); + free(pay); + pay = NULL; + } + + if (stage) { + syslog(LOG_NOTICE, "Set fermenter %s/%s stage %s", node, alias, stage); + pay = fermenter_paybase(); + pay = xstrcat(pay, (char *)"{\"stage\":\""); + pay = xstrcat(pay, stage); + pay = xstrcat(pay, (char *)"\"}}"); + mqtt_publish(topic, pay); + free(pay); + pay = NULL; + } + + if (setpoint_low > 0 && setpoint_high > 0 && setpoint_high >= setpoint_low) { + syslog(LOG_NOTICE, "Set fermenter %s/%s setpoint %.1f %.1f", node, alias, setpoint_low, setpoint_high); + pay = fermenter_paybase(); + pay = xstrcat(pay, (char *)"{\"setpoint\":{\"low\":"); + snprintf(buf, 64, "%.1f", setpoint_low); + pay = xstrcat(pay, buf); + pay = xstrcat(pay, (char *)",\"high\":"); + snprintf(buf, 64, "%.1f", setpoint_high); + pay = xstrcat(pay, buf); + pay = xstrcat(pay, (char *)"}}}"); + mqtt_publish(topic, pay); + free(pay); + pay = NULL; + } + + if (heater_state >= 0) { + syslog(LOG_NOTICE, "Set fermenter %s/%s heater %d", node, alias, heater_state); + pay = fermenter_paybase(); + pay = xstrcat(pay, (char *)"{\"heater\":{\"state\":"); + snprintf(buf, 64, "%d", heater_state); + pay = xstrcat(pay, buf); + pay = xstrcat(pay, (char *)"}}}"); + mqtt_publish(topic, pay); + free(pay); + pay = NULL; + } + + if (cooler_state >= 0) { + syslog(LOG_NOTICE, "Set fermenter %s/%s cooler %d", node, alias, cooler_state); + pay = fermenter_paybase(); + pay = xstrcat(pay, (char *)"{\"cooler\":{\"state\":"); + snprintf(buf, 64, "%d", cooler_state); + pay = xstrcat(pay, buf); + pay = xstrcat(pay, (char *)"}}}"); + mqtt_publish(topic, pay); + free(pay); + pay = NULL; + } + + if (fan_state >= 0) { + syslog(LOG_NOTICE, "Set fermenter %s/%s fan %d", node, alias, fan_state); + pay = fermenter_paybase(); + pay = xstrcat(pay, (char *)"{\"fan\":{\"state\":"); + snprintf(buf, 64, "%d", fan_state); + pay = xstrcat(pay, buf); + pay = xstrcat(pay, (char *)"}}}"); + mqtt_publish(topic, pay); + free(pay); + pay = NULL; + } + + if (beeruuid && beercode && beername && (yeast_hi > yeast_lo) && (yeast_lo > 0)) { + syslog(LOG_NOTICE, "Set fermenter %s/%s beer %s %s", node, alias, beercode, beername); + pay = fermenter_paybase(); + pay = xstrcat(pay, (char *)"{\"product\":{\"uuid\":\""); + pay = xstrcat(pay, beeruuid); + pay = xstrcat(pay, (char *)"\",\"code\":\""); + pay = xstrcat(pay, beercode); + pay = xstrcat(pay, (char *)"\",\"name\":\""); + pay = xstrcat(pay, beername); + pay = xstrcat(pay, (char *)"\",\"yeast_lo\":"); + snprintf(buf, 64, "%.1f", yeast_lo); + pay = xstrcat(pay, buf); + pay = xstrcat(pay, (char *)",\"yeast_hi\":"); + snprintf(buf, 64, "%.1f", yeast_hi); + pay = xstrcat(pay, buf); + pay = xstrcat(pay, (char *)"}}}"); + mqtt_publish(topic, pay); + free(pay); + pay = NULL; + } + + if (profile) { + syslog(LOG_NOTICE, "%s", profile); + if (strcmp(profile, (char *)"null") == 0) { + syslog(LOG_NOTICE, "Set fermenter %s/%s profile null", node, alias); + pay = fermenter_paybase(); + pay = xstrcat(pay, (char *)"{\"profile\":null}}"); + mqtt_publish(topic, pay); + free(pay); + pay = NULL; + } else if (profile_uuid && profile_name && profile_steps) { + syslog(LOG_NOTICE, "Set fermenter %s/%s profile %s", node, alias, profile_name); + pay = fermenter_paybase(); + pay = xstrcat(pay, (char *)"{\"profile\":{\"uuid\":\""); + pay = xstrcat(pay, profile_uuid); + pay = xstrcat(pay, (char *)"\",\"name\":\""); + pay = xstrcat(pay, profile_name); + pay = xstrcat(pay, (char *)"\",\"inittemp\":{\"low\":"); + snprintf(buf, 64, "%.1f", inittemp_lo); + pay = xstrcat(pay, buf); + pay = xstrcat(pay, (char *)",\"high\":"); + snprintf(buf, 64, "%.1f", inittemp_hi); + pay = xstrcat(pay, buf); + pay = xstrcat(pay, (char *)"},\"fridgemode\":"); + snprintf(buf, 64, "%d", profile_fridgemode); + pay = xstrcat(pay, buf); + pay = xstrcat(pay, (char *)",\"steps\":"); + pay = xstrcat(pay, profile_steps); + pay = xstrcat(pay, (char *)"}}}"); + mqtt_publish(topic, pay); + free(pay); + pay = NULL; + } else if (profile_command) { + syslog(LOG_NOTICE, "Set fermenter %s/%s profile command %s", node, alias, profile_command); + pay = fermenter_paybase(); + pay = xstrcat(pay, (char *)"{\"profile\":{\"command\":\""); + pay = xstrcat(pay, profile_command); + pay = xstrcat(pay, (char *)"\"}}}"); + mqtt_publish(topic, pay); + free(pay); + pay = NULL; + } + } + } + + free(topic); + if (node) + free(node); + if (alias) + free(alias); + if (beeruuid) + free(beeruuid); + if (beercode) + free(beercode); + if (beername) + free(beername); + if (mode) + free(mode); + if (stage) + free(stage); + if (profile) + free(profile); + if (profile_uuid) + free(profile_uuid); + if (profile_name) + free(profile_name); + if (profile_steps) + free(profile_steps); + if (profile_command) + free(profile_command); +} + + void fermenter_set(char *edge_node, char *alias, bool birth, char *payload) { struct json_object *jobj, *val, *sensor, *temp; sys_fermenter_list *fermenter, *tmpp; bool new_fermenter = true; - char *msg = NULL, buf[65]; -// fprintf(stdout, "fermenter_set: %s/%s %s %s\n", edge_node, alias, birth ? "BIRTH":"DATA", payload); + //syslog(LOG_NOTICE, "fermenter_set: %s/%s %s %s", edge_node, alias, birth ? "BIRTH":"DATA", payload); /* * Search fermenter record in the memory array and use it if found. @@ -267,8 +654,6 @@ } if (json_object_object_get_ex(jobj, "profile", &sensor)) { if (strcmp(json_object_to_json_string_ext(sensor, 0), "null")) { -// printf("profile: %s\n", json_object_to_json_string_ext(sensor, 0)); - if (json_object_object_get_ex(sensor, "uuid", &val)) { if (fermenter->profile_uuid) free(fermenter->profile_uuid); @@ -314,82 +699,11 @@ fermenter->profile_uuid = fermenter->profile_name = fermenter->profile_state = fermenter->profile_steps = NULL; fermenter->profile_percent = 0; fermenter->profile_inittemp_high = fermenter->profile_inittemp_low = 0.0; - fermenter->yeast_lo = 12; - fermenter->yeast_hi = 24; } } json_object_put(jobj); - msg = xstrcpy((char *)"{\"device\":\"fermenters\",\"node\":\""); - msg = xstrcat(msg, edge_node); - msg = xstrcat(msg, (char *)"\",\"unit\":\""); - msg = xstrcat(msg, alias); - msg = xstrcat(msg, (char *)"\",\"online\":"); - msg = xstrcat(msg, fermenter->online ? (char *)"1":(char *)"0"); - msg = xstrcat(msg, (char *)",\"mode\":\""); - msg = xstrcat(msg, fermenter->mode); - msg = xstrcat(msg, (char *)"\",\"yeast_lo\":"); - snprintf(buf, 64, "%.3f", fermenter->yeast_lo); - msg = xstrcat(msg, buf); - msg = xstrcat(msg, (char *)",\"yeast_hi\":"); - snprintf(buf, 64, "%.3f", fermenter->yeast_hi); - msg = xstrcat(msg, buf); - if (fermenter->air_address) { - msg = xstrcat(msg, (char *)",\"air\":"); - snprintf(buf, 64, "%.3f", fermenter->air_temperature); - msg = xstrcat(msg, buf); - } - if (fermenter->beer_address) { - msg = xstrcat(msg, (char *)",\"beer\":"); - snprintf(buf, 64, "%.3f", fermenter->beer_temperature); - msg = xstrcat(msg, buf); - } - if (fermenter->chiller_address) { - msg = xstrcat(msg, (char *)",\"chiller\":"); - snprintf(buf, 64, "%.3f", fermenter->chiller_temperature); - msg = xstrcat(msg, buf); - } - if (fermenter->heater_address) { - msg = xstrcat(msg, (char *)",\"heater\":"); - snprintf(buf, 64, "%d", fermenter->heater_state); - msg = xstrcat(msg, buf); - } - if (fermenter->cooler_address) { - msg = xstrcat(msg, (char *)",\"cooler\":"); - snprintf(buf, 64, "%d", fermenter->cooler_state); - msg = xstrcat(msg, buf); - } - if (fermenter->fan_address) { - msg = xstrcat(msg, (char *)",\"fan\":"); - snprintf(buf, 64, "%d", fermenter->fan_state); - msg = xstrcat(msg, buf); - } - if (fermenter->light_address) { - msg = xstrcat(msg, (char *)",\"light\":"); - snprintf(buf, 64, "%d", fermenter->light_state); - msg = xstrcat(msg, buf); - } - if (fermenter->door_address) { - msg = xstrcat(msg, (char *)",\"door\":"); - snprintf(buf, 64, "%d", fermenter->door_state); - msg = xstrcat(msg, buf); - } - msg = xstrcat(msg, (char *)",\"sp_lo\":"); - snprintf(buf, 64, "%.3f", fermenter->setpoint_low); - msg = xstrcat(msg, buf); - msg = xstrcat(msg, (char *)",\"sp_hi\":"); - snprintf(buf, 64, "%.3f", fermenter->setpoint_high); - msg = xstrcat(msg, buf); - msg = xstrcat(msg, (char *)",\"alarm\":"); - snprintf(buf, 64, "%d", fermenter->alarm); - msg = xstrcat(msg, buf); - msg = xstrcat(msg, (char *)",\"stage\":\""); - msg = xstrcat(msg, fermenter->stage); - msg = xstrcat(msg, (char *)"\"}"); - ws_broadcast(msg); - free(msg); - msg = NULL; - + fermenter_ws_send(fermenter); // fermenter_dump(fermenter); if (new_fermenter) {