WTH: Why can’t I use “for” without defining a “to”-state in automations?

In automations I can only use “for” if I know the “to”-state. I can’t do something like this, if I only want to make sure the state is the same for a while, without knowing the state:

automation:
  trigger:
    platform: state
    entity_id: sensor.somesensor
    for: "01:10:05"

Something has to start the period.

Otherwise the the whole thing becomes undefined also in human logic.

You start Home Assistant. And after “for” time the trigger becomes true.

And from then on it is true. So when does it trigger. Every second?

A trigger has to be something that happens in a single logically atomic event.

Conditions can be related to intervals or states. But a trigger has to be something that changes and reaches the trigger criteria

It cannot be something that continuously meets the criteria. That is the same in all home automation programs that I know of. It is always something with

When this happens
And these criteria are met
Then do this

1 Like

What is your intended application for this?

You could create a binary sensor with a delay on equal to a delay off and use that as your trigger instead.

Yeah, the state change would start it. I agree with OP and I don’t see this being difficult to implement. It would just start a timer on every state change. I don’t see a use case, but I’m sure there are some. I seem to remember someone needing something like this in the past.

I can think of a few (since I like this idea as well). First one that comes to my mind would be a sensor you were using for presence. Let’s say for example that you had a sensor that detected when someone was sitting in a chair and you wanted to use input from that sensor to determine whether to turn on the lights.

The easy way to do that would be to turn the lights on if the sensor says someone is in the chair and turn it off if not. That would probably work but if the sensor is pretty sensitive that could get quite “twitchy”. You wouldn’t want the lights to flicker just because someone shifted in the chair. Limiting it to transition only if the sensor’s state has changed for at least a second or two seems like it would result in a better experience.

Another I personally use a lot is a light sensor to determine brightness in the room. I track light level in rooms with smart lights and have binary sensors for bright_<room> which becomes on when light level is above a threshold and off otherwise. I then combine that with presence data to turn the lights on/off when someone is in the lights and its dark.

This one has similar issues to the chair situation though, I don’t want it to be “twitchy”. In this case the problem occurs if the light level is very close to threshold. So because of that prefer to only transition the light if light level has crossed the threshold for a specified amount of time.

Now with these you could argue that since these use cases are all binary wouldn’t it just be easier to make an on and off automation instead of using a conditional in the script? Perhaps, I prefer to combine but I can understand this. So here’s one additional non-binary one I use as well: guessing the mode of transit based on the velocity of a device_tracker.

This could then be used for calculating ETA to send that information to Nest/Ecobee/etc. so the house can be a comfortable temperature by the time you get there. If you’re differentiating between car, walking and biking based on velocity though then you’d obviously have a problem with traffic lights since the car’s velocity goes to 0. So you’d only want to change your mode guess if there was a sustained transition between states.

2 Likes

That’s a lot of words to described this:

  trigger:
    platform: state
    entity_id: binary_sensor.chair
    to: 'on'
    for: '00:00:05'

That’s 5 seconds of hysteresis to confirm butt is truly on the chair.

Plus this:

  trigger:
    platform: state
    entity_id: binary_sensor.chair
    to: 'off'
    for: '00:00:05'

to provide 5 seconds of hysteresis to confirm butt is truly off the chair.

Except you want both to be expressed in one trigger:

  trigger:
    platform: state
    entity_id: binary_sensor.chair
    for: '00:00:05'

Then it’s left to the action’s template to determine which occurred (on or off) using the Trigger State Object.

OK, that makes sense to me.

4 Likes

Related question, are we allowed to use for: for from: state triggers now?

I seem to remember hitting that rodeblock once but it was a while ago.

well with this change (if it happens), I would suspect that would work now.

The use case I would see for this is for “dead” sensor detection. Say there is a battery operated temperature sensor that stops reporting. It isn’t a binary sensor so there isn’t one particular state to use in a for: clause.

However this can be done with a template trigger comparing the timestamp of the last_updated field.

{{as_timestamp(now())|int - as_timestamp(states.sensor.upstairs_temperature.last_changed)|int > 60 }}

The above example will return true after 60 seconds.

1 Like

The last time, it wanted the write an automation which triggers an update when one specific sensor showed the same value for X minutes - but especially not on a fixed schedule.
In that case I can’t possibly know the state (and add that many triggers), because it could be one of hundreds.

Also the use case above with binary_sensor.chair is something could use often and would clean up my automations by a lot.

Yes. If we explitly assume any state change, then it makes sense.
However I would prefer a syntax that does not leave any open questions.
For example that the change from undefined to a value during start or restart, should that count as a change?
Would it be better do define use of a wildcard as a to value.

I agree with the many usecases already raised.

I am not sure what that would mean, what would cancel the for: so it does not trigger?

trigger:
  platform: state
  entity_id: media_player.foo
  from: playing
  for:
    seconds: 30

Would only trigger if paused, stopped, idle or unknown for 30 seconds. i.e. anything other than playing for 30 seconds.

It would “cancel” when the state returned to playing and then be able to be triggered again.

the same as using the to: trigger but only the opposite.

if the state changes from from: then the trigger is cancelled.

My use for it was in a device tracker since there can be many states since the tracker can be home, not_home or in any number of zones.

So we cant say:

trigger:
  platform: state
  entity_id: device_tracker.something
  from: not_home # meaning tracker is actually home or in some defined zone
  for:
    minutes: 10

use case:

Your child leaves home for school but occasionally stops at a different acceptable and known location in between (all known zones) but doesn’t get to the school zone in an expected amount of time so send a notification.

To do this now you would have to account for every zone they might stop in to define a from:/to: scenario.

Might be a bad use case since I just came up with it and haven’t necessarily thought it all the way thru but you get the idea I hope.

@tom_l @finity Thank you both, I think it is now clear.

(Another option was that moving from playing via paused to stopped would cancel the from: playing trigger when it was no longer the most recent from_state.)

There are some enhancements that seem subtle on the surface but are actually game-changers in how they improve our ability to create automation logic.

The pending enhancements to how listeners are assigned to Template Sensors is this kind of game-changer and so is this one (if ever implemented).

1 Like

It turns out that a to: wildcard works, so you can do this:

automation:
  trigger:
    platform: state
    entity_id: sensor.somesensor
    to: "*"
    for: "01:10:05"

and it seems that it will do what you asked,

1 Like

Really?

The https://www.home-assistant.io/docs/automation/trigger/ only mention the use of wildcard for time.

What other fields in automations accept wildcards?

It seems this WTH becomes almost not needed if you could read in the documentation that you can write to: "*"

Is the to: "*" even needed? Can you not just specify “for” and it will trigger on any new state being “on” for the specified time?

1 Like