Count lights and switches that control lights

Hello, I want to count lights and the switches that control some of the lights. I have this that count the lights:

{% set lightsOnCount = states[domain] | selectattr( 'state', 'eq', 'on') | rejectattr('attributes.entity_id', 'defined') | list | count %}
{{lightsOnCount}}

But I have also switches that control some of the lights. How can I include it in the code? I tried to change it to:

{% set switchOnCount = states[domain] | selectattr( 'state', 'eq', 'on') | rejectattr('attributes.entity_id', 'defined') | list | count %}
{{switchOnCount}}

But it counts a lot like 33 :joy:. I have only 4 switches that control some of the lights.

Have you examined the list of 33 switch entities?

It’s likely to reveal that a switch entity isn’t limited to controlling a light and is also used for other purposes (for example, enabling/disabling a feature in a device).

You will need to find some characteristic that is common exclusively to your 4 light-controlling switches and use it in your template to filter out the other switches.

I have managed to find a solution by listing it individually(since I have less/few switch). For anyone interested, here it is:

{% set switch = [
          states.switch.livingroom_switch_1,
          states.switch.livingroom_switch_2,
          states.switch.bedroom_switch_1,
          states.switch.kitchen_switch_1,
          states.switch.utility,
          ] %}
          {{ switch | selectattr('state','eq','on') | list | count }}

Maybe your first post didn’t explain what you were attempting to achieve but your alleged Solution is dramatically different from what the original template attempted.

It changed from checking a dynamic list of all switches in the system to checking a hard-coded list of four five switches (edit: you originally said you only have 4 switches but your template has 5).

I suggest you add a label to each switch, and to any future additional light switches, and then you can check them dynamically (i.e. no hard-coded entity_ids).

For example, if you label them “lightswitch” you can use this:

{{ label_entities('lightswitch') | map('states')
  | select('eq', 'on') | list | count }}
1 Like

I implemented this and I like it more than my solution. Thank you so much. I didn’t know about labels.

1 Like

BTW, how can I implement this on sensor’s battery? I want to count batteries that are above 60%, 30% and 10%. I already setup labels for the sensor’s battery.

There are several existing blueprints designed for handling entities with a “Low Battery”. You may wish to explore them and see if any meet your requirements.

If you just want a quick list of entities, copy-paste the following template into the Template Editor. It reports all entities with a “battery” label (change it to match whatever label you created) that have a state value less than 30.

{% set b = label_entities('battery') %}
{% set eid = b | select('has_value') | list %}
{% set val = eid | map('states') | map('float', 0) | list %}
{% set z = zip(eid, val)| selectattr(1, 'lt', 30) | list %}
{{ z | map('join', ': ') | join('\n') }}

It can also be used in a Markdown Card.

1 Like

It doesn’t work on my end. I changed the label to label that I set which is “sensorbattery” but it doesn’t count. I managed to find a solution to your previous code that I used in counting lights. Here it is:

{{ label_entities('sensorbattery') 
  | map('states')
  | map('float')
  | select('lt', 20)
  | list | count }}

I just added "map(‘float’)" and change “eq” to “lt”.
It’s simpler. I already tested it.

I’m surprised it didn’t work for you.

I tested it on my system and it correctly identified five entities whose state value is less than 30. It presented the results as a list of entity_ids and corresponding values.

sensor.foyer_battery: 29.0
sensor.kitchen_button_battery: 24.0
sensor.kitchen_dimmer_switch_battery_level: 23.0
sensor.living_room_dimmer_switch_battery_level: 20.0
sensor.bedroom_dimmer_switch_battery_level: 11.0

However, if you only want quantity (and not identify which entity has a low battery) then, yes, your template is ideal for the task.

nice!
not using zip myself yet, but this could be a nice incentive :wink:

what I’d ideally see is the names of the entities, and not their entity_id.

however, we can not expand and use |expand|map(attribute='name') because the map to states has already been done.

Is there any chance zip can help us out here too, and not require a namespace construction after all?

maybe add the name as 3rd argument somehow?

{% set b = label_entities('battery') %}
{% set eid = b | select('has_value') | list %}
{% set val = eid | map('states') | map('float', 0) | list %}
{% set nam = eid | expand | map(attribute='name') | list %}
{% set z = zip(nam, val)| selectattr(1, 'lt', 30) | list %}
{{ z | map('join', ': ') | join('\n') }}

EDIT 1

Compact version:

{% set eid = label_entities('battery') | select('has_value') | list %}
{{ zip(eid | expand | map(attribute='name'),
       eid | map('states') | map('float', 0))
  | selectattr(1, 'lt', 30) 
  | map('join', ': ') | join('\n') }}

EDIT 2

Removed redundant list filters from compact example (as per Mariusthvdb’s observations posted below).

1 Like

sweet:

thank you very much Taras, appreciated!

1 Like

btw, I just realized we can leave out all the |list filters (and even the has_value depending on your needs)

so we can also do this directly on the b variable:

{% set b = label_entities('batterij') %}
{% set val = b | map('states') | map('float', 0) %}
{% set nam = b | expand | map(attribute='name') %}
{% set z = zip(nam, val)| selectattr(1, 'lt', 30) %}
{{ z | map('join', ': ') | join('\n') }}

update

except… the listings are not correct at all, many of these battery levels simply are not the ones mapped to the devices.

the first 1 Plafond Bijkeuken is 100% !

and I can list that for all of the other sensors…
now what is wrong here.
if I use my namespace template

        {%- set alert_level = states('input_number.battery_alert_level')|int %}
        {%- set ns = namespace(batt_low=[]) %}

        {%- set ns = namespace(batt_low=[]) %}
        {%- for s in label_entities('batterij')
          if is_number(states(s)) and states(s)|int < alert_level
          or not has_value(s) %}
        {%- set ns.batt_low = ns.batt_low + [s] %}
        {%- endfor %}
        {{ns.batt_low}}

it lists the correct entities (I did check with the hardcoded 30, as in the zip example too)
I am not yet able to find the issue here…
but it does find a lot of 100% batteries and lists them as 0, maybe the default kicking in

it is not only that though, check a few here:

really mysterious

all manual retrieved now according to the template output:

it’s the expand | map(attribute='name') that frustrates the zip, as expand sorts the output.
using {% set nam = b | map('state_attr', 'friendly_name') %} solves that, so we should do:

{% set b = label_entities('batterij') %}
{% set val = b | map('states')| map('float',-1)  %}
{% set nam = b | map('state_attr', 'friendly_name') %}
{% set z = zip(nam, val)  %}
{{ z | map('join', ': ') | join('\n') }}

thanks to @hilburn for informing me in Discord

adding some more spice, sorting on val and using a dynamic alert_level:

{% set b = label_entities('batterij') %}
{% set alert_level = states('input_number.battery_alert_level')|int %}
{% set val = b | map('states')| map('float',-1)  %}
{% set nam = b | map('state_attr', 'friendly_name') %}
{% set z = zip(nam, val)| selectattr(1, 'lt', alert_level)|sort(attribute=1) %}
{{ z | map('join', ': ') | join('\n') }}