so what it is in my case ?
my automation turn sonoff for 30 min.
( you can ser above what i copied. )
Yes, but you use a delay, not a timer. Same effect, but different approach.
o.k
so can you show me what to change in my automation for using it with timer ?
hi,
i think its a little more complicated.
is there other way to acomplished it ?
EDIT
Overlooked to updated both examples with BugFix1.
@allanbell3d Thank you for bringing the oversight to my attention!
Here is how I would handle the situation where I wish to either exclude, or include, a subset of all timers. The choice of which to use depends on how many timers are involved.
Exclusion
Use this version when you only want to EXCLUDE a few timers. For example, you have 10 timers and want all but 3 of them to survive a restart.
- In the
trigger
, specify the 7 timers to be preserved. - In the template’s
timers
variable, specify the 3 timers to be excluded.
- alias: 'Active Timers Save'
trigger:
platform: state
entity_id:
- timer.timer1
- timer.timer2
- timer.timer3
- timer.timer4
- timer.timer5
- timer.timer6
- timer.timer7
action:
- service: input_text.set_value
data_template:
entity_id: input_text.active_timers
value: >
{% set timers = states.timer
| rejectattr('object_id', 'in', ['timer8', 'timer9', 'timer10'])
| selectattr('state', 'eq', 'active')
| list %}
{% set ns = namespace(timers = '') %}
{% for t in timers %}
{% set d = t.attributes.duration.split(':') %}
{% if 'day' in d[0] %}
{% set z = d[0].split(', ') %}
{% set h = ((z[0].split()[0] | int) * 24 + (z[1].split(':')[0] | int)) * 3600 %}
{% else %}
{% set h = d[0] | int * 3600 %}
{% endif %}
{% set s = h + (d[1]|int*60) + (d[2]|int) %}
{% set c = ',' if not loop.first else '' %}
{% set ns.timers = ns.timers ~ '{}{} {}'.format(c, t.object_id, t.last_changed.timestamp()|int + s) %}
{% endfor %}
{{ ns.timers }}
Inclusion
Use this version when you only want to INCLUDE a few timers. For example, you have 10 timers but only want 3 of them to survive a restart.
- In the trigger, specify the 3 timers to be preserved.
- In the template’s
timers
variable, specify the same 3 timers.
- alias: 'Active Timers Save'
trigger:
platform: state
entity_id:
- timer.timer1
- timer.timer2
- timer.timer3
action:
- service: input_text.set_value
data_template:
entity_id: input_text.active_timers
value: >
{% set timers = [states.timer.timer1, states.timer.timer2, states.timer.timer3]
| selectattr('state', 'eq', 'active')
| list %}
{% set ns = namespace(timers = '') %}
{% for t in timers %}
{% set d = t.attributes.duration.split(':') %}
{% if 'day' in d[0] %}
{% set z = d[0].split(', ') %}
{% set h = ((z[0].split()[0] | int) * 24 + (z[1].split(':')[0] | int)) * 3600 %}
{% else %}
{% set h = d[0] | int * 3600 %}
{% endif %}
{% set s = h + (d[1]|int*60) + (d[2]|int) %}
{% set c = ',' if not loop.first else '' %}
{% set ns.timers = ns.timers ~ '{}{} {}'.format(c, t.object_id, t.last_changed.timestamp()|int + s) %}
{% endfor %}
{{ ns.timers }}
So what’s different between these examples and the original one I posted?
The main difference is how the template refers to your timers:
- In the original example, it simply uses
states.timers
which represents all of your timers. - In the exclusion example, it also uses
states.timer
but then rejects all the entities you specified in the list:rejectattr('object_id', 'in', ['timer8', 'timer9', 'timer10'])
- In the inclusion example, it doesn’t use
states.timer
. It uses the timers you specify in the list:[states.timer.timer1, states.timer.timer2, states.timer.timer3]
.
Once again thank you very much for the guide and explanation.
As explained by francisp, your automation uses a delay
not a timer
. I’ve formatted your automation to make it easier to read:
- id: Hot_Water
alias: 'Hot_Water'
trigger:
platform: state
entity_id: automation.hot_water
from: 'off'
to: 'on'
for: '1'
action:
- service: switch.turn_on
entity_id: switch.sonoff_XXXX
- delay: '00:30:00'
- service: switch.turn_off
entity_id: switch.sonoff_XXXX
- service: automation.turn_off
entity_id: automation.hot_water
- service: automation.turn_off
entity_id: automation.hot_water
At the very end of the action, it turns off automation.hot_water
twice. I don’t understand why the automation is turning itself off and why it attempts to do that twice. However that’s a separate discussion.
If I understand you correctly, you are asking for assistance to convert your automation from using delay
to using a timer
. If that’s the case then please start a new, separate topic. This one is dedicated to discussing the preservation of timers after a restart.
If you are looking for a replacement for delay
but believe timer
is too complicated then you don’t have any other options. Those are the two principle ways of waiting for fixed period of time. There is also wait_template but it is designed to wait for a specified condition to become true.
thanks for your help.
I’ve just stumbled upon this post - thanks for sharing, the idea is interesting.
I restore timers individually just because a) there are not many long-duration timers in my system and b) I can control what timers to restore (as some of them just shouldn’t be).
Just want to point out that as you may know, input_text
as any state object can hold no more than 255 characters as its state so I presume that if someone creative calls their timers like morning_routine_when_I_am_in_the_mood_to_excersise_for_longer
and they have say, 3 or more of them, they’ll be in trouble because some timers’ data won’t make it to the input_boolean
or (more likely) HA will refuse to accept a new one and they’ll end up with an old dataset (or empty string).
Yes, you’re right. That’s a limitation of this design. At the time I was developing it, someone else was submitting a PR to make the restoration of active timers a native capability. Therefore, I considered my solution a stopgap measure until the PR was released. However, the PR was never released.
I can think of alternatives to using an input_text but they’re more complicated. If you know of a simple substitute, I’d like to hear about it. My impression is very few people have adopted what I’ve shared (and none have reported encountering the limitation) so I’m in no hurry to alter the design, especially if it makes it more complicated.
I see.
Just wanted to highlight the limitation for potential users.
Alternative can be using separate input_text
s for each timer. It’s a bit more complicated and requires some naming agreements (and it’s just a concept, I haven’t implemented it).
maybe because doing it in bulk is rarely needed?
I think the reason is more comprehensive: I believe few people are even aware that active timers (and delays) aren’t restored. They discover it empirically, when their long duration timer fails to run to completion because it was interrupted by a restart.
it’s says about it in the docs. so maybe it’s even more comprehensive - few people need to restore their timers at all as their timers never run for more than few minutes anyway.
just a guess, nevermind
I agree with you. It includes me as well! Plus my server is an old laptop with several hours of battery life. Fact is, I created this solution as an intellectual exercise and actually have no personal need for it.
Just to add to this discussion, some time ago I set up some ‘guest mode’ timers which I needed to survive a restart. My method is I think similar that which @AhmadK is suggesting. It saves the start time and duration when a timer starts and on a restart checks it should still be active and if so, (re)starts it for the necessary remaining time.
It is almost certainly not perfect but it works flawlessly for me. It was however one of my early HA projects and I haven’t been back to revisit it since, so there may well be a better way to do this.
But in case anyone coming here in future is interested, here is the meat of it. Any constructive criticism is welcome, as I said I wrote it a long time ago.
- alias: Guest mode schedule 1 check at startup
trigger:
- platform: homeassistant
event: start
condition:
- condition: state
entity_id: input_boolean.guest_mode_schedule_1
state: 'on'
- condition: or
conditions:
- condition: template
value_template: "{{ states('input_select.guest_mode_schedule_1_day') == now().strftime('%A') }}"
- condition: template
value_template: >
{% set time_now = as_timestamp(now()) %}
{% set start_time = states('input_datetime.guest_mode_schedule_1_start_time') %}
{% set start_time = as_timestamp(now()) | timestamp_custom('%Y-%m-%d') + ' ' + start_time %}
{% set duration = states('input_number.guest_mode_schedule_1_duration') | int * 60 %}
{% set end_time = as_timestamp(start_time) + duration %}
{{ time_now > as_timestamp(start_time) and time_now < end_time }}
action:
- service: timer.start
data_template:
entity_id: timer.guest_mode_schedule_1_duration
duration: >
{% set time_now = as_timestamp(now()) %}
{% set start_time = states('input_datetime.guest_mode_schedule_1_start_time') %}
{% set start_time = as_timestamp(now()) | timestamp_custom('%Y-%m-%d') + ' ' + start_time %}
{% set duration = states('input_number.guest_mode_schedule_1_duration') | int * 60 %}
{% set end_time = as_timestamp(start_time) + duration %}
{% set seconds_left = end_time - time_now %}
{% set hours_left = seconds_left // 3600 %}
{% set minutes_left = (seconds_left - (hours_left * 3600)) // 60 %}
{{ '%02i' | format(hours_left) }}:{{ '%02i' | format(minutes_left) }}:01
I have a bunch of timers set, but I also constantly mess with HA configuration and have to restart. The one I care about is automatic door lock after 15 minutes. In 15 minutes that I come back from walking the dog I already manage to restart HA 3 times, so the door never auto-locks (because i turned off the asinine 30 second auto-lock). I mean I can add another automation to lock 15 minutes after HA restart, but i would be nice if timers had an option to save state.
Or maybe a supervisor feature. Timer set at 7:45PM to run at 8PM. It is 8PM now and the automation is turned on, but did not fire. Show alert / Execute automation.
I’ve been using this python script since released and works great. All my timers survive.
And if I want to exclude there’s guidance offered by the contributor up above.
Thanks for the info; it works great! Well… a little too great. My timer wont reset if a timer.cancel is initiated.
I’m basically loading this timer from an input_boolean on/off trigger. OFF should cancel the current timer (timer.XXX) — which is does; but upon the boolean ON command again, it loads up the remaining time that was left before it was cancelled. I know it’s because the data was stored (front these automations and python),
How do i clear those values on timer.cancel?
P.S. even timer.start with its 18000s (5Hrs) value in config doiesnt reset it back to 18000s.
Thanks for any help.
What you are experiencing is explained by the Note in the first post.
Because of how the restoration technique works (i.e how it affects duration
) you must always specify the timer’s duration
when starting it. Otherwise you run the risk of having the timer use a duration
that differs from what you originally specified.