I have a couple of automations that trigger after long timers (example below). If HA is restarted for any reason, the timer will never fire. I’m looking for any approach that WILL still fire.
My best idea is to use template binary_sensors that check the time when another sensor was last
changed to a given state, however, I can’t find a way to access state history timestamps from inside a template.
Is that possible?
If not, can someone suggest a new approach?
Example rule:
- id: enter_low_power
trigger:
platform: state
entity_id: binary_sensor.house_occupied
to: 'off'
for:
days: 1
action:
- service: homeassistant.turn_off
entity_id: group.low_power
I think your probably up the right alley, I’d do a template sensor based on
state==on and (as_timestamp(now()) - as_timestamp(last_changed state)) > 1 day
As now() will no longer update on its own though, you will need another automation to on a per minute/hour basis, run homeassistant.update on it.
Then your enter_low_power automation would just trigger from off to: on
I didn’t know that “last_changed” existed, just hoped there was something like it. So, you’ve helped me there, and pointed out the issue with “now()” before I even hit it.
Which gives me the functional binary_sensor template:
{{
(not states('binary_sensor.house_occupied')) and
((as_timestamp(states('sensor.date_time_iso')) -
as_timestamp(states.binary_sensor.house_occupied.last_changed)) >
timedelta(days=1).total_seconds())
}}
This should work! It can be slightly off, because the source sensors are templates that are ‘changed’ at system restart, but at least the rules will still fire eventually.
I do feel like there is an opportunity to simplify this a bit, but I can’t seem to get it to work, even after way too much time researching.
The time sensor’s value is a string, not a datetime object. last_changed IS a datetime object. If I could
convert both values to datetime, it would be something like:
{{
(not states('binary_sensor.house_occupied')) and
((states('sensor.date_time_iso') -
states.binary_sensor.house_occupied.last_changed) >
timedelta(days=1))
}}
However, the time sensor is just a string, and strptime() appears to convert to a string, not a datetime as documented.
I don’t know if you have realized it yet but last_changed has the same vulnerability as a timer or using for in a State Trigger. All lose their countdown when Home Assistant is restarted.
The issue with last_changed is that its value is not retained after a restart. It is set to the current time and date at startup. Obviously this screws up any time duration calculations.
If you are interested, I posted a means of restarting active timers interrupted by a restart.
Could this also work as a condition in an automation rule?
I’ve tried but no success, or might it be that HA no longer supports this?
I read something about now() no longer updating.
As I couldn’t get my statement to work as a condition (always false) while it did work in the dev tools, I moved the condition to my action and now it works.
Please note that for debugging purposes I’ve split the function into several variables such that I could inspect what was going on with my core 2023.11.3.