Select all lights on one floor with a Template

Hi,

I would like to select all lights in a certain ‘room’ (‘ruimte’ in Dutch) so that I can inform with a mushroom card the user how many lights are (still) on on that floor, or in that room.

Now I have it hardcoded with a manual filled array of all lights on that floor like this:

      - type: vertical-stack
        cards:
          - type: custom:mushroom-title-card
            title: 1e Verdieping
            subtitle: >-
              Er zijn {{ [
              'light.badkamer_bad',
              'light.badkamer_douche', 
              'light.badkamer_toilet' ,
              'light.badkamer_wastafel' ,
              'light.slaapkamer_kleurenlamp',
              'light.overloop_lamp',
              'light.kantoor_burolamp',
              'light.kantoor_plafond_kast',
              'light.kantoor_plafond_lamp_printer', 
              'light.kantoor_plafond_schilderij'
              ] | select('is_state', 'on') | list | count }} op de eerste verdieping aan, {{user}}!

But that isn’t very flexible; as soon as I add a light, I need to code again.

On my first floor I have the following Rooms/Ruimtes (which I consider as a pretty stable list):

  • Slaapkamer
  • Logeerkamer
  • Badkamer
  • Kantoor
  • Overloop

How do I achieve that?

Regards,
Martin

Never tried this, but assigning an area to each light seems to give you a number of template filtering options:

You can sum the counts from different areas as follows:

- type: vertical-stack
  cards:
    - type: custom:mushroom-title-card
      title: 1e Verdieping
      subtitle: >-
        {% set ns = namespace(lights_on=[]) %}
        {% set region = ['Slaapkamer', 'Logeerkamer', 'Badkamer',
        'Kantoor', 'Overloop'] %}
        {% for room in region %}
        {% set ns.lights_on = ns.lights_on + [area_entities(room)
        | select('match', 'light.*') | select('is_state', 'on') | list | count ] %}
        {% endfor %}
        Er zijn {{ ns.lights_on | sum }} op de eerste verdieping aan, {{user}}!

However, using an Area-based approach may end up needing just as much maintenance as your original method. There can be numerous integrations that create light entities that you don’t want to include in your count which you will have to reject from the results of the template or disable. Light groups pose a similar issue that you will need to decide how to handle and possibly update every time you add or change a light group.

As I’m not (yet) so familiar with templating and this language,

Can you step by step explain to me what you are doing with this code so that I can reproduce it myself in other situations?

I have JavaScript and React experience, so I do understand programming in general but this syntax has some caviats I expect.

Thanks in advance

Sources for Jinja Templating Information

Home Assistant Templating : This is the the most comprehensive source for HA-specific functions

Jinja Docs: These docs are not geared toward new/casual users, but they contain a lot of important information.

Jinja for Ninjas: @skalavala has put together a well organized tutorial and group of examples. It’s been a while since this was updated, so there are better/easier ways to do some of the things shown, but it’s still a good source.

Many Python methods also to work in templates. I’ve never seen a complete list of which methods work and which don’t… But the Official Python docs have come in handy for me multiple times to figure out what’s going on in templates posted by some of the more advanced users on this forum.


{% set ns = namespace(lights_on=[]) %}
{% set region = ['Slaapkamer', 'Logeerkamer', 'Badkamer',
'Kantoor', 'Overloop'] %}

Setup variables:
A namespace is needed so that we can access the information outside of the loop.

{% for room in region %}
   {% set ns.lights_on = ns.lights_on + [area_entities(room)
   | select('match', 'light.*') | select('is_state', 'on') | list | count ] %}
{% endfor %}

Loop through rooms.
area_entities(room): Instantiate a list of the entitie IDs assigned to a given Area.
| select('match', 'light.*'): Keep all entity IDs that contain “light.”
| select('is_state', 'on'): Keep only entity IDs for entities whose state is “on”
| list | count : Generate a list of the entity IDs and return the count of items in the list

Er zijn {{ ns.lights_on | sum }} op de eerste verdieping aan, {{user}}!

Return results:
ns.lights_on | sum: Return the sum of all the counts in the list.

1 Like

You can use | reject('is_hidden_entity') to ease your life.

Came across this looking for a solution.
Didgeridew’s answer helped a lot, but I managed to improve upon it thanks to the recent addition of some functions
So I thought I’d share here for anyone else looking for a better answer

- type: vertical-stack
  cards:
    - type: custom:mushroom-title-card
      title: 1e Verdieping
      subtitle: >-
        {% set ns = namespace(lights_on=[]) %}
        {% set region = floor_areas('floor_1') %}
        {% for room in region %}
        {% set ns.lights_on = ns.lights_on + [area_entities(room)
        | select('match', 'light.*') | select('is_state', 'on') | list | count ] %}
        {% endfor %}
        Er zijn {{ ns.lights_on | sum }} op de eerste verdieping aan, {{user}}!
1 Like

Alternative that doesn’t use a for-loop.

- type: vertical-stack
  cards:
    - type: custom:mushroom-title-card
      title: 1e Verdieping
      subtitle: >-
        {% set x = floor_areas('floor_1') | map('area_entities') | sum(start=[])
          | select('match', 'light') | select('is_state', 'on') | list | count %}
        Er zijn {{ x }} op de eerste verdieping aan, {{ user }}!

Other examples here: