Automation trigger of state change after being at a state for a time

I can make an automation trigger because an entity had been at a state for some time, but I’d like to have a trigger for a state change after that entity has been static for some time.

Practical example: my proximity sensor regularly switches between ‘stationary’, and either ‘towards’ or ‘away_from’ everytime my device tracker sees me moving. I’d like to be able to have an automation trigger only if that state changes after having been stationary for 20 minutes, so it wouldn’t trigger after I was stopped at a traffic light, for example, but it would if I had legit stopped somewhere.

Is this possible today?

Try a template condition with something like:

{{ now().timestamp() - as_timestamp(states.DOMAIN.OBJECT_ID.last_changed) > 20*60 }}
1 Like

Of course, you are right. I can’t believe I didn’t see this solution. Too fixated on the trigger to think about the conditions as the solution.

1 Like

I realize now that this actually isn’t going to work the way I need it to.

- alias: trigger_when_static_for_1_minute
  trigger:
    - platform: state
      entity_id: sensor.my_sensor
  condition:
    condition: template
    value_template: >
      {{ now().timestamp() - as_timestamp(states.sensor.my_sensor.last_changed) > 60 }}
  action:
   - service: blah

This will still fire when the state changes, get ignored by the condition, and then never fire again. It won’t actually get triggered when the state of the sensor has remained unchanged for 60 seconds. It’ll only get triggered when it gets changed after being static for more than 60 seconds.

1 Like

I think I actually need a timer, and a second automation to fire when the timer goes off, and do the action after verifying that the sensor hasn’t changed.

1 Like

I think what you’re looking for is:

- alias: trigger_when_static_for_1_minute
  trigger:
    - platform: state
      entity_id: sensor.my_sensor
  condition:
    condition: template
    value_template: >
      {{ trigger.to_state and trigger.from_state and
         (trigger.to_state.last_changed - trigger.from_state.last_changed).total_seconds() > 60 }}
  action:
   - service: blah

Let me know if you have any questions.

I don’t think that’s going to do it either. I need a trigger that’s going to fire when the status is N time old. It can’t be a condition.

Wait, let’s take a step back…

First, this won’t actually do what you think. When the state changes the last_changed field will be updated to basically now, so this automation will never run its action.

What you need to look at instead is trigger.from_state.last_changed. That will be the last time its state changed (i.e., before this recent change.)

Next, have you changed your requirements? It was pretty clear that originally you were asking how to run an action when a sensor changed, but only if it hadn’t changed for a specified amount of time before that. Now you seem to be asking for something different – i.e., run an action some amount of time after a sensor changes state. So which is it?

Yeah, perhaps I didn’t state things clearly before. I want the functionality of

trigger:
  - platform: state
    entity_id: sensor.mysensor
    for: '00:01:00'

but without having to specify the to field, because I don’t care what that value is, as long as it stays there for a minute.

Ok, fair enough. And, yes, unfortunately you are correct. To use the for option you need to specify to. I think you’re also correct in that the best way to implement this is probably with a timer. Maybe something like:

- alias: trigger_when_static_for_1_minute
  trigger:
    platform: state
    entity_id: sensor.my_sensor
  condition:
    condition: template
    value_template: >
      {{ trigger.to_state and trigger.from_state and
         trigger.to_state.state != trigger.from_state.state }}
  action:
    service: timer.start
    entity_id: timer.my_sensor

- alias: static_part_2
  trigger:
    platform: event
    event_type: timer.finished
    event_data:
      entity_id: timer.my_sensor
  action:
    ...

The first automation will start, or restart, the timer. The second automation will run the action when the timer finishes.

Note that the condition of the first automation makes sure that only real state changes will (re)start the timer. I.e., attribute only changes will not affect the timer. If the sensor doesn’t have any attributes (that change), then you can probably do without the condition.

Yeah, I’m halfway through doing exactly this. The actual implementation in my case is a little more complex, but that’s the idea.

on a related note:

is there any way to check that the state has been “not” in some state for a period of time?

specifically, for my use I’d like to check that the state is from a state not to a state:

trigger:
  platform: state
  entity_id: person.me
  from: some_zone
  for: '00:10:00'

I had a case for this too. I ended up using a timer and splitting my automation into two: one that started the timer when the state moved from the one I was tracking, and the other when the timer finished and did whatever the single automation was supposed to do

So far I’m using a binary sensor that goes to on when I’m not in the zone and triggering on that turning on for 10 minutes.

I’m really surprised that “from: something for: a time” was overlooked as a need.

I guess I could add a feature request but I’m not sure those really do any good.

Yeah, I see that as a definite need. I would often want a sensor automation to fire if it was “not off” for more time than a short blip to ‘unavailable’ and back.

That’s exactly the reason i needed it.

FR here: Add "for:" option to automation trigger for a "from:" transition

Would this do it?

trigger:
- platform: template
  value_template: "{{ not is_state('person.me', 'some_zone') }}"
  for: '00:10:00'

Yeah, it would. But it was more of a generic question and/or statement of surprise that we couldn’t use for: in a from: option like we can in the to:

Unfortunately, the for option is only available on the state trigger, not template. I suppose you could define a template (binary) sensor and then use the state trigger for that though.

Why do you say that? It sure is.