Back again with another logic problem that I think I have licked but a second set of eyes wouldn’t hurt.
Problem: I have a mudroom with an automation that turns lights based on motion. 2 minutes after the lights have been on, turn lights off.
At it’s most basic level, this works fine. However, I have noticed (and found several threads) where “stacked timers” interfere with shutting off the light if it’s turned on and off again during automation timer. I’ve seen methods like using a script timer reset to work around this. I’ve tried trigger templates (which I’ve seen require sensor.time as apparently now() doesn’t work in trigger templates–haven’t been successful in trying this but that could be my own inexperience.)
So I decided to do this instead, I think my logic is correct here based on observation while at the same time defeating the “stacked timer” effect:
- alias: Auto Turn Off Mudroom
trigger:
- platform: state
entity_id: light.mudroom
to: 'on'
for:
minutes: 2
**new**
condition:
condition: or
conditions:
- condition: template
value_template: '{{ as_timestamp(now()) - as_timestamp(states.automation.auto_turn_off_mudroom.attributes.last_triggered) | int > 120 }}'
- condition: template
value_template: '{% if states.automation.auto_turn_off_mudroom.attributes.last_triggered == none %}true{% endif %}'
**new**
action:
- service: homeassistant.turn_off
entity_id: light.mudroom
Idea being that if:
(my new automation code is in between the new section, basically, the condition check)
Mudroom lights have been on for 2 minutes, turn them off if:
a) The last time this automation was last_triggered is greater than 2 minutes, or
b) The last time this automation was last_triggered was never
Thanks, I tried that previously as well. Still results in a stacked timer end result.
I haven’t actually tried my new version yet (will when I get home) but I think it will get around the problem but was hoping to have more eyes weigh in
Seems to work and has the added benefit of resetting the timer for shut-off as well when multiple motion events happen after it’s already turned on. Nice.
You could introduce a Boolean sensor in this?
With that you break it up in two automations.
The first one acts on the motion sensor and does two things: turn on the light and sets the Boolean to “on”.
Then you have a second automation that monitors the Boolean sensor. Once that reaches 2 minutes of being “on” it turns off the light, and sets the Boolean back to “off”.
I must admit that I’m not 100% sure from your description what you’re trying to achieve, but I would think that the booleans give you the flexibility you need, even if it is slightly different from what I described above.
I can try that too. I think it’s actually working but it’s hard to reproduce on demand it seems (the issues I’m trying to overcome.)
Basically as @Pilot wrote above (from the other thread) is that when there are multiple instances of an automation fired where a timer is attached (in my case, and his in that thread, using “for:” – even happens with with “delay:”) that a series of timers stack up causing an automation to fire multiple times rather than being atomic (if that makes sense.)
Right now it’s definitely turning off the light – I’ve tried turning on the light manually via dashboard and waiting for it to turn off, which it does. I’m trying to reproduce a scenario I encountered where the automation to turn off the lights builds multiple “off timers” and turns it off at random times.
Basically:
Light turns on, light turns off by human before 2 min
Light turns on, stays on for 1 min, turned off by automation as timer still counting
It was easier to reproduce with bigger time frames (I used to have it turning off @ 5min instead of @ 2min) so it’s a bit slow-going to repo the issue But a boolean as a switch to check whether to turn off may also work (but that’s why I used last_triggered for the automation > 120; same logic being applied–in my mind anyways.)
Thanks, appreciate the input. I have two automation, ones that turns the light on and one that turns it off. I’ve tried delay and for: and both produce same results. Your example above is pretty much what I have except you’re using the delay for off whereas I tried delay: and for: (stuck with for:) – It’s a pretty specific use-case I think that I’m working on.
I think I might have it licked. So here’s the automation:
- alias: Auto Turn Off Mudroom
trigger:
- platform: state
entity_id: light.mudroom
to: 'on'
for:
minutes: 1
condition:
condition: or
conditions:
- condition: template
value_template: '{{ as_timestamp(now()) - as_timestamp(states.automation.auto_turn_off_mudroom.attributes.last_triggered) | int > 60 }}'
- condition: template
value_template: '{% if states.automation.auto_turn_off_mudroom.attributes.last_triggered == none %}true{% endif %}'
- condition: template
value_template: '{{ as_timestamp(now()) - as_timestamp(states.automation.mudroom_motion.attributes.last_triggered) | int > 60 }}'
action:
- service: homeassistant.turn_off
entity_id: light.mudroom
Basically I check three things:
Is the time for the automation to turn off lights last_triggered > 60 seconds
Or is the time for the automation to turn off lights last_triggered = never
Or is the time for the automation to turn ON lights last_triggered > 60 seconds
I believe this will solve the stacked timer problem. Will continue to test but just wanted to post some results I’ve had so far. I haven’t had any wonky-random shut-off’s by having these three checks which should stop any future timers from firing out of band (I think… logic seems sound to me as I understand it.)