Updating Templates with the new default values in 2021.10.x

I’ll save petro the understandable angst (it’ll be karma for all the angst I’ve caused him over the years).

It looks like your sensor isn’t returning something that can be interpreted as an integer (and you don’t need the second | int on the first line)

You need to check if the sensor is a number and/or provide a default:

{% if is_number(states.sensor.apc2_battery_runtime.state) %}
... do something
{% else %}
... do something else
{% endif%}

or

        {% set time = (states.sensor.apc2_battery_runtime.state) | int(0) %}
        {% set minutes = ((time % 3600) / 60) %}
        {% set hours = ((time % 86400) / 3600) %}
        {% set days = (time / 86400) %}

time defaults here to zero, you can change that to any number. And once it is an integer you don’t need to keep converting it.

Also, heeding this warning may help:

https://www.home-assistant.io/docs/configuration/templating/#states

2 Likes

Hi, i chnge te template sensor with:

  {% set time = (states.sensor.apc2_battery_runtime.state) | int(0) %}
  {% set minutes = ((time % 3600) / 60) %}
  {% set hours = ((time % 86400) / 3600) %}
  {% set days = (time / 86400) %}

But now, instead of having as a result: 4h 20m
have: 0.18055555555555555 d 4.333333333333333 h 20.0 m
Where is the problem?

sensor.apc2_battery_runtime have 15.600 s value.

Would the division not keep creating a float, which Marco is now seeing?

I believe that, for integer division, one must use two slashes instead of the one, like ((time % 3600) // 60). Or just go back to converting it after :slight_smile:.

1 Like

Is states.sensor.apc2_battery_runtime.state in seconds??

if it is I did the following in developer tools → templates

{% set mynow = as_timestamp( now()) %}
{{ mynow }}
{% set years = (mynow/31556925)| int %}
{{years}}
{% set f_year = (mynow%31556925) %}
{{f_year}}
{% set f_day = (f_year%86400) %}
{{ f_day }}
{% set time = f_day %}
{{ time }}
{% set days = ( (time / 86400)) | int %}
{% set hours = ((time / 3600) | int) %}
{% set minutes = (((time % 3600)/60)|int) %}
{{minutes}}
{{hours}}
{{days}}

and I got this result.

the seconds divisor 31556925 is the seconds in a solar year. Close enough for an example

I was working down to fractional days. I assume the APC battery is not running over a day.

So in the example I get 0 days 9 hours 54 minutes. Is this what you were looking for?

EDIT: Removed timestamp_custom

Bringing my rant from here over here, to avoid pissing off nice people like @petro.

I want to understand something. The warning says: “this template will fail to render in Home Assistant core 2022.1”. Does this mean:
a. The template will give a warning/error in the logs and will not have a default value anymore
or
b. The system will refuse to start when it sees such a construct (w/o a default)
?

If a), then I don’t really see the reason for the warning, and I, for my part, won’t need to make any changes, because I don’t want to hide “default” assignments to zero.

If b), that is IMHO a very poor decision, because “fixing” this warning will hide actual bugs.

I still believe this change is not warranted and it’s been implemented as a workaround for a specific problem, but it will affect a lot of HA deployments out there.

I believe it is option “a”.

the only reason I can see for the change is that there were some users who were getting erroneous results in their templates and had no idea it was happening or why.

I think I would have handled it differently if that was the case.

I think it would have been sufficient to maintain the default “defaults” but also log a warning/error that the template was forced to fall back to the default values.

that way it shows users where (and if) they made a mistake but also provides for using the built-in default if that was already sufficient for what someone needs without the need for extra coding or trying to figure out the complexities of which defaults are needed and the required syntax.

the “make it easy” mantra always seems to be undermined by these types of changes.

2 Likes

It will produce an error instead of a warning. If it happens at startup (likely) you’re entity won’t be created. If it happens randomly but the entity already exists (i.e. after startup), you’ll just get an error.

I have this template sensor with availability template:

template:
  - sensor:
      - name: Living TV Volume Level
        unit_of_measurement: "%"
        availability: >-
          {{ state_attr("media_player.living_tv", "volume_level") not in 
            [None, unknown, 'none', 'unknown', 'unavailable'] }}
        state: >
            {{ (state_attr("media_player.living_tv", "volume_level") * 100)
              | int }}
        icon: >
          {% set vol = states('sensor.living_tv_volume_level')
            | int %}
          {% set lvl = (( (vol-1) // (100/3) ) | int) + 1 %}
          {% set icons = ['off','low','medium','high'] %}
          {% if 0 <= lvl <= 3 %}
          mdi:volume-{{ icons[lvl] }}
          {% else %}
          mdi:volume-{{ icons[1] }}
          {% endif %}

The log shows this entry:

Logger: homeassistant.helpers.template
Source: helpers/template.py:1291 
First occurred: 22:45:38 (5 occurrences) 
Last logged: 22:45:53

...

Template warning: 'int' got invalid input 'unknown' when rendering template '{% set vol = states('sensor.living_tv_volume_level') | int %} {% set lvl = (( (vol-1) // (100/3) ) | int) + 1 %} {% set icons = ['off','low','medium','high'] %} {% if 0 <= lvl <= 3 %} mdi:volume-{{ icons[lvl] }} {% else %} mdi:volume-{{ icons[1] }} {% endif %}' but no default was specified. Currently 'int' will return '0', however this template will fail to render in Home Assistant core 2022.1

Can someone explain why I see the error?

An availability template does not stop the state template from attempting to resolve. It just masks the result. I think there is a PR in progress to alter this behaviour. Either way your issue is with the icon template that this PR will not address. Just supply a default value for your use of |int in this template.

    icon: >
      {% set vol = states('sensor.living_tv_volume_level')
        | int(0) %}
      {% set lvl = (( (vol-1) // (100/3) ) | int) + 1 %}
      {% set icons = ['off','low','medium','high'] %}
      {% if 0 <= lvl <= 3 %}
      mdi:volume-{{ icons[lvl] }}
      {% else %}
      mdi:volume-{{ icons[1] }}
      {% endif %}

I was hoping to avoid adding defaults by using availability for all the templates. If I can’t than I definitely will add defaults.

Not sure where I got this idea but I cant find any relevant PR. So maybe I dreamt it.

I’m 99% sure it already went through but it only affects state. Not the other templates. his icon template is causing the problem as that’s the only string to int conversion that will fail on startup. The others aren’t conversions that would result in a failure.

ofc simply preventing that using:

        icon: >
          {% set state = states('input_number.intercom_volume') %}
          {% if state == '0.0' %} mdi:volume-off
          {% elif state <= '0.3' %} mdi:volume-low
          {% elif state <= '0.6'%} mdi:volume-medium
          {% else %} mdi:volume-high
          {% endif %}

is also possible :wink: though it might be luck this works considering this is comparing strings…

this is better in that regard:

          {% set state = states('input_number.intercom_volume')|float(0) %}
          {% if state == 0.0 %} mdi:volume-off
          {% elif state <= 0.3 %} mdi:volume-low
          {% elif state <= 0.6 %} mdi:volume-medium
          {% else %} mdi:volume-high
          {% endif %}

TIL templating is hard work. :wink:

This explains a lot. I’ll consider some other code for the icon.

That’s a nice suggestion.

I’ve discovered that templating the icon attribute is also determined by the availability attribute. When attribute is False, the sensor state is ‘unavailable’, and the sensor icon is not templated. The icon attribute will not be set.

Availability added:

Availability removed:

You can reproduce this with my below code and look at the developer tools with the availability template added or removed.

I’ve updated my code to this:

template:
  - sensor:
      - name: Living TV Volume Level
        unique_id: 655f97da-54dc-40d2-8de1-db1b9cc66bf3
        unit_of_measurement: "%"
        availability: >-
          {{ state_attr('media_player.living_tv','volume_level') is not none }}
        state: >-
            {{ (state_attr('media_player.living_tv','volume_level') 
              | float(0) * 100) | int }}
        icon: >-
          {% set state = states('sensor.living_tv_volume_level') | float(0) %}
          {% if state == 0.0 %} mdi:volume-off
          {% elif state <= 0.3 %} mdi:volume-low
          {% elif state <= 0.6 %} mdi:volume-medium
          {% else %} mdi:volume-high
          {% endif %}

Noice.

That has the effect of drawing the eye to the deeper problem. Don’t fuck with it.

This is awesome, but had to be pointed out to me by someone else.
Perhaps melding this into the Official Docs AND melding your sample availability example into the related docs for that would be more helpful. (I had NO CLUE how to use that before this article)
No offense, I use the community pages here but I always look first at the official Docs and put more weight in what they say rather than random guessers. I do take what you say an a few others as 99.5% correct, but there are lots of other advise in here that, well, not so much… That’s why I look to the Official Docs first and would not have found this without Thanasis’s help. Wouldn’t have known to look…

I am getting an error when using a value template for an automation to control air conditioning. Hoping someone can help fix up my code :slight_smile: It doesn’t specify the error, just says “error while processing template”.

Basically it triggers an automation when a temperature sensor goes above or below a certain value, in this case above 24 degrees.

trigger:
  - platform: template
    value_template: "{{ states('sensor.girls_sensor_temperature') | round(0,0) | int(0) >= 24 }}"
1 Like

The second argument for round is method. I.e. rounding to the floor, cieling, or just a normal round. You need to use round(0, default=0) if you don’t plan on providing a method for the round.

Also, if you provide a default for the round, you don’t need a default for the int.

4 Likes