Fri, 13 Dec 2019 16:49:50 +0100
Initial code for iSpindel support in the daemon
/** * @file ispindels.c * @brief Handle ispindels status * @author Michiel Broek <mbroek at mbse dot eu> * * Copyright (C) 2019 * * This file is part of the bms (Brewery Management System) * * 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. * * bms 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 "bms.h" #include "xutil.h" #include "ispindels.h" #include "mysql.h" #include "nodes.h" sys_ispindel_list *ispindels = NULL; extern int debug; extern sys_config Config; extern MYSQL *con; extern MYSQL_RES *res_set; extern MYSQL_ROW row; void ispindel_set(char *node, char *key, char *payload) { sys_ispindel_list *ispindel, *tmpp; bool new_ispindel = true, do_update = false; char *t, *p; float temperature = 20; uint8_t temp_units = 'C'; fprintf(stdout, "ispindel_set: %s %s\n", node, payload); /* * Search ispindel record in the memory array and use it if found. */ if (ispindels) { for (tmpp = ispindels; tmpp; tmpp = tmpp->next) { if (strcmp(tmpp->node, node) == 0) { new_ispindel = false; ispindel = tmpp; break; } } } printf("new_ispindel %s\n", new_ispindel ? "true":"false"); /* * Allocate new ispindel if not yet known. */ if (new_ispindel) { ispindel = (sys_ispindel_list *)malloc(sizeof(sys_ispindel_list)); memset(ispindel, 0, sizeof(sys_ispindel_list)); ispindel->node = xstrcpy(node); } if (! ispindel->online) { ispindel->online = true; syslog(LOG_NOTICE, "Online ispindel %s", node); } /* * Process the simple iSpindel MQTT payload. */ if (strcmp(key, "tilt") == 0) { ispindel->tilt = atof(payload); } else if (strcmp(key, "temperature") == 0) { temperature = atof(payload); } else if (strcmp(key, "temp_units") == 0) { temp_units = payload[0]; } else if (strcmp(key, "battery") == 0) { ispindel->battery = atof(payload); } else if (strcmp(key, "gravity") == 0) { ispindel->gravity = atof(payload); } else if (strcmp(key, "interval") == 0) { ispindel->interval = atoi(payload); } else if (strcmp(key, "RSSI") == 0) { ispindel->rssi = atoi(payload); do_update = true; if (temp_units == 'C') { ispindel->temperature = temperature; } else if (temp_units == 'F') { ispindel->temperature = temperature / 1.8 - 32; } else if (temp_units == 'K') { ispindel->temperature = temperature - 273.15; } else { ispindel->temperature = temperature; } } else { syslog(LOG_NOTICE, "Unknown keyword `%s' from `%s'", key, node); } ispindel_dump(ispindel); if (new_ispindel || do_update) { char buf[21]; t = xstrcpy((char *)"mbv1.0/ispindels/NBIRTH/"); t = xstrcat(t, node); p = xstrcpy((char *)"{\"metric\":{\"properties\":{\"hardwaremake\":\"MBSE\",\"hardwaremodel\":\"Wemos D1 mini\"},\"net\":{\"rssi\":"); sprintf(buf, "%d", ispindel->rssi); p = xstrcat(p, buf); p = xstrcat(p, (char *)"}}}"); node_birth_data(t, p); free(t); free(p); } if (new_ispindel) { if (ispindels == NULL) { ispindels = ispindel; } else { for (tmpp = ispindels; tmpp; tmpp = tmpp->next) { if (tmpp->next == NULL) { tmpp->next = ispindel; break; } } } ispindel_mysql_insert(ispindel); } else if (do_update) { ispindel_mysql_update(ispindel); } } /* * Process iSpindel MQTT message. */ void ispindel_mqtt(char *topic, char *payload) { char *namespace, *node, *keyword; namespace = strtok(topic, "/"); // must be ispindel node = strtok(NULL, "/"); keyword = strtok(NULL, "/\0"); if (strcmp(namespace, "ispindels")) { syslog(LOG_NOTICE, "ispindel_mqtt(%s, %s) error", topic, payload); return; } ispindel_set(node, keyword, payload); } void ispindel_log(char *topic, char *payload) { char *edge_node, *alias, *line, buf[128], *logfile; struct json_object *jobj, *val, *metric; co2pressure_log *log; struct tm *mytime; time_t timestamp; FILE *fp; strtok(topic, "/"); // ignore namespace strtok(NULL, "/"); // group_id strtok(NULL, "/"); // message_type edge_node = strtok(NULL, "/\0"); alias = strtok(NULL, "/\0"); log = (co2pressure_log *)malloc(sizeof(co2pressure_log)); memset(log, 0, sizeof(co2pressure_log)); log->node = xstrcpy(edge_node); log->alias = xstrcpy(alias); jobj = json_tokener_parse(payload); timestamp = time(NULL); log->datetime = malloc(73); mytime = localtime(×tamp); snprintf(log->datetime, 72, "%04d-%02d-%02d %02d:%02d:%02d", mytime->tm_year + 1900, mytime->tm_mon + 1, mytime->tm_mday, mytime->tm_hour, mytime->tm_min, mytime->tm_sec); if (json_object_object_get_ex(jobj, "metric", &metric)) { if (json_object_object_get_ex(metric, "uuid", &val)) { if (strcmp((char *)"(null)", json_object_get_string(val))) log->uuid = xstrcpy((char *)json_object_get_string(val)); } if (json_object_object_get_ex(metric, "temperature", &val)) { log->temperature = json_object_get_double(val); } if (json_object_object_get_ex(metric, "pressure", &val)) { log->pressure = json_object_get_double(val); } } json_object_put(jobj); /* * Because ispindels are not so smart and don't hold product information * search the missing pieces in the database. */ snprintf(buf, 127, "SELECT beercode,beername,beeruuid FROM mon_ispindels WHERE uuid='%s'", log->uuid); if (mysql_query(con, buf)) { syslog(LOG_NOTICE, "MySQL: %s error %u (%s))", buf, mysql_errno(con), mysql_error(con)); } else { res_set = mysql_store_result(con); if (res_set == NULL) { syslog(LOG_NOTICE, "MySQL: mysq_store_result error %u (%s))", mysql_errno(con), mysql_error(con)); } else { if ((row = mysql_fetch_row(res_set)) != NULL) { /* * Ignore when the beer_name or beer_code is not set. */ if ((int)strlen(row[0]) == 0 || (int)strlen(row[1]) == 0) { if (log->datetime) free(log->datetime); if (log->uuid) free(log->uuid); if (log->node) free(log->node); if (log->alias) free(log->alias); free(log); return; } log->product_code = xstrcpy(row[0]); log->product_name = xstrcpy(row[1]); log->product_uuid = xstrcpy(row[2]); } } } /* * Build csv log line */ line = xstrcpy(log->datetime); line = xstrcat(line, (char *)","); snprintf(buf, 64, "%.3f", log->temperature); line = xstrcat(line, buf); line = xstrcat(line, (char *)","); snprintf(buf, 64, "%.3f", log->pressure); line = xstrcat(line, buf); line = xstrcat(line, (char *)","); line = xstrcat(line, log->uuid); /* * Build logfile name */ logfile = xstrcpy(Config.web_root); logfile = xstrcat(logfile, (char *)"/log/co2pressure/"); logfile = xstrcat(logfile, log->product_code); logfile = xstrcat(logfile, (char *)" "); logfile = xstrcat(logfile, log->product_name); logfile = xstrcat(logfile, (char *)".log"); if (debug) fprintf(stdout, "%s %s\n", logfile, line); fp = fopen(logfile, "a"); if (fp) { fprintf(fp, "%s\n", line); fclose(fp); } else { syslog(LOG_NOTICE, "cannot append to `%s'", logfile); } free(logfile); logfile = NULL; free(line); line = NULL; if (log->datetime) free(log->datetime); if (log->product_uuid ) free(log->product_uuid ); if (log->product_code ) free(log->product_code ); if (log->product_name ) free(log->product_name ); if (log->uuid) free(log->uuid); if (log->node) free(log->node); if (log->alias) free(log->alias); free(log); } void ispindel_dump(sys_ispindel_list *ispindel) { if (debug) { printf("node %s\n", ispindel->node); printf("online %s\n", ispindel->online ? "yes":"no"); printf("product %s / %s\n", ispindel->beercode, ispindel->beername); printf("tilt %.3f\n", ispindel->tilt); printf("temperature %.3f\n", ispindel->temperature); printf("battery %.3f\n", ispindel->battery); printf("gravity %.3f\n", ispindel->gravity); printf("interval %d\n", ispindel->interval); printf("rssi %d\n", ispindel->rssi); } }