Node-RED. Dashboard pour objet connecté. Jauges, graphiques, notifications, template HTML (Partie 2) • Domotique et objets connectés à faire soi-même

Dans ce second tutoriel consacré à la création d’un dashboard (tableau de bord) pour objet connecté à l’aide du module Dashboard pour Node-RED, nous allons nous intéresser à l’ajout des afficheurs graphiques. Jauges, graphiques, notifications, template HTML / Angular.

Tutoriel actualisé le 27 juillet 2020

Le module Dashboard propose 4 types d’afficheurs (jauge, graphique, champ texte, notification furtive), le composant ui-control qui permet de changer de panneau (tab) par programmation, et enfin un champ qui permet d’afficher du code HTML libre (déjà vu dans la 1ère partie).

Sonde de température MySensors DHT22 pour générer des mesures à afficher

Pour illustrer le fonctionnement des différents composants proposés par le plugin node-red-dashboard, je vous propose d’utiliser des mesures en provenance d’une sonde de température DHT22 MySensors. Nous allons simplement reprendre la sonde DHT22 créée pour ce projet.

Créer la page MySensors

Ouvrez l’onglet Dashboard et ajoutez un nouveau Tab. Nommez le MySensors par exemple. Ajoutez 2 groupes :

Le Dashboard ressemble à ça maintenant.

Changer de page par programmation (ui-control)

Ajoutons maintenant un composant ui-control qui permet de changer de page (tab) par programmation. Il accepte en entrée un payload sous 2 formes :

  • {tab:”MySensors”} on donne le nom de la page de destination. Attention, il faudra reporter tout changement de nom de la page dans le dashboard.
  • {tab:1} ou alors, on donne le numéro de la page. Idem, si on ré-ordonne les pages, il faudra appliquer le nouveau index dans le code.

Pour cela, ajoutez une fonction et collez ce code

var msg = {};
msg.payload = {tab:"MySensors"};    // ou/or 1

return msg;

On peut déclencher le passage à une autre page depuis un bouton de commande par exemple.

Connection et extraction des mesures de la sonde MySensors DHT22

Maintenant, connectons Node-RED à la gateway MySensors pour récupérer les mesures. Si vous débutez sur le sujet, commencez par lire cet article. Ce flow (code ci-dessous) utilise le flow de décodage des messages MySensors. Un premier filtre permet d’extraire la mesure de température du noeud qui nous intéresse. Le second filtre permet d’extraire la mesure d’humidité.

Code du flow de connexion et d’extraction des mesures

[{"id":"3d21e1ce.01afee","type":"tcp in","z":"df9159f.e304ea8","name":"MySensors Gateway","server":"client","host":"192.168.1.20","port":"5003","datamode":"stream","datatype":"utf8","newline":"","topic":"","base64":false,"x":210,"y":640,"wires":[["4fc18f88.1911"]]},{"id":"4fc18f88.1911","type":"function","z":"df9159f.e304ea8","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 timestamp = new Date();\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            newPayload.timestamp = timestamp;\n            newPayload.mode =       \"Presentation\";\n            newPayload.type =       labelPresentation[subType];\n            break;\n        case 1:     // Set\n            newPayload.timestamp = timestamp;\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.timestamp = timestamp;\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.timestamp = timestamp;\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.timestamp = timestamp;\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":360,"y":560,"wires":[["e32665a5.08e548","ff9b32b9.a232c"]]},{"id":"e32665a5.08e548","type":"function","z":"df9159f.e304ea8","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    msg.topic = \"temperature\"\n    return msg;\n}    ","outputs":1,"noerr":0,"x":640,"y":620,"wires":[["f80bd8b2.372db8","3f202da1.ad8562","a1e15601.1df708"]]},{"id":"ff9b32b9.a232c","type":"function","z":"df9159f.e304ea8","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    msg.topic = \"humidity\"\n    return msg;\n}    ","outputs":1,"noerr":0,"x":630,"y":660,"wires":[["cdcc69de.3c1538","5e7f2a5b.57ba14","a1e15601.1df708"]]}]

Afficher une jauge (ou donut, compass, level)

Il ne reste plus qu’à afficher les mesures dans une jauge. Ajoutez un composant jauge sur le flow. On dispose de 4 types de présentation :

  • Jauge adapté pour afficher une mesure sur un cadran. Par exemple toutes les mesures physiques dans une plage connue (température, humidité, pression atmosphérique, vitesse du vent…)
  • Donut adapté pour un affichage de plusieurs valeurs. Par exemple une répartition de puissance consommée par différents appareils
  • Compass adapté pour indiquer une direction. Par exemple la direction du vent mesuré par une girouette connectée.
  • Level adapté pour affiché un niveau. Par exemple le niveau de remplissage d’un réservoir (eau, fuel domestique…)

Ici nous choisirons le type jauge. Les autres paramètres importants sont :

  • Value format cette chaine permet de définir comment afficher la mesure. On peut ajouter du texte avant et après. La variable se présente sous la forme {{value}}. Node-RED remplacera cette variable par la valeur contenue dans le msg.payload en entrée. Par exemple, pour la température, on indiquera {{value}}°C pour ajouter l’unité après la mesure.
  • Label une étiquette placée en dessous de la valeur
  • Range plage de valeur minimum et maximum de l’afficheur
  • Color gradient (uniquement pour jauge et donut), on peut définir 3 couleurs, par exemple froid (bleu), tiède (orange), chaud (rouge).

Ce qui donne ceci

Afficher un graphique (chart)

Le module dashboard propose 2 types de graphiques :

  • En ligne (Line Chart). Il est très bien adapté à l’affichage de mesure en temps réel
  • En barre (Bar Chart). Comme le Donut, il est bien adapté pour comparer des mesures. Par exemple la température dans plusieurs pièces

Il est possible d’avoir plusieurs données sur un même graphique. Il suffit de “brancher” les flows sur le Node Chart. Le module Dashboard se charge de créer une donnée pour chaque payload entrant. Il faut essayer de mettre des mesures avec une plage assez proche (ou encore mieux de même nature) pour que le rendu soit correct.

Les autres paramètres du Node Chart :

  • Size : on peut adapter la taille pour avoir un affichage homogène
  • Label : libellé du graphique qui sera affiché au dessus de celui-ci
  • Type en ligne ou en barre
  • X-axis (uniquement pour Line Chart) base de temps de l’échelle de l’abscisse en secondes, heures, jours, semaine. On peut personnaliser l’affichage, par exemple H:M, H:M:S…
  • Y-axis échelle minimum et maximum de l’axe Y
  • Interpolate méthode d’interpolation entre deux points. C’est utile si les mesures sont très espacées dans le temps.
  • Legend affiche ou pas la légende. Pratique si on affiche plusieurs mesures sur un même graphique. Le Dashboard attribue automatiquement une couleur
  • Blank label : texte affiché s’il n’y a rien à tracer sur le graphique

Ce qui donne le graphique suivant

Zone de texte et notification furtive

Nous allons terminé la présentation du module Dashboard avec l’affichage d’un texte dans un champ et dans une notification furtive. Commençons par préparer la chaine de texte à afficher

Assembler plusieurs payload en une seule chaine de caractère

Node-RED est un système asynchrone, c’est à dire que les opérations ne se terminent pas forcément en même temps. Dans le cas présent (oui j’aurais pu le faire autrement, mais c’est un problème récurrent de Node-RED), j’ai extrait la température et l’humidité séparément. C’est nécessaire pour afficher simplement la mesure dans une jauge, mais ça ne nous arrange pas pour afficher le tout dans une notification. Voici comment faire.

Dans chaque filtre, j’ai ajouté un topic (par exemple température et humidity). On créé une variable de context; A chaque fois qu’un payload se présente dans le Node, on test le topic et on range la valeur dans l’objet de context. Ensuite on test si le context contient une valeur pour la température et l’humidité (et si elle n’est pas undefined). Si c’est le cas, on construit une chaine correctement formatée qu’il ne suffira plus qu’à afficher. Par exemple Température : 21.4°C – Humidité : 52.3%.

context.data = context.data || new Object();

switch (msg.topic) {
    case "Temperature":
        context.data.temperature = msg.payload;
        msg = null;
        break;
    case "Humidity":
        context.data.humidity = msg.payload;
        msg = null;
        break;
    default:
        msg = null;
        break;

}

if(context.data.temperature !== null && context.data.humidity !== null && context.data.temperature !== undefined && context.data.humidity !== undefined) {
    msgOut = ""; //new Object();
    msgOut = "Température : " 
    msgOut += context.data.temperature.toString(); 
    msgOut+= "°C - Humidité : "; 
    msgOut+= context.data.humidity.toString();
    msgOut+= "%";
    context.data=null;
    var msg = {};
    msg.payload = msgOut;
    return msg;
}

Le Node Text permet d’afficher très simplement du texte contenu dans un payload. On le configure comme ceci :

  • Size : la taille du champ
  • Label : le libellé du champ.
  • Value format : on peut personnaliser l’affichage de la valeur. Par exemple, si on veut ajouter une unité ou un préfixe. On pourrait aussi afficher le topic (msg.topic) ou accéder directement à un élément d’un objet JSON, par exemple msg.payload.data.valeur. Dans le cas présent, on ne changera rien.
  • Layout : permet de choisir un mode d’affichage. Le libellé collé à gauche, la valeur à droite ou une autre combinaison de position.

Ce qui donne

Afficher une notification furtive

Nous allons terminer ce tutoriel par la notification furtive. On peut choisir parmi 4 positions :

  • Coin supérieur droit (Top Right)
  • Coin inférieur droit (Bottom Right)
  • Coin supérieur gauche (Top Left)
  • Coin inférieur droit (Bottom Left)

On définit également la durée d’apparition du message furtif. Par défaut, 3 secondes.

Ce qui donne pour terminer un affichage plutôt sympa !

Créer un widget personnalisé avec le node template HTML / Angular

Pour en savoir plus sur la création de widget avec du code HTML / Angular, lisez cet article détaillé

Code complet du flow Node-RED

Importez simplement ce code dans un flow si vous ne voulez pas réaliser toutes les étapes. Ce flow contient également la 1ère partie de ce tutoriel.

[{"id":"6eecf682.454f38","type":"ui_button","z":"df9159f.e304ea8","name":"Bouton","group":"2a5abbd3.afa284","order":0,"width":0,"height":0,"label":"Bouton","color":"#fffff","icon":"fa-star","payload":"true","payloadType":"bool","topic":"Button","x":360,"y":100,"wires":[["1e96adb5.fd25e2"]]},{"id":"2a0c052c.dfe4ca","type":"ui_dropdown","z":"df9159f.e304ea8","name":"Liste de choix","label":"Choisissez ce que vous voulez","group":"2a5abbd3.afa284","order":0,"width":0,"height":0,"passthru":true,"options":[{"label":"Choix 1 : chaine","value":"Choix1","type":"str"},{"label":"Choix 2 : numérique","value":4,"type":"num"},{"label":"Choix 3 : bool","value":true,"type":"bool"}],"payload":"","topic":"Liste de choix","x":340,"y":140,"wires":[["1e96adb5.fd25e2"]]},{"id":"61be9b53.3a5ff4","type":"debug","z":"df9159f.e304ea8","name":"Dashboard Log","active":true,"console":"false","complete":"payload","x":900,"y":240,"wires":[]},{"id":"e7869632.cb19b8","type":"ui_switch","z":"df9159f.e304ea8","name":"Interrupteur","label":"switch","group":"2a5abbd3.afa284","order":0,"width":0,"height":0,"passthru":true,"topic":"Interrupteur","style":"","onvalue":"true","onvalueType":"bool","onicon":"","oncolor":"","offvalue":"false","offvalueType":"bool","officon":"","offcolor":"","x":350,"y":180,"wires":[["1e96adb5.fd25e2"]]},{"id":"6f4d5597.73fb0c","type":"ui_slider","z":"df9159f.e304ea8","name":"Slider","label":"slider","group":"2a5abbd3.afa284","order":0,"width":0,"height":0,"passthru":true,"topic":"Slider","min":0,"max":10,"step":1,"x":370,"y":220,"wires":[["1e96adb5.fd25e2"]]},{"id":"93c06deb.61b61","type":"ui_numeric","z":"df9159f.e304ea8","name":"","label":"numeric","group":"2a5abbd3.afa284","order":0,"width":0,"height":0,"passthru":true,"topic":"Numérique","format":"{{value}}","min":0,"max":10,"x":360,"y":260,"wires":[["1e96adb5.fd25e2"]]},{"id":"8f5cb4d9.8208a8","type":"ui_text_input","z":"df9159f.e304ea8","name":"","label":"Champ saisie de Texte","group":"2a5abbd3.afa284","order":0,"width":0,"height":0,"passthru":true,"mode":"text","delay":"0","topic":"Champ saisie de Texte","x":320,"y":300,"wires":[["1e96adb5.fd25e2"]]},{"id":"3375a2e.57b475e","type":"ui_form","z":"df9159f.e304ea8","name":"","label":"Un formulaire Node-RED","group":"febe591f.8ca1f8","order":0,"width":0,"height":0,"options":[{"label":"Du texte","value":"Texte","type":"text","required":true},{"label":"Un nombre","value":"Nombre","type":"number","required":false},{"label":"Un email","value":"email","type":"email","required":false},{"label":"Un mot de passe","value":"Mot de passe","type":"password","required":false},{"label":"Une case à cocher","value":"Case à cocher","type":"checkbox","required":false},{"label":"Un interrupteur","value":"Interrupteur","type":"switch","required":false}],"formValue":{"Texte":"","Nombre":"","email":"","Mot de passe":"","Case à cocher":false,"Interrupteur":false},"payload":"","topic":"Formulaire","x":310,"y":460,"wires":[["1e96adb5.fd25e2"]]},{"id":"1e96adb5.fd25e2","type":"function","z":"df9159f.e304ea8","name":"Enregistre les événements","func":"// Créé une variable pour stocker le journal du dashboard si inexistante\n// initialise the counter to 0 if it doesn't exist already\nvar dashboardLog = context.get('dashboardLog')|| [];\n\ndashboardLog.push(msg);\nif (dashboardLog.length > 20){\n    // Supprime le plus anciens message si > 20\n    // Delete oldest message if > 20\n    dashboardLog.shift();\n    dashboardLog.length = 20;\n} \n\n// Enregistre les messages du dashboard pour le prochain affichage\n// store the value back\ncontext.set('dashboardLog',dashboardLog);\n\n// Affiche le journal des messages\n// make it part of the outgoing msg object\nmsg = {};\nmsg.payload = dashboardLog;\nreturn msg;\n","outputs":1,"noerr":0,"x":660,"y":280,"wires":[["61be9b53.3a5ff4","7a421874.47f638"]]},{"id":"7a421874.47f638","type":"ui_template","z":"df9159f.e304ea8","group":"842b8d23.22294","name":"Journal des événement du Dashboard","order":1,"width":"8","height":"10","format":"
    \n

  • \n {{x.topic}}\n
      \n

    • {{x.payload}}
    • \n

    \n

  • \n

","storeOutMessages":true,"fwdInMessages":true,"x":970,"y":320,"wires":[[]]},{"id":"87bf88d.1fbd678","type":"ui_text_input","z":"df9159f.e304ea8","name":"","label":"Champ saisie email","group":"2a5abbd3.afa284","order":0,"width":0,"height":0,"passthru":true,"mode":"email","delay":300,"topic":"Champ saisie email","x":330,"y":340,"wires":[["1e96adb5.fd25e2"]]},{"id":"55e7b58f.cafe6c","type":"ui_text_input","z":"df9159f.e304ea8","name":"","label":"Champ saisie mot de passe","group":"2a5abbd3.afa284","order":0,"width":0,"height":0,"passthru":true,"mode":"password","delay":300,"topic":"Champ saisie mot de passe","x":300,"y":380,"wires":[["1e96adb5.fd25e2"]]},{"id":"21feb1b7.018a5e","type":"ui_text_input","z":"df9159f.e304ea8","name":"","label":"Sélecteur de couleur","group":"2a5abbd3.afa284","order":0,"width":0,"height":0,"passthru":true,"mode":"color","delay":300,"topic":"Sélecteur de couleur","x":320,"y":420,"wires":[["1e96adb5.fd25e2"]]},{"id":"baf63f2d.83977","type":"ui_text","z":"df9159f.e304ea8","group":"67f72709.c415f8","order":0,"width":0,"height":0,"name":"","label":"Dernière mesure","format":"{{msg.payload}}","layout":"row-spread","x":1140,"y":820,"wires":[]},{"id":"1d7d4ce7.8a5523","type":"ui_toast","z":"df9159f.e304ea8","position":"top right","displayTime":"5","name":"Notification","x":1130,"y":780,"wires":[]},{"id":"5e686a19.a16694","type":"ui_ui_control","z":"df9159f.e304ea8","name":"ui control","x":900,"y":500,"wires":[[]]},{"id":"4bb4277.686a0d8","type":"ui_button","z":"df9159f.e304ea8","name":"","group":"2a5abbd3.afa284","order":0,"width":0,"height":0,"label":"Aller aux capteurs MySensors","color":"","icon":"","payload":"","payloadType":"str","topic":"Vers Tab capteurs MySensors","x":310,"y":500,"wires":[["1e96adb5.fd25e2","ae9daf53.dbc43"]]},{"id":"ae9daf53.dbc43","type":"function","z":"df9159f.e304ea8","name":"Aller à MySensors","func":"var msg = {};\nmsg.payload = {tab:\"MySensors\"};    // ou/or 1\n\n\nreturn msg;","outputs":1,"noerr":0,"x":630,"y":500,"wires":[["5e686a19.a16694"]]},{"id":"3d21e1ce.01afee","type":"tcp in","z":"df9159f.e304ea8","name":"MySensors Gateway","server":"client","host":"192.168.1.20","port":"5003","datamode":"stream","datatype":"utf8","newline":"","topic":"","base64":false,"x":190,"y":640,"wires":[["4fc18f88.1911"]]},{"id":"4fc18f88.1911","type":"function","z":"df9159f.e304ea8","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 timestamp = new Date();\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            newPayload.timestamp = timestamp;\n            newPayload.mode =       \"Presentation\";\n            newPayload.type =       labelPresentation[subType];\n            break;\n        case 1:     // Set\n            newPayload.timestamp = timestamp;\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.timestamp = timestamp;\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.timestamp = timestamp;\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.timestamp = timestamp;\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":360,"y":560,"wires":[["e32665a5.08e548","ff9b32b9.a232c"]]},{"id":"e32665a5.08e548","type":"function","z":"df9159f.e304ea8","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    msg.topic = \"Temperature\"\n    return msg;\n}    ","outputs":1,"noerr":0,"x":640,"y":620,"wires":[["3f202da1.ad8562","a1e15601.1df708","f89448e5.9519d8"]]},{"id":"3f202da1.ad8562","type":"ui_gauge","z":"df9159f.e304ea8","name":"Gauge : Température","group":"67f72709.c415f8","order":0,"width":0,"height":0,"gtype":"gage","title":"Température DHT22","label":"MySensors v2","format":"{{value}}°C","min":0,"max":"50","colors":["#66ccff","#ff8000","#ca3838"],"x":940,"y":600,"wires":[]},{"id":"ff9b32b9.a232c","type":"function","z":"df9159f.e304ea8","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    msg.topic = \"Humidity\"\n    return msg;\n}    ","outputs":1,"noerr":0,"x":630,"y":660,"wires":[["cdcc69de.3c1538","a1e15601.1df708","f89448e5.9519d8"]]},{"id":"cdcc69de.3c1538","type":"ui_gauge","z":"df9159f.e304ea8","name":"Gauge : Humidité","group":"67f72709.c415f8","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":930,"y":640,"wires":[]},{"id":"a1e15601.1df708","type":"function","z":"df9159f.e304ea8","name":"Attendre temperature & humidité","func":"context.data = context.data || new Object();\n\nswitch (msg.topic) {\n    case \"Temperature\":\n        context.data.temperature = msg.payload;\n        msg = null;\n        break;\n    case \"Humidity\":\n        context.data.humidity = msg.payload;\n        msg = null;\n        break;\n    default:\n        msg = null;\n    \tbreak;\n\n}\n\nif(context.data.temperature !== null && context.data.humidity !== null && context.data.temperature !== undefined && context.data.humidity !== undefined) {\n\tmsgOut = \"\"; //new Object();\n    msgOut = \"Température : \" \n    msgOut += context.data.temperature.toString(); \n    msgOut+= \"°C - Humidité : \"; \n    msgOut+= context.data.humidity.toString();\n    msgOut+= \"%\";\n    context.data=null;\n    var msg = {};\n    msg.payload = msgOut;\n\treturn msg;\n} \n//else return msg;","outputs":1,"noerr":0,"x":980,"y":720,"wires":[["1d7d4ce7.8a5523","baf63f2d.83977"]]},{"id":"f89448e5.9519d8","type":"ui_chart","z":"df9159f.e304ea8","name":"Graph : Température & Humidité","group":"45ccf5ba.b188ac","order":0,"width":"6","height":"9","label":"Température & Humidité","chartType":"line","legend":"true","xformat":"%H:%M","interpolate":"linear","nodata":"Rien à afficher","ymin":"0","ymax":"80","removeOlder":"12","removeOlderUnit":"3600","x":970,"y":680,"wires":[[],[]]},{"id":"2a5abbd3.afa284","type":"ui_group","z":"","name":"Eléments d'entrée","tab":"99f501d2.56c31","order":1,"disp":true,"width":"8"},{"id":"febe591f.8ca1f8","type":"ui_group","z":"","name":"Formulaire","tab":"99f501d2.56c31","order":2,"disp":true,"width":"8"},{"id":"842b8d23.22294","type":"ui_group","z":"df9159f.e304ea8","name":"Journal des événements du Dashboard","tab":"99f501d2.56c31","order":3,"disp":true,"width":"8"},{"id":"67f72709.c415f8","type":"ui_group","z":"","name":"Mesures","tab":"70b0ee04.be689","order":1,"disp":true,"width":"6"},{"id":"45ccf5ba.b188ac","type":"ui_group","z":"","name":"Graphiques","tab":"70b0ee04.be689","order":2,"disp":true,"width":"6"},{"id":"99f501d2.56c31","type":"ui_tab","z":"","name":"Ecran Principal","icon":"home","order":2},{"id":"70b0ee04.be689","type":"ui_tab","z":"","name":"MySensors","icon":"dashboard","order":3}]

Avez-vous aimé cet article ?

[Total: 1 Moyenne: 5]