Counts the lights on

Just trying… tell you in a minute after restarting.

Perfect !!! Thank you so much.
Two hours trying to figure out the problem…until i decided to post it here.
Now…no delay.

If they’re all in the group then petro’s suggestion is the way to go.

Yeah, thanks Taras. Tried and working fine.

For future reference, if you want the Template Sensor to include an entity that is not in the group (and for whatever reason you don’t want it within the group), you can simply add it to expand like this:

        value_template: "{{ expand('group.luces', 'light.whatever') | selectattr('state','eq','on') | list | count }}"

EDIT

Correction. Removed errant closing parenthesis.

2 Likes

Just to share how I did it.

image

To explain a bit:

  • My second floor is organized in 4 areas.
  • I have renamed all lights that are part of another light to something like “2nd Floor xyz”. These are for instance IKEA bulbs in a lamp with 3 bulbs. I have organized this using light groups into one light.
  • I use custom button cards for the buttons. Check out https://github.com/custom-cards/button-card.
  - platform: template
    sensors:
      lights_number_on_in_2nd_floor:
        friendly_name: 'Lights on in 2nd floor'
        unique_id: lights_number_on_in_2nd_floor
        value_template: > 
          {%- set search_state = 'on' %}
          {%- set search_areas = ['Office', 'Loft', 'Bedroom', 'Master bedroom'] %}
          {%- set ns = namespace(lights=[]) %}
          {%- for light in states.light | selectattr('state','eq', search_state) %}
            {%- for area in search_areas %}
              {% if area_name(light.entity_id) == area and "2nd Floor" not in state_attr(light.entity_id, "friendly_name") %}
                {%- set ns.lights = ns.lights + [ light.entity_id ] %}
              {% endif%}
              {%- endfor %}
          {%- endfor %}
          {{ ns.lights| list | length }}

Edit: Thanks to @petro and everyone else for the help in the thread.

3 Likes

If you wish, you can reduce the template to this (no for-loops required):

        value_template: > 
          {{ states.light | selectattr('state', 'eq', 'on')
            | rejectattr('name', 'search', '2nd Floor')
            | map(attribute='entity_id') | map('area_name')
            | select('in', ['Office', 'Loft', 'Bedroom', 'Master bedroom'])
            | list | count }}

EDIT

Explanation of how the template works:

  1. Start by selecting all lights.
  2. Select only the lights that are on.
  3. Reject lights whose friendly_name contains the string 2nd Floor'.
  4. Reduce the information to just each light’s entity_id.
  5. Find the area in which each light is located.
  6. Select only the areas matching one of these four: Office’, ‘Loft’, ‘Bedroom’, ‘Master bedroom’.
  7. Convert the resulting information into a list.
  8. Count the number of items in the list.

EDIT

Correction. Replaced attributes.name with name.

7 Likes

Thanks. Will look at it later. More compact code is nice.

Edit: Thanks @123 ! It is working perfectly and the code is more compact. I just had to change attributes.name to attributes.friendly_name. Thanks again man!

Yes, that will work but the mistake I made was including the word attributes. in attributes.name. It only needs to be name because that’s synonymous with the friendly_name attribute (if it exists).

Here’s what I mean:

I have corrected the example in my previous message.

it’s possible to use an event trigger to automatically update the count without having to specify every light in your template.

template sensors that show a count of lights on for a light group:

template:
  - trigger:
        - platform: event
          event_type: state_changed
    sensor:
      - name: Lights On Downstairs
        state: >
          {% set entities = state_attr('light.lights_downstairs',"entity_id") %}
          {% set result = namespace(turned_on=[]) %}
          {% for entity in entities if is_state(entity,'on') %}      
            {% set result.turned_on = result.turned_on + [entity] %}
          {% endfor %}
          {{ result.turned_on | count }}
      - name: Lights On Upstairs
        state: >
          {% set entities = state_attr('light.lights_upstairs',"entity_id") %}
          {% set result = namespace(turned_on=[]) %}
          {% for entity in entities if is_state(entity,'on') %}      
            {% set result.turned_on = result.turned_on + [entity] %}
          {% endfor %}
          {{ result.turned_on | count }}
      - name: Lights On Outside
        state: >
          {% set entities = state_attr('light.lights_outside',"entity_id") %}
          {% set result = namespace(turned_on=[]) %}
          {% for entity in entities if is_state(entity,'on') %}      
            {% set result.turned_on = result.turned_on + [entity] %}
          {% endfor %}
          {{ result.turned_on | count }}

light group:

light:
  - platform: group
    name: Lights Downstairs
    entities:
      - light.breakfast_room_light
      - light.family_room_light
      - light.dining_room_light
      - light.kitchen_light
      - light.living_room_light
      - light.living_room_reading_light
      - light.office_light
      - light.tv_light
      - light.foyer_light
      - light.closet_light
      - light.stairs_light
      - light.desk_light

this type of template sensor would perform better if the event trigger data filter accepted wildcards, e.g.

  - trigger:
      - platform: event
        event_type: state_changed
        event_data:
          entity_id: light.*  # not supported in 2021.11.1 ...

*edit: complete sensor, light group, and failed event_data wildcard filter test result

1 Like

It’s possible, but not recommended.

You are suggesting to use an Event Trigger to monitor state_changed events. That means it will be triggered by every state-change that occurs in Home Assistant’s state machine (locks, binary_sensors, sensors, fans, timers, switches, etc). The three Trigger-based Template Sensors will be evaluated far more often than simply when a light changes state.

Just use the expand() function; the templates will be evaluated only when one of the Light Group’s members undergoes a state-change. Counting them can also be done without using a for-loop.

template:
  - sensor:
      - name: Lights On Downstairs
        state: "{{ expand('light.lights_downstairs') | selectattr('state', 'eq', 'on') | list | count }}"
      - name: Lights On Upstairs
        state: "{{ expand('light.lights_upstairs') | selectattr('state', 'eq', 'on') | list | count }}"
      - name: Lights On Outside
        state: "{{ expand('light.lights_outside') | selectattr('state', 'eq', 'on') | list | count }}"
1 Like

true, and I believe the catch-all state changes code I posted may have been causing a stabilization issue in my instance …and, I’ve removed it…

since I’m using “light” groups and not a “group” of lights, I had to make a small modification to your code, but it appears to be working muuuch better:

template:
  - sensor:
      - name: Lights On Downstairs
        state: "{% set entities = state_attr('light.lights_downstairs','entity_id') %} {{ expand(entities) | selectattr('state', 'eq', 'on') | list | count }}"
      - name: Lights On Upstairs
        state: "{% set entities = state_attr('light.lights_upstairs','entity_id') %} {{ expand(entities) | selectattr('state', 'eq', 'on') | list | count }}"
      - name: Lights On Outside
        state: "{% set entities = state_attr('light.lights_outside','entity_id') %} {{ expand(entities) | selectattr('state', 'eq', 'on') | list | count }}"

“light” groups support additional features and play well with other integrations such as homekit and alexa out of the box, which is why I prefer them. however every non-dimmer zwave toggle switch requires a “light” switch before it can be added to a “light” group… a regular group will take both lights and switches, but the “group” entity doesn’t expose a turn_on/off service right? there is a smoothness still missing here

scenes are my favorite light groups, and I have created a working “light” scene custom component that allows scenes to be treated as a “light”, so that scenes can be toggled on and off, and the scene light maintains an ‘on’ state until a child light is changed and allow for useful/stateful scene button ui

Ah, my mistake. The expand function is capable of automatically expanding the entity_id attribute of a Group but not a Light Group. A compact way of handling a Light Group would be like this:

template:
  - sensor:
      - name: Lights On Downstairs
        state: "{{ state_attr('light.lights_downstairs','entity_id') | expand | selectattr('state', 'eq', 'on') | list | count }}"
      - name: Lights On Upstairs
        state: "{{ state_attr('light.lights_upstairs','entity_id') | expand | selectattr('state', 'eq', 'on') | list | count }}"
      - name: Lights On Outside
        state: "{{ state_attr('light.lights_outside','entity_id') | expand | selectattr('state', 'eq', 'on') | list | count }}"

You would use the generic homeassistant.turn_on service (and turn_off).

Hi, this works.
but how can I find number of lights “on” in a specified “area”? ( in a room only, not in the whole house?)
thanks.

{{ expand(area_entities('Living Room')) | selectattr('domain','eq','light') | selectattr('state','eq','on') | list | count }}
6 Likes

hi, thanks for your quick reply!

tried it. there are two lights on but showing 0 !!

make sure your area is actually named “Bedroom 1” and that the “Bedroom 1” contains those bedroom lights.

EDIT Also found a typo, review my original post again with the updates

area name : Bedroom 1
Area ID: bedroom_1

see my edit

YES! that works.

I am also trying to get light brightness and when it was last on? could you please help me.
thanks.