Conditional counting of subgrouped entities

I need to count the powered on lights of a group consisting subgroups and single lights.

{{ states.light.e27
    | selectattr('state', 'eq', 'on')
    | list
    | count
}}

result

Keyerror:

What am I doing wrong?


{{ expand(states.light.e27) }}
[<template TemplateState(<state light.e27=on; min_mireds=153
 max_mireds=500
 effect_list=['colorloop']
 supported_color_modes=['brightness'
 'color_temp'
 'hs']
 color_mode=color_temp
 brightness=31
 color_temp=500
 entity_id=['light.livingroom_lights'
 'light.bedroom_lights'
 'light.lightkitchendimmable']
 friendly_name=e27
 icon=mdi:lightbulb-group
 supported_features=44 @ 2021-05-27T12:40:17.461354+02:00>)>] 
light:
    name: Bedroom lights
    entities:
      - light.light_bed_door_extended_color
      - light.light_bed_window_extended_color
  - platform: group
    name: Livingroom lights
    entities:
      - light.light_living_work
      - light.light_living_read
      - light.light_living_door
  - platform: group
    name: e27
    entities:
      - light.livingroom_lights
      - light.bedroom_lights
      - light.lightkitchendimmable

states.light.e27 is a single light, its not a list. You’re asking it to treat it like a list. You have to expand the group of lights inside it first, try this:

{{ state_attr('light.e27', 'entity_id')
    | expand
    | selectattr('state', 'eq', 'on')
    | list
    | count
}}

It’s not a Group, it’s a Light Group. They’re two different integrations.

You can expand a Group directly but for a Light Group you must do what Central Command provided (expand the Light Group’s entity_id attribute).

Another example of expanding a Light Group can be found here:

Thank you

{{ state_attr('light.e27', 'entity_id')
    | expand
    | selectattr('state', 'eq', 'on')
    | list
    | count
}} # >> Only returns the count of groups though not entities

Heard of flatten though that returns an error

{{ state_attr('light.e27', 'entity_id')
    | expand
    | selectattr('state', 'eq', 'on')
    | list
    | flatten
    | count
}}

Result of having one grouped (bedroom) and one ungrouped light (kitchen) on:

{{ state_attr('light.e27', 'entity_id')
    | expand
    | selectattr('state', 'eq', 'on')
    | list
}}

Result

[<template TemplateState(<state light.bedroom_lights=on; min_mireds=153
 max_mireds=500
 effect_list=['colorloop']
 supported_color_modes=['color_temp'
 'hs']
 color_mode=color_temp
 brightness=1
 color_temp=500
 entity_id=['light.light_bed_door_extended_color'
 'light.light_bed_window_extended_color']
 friendly_name=Bedroom lights
 icon=mdi:lightbulb-group
 supported_features=44 @ 2021-05-27T15:26:35.069098+02:00>)>
 <template TemplateState(<state light.lightkitchendimmable=on; supported_color_modes=['brightness']
 color_mode=brightness
 brightness=254
 is_deconz_group=False
 friendly_name=LightKitchenDimmable
 supported_features=41 @ 2021-05-27T15:26:23.889785+02:00>)>]

That’s an interesting observation.

When you expand a nested Group, it will return all entities from its sub-Groups. Based on your observation, it appears that it doesn’t work the same way for a Light Group; it only returns its direct child-groups and no further.

Ah. light.e27 is a light group containing other light groups. That’s going to be a problem because of what 123 said - you can’t expand a light group like a group, you have to expand its entity_id attribute.

I’m not really sure if there’s a good, generic solution to this problem. You would need to be able to recurse or use a while loop in order to loop through children expanding groups until you got to all the leaf nodes and a Jinja template can’t do either of those things. There is a kind of crappy solution though, you can just loop over an arbitrarily high range and pretend its a while loop using the conditional loop option. So something like this:

{% set ns = namespace(queue=["light.e27"], lights=[]) %}
{% for a in range(1, 100) if ns.queue | count > 0 %}
  {% set light = (ns.queue[-1] | expand)[0] %}
  {% set ns.queue = ns.queue[0:-1] %}
  {% if light.attributes.entity_id is defined %}
    {% set ns.queue = ns.queue + light.attributes.entity_id %}
  {% else %}
    {% set ns.lights = ns.lights + [light] %}
  {% endif %}
{% endfor %}
{{ ns.lights | selectattr('state', 'eq', 'on') | list | count }}

EDIT: In case your wondering as I was, Jinja does not have a break like python does. Which is annoying as this solution would be significantly less crappy with that. Without recursion, while loops or break I think this is kind of the best that can be done here.

1 Like

Awesome work, thank you so much.

Note: Had to change ln3 from @CentralCommand from

{% set light = (ns.queue[-1] | expand)[0] %}

to

{% set light = expand(ns.queue[-1])[0] %}

Otherwise it works only in the the template editor, but not in the config

1 Like