Variable empty in template after being piped into list

Hi

I’m currently trying to build a template sensor (adapted from @jazzyisj’s unavailable-entities-sensor).

However, the template seems not to behave as I’d expect and I don’t understand why. Maybe someone here can point me in the right direction :slight_smile:

I’m debugging the template in the Developer Tools and the code looks like this:

{% set entities = states 
    | rejectattr('attributes.device_class', 'undefined')
    | selectattr('attributes.device_class', 'eq', 'battery') %}
{# print1: {{ entities | list }}  #}
{% set ignored = state_attr('group.ignored_battery_levels', 'entity_id') %}
{% if ignored != none %}
  {% set entities =  (entities | rejectattr('entity_id', 'in', ignored)) %}
{% endif %}
{# print2: {{ entities | list }}  #}
{% set low = entities 
    | map(attribute='state') 
    | map('int') 
    | select('<', 90)
    | map('string') 
    | list %}
{# print3: {{ entities | list }} #}
{# print4: {{ low | list }} #}
{{ entities | selectattr('state', 'in', low) | map(attribute='entity_id') | list }}

Issue: the last line always prints an empty list

Debugging steps:

  1. If I uncomment comment 1 and list the entities, the correct list is printed out.
  2. If I then go ahead and uncomment comment 2, the printed list is empty.
  3. If then I comment out the print1 again, then suddenly the print2 part lists the correctly filtered entities.
  4. If I “disable” the print1 and print2 again and uncomment print3 the printed list is still empty. However, uncommenting print4 outputs 1 (correct) value from the low variable.

This leaves me wondering if the entities variable is kind of “consumed” as soon as list has been called once on it. :confused: :thinking:

That’s how generators work. You need to make them lists in order for them to persist. Otherwise, use them once and they are done.

put | list on the end of both set entities.

Also, you can simplify this a bit.

{% set ignored = state_attr('group.ignored_battery_levels', 'entity_id') or [] %}
{% set entities = states 
    | rejectattr('attributes.device_class', 'undefined')
    | selectattr('attributes.device_class', 'eq', 'battery')
    | rejectattr('entity_id', 'in', ignored)
    | list 
%}
{% set low = entities 
    | selectattr('state','is_number')
    | map(attribute='state') 
    | map('int') 
    | select('<', 90)
    | map('string') 
    | list %}
{{ entities | selectattr('state', 'in', low) | map(attribute='entity_id') | list }}

Another thing to keep in mind, this doesn’t account for low battery binary sensors. To account for that…

{% set ignored = state_attr('group.ignored_battery_levels', 'entity_id') or [] %}
{% set entities = states 
    | rejectattr('attributes.device_class', 'undefined')
    | selectattr('attributes.device_class', 'eq', 'battery')
    | rejectattr('entity_id', 'in', ignored)
    | list 
%}
{% set low = entities 
    | selectattr('state','is_number')
    | map(attribute='state') 
    | map('int') 
    | select('<', 90)
    | map('string') 
    | list + ['on'] %}
{{ entities | selectattr('state', 'in', low) | map(attribute='entity_id') | list }}

That’s how generators work. You need to make them lists in order for them to persist. Otherwise, use them once and they are done.

put | list on the end of both set entities.

oh - that easy! :sweat_smile:

Also, you can simplify this a bit.

wow thanks a lot! much appreciated! also for the hint regarding binary sensor batteries