Help with new (default) templating in 2021.10

Hi all,

I have a template sensor setup to display my last made auto backup in a readable format (ex. “2 days ago”). After upgrading to 2021.10 I’m getting the log message that I need to add a default to the template for it to keep working in future Home Assistant versions. I’ve watched the release party and read the docs, but I’m not versed enough in templates to figure out where to add it. Below is the template sensor, I tried adding the default but it’s incorrect:

          {%- set time = (as_timestamp(now()) - as_timestamp(state_attr('sensor.samba_backup', 'last_backup'))) | int(default=0) %}
          {%- set minutes = ((time % 3600) // 60) %}
          {%- set minutes = '{} minutes ago'.format(minutes) %}
          {%- set hours = ((time % 86400) // 3600) %}
          {%- set hours = '{} hours ago'.format(hours) %}
          {%- set days = (time // 86400) %}
          {%- set days = '{} days ago'.format(days) %}
          {% if time < 60 %}
            {{ 'Less than 1 minute ago' }}
          {% elif time < 120 %}
            {{ '1 minute ago' }}
          {% elif time < 3600 %}
            {{ minutes }}
          {% elif time < 7200 %}
            {{ '1 hour ago' }}
          {% elif time < 86400 %}
            {{ hours }}
          {% elif time < 172800 %}
            {{ '1 day ago' }}
          {% else %}
            {{ days }}
            {% endif %}

And the error message:

Template warning: 'as_timestamp' got invalid input 'None' when rendering template '{%- set time = (as_timestamp(now()) - as_timestamp(state_attr('sensor.samba_backup', 'last_backup'))) | int(default=0) %} {%- set minutes = ((time % 3600) // 60) %} {%- set minutes = '{} minutes ago'.format(minutes) %} {%- set hours = ((time % 86400) // 3600) %} {%- set hours = '{} hours ago'.format(hours) %} {%- set days = (time // 86400) %} {%- set days = '{} days ago'.format(days) %} {% if time < 60 %} {{ 'Less than 1 minute ago' }} {% elif time < 120 %} {{ '1 minute ago' }} {% elif time < 3600 %} {{ minutes }} {% elif time < 7200 %} {{ '1 hour ago' }} {% elif time < 86400 %} {{ hours }} {% elif time < 172800 %} {{ '1 day ago' }} {% else %} {{ days }} {% endif %}' but no default was specified. Currently 'as_timestamp' will return 'None', however this template will fail to render in Home Assistant core 2021.12

The error message seems to suggest that samba backup does not exist.
What happens if you only try to output the samba backup in the template tools?

This would be a much simpler template:

{{ relative_time( strptime( state_attr('sensor.samba_backup', 'last_backup'), '%Y-%m-%d %H:%M') ) }}

Screenshot 2021-10-07 at 20-22-05 Templating

Screenshot 2021-10-07 at 20-22-54 Templating

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

3 Likes

@tom_l That’s amazing, thank you! Just shows how inexperienced I still am with templating. Having said that, I still get a similar error message. Not 100% sure but it seems to only occur at boot:

Template warning: 'strptime' got invalid input 'None' when rendering template '{{ relative_time( strptime( state_attr('sensor.samba_backup', 'last_backup'), '%Y-%m-%d %H:%M') ) }}' but no default was specified. Currently 'strptime' will return 'None', however this template will fail to render in Home Assistant core 2021.12

@Hellis81 the sensor does exist, using dev tools I get the following. Perhaps it is unavailable during boot?

Hello. I have an automation with the template:

automation:
    - id: heiman_last_action_emergency
      alias: 'heiman last action emergency'
      trigger:
        - platform: state
          entity_id: sensor.0x00158d0001a8db49_action
          to: 'emergency'
      condition:
        - condition: template
          value_template: >
            {% set format_str = '%d.%m.%y %H:%M:%S' %}
            {% set last_triggered_str = as_timestamp(strptime(state_attr('automation.heiman_last_action_emergency', 'last_triggered'), '%Y-%m-%d %H:%M:%S')) | timestamp_custom(format_str) %}
            {{ (now().replace(tzinfo=None) - strptime(last_triggered_str, format_str)).total_seconds() > 10 }}
      action:
        - service: mqtt.publish
          data_template:
            topic: "custom/kitchen/heiman/custom_action"
            payload: "emergency"
            retain: true
        - delay: 00:00:01   
        - service: mqtt.publish
          data_template:
            topic: "custom/kitchen/heiman/custom_action"
            payload: "none"
            retain: true

I can see this error for the automation:

Template warning: ‘strptime’ got invalid input ‘2021-10-07 07:49:14.573922+00:00’ when rendering template ‘{% set format_str = ‘%d.%m.%y %H:%M:%S’ %} {% set last_triggered_str = as_timestamp(strptime(state_attr(‘automation.heiman_last_action_emergency’, ‘last_triggered’), ‘%Y-%m-%d %H:%M:%S’)) | timestamp_custom(format_str) %} {{ (now().replace(tzinfo=None) - strptime(last_triggered_str, format_str)).total_seconds() > 10 }}’ but no default was specified. Currently ‘strptime’ will return ‘2021-10-07 07:49:14.573922+00:00’, however this template will fail to render in Home Assistant core 2021.12

How I can fix this?

The string “2021-10-07 07:49:14.573922+00:00” doesn’t match the format “%d.%m.%y %H:%M:%S”

For future reference, the plural form of the word “template” is “templates”, not “temptations” which has a very different meaning.

2 Likes

I’m struggling with ‘strptime’ too, directly after a restart of HA:

2021-10-08 15:37:07 WARNING (MainThread) [homeassistant.helpers.template] Template warning: 'strptime' got invalid input 'unknown' when rendering template '{{ relative_time(strptime(states('sensor.octopi_last_boot'), '%Y-%m-%dT%H:%M:%S%z' )) }}' but no default was specified. Currently 'strptime' will return 'unknown', however this template will fail to render in Home Assistant core 2021.12

How can I fix this?

Edit:
Got it, I think.

"{{ relative_time(strptime(states('sensor.octopi_last_boot'), '%Y-%m-%dT%H:%M:%S%z', '2021-10-08T00:00:00+02:00' )) }}"

However, Relative_time doesn’t understand my default value, it doesn’t display the relative time, but the default value itself.

Edit 2:
Fixed it at last, with an even better solution:

{{ relative_time(strptime(states('sensor.rocrail_last_boot'), '%Y-%m-%dT%H:%M:%S%z', now() )) }}

Add a default value to strptime. That’s what the warning message is reporting: “no default was specified”.

For example, if strptime is unable to convert the sensor’s value (perhaps because the sensor is unavailable) this will report the current time and date as the default value.

{{strptime(states('sensor.octopi_last_boot'), '%Y-%m-%dT%H:%M:%S%z', now())}}
                                                                      ^
                                                                      |
                                                        Whatever you put here 
                                                   represents the default value

That’s just an example. What you want it to report as the default value is your choice.

1 Like

Thanks! I found that solution myself right after posting my question :slight_smile:

strptime shouldn’t even be used anymore, that line can be simplified to

{{ states('sensor.octopi_last_boot') | as_datetime }}

which ironically, doesn’t have a default

1 Like

@123 The eternal battle with autocorrect continues :yum:

@petro That looks good. Is strptime deprecated or just not advised? Using your code I no longer seem to get the default warning (yay!), but I do get a new one:

TemplateError('TypeError: argument 1 must be str, not None') while processing template 'Template("{{ relative_time( state_attr('sensor.samba_backup', 'last_backup') | as_datetime) }}")' for attribute '_attr_native_value' in entity 'sensor.samba_relative_backup'

The new sensor using your example:

{{ relative_time( state_attr('sensor.samba_backup', 'last_backup') | as_datetime) }}

Neither.

The purpose of strptime is to convert a datetime string into a datetime object. For your example, the datetime string reported by sensor.octopi_last_boot is already in a format that is easily converted to a datetime object using as_datetime.

2 Likes

What @123 said is correct

The last_backup attribute already contains a datetime object so attempting to use as_datetime causes the error message you received. Remove as_datetime from the template.

{{ relative_time(state_attr('sensor.samba_backup', 'last_backup')) }}

@123 Alright, I think I understand. However, oddly enough, when I remove as_datetime it no longer works:

relative time requires a datetime object. Your attribute appears to be a string, not a datetime object. A datetime object would be fully fleshed out, meaning it would contain seconds.

1 Like

What petro said. In this case, last_backup attribute doesn’t actually contain a datetime object. It contains a datetime string without all the necessary parts to be understood as a datetime object.

You will need to investigate why the template reports a value in the screenshot (15 hours) but failed previously with the TempleError message indicating that last_backup was None. If that happened at startup then it’s possible that sensor.samba_backup was unavailable or unknown.

1 Like

considering the Dst sensor:

          {%- set ns = namespace(previous=2,spring=none,fall=none) %}
          {%- set today = strptime(states('sensor.date'),'%Y-%m-%d').astimezone().replace(hour=ns.previous) %}
          {%- for i in range(365) %}
          {%- set day = (today + timedelta(days=i)).astimezone() %}
          {%- if ns.previous - day.hour == -1 %}
          {%- set ns.spring = today + timedelta(days=i)|timestamp_local %}
          {%- elif ns.previous - day.hour == 1 %}
          {%- set ns.fall = today + timedelta(days=i)|timestamp_local %}
          {%- endif %}
          {%- set ns.previous = day.hour %}
          {%- endfor %}
          {{([ns.spring,ns.fall]|min).isoformat()}}

how would we set the today without strptime?

I’d just keep it with strftime. I have no plans on updating my dst sensor.