Updating Templates with the new default values in 2021.10.x

Uh oh, maybe I made a mistake

Yep, gonna pull back that PR…

It can be confusing because the Jinja2 docs describe its filters like when they are used as functions, so in that case int can take three arguments. However, Home Assistant’s current implementation of int is only as a filter, not a function. As a filter, it can take two arguments where the first is the default value and the last is the base.

I was basing it off pythons int

Ehh, just for me then… where does this leave my template? Why the error? And more importantly, how to fix ?

the 2 Int’s what do I set them to?

{%- set alert_level = states('input_number.battery_alert_level')|int(default=0) %} {%- set count = expand('group.battery_sensors')
                       |map(attribute='state')
                       |rejectattr('state','in',['unknown','unavailable'])
                       |map('int',0)
                       |select('<',alert_level)
                       |list|count %}
{% set phrase = 'battery is' if count == 1 else 'batteries are' %} {%- if count > 0 %} {%- for s in expand('group.battery_sensors')
              if s.state not in ['unknown','unavailable','None'] and
                 s.state|int(default=0) < alert_level %}
{%- if loop.first %}{{loop.length}} {{phrase}} below {{alert_level}} %: {% endif %} {{s.name + ': ('+ s.state + '%),\n'}} {%- endfor %} {%- else %} All batteries above {{alert_level}} % {%- endif %}

Odd thing is, when I have a running system, I can’t force a warning on this template…So might it be some startup issue? Maybe I should add an availability template?

think this does it:

      - unique_id: low_level_batteries
        name: Low level batteries
        state: >
          {% set alert_level = states('input_number.battery_alert_level')|int(default=0) %}
          {{expand('group.battery_sensors')
                   |map(attribute='state')
                   |rejectattr('state','in',['unknown','unavailable'])
                   |map('int',default=0)
                   |select('<',alert_level)
                   |list|count}}
        icon: mdi:battery-alert
        attributes:
          list_low: >
            {%- set alert_level = states('input_number.battery_alert_level')|int(default=0) %}
            {%- set count = expand('group.battery_sensors')
                                   |map(attribute='state')
                                   |rejectattr('state','in',['unknown','unavailable'])
                                   |map('int',default=0)
                                   |select('<',alert_level)
                                   |list|count %}
            {% set phrase = 'battery is' if count == 1 else 'batteries are' %}
            {%- if count > 0 %}
            {%- for s in expand('group.battery_sensors')
                          if s.state not in ['unknown','unavailable','None'] and
                             s.state|int(default=0) < alert_level %}
            {%- if loop.first %}{{loop.length}} {{phrase}} below {{alert_level}} %: {% endif %}
            {{s.name + ': ('+ s.state + '%),\n'}}
            {%- endfor %}
            {%- else %} All batteries above {{alert_level}} %
            {%- endif %}
          list_all: >
            {%- for s in expand('group.battery_sensors')%}
            {{s.name + ': ('+ s.state + '%),\n'}}
            {%- endfor %}

pff

For a such a conceptually simple change this new templating update seems to be causing a lot of work and questions.

Can I ask a couple of simple(?) ones…

In general, when there is no way to provide a sensible default (i.e. it would produce a result that is no better than a guess) does it make sense to always provide default=none? There seems to be no way to guard against an invalid incoming date like you can for numbers (is_number).

The current example I am working on is strptime, There is no ‘sensible valid’ default for sensor.next_trains_estimated.


{% set estimated = strptime(states('sensor.next_trains_estimated'), "%H:%M") %}
{% set tnow = strptime(now().strftime('%H:%M'),  "%H:%M") %}
{% set time_to_next_train = (estimated - tnow).total_seconds() / 60 %}
{% set time_to_next_train = time_to_next_train | round %}

And, am I reading this all correctly, the next version of HA introduces more of these e.g int? Why weren’t they all included at once?


And finally a minor rhetorical rant. I know all the stock answers but I do think this apparently-simple-but-actually-quite-seismic change could have been better documented. The OP here is obviously very instructive but surely this information should be in the docs at release time and not have to be buried in the forum where only a few will see it.

I do think HA let’s itself down on two issues. Communication (see the latest Tuya issue) and documentation. It is far better than it was but still not really good enough when things get added (I believe the main source of info to get the energy integration working is still the Blog post or the ‘Developer docs’) or ‘broken’ by upgrades (e.g. these templates).

2 Likes

Just wait til 2021.11 for that one. A new filter and function today_at will make that template easier.

simply wondering why a template like:

      - unique_id: ram_too_high
        name: Ram usage too high
        state: >
          {{states('sensor.memory_use_percent')|int > 85}}

doesnt issue a warning on the |int without a default

might be wide of the mark here (and probably well out of my depth so be gentle :slight_smile: ), but isn’t it a case the the Warning message currently only appears when a Template presents an invalid result…
So taking your template then the Memory Usage will pretty much always have an Integer Value (once HA is running on your device) so it’ll never throw an invalid result, etc therefore doesn’t warn in your logs.
(and following on from that it’ll only error if that sensor ever goes unavailable which I guess is unlikely)
“Technically” you should supply a default but operationally there is no need as the sensor is always(nearly always) providing a valid result

That’s my understanding of these new changes anyway…may be wrong so be grateful for confirmation/correction…

2 Likes

Because your sensor must never go Unavailable or unknown

1 Like

Hello,

How can I fix this?
Now give me a warning…

automation:

    - alias: Rádio - Play
      trigger:
        - platform: state
          entity_id: input_boolean.radio_hall,  input_boolean.radio_cozinha,  input_boolean.radio_quarto
          to: 'on'
      action:
        - service: media_player.volume_set
          data_template:
            entity_id: >
              {% if trigger.from_state.entity_id == "input_boolean.radio_hall" %} media_player.a7_fully
              {% elif trigger.from_state.entity_id == "input_boolean.radio_cozinha" %} media_player.sala_de_estar
              {% elif trigger.from_state.entity_id == "input_boolean.radio_quarto" %} media_player.quarto_wall
              {% endif %}
            volume_level: >
              {% if '09:00' <= states.sensor.time.state < '10:00' | timestamp_custom('%H:%M') %}
                0.35
              {% elif '10:00' <= states.sensor.time.state < '22:00' | timestamp_custom('%H:%M') %}
                0.40
              {% elif '22:00' <= states.sensor.time.state <= '23:59' | timestamp_custom('%H:%M') %}
                0.30
              {% else %}
                0.25
              {% endif %} 

Error:

Logger: homeassistant.helpers.template
Source: helpers/template.py:1210
First occurred: 09:39:03 (3 occurrences)
Last logged: 09:39:03

Template warning: 'timestamp_custom' got invalid input '10:00' when compiling template '{% if '09:00' <= states.sensor.time.state < '10:00' | timestamp_custom('%H:%M') %} 0.35 {% elif '10:00' <= states.sensor.time.state < '22:00' | timestamp_custom('%H:%M') %} 0.40 {% elif '22:00' <= states.sensor.time.state <= '23:59' | timestamp_custom('%H:%M') %} 0.30 {% else %} 0.25 {% endif %}' but no default was specified. Currently 'timestamp_custom' will return '10:00', however this template will fail to render in Home Assistant core 2021.12
Template warning: 'timestamp_custom' got invalid input '22:00' when compiling template '{% if '09:00' <= states.sensor.time.state < '10:00' | timestamp_custom('%H:%M') %} 0.35 {% elif '10:00' <= states.sensor.time.state < '22:00' | timestamp_custom('%H:%M') %} 0.40 {% elif '22:00' <= states.sensor.time.state <= '23:59' | timestamp_custom('%H:%M') %} 0.30 {% else %} 0.25 {% endif %}' but no default was specified. Currently 'timestamp_custom' will return '22:00', however this template will fail to render in Home Assistant core 2021.12
Template warning: 'timestamp_custom' got invalid input '23:59' when compiling template '{% if '09:00' <= states.sensor.time.state < '10:00' | timestamp_custom('%H:%M') %} 0.35 {% elif '10:00' <= states.sensor.time.state < '22:00' | timestamp_custom('%H:%M') %} 0.40 {% elif '22:00' <= states.sensor.time.state <= '23:59' | timestamp_custom('%H:%M') %} 0.30 {% else %} 0.25 {% endif %}' but no default was specified. Currently 'timestamp_custom' will return '23:59', however this template will fail to render in Home Assistant core 2021.12

did you read the opening post of this topic?

btw, did you also read this Warning: Templating - Home Assistant

it applies to your states.sensor.time.state

automation:


    - alias: Rádio - Play
      trigger:
        - platform: state
          entity_id: input_boolean.radio_mini_sala,  input_boolean.radio_mini_cozinha,  input_boolean.radio_mini_wc,  input_boolean.radio_mini_quarto
          to: 'on'
      action:
        - service: media_player.volume_set
          data_template:
            entity_id: >
              {% if trigger.from_state.entity_id == "input_boolean.radio_mini_sala" %} media_player.google_mini_sala
              {% elif trigger.from_state.entity_id == "input_boolean.radio_mini_cozinha" %} media_player.google_mini_cozinha
              {% elif trigger.from_state.entity_id == "input_boolean.radio_mini_wc" %} media_player.google_mini_wc
              {% elif trigger.from_state.entity_id == "input_boolean.radio_mini_quarto" %} media_player.google_mini_quarto
              {% endif %}
            volume_level: >
              {% if '09:00' <= states('sensor.time') < '10:00' | timestamp_custom('%H:%M', default = 'False' ) %}
                0.25
              {% elif '10:00' <= states('sensor.time') < '22:00' | timestamp_custom('%H:%M', default = 'False' ) %}
                0.40
              {% elif '22:00' <= states('sensor.time') <= '23:59' | timestamp_custom('%H:%M', default = 'False' ) %}
                0.20
              {% else %}
                0.15
              {% endif %} 
        - service_template: >
              {% if trigger.from_state.entity_id == "input_boolean.radio_mini_sala" %} script.radio_sala
              {% elif trigger.from_state.entity_id == "input_boolean.radio_mini_cozinha" %} script.radio_cozinha
              {% elif trigger.from_state.entity_id == "input_boolean.radio_mini_wc" %} script.radio_wc
              {% elif trigger.from_state.entity_id == "input_boolean.radio_mini_quarto" %} script.radio_quarto
              {% endif %}
        - service: automation.turn_on
          entity_id:
            - automation.radio_volume_input
            - automation.radio_volume_minis

That’s an unnecessary use of the timestamp_custom() function.

'10:00' is not a timestamp, it’s a string and the function can’t do anything with it so it’s obligated to report a default value. There’s absolutely no need to use that function in this situation. Remove it.

In fact, your template doesn’t even need to use the sensor.time entity. It’s simply checking if the current hour is within a range of hours so it can use the now().hour.

Here’s a revised version of your automation employing everything I suggested plus a few additional ones:

    - alias: Rádio - Play
      trigger:
        - platform: state
          entity_id:
            - input_boolean.radio_hall
            - input_boolean.radio_cozinha
            - input_boolean.radio_quarto
          to: 'on'
      action:
        - service: media_player.volume_set
          target:
            entity_id: >
              {% set players = {'radio_hall': 'a7_fully', 'radio_cozinha': 'sala_de_estar', 'radio_quarto': 'quarto_wall' } %}
              media_player.{{ players.get(trigger.to_state.object_id, 'unknown') }}
          data:
            volume_level: >
              {% if now().hour == 9 %} ​0.35
              ​{% elif 10 <= now().hour < 22 %} 0.40
              ​{% elif now().hour in [22, 23] %} 0.30
              ​{% else %} 0.25
              ​{% endif %} 
2 Likes

Guys, just updated to .11 coming from .10…

WARNING (MainThread) [homeassistant.helpers.template] Template warning: 'int' got invalid input 'None' when rendering template '{{ ( state_attr('sensor.xxx', '4503') | int(base=16) / 90 * 255 ) | int }}' but no default was specified. Currently 'int' will return '0', however this template will fail to render in Home Assistant core 2022.1

This is the code:

level_template: "{{ ( state_attr('sensor.xx', '4503') | int(base=16) / 90 * 255 ) | int }}"

if i change to below, i still see the error, what am i missing?

level_template: "{{ ( state_attr('sensor.xx', '4503') | int(base=16) / 90 * 255 ) | int(default=0 }}"

EDIT: if i do this, then warning is gone, is that correct?

level_template: "{{ ( state_attr('sensor.xx', '4503') | int(base=16,default=0) / 90 * 255 ) | int(default=0 }}"

Yep, that’s correct

thnx @petro as always

You probably don’t need the last int, only the one on the states method. Unless you only want a whole number

indeed, i need a whole number, because its the level template of a light :slight_smile:

Uff I think if someone could write a tutorial about to fix several styles of templates it would help a lot. Frankly as a non JS dev I’m puzzled. To many possibilities around those default values.
I get several of this warnings and tried out different ways to fix it, without any success:

    shelly_em_victron_ac_loads:
      friendly_name: 'AC loads, Oven / Microwave / Dryer etc.'
      value_template: >-
          {% if ((states('sensor.multiplus_ac_loads')| int - states('sensor.shelly_em_channel_1_power')| int - states('sensor.shelly_em_channel_2_power')| int)  <= 0) %}
            0
          {% else %}
            {{(states('sensor.multiplus_ac_loads')| int - states('sensor.shelly_em_channel_1_power')| int - states('sensor.shelly_em_channel_2_power')| int)| int(default=0)}}
          {% endif %}
      unit_of_measurement: "W"
      device_class: power

More or less are my template as this one, so I hope I don’t need more help for the rest if I can understand the issue with this example.