Heads up! Upcoming breaking change in the Template integration

The way you have it now, it is going to render every time ‘sensor.time’ state changes (every minute or 1440 times a day) or when the ‘alarm_control_panel.ha_alarm’ state changes. Add this to the top of template to get it to work the same way:

{% set x = states('sensor.time') %}

Ideally we give you a way to make a time_interval sensor that only updates every hour so you could do

{% set x = states('sensor.time_that_updates_every_hour') %}

so it would only re-render when ‘sensor.time_that_updates_every_hour’ changes (24 times a day) or when the ‘alarm_control_panel.ha_alarm’ state changes.

Well you really only need one that updates at 9am and 5pm but 24 times is still a lot less than 1440 times a day so you could build an automation that fires at 9am and 5pm and calls homeassistant.update_entity on it which would mean it would only re-render 2x a day + any state change of ‘alarm_control_panel.ha_alarm’

1 Like

So I remember back when we didn’t have to specify an entity_id at all and then we started getting warnings that the template didn’t know when to be evaluated and to add the entity_id… so this is now changing again and I need to remove all the entity_id entries from my sensors? Ok… so will there be a warning if the template can’t be evaluated again then so I will need to know I need some other magic to make it work?

The new system can always find all the entities and there isn’t a case where the automatic detection can fail anymore so there isn’t a warning about this anymore. The only time you would need to do manual evaluation is where there are no entities in the template or you have something like the now() case mentioned above.

1 Like

Perfect. Thanks for clarifying Nick.

I built an integration to create time_interval sensors, and then thought about adding something like refresh_time_patterns as it would be a lot more efficient than having additional state machine updates or tracking sensor.time:

# Example configuration.yaml entry
sensor:
  - platform: template
    sensors:
      display_night_cards_armed:
        friendly_name: Display card between 9PM and 5AM and Alarm Armed
        value_template: >
            {% set ct = now().hour + now().minute/60 + now().second/3600 %}
            {{ (21 <= ct or ct <= 5) and is_state('alarm_control_panel.ha_alarm','armed_home')}}
        refresh_time_patterns:
          - hours: "5"
            minutes: "0"
            seconds: "0"
          - hours: "21"
            minutes: "0"
            seconds: "0"
      every_zero_second:
        friendly_name: Time every zero second
        value_template: "{{ now() }}"
        refresh_time_patterns:
          - hours: "*"
            minutes: "*"
            seconds: "0"

I’m still not sure if that picks up all the use cases.

2 Likes

Over the past 2 years, I’ve seen a lot of Template Sensors and the majority that needed periodic ‘prodding’ were well served by either sensor.time or sensor.date. I question the need for the dizzying amount of scheduling power and flexibility proposed in that example.

If someone needs something other than once a minute or once a day, they can use the (upcoming) documentation’s suggestion and use a Time Pattern Trigger in an automation that calls homeassistant.update_entity.

3 Likes

I think you are spot on. There are already multiple solutions here, and we do not need another one. The automation option is efficient, already has a nice UI to manage it, and doesn’t add any additional maintenance burden.

Just brainstorming but what if the Time & Date integration was enhanced so that its sensors had datetime objects as attributes? For example, if sensor.time had a time object, sensor.date had a date object and sensor.datetime had a datetime object.

Instead of using the now() function in a template, (to do some time arithmetic) I can use sensor.time and refer to its time object attribute (and employ its methods). My template has an identifiable entity, namely sensor.time, which isn’t just there to ‘prod’ for updates but is actually part of time calculations I would have otherwise used now() to perform.


EDIT

Actually, I would probably use sensor.datetime’s datetime attribute because that’s more like now().

So something like ?

{{ state_attr("sensor.time", "datetime").month }}/{{ state_attr("sensor.time", "datetime").day }}/{{ state_attr("sensor.time", "datetime").year }} {{ state_attr("sensor.time", "datetime").hour }}:{{ state_attr("sensor.time", "datetime").minute }}:{{ state_attr("sensor.time", "datetime").second }}

or

{{ state_attr("sensor.time", "datetime").strftime("%m/%d/%y %H:%M:%S") }}


This can already be accomplished with something like this

{{ states.sensor.time.last_updated.month }}/{{ states.sensor.time.last_updated.day }}/{{ states.sensor.time.last_updated.year }} {{ states.sensor.time.last_updated.hour }}:{{ states.sensor.time.last_updated.minute }}:{{ states.sensor.time.last_updated.second }}

or

{{ states.sensor.time.last_updated.strftime("%m/%d/%y %H:%M:%S") }}


{{ now() }} should be able to be replaced with {{ states.sensor.time.last_updated }} in the cases you want an update every minute.

Examples:

{{ now().minute }} becomes {{ states.sensor.time.last_updated.minute }}

Edit: It might make sense to go with ‘last_changed’ instead. They are probably the same in this case.

2 Likes

I’m pretty sure that’s what I said
:rofl:

That would just tell you that sensor.time ‘just updated’ ? - Ah.! Which is what now() does… Brilliant
:+1:

But I think newbies will have a hard time wrapping their heads round this.

( @finity, this is right in your ballpark, you ‘may’ have to update a certain epic time thread )

1 Like

If the entity_id is no longer defined, how would you know it would still be vacuum.robotrock…? This confuses me a little, since it was referencing the state of the entity_id, which is now not set manually. Maybe someone can explain this for me? I admit I’m not too familiar with template sensors within hass. Thanks.

There’s a clever function that scans the template for entity ids to monitor. This was the case before too. It’s just that it is much better at it now. So there’s no need to explicitly list them now.

As Tom says: there’s : -

And in this case fabio had : -

In his template so that didn’t need the entity_id anyway.

It’s going to be an interesting transition, you could rely on the backward compatibility but to gain the performance advantages bdraco is offering…
:wink:

1 Like

I have seen in the documentation PR by @bdraco this trick used.

{{ states('sensor.time') and now() }}

states('entity_id') when provided with any entity_id valid or not returns as true so only the expression to the right of the and statement does anything useful. The entity_id in states() is only there for the parser.

sensor.date_time_iso comes pretty close to a python datetime string. Will all date functions work with it?

Doh! :man_facepalming:

Right in front of my nose yet I’ve never seen it!

{% set t = states.sensor.time.last_updated %}

Timestamp: {{ t.timestamp() }}
Date: {{ t.date() }}
CTime: {{ t.ctime() }}
Year: {{ t.year }}
Month: {{ t.month }}
Day: {{ t.day }}
Hour: {{ t.hour }}
Minute: {{ t.minute }}
Second: {{ t.second }}

Yup, states.sensor.time.last_updated has everything needed to do date arithmetic and can easily replace the use of now() in a template.


EDIT

Oops! There’s a difference: last_updated reports UTC time whereas now() reports local time.

1 Like

Also have to be careful with that timestamp. It has microsecond resolution but the last changed attribute only updates every minute.

1 Like

True, but an int can remedy that whereas converting UTC to local time is messy.
Misunderstood your point about the microseconds.

All this to say that states.sensor.time.lastupdated is more like using utcnow() than now(). The user needs to keep that in mind if they intend to use it in their date calculations.

And as long as they realise it’s got a one minute resolution, no good for 30 second comparisons for example.

1 Like

I think the takeaway is that states.sensor.time.last_updated can be useful but should be used judiciously because it isn’t the equivalent of either now() or utcnow(). As you mentioned, it’s sensor.time after all so it only has 1-minute resolution and last_updated is UTC-based.

That’s also good advice for existing Template Sensors that use this:

    entity_id: sensor.time

and then proceed to use now() to perform time arithmetic that look for sub 1 minute differences. The darn thing is only going to be evaluated every minute so looking for, as you mentioned, a 30-second difference would be a mistake. You’re obliged to look for differences in whole minutes.

Hopefully, very few people have made that mistake.

1 Like