Automation trigger on any member of a group, is it possible?

OK so

  • a separe list of devices in entity_id in trigger : one of them match the rule -> action is triggered
  • a group in entity_id in trigger : all of them match the rule -> action is triggered
  • a group in entity_id in action : all of them are actioned on

Correct ?

Not quite.

The important thing to understand about using a group in a state trigger is that the group’s state only changes when it goes from “all off/not_home/etc.” to “one or more on/home/etc.”, and vice versa. Going from “one on/home/etc.” to “two on/home/etc.”, or any other transition where there are one or more on/home/etc. to still one or more on/home/etc., does not cause a state change (because the group’s state will continue to be on/home/etc.), and hence, will not trigger the automation.

Next, if you have a list of entities for a state trigger, the automation will trigger when the state of any of those entities transitions as defined. (If you don’t specify from or to then any state transition will cause a trigger.) If one of those entities (or the only entity specified) is a group, then the group’s state has to change (which may or may not happen when the state of a single entity in the group changes, due to what I described above.)

So, bottom line, if you want an automation to trigger when any entity in a group changes state, you can’t use the group in the trigger; you have to use the individual entities.

For what it’s worth, I’ve been trying to find a way to cause an automation to trigger when any item in a group changes. So far all attempts I’ve tried have failed. I’ve even been paying attention to other topics where this is discussed, and so far I haven’t seen any solutions. But it just occurred to me of one potential way to do it. I.e., create a sensor whose state is a count of the number of entities in a group that are on (or home or whatever.) I know how to do this with a template sensor. Then use that as the trigger. Also use a condition to qualify. E.g., if you want to trigger whenever someone comes home, the condition would be trigger.to_state.state > trigger.from_state.state, because someone coming home would cause the count of entities home to increase. Hmm, I’ll have to give this a try…

4 Likes

So here’s how to create a template sensor whose state is the number of people home. In this example I’m using the automatic device tracker group group.all_devices and an input boolean I use to indicate that there are guests staying in the house (which I use to effectively disable some automations):

sensor:
  - platform: template
    sensors:
      n_people_home:
        friendly_name: Number of People Home
        value_template: >
          {{ states|selectattr('entity_id','in',state_attr('group.all_devices','entity_id'))
                   |selectattr('state','eq','home')|list|count +
             (1 if is_state('input_boolean.guests','on') else 0) }}

The first part filters down the list of all states in the State Manager to just those that correspond to entities in the automatic device tracker group, and then further filters those down to just the ones of those whose states are home. Then it filters that into a count of those state objects. The result is the number of entities in group.all_devices that are home.

Next I add one to that if input_boolean.guests is on.

I haven’t yet tried this in my automations, but the basic idea is, if you want to trigger when someone comes home (or if input_boolean.guests is turned on), then it might look something like this:

automation:
  - alias: Trigger when someone comes home
    trigger:
      platform: state
      entity_id: sensor.n_people_home
    condition:
      condition: template
      value_template: >
        {{ trigger.to_state.state|int > trigger.from_state.state|int }}
    action:
      ...
1 Like

nice! though in my setup the result is 39… :wink: many devices using home… now how to filter out those, instead of simply using group.family (which has max 6 entity_id’s in our household…)

Not exactly sure what you’re asking, but basically, if you have a group (or you can create one) that contains the entities you care about in some particular scenario, and you want to get the count of the entities in that group that are in some particular state, then you can adjust the template accordingly. I.e., change 'group.all_devices' to whatever group you’re using, and change 'home' to whatever state you’re interested in. And, of course, you can delete the + (1 if ... else 0) part.

related probably:

using this template to do exactly what your trying to do above, count or show who is home:

  - platform: template
    sensors:
      who_is_home:
        friendly_name: Who is home
        value_template: >
          {% if is_state('group.family', 'home') %}
            {{ dict((states|selectattr('entity_id', 'in', state_attr('group.family', 'entity_id'))
            |list)|groupby('state'))['home']|map(attribute='name')|list|join(', ') }}
          {%else%}
            Nobody home
          {%endif%}

the template works fine in the dev-tools, but in the frontend is showing only correct at reboot. Why doesnt this trigger automatically following the states of the devices?
refreshing the page, nor reloading the core help. only restarting Hassio.

1 Like

sure, i understood as much, maybe was merely wondering if this was a real life scenario template or just for educational purposes. Really appreciate though, my next step in templating! so thanks

Hmm, good question. My “solution” of a count template sensor might suffer from the same problem. I only tested it by changing input_boolean.guests. Let me do some more testing by actually changing one of the device_tracker entities and see if it updates…

Darn! It doesn’t work either. I think the issue is the template processing code only sees the group entity (besides the input_boolean), so only updates when the group’s state changes, which is the same problem that started this topic. The only way I can see to solve this is to list all the entities of the group in the optional entity_id parameter of the template sensor. E.g.,

sensor:
  - platform: template
    sensors:
      n_people_home:
        friendly_name: Number of People Home
        entity_id:
          - device_tracker.name1
          ...
          - device_tracker.nameN
          - input_boolean.guests
        value_template: >
          {{ states|selectattr('entity_id','in',state_attr('group.all_devices','entity_id'))
                   |selectattr('state','eq','home')|list|count +
             (1 if is_state('input_boolean.guests','on') else 0) }}

Not much better than just listing the individual entities in the automation trigger itself. But, I suppose, if you had many automations based on this, or had other uses for the count, then it might be worth it. I’ll give this a try and report back for completeness.

2 Likes

cool, glad its not me :wink:

Listing the entity_id’s in the template sensor makes it work. Now whenever any of the individual device_tracker entities change the sensor is updated.

So there are certainly some trade-offs here. Using this technique requires creating a new entity, and although it simplifies the automation trigger, it requires an additional condition. Also, if any device_tracker entities are added or removed, it still requires updating accordingly. Still, I think it might be useful, especially as I said, if you have multiple automations based on this or could use the count elsewhere. I think I’ll switch over my automations to use it. If I run into any unexpected problems, I’ll be sure to reply here again with an update.

Just an FYI template triggers and template sensors only update if the entity id’s spelled out in the templates update. So using any kind of group to search through it’s entities will only fire when the group’s state changes, not it’s underlying entities.

1 Like

well, it was worth the try, and i’ve learned a lot about lists and dictionaries. And again about the behavior and treatment of groups. not nearly enough.

luckily I have python to the rescue though to list the people at home within the blink of an eye and do exactly what we want here :wink:

just as an extra note:
this template on motion detection, tased on the same technique does respond rather swiftly. It only shows 1 sensor, admitted, but it does respond to changes when they trigger:

value_template: >
  {% if is_state('group.philips_motion_sensors', 'off') %}
    Clear
  {%else%}
    {{ dict((states|selectattr('entity_id', 'in', state_attr('group.philips_motion_sensors', 'entity_id'))
      |list)|groupby('state'))['on']|map(attribute='name')|list|join(', ') }}
  {%endif%}

not sure I understand why the difference in behavior compared to the people home scenario. Could the opposed logic of if > then > else be it? or would it be the fact that every few seconds the motion sensors are all off, the group is off, and on triggering the template kicks in?

If the latter would be the case, some sort of extra condition or time trigger could be added to the people home template, eg run every 10 sec or so?

Well, if you want to know how it works, I can explain:

Basically, the template sensor/trigger when created parses the template and finds all the entity_ids that will update the sensor or cause a trigger. It then listens to those entitys and updates based on their state. If you list the group, the parser only finds the group because the template has no reference to the groups entity list. That’s why template sensors has the entity_id list as an option. You can add a listener to those extra entities that way.

It’s not really spelled out that way in the documentation, I only found it out by reading the code and following the flow.

I’m not sure, it’s possible that the groups update differently when some devices are inside them. My guess is that would be the case for presence detection whereas lights wouldn’t need that. I’d have to look over the group code to know for sure…

1 Like

quite. thanks.

since you mention adding a listener: every once in a while i see errors in the logs not being able ‘to remove a listener’ or the likes of this.

Any ideas what those could refer to:

2018-06-13 16:54:01 WARNING (MainThread) [homeassistant.core] Unable to remove unknown listener <function async_track_point_in_utc_time.<locals>.point_in_time_listener at 0x6e373a08>

followed by:

Traceback (most recent call last):
  File "uvloop/cbhandles.pyx", line 49, in uvloop.loop.Handle._run
  File "/usr/lib/python3.6/site-packages/homeassistant/helpers/event.py", line 211, in point_in_time_listener
    hass.async_run_job(action, now)
  File "/usr/lib/python3.6/site-packages/homeassistant/core.py", line 253, in async_run_job
    target(*args)
  File "/usr/lib/python3.6/site-packages/homeassistant/helpers/script.py", line 95, in async_script_delay
    self._async_listener.remove(unsub)
ValueError: list.remove(x): x not in list

Wouldn’t worry about it. Home assistant is trying to cancel a listener that doesn’t exist. Something else may have canceled it

So, to put it all together, here is what I have, which seems to work:

input_boolean:
  guests:
    name: We have guests
    icon: mdi:account-multiple

input_select:
  home_mode:
    name: Home Mode
    icon: mdi:home-account
    options:
      - Home
      - Away
      - Returning
      - Vacation

sensor:
  - platform: template
    sensors:
      n_people_home:
        friendly_name: Number of People Home
        entity_id:
          - device_tracker.name1
          - device_tracker.name2
          - device_tracker.name3
          - input_boolean.guests
        value_template: >
          {{ states|selectattr('entity_id','in',
                      state_attr('group.all_devices','entity_id'))
                   |selectattr('state','eq','home')|list|count +
             (1 if is_state('input_boolean.guests','on') else 0) }}

automation:
  - alias: Home Mode - Leaving
    trigger:
      platform: numeric_state
      entity_id: sensor.n_people_home
      below: 1
    condition:
      condition: state
      entity_id: input_select.home_mode
      state: Home
    action:
      service: input_select.select_option
      entity_id: input_select.home_mode
      data:
        option: Away

  - alias: Home Mode - Arriving
    trigger:
      platform: state
      entity_id: sensor.n_people_home
    condition:
      condition: template
      value_template: >
        {{ trigger.to_state.state|int > trigger.from_state.state|int }}
    action:
      service: input_select.select_option
      entity_id: input_select.home_mode
      data:
        option: Home
1 Like

I just found this thread as I was trying to trigger off any entity in a group changing. My biggest motivation is being able to add a new member to a group and have everything associated with that group seamlessly work/update.

It seems the way things currently are, I will have to manually find any automations that list the entity ids separately and add the new member manually to those lists. If you miss an automation in the manual update, it won’t respond to the new entity and it may take a long time to realize it was missed.

I was hoping something like this would work:

    trigger:
      - platform: template
        value_template: >
          {% set entities = expand('group.indoor_light_summary') %}
          {%- for x in entities -%}
          - {{ x.entity_id }}
          {% endfor %}

Is there still no way to use some kind of variable/template for the list of id’s so you don’t have to do a bunch of manual updating?

2 Likes

I guess one kind of nasty work around with limited value would be to use sensor.time as the trigger and then use conditions and/or templates as desired. I recently got help from some members here on creating a sensor for a list of any low batteries that home assistant is monitoring.

  ### Low Battery Sensor
  - platform: template
    sensors:
      low_batteries:
        entity_id: sensor.time
        value_template: >-
          {% set entities = expand('group.door_lock_batteries') +
                            expand('group.door_sensor_batteries') +
                            expand('group.motion_sensor_batteries') +
                            expand('group.temp_sensor_batteries') +
                            expand('group.other_batteries') +
                            expand('group.button_cube_batteries') %}
          {% for x in entities if x.state|int < 30 %}
            {%- if not loop.first %}, {% endif -%}
            {{- x.name -}}
          {% endfor %}

had the same idea: Use new template 'expand' functionality in automation trigger?

no solution just yet…it simply isnt accepted by the config checker. so not even a matter of updating or not