Node-RED : comment intégrer un objet connecté MySensors v2 • Domotique et objets connectés à faire soi-même

Il est très facile de créer ses propres objets connectés à base d’Arduino qui communiquent par ondes radio à l’aide de la librairie MySensors v2 et de les exploiter dans un projet Node-RED. Pour ce tutoriel, nous allons utiliser une simple sonde de température et d’humidité (DHT22). Nous afficherons les mesures de température et d’humidité à l’aide du module Dashboard.

Read this article in English

Préparer une sonde de température DHT22 MySensors

J’ai repris le code et le câblage du projet précédent. Vous devez également disposer d’une gateway réseau (suivez ce tutoriel pour la préparer) ou une gateway série.

Matériel nécessaire

Circuit

Code

Téléversez le code suivant dans l’Arduino Nano.

/**
 * The MySensors Arduino library handles the wireless radio link and protocol
 * between your home built sensors/actuators and HA controller of choice.
 * The sensors forms a self healing radio network with optional repeaters. Each
 * repeater and gateway builds a routing tables in EEPROM which keeps track of the
 * network topology allowing messages to be routed to nodes.
 *
 * Created by Henrik Ekblad 
 * Copyright (C) 2013-2015 Sensnology AB
 * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
 *
 * Documentation: http://www.mysensors.org
 * Support Forum: http://forum.mysensors.org
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * version 2 as published by the Free Software Foundation.
 *
 *******************************
 *
 * REVISION HISTORY
 * Version 1.0 - PROJETS DIY
 * 
 * DESCRIPTION
 * Example sketch showing how to measue light level using a LM393 photo-resistor 
 * http://www.mysensors.org/build/light
 */

// Active le mode debug / Enable debug prints to serial monitor
#define MY_DEBUG 

// Mode Radio / Enable and select radio type attached
#define MY_RADIO_NRF24
//#define MY_RADIO_RFM69

#define MY_RF24_PA_LEVEL RF24_PA_LOW

// Noeud de l'objet / Object Node
#define MY_NODE_ID 3

#include 
#include   
#include  

#define CHILD_ID_TEMP 0  
#define CHILD_ID_HUM 1
#define SLEEP_NODE true // Mettre à True pour activer la mise en sommeil (Sleep Mode) / True to activate Sleep Mode
unsigned long SLEEP_TIME = 10 * 1000; // Temps de mise en sommeil (en ms) / Sleep time between reads (in milliseconds)

#define DHTPIN 3        // Broche sur laquelle est branché le DHT / what pin we're connected to
#define DHTTYPE DHT22   // DHT 22  (AM2302), DHT11

float lastTemp;
float lastHum;
boolean metric = true; 
MyMessage msgHum(CHILD_ID_HUM, V_HUM);
MyMessage msgTemp(CHILD_ID_TEMP, V_TEMP);

void setup() { 
}

void presentation()  {
  // Présenttion du sketch / Send the sketch version information to the gateway and Controller
  sendSketchInfo("Sonde Temp/Hum DHT22", "1.0");

  // Déclaration des capteurs attachés au noeud
  present(CHILD_ID_TEMP, S_TEMP);
  present(CHILD_ID_HUM, S_HUM);
}

void loop()      
{    
  DHT dht(DHTPIN, DHTTYPE,3); // Creation d'un objet dht dans la loop sinon les valeurs ne sont pas mesurées au réveil
  float temperature = dht.readTemperature();
  float humidity = dht.readHumidity();
  if (isnan(temperature)) {
      Serial.println("Impossible de lire la temperature sur le DHT");
  } else {
    if (temperature != lastTemp) {
      lastTemp = temperature;
      if (!metric) {
        temperature = dht.readTemperature(true);
      }
      
      Serial.print("T: ");
      Serial.print(temperature);
      Serial.print(" | H: ");
      Serial.println(humidity);
      send(msgTemp.set(temperature, 1));
      send(msgHum.set(humidity, 1));
    } else {
      Serial.println("Temperature identique => on force l'envoi");  
      Serial.print("T: ");
      Serial.print(temperature);
      Serial.print(" | H: ");
      Serial.println(humidity);
      send(msgTemp.set(temperature, 1));
      send(msgHum.set(humidity, 1));
    }
  }  
  
  if (SLEEP_NODE) {
    Serial.println("Sleep");
    sleep(SLEEP_TIME);
  } else {
    delay (SLEEP_TIME);
  }
}

Intégrer un objet MySensors à un flow Node-RED

Il existe un plugin officiel MySensor (http://flows.nodered.org/node/node-red-contrib-mysensors). Pour ce projet, je vous propose d’utiliser le flow que j’ai développé et publié sur la librairie en ligne Node-RED (http://flows.nodered.org/flow/fa02078c160cb3e00e09f4980b534490). Il se charge de décoder les messages MySensors et renvoie en sortie un objet JSON. Il est plus facile de filtrer des valeurs souhaitées pour un noeud donné.

Code du flow MySensors Decoder

[{"id":"f4fd4940.32ba8","type":"function","z":"eb4ead14.fd77f","name":"Decode MySensor Message","func":"/* MySensors v2 Message Decoder\n*  Payload : JSON object\n*  www.projetsdiy.fr - oct. 2016\n*/\nvar mySensorsMessage = {}\nvar newPayload = {};\nvar message = msg.payload.toString();\nmessage = message.replace(/(\\r\\n|\\n|\\r)/gm, \"\");\nvar tokens = message.split(\";\")\nif(tokens.length == 6)\n{\n    mySensorsMessage.nodeId =       parseInt(tokens[0]);\n    mySensorsMessage.childSensorId= parseInt(tokens[1]);\n    mySensorsMessage.messageType =  parseInt(tokens[2]);\n    mySensorsMessage.ack =          parseInt(tokens[3]);\n    mySensorsMessage.subType =      parseInt(tokens[4]);\n    mySensorsMessage.value =        Number(tokens[5]);\n\n    var messageType = mySensorsMessage.messageType;\n    var subType = mySensorsMessage.subType;\n    var labelPresentation = [\"S_DOOR\",\"S_MOTION\",\"S_SMOKE\",\"S_LIGHT\",\"S_BINARY\",\"S_DIMMER\",\"S_COVER\",\"S_TEMP\",\"S_HUM\",\"S_BARO\",\"S_WIND\",\"S_RAIN\",\"S_UV\",\"S_WEIGHT\",\"S_POWER\",\"S_HEATER\",\"S_DISTANCE\",\"S_LIGHT_LEVEL\",\"S_ARDUINO_NODE\",\"S_ARDUINO_REPEATER_NODE\",\"S_LOCK\",\"S_IR\",\"S_WATER\",\"S_AIR_QUALITY\",\"S_CUSTOM\",\"S_DUST\",\"S_SCENE_CONTROLLER\",\"S_RGB_LIGHT\",\"S_RGBW_LIGHT\",\"S_COLOR_SENSOR\",\"S_HVAC\",\"S_MULTIMETER\",\"S_SPRINKLER\",\"S_WATER_LEAK\",\"S_SOUND\",\"S_VIBRATION\",\"S_MOISTURE\",\"S_INFO\",\"S_GAS\",\"S_GPS\",\"S_WATER_QUALITY\"];\n    var labelSet = [\"V_TEMP\",\"V_HUM\",\"V_STATUS\",\"V_LIGHT\",\"V_PERCENTAGE\",\"V_DIMMER\",\"V_PRESSURE\",\"V_FORECAST\",\"V_RAIN\",\"V_RAINRATE\",\"V_WIND\",\"V_GUST\",\"V_DIRECTION\",\"V_UV\",\"V_WEIGHT\",\"V_DISTANCE\",\"V_IMPEDANCE\",\"V_ARMED\",\"V_TRIPPED\",\"V_WATT\",\"V_KWH\",\"V_SCENE_ON\",\"V_SCENE_OFF\",\"V_HVAC_FLOW_STATE\",\"V_HVAC_SPEED\",\"V_LIGHT_LEVEL\",\"V_VAR1\",\"V_VAR2\",\"V_VAR3\",\"V_VAR4\",\"V_VAR5\",\"V_UP\",\"V_DOWN\",\"V_STOP\",\"V_IR_SEND\",\"V_IR_RECEIVE\",\"V_FLOW\",\"V_VOLUME\",\"V_LOCK_STATUS\",\"V_LEVEL\",\"V_VOLTAGE\",\"V_CURRENT\",\"V_RGB\",\"V_RGBW\",\"V_ID\",\"V_UNIT_PREFIX\",\"V_HVAC_SETPOINT_COOL\",\"V_HVAC_SETPOINT_HEAT\",\"V_HVAC_FLOW_MODE\",\"V_TEXT\",\"V_CUSTOM\",\"V_POSITION\",\"V_IR_RECORD\",\"V_PH\",\"V_ORP\",\"V_EC\",\"V_VAR\",\"V_VA\",\"V_POWER_FACTOR\"]\n    var labelInternal = [\"I_BATTERY_LEVEL\",\"I_TIME\",\"I_VERSION\",\"I_ID_REQUEST\",\"I_ID_RESPONSE\",\"I_INCLUSION_MODE\",\"I_CONFIG\",\"I_FIND_PARENT\",\"I_FIND_PARENT_RESPONSE\",\"I_LOG_MESSAGE\",\"I_CHILDREN\",\"I_SKETCH_NAME\",\"I_SKETCH_VERSION\",\"I_REBOOT\",\"I_GATEWAY_READY\",\"I_REQUEST_SIGNING\",\"I_GET_NONCE\",\"I_GET_NONCE_RESPONSE\",\"I_HEARTBEAT\",\"I_PRESENTATION\",\"I_DISCOVER\",\"I_DISCOVER_RESPONSE\",\"I_HEARTBEAT_RESPONSE\",\"I_LOCKED\",\"I_PING\",\"I_PONG\",\"I_REGISTRATION_REQUEST\",\"I_REGISTRATION_RESPONSE\",\"I_DEBUG\"]\n    \n    switch (messageType) {\n        case 0:     // Presentation\n            \n            newPayload.mode =       \"Presentation\";\n            newPayload.type =       labelPresentation[subType];\n            break;\n        case 1:     // Set\n            newPayload.nodeId=      mySensorsMessage.nodeId;\n            newPayload.sensorId=    mySensorsMessage.childSensorId;\n            newPayload.mode=        \"Set\";\n            newPayload.type=        subType;\n            newPayload.typeLabel=   labelSet[subType];\n            newPayload.value=       mySensorsMessage.value;\n            break;\n        case 2:     // Req\n            newPayload.nodeId=      mySensorsMessage.nodeId;\n            newPayload.sensorId=    mySensorsMessage.childSensorId;\n            newPayload.mode=        \"Req\";\n            newPayload.type=        subType;\n            newPayload.typeLabel=   labelSet[subType];\n            newPayload.value=       mySensorsMessage.value;\n            break;  \n        case 3:     // Internal\n            newPayload.nodeId=      mySensorsMessage.nodeId;\n            newPayload.sensorId=    mySensorsMessage.childSensorId;\n            newPayload.mode=        \"Internal\";\n            newPayload.type=        subType;\n            newPayload.typeLabel=   labelInternal[subType];\n            newPayload.value=       mySensorsMessage.value;\n            break;    \n        case 4:     // Stream - OTA firmware update\n            newPayload.nodeId=      mySensorsMessage.nodeId;\n            newPayload.mode=        \"stream\";\n            break;\n        default:\n            break;\n    }\n\n    msg.payload = newPayload; \n} else {\n    msg.payload = \"Error! Nothing to decode\"\n}  \n\nreturn msg;","outputs":1,"noerr":0,"x":394.5555419921875,"y":279.5555725097656,"wires":[["22cb3401.ef7e24","2d12c5a2.7304aa","fd30fa09.244ce8"]]}]

Se connecter à une Gateway réseau MySensors depuis Node-RED

Pour se connecter à une gateway réseau MySensors, nous allons utilise le protocole tcp (classé dans Input).

Configurez le Node comme ceci :

  • Type : Connect To
  • Port: 5003 (par défaut, sinon le port que vous avez configuré pour votre gateway)
  • at host : l’adresse ip de la gateway
  • Output : stream of / string
  • Vous pouvez aussi changer le nom affiché sur le flow.
  • Cliquez sur Done pour enregistrer la configuration

Vous pouvez maintenant relier la passerelle au décodeur de message. En branchant un Node debug, vous pourrez lire très facilement tous les messages (décodés) qui passent sur le réseau MySensors !

Afficher les mesures sur un graphique et une gauge

Regarder les mesures passer dans le log, c’est bien, mais on doit pouvoir faire un peu mieux ! Nous allons ajouter une interface graphique à notre projet Node-RED. Ouvrez le gestionnaire de palette. Celui-ci s’ouvre à gauche de l’écran. Allez dans l’onglet Install et installez le module Dashboard. Actualisez la page de navigateur à la fin de l’installation pour que la palette s’affiche (en bas).

Maintenant nous allons ajouter une fonction qui filtre la mesure que l’on souhaite afficher depuis le noeud DHT22. Collez ce code

if (msg.payload.nodeId == 3 && msg.payload.type === 0) {
    var msg;
    msg.payload = msg.payload.value;
    return msg;
}

Dans ce cas, on ne renvoie la valeur (value) que si le message provient du noeud 3 (nodeId == 3) et que c’est un type 0 (température, V_TEMP) ou 1 (humidité, V_HUM).

Depuis la palette dashboard déposez une gauge et configurez la comme ceci.

Il faut déjà créer une Tab. C’est une page WEB. On passe d’une page à l’autre depuis le menu dans le coin supérieur gauche.

Ensuite un Group. On peut regrouper les affichages (interrupteurs, gauge, graph, formulaire…) par groupe (group).

Enfin on peut régler les paramètres d’affichage de la gauge. On dispose de 4 types d’affichage :

Ajoutez également un graphique. Il fonctionne sur le même principe. Il faut l’associer au Group d’une Tab

Faites de même pour la mesure d’humidité. Voici le flow terminé.

Maintenant, ouvrez une nouvelle page dans le navigateur et saisissez l’adresse suivante

IP_NODE_RED:1880/ui

Et voilà, vous disposez maintenant d’un affichage graphique de votre sonde DHT22 MySensors en quelques minutes !

olb3n0ga2uu6rq30i7an-6023231

Vous n’aimez pas le bleu, aucun problème. Retournez sur Node-RED. Allez dans l’onglet dashboard qui se trouve à coté de l’onglet debug. Dans la liste Theme, choisissez Dark et déployez le projet.

Retournez sur la page UI pour contempler votre projet !

Flow du projet

Vous pouvez également directement importez ce flow si vous ne voulez pas réaliser toutes les étapes de ce tutoriel.

[{"id":"4c979a2.0f86f64","type":"tcp in","z":"5c2ea4a9.8713cc","name":"MySensors Gateway","server":"client","host":"192.168.1.20","port":"5003","datamode":"stream","datatype":"utf8","newline":"","topic":"","base64":false,"x":154.00001525878906,"y":296,"wires":[["7710e899.e4b198"]]},{"id":"7710e899.e4b198","type":"function","z":"5c2ea4a9.8713cc","name":"Decode MySensor Message","func":"/* MySensors v2 Message Decoder\n*  Payload : JSON object\n*  www.projetsdiy.fr - oct. 2016\n*/\nvar mySensorsMessage = {}\nvar newPayload = {};\nvar message = msg.payload.toString();\nmessage = message.replace(/(\\r\\n|\\n|\\r)/gm, \"\");\nvar tokens = message.split(\";\")\nif(tokens.length == 6)\n{\n    mySensorsMessage.nodeId =       parseInt(tokens[0]);\n    mySensorsMessage.childSensorId= parseInt(tokens[1]);\n    mySensorsMessage.messageType =  parseInt(tokens[2]);\n    mySensorsMessage.ack =          parseInt(tokens[3]);\n    mySensorsMessage.subType =      parseInt(tokens[4]);\n    mySensorsMessage.value =        Number(tokens[5]);\n\n    var messageType = mySensorsMessage.messageType;\n    var subType = mySensorsMessage.subType;\n    var labelPresentation = [\"S_DOOR\",\"S_MOTION\",\"S_SMOKE\",\"S_LIGHT\",\"S_BINARY\",\"S_DIMMER\",\"S_COVER\",\"S_TEMP\",\"S_HUM\",\"S_BARO\",\"S_WIND\",\"S_RAIN\",\"S_UV\",\"S_WEIGHT\",\"S_POWER\",\"S_HEATER\",\"S_DISTANCE\",\"S_LIGHT_LEVEL\",\"S_ARDUINO_NODE\",\"S_ARDUINO_REPEATER_NODE\",\"S_LOCK\",\"S_IR\",\"S_WATER\",\"S_AIR_QUALITY\",\"S_CUSTOM\",\"S_DUST\",\"S_SCENE_CONTROLLER\",\"S_RGB_LIGHT\",\"S_RGBW_LIGHT\",\"S_COLOR_SENSOR\",\"S_HVAC\",\"S_MULTIMETER\",\"S_SPRINKLER\",\"S_WATER_LEAK\",\"S_SOUND\",\"S_VIBRATION\",\"S_MOISTURE\",\"S_INFO\",\"S_GAS\",\"S_GPS\",\"S_WATER_QUALITY\"];\n    var labelSet = [\"V_TEMP\",\"V_HUM\",\"V_STATUS\",\"V_LIGHT\",\"V_PERCENTAGE\",\"V_DIMMER\",\"V_PRESSURE\",\"V_FORECAST\",\"V_RAIN\",\"V_RAINRATE\",\"V_WIND\",\"V_GUST\",\"V_DIRECTION\",\"V_UV\",\"V_WEIGHT\",\"V_DISTANCE\",\"V_IMPEDANCE\",\"V_ARMED\",\"V_TRIPPED\",\"V_WATT\",\"V_KWH\",\"V_SCENE_ON\",\"V_SCENE_OFF\",\"V_HVAC_FLOW_STATE\",\"V_HVAC_SPEED\",\"V_LIGHT_LEVEL\",\"V_VAR1\",\"V_VAR2\",\"V_VAR3\",\"V_VAR4\",\"V_VAR5\",\"V_UP\",\"V_DOWN\",\"V_STOP\",\"V_IR_SEND\",\"V_IR_RECEIVE\",\"V_FLOW\",\"V_VOLUME\",\"V_LOCK_STATUS\",\"V_LEVEL\",\"V_VOLTAGE\",\"V_CURRENT\",\"V_RGB\",\"V_RGBW\",\"V_ID\",\"V_UNIT_PREFIX\",\"V_HVAC_SETPOINT_COOL\",\"V_HVAC_SETPOINT_HEAT\",\"V_HVAC_FLOW_MODE\",\"V_TEXT\",\"V_CUSTOM\",\"V_POSITION\",\"V_IR_RECORD\",\"V_PH\",\"V_ORP\",\"V_EC\",\"V_VAR\",\"V_VA\",\"V_POWER_FACTOR\"]\n    var labelInternal = [\"I_BATTERY_LEVEL\",\"I_TIME\",\"I_VERSION\",\"I_ID_REQUEST\",\"I_ID_RESPONSE\",\"I_INCLUSION_MODE\",\"I_CONFIG\",\"I_FIND_PARENT\",\"I_FIND_PARENT_RESPONSE\",\"I_LOG_MESSAGE\",\"I_CHILDREN\",\"I_SKETCH_NAME\",\"I_SKETCH_VERSION\",\"I_REBOOT\",\"I_GATEWAY_READY\",\"I_REQUEST_SIGNING\",\"I_GET_NONCE\",\"I_GET_NONCE_RESPONSE\",\"I_HEARTBEAT\",\"I_PRESENTATION\",\"I_DISCOVER\",\"I_DISCOVER_RESPONSE\",\"I_HEARTBEAT_RESPONSE\",\"I_LOCKED\",\"I_PING\",\"I_PONG\",\"I_REGISTRATION_REQUEST\",\"I_REGISTRATION_RESPONSE\",\"I_DEBUG\"]\n    \n    switch (messageType) {\n        case 0:     // Presentation\n            \n            newPayload.mode =       \"Presentation\";\n            newPayload.type =       labelPresentation[subType];\n            break;\n        case 1:     // Set\n            newPayload.nodeId=      mySensorsMessage.nodeId;\n            newPayload.sensorId=    mySensorsMessage.childSensorId;\n            newPayload.mode=        \"Set\";\n            newPayload.type=        subType;\n            newPayload.typeLabel=   labelSet[subType];\n            newPayload.value=       mySensorsMessage.value;\n            break;\n        case 2:     // Req\n            newPayload.nodeId=      mySensorsMessage.nodeId;\n            newPayload.sensorId=    mySensorsMessage.childSensorId;\n            newPayload.mode=        \"Req\";\n            newPayload.type=        subType;\n            newPayload.typeLabel=   labelSet[subType];\n            newPayload.value=       mySensorsMessage.value;\n            break;  \n        case 3:     // Internal\n            newPayload.nodeId=      mySensorsMessage.nodeId;\n            newPayload.sensorId=    mySensorsMessage.childSensorId;\n            newPayload.mode=        \"Internal\";\n            newPayload.type=        subType;\n            newPayload.typeLabel=   labelInternal[subType];\n            newPayload.value=       mySensorsMessage.value;\n            break;    \n        case 4:     // Stream - OTA firmware update\n            newPayload.nodeId=      mySensorsMessage.nodeId;\n            newPayload.mode=        \"stream\";\n            break;\n        default:\n            break;\n    }\n\n    msg.payload = newPayload; \n} else {\n    msg.payload = \"Error! Nothing to decode\"\n}  \n\nreturn msg;","outputs":1,"noerr":0,"x":291.66668701171875,"y":424.6278991699219,"wires":[["f10887ac.6a2f28","e4304f11.8e755","3c923a76.ea6cb6"]]},{"id":"f10887ac.6a2f28","type":"function","z":"5c2ea4a9.8713cc","name":"Filtre : température noeud 3","func":"if (msg.payload.nodeId == 3 && msg.payload.type === 0) {\n    var msg;\n    msg.payload = msg.payload.value;\n    return msg;\n}    ","outputs":1,"noerr":0,"x":574.5,"y":394,"wires":[["7a1e3f92.b811d","f8fdeb6d.dcb858"]]},{"id":"7a1e3f92.b811d","type":"ui_gauge","z":"5c2ea4a9.8713cc","name":"Température","group":"febe591f.8ca1f8","order":0,"width":0,"height":0,"gtype":"gage","title":"Température DHT22","label":"MySensors v2","format":"{{value}}°C","min":0,"max":"50","colors":["#00b500","#e6e600","#ca3838"],"x":825.5,"y":358,"wires":[]},{"id":"e4304f11.8e755","type":"function","z":"5c2ea4a9.8713cc","name":"Filtre : humidité noeud 3","func":"if (msg.payload.nodeId == 3 && msg.payload.type === 1) {\n    var msg;\n    msg.payload = msg.payload.value;\n    return msg;\n}    ","outputs":1,"noerr":0,"x":564.8888549804688,"y":455.92767333984375,"wires":[["8e065da0.32b5f","e22f8ceb.eecbb"]]},{"id":"8e065da0.32b5f","type":"ui_gauge","z":"5c2ea4a9.8713cc","name":"Humidité","group":"febe591f.8ca1f8","order":0,"width":"0","height":"0","gtype":"gage","title":"Humidité DHT22","label":"MySensors v2","format":"{{value}}%","min":0,"max":"100","colors":["#1a25ab","#e6e600","#ca3838"],"x":811.8888549804688,"y":466.92767333984375,"wires":[]},{"id":"f8fdeb6d.dcb858","type":"ui_chart","z":"5c2ea4a9.8713cc","name":"Température","group":"45ccf5ba.b188ac","order":0,"width":0,"height":0,"label":"Température","chartType":"line","legend":"false","xformat":"%H:%M","interpolate":"linear","nodata":"","ymin":"0","ymax":"50","removeOlder":1,"removeOlderUnit":"3600","x":827.5,"y":413,"wires":[[],[]]},{"id":"e22f8ceb.eecbb","type":"ui_chart","z":"5c2ea4a9.8713cc","name":"Humidité","group":"45ccf5ba.b188ac","order":0,"width":0,"height":0,"label":"Humidité","chartType":"line","legend":"false","xformat":"%H:%M","interpolate":"linear","nodata":"","ymin":"0","ymax":"100","removeOlder":1,"removeOlderUnit":"3600","x":808,"y":514,"wires":[[],[]]},{"id":"3c923a76.ea6cb6","type":"debug","z":"5c2ea4a9.8713cc","name":"Message décodé","active":true,"console":"false","complete":"payload","x":484.5,"y":295,"wires":[]},{"id":"febe591f.8ca1f8","type":"ui_group","z":"","name":"Mesures","tab":"99f501d2.56c31","disp":true,"width":"6"},{"id":"45ccf5ba.b188ac","type":"ui_group","z":"","name":"Graphiques","tab":"99f501d2.56c31","disp":true,"width":"6"},{"id":"99f501d2.56c31","type":"ui_tab","z":"","name":"Salon","icon":"dashboard"}]

Node-RED est vraiment magique, rien ne vous empêche de concevoir votre propre logiciel domotique et bien plus encore !

Avez-vous aimé cet article ? [Total: 0 Moyenne: 0]