Skip to content

Node Red integration

sanderkob edited this page Feb 24, 2023 · 7 revisions

Pre-requisites

  • Node-RED is installed and configured
  • MQTT broker (e.g. Mosquitto) is installed
  • The CVE unit must be in "standard" or "medium" setting as per Itho design.

Steps

Import the Node-RED flow

You can also use "itho/#" where # is the wildcard for MQTT traffic so it captures all topics defined under "MQTT" in the add-on webpage, e.g. itho/ithostatus, itho/remotesinfo.

You get 2 nodes with flow down below that each listen to "state" and "sensor"

[
    {
        "id": "26a4fac610847e53",
        "type": "tab",
        "label": "ITHO Daalderop HVAC",
        "disabled": false,
        "info": "created for the nrg-addon"
    },
    {
        "id": "41bbb41dd8645b46",
        "type": "mqtt in",
        "z": "26a4fac610847e53",
        "name": "sensor-output",
        "topic": "Itho/sensor",
        "qos": "2",
        "datatype": "auto",
        "broker": "ff2de987.5f8a68",
        "nl": false,
        "rap": true,
        "rh": 0,
        "x": 410,
        "y": 120,
        "wires": [
            [
                "81c664d72f0c4396"
            ]
        ]
    },
    {
        "id": "81c664d72f0c4396",
        "type": "debug",
        "z": "26a4fac610847e53",
        "name": "debug-sensor-output",
        "active": false,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "false",
        "statusVal": "",
        "statusType": "auto",
        "x": 620,
        "y": 120,
        "wires": []
    },
    {
        "id": "e755a4408c62afc9",
        "type": "mqtt in",
        "z": "26a4fac610847e53",
        "name": "state-output",
        "topic": "Itho/state",
        "qos": "2",
        "datatype": "auto",
        "broker": "ff2de987.5f8a68",
        "nl": false,
        "rap": true,
        "rh": 0,
        "x": 390,
        "y": 180,
        "wires": [
            [
                "4f36ddf10333eba7"
            ]
        ]
    },
    {
        "id": "4f36ddf10333eba7",
        "type": "debug",
        "z": "26a4fac610847e53",
        "name": "debug-state-output",
        "active": false,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "false",
        "statusVal": "",
        "statusType": "auto",
        "x": 610,
        "y": 180,
        "wires": []
    },
    {
        "id": "ff2de987.5f8a68",
        "type": "mqtt-broker",
        "name": "",
        "broker": "localhost",
        "port": "1883",
        "clientid": "",
        "usetls": false,
        "protocolVersion": "4",
        "keepalive": "60",
        "cleansession": true,
        "birthTopic": "",
        "birthQos": "0",
        "birthPayload": "",
        "birthMsg": {},
        "closeTopic": "",
        "closeQos": "0",
        "closePayload": "",
        "closeMsg": {},
        "willTopic": "",
        "willQos": "0",
        "willPayload": "",
        "willMsg": {},
        "sessionExpiry": ""
    }
]

Extracting values from MQTT when labels have special characters (and for normal labels this works as well)

The most used notation to access elements of a JSON is using the dot notation. ie. to extract the key temperature from the payload in node-red: msg.payload.temperature

Although this works for normalized keys, this does not work for keys that have special characters. For this (but also for the mentioned example) the JavaScript bracket notation can be used.

ie. msg.payload['temperature'] instead of msg.payload.temperature or ie. payload['Fan speed (rpm)'] for the value of label 'Fan speed (rpm)' of the JSON on the MQTT topic itho/ithostatus

This also works nested. For a msg of type JSON with the following content {"first level":{"nested level":10}} the statement msg['first level']['nested level'] would pass the value 10 to the next node.

Simple example flow:

[{"id":"8d04620e7b4f9b97","type":"debug","z":"79360772.4553e8","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1070,"y":1720,"wires":[]},{"id":"2cdc290bb8e51f85","type":"change","z":"79360772.4553e8","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"itho_co2","tot":"global"}],"action":"","property":"","from":"","to":"","reg":false,"x":860,"y":1720,"wires":[["8d04620e7b4f9b97"]]},{"id":"fdca1683f90c9be8","type":"trigger","z":"79360772.4553e8","name":"","op1":"","op2":"","op1type":"date","op2type":"nul","duration":"1","extend":true,"overrideDelay":false,"units":"ms","reset":"","bytopic":"all","topic":"topic","outputs":1,"x":660,"y":1720,"wires":[["2cdc290bb8e51f85"]]},{"id":"a0b62caf5d330adb","type":"change","z":"79360772.4553e8","name":"","rules":[{"t":"set","p":"itho_co2","pt":"global","to":"payload['Highest CO2 concentration (ppm)']","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":390,"y":1720,"wires":[["fdca1683f90c9be8"]]},{"id":"7a57ac91d3cbc894","type":"mqtt in","z":"79360772.4553e8","name":"","topic":"itho/ithostatus","qos":"2","datatype":"json","broker":"b4eed736.102278","nl":false,"rap":true,"rh":0,"x":160,"y":1540,"wires":[["c12148d5d894edb0","6c21177deab25ac7","358ac2eb91d89950","c022aa4e833f686d","f5dc2e7677773603","dc906465f5ca55d8","a0b62caf5d330adb"]]},{"id":"b4eed736.102278","type":"mqtt-broker","name":"MQTT server","broker":"192.168.1.1","port":"1883","clientid":"","usetls":false,"compatmode":false,"protocolVersion":4,"keepalive":"60","cleansession":true,"birthTopic":"","birthQos":"0","birthPayload":"","closeTopic":"","closeQos":"0","closePayload":"","willTopic":"","willQos":"0","willPayload":""}]

Set values for Node-RED

A function (node) contents to set values for Node-RED

var temp = msg.payload.temperature.value;
var humi = msg.payload.humidity.value;
var batt = msg.status.battery;
var idx = msg.payload.idx;

msg.payload = {}

// Humidity Status
if (humi < 31) {
    humistat = "2";
} else if (humi > 69) {
    humistat = "3";
} else if (humi > 34 && humi < 66 && temp > 21 && temp < 27) {
    humistat = "1";
} else {
    humistat = "0";
}

msg.payload.idx = idx;
msg.payload.nvalue = 0;
msg.payload.svalue = temp.toString()+";"+humi.toString()+";"+humistat;
if (typeof batt !== 'undefined' && batt !== null){
msg.payload.Battery = Math.round(batt/9*100);
}

return msg;

The result of the above payload is:

{
  "idx":10,
  "nvalue":0,
  "svalue":"13.1;74;3",
  "Battery":100
}

Example of bathroom humidity monitoring

This script below communicates with the add-on through the api. An extended version has been published here: Node-red itho ventilation flow and monitors absolute humidity (shower) and presence (toilets), stops during the night, has night cooling and sends Telegram messages. Many variables are published to a Domoticz client. Interaction with the itho add-on is through web API calls.

image

[ { "id": "3dd6103ad43a8b44", "type": "tab", "label": "Flow 1", "disabled": false, "info": "" }, { "id": "46696f08d834fd2f", "type": "http request", "z": "3dd6103ad43a8b44", "name": "get ithostatus", "method": "GET", "ret": "obj", "paytoqs": "ignore", "url": "http://192.168.1.91/api.html?get=ithostatus", "tls": "", "persist": false, "proxy": "", "authType": "", "credentials": {}, "x": 150, "y": 860, "wires": [ [ "0a22200b47015429" ] ] }, { "id": "0a22200b47015429", "type": "change", "z": "3dd6103ad43a8b44", "name": "get ppmw", "rules": [ { "t": "set", "p": "payload", "pt": "msg", "to": "$round(payload.ppmw,0)", "tot": "jsonata" } ], "action": "", "property": "", "from": "", "to": "", "reg": false, "x": 180, "y": 920, "wires": [ [ "7bdf7b699cbced84" ] ] }, { "id": "c936450d68b013d0", "type": "stoptimer-varidelay", "z": "3dd6103ad43a8b44", "duration": "40", "durationType": "num", "units": "Minute", "payloadtype": "num", "payloadval": "0", "name": "40 minutes", "reporting": "last_minute_seconds", "persist": true, "ignoretimerpass": false, "x": 1030, "y": 1100, "wires": [ [ "ddbace9092efa18e" ], [], [] ] }, { "id": "78d799b6d9b47f28", "type": "change", "z": "3dd6103ad43a8b44", "name": "set high, reset low", "rules": [ { "t": "set", "p": "state_high", "pt": "global", "to": "true", "tot": "bool" }, { "t": "set", "p": "low", "pt": "global", "to": "false", "tot": "bool" } ], "action": "", "property": "", "from": "", "to": "", "reg": false, "x": 1130, "y": 960, "wires": [ [ "c936450d68b013d0", "3694f7919ea84cb6" ] ] }, { "id": "8ae5216b24c3c7c2", "type": "change", "z": "3dd6103ad43a8b44", "name": "itho 180", "rules": [ { "t": "set", "p": "payload", "pt": "msg", "to": "180", "tot": "num" } ], "action": "", "property": "", "from": "", "to": "", "reg": false, "x": 1640, "y": 940, "wires": [ [ "1bda9d1733a2dbe1" ] ] }, { "id": "e18b3c7efa9e107d", "type": "change", "z": "3dd6103ad43a8b44", "name": "STOP", "rules": [ { "t": "set", "p": "payload", "pt": "msg", "to": "STOP", "tot": "str" } ], "action": "", "property": "", "from": "", "to": "", "reg": false, "x": 850, "y": 1100, "wires": [ [ "c936450d68b013d0" ] ] }, { "id": "ac07c02b2adcd330", "type": "switch", "z": "3dd6103ad43a8b44", "name": "> 1000?", "property": "payload.ppmw-1000", "propertyType": "jsonata", "rules": [ { "t": "gt", "v": "payload.min", "vt": "msg" } ], "checkall": "true", "repair": false, "outputs": 1, "x": 920, "y": 960, "wires": [ [ "78d799b6d9b47f28" ] ] }, { "id": "425c75d9bfb84008", "type": "switch", "z": "3dd6103ad43a8b44", "name": "< -700?", "property": "payload.ppmw+700", "propertyType": "jsonata", "rules": [ { "t": "lt", "v": "payload.max", "vt": "msg" } ], "checkall": "true", "repair": false, "outputs": 1, "x": 1000, "y": 1180, "wires": [ [ "e18b3c7efa9e107d", "d62f5496b1e62a62" ] ] }, { "id": "2aab351fedcf3146", "type": "smooth", "z": "3dd6103ad43a8b44", "name": "max 8min", "property": "payload.max", "action": "max", "count": "96", "round": "", "mult": "single", "reduce": false, "x": 540, "y": 1180, "wires": [ [ "78c383bc4475c8dd" ] ] }, { "id": "aea68bd37d56b2fc", "type": "smooth", "z": "3dd6103ad43a8b44", "name": "min 8min", "property": "payload.min", "action": "min", "count": "96", "round": "", "mult": "single", "reduce": false, "x": 620, "y": 920, "wires": [ [ "b187e4529b635424" ] ] }, { "id": "78c383bc4475c8dd", "type": "switch", "z": "3dd6103ad43a8b44", "name": "if high", "property": "state_high", "propertyType": "global", "rules": [ { "t": "true" } ], "checkall": "true", "repair": false, "outputs": 1, "x": 690, "y": 1180, "wires": [ [ "80cba0d306d66dc8" ] ] }, { "id": "80cba0d306d66dc8", "type": "switch", "z": "3dd6103ad43a8b44", "name": "changed?", "property": "currentspeed", "propertyType": "global", "rules": [ { "t": "neq", "v": "180", "vt": "num" }, { "t": "eq", "v": "180", "vt": "num" } ], "checkall": "true", "repair": false, "outputs": 2, "x": 840, "y": 1180, "wires": [ [ "a167ad5b2ed05eec" ], [ "425c75d9bfb84008" ] ] }, { "id": "b187e4529b635424", "type": "switch", "z": "3dd6103ad43a8b44", "name": "if low", "property": "low", "propertyType": "global", "rules": [ { "t": "true" } ], "checkall": "true", "repair": false, "outputs": 1, "x": 770, "y": 940, "wires": [ [ "ac07c02b2adcd330", "bbbf2a481f165956" ] ] }, { "id": "7bdf7b699cbced84", "type": "smooth", "z": "3dd6103ad43a8b44", "name": "avg 3", "property": "payload", "action": "mean", "count": "3", "round": "0", "mult": "multi", "reduce": false, "x": 190, "y": 980, "wires": [ [ "5951881fb9214cef" ] ] }, { "id": "d06b64737c81ad83", "type": "stoptimer-varidelay", "z": "3dd6103ad43a8b44", "duration": "10", "durationType": "num", "units": "Minute", "payloadtype": "num", "payloadval": "0", "name": "10 minutes", "reporting": "last_minute_seconds", "persist": false, "ignoretimerpass": false, "x": 1330, "y": 1180, "wires": [ [ "f4cf8a6ceb9d16ec" ], [], [] ] }, { "id": "b55553cb678b6675", "type": "change", "z": "3dd6103ad43a8b44", "name": "save speed", "rules": [ { "t": "set", "p": "savedspeed", "pt": "global", "to": "currentspeed", "tot": "global" } ], "action": "", "property": "", "from": "", "to": "", "reg": false, "x": 1490, "y": 940, "wires": [ [ "8ae5216b24c3c7c2" ] ] }, { "id": "bbbf2a481f165956", "type": "switch", "z": "3dd6103ad43a8b44", "name": "ppmw >15000?", "property": "payload.ppmw", "propertyType": "msg", "rules": [ { "t": "gt", "v": "15000", "vt": "num" } ], "checkall": "true", "repair": true, "outputs": 1, "x": 940, "y": 920, "wires": [ [ "f5dd5a449658d0d9" ] ] }, { "id": "d62f5496b1e62a62", "type": "change", "z": "3dd6103ad43a8b44", "name": "reset high", "rules": [ { "t": "set", "p": "state_high", "pt": "global", "to": "false", "tot": "bool" } ], "action": "", "property": "", "from": "", "to": "", "reg": false, "x": 1160, "y": 1180, "wires": [ [ "d06b64737c81ad83" ] ] }, { "id": "ddbace9092efa18e", "type": "change", "z": "3dd6103ad43a8b44", "name": "reset high, set low", "rules": [ { "t": "set", "p": "state_high", "pt": "global", "to": "false", "tot": "bool" }, { "t": "set", "p": "low", "pt": "global", "to": "true", "tot": "bool" } ], "action": "", "property": "", "from": "", "to": "", "reg": false, "x": 1210, "y": 1080, "wires": [ [ "ac9a1187403536d8" ] ] }, { "id": "a167ad5b2ed05eec", "type": "change", "z": "3dd6103ad43a8b44", "name": "reset high, set low", "rules": [ { "t": "set", "p": "state_high", "pt": "global", "to": "false", "tot": "bool" }, { "t": "set", "p": "low", "pt": "global", "to": "true", "tot": "bool" } ], "action": "", "property": "", "from": "", "to": "", "reg": false, "x": 670, "y": 1100, "wires": [ [ "e18b3c7efa9e107d" ] ] }, { "id": "f4cf8a6ceb9d16ec", "type": "change", "z": "3dd6103ad43a8b44", "name": "set low", "rules": [ { "t": "set", "p": "low", "pt": "global", "to": "true", "tot": "bool" } ], "action": "", "property": "", "from": "", "to": "", "reg": false, "x": 1500, "y": 1160, "wires": [ [ "ac9a1187403536d8" ] ] }, { "id": "f5dd5a449658d0d9", "type": "change", "z": "3dd6103ad43a8b44", "name": "set hum, reset low", "rules": [ { "t": "set", "p": "hum", "pt": "global", "to": "true", "tot": "bool" }, { "t": "set", "p": "low", "pt": "global", "to": "false", "tot": "bool" } ], "action": "", "property": "", "from": "", "to": "", "reg": false, "x": 1130, "y": 920, "wires": [ [ "3694f7919ea84cb6" ] ] }, { "id": "c4f252231f26bdc2", "type": "switch", "z": "3dd6103ad43a8b44", "name": "ppmw <14500", "property": "payload.ppmw", "propertyType": "msg", "rules": [ { "t": "lt", "v": "14500", "vt": "num" } ], "checkall": "true", "repair": true, "outputs": 1, "x": 940, "y": 1020, "wires": [ [ "f139fd931221c692" ] ] }, { "id": "f139fd931221c692", "type": "change", "z": "3dd6103ad43a8b44", "name": "reset hum, set low", "rules": [ { "t": "set", "p": "hum", "pt": "global", "to": "false", "tot": "bool" }, { "t": "set", "p": "low", "pt": "global", "to": "true", "tot": "bool" } ], "action": "", "property": "", "from": "", "to": "", "reg": false, "x": 1130, "y": 1020, "wires": [ [ "ac9a1187403536d8" ] ] }, { "id": "aeb4a69e4266862c", "type": "switch", "z": "3dd6103ad43a8b44", "name": "if hum", "property": "hum", "propertyType": "global", "rules": [ { "t": "true" } ], "checkall": "true", "repair": false, "outputs": 1, "x": 610, "y": 1000, "wires": [ [ "c4f252231f26bdc2" ] ] }, { "id": "1bda9d1733a2dbe1", "type": "http request", "z": "3dd6103ad43a8b44", "name": "set speed", "method": "GET", "ret": "txt", "paytoqs": "ignore", "url": "http://192.168.1.91/api.html?speed={{{payload}}}", "tls": "", "persist": false, "proxy": "", "authType": "", "credentials": {}, "x": 1780, "y": 1000, "wires": [ [] ] }, { "id": "ac9a1187403536d8", "type": "change", "z": "3dd6103ad43a8b44", "name": "itho low", "rules": [ { "t": "set", "p": "payload", "pt": "msg", "to": "savedspeed", "tot": "global" } ], "action": "", "property": "", "from": "", "to": "", "reg": false, "x": 1400, "y": 1040, "wires": [ [ "1bda9d1733a2dbe1" ] ] }, { "id": "5951881fb9214cef", "type": "function", "z": "3dd6103ad43a8b44", "name": "set min, max", "func": "ppmw=msg.payload;\nmsg.payload={ppmw:ppmw, max: ppmw,min:ppmw};\nmsg.payload.min=ppmw;\nmsg.payload.max=ppmw;\nreturn msg;", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 430, "y": 960, "wires": [ [ "2aab351fedcf3146", "aea68bd37d56b2fc", "aeb4a69e4266862c" ] ] }, { "id": "3694f7919ea84cb6", "type": "switch", "z": "3dd6103ad43a8b44", "name": "speed <180?", "property": "currentspeed", "propertyType": "global", "rules": [ { "t": "lt", "v": "180", "vt": "num" } ], "checkall": "true", "repair": false, "outputs": 1, "x": 1330, "y": 940, "wires": [ [ "b55553cb678b6675" ] ] } ]