Marc Silanus

Node red et MySql

Posted on 2 avril 2018

Dans cet article, je vous propose de mettre en oeuvre une solution de sauvegarde de données dans une base de données MySql. Nous utiliserons les informations issues du capteur de température du CPU de notre Raspberry Pi toutes les minutes pour peupler la base de données. Nous utiliserons Node Red pour les lire et les présenter sous forme d'un tableau et d'un graphique retraçant l'évolution des dernières mesures. Pour cela il nous faudra procéder à l'installation de MySql sur notre Raspberry. Pour faciliter la gestion des bases de données MySql, nous installerons également un serveur Apache et  phpMyAdmin en suivant au choix  un de ces tutoriels :

Acquisition de la température du CPU

Le noyau Linux permet à un utilisateur standard d’accéder à un certain nombre d’informations sur les périphériques du système. Parmi ces informations, on retrouve la température de “zones thermiques” du PC.

Le concept de zone thermique est un peu compliqué et ne devrait pas être associé à un composant en particulier (CPU, GPU…​).

Depuis la version 2.6 du noyau, ces informations sont présentes dans des fichiers du système de fichiers virtuel Sysfs. Le "virtuel" signifie simplement que ces fichiers ne sont pas physiquement stockés sur le disque dur mais simulés en mémoire. Malgré tout, leur accès se fait de manière tout à fait traditionnelle.

La racine du système de fichiers Sysfs est /sys.

Dans un terminal, on peut lire la  température de la zone thermique n°0 par la commande suivante :

cat /sys/class/thermal/thermal_zone0/temp
Lecture de la température CPU

Nous allons écrire un programme pour lire cette valeur et la stockée dans la base de donnée. Avant tout, créons une base de données et une table avec phpMyAdmin.

  • Base de données : GTCEP
  • Table : sensors
  • Champs :
    • id : int - Auto incrément (A_I) - Clé primaire
    • date : datetime
    • temperature : float

Nous aurons besoin de la libraire libmysqlclient pour enregistrer  les données à partir d'un programme C++ :

sudo apt-get install -t stretch default-libmysqlclient-dev
Installation de libmysqlclient

Le code du programme :

// reading a text file
#include <iostream>
#include <fstream>
#include <string>
#include <mysql/mysql.h>
using namespace std;

MYSQL *conn, mysql;
MYSQL_RES *res;
MYSQL_ROW row;

int query_state;

float t;

int main () {
  string line;
  ifstream myfile ("/sys/class/thermal/thermal_zone0/temp");
  if (myfile.is_open())
  {
    getline(myfile,line);
    myfile.close();
    t = stof(line)/1000.0;
    cout << t << endl;
  }
  else 
  {
    cout << "Unable to open file";
    return 1;
  } 

  const char *server="localhost";
  const char *user="root";
  const char *password="raspberry";
  const char *database="GTCEP";

  mysql_init(&mysql);
  conn=mysql_real_connect(&mysql, server, user, password, database, 0, 0, 0);
  if(conn==NULL)
  {
     cout << mysql_error(&mysql) << endl << endl;
     return 1;
  }
  string query;
  query ="INSERT INTO `sensors` (`id`, `date`, `temperature`)";
  query += " VALUES (NULL, CURRENT_TIME(), ";
  query += to_string(t);
  query += ");";
  
  //cout << query << endl;
   
  query_state=mysql_query(conn, query.c_str());
  if(query_state!=0)
  {
     cout<<mysql_error(conn)<<endl<<endl;
     return 1;
  }
  else
  {
     //cout << "Energister en BDD" << endl;
  }
  return 0;
}
programme readTemp.cpp

Compilation à l'aide de g++ :

g++ readTemp.cpp -o readTemp -std=c++11 -lmysqlclient
Compilation

Exécution périodique toutes les minutes avec le planificateur de tâche CRON :

$ crontab -e

# Edit this file to introduce tasks to be run by cron.
#
# Each task to run has to be defined through a single line
# indicating with different fields when the task will be run
# and what command to run for the task
#
# To define the time you can provide concrete values for
# minute (m), hour (h), day of month (dom), month (mon),
# and day of week (dow) or use '*' in these fields (for 'any').#
# Notice that tasks will be started based on the cron's system
# daemon's notion of time and timezones.
#
# Output of the crontab jobs (including errors) is sent through
# email to the user the crontab file belongs to (unless redirected).
#
# For example, you can run a backup of all your user accounts
# at 5 a.m every week with:
# 0 5 * * 1 tar -zcf /var/backups/home.tgz /home/
#
# For more information see the manual pages of crontab(5) and cron(8)
#
# m h  dom mon dow   command

* * * * * /home/pi/Documents/readTemp

Vérifions le peuplement de la table :

Remarque : On aurait pu tout aussi bien enregistrer les données dans la BDD à partir de node red en utilisant le node file. (C'est certainement plus facile !)

Lecture des données avec node red

Il faut commencer par installer le node node-red-node-mysql : http://<ip_raspberry>:1880

Menu -> Manage palette -> Install

Essai de connexion

Créez un nouveau flow et insérez le node node-red-node-mysql. Double cliquez sur ce node pour le configurer :

Après avoir déployé le flow, vous devez voir apparaitre un petit rectangle vert noté connected indiquant la connexion à la base de données. Sinon, revoir les paramètres de connexion (Host, User, Password, Database).

Lecture de données

Nous allons procéder à une lecture élémentaire des données dans la table sensors. Pour cela, il nous faut fournir en entrée la requête à soumettre au serveur MySql. Nous utiliserons un node inject dans lequel nous renseignerons la propriété topic avec la requête et un node debug pour lire le résultat :

Déployez le flow puis cliquez sur la poignée en entrée du node inject pour soumettre la requête et observez le résultat dans la fenêtre debug :

Production de l'IHM

Pour assurer la lecture des données, nous allons soumettre la requête toutes les minutes et générer une IHM à partir des nodes du dashboard (voir ce précédent article).

Configurez le node inject :

Complétez le flow :

Configuration du node template :

  • Groupe : Température du processeur / Size : 16x10
  • Tab : BDD / Width : 24

Code de la fonction prepareHtml :

var temp = {};
var html = "<table width='100%'><tr><td width='75%'>Date</td><td width='25%'>Température</td></tr>";
for(var i in msg.payload)
{
    temp = msg.payload[i];
    html += "<tr><td>"+temp.date+"</td><td>"+temp.temperature+"</td></tr>";
}
html += "</table>";
msg.payload = html;
return msg;
prepareHtml

La variable html qui constitue la charge utile du message retourné par la fonction contient le code html qui sera affiché par le node template. On y créer un tableau avec une colonne "Date" et une colonne "Température". Le node node-red-node-mysql retourne une liste d'objet contenant en propriétés les champs de la table et leurs valeurs. La boucle for permet de parcourir cette liste et insère les valeurs des champs date et temperature dans une nouvelle ligne du tableau.

Remarque : Pas facile de lire les résultats avec cette requête. Ils sont ordonnés du plus ancien au plus récent. Modifions la pour n'afficher que les 10 dernières valeurs.

SELECT * FROM sensors ORDER BY date DESC LIMIT 10;

Code complet du flow pour ceux d'entre vous qui sont pressés.  A importer dans le clipboard (Menu -> Importer -> Clipboard).

[
    {
        "id": "9c300a74.a25b48",
        "type": "tab",
        "label": "Flow 3",
        "disabled": false,
        "info": ""
    },
    {
        "id": "4eaeea5a.782e84",
        "type": "mysql",
        "z": "9c300a74.a25b48",
        "mydb": "5a7da5ac.ff2f14",
        "name": "",
        "x": 771,
        "y": 267,
        "wires": [
            [
                "b9f76309.5d9188",
                "3a349590.99d05a"
            ]
        ]
    },
    {
        "id": "a529c3a5.fd5f2",
        "type": "inject",
        "z": "9c300a74.a25b48",
        "name": "",
        "topic": "SELECT * FROM sensors ORDER BY date DESC LIMIT 10;",
        "payload": "",
        "payloadType": "date",
        "repeat": "60",
        "crontab": "",
        "once": true,
        "x": 525,
        "y": 269,
        "wires": [
            [
                "4eaeea5a.782e84"
            ]
        ]
    },
    {
        "id": "b9f76309.5d9188",
        "type": "debug",
        "z": "9c300a74.a25b48",
        "name": "",
        "active": true,
        "console": "false",
        "complete": "false",
        "x": 990,
        "y": 152,
        "wires": []
    },
    {
        "id": "3a349590.99d05a",
        "type": "function",
        "z": "9c300a74.a25b48",
        "name": "prepareHtml",
        "func": "var temp = {};\nvar html = \"<table width='100%'><tr><td width='75%'>Date</td><td width='25%'>Temperature</td></tr>\";\nfor(var i in msg.payload)\n{\n    temp = msg.payload[i];\n    html += \"<tr><td>\"+temp.date+\"</td><td>\"+temp.temperature+\"</td></tr>\";\n}\nhtml += \"</table>\";\nmsg.payload = html;\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "x": 985,
        "y": 272,
        "wires": [
            [
                "cc31cacd.2b7208"
            ]
        ]
    },
    {
        "id": "cc31cacd.2b7208",
        "type": "ui_template",
        "z": "9c300a74.a25b48",
        "group": "cfbca1bb.7a494",
        "name": "",
        "order": 7,
        "width": "16",
        "height": "6",
        "format": "<div ng-bind-html=\"msg.payload\"></div>",
        "storeOutMessages": true,
        "fwdInMessages": true,
        "templateScope": "local",
        "x": 1196,
        "y": 272,
        "wires": [
            []
        ]
    },
    {
        "id": "5a7da5ac.ff2f14",
        "type": "MySQLdatabase",
        "z": "",
        "host": "127.0.0.1",
        "port": "3306",
        "db": "GTCEP",
        "tz": ""
    },
    {
        "id": "cfbca1bb.7a494",
        "type": "ui_group",
        "z": "",
        "name": "Températures du processeur",
        "tab": "21744230.c4774e",
        "order": 5,
        "disp": true,
        "width": "24",
        "collapse": true
    },
    {
        "id": "21744230.c4774e",
        "type": "ui_tab",
        "z": "",
        "name": "BDD",
        "icon": "dashboard"
    }
]

Ajoutons maintenant un graphique plus commode à la lecture. Insérez un node Chart sur le flow et un node function pour préparer les données :

Configuration du node Chart :

Code de la fonction prepareChart :

var temp = {};
var data = [];

for(var i in msg.payload)
{
    temp = msg.payload[i];
    data[i] = {"x": temp.date, "y": temp.temperature };
}

var chart = [{
"series": ["Température"],
"data": [
    data
]
}];
msg.payload = chart;

return msg;
prepareChart

Cette fonction créer le tableau attendu par le node chart. Celui-ci doit comporter au moins 2 tableaux d'objets series et data. Le premier contient la listes des séries qui seront affichées, ici, on en a qu'une, le second contient les points de la série. Ces derniers sont contenus dans le tableau d'objets data fabriqué dans la boucle for à partir de la charge utile du message fournie par le node node-red-node-mysql. Chaque objet point contient une propriété x dans laquelle on met la date et une propriété y dans laquelle on met la température.

Code complet du flow pour ceux d'entre vous qui sont pressés.  A importer dans le clipboard (Menu -> Importer -> Clipboard).

[
    {
        "id": "9c300a74.a25b48",
        "type": "tab",
        "label": "Flow 3",
        "disabled": false,
        "info": ""
    },
    {
        "id": "4eaeea5a.782e84",
        "type": "mysql",
        "z": "9c300a74.a25b48",
        "mydb": "5a7da5ac.ff2f14",
        "name": "",
        "x": 771,
        "y": 267,
        "wires": [
            [
                "b9f76309.5d9188",
                "3a349590.99d05a",
                "2e9664c8.eeb4dc"
            ]
        ]
    },
    {
        "id": "a529c3a5.fd5f2",
        "type": "inject",
        "z": "9c300a74.a25b48",
        "name": "",
        "topic": "SELECT * FROM sensors ORDER BY date DESC LIMIT 10;",
        "payload": "",
        "payloadType": "date",
        "repeat": "60",
        "crontab": "",
        "once": true,
        "x": 525,
        "y": 269,
        "wires": [
            [
                "4eaeea5a.782e84"
            ]
        ]
    },
    {
        "id": "b9f76309.5d9188",
        "type": "debug",
        "z": "9c300a74.a25b48",
        "name": "",
        "active": true,
        "console": "false",
        "complete": "false",
        "x": 990,
        "y": 152,
        "wires": []
    },
    {
        "id": "3a349590.99d05a",
        "type": "function",
        "z": "9c300a74.a25b48",
        "name": "prepareHtml",
        "func": "var temp = {};\nvar html = \"<table width='100%'><tr><td width='75%'>Date</td><td width='25%'>Temperature</td></tr>\";\nfor(var i in msg.payload)\n{\n    temp = msg.payload[i];\n    html += \"<tr><td>\"+temp.date+\"</td><td>\"+temp.temperature+\"</td></tr>\";\n}\nhtml += \"</table>\";\nmsg.payload = html;\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "x": 985,
        "y": 272,
        "wires": [
            [
                "cc31cacd.2b7208"
            ]
        ]
    },
    {
        "id": "cc31cacd.2b7208",
        "type": "ui_template",
        "z": "9c300a74.a25b48",
        "group": "cfbca1bb.7a494",
        "name": "",
        "order": 7,
        "width": "16",
        "height": "6",
        "format": "<div ng-bind-html=\"msg.payload\"></div>",
        "storeOutMessages": true,
        "fwdInMessages": true,
        "templateScope": "local",
        "x": 1196,
        "y": 272,
        "wires": [
            []
        ]
    },
    {
        "id": "69c11fac.9bf2a",
        "type": "ui_chart",
        "z": "9c300a74.a25b48",
        "name": "",
        "group": "cfbca1bb.7a494",
        "order": 8,
        "width": "24",
        "height": "8",
        "label": "Température",
        "chartType": "line",
        "legend": "false",
        "xformat": "dd HH:mm",
        "interpolate": "bezier",
        "nodata": "",
        "dot": true,
        "ymin": "30",
        "ymax": "60",
        "removeOlder": 1,
        "removeOlderPoints": "",
        "removeOlderUnit": "3600",
        "cutout": 0,
        "useOneColor": false,
        "colors": [
            "#ff0000",
            "#aec7e8",
            "#ff7f0e",
            "#2ca02c",
            "#98df8a",
            "#d62728",
            "#ff9896",
            "#9467bd",
            "#c5b0d5"
        ],
        "useOldStyle": false,
        "x": 1180,
        "y": 354,
        "wires": [
            [],
            []
        ]
    },
    {
        "id": "2e9664c8.eeb4dc",
        "type": "function",
        "z": "9c300a74.a25b48",
        "name": "prepareChart",
        "func": "var temp = {};\nvar data = [];\n\nfor(var i in msg.payload)\n{\n    temp = msg.payload[i];\n    data[i] = {\"x\": temp.date, \"y\": temp.temperature };\n}\n\nvar chart = [{\n\"series\": [\"Température\"],\n\"data\": [\n    data\n]\n}];\nmsg.payload = chart;\n\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "x": 1003,
        "y": 354.449951171875,
        "wires": [
            [
                "69c11fac.9bf2a"
            ]
        ]
    },
    {
        "id": "5a7da5ac.ff2f14",
        "type": "MySQLdatabase",
        "z": "",
        "host": "127.0.0.1",
        "port": "3306",
        "db": "GTCEP",
        "tz": ""
    },
    {
        "id": "cfbca1bb.7a494",
        "type": "ui_group",
        "z": "",
        "name": "Températures du processeur",
        "tab": "21744230.c4774e",
        "order": 5,
        "disp": true,
        "width": "24",
        "collapse": true
    },
    {
        "id": "21744230.c4774e",
        "type": "ui_tab",
        "z": "",
        "name": "BDD",
        "icon": "dashboard"
    }
]

Filtrage des données

Notre IHM nous permet d'observer seulement les 10 dernières valeurs. Il serait bon de pouvoir choisir le nombre de valeurs à observer ou depuis quand. Voici une amélioration pour choisir la date de début d'observation. Elle utilise un node date picker pour choisir le jour et deux nodes numeric pour choisir l'heure et les minutes. On utilise ici un node join pour assembler les éléments constitutifs de la date de début puis une fonction pour formater la requête à soumettre.

Le bouton Filtrer déclenche la recherche. Les informations filtrées sont visibles durant 1 minute puisque le node inject est paramétré pour répéter l'injection de la requête initiale toutes les minutes. La charge utile de ce node est le timestamp (horodatage : nombre de secondes écoulées depuis le 1er janvier 1970 à minuit UTC). On utilise donc cette information pour prépositionner le calendrier à la date du jour, le réglage de l'heure sur l'heure qu'il est ainsi que les minutes.

Code complet du flow.  A importer dans le clipboard (Menu -> Importer -> Clipboard).

[
    {
        "id": "48eb6118.f097e",
        "type": "tab",
        "label": "MySQL test",
        "disabled": false,
        "info": ""
    },
    {
        "id": "643b3090.6dd398",
        "type": "debug",
        "z": "48eb6118.f097e",
        "name": "",
        "active": true,
        "console": "false",
        "complete": "payload",
        "x": 739.449951171875,
        "y": 452.2499694824219,
        "wires": []
    },
    {
        "id": "41e70c1f.535c6c",
        "type": "mysql",
        "z": "48eb6118.f097e",
        "mydb": "5a7da5ac.ff2f14",
        "name": "",
        "x": 677.11669921875,
        "y": 130.11666870117188,
        "wires": [
            [
                "1b3f8b43.9ea40d",
                "115955fd.233c82"
            ]
        ]
    },
    {
        "id": "72efc503.bfeb94",
        "type": "inject",
        "z": "48eb6118.f097e",
        "name": "",
        "topic": "SELECT * FROM sensors ORDER BY date DESC LIMIT 10; ",
        "payload": "",
        "payloadType": "date",
        "repeat": "60",
        "crontab": "",
        "once": true,
        "x": 197.44998168945312,
        "y": 80.01669311523438,
        "wires": [
            [
                "41e70c1f.535c6c",
                "fbcefa0c.7536f8",
                "7e49fb42.c6ecbc",
                "dde00d3.726d37"
            ]
        ]
    },
    {
        "id": "1629eb5f.1c3dad",
        "type": "ui_template",
        "z": "48eb6118.f097e",
        "group": "cfbca1bb.7a494",
        "name": "",
        "order": 7,
        "width": "16",
        "height": "5",
        "format": "<div ng-bind-html=\"msg.payload\"></div>",
        "storeOutMessages": true,
        "fwdInMessages": true,
        "templateScope": "local",
        "x": 1076.4500732421875,
        "y": 129.23333740234375,
        "wires": [
            []
        ]
    },
    {
        "id": "af2b51e9.bdded8",
        "type": "ui_chart",
        "z": "48eb6118.f097e",
        "name": "",
        "group": "cfbca1bb.7a494",
        "order": 8,
        "width": "24",
        "height": "8",
        "label": "Température",
        "chartType": "line",
        "legend": "false",
        "xformat": "auto",
        "interpolate": "bezier",
        "nodata": "",
        "dot": true,
        "ymin": "30",
        "ymax": "60",
        "removeOlder": 1,
        "removeOlderPoints": "",
        "removeOlderUnit": "3600",
        "cutout": 0,
        "useOneColor": false,
        "colors": [
            "#ff0000",
            "#aec7e8",
            "#ff7f0e",
            "#2ca02c",
            "#98df8a",
            "#d62728",
            "#ff9896",
            "#9467bd",
            "#c5b0d5"
        ],
        "useOldStyle": false,
        "x": 1097.4500732421875,
        "y": 361.7667236328125,
        "wires": [
            [],
            []
        ]
    },
    {
        "id": "1b3f8b43.9ea40d",
        "type": "function",
        "z": "48eb6118.f097e",
        "name": "prepareChart",
        "func": "var temp = {};\nvar data = [];\n\nfor(var i in msg.payload)\n{\n    temp = msg.payload[i];\n    data[i] = {\"x\": temp.date, \"y\": temp.temperature };\n}\n\nvar chart = [{\n\"series\": [\"Température\"],\n\"data\": [\n    data\n]\n}];\nmsg.payload = chart;\n\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "x": 920.4500732421875,
        "y": 362.2166748046875,
        "wires": [
            [
                "af2b51e9.bdded8"
            ]
        ]
    },
    {
        "id": "dde00d3.726d37",
        "type": "ui_date_picker",
        "z": "48eb6118.f097e",
        "name": "date",
        "label": "Date de début",
        "group": "f328f8b.95a5b88",
        "order": 3,
        "width": "4",
        "height": "1",
        "passthru": true,
        "topic": "date",
        "x": 345.4499816894531,
        "y": 186.7166748046875,
        "wires": [
            [
                "e1f2a69c.6da95"
            ]
        ]
    },
    {
        "id": "146f93b1.d181cc",
        "type": "function",
        "z": "48eb6118.f097e",
        "name": "prepareQuery",
        "func": "if (!msg.payload.date) msg.payload.date = Math.round(+new Date());\nvar date = msg.payload.date;\nvar dt;\ndt = new Date(date);\n\nif (!(\"heure\" in msg.payload)) msg.payload.heure = dt.getHours();\nvar heure = msg.payload.heure;\n\nif (!(\"minute\" in msg.payload)) msg.payload.minute = dt.getMinutes();\nvar minute = msg.payload.minute;\n\nvar query;\nquery = \"SELECT * FROM sensors WHERE date >='\";\nquery += dt.getFullYear()+\"-\";\nquery += (dt.getMonth()+1)+\"-\";\nquery += dt.getDate()+\" \";\nquery += heure + \":\";\nquery += minute + \":00' ORDER BY date;\";\nmsg.topic = query;\n\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "x": 619.4500732421875,
        "y": 325.1166687011719,
        "wires": [
            [
                "643b3090.6dd398",
                "41e70c1f.535c6c"
            ]
        ]
    },
    {
        "id": "e1f2a69c.6da95",
        "type": "join",
        "z": "48eb6118.f097e",
        "name": "",
        "mode": "custom",
        "build": "object",
        "property": "payload",
        "propertyType": "msg",
        "key": "topic",
        "joiner": ",",
        "joinerType": "str",
        "accumulate": false,
        "timeout": "",
        "count": "",
        "x": 490.4499816894531,
        "y": 262.3500061035156,
        "wires": [
            [
                "146f93b1.d181cc"
            ]
        ]
    },
    {
        "id": "86d9bdeb.a4039",
        "type": "ui_button",
        "z": "48eb6118.f097e",
        "name": "",
        "group": "68cc7623.8a519",
        "order": 6,
        "width": "4",
        "height": "1",
        "passthru": false,
        "label": "Filtrer",
        "color": "",
        "bgcolor": "",
        "icon": "search",
        "payload": "true",
        "payloadType": "bool",
        "topic": "button",
        "x": 83.44998168945312,
        "y": 507.1333923339844,
        "wires": [
            [
                "e8ce00b1.8fa81"
            ]
        ]
    },
    {
        "id": "e8ce00b1.8fa81",
        "type": "function",
        "z": "48eb6118.f097e",
        "name": "complete",
        "func": "\nreturn {\n    complete : true\n};",
        "outputs": 1,
        "noerr": 0,
        "x": 441.4499816894531,
        "y": 504.6166687011719,
        "wires": [
            [
                "e1f2a69c.6da95"
            ]
        ]
    },
    {
        "id": "7e49fb42.c6ecbc",
        "type": "function",
        "z": "48eb6118.f097e",
        "name": "getHours",
        "func": "var dt;\ndt = new Date(msg.payload);\nmsg.payload = dt.getHours();\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "x": 107.44998168945312,
        "y": 247.51666259765625,
        "wires": [
            [
                "2ad6c338.7ca8f4"
            ]
        ]
    },
    {
        "id": "fbcefa0c.7536f8",
        "type": "function",
        "z": "48eb6118.f097e",
        "name": "getMinutes",
        "func": "var dt;\ndt = new Date(msg.payload);\nmsg.payload = dt.getMinutes();\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "x": 189.11666870117188,
        "y": 373.1166687011719,
        "wires": [
            [
                "541deed4.b61a18"
            ]
        ]
    },
    {
        "id": "2ad6c338.7ca8f4",
        "type": "ui_numeric",
        "z": "48eb6118.f097e",
        "name": "",
        "label": "hh :",
        "group": "357b6534.f93ada",
        "order": 0,
        "width": 0,
        "height": 0,
        "passthru": true,
        "topic": "heure",
        "format": "{{value}}",
        "min": 0,
        "max": "23",
        "step": 1,
        "x": 269.4499816894531,
        "y": 249.39999389648438,
        "wires": [
            [
                "e1f2a69c.6da95"
            ]
        ]
    },
    {
        "id": "541deed4.b61a18",
        "type": "ui_numeric",
        "z": "48eb6118.f097e",
        "name": "",
        "label": "mm :",
        "group": "c5ebff61.3533f8",
        "order": 0,
        "width": 0,
        "height": 0,
        "passthru": true,
        "topic": "minute",
        "format": "{{value}}",
        "min": 0,
        "max": "59",
        "step": 1,
        "x": 339.4499816894531,
        "y": 374.3999938964844,
        "wires": [
            [
                "e1f2a69c.6da95"
            ]
        ]
    },
    {
        "id": "115955fd.233c82",
        "type": "function",
        "z": "48eb6118.f097e",
        "name": "prepareHtml",
        "func": "var temp = {};\nvar html = \"<table width='100%'><tr><td width='75%'>Date</td><td width='25%'>Temperature</td></tr>\";\nfor(var i in msg.payload)\n{\n    temp = msg.payload[i];\n    html += \"<tr><td>\"+temp.date+\"</td><td>\"+temp.temperature+\"</td></tr>\";\n}\nhtml += \"</table>\";\nmsg.payload = html;\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "x": 904.4500732421875,
        "y": 128.41665649414062,
        "wires": [
            [
                "1629eb5f.1c3dad"
            ]
        ]
    },
    {
        "id": "5a7da5ac.ff2f14",
        "type": "MySQLdatabase",
        "z": "",
        "host": "127.0.0.1",
        "port": "3306",
        "db": "GTCEP",
        "tz": ""
    },
    {
        "id": "cfbca1bb.7a494",
        "type": "ui_group",
        "z": "",
        "name": "Températures du processeur",
        "tab": "21744230.c4774e",
        "order": 5,
        "disp": true,
        "width": "24",
        "collapse": true
    },
    {
        "id": "f328f8b.95a5b88",
        "type": "ui_group",
        "z": "",
        "name": "Date",
        "tab": "21744230.c4774e",
        "order": 1,
        "disp": true,
        "width": "6",
        "collapse": false
    },
    {
        "id": "68cc7623.8a519",
        "type": "ui_group",
        "z": "",
        "name": "Filtrer les données",
        "tab": "21744230.c4774e",
        "order": 4,
        "disp": true,
        "width": "6",
        "collapse": false
    },
    {
        "id": "357b6534.f93ada",
        "type": "ui_group",
        "z": "",
        "name": "Heure",
        "tab": "21744230.c4774e",
        "order": 2,
        "disp": true,
        "width": "6",
        "collapse": false
    },
    {
        "id": "c5ebff61.3533f8",
        "type": "ui_group",
        "z": "",
        "name": "Minute",
        "tab": "21744230.c4774e",
        "order": 3,
        "disp": true,
        "width": "6",
        "collapse": false
    },
    {
        "id": "21744230.c4774e",
        "type": "ui_tab",
        "z": "",
        "name": "BDD",
        "icon": "dashboard"
    }
]
Flow node red d'observation de la température CPU

Filtrage des données sur plus de 24 heures :

On observe une pointe le 1er avril vers 21h (9PM). J'ai obtenu cette pointe en stressant le CPU de ma Raspberry grace à l'utilitaire sysbench.

$ sudo apt-get install sysbench
$ sysbench --test=cpu --cpu-max-prime=20000 run
Stresser le système

On peut également observé une baisse de la température du CPU de 1h du matin à 8h. C'est l'heure de la programmation de la coupure wifi sur ma box. C'est bien la preuve que le wifi, ça consomme !

Commentaires (0) Trackbacks (0)

Désolé, le formulaire de commentaire est fermé pour le moment

Trackbacks are disabled.