[Node-Red] How to make and switch device groups? (Multizone heating)

Hey all,

I’ve got a question. I’m tinkering with node-red and want to make a automated heating system that has:

  • 2 central heating system boilers
  • 14 rooms
  • 14 thermostats
  • about 40 radiators

What I would like is to create 2 boiler groups - that have (say) 7 room groups - these room groups have 1 thermostat and (say) 3 radiators. Like the simplified diagram below:

What I would like is to:

  • On room level: set the temprature for the 3 radiators at once
  • On boiler level: if one room requires the boiler switch the boiler on. If none of the rooms requires the boiler, switch it off.

(Later on, I think I would add a weather station and switch the boiler modular with openTherm.)

What is my question
I’m new with node-red. But I’ve played with some public flows. This I’ve gotten to work between a single thermostat and radiator valve. But I would like to add devices to groups and switch them based on groups. So my main question would be “How can I make groups and add devices to them. And then send command to the group.” And can these groups be nested?

You’ll have to get more specific for you to get a real answer. It all matters what type of heating system, how the zones are controlled, what kind of thermostats, etc. There isn’t a generic flow that can be applied.

Nodered is versatile enough to get you to any configuration you like but a lot of details need to be ironed out. Check out this project that is a total DIY. The control for that will look different if you want to use off the shelf devices.

Import this in Node-Red to give you an idea.

[{“id”:“42b077e23bac54a6”,“type”:“server-state-changed”,“z”:“25f5f33873f169c4”,“name”:“Someone changed room 2 thermostat”,“server”:“e447e3557e0eea14”,“version”:3,“exposeToHomeAssistant”:false,“haConfig”:[{“property”:“name”,“value”:""},{“property”:“icon”,“value”:""}],“entityidfilter”:"",“entityidfiltertype”:“exact”,“outputinitially”:false,“state_type”:“str”,“haltifstate”:"",“halt_if_type”:“str”,“halt_if_compare”:“is”,“outputs”:1,“output_only_on_state_change”:true,“for”:0,“forType”:“num”,“forUnits”:“minutes”,“ignorePrevStateNull”:false,“ignorePrevStateUnknown”:false,“ignorePrevStateUnavailable”:false,“ignoreCurrentStateUnknown”:false,“ignoreCurrentStateUnavailable”:false,“outputProperties”:[{“property”:“payload”,“propertyType”:“msg”,“value”:"",“valueType”:“entityState”},{“property”:“data”,“propertyType”:“msg”,“value”:"",“valueType”:“eventData”},{“property”:“topic”,“propertyType”:“msg”,“value”:"",“valueType”:“triggerId”}],“x”:170,“y”:340,“wires”:[[“b826afd9a956fca1”]]},{“id”:“b826afd9a956fca1”,“type”:“function”,“z”:“25f5f33873f169c4”,“name”:“maybe do some calculations and send a temperature”,“func”:"\nreturn msg;",“outputs”:1,“noerr”:0,“initialize”:"",“finalize”:"",“libs”:[],“x”:280,“y”:400,“wires”:[[“cd1646b2012b4135”,“368957bfe2a23e06”,“0240983bfe0195fa”]]},{“id”:“cd1646b2012b4135”,“type”:“api-call-service”,“z”:“25f5f33873f169c4”,“name”:“call a service to set a temperature on radiator 1 in room 2”,“server”:“e447e3557e0eea14”,“version”:3,“debugenabled”:false,“service_domain”:"",“service”:"",“entityId”:"",“data”:"",“dataType”:“jsonata”,“mergecontext”:"",“mustacheAltTags”:false,“outputProperties”:[],“queue”:“none”,“x”:730,“y”:360,“wires”:[[“ca0d4a56f75fdade”]]},{“id”:“368957bfe2a23e06”,“type”:“api-call-service”,“z”:“25f5f33873f169c4”,“name”:“call a service to set a temperature on radiator 2 in room 2”,“server”:“e447e3557e0eea14”,“version”:3,“debugenabled”:false,“service_domain”:"",“service”:"",“entityId”:"",“data”:"",“dataType”:“jsonata”,“mergecontext”:"",“mustacheAltTags”:false,“outputProperties”:[],“queue”:“none”,“x”:730,“y”:400,“wires”:[[“ca0d4a56f75fdade”]]},{“id”:“0240983bfe0195fa”,“type”:“api-call-service”,“z”:“25f5f33873f169c4”,“name”:“call a service to set a temperature on radiator 3 in room 2”,“server”:“e447e3557e0eea14”,“version”:3,“debugenabled”:false,“service_domain”:"",“service”:"",“entityId”:"",“data”:"",“dataType”:“jsonata”,“mergecontext”:"",“mustacheAltTags”:false,“outputProperties”:[],“queue”:“none”,“x”:730,“y”:440,“wires”:[[“ca0d4a56f75fdade”]]},{“id”:“057db9044f3280dd”,“type”:“server-state-changed”,“z”:“25f5f33873f169c4”,“name”:“Someone changed room 1 thermostat”,“server”:“e447e3557e0eea14”,“version”:3,“exposeToHomeAssistant”:false,“haConfig”:[{“property”:“name”,“value”:""},{“property”:“icon”,“value”:""}],“entityidfilter”:"",“entityidfiltertype”:“exact”,“outputinitially”:false,“state_type”:“str”,“haltifstate”:"",“halt_if_type”:“str”,“halt_if_compare”:“is”,“outputs”:1,“output_only_on_state_change”:true,“for”:0,“forType”:“num”,“forUnits”:“minutes”,“ignorePrevStateNull”:false,“ignorePrevStateUnknown”:false,“ignorePrevStateUnavailable”:false,“ignoreCurrentStateUnknown”:false,“ignoreCurrentStateUnavailable”:false,“outputProperties”:[{“property”:“payload”,“propertyType”:“msg”,“value”:"",“valueType”:“entityState”},{“property”:“data”,“propertyType”:“msg”,“value”:"",“valueType”:“eventData”},{“property”:“topic”,“propertyType”:“msg”,“value”:"",“valueType”:“triggerId”}],“x”:170,“y”:140,“wires”:[[“a8d10eff0f61aee1”]]},{“id”:“a8d10eff0f61aee1”,“type”:“function”,“z”:“25f5f33873f169c4”,“name”:“maybe do some calculations and send a temperature”,“func”:"\nreturn msg;",“outputs”:1,“noerr”:0,“initialize”:"",“finalize”:"",“libs”:[],“x”:280,“y”:200,“wires”:[[“7735b5f450fb0b22”,“2389ac2e6d2e31a0”,“8feca2f243cfc982”]]},{“id”:“7735b5f450fb0b22”,“type”:“api-call-service”,“z”:“25f5f33873f169c4”,“name”:“call a service to set a temperature on radiator 1 in room 1”,“server”:“e447e3557e0eea14”,“version”:3,“debugenabled”:false,“service_domain”:"",“service”:"",“entityId”:"",“data”:"",“dataType”:“jsonata”,“mergecontext”:"",“mustacheAltTags”:false,“outputProperties”:[],“queue”:“none”,“x”:730,“y”:160,“wires”:[[“ca0d4a56f75fdade”]]},{“id”:“2389ac2e6d2e31a0”,“type”:“api-call-service”,“z”:“25f5f33873f169c4”,“name”:“call a service to set a temperature on radiator 2 in room 1”,“server”:“e447e3557e0eea14”,“version”:3,“debugenabled”:false,“service_domain”:"",“service”:"",“entityId”:"",“data”:"",“dataType”:“jsonata”,“mergecontext”:"",“mustacheAltTags”:false,“outputProperties”:[],“queue”:“none”,“x”:730,“y”:200,“wires”:[[“ca0d4a56f75fdade”]]},{“id”:“8feca2f243cfc982”,“type”:“api-call-service”,“z”:“25f5f33873f169c4”,“name”:“call a service to set a temperature on radiator 3 in room 1”,“server”:“e447e3557e0eea14”,“version”:3,“debugenabled”:false,“service_domain”:"",“service”:"",“entityId”:"",“data”:"",“dataType”:“jsonata”,“mergecontext”:"",“mustacheAltTags”:false,“outputProperties”:[],“queue”:“none”,“x”:730,“y”:240,“wires”:[[“ca0d4a56f75fdade”]]},{“id”:“ca0d4a56f75fdade”,“type”:“api-current-state”,“z”:“25f5f33873f169c4”,“name”:“pull state of heating on thermostat in room 1”,“server”:“e447e3557e0eea14”,“version”:2,“outputs”:1,“halt_if”:"",“halt_if_type”:“str”,“halt_if_compare”:“is”,“entity_id”:"",“state_type”:“str”,“blockInputOverrides”:false,“outputProperties”:[{“property”:“payload”,“propertyType”:“msg”,“value”:"",“valueType”:“entityState”},{“property”:“data”,“propertyType”:“msg”,“value”:"",“valueType”:“entity”}],“override_topic”:false,“state_location”:“payload”,“override_payload”:“msg”,“entity_location”:“data”,“override_data”:“msg”,“x”:1170,“y”:160,“wires”:[[“a30341956341d23d”]]},{“id”:“a30341956341d23d”,“type”:“function”,“z”:“25f5f33873f169c4”,“name”:“Do some calculations to get a boolean value (yes/no, heating/no heating, over/under or whatever))”,“func”:"\nreturn msg;",“outputs”:1,“noerr”:0,“initialize”:"",“finalize”:"",“libs”:[],“x”:1380,“y”:220,“wires”:[[“58d6ba6cc9def58c”]]},{“id”:“9b09cb41c06ebbda”,“type”:“function”,“z”:“25f5f33873f169c4”,“name”:“Do some calculations to get a boolean value (yes/no, heating/no heating, over/under or whatever))”,“func”:"\nreturn msg;",“outputs”:1,“noerr”:0,“initialize”:"",“finalize”:"",“libs”:[],“x”:1380,“y”:560,“wires”:[[“594f4fd1025a90b3”]]},{“id”:“578775b9e2577b80”,“type”:“api-current-state”,“z”:“25f5f33873f169c4”,“name”:“pull state of heating on thermostat in room 1”,“server”:“e447e3557e0eea14”,“version”:2,“outputs”:1,“halt_if”:"",“halt_if_type”:“str”,“halt_if_compare”:“is”,“entity_id”:"",“state_type”:“str”,“blockInputOverrides”:false,“outputProperties”:[{“property”:“payload”,“propertyType”:“msg”,“value”:"",“valueType”:“entityState”},{“property”:“data”,“propertyType”:“msg”,“value”:"",“valueType”:“entity”}],“override_topic”:false,“state_location”:“payload”,“override_payload”:“msg”,“entity_location”:“data”,“override_data”:“msg”,“x”:1170,“y”:500,“wires”:[[“9b09cb41c06ebbda”]]},{“id”:“58d6ba6cc9def58c”,“type”:“switch”,“z”:“25f5f33873f169c4”,“name”:“heating?”,“property”:“payload”,“propertyType”:“msg”,“rules”:[{“t”:“eq”,“v”:“yes”,“vt”:“str”},{“t”:“eq”,“v”:“no”,“vt”:“str”}],“checkall”:“true”,“repair”:false,“outputs”:2,“x”:1130,“y”:280,“wires”:[[“bf67485d79f67aa0”],[“578775b9e2577b80”]]},{“id”:“594f4fd1025a90b3”,“type”:“switch”,“z”:“25f5f33873f169c4”,“name”:“heating?”,“property”:“payload”,“propertyType”:“msg”,“rules”:[{“t”:“eq”,“v”:“yes”,“vt”:“str”},{“t”:“eq”,“v”:“no”,“vt”:“str”}],“checkall”:“true”,“repair”:false,“outputs”:2,“x”:1140,“y”:620,“wires”:[[“bf67485d79f67aa0”],[“08e2593403179c08”]]},{“id”:“08e2593403179c08”,“type”:“api-call-service”,“z”:“25f5f33873f169c4”,“name”:“No thermostats are requiring heating, so Boiler OFF!”,“server”:“e447e3557e0eea14”,“version”:3,“debugenabled”:false,“service_domain”:"",“service”:"",“entityId”:"",“data”:"",“dataType”:“jsonata”,“mergecontext”:"",“mustacheAltTags”:false,“outputProperties”:[],“queue”:“none”,“x”:1540,“y”:720,“wires”:[[]]},{“id”:“bf67485d79f67aa0”,“type”:“api-call-service”,“z”:“25f5f33873f169c4”,“name”:“Boiler ON!”,“server”:“e447e3557e0eea14”,“version”:3,“debugenabled”:false,“service_domain”:"",“service”:"",“entityId”:"",“data”:"",“dataType”:“jsonata”,“mergecontext”:"",“mustacheAltTags”:false,“outputProperties”:[],“queue”:“none”,“x”:2070,“y”:600,“wires”:[[]]},{“id”:“e447e3557e0eea14”,“type”:“server”,“name”:“test”,“version”:1,“legacy”:false,“addon”:false,“rejectUnauthorizedCerts”:true,“ha_boolean”:“y|yes|true|on|home|open”,“connectionDelay”:true,“cacheJson”:true,“credentials”:{“host”:“127.0.0.1:8123”,“access_token”:""}}]

Alright, think this is a start. My first flow :slight_smile:

I’m now thinking of sending the boiler group and room info with the mqtt message.
Then I can use HA node “get entities” to get all entities and filter out the radiators from the right room. This way I can grow the devices without changing the flow. So I can add rooms and radiators.

The entity names define the location, like: heating_boiler_01_room_01_radiator_02.

The thermostat would send a json message like:

{
	"entity_id": "heating_boiler_01_room_01_thermostat_01",
	"cmd": "set_temprature",
	"value": 26,
	"boiler": "01",
	"room": "01"
}

Later on I could substract the data from the enity_id I guess.

[{"id":"88553c180b60c1ad","type":"mqtt in","z":"df0633f3e1626eb1","name":"","topic":"homeassistant/heating/#","qos":"2","datatype":"json","broker":"b3d85074aaaa3a1c","nl":false,"rap":true,"rh":0,"x":710,"y":620,"wires":[["0b2bdbe9a7fa47d6"]]},{"id":"3f09068aa3521e81","type":"switch","z":"df0633f3e1626eb1","name":"route_command","property":"data.cmd","propertyType":"msg","rules":[{"t":"eq","v":"turn_off","vt":"str"},{"t":"eq","v":"turn_on","vt":"str"},{"t":"eq","v":"set_temprature","vt":"str"}],"checkall":"true","repair":false,"outputs":3,"x":1150,"y":620,"wires":[["51bf181efe79eb85"],["1c4a2640a0b46822"],["5eae7f49b1eaab90"]]},{"id":"1c4a2640a0b46822","type":"debug","z":"df0633f3e1626eb1","name":"turn_on","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":1370,"y":660,"wires":[]},{"id":"51bf181efe79eb85","type":"debug","z":"df0633f3e1626eb1","name":"turn_off","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"\"off\"","targetType":"jsonata","statusVal":"","statusType":"auto","x":1370,"y":620,"wires":[]},{"id":"5eae7f49b1eaab90","type":"ha-get-entities","z":"df0633f3e1626eb1","name":"Get all entities","server":"fa2a964fbd125eb1","version":0,"rules":[{"property":"entity_id","logic":"is","value":".*","valueType":"re"}],"output_type":"array","output_empty_results":true,"output_location_type":"msg","output_location":"payload","output_results_count":1,"x":680,"y":780,"wires":[["81aa19ed69eccd1e"]]},{"id":"d43d39a593c7ad90","type":"api-call-service","z":"df0633f3e1626eb1","name":"","server":"fa2a964fbd125eb1","version":3,"debugenabled":true,"service_domain":"switch","service":"{{data.value}}","entityId":"{{payload.entity_id}}","data":"","dataType":"json","mergecontext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":1290,"y":780,"wires":[[]]},{"id":"81aa19ed69eccd1e","type":"function","z":"df0633f3e1626eb1","name":"Filter entities by ID","func":"// I think this can be done in \"Get all entities\". \n// Todo find out how to filter general expressoins with data from the message\n\nconst values = Object.values(msg.payload);\n\nlet entities = [];\nconst entityBase =  \"heating_\" +\n                    \"boiler_\" + msg.data.boiler + \"_\" +\n                    \"room_\" + msg.data.room;\n\nvalues.forEach(entity => {\n    \n    if(entity.entity_id.includes(entityBase)   ){\n        entities.push(entity);\n    }\n})\n\nmsg.payload = entities;\nreturn msg;\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":900,"y":780,"wires":[["9c3e8704e648d97e"]]},{"id":"9c3e8704e648d97e","type":"split","z":"df0633f3e1626eb1","name":"","splt":"\\n","spltType":"str","arraySplt":1,"arraySpltType":"len","stream":false,"addname":"","x":1090,"y":780,"wires":[["d43d39a593c7ad90"]]},{"id":"0b2bdbe9a7fa47d6","type":"function","z":"df0633f3e1626eb1","name":"Copy data","func":"// copy payload to data, because we need the payload for something else at \"get entities\". \nmsg.data= msg.payload;\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":950,"y":620,"wires":[["3f09068aa3521e81"]]},{"id":"b3d85074aaaa3a1c","type":"mqtt-broker","name":"","broker":"192.168.1.206","port":"1883","clientid":"","usetls":false,"protocolVersion":"4","keepalive":"60","cleansession":true,"birthTopic":"homeassistant/climate/thermostat","birthQos":"0","birthPayload":"\"hello world\"","birthMsg":{},"closeTopic":"homeassistant/climate/thermostat","closeQos":"0","closePayload":"\"goodbye\"","closeMsg":{},"willTopic":"","willQos":"0","willPayload":"","willMsg":{},"sessionExpiry":""},{"id":"fa2a964fbd125eb1","type":"server","name":"Home Assistant","version":1,"legacy":false,"addon":true,"rejectUnauthorizedCerts":true,"ha_boolean":"y|yes|true|on|home|open","connectionDelay":false,"cacheJson":true}]

This test flow is just to see how to switch many devices without adding them as nodes to the flow. To keep it flexible.

if you can change the entity_id, then you will have it easier with the split.
If you could do something like “heating_boiler-01–room-01–thermostat_01”, then first a split on “–” will give you “heating_boiler-01”, “room-01” and “thermostat-01”.
Then you could do a key/value on those and get heating_boiler:01, room:01 and thermostat:01.

Problem with this is that in Node-RED the obj.entity_id and the obj.attributes.friendly_name both return like heating_boiler_01_room_01_thermostat_01. So, it converts all the other characters to underscores. This means, that on a device state change I cannot subtract it like this. (I could split the string and look for the keywords “boiler” and “room” and then grab the index+1. But this feels not that clean :slight_smile: )

I see, but your solution seems to be one of the only ones then.
The other would be to read the fixed positions, if only the numbers change.

Somehow another page to edit the device name gives no error. So I was able to rename the devices.
I’ve implemented your suggestion and now am able to reuse it for mqtt events and device events. I think I’m now up to speed to develop the thermostat rules in general. Thanks!

[{"id":"6aeb66b5e4679bc8","type":"subflow","name":"getDataFromEntityName","info":"","category":"","in":[{"x":40,"y":80,"wires":[{"id":"4824471d79ba0f7d"}]}],"out":[{"x":580,"y":80,"wires":[{"id":"0b2bdbe9a7fa47d6","port":0}]}],"env":[],"meta":{},"color":"#DDAA99"},{"id":"0b2bdbe9a7fa47d6","type":"function","z":"6aeb66b5e4679bc8","name":"getFriendlyName","func":"let routeInfo;\n\nif(msg.data.hasOwnProperty('attributes')){\n    \n    routeInfo = msg.data.attributes.friendly_name;\n    \n} else if(msg.data.hasOwnProperty('new_state')){\n    \n    routeInfo = msg.data.new_state.attributes.friendly_name;\n    \n} else if(msg.data.hasOwnProperty('entity_id')){\n    \n    routeInfo = msg.data.entity_id;\n    \n} \n\nrouteInfo = routeInfo.split('_');\n\nrouteInfo.forEach( value => {\n    \n    value = value.split('-');\n    if(value.length > 1){\n        msg.data[value[0]] = value[1];\n    }\n});\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":410,"y":80,"wires":[[]]},{"id":"4824471d79ba0f7d","type":"function","z":"6aeb66b5e4679bc8","name":"copyData","func":"// copy payload to data, because we need the payload for something else at \"get entities\". \nif( typeof msg.payload === 'object' ){\n    msg.data= msg.payload;\n} else {\n    if(!msg.hasOwnProperty('data')){\n        msg.data = {};\n    }   \n    msg.data.cmd = msg.payload;\n}\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":200,"y":80,"wires":[["0b2bdbe9a7fa47d6"]]},{"id":"df0633f3e1626eb1","type":"tab","label":"Flow 2","disabled":false,"info":""},{"id":"88553c180b60c1ad","type":"mqtt in","z":"df0633f3e1626eb1","name":"","topic":"homeassistant/heating/#","qos":"2","datatype":"json","broker":"b3d85074aaaa3a1c","nl":false,"rap":true,"rh":0,"x":590,"y":620,"wires":[["c96c54721c525cf1"]]},{"id":"3f09068aa3521e81","type":"switch","z":"df0633f3e1626eb1","name":"route_command","property":"data.cmd","propertyType":"msg","rules":[{"t":"eq","v":"turn_off","vt":"str"},{"t":"eq","v":"turn_on","vt":"str"},{"t":"eq","v":"set_temprature","vt":"str"}],"checkall":"true","repair":false,"outputs":3,"x":1093,"y":621,"wires":[["51bf181efe79eb85"],["1c4a2640a0b46822"],["5eae7f49b1eaab90"]]},{"id":"1c4a2640a0b46822","type":"debug","z":"df0633f3e1626eb1","name":"turn_on","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":1313,"y":661,"wires":[]},{"id":"51bf181efe79eb85","type":"debug","z":"df0633f3e1626eb1","name":"turn_off","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"\"off\"","targetType":"jsonata","statusVal":"","statusType":"auto","x":1313,"y":621,"wires":[]},{"id":"5eae7f49b1eaab90","type":"ha-get-entities","z":"df0633f3e1626eb1","name":"Get all entities","server":"fa2a964fbd125eb1","version":0,"rules":[{"property":"entity_id","logic":"is","value":".*","valueType":"re"}],"output_type":"array","output_empty_results":true,"output_location_type":"msg","output_location":"payload","output_results_count":1,"x":623,"y":781,"wires":[["81aa19ed69eccd1e"]]},{"id":"d43d39a593c7ad90","type":"api-call-service","z":"df0633f3e1626eb1","name":"","server":"fa2a964fbd125eb1","version":3,"debugenabled":false,"service_domain":"switch","service":"{{data.value}}","entityId":"{{payload.entity_id}}","data":"","dataType":"json","mergecontext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":1233,"y":781,"wires":[[]]},{"id":"81aa19ed69eccd1e","type":"function","z":"df0633f3e1626eb1","name":"Filter entities by ID","func":"// I think this can be done in \"Get all entities\". \n// Todo find out how to filter general expressoins with data from the message\n\nconst values = Object.values(msg.payload);\n\nlet entities = [];\nconst entityBase =  \"heating_boiler-\" + msg.data.boiler + \"_\" +\n                    \"room-\" + msg.data.room;\n\nvalues.forEach(entity => {\n    if(entity.attributes.friendly_name.includes(entityBase)   ){\n        entities.push(entity);\n    }\n})\n\nmsg.payload = entities;\nreturn msg;\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":843,"y":781,"wires":[["9c3e8704e648d97e"]]},{"id":"9c3e8704e648d97e","type":"split","z":"df0633f3e1626eb1","name":"","splt":"\\n","spltType":"str","arraySplt":1,"arraySpltType":"len","stream":false,"addname":"","x":1033,"y":781,"wires":[["d43d39a593c7ad90"]]},{"id":"9f9e6b3e1bf5514c","type":"debug","z":"df0633f3e1626eb1","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1210,"y":940,"wires":[]},{"id":"5c0494be58abb4ec","type":"server-state-changed","z":"df0633f3e1626eb1","name":"","server":"fa2a964fbd125eb1","version":3,"exposeToHomeAssistant":false,"haConfig":[{"property":"name","value":""},{"property":"icon","value":""}],"entityidfilter":"switch.heating_boiler_.*_room_.*_.*","entityidfiltertype":"regex","outputinitially":false,"state_type":"str","haltifstate":"","halt_if_type":"str","halt_if_compare":"is","outputs":1,"output_only_on_state_change":false,"for":0,"forType":"num","forUnits":"minutes","ignorePrevStateNull":false,"ignorePrevStateUnknown":false,"ignorePrevStateUnavailable":false,"ignoreCurrentStateUnknown":false,"ignoreCurrentStateUnavailable":false,"outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"entityState"},{"property":"data","propertyType":"msg","value":"","valueType":"eventData"},{"property":"topic","propertyType":"msg","value":"","valueType":"triggerId"}],"x":670,"y":940,"wires":[["715bacf14be3466f"]]},{"id":"c96c54721c525cf1","type":"subflow:6aeb66b5e4679bc8","z":"df0633f3e1626eb1","name":"","env":[],"x":870,"y":620,"wires":[["3f09068aa3521e81"]]},{"id":"715bacf14be3466f","type":"subflow:6aeb66b5e4679bc8","z":"df0633f3e1626eb1","name":"","x":1010,"y":940,"wires":[["9f9e6b3e1bf5514c"]]},{"id":"b3d85074aaaa3a1c","type":"mqtt-broker","name":"","broker":"192.168.1.206","port":"1883","clientid":"","usetls":false,"protocolVersion":"4","keepalive":"60","cleansession":true,"birthTopic":"homeassistant/climate/thermostat","birthQos":"0","birthPayload":"\"hello world\"","birthMsg":{},"closeTopic":"homeassistant/climate/thermostat","closeQos":"0","closePayload":"\"goodbye\"","closeMsg":{},"willTopic":"","willQos":"0","willPayload":"","willMsg":{},"sessionExpiry":""},{"id":"fa2a964fbd125eb1","type":"server","name":"Home Assistant","version":1,"legacy":false,"addon":true,"rejectUnauthorizedCerts":true,"ha_boolean":"y|yes|true|on|home|open","connectionDelay":false,"cacheJson":true}]

Looking great!
Happy Playing! :smiley:

1 Like