Templating changes in 2021.10.0

08/15-User means the quite normal user with average or little programming knowledge.

I read the docs, that didn’t help much:

  • Filter timestamp_custom(format_string, local_time=True, default) converts an UNIX timestamp to its string representation based on a custom format, the use of a local timezone is default. If that fails, returns the default value, or if omitted the unprocessed input value. Supports the standard Python time formatting options.

What is the default of time? Getting either „TemplateSyntaxError: invalid syntax for function call expression“ or „TypeError: timestamp_custom() got an unexpected keyword argument ‘local_time’“

The default is returned when timestamp_custom fails to convert the timestamp. So what do you want it to return?

I cobbled it together from posts about strftime. This one works so far:


"{{ as_timestamp(state_attr('automation.katzendetektor', 'last_triggered') ) | timestamp_custom('%d.%m., %R', now() ) }}"

The example from the docs is not working (or I do it wrong):


"{{ as_timestamp(state_attr('automation.katzendetektor', 'last_triggered') ) | timestamp_custom('%d.%m., %R', local_time=True, now() ) }}"

EDIT: No, does not work:

Template warning: 'as_timestamp' got invalid input 'None' when rendering template '{{ as_timestamp(state_attr('automation.katzendetektor', 'last_triggered') ) | timestamp_custom('%d.%m., %R', now() ) }}' but no default was specified. Currently 'as_timestamp' will return 'None', however this template will fail to render in Home Assistant core 2021.12

Maybe without the writing ‘local_time=’

{{ as_timestamp(state_attr('automation.katzendetektor', 'last_triggered') ) | timestamp_custom('%d.%m., %R', True, now() ) }}

or

{{ as_timestamp(state_attr('automation.katzendetektor', 'last_triggered') , now() ) | timestamp_custom('%d.%m., %R') }}

or :rofl:

{{ as_timestamp(state_attr('automation.katzendetektor', 'last_triggered') , as_timestamp(now()) ) | timestamp_custom('%d.%m., %R') }}

why would this trigger a template warning when a device is unavailable, given there is a check for unavailable…

{% for entity_id in states.group.battery_status.attributes.entity_id if (
  not (
        is_state_attr(entity_id, 'battery_alert_disabled', true)
        or is_state_attr(entity_id, 'restored', true)
      )
  and states(entity_id) is not none
  and (
    (
      (
        states(entity_id) is number
        or states(entity_id) | length == states(entity_id)| int | string | length
        or states(entity_id) | length == states(entity_id)| float | string | length
      )
      and states(entity_id) | int < states.input_number.battery_alert_threshold_max.state | int
      and states(entity_id) | int > states.input_number.battery_alert_threshold_min.state | int
    )
    or states(entity_id) | lower == 'low'
    or states(entity_id) | lower == 'unknown'
    or states(entity_id) | lower == 'unavailable'
  )
) -%}
  {{ state_attr(entity_id, "friendly_name") }} ({{ states(entity_id) }})
{% endfor -%}

creates

Template warning: 'float' got invalid input 'unavailable' when rendering template ..... but no default was specified. Currently 'float' will return '0', however this template will fail to render in Home Assistant core 2021.12

When testing in devtools it runs and returns the device that is unavailable, plus the warning to log.

do I just need to change the the float

changed the float to float(default=0) so I guess even with the state check, all the content is parsed?

when the float is executed, it knows a default wasn’t provided. That’s when the warning appears.

Also, what’s the goal of this template? It looks overly complicated… Is this from that really old ‘battery notification’ engine that NotoriousBDG wrote in 2017?


 "{{ as_timestamp(state_attr('automation.katzendetektor', 'last_triggered'), 0 ) | timestamp_custom('%d.%m., %R') }}"

works so far. Thanks a lot for pointing me in the right direction.

Dumb question - Is this going to break completely in 2021.12, or just not render the dodgy reading?

I have a binary sensory that gets an average reading from multiple MQTT sensors and decides if it should turn on the dehumidifier, or not.

On system restart, there is a race condition before the MQTT data from all the sensors is valid, which is when I get the warnings. Once the sensors are all availbe, the readings are fine.

Good question. It depends on the template. Chances are, you’ll just get an error every time it’s encountered. However, it can lead to broken templates that stop updating.

If you just provide a default, you should be fine.

Not sure which template? Tried the binary sensor, but couldnt get it to work.

binary_sensor:
  - platform: template
    sensors:
      humidity:
        device_class: moisture
        friendly_name: 'Humidity'
        value_template: >-
          {{ states('sensor.average_humidity')|float > 52.0 }}
      dehumidifier_on:
        device_class: power
        friendly_name: 'Dehumidifier'
        value_template: >-
          {{ states('sensor.dehumidifier_current')|float > 0.10 }}
      kettle:
        device_class: power
        friendly_name: 'Kettle'
        value_template: >-
          {{ states('sensor.kettle_current')|float > 0.50 }}
- platform: template
    sensors:
      average_humidity:
        friendly_name: 'Average Flat Humidity'
        device_class: humidity        
        unit_of_measurement: "%"
        value_template: '{{ ((float(states.sensor.bedroom_humidity.state) + float(states.sensor.lab_humidity.state) + float(states. sensor.living_room_humidity.state) + float(states. sensor.kitchen_humidity.state)) / 4) | round(2) }}'

All of them need to be adjusted. change |float to |float(0)

for your average humidity, you should update the entire template to use the states method instead of using the states object, and have them use the float filter instead of the float method. I.e. make them look like your sensors.

having only experimented with a few template formats because if this change, I must have missed a most important fact: where are these warnings listed? Asking because no matter which example I enter in the dev tools, there’s not a single warning in my logs, and Logviewer remains empty
making me nervous really… I want those errors

I don’t really want a value of 0 being returned, as it will mess up long-term statistics.
Will update to states method as you have suggested.

I guess I’ll wait for 2021.12 to see if it breaks.

Manyt thanks for your help and suggestions Petro

if you don’t want zero on the average_humidity, then you’ll have to completely rewrite it.

- platform: template
    sensors:
      average_humidity:
        friendly_name: 'Average Flat Humidity'
        device_class: humidity        
        unit_of_measurement: "%"
        value_template: >
          {% set sensors = expand(
            "sensor.bedroom_humidity",
            "sensor.lab_humidity",
            "sensor.living_room_humidity",
            "sensor.kitchen_humidity",
          ) %}
          {% set humidities = sensors | rejectattr('state','in', ['unknown','unavailable']) | map(attribute='state') | map('float', 0) | list %}
          {{ humidities | sum / humidities | count }}
        availability_template: >
          {% set sensors = expand(
            "sensor.bedroom_humidity",
            "sensor.lab_humidity",
            "sensor.living_room_humidity",
            "sensor.kitchen_humidity",
          ) %}
          {{ sensors | selectattr('state','in', ['unknown','unavailable']) | list |length == 0 }}

Do you have the logger in the configuration.yalm set to info?

1 Like

It looks like the changes are going to force us to learn to code the templates correctly. ( A good thing). I have been trying to find a good tutorial. Most require me to learn a lot more python than I am interested in. Do you have any recommendations?

I’d probably ask 123. I don’t think he had any prior python knowledge before learning this. I’m a bit bias because i’ve used python for over a decade and I know what terminology to google.

But, I started with trial by fire. I was forced to learn how to code for my last job. I went face first just looking at examples and replicating code to work for me, mind you I had taken 1 C++ class in college so code wasn’t foreign to me. After a year or 2 of that I used codecademy to take some advanced python classes. Then I was promoted into a software team and learned the proper way to do things… again trial by fire.

Thanks. Last formal programing course I had was Fortran in 1977.

1 Like

Many thanks for the code.
I’m still trying to get my head around it!

My knowledge of templating/Jinja is zero and python not much better, although I normally manage to struggle through :grin:

The sad thing, is I’ve been in IT for 40+ years and can code in C, C# and Java in my sleep!

I guess its a case of RTFM :rofl: