bmsd/nodes.c

Sat, 18 Apr 2020 15:56:40 +0200

author
Michiel Broek <mbroek@mbse.eu>
date
Sat, 18 Apr 2020 15:56:40 +0200
changeset 657
a5ade45597d8
parent 578
e75ce5bbda73
child 672
23f959713fcb
permissions
-rw-r--r--

More code cleanup

/**
 * @file nodes.c
 * @brief Handle nodes status
 * @author Michiel Broek <mbroek at mbse dot eu>
 *
 * Copyright (C) 2018-2020
 *
 * 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 "nodes.h"
#include "mysql.h"


sys_node_list			*nodes = NULL;

extern int			debug;
extern sys_fermenter_list	*fermenters;
extern sys_co2meter_list	*co2meters;
extern sys_ispindel_list	*ispindels;


void node_birth_data(char *topic, char *payload)
{
    struct json_object	*jobj, *val, *metric, *metric2;
    sys_node_list	*node, *tmpp;
    char		*group_id, *message_type, *edge_node;
    bool		new_node = true;

//    fprintf(stdout, "node_birth: %s %s\n", topic, payload);

    strtok(topic, "/");	// ignore namespace
    group_id = strtok(NULL, "/");
    message_type = strtok(NULL, "/");
    edge_node = strtok(NULL, "/\0");

    /*
     * Search node record in the memory array and use it if found.
     */
    if (nodes) {
	for (tmpp = nodes; tmpp; tmpp = tmpp->next) {
	    if ((strcmp(tmpp->group_id, group_id) == 0) && (strcmp(tmpp->node, edge_node) == 0)) {
		new_node = false;
		node = tmpp;
		node->lastseen = time(NULL);
		node->online = true;
		break;
	    }
	}
    }

    /*
     * Allocate new node if not yet known.
     */
    if (new_node) {
	node = (sys_node_list *)malloc(sizeof(sys_node_list));
    	node->uuid = NULL;
   	node->next = NULL;
    	node->group_id = xstrcpy(group_id);
    	node->node = xstrcpy(edge_node);
    	node->online = true;
    	node->hardwaremake = node->hardwaremodel = node->os = node->os_version = node->firmware = NULL;
    	node->firstseen = node->lastseen = time(NULL);
    	node->temperature = node->humidity = node->barometer = 0.0;
    	node->gps_latitude = node->gps_longitude = node->gps_altitude = 0.0;
	node->net_address = node->net_ifname = NULL;
	node->net_rssi = 0;
	node->interval = 300;
    }

    /*
     * Process the JSON formatted payload. 
     * Update only the fields that are found in the payload.
     */
    jobj = json_tokener_parse(payload);

    if (json_object_object_get_ex(jobj, "timestamp", &val)) {
	if (strcmp((char *)"NDATA", message_type)) {
	    node->firstseen = json_object_get_int(val);
	    syslog(LOG_NOTICE, "Online node `%s/%s'", node->group_id, node->node);
	} else {
	    node->lastseen = json_object_get_int(val);
	}
    }

    /*
    if (json_object_object_get_ex(jobj, "seq", &val)) {
	printf("seq: %s\n", json_object_to_json_string_ext(val, 0));	// Do we need it?
    }
    */

    if (json_object_object_get_ex(jobj, "metric", &metric)) {
	if (json_object_object_get_ex(metric, "uuid", &val)) {
	    if (node->uuid)
		free(node->uuid);
	    node->uuid = xstrcpy((char *)json_object_get_string(val));
	}
	if (json_object_object_get_ex(metric, "interval", &val)) {
	    node->interval = json_object_get_int(val);
	}
	if (json_object_object_get_ex(metric, "properties", &metric2)) {
	    if (json_object_object_get_ex(metric2, "hardwaremake", &val)) {
		if (node->hardwaremake)
		    free(node->hardwaremake);
		node->hardwaremake = xstrcpy((char *)json_object_get_string(val));
	    }
	    if (json_object_object_get_ex(metric2, "hardwaremodel", &val)) {
		if (node->hardwaremodel)
		    free(node->hardwaremodel);
		node->hardwaremodel = xstrcpy((char *)json_object_get_string(val));
	    }
	    if (json_object_object_get_ex(metric2, "os", &val)) {
		if (node->os)
		    free(node->os);
		node->os = xstrcpy((char *)json_object_get_string(val));
	    }
	    if (json_object_object_get_ex(metric2, "os_version", &val)) {
		if (node->os_version)
		    free(node->os_version);
		node->os_version = xstrcpy((char *)json_object_get_string(val));
	    }
	    if (json_object_object_get_ex(metric2, "FW", &val)) {
		if (node->firmware)
		    free(node->firmware);
		node->firmware = xstrcpy((char *)json_object_get_string(val));
	    }
	}
	if (json_object_object_get_ex(metric, "THB", &metric2)) {
	    if (json_object_object_get_ex(metric2, "temperature", &val)) {
		node->temperature = json_object_get_double(val);
	    }
	    if (json_object_object_get_ex(metric2, "humidity", &val)) {
		node->humidity= json_object_get_double(val);
	    }
	    if (json_object_object_get_ex(metric2, "barometer", &val)) {
		node->barometer = json_object_get_double(val);
	    }
	}
	if (json_object_object_get_ex(metric, "GPS", &metric2)) {
	    if (json_object_object_get_ex(metric2, "latitude", &val)) {
		node->gps_latitude = json_object_get_double(val);
	    }
	    if (json_object_object_get_ex(metric2, "longitude", &val)) {
		node->gps_longitude = json_object_get_double(val);
	    }
	    if (json_object_object_get_ex(metric2, "altitude", &val)) {
		node->gps_altitude = json_object_get_double(val);
	    }
	}
	if (json_object_object_get_ex(metric, "net", &metric2)) {
	    if (json_object_object_get_ex(metric2, "address", &val)) {
		if (node->net_address)
		    free(node->net_address);
		node->net_address = xstrcpy((char *)json_object_get_string(val));
	    }
	    if (json_object_object_get_ex(metric2, "ifname", &val)) {
		if (node->net_ifname)
		    free(node->net_ifname);
		node->net_ifname = xstrcpy((char *)json_object_get_string(val));
	    }
	    if (json_object_object_get_ex(metric2, "rssi", &val)) {
		node->net_rssi = json_object_get_int(val);
	    }
	}
    }
    json_object_put(jobj);

//    node_dump(node);

    if (new_node) {
    	if (nodes == NULL) {
	    nodes = node;
	} else {
	    for (tmpp = nodes; tmpp; tmpp = tmpp->next) {
		if (tmpp->next == NULL) {
		    tmpp->next = node;
		    break;
		}
	    }
	}
	node_mysql_insert(node);
    } else {
	node_mysql_update(node);
    }
}



void node_dump(sys_node_list *node)
{
    if (debug) {
	printf("online    %s\n", node->online ? "yes":"no");
    	printf("uuid      %s\n", node->uuid);
    	printf("node      %s\n", node->node);
    	printf("group     %s\n", node->group_id);
    	printf("hw make   %s  model %s\n", node->hardwaremake, node->hardwaremodel);
    	printf("os        %s  version %s\n", node->os, node->os_version);
    	printf("firmware  %s\n", node->firmware);
    	printf("first     %ld   last %ld\n", node->firstseen, node->lastseen);
    	printf("THB       %.2f  %.2f  %.2f\n", node->temperature, node->humidity, node->barometer);
    	printf("GPS       %.5f  %.5f  %.5f\n", node->gps_latitude, node->gps_longitude, node->gps_altitude);
	printf("net       %s:%s\n", node->net_ifname, node->net_address);
	printf("rssi      %d\n", node->net_rssi);
	printf("interval  %d\n", node->interval);
    }
}



void node_death(char *topic)
{
    char		*group_id, *edge_node;
    sys_node_list	*tmpp;

    strtok(topic, "/"); // ignore namespace
    group_id = strtok(NULL, "/");
    strtok(NULL, "/");	// ignore message_type
    edge_node = strtok(NULL, "/\0");

    syslog(LOG_NOTICE, "Offline node `%s/%s'", group_id, edge_node);
    node_mysql_death(edge_node);

    for (tmpp = nodes; tmpp; tmpp = tmpp->next) {
	if (strcmp(tmpp->node, edge_node) == 0) {
	    tmpp->online = false;
	    break;
	}
    }
}



void nodes_check_online()
{
    sys_node_list	*tmpn;
    sys_fermenter_list  *tmpf;
    sys_co2meter_list	*tmpc;
    sys_ispindel_list	*tmpi;
    time_t		now = time(NULL);

    for (tmpn = nodes; tmpn; tmpn = tmpn->next) {
//	if (debug)
//	    printf("%-20s online %s  %ld  %d\n", tmpn->node, tmpn->online ? "yes":"no ", tmpn->lastseen, tmpn->interval);
	if (tmpn->online && ((now - tmpn->lastseen) > (tmpn->interval * 2 + 5))) { // 2 times interval + 5 seconds
	    syslog(LOG_NOTICE, "Timeout node `%s/%s' after %ld seconds", tmpn->group_id, tmpn->node, (now - tmpn->lastseen));
	    tmpn->online = false;
	    node_mysql_death(tmpn->node);

	    for (tmpf = fermenters; tmpf; tmpf = tmpf->next) {
            	if (strcmp(tmpf->node, tmpn->node) == 0) {
                    if (tmpf->online) {
                    	syslog(LOG_NOTICE, "Timeout fermenter %s/%s", tmpf->node, tmpf->alias);
                	tmpf->online = false;
			fermenter_mysql_death(tmpf->node, tmpf->alias);
		    }
            	}
            }

	    for (tmpc = co2meters; tmpc; tmpc = tmpc->next) {
		if (strcmp(tmpc->node, tmpn->node) == 0) {
		    if (tmpc->online) {
			syslog(LOG_NOTICE, "Timeout co2meter %s/%s", tmpc->node, tmpc->alias);
			tmpc->online = false;
			co2meter_mysql_death(tmpc->node, tmpc->alias);
		    }
		}
	    }

	    for (tmpi = ispindels; tmpi; tmpi = tmpi->next) {
		if (strcmp(tmpi->node, tmpn->node) == 0) {
		    if (tmpi->online) {
                        syslog(LOG_NOTICE, "Timeout ispindel %s", tmpi->node);
                        tmpi->online = false;
                        ispindel_mysql_death(tmpi->node);
                    }
		}
	    }
	}
    }
}

mercurial