Unleash the power of 'expand' for Template Sensors

Great work @123! Will your PR make it in the next release (0.110)?

I had no part in the PR. All the credit goes to Tho85.

The PR was merged into the home-assistant:dev branch. I don’t know if it will appear in 0.110.

Update:

The blog post for 0.110.0 indicates that the PR was merged into the release. However, I tested it, using the example provided in the PR, and it did not work as advertized.

I have reported it as an Issue in the Core repo.

1 Like

I have a solution for not having to include every single entity_id, just create an automation that triggers when a light changes it’s state and force the update of the sensor
like this:

automation:
  - alias: current_lights_on
    initial_state: true
    trigger:
      - platform: event
        event_type: call_service
        event_data:
          domain: light
    action:
      - service: homeassistant.update_entity
        entity_id: sensor.current_lights_on

That’s an interesting workaround but it will trigger when any light’s state changes even lights that are not part of the desired group.

The goal is to update the sensor only when one of the group’s members changes state (and not just any light entity). The PR to implement this functionality is currently awaiting review and will hopefully be incorporated in the next major release.

been using this for a long time, now parked, but still functional:

  - alias: 'State changed Light'
    id: 'State changed Light'
    initial_state: 'off'
    trigger:
      platform: event
      event_type: state_changed
    condition:
      condition: template
      value_template: >
        {{trigger.event.data.entity_id in state_attr('group.all_lights_only','entity_id')}}
    action:

and this would be possible too:

  - alias: 'Call Service Event Light'
    id: 'Call Service Event Light'
    initial_state: 'off'
    trigger:
      platform: event
      event_type: call_service
      event_data:
        domain: light
    condition:
      condition: template
      value_template: >
        {{trigger.event.data.entity_id in state_attr('group.all_inside_lights','entity_id')}}

of course change the group to your needs.

or select more groups :wink:

      value_template: >
        {% for x in
             ['family',
              'hubs_binary_pinged',
              'critical_devices_state',
              'media_player_media',
              'device_tracker_media',
              'all_lights_only',
              'iungo_switch_switches_template',
              'iungo_switch_appliances_template',
              'binary_sensors_active_template']
          if trigger.event.data.entity_id in state_attr('group.'+x,'entity_id') %} true
        {% else %} false
        {% endfor %}
1 Like

… and when the PR is merged these additional automations will be unnecessary.

1 Like

yep, wanted to type:
‘and still would very much welcome the PR’ …

but you beat me :wink:

Yes, it triggers every light, but that’s not a problem at all. If a light isn’t in the group the state remain the same

It’s inefficient. Given a group of 5 lights out of 30 lights, the sensor requires updating only when one of the 4 lights changes state, not when one of the 25 other lights change.

In addition, the automation monitors all call_service events and then filters for domain = light. So the automation’s trigger is evaluated for service calls beyond just the ones for lights.

Totally agree, but that’s a temporary workaround until something better is released
This way I don’t need to input every entity_id which is very great. I only need to maintain the group list

yes that is of course true, and reason I went another way with these automations. Would you expect the unleashing of ‘expand’ to truly only see to those entities, or might it under the hood do the exact same thing…as it has to expand the group first, and then add some filtering, I would think it also has some overhead?

It appears that the problem that prevented this feature from working correctly (when it was first introduced in version 0.110) has been resolved.

So the new functionality should appear in 0.114 and a Template Sensor like this will work correctly:

  - platform: template
    sensors:
      lights_on:
        friendly_name: 'Lights ON'
        value_template: >-
          {{ expand('group.my_lights')
             | selectattr('state', 'eq', 'on')
             | list | count }}

The lights within group.my_lights will be monitored for changes.

If you add a light to the group, you won’t have to re-visit this Template Sensor to update any entities. However, you will need to restart Home Assistant first so that it re-evaluates the Template Sensor and detects the new light in the group. Currently, there’s no “reload” service for Template Sensors, so restarting Home Assistant is the only way to re-configure them.

… and, no, executing group.reload isn’t a substitute for restarting Home Assistant. On startup, Home Assistant examines a Template Sensor’s template, identifies entities, and assigns a listener to each entity. That operation occurs on startup and not when group.reload is executed.

Do you know if this will work as a trigger for automations? Like, trigger off of a state change from any off the group? Let’s say motion sensors on the ground floor.

Could we still use trigger.to_state.entity_id? Or would it point to the group id instead of the individuals?

I tested 0.114 and the new functionality still doesn’t work. I have reported the problem.

1 Like

I’m pleased to report that the new functionality works in 0.115.

Here’s a simple demonstration of how listeners are assigned to entities when your template uses expand.

Let’s say we have three groups, where the third one incorporates the first two (i.e nested groups).

  lights_downstairs:
    - light.family_mantle
    - light.family_ceiling
    - light.kitchen_ceiling

  lights_upstairs:
    - light.hallway_ceiling
    
  lights:
    - group.lights_downstairs
    - group.lights_upstairs

The following template is assigned listeners to each group and, most importantly, to each one of the four entities represented by the groups:

In addition, you can add/subtract entities from a group, execute Reload Groups, and the listeners are automatically updated.

2 Likes

just wondering if we could also subtract expanded groups?
something like:

for s in (expand('group.all_switches') - expand('group.switches_to_exclude'))

I am now using this:

{%- set ns = namespace(not_off=[]) %}
{%- for s in expand('group.iungo_switches_actueel')
  if s.entity_id not in
     ['sensor.inductieplaat_actueel','sensor.patchboard_zolder_actueel']  and
    (states(s.entity_id) != '0' and
     states(s.entity_id.split('_actueel')[0]|replace('sensor','switch')) == 'off') %}
{%- set ns.not_off = ns.not_off + [s] %}
{%- endfor %}
{{ns.not_off|count}}

but it would be way easier if I could subtract those listed entity_id’s which are also in a group.

I bookmarked this ages ago to answer and forgot all about it.

I’m sure you found the answer but thought I’d still reply in case anyone else wondered.

Probably an easier way to do it but this works.

expand('group.quiet_speakers')|map(attribute='entity_id')|reject('in',expand('group.night_speakers')|map(attribute='entity_id'))|list

2 Likes

I’m going to close this as this is the behavior of templates now.

TLDR: All templates create listeners for states objects that are hit in the template logic. So expanding a group will create listeners for each entity in said group.

1 Like