Template Sensor: Template variable warning with HA 2021.4

Introduced with the new HA core version 2021.4 we now get warnings for undefined variables in template sensors (https://www.home-assistant.io/blog/2021/04/07/release-20214/#warnings-for-undefined-variables-in-templates). So far, so great :slight_smile:

I wanted to integrate a “default” value for this template sensor, but with no luck:

- platform: template
  sensors:
    low_batteries:
      friendly_name: Low batteries
      value_template: >-
        {%- for state in states if state.attributes.battery_level or state.attributes.battery -%}
          {%- set battery = state.attributes.battery_level or state.attributes.battery | default(100) -%}
          {%- if battery | float > 2.2 -%}
            {%- set battery = 100 -%}
          {%- elif battery == 'High' -%}
            {%- set battery = 100 -%}
          {%- else -%}
            {%- if "LOWBAT" in state.attributes.friendly_name -%}
            {%- elif "TEMPERATURE" in state.attributes.friendly_name -%}
            {%- elif "HUMIDITY" in state.attributes.friendly_name -%}
            {%- elif "COUNTER" in state.attributes.friendly_name -%}
            {%- elif "POWER" in state.attributes.friendly_name -%}
            {%- elif "LOWBAT" in state.attributes.friendly_name -%}
            {%- else -%}
              {{state.attributes.friendly_name}}{{- '\n' -}}
            {%- endif -%}
          {%- endif -%}
        {%- endfor -%}

Any hints how to correct my template? Thanks in advance!

Can you post the warning you get in the log?

sure, here it is:

2021-04-08 10:03:22 WARNING (MainThread) [homeassistant.helpers.template] Template variable warning: 'mappingproxy object' has no attribute 'battery_level' when rendering '{%- for state in states if state.attributes.battery_level or state.attributes.battery -%}
  {%- set battery = state.attributes.battery_level or state.attributes.battery -%}
  {%- if battery | float > 2.2 -%}
    {%- set battery = 100 -%}
  {%- elif battery == 'High' -%}
    {%- set battery = 100 -%}
  {%- else -%}
    {%- if "LOWBAT" in state.attributes.friendly_name -%}
    {%- elif "TEMPERATURE" in state.attributes.friendly_name -%}
    {%- elif "HUMIDITY" in state.attributes.friendly_name -%}
    {%- elif "COUNTER" in state.attributes.friendly_name -%}
    {%- elif "POWER" in state.attributes.friendly_name -%}
    {%- elif "LOWBAT" in state.attributes.friendly_name -%}
    {%- else -%}
      {{state.attributes.friendly_name}}{{- '\n' -}}
    {%- endif -%}
  {%- endif -%}
{%- endfor -%}'
2021-04-08 10:03:22 WARNING (MainThread) [homeassistant.helpers.template] Template variable warning: 'mappingproxy object' has no attribute 'battery' when rendering '{%- for state in states if state.attributes.battery_level or state.attributes.battery -%}
  {%- set battery = state.attributes.battery_level or state.attributes.battery -%}
  {%- if battery | float > 2.2 -%}
    {%- set battery = 100 -%}
  {%- elif battery == 'High' -%}
    {%- set battery = 100 -%}
  {%- else -%}
    {%- if "LOWBAT" in state.attributes.friendly_name -%}
    {%- elif "TEMPERATURE" in state.attributes.friendly_name -%}
    {%- elif "HUMIDITY" in state.attributes.friendly_name -%}
    {%- elif "COUNTER" in state.attributes.friendly_name -%}
    {%- elif "POWER" in state.attributes.friendly_name -%}
    {%- elif "LOWBAT" in state.attributes.friendly_name -%}
    {%- else -%}
      {{state.attributes.friendly_name}}{{- '\n' -}}
    {%- endif -%}
  {%- endif -%}
{%- endfor -%}'

What is the value of this sensor supposed to be? You’ve set a value that I’m not sure what it does for battery in the if and elif but not the else. Then you have several seemingly unrelated if and elif statements that produce no value in the else portion. I’m really not sure what you’re trying to do with this template?

OK I’m tired…, I worked out what you’re doing. You’ve just gone about it in an unusual manner (to me anyway).

This is my low battery template binary sensor maybe you can use it to figure out what you’re trying to do. I’ve based mine on the battery device class. You can set the device class for entities that aren’t automatically set in the customize section if necessary (I had to for my Nest devices).

The state is on when any battery goes below the set threshold. The entities attribute is a list of entity id’s of the entities with low batteries. I filter out our mobile devices because I have a separate alert for those. ‘Replace’ is the state of a Nest device with a low battery.

Low Battery Template Sensor
binary_sensor:
  - platform: template
    sensors:
      low_battery_alert:
        friendly_name: Low Battery
        unique_id: low_battery_alert
        icon_template: "{{ 'mdi:battery-alert' if is_state('binary_sensor.low_battery_alert','on') else 'mdi:battery-90' }}"
        value_template: >
          {% set low_batteries = namespace(value=0) %}
          {% set batteries = states|selectattr('attributes.device_class','eq','battery')|rejectattr('attributes.mobile','eq',true)|map(attribute='entity_id')|list %}
          {% for item in batteries %}
            {% if states(item) == 'Replace' or (states(item)|int(-1) != -1 and states(item)|int < states('input_number.battery_alert_threshold')|int) %}
              {% set low_batteries.value = low_batteries.value + 1 %}
            {% endif %}
          {% endfor %}
          {{ low_batteries.value|int > 0 }}
        attribute_templates:
          entities: >
            {% set low_batteries = namespace(value=[]) %}
            {% set low_batts = states|selectattr('attributes.device_class','eq','battery')|rejectattr('attributes.mobile','eq',true)|map(attribute='entity_id')|list %}
            {% for item in low_batts %}
              {% if states(item) == 'Replace' or (states(item)|int(-1) != -1 and states(item)|int < states('input_number.battery_alert_threshold')|int) %}
                {% set low_batteries.value = low_batteries.value + [item] %}
              {% endif %}
            {% endfor %}
            {{ low_batteries.value }}

I think this does what you want.

{%- set low_batteries = namespace(value='') %}
{%- set batteries = expand(states|selectattr('attributes.battery_level','ne',null)|map(attribute='entity_id')|list
    + states|selectattr('attributes.battery','ne',null)|map(attribute='entity_id')|list) -%}
{%- for battery in batteries %}
  {%- if battery.state != 'High' and battery.state|float(-1) < 2.2 -%}
    {%- if "LOWBAT" in battery.attributes.friendly_name -%}
    {%- elif "TEMPERATURE" in battery.attributes.friendly_name -%}
    {%- elif "HUMIDITY" in battery.attributes.friendly_name -%}
    {%- elif "COUNTER" in battery.attributes.friendly_name -%}
    {%- elif "POWER" in battery.attributes.friendly_name -%}
    {%- elif "LOWBAT" in battery.attributes.friendly_name -%}
    {%- else -%}
      {%- set low_batteries.value = low_batteries.value ~ battery.attributes.friendly_name ~'\n' -%}
    {%- endif -%}
  {%- endif -%}
{%- endfor -%}
{{ low_batteries.value }}
1 Like

just testet you template, thanks for it :slight_smile:

with a little correction (the battery level is in the attribute, not in the state of the sensor) it works now as expected. here is the corrected version:

{%- set low_batteries = namespace(value='') %}
{%- set batteries = expand(states|selectattr('attributes.battery','ne',null)|map(attribute='entity_id')|list
    + states|selectattr('attributes.battery','ne',null)|map(attribute='entity_id')|list) -%}
{%- for battery in batteries %}
  {%- if  battery.attributes.battery != 'High' and battery.attributes.battery|float(-1) < 2.2 -%}
    {%- if "LOWBAT" in battery.attributes.friendly_name -%}
    {%- elif "TEMPERATURE" in battery.attributes.friendly_name -%}
    {%- elif "HUMIDITY" in battery.attributes.friendly_name -%}
    {%- elif "COUNTER" in battery.attributes.friendly_name -%}
    {%- elif "POWER" in battery.attributes.friendly_name -%}
    {%- else -%}
      {%- set low_batteries.value = low_batteries.value ~ battery.attributes.friendly_name ~ '\n' -%}
    {%- endif -%}
  {%- endif -%}
{%- endfor -%}
{{ low_batteries.value }}

Hey there!

I have the same problem but with other code:

  - platform: template
    sensors:
      hassio_drifttid:
        friendly_name: 'Hassio Drifttid'
        value_template: >-
          {%- set word_for_and = 'och' %}
          {%- set up_time = as_timestamp(now())-as_timestamp(states('sensor.uptime')) %}
          
          {%- macro phrase(name, plural_name, divisor, mod=None) %}
            {%- set value = ((up_time // divisor) % (mod if mod else divisor)) | int %}
            {%- set name = plural_name if value > 1 else name %}
            {{- '{} {}'.format(value, name) if value | int > 0 else '' }}
          {%- endmacro %}
          
          {%- set values = [ 
                     phrase('dag', 'dagar', 60*60*24, 7),
                     phrase('timme', 'timmar', 60*60, 24),
                     phrase('min', 'min', 60)
                 ] | select('!=','') | list %}
                        
          {{ values[:-1] | join(', ') ~ ' ' ~ word_for_and ~ ' ' ~ values[-1] if values | length > 1 else values | first }}

Warning:

2021-04-21 19:26:15 WARNING (MainThread) [homeassistant.helpers.template] Template variable warning: No first item, sequence was empty. when rendering '{%- set word_for_and = 'och' %} {%- set up_time = as_timestamp(now())-as_timestamp(states('sensor.uptime')) %}
{%- macro phrase(name, plural_name, divisor, mod=None) %}
{%- set value = ((up_time // divisor) % (mod if mod else divisor)) | int %}
{%- set name = plural_name if value > 1 else name %}
{{- '{} {}'.format(value, name) if value | int > 0 else '' }}
{%- endmacro %}
{%- set values = [
phrase('dag', 'dagar', 60*60*24, 7),
phrase('timme', 'timmar', 60*60, 24),
phrase('min', 'min', 60)
] | select('!=','') | list %}
{{ values[:-1] | join(', ') ~ ' ' ~ word_for_and ~ ' ' ~ values[-1] if values | length > 1 else values | first }}'

What do I ADD and where?

i have the error:
[homeassistant.helpers.template] Template variable warning: ‘end’ is undefined when rendering

hass_io_uptime_pretty:
      friendly_name: Hass.io Uptime
      value_template: >
        {%- set up_time = as_timestamp(now())-as_timestamp(states('sensor.hass_io_uptime')) %}

        {% if states('sensor.hass_io_uptime') == '0.0' %} 
          Soeben neu gestartet...
        {% else %}
        {%- macro phrase(name, divisor, mod=None) %}
          {%- set value = ((up_time // divisor) % (mod if mod else divisor)) | int %}
          {{- '{} {}{}'.format(value, name, end) if value | int > 0 else '' }}
        {%- endmacro %}

        {%- set values = [
          phrase('W.', 60*60*24*7),
          phrase('T.', 60*60*24, 7),
          phrase('Std.', 60*60, 24),
          phrase('Min.', 60),
          phrase('Sek.', 1, 60)
        ] | select('!=','') | list %}

        {{ values[:-1] | join(', ') ~ ' ' ~ values[-1] if values | length > 1 else values | first }}
        {% endif %}

is that the point ??
{{- '{} {}{}'.format(value, name, end) if value | int > 0 else '' }}

here the Solution:

value_template: >
        {%- set up_time = as_timestamp(now())-as_timestamp(states('sensor.hass_io_uptime')) %}

        {% if states('sensor.last_boot') == '0.0' %}
          Soeben neu gestartet...
        {% else %}

        {%- macro phrase(name, divisor, mod=None) %}
          {%- set value = ((up_time // divisor) % (mod if mod else divisor)) | int %}
          {{- '{} {}'.format(value, name) if value | int > 0 else '' }}
        {%- endmacro %}

        {%- set values = [
          phrase('W.', 60*60*24*7),
          phrase('T.', 60*60*24, 7),
          phrase('Std.', 60*60, 24),
          phrase('Min.', 60),
          phrase('Sek.', 1, 60)
        ] | select('!=','') | list %}

        {{ values[:-1] | join(', ') ~ ' ' ~ values[-1] if values | length > 1 else values | first }}
        {% endif %}