Hi,
I have written this automation that turns on the light at the outside door (with Sonoff relay) for “x” seconds, after sunset, when the reed switch on sliding door disengages.
The automation is working but I need to make it smarter and its getting too complicated in my head. So essentially what I want is as follows:
Once the door opens then light should stay “on” as long as the door is open or till a specified time, I will hard code “5 seconds” for now but will replace with a helper eventually.
@Hellis81 Thanks, I’ve never used “wait_for_trigger” so learnt something new!
So now the light turns off when door closes or if the 15 seconds is up (even if door is still open). Is there an easy fix to change it to greater of 15 seconds or the door open duration?
I’m leaving the house, just need time (~15 seconds) to lock and walk away and the light should turn off within some hard coded value - 15 seconds in code above.
I open the door and walk up to the mailbox and then walk back, I’d like the light to stay on as long as the door is open. It will be more than 15 seconds for sure in this scenario.
The key is that he does not close the door when walking to the mailbox but does when leaving the house. So all that is needed is on when the door opens and a 15 second delayed off when the door closes.
How about the following? Also note that restart mode seems more appropriate.
- id: '1656649797945'
alias: A-Test
description: ''
trigger:
- platform: state
entity_id:
- binary_sensor.window_b10
from: 'off'
to: 'on'
for: 2
action:
- type: turn_on
device_id: 2ccdc1687b78569a1d259801e333a128
entity_id: switch.basic02_relay
domain: switch
# Wait for either door to close or 15 seconds,
# whichever comes first.
- wait_for_trigger:
- platform: state
entity_id:
- binary_sensor.window_b10
from: 'on'
to: 'off'
timeout: 15
- if: "{{ wait.trigger is none }}"
then:
# Door is still open after 15 seconds.
# Continue to wait for it to close.
- wait_for_trigger:
- platform: state
entity_id:
- binary_sensor.window_b10
from: 'on'
to: 'off'
else:
# Door closed within 15 seconds.
# Wait for remainder of 15 seconds to elapse.
- delay: "{{ wait.remaining }}"
- type: turn_off
device_id: 2ccdc1687b78569a1d259801e333a128
entity_id: switch.basic02_relay
domain: switch
mode: restart
No, that is only part of the implementation. See the if that comes next.
The main point is the automation action needs to wait for one of two events: the door closing or 15 seconds after it opens. By using a wait_for_trigger with a timeout it can do both. There are two outcomes to that wait: 1) the door does not close within 15 seconds (wait.trigger is none), in which case it needs to continue waiting for the door to close; or 2) the door closes within 15 seconds, in which case it needs to wait for whatever time is remaining on the 15 second timeout.
That’s not what was requested (at least how I interpreted it), although it’s also a reasonable way to do it.
Tom - the split automation you’ve suggested is working like a charm, so solved the problem for now.
Phil - your automation seems interesting and I may have another use for it but I could not pass the validation check as “duration: 15” kept giving errors. What do you mean by door.timer exist?
I’ve implemented what I call ‘state-based’ automations, rather than ‘event-driven’ automations. Essentially, a model determines what the state of your entity should be at any moment in time, based on states of other entities. For example, here’s the automation for my garage light:
alias: Garage Light Automation
description: ''
trigger:
- platform: time_pattern
minutes: /1
- platform: state
entity_id: sensor.garage_motion
to: Violated
- platform: state
entity_id: cover.garage_door_1
to: open
- platform: state
entity_id: cover.garage_door_2
to: open
- platform: state
entity_id: sensor.back_door
to: Violated
condition: []
action:
- service: |
{%- macro delta(dt) -%}
{{as_timestamp(dt) - as_timestamp(now())}}
{%- endmacro -%}
{%- set NOW = 0 -%}
{%- set STARTUP_DELAY_SEC = 60 -%}
{%- set LIGHT_DELAY_SEC = 300 -%}
{%- if
NOW < delta(states('sensor.uptime')) | int + LIGHT_DELAY_SEC + STARTUP_DELAY_SEC or
NOW < delta(states('input_datetime.garage_light_last_manually_switched')) | int + LIGHT_DELAY_SEC
-%}
{# Do nothing if HA started up recently and lost last changed time or if light was manually toggled #}
script.noop
{%- elif
NOW < delta(states.sensor.garage_motion.last_changed) | int + LIGHT_DELAY_SEC or
is_state('cover.garage_door_1', 'open') or
NOW < delta(states.cover.garage_door_1.last_changed) | int + LIGHT_DELAY_SEC or
is_state('cover.garage_door_2', 'open') or
NOW < delta(states.cover.garage_door_2.last_changed) | int + LIGHT_DELAY_SEC or
is_state('sensor.back_door', 'Violated') or
NOW < delta(states.sensor.back_door.last_changed) | int + LIGHT_DELAY_SEC
-%}
light.turn_on
{%- else -%}
light.turn_off
{%- endif -%}
entity_id: light.garage_light
mode: queued
The automation will turn the light for as long as either of the garage doors or the back door are open, and for the 5 minutes after any of those or the motion sensor changed state.
Every sensor that is evaluated needs to be included in the trigger, but the action is basically a large check to determine what the state of the light should be. Perhaps a bit wasteful on resources (for example, the automation is triggered every minute, on the minute), but I find it way easier and less error-prone to manage complex rules. Thoughts and feedback appreciated.
It’s time pattern that makes it a bad automation.
You’re using so many calculations which is quite wasteful.
You could just use state change triggers and all these calculations would be gone.
The time you keep the light on is in my opinion not long enough for me to make it resistive to restarts as your probably is.
If I was to do it, then I would set an input datetime with the time the light should go off and trigger on time > that datetime.
You do realize that this too would be evaluated every minute just like the time pattern, right? It would be great if HA could register for a particular time and get a callback, but last time I checked it didn’t work that way.
I’m running HA instance on a single rack server so computation load is least of my worries.
For the garage door, I also struggled with persistence of state and did not want to keep writing to D1-Mini board memory. I made peace on the project by installing two reed switch to increase reliability but your “state-based” code may have worked with single reed sensor on the garage door.