Determine how a switch's state was set

I have a Wallmote Quad backed by a NodeRed flow that is invoked when the button is pushed that turns on a Sonoff S31 switch. I’d like to also control that same switch with an Aqara FP2 presence sensor – but I do not want the absence of presence to turn off the switch if it had previously been turned on manually via Wallmote button press. How can I determine if the sonoff’s state (on / off) was set by the Wallmote Quad’s button being pressed?

In a Home Assistant automation or Node Red?

I think I need to know from an automation if the switch was manually turned. If the switch was manually turned on – by pressing a button on the wallmote quad – then I do not want the automation triggered by the presence sensor notifying that “absence” is detected (ie: people have left the room) to be processed.

Would creating a toggle Helper and setting it to “turn_on” in the NodeRed flow triggered by the button press accomplish my goal? I could examine the value state of the toggle in the automation triggered by the FP2’s trigger of absence detected?

An Update: By creating a Helper of type “Toggle,” I now have an input_boolean that I can invoke the “turn_on” and “turn_off” service against in the Node Red flows associated with my Wallmote buttons. I have a lot of experimenting to do to learn more about this use of a Helper object (ie: does the state value persist across HA restarts? etc), but if I’m mis-using a Helper or if there is a better way to achieve what I’m trying to accomplish here, I would very much appreciate any guidance and clarification on the better / right way to do it.

This looks really handy, but… Does trigger.to_state.context persist until the next time the state is changed? I don’t need to know about the state change when it happens; I need to know about it before deciding what to do upon the next state change.

I had the same issue, people turning off a light and then when they move to leave the room the light goes back on due to a motion sensor. After some thought I decided I would just set it up such that only after the switch is turned off MANUALLY then no logic that might turn it on would not be able to turn it on for 5 minutes. This work well enough for our case. I did it several different ways but then settld on this elegant ‘tweaked’ solution:

  1. Originally I had the trigger conditions for how a light was turned off within automations but I needed to use them for additional logic so didn’t want to lose that information. So I have sensors for the “off context” (how it was turned off - only for the last time it was turned off) for many of my lights, in configuration.yaml:
#
# Den Dimmer (for accessing these and with the last_changed value):
# {{ states('sensor.den_dimmer_light_off_context') }}
# {{ states.sensor['sensor.den_dimmer_light_off_context'].last_changed }}
#
template:  
  - trigger:
      - platform: state
        entity_id: light.den_shelly_dimmer_2
    sensor:
      - name: "Den Dimmer Light Off Context"
        state: >
          {% set c_id = trigger.to_state.context.id %}
          {% set c_parent = trigger.to_state.context.parent_id %}
          {% set c_user = trigger.to_state.context.user_id %}
          {% if states('light.den_shelly_dimmer_2') == 'on' %}
            n/a
          {% elif c_id != none and c_parent == none and c_user == none %}
            physical
          {% elif c_id != none and c_parent == none and c_user != none %}
            dashboard_ui
          {% elif c_id != none and c_parent != none and c_user == none %}
            automation
          {% else %}
            unknown
          {% endif %}
        unique_id: den_dimmer_light_off_context

… so if a light is turned off - as long as it stays turned off - you have “physical”, “dashboard_ui”, or “automation” If it is on then it is “N/A”

  1. I created an input_text and a related automation that populated it every time the switch was turned off - from states.sensor[‘sensor.den_dimmer_light_off_context’].last_changed. Now that I think of it, this step might not be needed (and note what I have for step 3 to see why):

  2. So in the logic for the automation fired off whenever motion was detected to (indirectly - that is another story) turn the lights on, I added this condition which only allows them to go back on if they had not been previously turned off manually within the last 5 minutes (300 seconds). Here is an example of that automation in yaml:

alias: Bathroom Motion Detected (if not switched off manually within last 5 minutes)
description: ""
trigger:
  - type: motion
    platform: device
    device_id: aea2f20e0a1b340eada447d293217bb0
    entity_id: binary_sensor.bathroom_motion_sensor_motion
    domain: binary_sensor
condition:
  - condition: template
    value_template: >-
      {{ (float(as_timestamp(now())) -
      float(states('input_text.last_manual_off_bathroom'),0)) > 300 }}
action:
  - service: script.motion_detected
    data:
      enablement_input_selector_entity: input_select.automation_bathroom_is
      timer_duration_entity: input_number.bathroom_adjust_timer
      timer_entity: timer.bathroom_light_timer
mode: parallel
max: 1000

As I am forever tweaking code and I have found these “context” sensors to be very reliable, I may go back and tweak my code to remove step 2 and then use the “last_changed” from #1 instead (unless that information is lost when HA restarts - I think maybe that is why I kept #2 as the input_### sensors sata is saved - not sure I’ve forgotten…?), but you get the idea. Another improvement would be to have an input_number slider on the dashboard to change that 5 minute delay to whatever you want I guess instead of the hard coded 300 seconds…

Thoughts?

(P.S. the item on the bottom passes objects to a script to (re)start the passed timer with a specified (passed) duration and a (passed) input selector (which just has “Enabled” or “Disabled” on the dashboard to specified if that automation is enabled) - to get rid of code I had duplicated all over the place (that script is called by numerous automations)).