How to code this specific condition to skip an action in an automation?

Keeping it simple here so not going into every detail - using the datetime stamp of an entity state change, from “last_updated” - how do I get the trigger data (at a later time) from that event
(such as “trigger.to_state.context.####” to determine if it was manually changed at that time) - without setting up more variables to manually keep track of and maintain?

Here is the use case if more details are needed for clarity:

  1. Motion sensor automation turns on wall switch for overhead light
  2. At some point, someone turns OFF the wall switch manually and walks out of the room

As my motion sensor is configured to only detect motion once per minute, this use case usually works fine - IF the movement to turn off the light is detected and transmitted to Home Assistant -BEFORE the light is switched off, AND the person walks out of the room within one minute of when that motion is detected.

As you can imagine that is a little problematic - and annoying if the lights go back on while you are or just after you walk out of the room!

So, I am not sure how to enhance the condition for the automation in #1 to NOT turn said lights on if they were turned off manually within the last, say 5 minutes. Here is my research on how to implement this but it is lacking - and where I need help (the simple inelegant way is to set up variables maintained to use in the condition but I’d rather not) -

I believe this would tell me if the switch was turned off within the last 5 minutes:

{{ (as_timestamp(now()) - as_timestamp((states.input_boolean.entity_id_being_monitored.last_updated)) < 300)}}

and this will tell me if it was turned off MANUALLY (BUT I believe this information is only available at the exact time the state of the switch is changed previously - the information is not available later, is it?) -

condition:

  • “{{ trigger.to_state.context.id != none }}”
  • “{{ trigger.to_state.context.parent_id == none }}”
  • “{{ trigger.to_state.context.user_id == none }}”

So - without setting up variables to handle this (and as you can imagine I would then have a ton of these - ugh) - how do I get “trigger.to_state.context.####” information from a state that had changed in the past?

Have you considered a simpler approach? For example a State condition that the light switch has been off for at least x minutes. The following is one option of a Choose action I use for our kitchen lights where I had a similar issue:

      - alias: "Day: Turn Pantry light ON"
        conditions:
          - condition: trigger
            id: Pantry Motion
          - condition: state
            entity_id: switch.pantry_lightswitch
            state: "off"
            for: "00:00:30"
        sequence:
          - service: switch.turn_on
            target:
              entity_id: switch.pantry_lightswitch
            data: {}

Thank you so much @Didgeridrew, I had forgotten those settings and looked into it… but unfortunately I foresee an instance where that would cause the light to not go on automatically when we want it to, hence the validation of whether or not it was manually turned off to be used in the logic.

My use case is that when movement is detected then a timer (that is typically 30 minutes) is just (re)started. Then I have two other automations: one that will turn on the light if it is not already on when the timer is (re)started, and another automation that turns off the light when the timer is finished. (That is my way of using a less expensive motion detector and still not have lights go off for someone who is sitting still - who sits still for an entire 30 minutes?)

Since I prefer the timeout to be 5 minutes instead of 30 seconds (I have some bad automations that turn the lights on also from IFTTT but those are sometimes delayed by minutes - ugh) - with the above use case for motion indirectly turning on the lights - if I implement your good idea however - if someone walks into a room the lights would not go on - if it is within 5 minutes of the lights being turned off by the timer finishing.

Unfortunately I don’t think there really is a way to dig through history to get the trigger context data from the past. Therefore for each automation where I need this capability (only four places right now), I am just creating a datetime variable (helper) such as for example “last_manual_off-kitchen” which will be set by an additional automation run in parallel when someone manually turns off the switch (that is when I can utilize the trigger context information as a condition to populate the variable), and then checked whenever motion is sensed (so even if someone say last turned off the switch a month ago - it would not affect my use case).

I’ll leave this listed as not yet solved for now in case there are other ideas - as I do not like my workaround for this issue and @Didgeridrew your idea is a good one but not sure that’s the direction I want to go - :slight_smile:

Ok got 'er done - FYI for others if needed:

Wherever possible, I try to keep my automations and scripts very short and allow them to run in parallel, which has served well in overall performance and minimizing delays.

(*The paradigm I use below relies on other automations not shown here that will turn lights on (if not already on) when a certain timer is (re)started, and when that same timer either finishes or is cancelled, then turns the same lights off.)

I have discoveed there is a bug in HA for automations that use the “set” to set the value in an input_datetime helper. When you try to set the datetime, it also then afterward sets the time with midnight (“00:00:00”). It is shown there right in the yaml code - but it you go back in there and remove that line for setting the time (so the full datetime is just set instead), when you save it, that line of code to afterward set the time the “00:00:00” comes right back. I entered that as an issue (you can read that logged issue here). As a workaround until that is fixed, I just used input_text as the helpers as shown below.

One automation to set the value ONLY when the light swith is turned off MANUALLY (here is the yaml):

alias: Kitchen Lights Turned Off -> If Done Manually -> Set Last Manual Off Timestamp
description: >-
  If the kitchen lights are turned off (manually),  then make sure the
  "last_manual_off-kitchen" timestamp is updated
trigger:
  - platform: state
    entity_id:
      - light.kitchen_shelly_1_relay_switch
    to: "off"
condition:
  - "{{ trigger.to_state.context.id != none }}"
  - "{{ trigger.to_state.context.parent_id == none }}"
  - "{{ trigger.to_state.context.user_id == none }}"
action:
  - service: input_text.set_value
    data:
      value: "{{ as_timestamp(now()) }}"
    target:
      entity_id: input_text.last_manual_off_kitchen
mode: parallel
max: 1000

The above will set the value of the last time that switch was MANUALLY turned off. Then, any automation that would turn the light on, has the below condition template included in it’s code which returns true only if the difference is more than 5 minutes:

alias: Kitchen Motion Detected (Kitchen Motion Detector)
description: >-
  If the current time is more than 5 minutes after the last time the kitchen
  light switch was (ONLY MANUALLY) turned off, then call the generic script
  to handle turning on the lighting as appropriate.
trigger:
  - type: motion
    platform: device
    device_id: 7781595c0148066943b42d214a022a17
    entity_id: binary_sensor.kitchen_motion_sensor_motion_2
    domain: binary_sensor
condition:
  - condition: template
    value_template: >-
      {{ (as_timestamp(now()) -
      as_timestamp(states('input_text.last_manual_off_kitchen'),0) > 300) }}
action:
  - service: script.motion_detected
    data:
      enablement_input_selector_entity: input_select.kitchen_automation_is
      timer_duration_entity: input_number.kitchen_adjust_lights_timer
      timer_entity: timer.kitchen_lights_timer
mode: parallel
max: 1000

FYI, so that I can avoid code duplication, “script.motion_detected” is called from all over the place in my automations. the three parameters it is always called with are 1. If the automation is enabled (I can enable or disable them in my dashboard), 2. The duration of the timer used (I can also set that on my dashboards with a slider to adjust as needed), and 3. the timer object itself.

(When you read the below with the above paragraph (with the *) in mind, it will make sense)

alias: Motion Detected
sequence:
  - condition: template
    value_template: "{{ is_state(enablement_input_selector_entity,'Enabled') }}"
  - service: timer.start
    data:
      duration: "{{ (states(timer_duration_entity)|int*60) }}"
    target:
      entity_id: "{{ timer_entity }}"
mode: parallel
max: 1000
icon: mdi:run-fast