Since someone has asked for my code, here it is.
Use it as inspiration source only, it was not designed to be reused for other systems.
Missing are all the MQTT nodes, at the begin and/or the end of the flows. It should be relatively obvious where they should go.
Node-red : regulation
[
{
"id": "8b5865a5.a04078",
"type": "function",
"z": "49319db8.e1b464",
"name": "Manage defaulted zones",
"func": "//When a zone has no new temperature readings for a long time, it will \"copy\" what a defaultZone does\n\nvar MAX_INTERVAL_READINGS = 3600; //Max sec. between two readings before defaulting\n//Idéalement, doit être plus long que le plus long temps d'hysteresis\n\nvar defaultZone = \"Salon\" //Zone to default to\n\n\n// Code\n\n//Désactivate automatic regulation\nif (global.get(\"Regulation\") !== undefined && global.get(\"Regulation\") < 1) {\n return null;\n}\n\ncurrentTime = Math.round((new Date()).getTime() / 1000);\n\nvar zonesArray = flow.get(\"zonesArray\");\nvar defaultedZones = [];\n\nmsg.zonesArray = zonesArray;\n\nif (zonesArray[defaultZone] === undefined || zonesArray[defaultZone][\"lastUpdate\"] === undefined || currentTime - zonesArray[defaultZone][\"lastUpdate\"] > MAX_INTERVAL_READINGS) {\n //All hope is lost…\n node.status({fill:\"red\",shape:\"ring\",text:defaultZone + \" has defaulted… :'(\"});\n return null;\n}\n\nfor (var zone in zonesArray) {\n if (zonesArray[zone][\"lastUpdate\"] === undefined || currentTime - zonesArray[zone][\"lastUpdate\"] > MAX_INTERVAL_READINGS && zone != defaultZone) {\n defaultedZones.push(zone);\n }\n}\n\n//debug\nmsg.defaultedZones = defaultedZones;\n\nif (defaultedZones.length > 0) {\n node.status({fill:\"red\",shape:\"dot\",text:\"Some zone(s) have defaulted.\"});\n var newMessages = [[]];\n var defaultedState = zonesArray[defaultZone][\"state\"];\n \n for (var zone in defaultedZones) {\n newMessages[0].push({payload:defaultedState, zone:defaultedZones[zone]});\n }\n msg.newMessages = newMessages;\n //return msg;\n return newMessages;\n}\nelse {\n node.status({fill:\"green\",shape:\"dot\",text:\"No zone has defaulted.\"});\n return null;\n}",
"outputs": 1,
"noerr": 0,
"x": 330,
"y": 740,
"wires": [
[
"2c7399f5.10bde6",
"d25d775d.365da"
]
]
},
{
"id": "2b2b317a.fd6fe6",
"type": "switch",
"z": "49319db8.e1b464",
"name": "Thermometres",
"property": "topic",
"propertyType": "msg",
"rules": [
{
"t": "cont",
"v": "/Salon_Temperature",
"vt": "str"
},
{
"t": "cont",
"v": "/Cuisine_Temperature",
"vt": "str"
},
{
"t": "cont",
"v": "/Bureau_Temperature",
"vt": "str"
},
{
"t": "cont",
"v": "/Mezzanine_Temperature",
"vt": "str"
},
{
"t": "cont",
"v": "/PetitSalon_Temperature",
"vt": "str"
},
{
"t": "cont",
"v": "/ChParents_Temperature",
"vt": "str"
},
{
"t": "cont",
"v": "/ChQuentin_Temperature",
"vt": "str"
},
{
"t": "cont",
"v": "/Hall_Temperature",
"vt": "str"
},
{
"t": "cont",
"v": "/SdBParents_Temperature",
"vt": "str"
}
],
"checkall": "false",
"outputs": 9,
"x": 380,
"y": 440,
"wires": [
[
"6fa2e03b.54e1f8"
],
[
"a9d2a359.bf2da8"
],
[
"22474adb.5340ae"
],
[
"11a3ebcf.d9097c"
],
[
"2bb881ea.7a103e"
],
[
"9c5ebee1.fd5d8"
],
[
"253014.5fbda7ec"
],
[
"9b653647.b7e868"
],
[
"9af1ae3d.55b258"
]
]
},
{
"id": "6fa2e03b.54e1f8",
"type": "function",
"z": "49319db8.e1b464",
"name": "Salon",
"func": "//Only change this variable\nmsg.zone = \"Salon\";\n\n\n//Code\nmsg.newTemp = parseFloat(msg.payload);\nif (isNaN(msg.newTemp)) {\n node.error(\"Invalid temp received\", msg);\n return null;\n}\nmsg.consigne = global.get(msg.zone + \"_Setpoint\");\n\nif (msg.consigne === undefined){\n node.error(\"No valid schedule found !\", msg);\n return null;\n}\n\nif (msg.consigne > msg.newTemp + msg.hysteresis) {\n msg.payload = \"ON\";\n node.status({fill:\"green\",shape:\"dot\",text:\"Heating\"});\n}\nelse if (msg.consigne < msg.newTemp - msg.hysteresis) {\n msg.payload = \"OFF\";\n node.status({fill:\"red\",shape:\"dot\",text:\"Not heating\"});\n}\nelse {\n msg.payload = \"HYSTERESIS\";\n node.status({fill:\"grey\",shape:\"dot\",text:\"Hysteresis…\"});\n}\nreturn msg;",
"outputs": 1,
"noerr": 0,
"x": 550,
"y": 180,
"wires": [
[
"6b5ce50f.17177c",
"fb60fd21.038b"
]
]
},
{
"id": "72deaffd.89ea3",
"type": "function",
"z": "49319db8.e1b464",
"name": "Set variables",
"func": "//Remove unused vars\ndelete msg.qos;\ndelete msg.retain;\n\n//Set vars\nmsg.hysteresis = 0.1;\n\n//Desactivate regulation if we want to do thing manually\nif (global.get(\"Regulation\") !== undefined && global.get(\"Regulation\") < 1) {\n return null;\n}\nelse {\n return msg;\n}",
"outputs": 1,
"noerr": 0,
"x": 210,
"y": 440,
"wires": [
[
"2b2b317a.fd6fe6"
]
]
},
{
"id": "6b5ce50f.17177c",
"type": "switch",
"z": "49319db8.e1b464",
"name": "Radiateurs?",
"property": "zone",
"propertyType": "msg",
"rules": [
{
"t": "eq",
"v": "ChParents",
"vt": "str"
},
{
"t": "else"
}
],
"checkall": "false",
"outputs": 2,
"x": 790,
"y": 440,
"wires": [
[
"81a4ab2d.169738"
],
[
"372c7ceb.061e4c"
]
]
},
{
"id": "372c7ceb.061e4c",
"type": "function",
"z": "49319db8.e1b464",
"name": "Contrôle pompe sol",
"func": "/*\nPasses msg on output 1 and create a second message for the pump on output 2.\n */\n\nvar zonesArray = flow.get(\"zonesArray\");\n//We need to create the object\nif (!(zonesArray instanceof Object)) {\n zonesArray = {};\n}\n\nif (msg.payload == \"HYSTERESIS\" && zonesArray[msg.zone] !== undefined) {\n //Just update 'lastUpdate', do not change 'state'\n zonesArray[msg.zone][\"lastUpdate\"] = Math.round((new Date()).getTime() / 1000);\n}\nelse {\n zonesArray[msg.zone] = {state:msg.payload, lastUpdate:Math.round((new Date()).getTime() / 1000)};\n}\n\nflow.set(\"zonesArray\", zonesArray); //Save the array for later use\nif (msg.payload == \"HYSTERESIS\") {\n return null;\n}\n\nvar pump = \"OFF\";\nnode.status({fill:\"red\",shape:\"dot\",text:\"Off\"});\nfor (var zone in zonesArray) {\n if (zonesArray[zone][\"state\"] == \"ON\" || zonesArray[zone][\"state\"] >= 5) {\n pump = \"ON\";\n node.status({fill:\"green\",shape:\"dot\",text:\"On\"});\n }\n}\n\nvar pumpMsg = {payload: pump, topic: \"/openhab/in/command/Sol_Pump\"};\nreturn [msg, pumpMsg];",
"outputs": "2",
"noerr": 0,
"x": 1000,
"y": 460,
"wires": [
[
"d25d775d.365da"
],
[
"a36df686.1f096",
"6fb853ab.9165fc"
]
]
},
{
"id": "d25d775d.365da",
"type": "function",
"z": "49319db8.e1b464",
"name": "Change Topic",
"func": "//Will *delete* msg and create new message(s) to control individual 'chapeaux'.\n\n\n\nif (msg.zone == \"Salon\") {\n return {payload: msg.payload, topic:\"/openhab/in/command/Salon_Chapeau\"};\n}\nelse if (msg.zone == \"Cuisine\") {\n return {payload: msg.payload, topic:\"/openhab/in/command/Cuisine_Chapeau\"};\n}\nelse if (msg.zone == \"Bureau\") {\n return {payload: msg.payload, topic:\"/openhab/in/command/Bureau_Chapeau\"};\n}\nelse if (msg.zone == \"Mezzanine\") {\n return {payload: msg.payload, topic:\"/openhab/in/command/Mezzanine_Chapeau\"};\n}\nelse if (msg.zone == \"PetitSalon\") {\n return {payload: msg.payload, topic:\"/openhab/in/command/PetitSalon_Chapeau\"};\n}\nelse if (msg.zone == \"ChParents\") {\n return null; //Separate circuit with only pump, no chapeau\n}\nelse if (msg.zone == \"ChQuentin\") {\n return {payload: msg.payload, topic:\"/openhab/in/command/ChQuentin_Chapeau\"};\n}\nelse if (msg.zone == \"Hall\") {\n return [[{payload: msg.payload, topic:\"/openhab/in/command/HallBas_Chapeau\"}, {payload: msg.payload, topic:\"/openhab/in/command/HallHaut_Chapeau\"}]];\n}\nelse if (msg.zone == \"SdBParents\") {\n return {payload: msg.payload, topic:\"/openhab/in/command/SdBParents_Chapeau\"};\n}\nelse{\n node.error(\"Unknown zone\", msg);\n return null;\n}",
"outputs": 1,
"noerr": 0,
"x": 1340,
"y": 600,
"wires": [
[
"e09d60f9.577178"
]
]
},
{
"id": "81a4ab2d.169738",
"type": "function",
"z": "49319db8.e1b464",
"name": "Contrôle pompe radiateur",
"func": "/*\nPasses msg on output 1 and create a second message for the pump on output 2.\n */\n\nvar pump;\n\nif (msg.payload == \"HYSTERESIS\") {\n return null; //Just stay the way we are\n}\n\nif (msg.payload == \"ON\" || msg.payload >= 5) {\n pump = \"ON\";\n node.status({fill:\"green\",shape:\"dot\",text:\"On\"});\n}\nelse {\n pump = \"OFF\";\n node.status({fill:\"red\",shape:\"dot\",text:\"Off\"});\n}\n\nvar pumpMsg = {payload: pump, topic: \"/openhab/in/command/Radiateurs_Pump\"};\nreturn [msg, pumpMsg];",
"outputs": "2",
"noerr": 0,
"x": 1010,
"y": 400,
"wires": [
[
"d25d775d.365da"
],
[
"a36df686.1f096",
"7ca6cbf.9713734"
]
]
},
{
"id": "9c5ebee1.fd5d8",
"type": "function",
"z": "49319db8.e1b464",
"name": "ChParents",
"func": "//Only change this variable\nmsg.zone = \"ChParents\";\n\n\n//Code\nmsg.newTemp = parseFloat(msg.payload);\nif (isNaN(msg.newTemp)) {\n node.error(\"Invalid temp received\", msg);\n return null;\n}\nmsg.consigne = global.get(msg.zone + \"_Setpoint\");\n\nif (msg.consigne === undefined){\n node.error(\"No valid schedule found !\", msg);\n return null;\n}\n\nif (msg.consigne > msg.newTemp + msg.hysteresis) {\n msg.payload = \"ON\";\n node.status({fill:\"green\",shape:\"dot\",text:\"Heating\"});\n}\nelse if (msg.consigne < msg.newTemp - msg.hysteresis) {\n msg.payload = \"OFF\";\n node.status({fill:\"red\",shape:\"dot\",text:\"Not heating\"});\n}\nelse {\n msg.payload = \"HYSTERESIS\";\n node.status({fill:\"grey\",shape:\"dot\",text:\"Hysteresis…\"});\n}\nreturn msg;",
"outputs": 1,
"noerr": 0,
"x": 570,
"y": 480,
"wires": [
[
"6b5ce50f.17177c",
"fb60fd21.038b"
]
]
},
{
"id": "a9d2a359.bf2da8",
"type": "function",
"z": "49319db8.e1b464",
"name": "Cuisine",
"func": "//Only change this variable\nmsg.zone = \"Cuisine\";\n\n\n//Code\nmsg.newTemp = parseFloat(msg.payload);\nif (isNaN(msg.newTemp)) {\n node.error(\"Invalid temp received\", msg);\n return null;\n}\nmsg.consigne = global.get(msg.zone + \"_Setpoint\");\n\nif (msg.consigne === undefined){\n node.error(\"No valid schedule found !\", msg);\n return null;\n}\n\nif (msg.consigne > msg.newTemp + msg.hysteresis) {\n msg.payload = \"ON\";\n node.status({fill:\"green\",shape:\"dot\",text:\"Heating\"});\n}\nelse if (msg.consigne < msg.newTemp - msg.hysteresis) {\n msg.payload = \"OFF\";\n node.status({fill:\"red\",shape:\"dot\",text:\"Not heating\"});\n}\nelse {\n msg.payload = \"HYSTERESIS\";\n node.status({fill:\"grey\",shape:\"dot\",text:\"Hysteresis…\"});\n}\nreturn msg;",
"outputs": 1,
"noerr": 0,
"x": 560,
"y": 240,
"wires": [
[
"6b5ce50f.17177c",
"fb60fd21.038b"
]
]
},
{
"id": "22474adb.5340ae",
"type": "function",
"z": "49319db8.e1b464",
"name": "Bureau",
"func": "//Only change this variable\nmsg.zone = \"Bureau\";\n\n\n//Code\nmsg.newTemp = parseFloat(msg.payload);\nif (isNaN(msg.newTemp)) {\n node.error(\"Invalid temp received\", msg);\n return null;\n}\nmsg.consigne = global.get(msg.zone + \"_Setpoint\");\n\nif (msg.consigne === undefined){\n node.error(\"No valid schedule found !\", msg);\n return null;\n}\n\nif (msg.consigne > msg.newTemp + msg.hysteresis) {\n msg.payload = \"ON\";\n node.status({fill:\"green\",shape:\"dot\",text:\"Heating\"});\n}\nelse if (msg.consigne < msg.newTemp - msg.hysteresis) {\n msg.payload = \"OFF\";\n node.status({fill:\"red\",shape:\"dot\",text:\"Not heating\"});\n}\nelse {\n msg.payload = \"HYSTERESIS\";\n node.status({fill:\"grey\",shape:\"dot\",text:\"Hysteresis…\"});\n}\nreturn msg;",
"outputs": 1,
"noerr": 0,
"x": 560,
"y": 300,
"wires": [
[
"6b5ce50f.17177c",
"fb60fd21.038b"
]
]
},
{
"id": "11a3ebcf.d9097c",
"type": "function",
"z": "49319db8.e1b464",
"name": "Mezzanine",
"func": "//Only change this variable\nmsg.zone = \"Mezzanine\";\n\n\n//Code\nmsg.newTemp = parseFloat(msg.payload);\nif (isNaN(msg.newTemp)) {\n node.error(\"Invalid temp received\", msg);\n return null;\n}\nmsg.consigne = global.get(msg.zone + \"_Setpoint\");\n\nif (msg.consigne === undefined){\n node.error(\"No valid schedule found !\", msg);\n return null;\n}\n\nif (msg.consigne > msg.newTemp + msg.hysteresis) {\n msg.payload = \"ON\";\n node.status({fill:\"green\",shape:\"dot\",text:\"Heating\"});\n}\nelse if (msg.consigne < msg.newTemp - msg.hysteresis) {\n msg.payload = \"OFF\";\n node.status({fill:\"red\",shape:\"dot\",text:\"Not heating\"});\n}\nelse {\n msg.payload = \"HYSTERESIS\";\n node.status({fill:\"grey\",shape:\"dot\",text:\"Hysteresis…\"});\n}\nreturn msg;",
"outputs": 1,
"noerr": 0,
"x": 570,
"y": 360,
"wires": [
[
"6b5ce50f.17177c",
"fb60fd21.038b"
]
]
},
{
"id": "253014.5fbda7ec",
"type": "function",
"z": "49319db8.e1b464",
"name": "ChQuentin",
"func": "//Only change this variable\nmsg.zone = \"ChQuentin\";\n\n\n//Code\nmsg.newTemp = parseFloat(msg.payload);\nif (isNaN(msg.newTemp)) {\n node.error(\"Invalid temp received\", msg);\n return null;\n}\nmsg.consigne = global.get(msg.zone + \"_Setpoint\");\n\nif (msg.consigne === undefined){\n node.error(\"No valid schedule found !\", msg);\n return null;\n}\n\nif (msg.consigne > msg.newTemp + msg.hysteresis) {\n msg.payload = \"ON\";\n node.status({fill:\"green\",shape:\"dot\",text:\"Heating\"});\n}\nelse if (msg.consigne < msg.newTemp - msg.hysteresis) {\n msg.payload = \"OFF\";\n node.status({fill:\"red\",shape:\"dot\",text:\"Not heating\"});\n}\nelse {\n msg.payload = \"HYSTERESIS\";\n node.status({fill:\"grey\",shape:\"dot\",text:\"Hysteresis…\"});\n}\nreturn msg;",
"outputs": 1,
"noerr": 0,
"x": 570,
"y": 540,
"wires": [
[
"6b5ce50f.17177c",
"fb60fd21.038b"
]
]
},
{
"id": "9b653647.b7e868",
"type": "function",
"z": "49319db8.e1b464",
"name": "Hall",
"func": "//Only change this variable\nmsg.zone = \"Hall\";\n\n\n//Code\nmsg.newTemp = parseFloat(msg.payload);\nif (isNaN(msg.newTemp)) {\n node.error(\"Invalid temp received\", msg);\n return null;\n}\nmsg.consigne = global.get(msg.zone + \"_Setpoint\");\n\nif (msg.consigne === undefined){\n node.error(\"No valid schedule found !\", msg);\n return null;\n}\n\nif (msg.consigne > msg.newTemp + msg.hysteresis) {\n msg.payload = \"ON\";\n node.status({fill:\"green\",shape:\"dot\",text:\"Heating\"});\n}\nelse if (msg.consigne < msg.newTemp - msg.hysteresis) {\n msg.payload = \"OFF\";\n node.status({fill:\"red\",shape:\"dot\",text:\"Not heating\"});\n}\nelse {\n msg.payload = \"HYSTERESIS\";\n node.status({fill:\"grey\",shape:\"dot\",text:\"Hysteresis…\"});\n}\nreturn msg;",
"outputs": 1,
"noerr": 0,
"x": 550,
"y": 600,
"wires": [
[
"6b5ce50f.17177c",
"fb60fd21.038b"
]
]
},
{
"id": "9af1ae3d.55b258",
"type": "function",
"z": "49319db8.e1b464",
"name": "SdBParents",
"func": "//Only change this variable\nmsg.zone = \"SdBParents\";\n\n\n//Code\nmsg.newTemp = parseFloat(msg.payload);\nif (isNaN(msg.newTemp)) {\n node.error(\"Invalid temp received\", msg);\n return null;\n}\nmsg.consigne = global.get(msg.zone + \"_Setpoint\");\n\nif (msg.consigne === undefined){\n node.error(\"No valid schedule found !\", msg);\n return null;\n}\n\nif (msg.consigne > msg.newTemp + msg.hysteresis) {\n msg.payload = \"ON\";\n node.status({fill:\"green\",shape:\"dot\",text:\"Heating\"});\n}\nelse if (msg.consigne < msg.newTemp - msg.hysteresis) {\n msg.payload = \"OFF\";\n node.status({fill:\"red\",shape:\"dot\",text:\"Not heating\"});\n}\nelse {\n msg.payload = \"HYSTERESIS\";\n node.status({fill:\"grey\",shape:\"dot\",text:\"Hysteresis…\"});\n}\nreturn msg;",
"outputs": 1,
"noerr": 0,
"x": 570,
"y": 660,
"wires": [
[
"6b5ce50f.17177c",
"fb60fd21.038b"
]
]
},
{
"id": "a2faa2b1.9f65f",
"type": "inject",
"z": "49319db8.e1b464",
"name": "Every hour",
"topic": "",
"payload": "",
"payloadType": "date",
"repeat": "3600",
"crontab": "",
"once": false,
"x": 90,
"y": 740,
"wires": [
[
"8b5865a5.a04078"
]
]
},
{
"id": "2c7399f5.10bde6",
"type": "debug",
"z": "49319db8.e1b464",
"name": "",
"active": false,
"console": "false",
"complete": "true",
"x": 610,
"y": 740,
"wires": []
},
{
"id": "a36df686.1f096",
"type": "function",
"z": "49319db8.e1b464",
"name": "Contrôle temperature eau",
"func": "//To see which setpoints to use, check nodered on rpi-chaudiere\nsolTemp = 40;\nradiateursTemp = 55;\n\nsolTempOff = 20;\nradiateursTempOff = 20;\n\nradTopicIn = \"/openhab/in/command/Radiateurs_Pump\";\nsolTopicIn = \"/openhab/in/command/Sol_Pump\"\nchaudiereTopicOut = \"/openhab/in/command/Chaudiere_Setpoint\";\nsolTopicOut = \"/openhab/in/command/DepartSol_Setpoint\";\n\n\n//Code\nif (msg.payload != \"ON\" && msg.payload != \"OFF\") {\n node.error(\"Received msg with wrong payload.\", msg);\n return null;\n}\n\nif (msg.topic == radTopicIn) {\n context.set(\"pumpRadiateurs\", msg.payload);\n}\nelse if (msg.topic == solTopicIn) {\n context.set(\"pumpSol\", msg.payload);\n}\nelse {\n node.error(\"Received msg with wrong topic.\", msg);\n return null;\n}\n\nvar startSol;\nvar startRadiateurs;\nif (context.get(\"pumpSol\") === undefined || context.get(\"pumpSol\") == \"OFF\") {\n startSol = false;\n}\nelse {\n startSol = true;\n}\nif (context.get(\"pumpRadiateurs\") === undefined || context.get(\"pumpRadiateurs\") == \"OFF\") {\n startRadiateurs = false;\n}\nelse {\n startRadiateurs = true;\n}\n\nvar msgTempSol = {topic:solTopicOut};\nvar msgTempChaudiere = {topic:chaudiereTopicOut};\nif (!startSol && !startRadiateurs) {\n msgTempSol.payload = solTempOff;\n msgTempChaudiere.payload = radiateursTempOff;\n}\nelse if (!startSol && startRadiateurs) {\n msgTempSol.payload = solTempOff;\n msgTempChaudiere.payload = radiateursTemp;\n}\nelse if (startSol && !startRadiateurs) {\n msgTempSol.payload = solTemp;\n msgTempChaudiere.payload = solTemp;\n}\nelse if (startSol && startRadiateurs) {\n msgTempSol.payload = solTemp;\n msgTempChaudiere.payload = radiateursTemp;\n}\n\nreturn [msgTempSol, msgTempChaudiere];",
"outputs": "2",
"noerr": 0,
"x": 1370,
"y": 420,
"wires": [
[
"2921d9ac.576896"
],
[
"c8408e29.9dea3"
]
]
},
{
"id": "3f926e04.fb64da",
"type": "comment",
"z": "49319db8.e1b464",
"name": "Parametres température eau",
"info": "",
"x": 1380,
"y": 380,
"wires": []
},
{
"id": "9d8f375.5e4a848",
"type": "comment",
"z": "49319db8.e1b464",
"name": "Paramètre hystéresis",
"info": "",
"x": 220,
"y": 400,
"wires": []
},
{
"id": "b1522e8f.67e41",
"type": "comment",
"z": "49319db8.e1b464",
"name": "Paramètre zones sans mesure récente",
"info": "",
"x": 350,
"y": 700,
"wires": []
},
{
"id": "fb60fd21.038b",
"type": "debug",
"z": "49319db8.e1b464",
"name": "",
"active": false,
"console": "false",
"complete": "true",
"x": 770,
"y": 400,
"wires": []
},
{
"id": "2bb881ea.7a103e",
"type": "function",
"z": "49319db8.e1b464",
"name": "Petit Salon",
"func": "//Only change this variable\nmsg.zone = \"PetitSalon\";\n\n\n//Code\nmsg.newTemp = parseFloat(msg.payload);\nif (isNaN(msg.newTemp)) {\n node.error(\"Invalid temp received\", msg);\n return null;\n}\nmsg.consigne = global.get(msg.zone + \"_Setpoint\");\n\nif (msg.consigne === undefined){\n node.error(\"No valid schedule found !\", msg);\n return null;\n}\n\nif (msg.consigne > msg.newTemp + msg.hysteresis) {\n msg.payload = \"ON\";\n node.status({fill:\"green\",shape:\"dot\",text:\"Heating\"});\n}\nelse if (msg.consigne < msg.newTemp - msg.hysteresis) {\n msg.payload = \"OFF\";\n node.status({fill:\"red\",shape:\"dot\",text:\"Not heating\"});\n}\nelse {\n msg.payload = \"HYSTERESIS\";\n node.status({fill:\"grey\",shape:\"dot\",text:\"Hysteresis…\"});\n}\nreturn msg;",
"outputs": 1,
"noerr": 0,
"x": 570,
"y": 420,
"wires": [
[
"6b5ce50f.17177c",
"fb60fd21.038b"
]
]
},
{
"id": "e09d60f9.577178",
"type": "delay",
"z": "49319db8.e1b464",
"name": "",
"pauseType": "rate",
"timeout": "50",
"timeoutUnits": "milliseconds",
"rate": "1",
"nbRateUnits": "1",
"rateUnits": "second",
"randomFirst": "1",
"randomLast": "5",
"randomUnits": "seconds",
"drop": false,
"x": 1750,
"y": 500,
"wires": [
[
"acccff1a.facd4"
]
]
},
{
"id": "c8408e29.9dea3",
"type": "rbe",
"z": "49319db8.e1b464",
"name": "",
"func": "rbe",
"gap": "",
"start": "",
"inout": "out",
"x": 1570,
"y": 440,
"wires": [
[
"e09d60f9.577178"
]
]
},
{
"id": "2921d9ac.576896",
"type": "rbe",
"z": "49319db8.e1b464",
"name": "",
"func": "rbe",
"gap": "",
"start": "",
"inout": "out",
"x": 1570,
"y": 400,
"wires": [
[
"e09d60f9.577178"
]
]
},
{
"id": "6fb853ab.9165fc",
"type": "rbe",
"z": "49319db8.e1b464",
"name": "",
"func": "rbe",
"gap": "",
"start": "",
"inout": "out",
"x": 1310,
"y": 520,
"wires": [
[
"e09d60f9.577178"
]
]
},
{
"id": "7ca6cbf.9713734",
"type": "rbe",
"z": "49319db8.e1b464",
"name": "",
"func": "rbe",
"gap": "",
"start": "",
"inout": "out",
"x": 1310,
"y": 480,
"wires": [
[
"e09d60f9.577178"
]
]
}
]
This is hack-ish :
Nodered : save openhab state
[
{
"id": "feb9c50a.21df2",
"type": "function",
"z": "40c562ef.ffacf4",
"name": "Set ALL Openhab items to global variables",
"func": "\nlastSlashIndex = msg.topic.lastIndexOf('/');\n\nitem = msg.topic.slice(lastSlashIndex+1);\nglobal.set(item, msg.payload);\n\n\nreturn null;",
"outputs": "0",
"noerr": 0,
"x": 370,
"y": 40,
"wires": []
}
]