Software thermostat

Quite some time ago I posted a picture of my floor heating regulation. For each room I am running a software thermostat which needed many nodes and was clumsy and hard to read but it works perfectly. (12 rooms, 12 Nod On STPH-2-1-05 Enocean HT sensors, 1 UniPi 1.1, 2 shelly pro4, 23 valves, 3 z-wave radiator thermostats)
Therefore, I was looking for and easy 2 point regulator (thermostat) in Node-red which fulfilled my requirements. Unfortunately, there was no such piece of software and I wrote a single function node that does it all. (including boost functionality)
If you are interested, please feel free to use it and if you could improve it, I would very much appreciate your feedback.

[{"id":"7c89a60c.c53b78","type":"tab","label":"SW-Thermostat","disabled":false,"info":""},{"id":"4b541c43.e7c024","type":"mqtt in","z":"7c89a60c.c53b78","name":"ist Temp DGWZ","topic":"shellies/shellyht-58F85A/sensor/temperature/#","qos":"0","datatype":"auto","broker":"99603ece.52e2a","nl":false,"rap":true,"rh":0,"x":220,"y":380,"wires":[["951c9593.ed66c8"]]},{"id":"cd9c90bf.de3fb","type":"change","z":"7c89a60c.c53b78","name":"automatic on off","rules":[{"t":"set","p":"automatic-switch","pt":"flow","to":"off","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":680,"y":80,"wires":[[]]},{"id":"2d0ceba.3666e14","type":"inject","z":"7c89a60c.c53b78","name":"auto off","props":[{"p":"payload"}],"repeat":"","crontab":"","once":true,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":480,"y":80,"wires":[["cd9c90bf.de3fb"]]},{"id":"37cae76f.4fe0f8","type":"function","z":"7c89a60c.c53b78","name":"Zweipunktregler","func":"let topic = msg.topic;\nlet payload = msg.payload;\nlet runtime;\nlet starttime;\nlet endtime;\nlet myTimeout = 0;\n\n//--------\n\nswitch(topic) {\n  case \"soll\":\n    soll();\n    break;\n  case \"config_hys\":\n    config_hys();\n    break;\n  case \"config_boost\":\n    config_boost();\n    break;\n  case \"config_room\":\n    config_room(payload);\n    break;    \n  case \"ist\":\n    payload = parseFloat(payload);\n    context.set(\"ist\", payload);\n    if (context.get(\"min\") === 0 && context.get(\"max\") === 0){\n        reset();\n    }    \n    ist(payload);\n    break;\n  case \"switchit\":\n    switchit(payload);\n    break; \n  case \"reset\":\n    reset();\n    break;    \n  default:\n    return null;\n}\nreturn null;\n\n//--------\n\nfunction soll (){\n    context.set (\"soll\",msg.payload);\n    t = \"soll initialisiert mit \" + msg.payload + \"Grad C\";\n    node.status({fill:\"green\",shape:\"dot\",text:t});    \n    return;    \n}\n\n//--------\n\nfunction config_hys(){\n    context.set (\"h_low\", msg.payload.hys_low);\n    context.set (\"h_high\", msg.payload.hys_high);\n    node.status({fill:\"green\",shape:\"dot\",text:\"Hystereris initialisiert\"});    \n    return;\n}\n\n//--------\n\nfunction config_boost(){\n    let dauer = msg.payload.dauer * 1000 * 60;\n    context.set (\"dauer\", dauer);\n    context.set (\"anhebung\", msg.payload.anhebung);\n    let t = \"boost: \" + msg.payload.anhebung + \" Grad C \" + \"fĂĽr \" + msg.payload.dauer + \" min\";\n    node.status({fill:\"green\",shape:\"dot\",text:t}); \n    return null;\n}\n\n//--------\n\nfunction config_room(payload){\n    context.set (\"room\", payload);\n    let t = \"Room: \" + payload;\n    node.status({fill:\"green\",shape:\"dot\",text:t});\n    msg.topic = \"room\";\n    msg.payload = payload;\n    node.send(msg);    \n    return null;\n}\n\n//--------\nfunction ist(payload){\n    minmax(payload);\n    timeString();\n    timeStamp();\n    let c = context.get(\"counter\");\n    c++;\n    context.set(\"counter\", c);\n    let ist = payload;\n    let soll = context.get(\"soll\");\n    let delta = ist - soll;\n    msg.topic = \"soll\";\n    msg.payload = parseFloat(soll.toFixed(2));\n    node.send(msg);    \n    msg.topic = \"ist\";\n    //msg.payload = parseFloat(ist.toFixed(2));\n    msg.payload = ist;\n    node.send(msg);    \n    msg.topic = \"delta\";\n    msg.payload = parseFloat(delta.toFixed(2));\n    node.send(msg);\n    let high = context.get(\"h_high\");\n    let low = context.get(\"h_low\");\n    let off = soll + high;\n    let on = soll + low;\n\n    if (ist > off){\n        let status = \"ist:\" + c + \"/\" + ist + \" soll:\" + soll + \" Hys:\" + low + \" to \" + high + \" switch off\";\n        node.status({fill:\"green\",shape:\"dot\",text:status});\n        let stat = context.get(\"status\");\n        if (stat != \"off\"){\n            runtime_stop();\n            context.set(\"status\",\"off\");\n            msg.topic = \"Regler\";\n            msg.payload = \"off\";\n            node.send(msg);\n        }    \n    }\n    \n    if ((ist > on) && (ist < off)){\n        let status = \"ist:\" + c + \"/\" + ist + \" soll:\" + soll + \" Hys:\" + low + \" to \" + high + \" switch null\";\n        node.status({fill:\"green\",shape:\"dot\",text:status});          \n        msg.topic = \"Regler\";\n        msg.payload = \"on target\";\n        node.send(msg);\n    }\n    \n    if (ist < on){\n        let status = \"ist:\" + c + \"/\" + ist + \" soll:\" + soll + \" Hys:\" + low + \" to \" + high + \" switch on\";\n        node.status({fill:\"green\",shape:\"dot\",text:status});\n        let stat = context.get(\"status\");\n        if (stat != \"on\"){\n            runtime_start();\n            context.set(\"status\",\"on\");\n            msg.topic = \"Regler\";\n            msg.payload = \"on\";\n            node.send(msg);\n        }         \n    }\n    return;\n}   \n\n//--------\n\nfunction minmax(temp){\n    let ist = temp;\n    let min = context.get(\"min\");\n    let max = context.get(\"max\");\n\n    if (ist < min){\n        min = ist\n        context.set(\"min\", ist);\n    } \n    else if (ist > max){\n        max = ist\n        context.set(\"max\", ist)\n    }\n\n    let t = \"ist:\" + ist + \" min:\" + min +\" max:\" + max; \n    node.status({fill:\"green\",shape:\"dot\",text:t});\n\n    msg.topic = \"min\";\n    msg.payload = min;\n    node.send(msg);\n\n    msg.topic = \"max\";\n    msg.payload = max;\n    node.send(msg);\n    return;\n}    \n\n//--------\n\nfunction switchit(onoff){\n    msg.payload = onoff;\n    node.send(msg);\n    if (onoff === \"on\"){\n        context.set (\"boost\", true);\n        msg.topic = \"soll\";\n        msg.payload = boost_on();\n        node.send(msg);\n        myTimeout = setTimeout(boost_off,context.get(\"dauer\"));\n        context.set(\"myTimeout\", myTimeout);\n    }\n    else if (onoff === \"off\"){\n        context.set (\"boost\", false);\n        clearTimeout(context.get(\"myTimeout\"));\n        msg.topic = \"soll\";\n        msg.payload = context.get(\"soll\");\n        node.send(msg);\n    }\n    return;    \n}\n\n//--------\n\nfunction boost_on(){\n    let soll_prev =  context.get(\"soll\");\n    let soll_boost = soll_prev + context.get(\"anhebung\");\n    let dauer = context.get(\"dauer\");\n    node.status({fill:\"red\",shape:\"dot\",text:\"soll:\" + soll_boost + \" fĂĽr \" + dauer/1000/60 + \" min\"});    \n    return soll_boost;    \n}\n\nfunction boost_off(){\n    msg.payload = context.get(\"soll\");\n    node.status({fill:\"green\",shape:\"dot\",text:\"soll:\" + msg.payload});     \n    node.send(msg);    \n    return;\n}\n\n//--------\n\nfunction runtime_start(){\n    let r = context.get(\"room\");\n    global.set(r,\"on\");    \n    context.set(\"starttime\", Date.now());\n    return;\n}\n\n//--------\n\nfunction runtime_stop(){\n    let r = context.get(\"room\");\n    global.set(r,\"off\");\n    let end = Date.now();\n    //node.warn(\"runtime_stop: message\" + end);\n    let start = context.get(\"starttime\")\n    if (start === 0){\n        start = Date.now();\n    }\n    //node.warn(\"runtime_stop: message\" + start);\n   \n    let runtime = end - start;\n    msg.topic = \"runtime\";\n    msg.payload = runtime;\n    node.send(msg);\n\n    msg.topic = \"runtimestr\";\n    msg.payload = runtime_str(runtime);\n    node.send(msg);\n    \n    let total = context.get(\"runtimetotal\");\n    //node.warn(\"total: message\" + context.get(runtimetotal));    \n    total = total + runtime;\n    context.set(\"runtimetotal\", total);\n    msg.topic = \"runtimetotal\";\n    msg.payload = total;\n    node.send(msg);\n    \n    return;\n}\n\n//--------\n\nfunction reset(){\n    let ist_midnight = context.get(\"ist\");\n    context.set(\"min\", ist_midnight);\n    context.set(\"max\", ist_midnight);\n    return;\n}\n\n//--------\n\nfunction timeString(){\n    msg.topic = \"timeString\";\n    msg.payload = current_date_time(Date.now());\n    node.send(msg);\n    return;\n}\n\n//--------\n\nfunction timeStamp(){\n    msg.topic = \"timeStamp\";\n    msg.payload = Date.now();\n    node.send(msg);\n    return;\n}\n\n//--------\n\nfunction current_date_time(timestamp){\n    let date = new Date(timestamp);\n    let year = date.getFullYear();\n    let month = (\"0\" + (date.getMonth() + 1)).slice(-2);\n    let day = (\"0\" + date.getDate()).slice(-2);\n    let hours = (\"0\" + date.getHours()).slice(-2);\n    let minutes = (\"0\" + date.getMinutes()).slice(-2);\n    let seconds = (\"0\" + date.getSeconds()).slice(-2);\n    let datestring = day + \"-\" + month + \"-\" + year + \" \" + hours + ':' + minutes + ':' + seconds;  \n    return datestring;\n}\n \n//--------\n\n//  HH:MM:SS\n\nfunction runtime_str(ms){\n    let t = ms / 1000;\n    let h = (Math.floor(t / 3600)).toString();\n    let m = (Math.floor(t%3600 / 60)).toString();\n    let s = (Math.floor(t%3600 % 60)).toString();\n    let r = h + \":\" + (\"0\" + m).slice(-2) + \":\" + (\"0\" + s).slice(-2);\n    return r;  \n}\n","outputs":1,"noerr":0,"initialize":"// Code added here will be run once\n// whenever the node is started.\nnode.status({fill:\"red\",shape:\"ring\",text:\"not configured\"});\n\nif (context.get(\"counter\") === undefined) {\n    context.set(\"counter\", 0)\n}\n\ncontext.set (\"boost\",false);\n\nif (context.get(\"max\") === undefined) {\n    context.set(\"max\", 0)\n}\nif (context.get(\"min\") === undefined) {\n    context.set(\"min\", 0)\n}\n\nif (context.get(\"starttime\") === undefined){\n    context.set(\"starttime\", 0);\n}\n\nif (context.get(\"endtime\") === undefined){\n    context.set(\"endtime\", 0);\n}\n\nif (context.get(\"runtime\") === undefined){\n    context.set(\"runtime\", 0);\n}\n\nif (context.get(\"runtimetotal\") === undefined){\n    context.set(\"runtimetotal\", 0);\n}\n\nif (context.get(\"status\") === undefined){\n    context.set(\"status\", \"start\");\n}\n\nlet t = \"ist:\" + \"0\" + \" min:\" + \"0\" +\" max:\" + \"0\"; \nnode.status({fill:\"green\",shape:\"dot\",text:t});","finalize":"","libs":[],"x":780,"y":400,"wires":[["ffd8d6dd.22d358"]]},{"id":"a44dfc2.508d3","type":"inject","z":"7c89a60c.c53b78","name":"","props":[{"p":"topic","vt":"str"},{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"ist","payload":"20.89","payloadType":"num","x":480,"y":620,"wires":[["37cae76f.4fe0f8"]]},{"id":"42ae6d31.7f8fb4","type":"inject","z":"7c89a60c.c53b78","name":"","props":[{"p":"topic","vt":"str"},{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"ist","payload":"21.01","payloadType":"num","x":480,"y":580,"wires":[["37cae76f.4fe0f8"]]},{"id":"d28d691b.61d758","type":"inject","z":"7c89a60c.c53b78","name":"config_hys:{\"hys-high\":0.0,\"hys-low\":-0.1}","props":[{"p":"topic","vt":"str"},{"p":"payload"}],"repeat":"","crontab":"","once":true,"onceDelay":"0.4","topic":"config_hys","payload":"{\"hys_high\":0.0,\"hys_low\":-0.1}","payloadType":"json","x":380,"y":140,"wires":[["37cae76f.4fe0f8"]]},{"id":"cf8e5796.cfe258","type":"debug","z":"7c89a60c.c53b78","name":"soll","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":1310,"y":180,"wires":[]},{"id":"84325e62.d7bbc","type":"inject","z":"7c89a60c.c53b78","name":"soll temp manu 21.00","props":[{"p":"topic","vt":"str"},{"p":"payload"}],"repeat":"","crontab":"","once":true,"onceDelay":"0.3","topic":"soll","payload":"21.00","payloadType":"num","x":300,"y":420,"wires":[["93bd80d.8ae7e8"]]},{"id":"ffd8d6dd.22d358","type":"switch","z":"7c89a60c.c53b78","name":"soll/ist/delta/Regler...","property":"topic","propertyType":"msg","rules":[{"t":"eq","v":"soll","vt":"str"},{"t":"eq","v":"ist","vt":"str"},{"t":"eq","v":"delta","vt":"str"},{"t":"eq","v":"min","vt":"str"},{"t":"eq","v":"max","vt":"str"},{"t":"eq","v":"Regler","vt":"str"},{"t":"eq","v":"timeString","vt":"str"},{"t":"eq","v":"timeStamp","vt":"str"},{"t":"eq","v":"room","vt":"str"},{"t":"eq","v":"runtime","vt":"str"},{"t":"eq","v":"runtimestr","vt":"str"},{"t":"eq","v":"runtimetotal","vt":"str"}],"checkall":"true","repair":false,"outputs":12,"x":1060,"y":400,"wires":[["cf8e5796.cfe258"],["3b704c18.75f8b4"],["8f92f8cc.a6ef38"],["fa2f0338.4bbfb"],["3508834a.1f16ec"],["bf3a182c.e36468"],["33bd85e9.2a995a"],["cf0b1f45.7b82c"],["9eddd5e.0dd3e28"],["c39d193d.85f9c8"],["d57047e2.aec3a8"],["3abb331e.d7630c"]]},{"id":"bf3a182c.e36468","type":"debug","z":"7c89a60c.c53b78","name":"Regler","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":1310,"y":380,"wires":[]},{"id":"8f92f8cc.a6ef38","type":"debug","z":"7c89a60c.c53b78","name":"delta","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":1310,"y":260,"wires":[]},{"id":"3b704c18.75f8b4","type":"debug","z":"7c89a60c.c53b78","name":"ist","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":1310,"y":220,"wires":[]},{"id":"33bd85e9.2a995a","type":"debug","z":"7c89a60c.c53b78","name":"timeString","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":1320,"y":420,"wires":[]},{"id":"cf0b1f45.7b82c","type":"debug","z":"7c89a60c.c53b78","name":"timestamp","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":1330,"y":460,"wires":[]},{"id":"12e277b8.6351b8","type":"inject","z":"7c89a60c.c53b78","name":"config_boost:{\"anhebung\":3,\"dauer\":1}","props":[{"p":"topic","vt":"str"},{"p":"payload"}],"repeat":"","crontab":"","once":true,"onceDelay":"0.5","topic":"config_boost","payload":"{\"anhebung\":3,\"dauer\":1}","payloadType":"json","x":390,"y":180,"wires":[["37cae76f.4fe0f8"]]},{"id":"83f1c8cf.3eebc8","type":"inject","z":"7c89a60c.c53b78","name":"switch boost on","props":[{"p":"topic","vt":"str"},{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"switchit","payload":"on","payloadType":"str","x":460,"y":300,"wires":[["37cae76f.4fe0f8"]]},{"id":"1bdaeaa9.507775","type":"inject","z":"7c89a60c.c53b78","name":"switch boost off","props":[{"p":"topic","vt":"str"},{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"switchit","payload":"off","payloadType":"str","x":460,"y":340,"wires":[["37cae76f.4fe0f8"]]},{"id":"fa2f0338.4bbfb","type":"debug","z":"7c89a60c.c53b78","name":"min","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":1310,"y":300,"wires":[]},{"id":"3508834a.1f16ec","type":"debug","z":"7c89a60c.c53b78","name":"max","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":1310,"y":340,"wires":[]},{"id":"a3e3b021.60bde","type":"inject","z":"7c89a60c.c53b78","name":"reset min max","props":[{"p":"topic","vt":"str"},{"p":"payload"}],"repeat":"","crontab":"00 00 * * *","once":false,"onceDelay":0.1,"topic":"reset","payload":"","payloadType":"date","x":460,"y":260,"wires":[["37cae76f.4fe0f8"]]},{"id":"951c9593.ed66c8","type":"change","z":"7c89a60c.c53b78","name":"","rules":[{"t":"set","p":"topic","pt":"msg","to":"ist","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":470,"y":380,"wires":[["37cae76f.4fe0f8"]]},{"id":"d5b6b10b.f6a15","type":"inject","z":"7c89a60c.c53b78","name":"","props":[{"p":"topic","vt":"str"},{"p":"payload"}],"repeat":"","crontab":"","once":true,"onceDelay":"1","topic":"config_room","payload":"DGWZ","payloadType":"str","x":440,"y":220,"wires":[["37cae76f.4fe0f8"]]},{"id":"9eddd5e.0dd3e28","type":"debug","z":"7c89a60c.c53b78","name":"room","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":1310,"y":500,"wires":[]},{"id":"c39d193d.85f9c8","type":"debug","z":"7c89a60c.c53b78","name":"runtime","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":1320,"y":540,"wires":[]},{"id":"d57047e2.aec3a8","type":"debug","z":"7c89a60c.c53b78","name":"runtimestr","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":1320,"y":580,"wires":[]},{"id":"3abb331e.d7630c","type":"debug","z":"7c89a60c.c53b78","name":"runtimetotal","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":1330,"y":620,"wires":[]},{"id":"d3ff4f8c.7064d","type":"switch","z":"7c89a60c.c53b78","name":"auto","property":"automatic-switch","propertyType":"flow","rules":[{"t":"eq","v":"on","vt":"str"}],"checkall":"true","repair":false,"outputs":1,"x":490,"y":460,"wires":[["37cae76f.4fe0f8"]]},{"id":"93bd80d.8ae7e8","type":"switch","z":"7c89a60c.c53b78","name":"manu","property":"automatic-switch","propertyType":"flow","rules":[{"t":"eq","v":"off","vt":"str"}],"checkall":"true","repair":false,"outputs":1,"x":490,"y":420,"wires":[["37cae76f.4fe0f8"]]},{"id":"6950687a.bd9128","type":"function","z":"7c89a60c.c53b78","name":"soll temp auto","func":"\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":260,"y":460,"wires":[["d3ff4f8c.7064d"]]},{"id":"3e65ed7.2ee2e12","type":"comment","z":"7c89a60c.c53b78","name":"test only - off","info":"","x":310,"y":580,"wires":[]},{"id":"28f154da.f9578c","type":"comment","z":"7c89a60c.c53b78","name":"test only - on","info":"","x":310,"y":620,"wires":[]},{"id":"32cd0e60.b2e4f2","type":"comment","z":"7c89a60c.c53b78","name":"von cron plus","info":"different heating profiles stored on disk and can be loaded into cron plus","x":90,"y":460,"wires":[]},{"id":"d48cfc52.3f4b7","type":"comment","z":"7c89a60c.c53b78","name":"slider","info":"","x":110,"y":420,"wires":[]},{"id":"4ed38a00.cc2144","type":"comment","z":"7c89a60c.c53b78","name":"gauge / chart","info":"","x":1530,"y":180,"wires":[]},{"id":"6a073b42.b70e34","type":"comment","z":"7c89a60c.c53b78","name":"text / chart","info":"","x":1520,"y":300,"wires":[]},{"id":"8e060b9b.460b18","type":"comment","z":"7c89a60c.c53b78","name":"text / chart","info":"","x":1520,"y":340,"wires":[]},{"id":"4c0dff50.cd6d5","type":"comment","z":"7c89a60c.c53b78","name":"gauge / chart","info":"","x":1530,"y":260,"wires":[]},{"id":"c4a1a80d.8fd9f8","type":"comment","z":"7c89a60c.c53b78","name":"gauge / chart","info":"","x":1530,"y":220,"wires":[]},{"id":"8ff1745d.64f6e8","type":"comment","z":"7c89a60c.c53b78","name":"on / off relay/valve","info":"","x":1550,"y":380,"wires":[]},{"id":"3d0ab3dc.d4d00c","type":"comment","z":"7c89a60c.c53b78","name":"ms","info":"","x":1510,"y":540,"wires":[]},{"id":"155251af.7da36e","type":"comment","z":"7c89a60c.c53b78","name":"HH:MM:SS","info":"","x":1520,"y":580,"wires":[]},{"id":"1d00c73e.537889","type":"comment","z":"7c89a60c.c53b78","name":"ms","info":"","x":1510,"y":620,"wires":[]},{"id":"9c538999.93c378","type":"comment","z":"7c89a60c.c53b78","name":"text (global variable)","info":"thermostat sets global(\"DGWZ\",\"on\") or global(\"DGWZ\",\"off\").\nIf you have more than one room you could check the status of all rooms and switch a main circulation pump on or off.","x":1550,"y":500,"wires":[]},{"id":"cb986f8f.63da9","type":"comment","z":"7c89a60c.c53b78","name":"run at midnight","info":"","x":260,"y":260,"wires":[]},{"id":"99603ece.52e2a","type":"mqtt-broker","broker":"10.0.0.43","port":"1883","clientid":"","usetls":false,"compatmode":true,"keepalive":"60","cleansession":true,"birthTopic":"","birthQos":"0","birthPayload":"","willTopic":"","willQos":"0","willPayload":""}]
1 Like

Have a look at the node-red-contrib-ramp-thermostat

thanks for the info. Did not see it. Nearly identical.

very interesting, can you show your function "Zweipunktregler" ?

here

sehr interessant, kannst du deinen Zweipunktregler mal direkt einfĂĽgen in ``` ?

Import the flow and you will be able to see the function node

This topic was automatically closed 60 days after the last reply. New replies are no longer allowed.