Resume timers after reboot

Can you explain the design reasoning for restore_timeout? Based on its described functionality, it appears to be a ‘grace period’ for expiration. If a timer’s duration expired before Home Assistant restarted, this option allows for an extension of the duration. Please correct me if I’ve misinterpreted it.

What sort of timer applications do you envision would allow their duration to be extended? My point being that if I create a 30-minute timer, under what circumstances would it be acceptable to let it run for up to an additional (say) 15 minutes?


Any thoughts of making a Pull Request to incorporate your timer enhancements into the main code-base?

Yes. It is a grace period. Maybe that is a better name for it. When I was writing up the readme, I was thinking that restore_timeout might be a little confusing. restore_grace_period might be better.

So in my situation, I am setting up a timer to turn something off. If HA restarts during the time that it should have finished, I still want that something to turn off. Unless it’s like the next day or something, because I’ve probably manually intervened by that time. It will only be delayed for an additional 15 minutes late if HA was not available during that time to execute the finished event and trigger your automation. When HA starts up, the event will be triggered immediately. If HA was down for too long, then the event will be ignored.


Yeah, it would be awesome if it was accepted as a Pull Request… I just have no idea how to go about doing that. Do I fork the repo first? My experience with git is in small groups or by myself where I just create a branch and merge it. I don’t have the permissions to create a branch on the main repo.

Restore grace period does sound better.

It would be awesome if you could get this merged to core. I believe you do fork the HA repo, create a branch with your changes and then create a PR to the main repo, linking your fork branch. Someone else will correct me if I have that wrong :slight_smile:

Looks like you are right on :+1:: https://developers.home-assistant.io/docs/en/development_submitting.html

@123 Thanks for the inspiration. I changed the name of restore_timeout to restore_grace_period. Hopefully that is clearer for anyone who wants to use this.

Also thanks for the encouragement for submitting the pull request. That means a lot coming from you. I see you all over this forum. :beers: I don’t mean to take anything away from your solution. I had already started looking at the base code when you posted your solution and wanted to see if I could get it working, plus I thought it would be a cleaner solution.

1 Like

Fingers crossed :crossed_fingers:

3 Likes

I’m not sure that you are aware but the custom timer component is causing a failure to update past v0.102.

you can find info on the issue in this thread: 0.103: Unable to import timer component

I was not aware. Thank you. I will look into it. I am currently using it in version 0.102.2 without issue.

mmh, seems the PR has been stalled and therefore canceled, is the any objection to get the PR in?

I still need to look into writing the automated tests. I got slammed with a bunch of other things and haven’t had the time… It’s still on my todo list. :-/

A simpler solution that splits the decision about restarting to the timer consumer is as follows.
(Also needs a PR to timer)
For the timer add a state attribute: ExpectedEventAt
This is set to the time when the timer should expire.
If the timer is paused this should be set to None
When it is continued it should be set to the ExpectedEventAt based on remaining time.
When the timer expires it should be set to None

If a restart happens the user of the timer can see if the timer was active and based on the ExpectedEventtAt time could decide:

  • Ignore - i.e your grace time use case.
  • Restart the timer with the time needed to reach the new orignal ExpectedEventAt time.
  • Call the actions you would normally do when the timer expired.

I just looked at the code … the state of the timer (which is persistent unless you have an inital value)
has an attribute:
finishes_at=2021-07-15T01:40:02+00:00
Whis is what I called the ExpetedEvetAt time.

FWIW, I posted a means of automatically saving and restoring active/paused timers (employs two automations):

It uses last_changed and remaining (available for both active and paused timers) to determine how much longer the timer should run after Home Assistant is restarted again.

Normally, it won’t restart a timer whose duration expired while Home Assistant was offline. However, to satisfy requests to modify this behavior, near the end of the thread I offered a modification that allows even expired timers to be restarted for just one second so that they’re allowed to generate a ‘finished’ event (and trigger any associated automation listening for that event).

Personally, I don’t use many timers, and the host machine is protected by a UPS, but I do use this system to ensure active timers are restored.

This is a horribly old topic so apologies for the necromancing, but it occurs to me that @gremblin 's PR needed to not worry so much about how to handle expired timers during the HA outage, but to simply advise of that scenario and let the user deal with it however they choose to. So effectively, add another Event for the Timer integration like timer.expired that would fire during restoration of the active timers, if the original finishes_at attribute is before now() instead of restoring the timer.

I’ve never looked deep into events, but I assume there is attributes there so the event data can include the original finishes_at attribute, in case the user then wants to do something with the original end date/time (eg text in a notification).

Whether this is a viable way to handle the situation or not, two years on this PR is the closest we have ever got to natively handling timers across a restart. As someone smart once said - if it was easy, we would have done it already :slight_smile:

If you use input_datetimes, you can handle all this logic yourself and avoid timers all together. And it’s fairly easy to do if you make a ‘timer script’.

script:
  start_timer:
    sequence:
    - service: input_datetime.set_datetime
      target:
        entity_id: "{{ datetime }}"
      data:
        datetime: "{{ (now() + timedelta(seconds=duration)).strftime("%Y-%m-%d %H:%M:%S") }}"

Then your automations just use the datetimes. And when you want to start the timers. Just use the following service:

- service: script.start_timer
  data:
    datetime: input_datetime.xyz
    duration: 120

And if you want to display the ‘timer’ in the frontend make a template sensor for the datetime:

template:
- sensor:
  - name: My Timer
    device_class: timestamp
    state: "{{ (states('input_datetime.xyz') | as_datetime or now())| as_local }}"

Now you can do whatever you want with your automations because you have the end time. When you restart it will persist from the input_datetime. Then just make automations to check the datetimes on startup and action off that if they are ‘expired’.

2 Likes

Putting my use-cases aside, what’s your thoughts on the suggestion of firing a timer.expired event rather than handling the expired timers with some sort of grace period? I fleshed out the idea a bit more in one of the Month of WTH posts with an example of automation yaml here.

I appreciate the response and these are some good suggestions, but for me you’ve simply underscored that the built-in timer construct is not good enough to be useful. It’s not like you’ve used a timer object and then used a hack to extend the functionality, you’ve actually moved away from timers altogether and used an alternate object type. :man_shrugging:

In my case, I use the timer state (active, idle) not an event of start or finished, so your workarounds do not simply slip in as a replacement for my existing timers. I could rework the logic I guess, but I’d prefer to put that effort into one of the hacks that store the finishes_at time into a datetime object and uses that to “restore” the timer on HA start - that way if we do ever get timers that persist my automations are still valid as-is.

Personally, I’ve never found them useful because delay on a script achieves the exact same functionality if you template delay. The script is off when it’s not running the delay, and on when it is. You can cancel and restart the script using script.turn_off and script.turn_on. To me, timers were added to appease people who did not understand how to set that up in a script. So I’m the grandpa that still uses ‘timers’ the old way.

It could be useful but I’m not sure when it would fire. That would need to be fleshed out. Event’s in general are usually good ideas. The main problem is the logic applied at startup. By default, the only entities that store states after restarts are input_* devices if they are configured to behave that way.

I’ve been trying to get some love from the devs on this topic for a while now but no one seems to think it’s an issue.

I even posted a suggestion here on how it might be done.

sure there are complex work arounds but I still think a timer functionality is a pretty basic requirement for any real automation system.

every industrial PLC/CNC system I have ever worked with (siemens/modicon/twincat/allen bradley) provides that function, even 30 years ago.

petro must be REALLY old… :wink:

Yeah I saw that thread and your comments, and that (saving finish time at state change) is the approach I would take if I was to use datetime helpers to work around the current issue.

I agree that petro is not thinking about things in the same way that I am - a wait in an automation is not intuitive when the time wait is several tens of minutes or even hours. Plus that also suffers from the same issue - an in-flight automation with a 2-hour wait in it does not resume after an HA restart - leaving me with exactly the same problem still and zero options for working around it.

The longest delay I use is 5 minutes. Anything else’s is a scheduled time with templates. Survives restarts and displays nicely in the frontend. :man_shrugging: