Multiple triggers in a time window

Hello,

I have been trying to do a set of automations when I get home, but have been a little confused on the best way forward.

The first automation I want is that if I come home, and open the garage door, then unlock the inner door.

So I want this to trigger, if both the events (arrive home, and open garage door) occur within a set time window, say 1 minute.

Haven’t figured out the best way to do this.

Thanks

Do you want to open the garage door every time you come home or just when you come home by car and leave it closed when you arrive home e.g. by foot or taxi?

Easiest way is to use a trigger that kicks off when the a device you always have on you, e.g. a mobile phone, goes to the state ‘home’.
This can then result in both actions:

  1. Open the garage door
  2. Unlock the door

In this case you don’t need to check for both items to occur within a certain time because you set them up that they always will because they are always triggered together.

This is why it’s a little tricky. I only want to open the internal door if I arrive home (using router connection for presence detection) and I open the garage door within a time window.

I rejected other scenarios:

  1. Open the garage door when I come home - well most of the time I arrive home by foot and go through the front door.
  2. Just open the internal door whenever I come home - this is what I currently do, but I don’t really like it.

Another scenario:
When I arrive home, and open the front door, announce a welcome. Obviously I don’t want a welcome if I just open the front door (like to leave), but I also don’t want the welcome when I arrive home because I’m likely still outside.

Okay, misunderstood your first description.

I thought the ‘and’ was different.

How about this:

2 Scenarios to cover the issue that your router might detect presence before or after you opened the garage door manually.

  1. The garage door is open AND you come home.
  2. You are home AND then the garage door opens.
alias: Unlock internal door
  trigger:
    - platform: state
      entity_id: device_tracker.winter
      to: 'home'
    - platform: state
      entity_id: cover.garage_door
      to: 'open'
  condition:
    - condition: state
      entity_id: device_tracker.winter
      state: 'home'
    - platform: state
      entity_id: cover.garage_door
      state: 'open'
  action:
    service: lock.unlock
    entity_id: lock.internal_door

Alternatively, you could use an action that set’s a boolean for each trigger individually, have the individual boolean reset after 1 minute and only trigger the internal door lock if both booleans are on:

alias: Boolean garage door just opened
  trigger:
    - platform: state
      entity_id: cover.garage_door
      to: 'open'
  action:
    - service: homeassistant.turn_on
      entity_id: input_boolean.garage_door
    - delay: '00:01:00'
    - service: homeassistant.turn_off
      entity_id: input_boolean.garage_door

alias: Boolean winter just came home
  trigger:
    - platform: state
      entity_id: device_tracker.winter
      to: 'home'
  action:
    - service: homeassistant.turn_on
      entity_id: input_boolean.winter_home
    - delay: '00:01:00'
    - service: homeassistant.turn_off
      entity_id: input_boolean.winter_home

alias: Unlock internal door
  trigger:
    - platform: state
      entity_id: input_boolean.winter
      to: 'on'
    - platform: state
      entity_id: input_boolean.garage_door
      to: 'on'
  condition:
    - condition: state
      entity_id: input_boolean.winter
      state: 'on'
    - platform: state
      entity_id: input_boolean.garage_door
      state: 'on'
  action:
    service: lock.unlock
    entity_id: lock.internal_door

I would use one automation with a wait_template like this:

automation:
  - alias: Unlock door if garage opened within 1 min of coming home
    trigger:
      platform: state
      entity_id: DEVICE_TRACKER_ENTITY_ID
      to: 'home'
    action:
      - wait_template: "{{ is_state('GARAGE_DOOR_ENTITY_ID', 'on') }}"
        timeout: '00:01:00'
        continue_on_timeout: false
      - service: lock.unlock
        entity_id: LOCK_ENTITY_ID

I don’t use covers or locks so I might have gotten some of the details wrong. But the basic idea is trigger when you come home, then wait for the status of the garage door to be open, but only up to a minute. If it opens within that time-frame, then unlock the door. Otherwise, don’t continue.

3 Likes

What happens in this case if the router registers the device has arrived ‘home’ only after the garage door has been opened?

Then it does what the OP’s requirements state: nothing. :wink:

Not sure the sequence is set in stone that way - we’ll let the OP decide :hushed:

Thanks for the solution, much more simple and elegant than mine - never used the ‘wait’ function before but it’s definitely a good thing to have in one’s back pocket :+1:

1 Like

But seriously … you may be right. They could be interpreted that the door should be unlocked if the events happen in either order, as long as they happen within one minute of each other. I suppose to support that my above automation could be basically duplicated, but the roles switched. So, the above plus:

  - alias: Unlock door if come home within 1 min of opening garage door
    trigger:
      platform: state
      entity_id: GARAGE_DOOR_ENTITY_ID
      to: 'on'
    action:
      - wait_template: "{{ is_state('DEVICE_TRACKER_ENTITY_ID', 'home') }}"
        timeout: '00:01:00'
        continue_on_timeout: false
      - service: lock.unlock
        entity_id: LOCK_ENTITY_ID

But now that I think about it more, these don’t handle the cases where, e.g., the garage door was already open (for some time) when the device comes home, and vice versa. So let’s try this instead:

automation:
  - alias: Unlock door if garage opened within 1 min after coming home
    trigger:
      platform: state
      entity_id: DEVICE_TRACKER_ENTITY_ID
      to: 'home'
    condition:
      condition: template
      value_template: "{{ not is_state('GARAGE_DOOR_ENTITY_ID', 'on') }}"
    action:
      - wait_template: "{{ is_state('GARAGE_DOOR_ENTITY_ID', 'on') }}"
        timeout: '00:01:00'
        continue_on_timeout: false
      - service: lock.unlock
        entity_id: LOCK_ENTITY_ID
  - alias: Unlock door if come home within 1 min after opening garage door
    trigger:
      platform: state
      entity_id: GARAGE_DOOR_ENTITY_ID
      to: 'on'
    condition:
      condition: template
      value_template: "{{ not is_state('DEVICE_TRACKER_ENTITY_ID', 'home') }}"
    action:
      - wait_template: "{{ is_state('DEVICE_TRACKER_ENTITY_ID', 'home') }}"
        timeout: '00:01:00'
        continue_on_timeout: false
      - service: lock.unlock
        entity_id: LOCK_ENTITY_ID
1 Like

I use a condition to if the mud room door has been open in the last 4 mins meaning we are leaving the house instead of coming.

          - condition: template
            value_template: '{% if states.binary_sensor.mud_room_door.last_changed  %}{{(as_timestamp(now())-as_timestamp(states.binary_sensor.mud_room_door.last_changed)) > 360 }}{% else %}True{% endif %}'

There also seems to be an option to put this into the trigger directly - very interesting approach here:

Might be possible to do this by looking at the attributes for when the states were last changed.

Cool, a bunch of things to try out! I never heard of the wait_template.

To answer a previous question, the order of the events is not important, just that they happen in a window of time. Some times the door opens before I connect to router, other times its the router first, but both are valid reasons to unlock the internal door.

Here is the wait template docs.

1 Like

FYI, there is a slight chance that my solution won’t work if the transition to home and the door opening happen very close to each other. This is basically a race condition. The more I think about it, I think a better approach is to use one automation with a template trigger that requires both presence to be home and the garage door to be open, and that they both changed within the last minute. Not only would this be simpler, I’m pretty sure it will handle the case of both changing very close together. I’ll give it some more thought, but this is what I’m thinking:

automation:
  - alias: Unlock door when coming home and garage opens within a minute of each other
    trigger:
      platform: template
      value_template: >
        {{ is_state('DEVICE_TRACKER_ENTITY_ID', 'home') and
           is_state('GARAGE_DOOR_ENTITY_ID', 'on') and
           (now() - states.DEVICE_TRACKER_ENTITY_ID.last_changed).total_seconds() < 60 and
           (now() - states.GARAGE_DOOR_ENTITY_ID.last_changed).total_seconds() < 60 }}
    action:
      service: lock.unlock
      entity_id: LOCK_ENTITY_ID

The way this works is, the template will be evaluated when either of the entities change. It will be true if you’re home and the garage door is open, and they both changed to their current states within the last minute.

So, e.g., if you’re not home or the garage door is closed, then it will evaluate to False and the action won’t run. Also if you come home and the garage door is open, but it was opened more than a minute ago, the action also won’t run. Same if the garage opens and you’re home, but you’ve been home for more than a minute, the action also won’t run. But if you come home and the garage opens within a minute of each other, then when which happens last happens, the action will run to unlock the door.

3 Likes

@pnbruckner, genius!

Wait until you try it! I wouldn’t be too surprised if I’ve overlooked something. lol!!

One issue might be how this reacts at startup. Generally one of the entities in the template has to have a state change (either the state itself, or an attribute) for the trigger to “wake up” and be evaluated. But entities can act “funny” during startup. So it may be possible that one of the entities has a state change (e.g., an attribute) at startup which causes the trigger to be evaluated, and if this happens within a minute of startup, it’s possible this could unlock the door. If that does happen I can think of two solutions. 1) Set the initial state of the automation to off, which will prevent it from running after startup. Then have an automation that runs a few minutes after startup that turns this automation on. 2) Add a condition that HA’s “up-time” is more than a few minutes. I believe there is even an up-time sensor you can use for that. I think I’ve seen other people solve similar problems this way.

Bottom line - it needs testing! :slight_smile:

Ok, I implemented it so I will let you know how it goes :slight_smile:

I didnt receive any unlocks at startup so thats good.

1 Like

Promising template. I have a minor annoyance dealing with Lights turning on with motion and then off with no motion. Lights turn on with motion, then off when there has been no motion for 10 seconds. Works pretty well, but occasionally, I’m still and the lights turn off. Even that is not a huge deal, that’s what its supposed to do. :slight_smile:
But as soon as the lights go off, you move, then the binary sensor is already “on” before the automation finsihes, so the trigger “to: on” of course fails, so you stand there in a dark room for a few seconds until the sensor goes back to Off then move then start over. Usually I just end up telling Alexa to turn on the lights.

Again, not that common, but it happens. I just saw this and I think it should work using similiar logic from above.

- alias: Motion Lighting in the Kitchen
  trigger:
  - platform: state
    entity_id: binary_sensor.motion_sensor_kitchen_motion
    to: 'on'
  - platform: template
    value_template: >
      {{  is_state('binary_sensor.motion_sensor_kitchen_motion', 'on') and
         (now() - states.binary_sensor.motion_sensor_kitchen_motion.last_changed).total_seconds() < 20 }}
  condition:
  - condition: state
    entity_id: group.kitchen_zwave_lights
    state: 'off'
  - condition: numeric_state
    entity_id: sun.sun
    value_template: '{{ state.attributes.elevation }}'
    below: 3.0
  action:
  - service: homeassistant.turn_on
    entity_id: group.kitchen_zwave_lights
  - wait_template: "{{ is_state('binary_sensor.motion_delay_kitchen', 'off') }}"
  - condition: state
    entity_id: group.kitchen_zwave_lights
    state: 'on'
  - service: homeassistant.turn_off
    entity_id: group.kitchen_zwave_lights

The wait delay template is 10 seconds. I think I could get rid of the 1st trigger, right? That is the initial trigger.

Ah interesting, I always used two automation, one of on and one for off so never ran into this issue.

I wanted my off to be quick, and based on motion vs a time limit, which is what mostly found. My motion sensors have a quick on/off state (like 30 seconds), which I like. If I turned off as soon as motion stopped, I had to move around at least a little bit, so I added a short delay to keep the lights from turning on/off/on/off, but that ended up causing the issue described above. It’s like whack-a-mole. haha. Its actually about 90% good, and the 10% is not terrible, its not dark in the kitchen even with the lights off, but if I could get this 100%, I’d be pretty happy. :slight_smile:

So, with these two triggers:

  trigger:
  - platform: state
    entity_id: binary_sensor.motion_sensor_kitchen_motion
    to: 'on'
  - platform: template
    value_template: >
      {{  is_state('binary_sensor.motion_sensor_kitchen_motion', 'on') and
         (now() - states.binary_sensor.motion_sensor_kitchen_motion.last_changed).total_seconds() < 20 }}

the second one is (probably) useless.

Note that a template trigger will only fire when the template evaluates to True, and (normally) after it had been evaluated as False (although that’s not necessary for the first time it is evaluated after startup.) And it will only be evaluated when one of the referenced entities causes a state_changed event, which in this case is only when binary_sensor.motion_sensor_kitchen_motion’s state, or one of its attributes, change. And if it has no attributes that change (I don’t know, you don’t say), then only when its state (i.e., ‘on’ vs ‘off’) changes.

So, basically, the second trigger will only fire when binary_sensor.motion_sensor_kitchen_motion changes from something other than ‘on’ (probably just ‘off’) to ‘on’, which is exactly what the first trigger does. Also, the second part of the template is useless because it will always be less than 20 seconds since the state change when the state changes.

So, unless binary_sensor.motion_sensor_kitchen_motion has other attributes that change, the second trigger is effectively the same as the first trigger.