Thanks @stevemann / @Hellis81 - combining both your comments gave me an idea.
I’ve essentially created an “expand” node in Node Red using function nodes and use that to filter the events coming from an “Event: All” node
UPDATED with the regexp suggestion below so we don’t use the “Event: All” node.
I have two parts to the flow:
-
Subscribes to the actual group I want. It will then expand the entities and save it to a flow variable. This will be checked any time the state of the light group is changed.
-
The second part of the flow uses the “state changed” node with a regular expression to limit it to just lights (this is just to reduce the number of events we need to process). It will then check if the light that
changed is a light in our list of lights in the group. If it is then it will forward on the payload.
This then allows me to detect any changes in the light group.
[{"id":"2b79b1c358a510e2","type":"tab","label":"Flow 1","disabled":false,"info":"","env":[]},{"id":"a1919913755ef30d","type":"function","z":"2b79b1c358a510e2","name":"Filter out lights not in the light group","func":"var d = msg[\"data\"]\nif (d === undefined) {\n node.error(\"Data was undefined: \" + msg);\n return null;\n}\n\nvar changed_entity_id = d[\"entity_id\"]\n\nvar new_state = d[\"new_state\"]\nif (new_state === undefined) {\n node.error(\"New State was undefined: \" + changed_entity_id);\n return null;\n}\n\nvar entity_attributes = new_state[\"attributes\"]\nif(entity_attributes === undefined) {\n node.error(\"Attributes was undefined: \" + changed_entity_id);\n return null;\n}\n\nvar group_entity_ids = entity_attributes[\"entity_id\"]\nif(!(group_entity_ids === undefined)) {\n // If we have entities this is a group so ignore it\n // we are only insterested in actual lights\n return null;\n}\n\n// Get the previously created list of lights\nvar valid_entity_ids = flow.get(\"lights_in_group\")\n// If the variable isn't set yet we don't let anything through\n// This is preferable for my situation.\nif (valid_entity_ids === undefined) {\n node.error(\"Lights in group not set yet\");\n return null;\n}\n\nif(valid_entity_ids.includes(changed_entity_id)) {\n // Make the payload look the same as the state_changed node would produce\n // var newMsg = {\n // payload: msg.payload.event.new_state.state,\n // data: msg.payload.event\n // }\n // return newMsg;\n return msg\n} else {\n return null;\n}\n\n\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":600,"y":220,"wires":[["a8ca976a162c4234"]]},{"id":"a98a8ce84e87e90c","type":"server-state-changed","z":"2b79b1c358a510e2","name":"","server":"f71a28fc.c73d58","version":4,"exposeToHomeAssistant":false,"haConfig":[{"property":"name","value":""},{"property":"icon","value":""}],"entityidfilter":"light.all_downstairs_lights_group","entityidfiltertype":"exact","outputinitially":true,"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":220,"y":120,"wires":[["acc60331edae4e77"]]},{"id":"2a7708567efd0da0","type":"change","z":"2b79b1c358a510e2","name":"","rules":[{"t":"set","p":"lights_in_group","pt":"flow","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":850,"y":120,"wires":[[]]},{"id":"acc60331edae4e77","type":"function","z":"2b79b1c358a510e2","name":"Get all lights in light group","func":"var light_group_entity_id = msg.topic\nvar list_of_valid_entities = get_entities_in_group(light_group_entity_id)\n\nvar newMsg = { payload: list_of_valid_entities }\nreturn newMsg;\n\n\nfunction get_entities_in_group(entity_id) {\n var return_list = []\n var seen_before = []\n _get_entities_in_group(entity_id, return_list, seen_before)\n return return_list\n}\n\nfunction _get_entities_in_group(entity_id, return_list, seen_before) {\n var states = global.get('homeassistant.homeAssistant.states');\n // Get the state of the light we are checking\n var light_group_entity = states[entity_id];\n if(!(light_group_entity === undefined)) {\n var array_of_entities_in_group = light_group_entity[\"attributes\"][\"entity_id\"];\n\n // IF no entity_id this is an actual light in our group\n // Add it to the list\n if (array_of_entities_in_group === undefined || array_of_entities_in_group.length == 0) {\n return_list.push(entity_id)\n } else {\n // If we have entity_ids - loop through them.\n for (let index = 0; index < array_of_entities_in_group.length; index++) {\n const element = array_of_entities_in_group[index];\n if (!seen_before.includes(element)) {\n seen_before.push(element)\n _get_entities_in_group(element, return_list, seen_before);\n }\n }\n }\n }\n\n}","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":570,"y":120,"wires":[["2a7708567efd0da0"]]},{"id":"a8ca976a162c4234","type":"debug","z":"2b79b1c358a510e2","name":"debug","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":890,"y":220,"wires":[]},{"id":"6b180f7f5023543a","type":"server-state-changed","z":"2b79b1c358a510e2","name":"","server":"f71a28fc.c73d58","version":4,"exposeToHomeAssistant":false,"haConfig":[{"property":"name","value":""},{"property":"icon","value":""}],"entityidfilter":"^light.","entityidfiltertype":"regex","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":140,"y":220,"wires":[["a1919913755ef30d"]]},{"id":"f71a28fc.c73d58","type":"server","name":"Home Assistant","version":2,"addon":true,"rejectUnauthorizedCerts":true,"ha_boolean":"y|yes|true|on|home|open","connectionDelay":true,"cacheJson":true,"heartbeat":false,"heartbeatInterval":30}]