bmsd/ispindels.c

Fri, 13 Dec 2019 16:49:50 +0100

author
Michiel Broek <mbroek@mbse.eu>
date
Fri, 13 Dec 2019 16:49:50 +0100
changeset 567
6bf0afc33e70
child 568
6f3c24e21deb
permissions
-rw-r--r--

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(&timestamp);
    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);
    }
}

mercurial