Automation Condition: State wasn't x in the last y seconds

I saw a few similar questions posted here, but the answer seem to direct to the for: directive. Here is what I’m trying to achieve. I have an automation based on my Unifi G4 Pro doorbell. If the doorbell detects a person, it sends a picture to my phone, sends a picture to the tv and plays an alert on the Google home. This works well, but it also alerts if I walk out the front door. I’d like to prevent that. What I was thinking was if the front door had been unlocked within the last X seconds, then that means I probably left the house. The state of the lock when the doorbell sees me may be locked though, so I don’t want to just check that it’s unlocked for X seconds. I want to say, was it changed from locked to unlocked within the last X seconds. How can I add that into the conditions?

Thanks!

Here’s my current automation in YAML:

alias: Front Door - Person Detected
description: ""
trigger:
  - platform: state
    entity_id:
      - binary_sensor.front_door_person_detected
    from: "off"
    to: "on"
condition: []
action:
  - parallel:
      - service: shell_command.get_image_full
        data:
          entity_id: sensor.front_door_camera_snap
          ha_token: xyz
          ha_url: xyz
          img_ext: jpeg
          img_url: http://192.168.2.36/snap.jpeg
          save_loc: /mnt/ha_www_images/
        alias: Get Image
      - type: turn_on
        device_id: a9af91ad9b9edd85013e47022d41934f
        entity_id: light.porch_light
        domain: light
    enabled: true
  - parallel:
      - service: media_player.play_media
        target:
          entity_id: media_player.kitchen_display
        data:
          media_content_id: media-source://tts/google_translate?message=Person
          media_content_type: provider
        metadata:
          title: Doorbell
          thumbnail: https://brands.home-assistant.io/_/google_translate/logo.png
          media_class: app
          children_media_class: null
          navigateIds:
            - {}
            - media_content_type: app
              media_content_id: media-source://tts
            - media_content_type: provider
              media_content_id: media-source://tts/google_translate?message=Person
      - service: notify.living_room_tv
        data:
          message: Person Detected
          title: Home Assistant
          data:
            color: grey
            duration: 5
            image:
              url: http://192.168.2.36/snap.jpeg
            fontsize: large
            interrupt: 1
            position: bottom-right
            transparency: 25%
        alias: Put image on TV
      - service: shell_command.notify
        data:
          message: Person at front door
          space: xyz
          file_name: "{{ states('sensor.front_door_camera_snap') }}"
          token: xyz
          type: image
        alias: Send to Phone
        enabled: true
    enabled: true
mode: single

You can use the history stats.

sensor:
  - platform: history_stats
    name: Door unlocked in the last X seconds
    entity_id: binary_sensor.door_lock
    state: "off"
    type: count
    end: "{{ now() }}"
    duration:
      seconds: X

This sensor will be a count of the fictitious binary_sensor.door_lock transitioning to off in the last X seconds.
To play with as condition in your automation.

If you have a door sensor, you can keep it simple with just a state condition and a for… i.e. “the door has been closed longer than X seconds”. Otherwise, Olivier’s suggestion is a good one.

2 Likes

Thanks! That makes a lot of sense. I just set up a sensor like this:

  - platform: history_stats
    name: Door unlocked within last 10 seconds
    entity_id: lock.front_door_lock
    state: "unlocked"
    type: count
    end: "{{ now() }}"
    duration:
      seconds: 10

But it seems to only increment when the lock status changes from unlocked (to locked). It also seemed to stay at 1 for a minute, not 10 seconds. Perhaps I’ll try changing the format of the duration.

That part should count how many time it has changed to unlocked. If it is the other way around then maybe the status of the lock is not what everyone would expect :smiley:

You have to know that HA is more about the minute. Usually almost everything is evaluated every minute. So, yes, it might be possible that it will be 1 for the remaining of the current minute or something.

There is also a possibility to check that both this history sensor is 1 and maybe the last_updated timestamp of the lock and/or the history sensor. Going under the minute is always tricky and it will not be easy to setup.

Or you use the idea of @Didgeridrew and add a for: with the lock status

condition:
  alias: "Door was locked in the last X seconds, so was unlocked before"
  condition: state
  entity_id: lock.front_door_lock
  state: 'locked'
  for:
    hours: 0
    minutes: 0
    seconds: 10

Feel free to do a combo with all our ideas :slight_smile:

EDIT To be as complete as possible, here are 2 templates you can use, giving a number of seconds

Last time it was changed
{{ now() | as_timestamp | int - states['lock.front_door_lock'].last_changed | as_timestamp | int }}

Last time it was updated
{{ now() | as_timestamp | int - states['lock.front_door_lock'].last_updated | as_timestamp | int }}

1 Like

You can simplify that quite a bit by leaving out the timestamp conversions…

{{ (now() - states.lock.front_door_lock.last_changed).total_seconds() }}

Great! I added this and it worked (I had to make it 30 seconds because evidently it takes me longer than 10 seconds to unlock the door, open it, walk outside, pick up an amazon package and come back in!):

condition:
  - condition: not
    conditions:
      - condition: template
        value_template: >-
          {{ (now() - states.lock.front_door_lock.last_changed).total_seconds()
          < 30 }}

Thanks!

1 Like