Restart a delay if condition/trigger satisfied

Hi,

I have an automation what closes my bedroom blinds whenever the humidity in the bathroom jumps up significantly (i.e. shower) and then waits for 20 minutes, before opening them back to the initial state.

I would like to add a new piece: if during the wait, the humidity goes up at all (i.e. second person is taking a shower) then restart the 20-minute wait. I don’t quite know how to achieve this.

Right now I just have a

delay: 0:20:00

in between the closing and opening of the blind.

I was thinking I could change this for a wait_for_trigger and trigger on the humidity sensor’s state with a timeout of 20 mins, but this would somehow need to be conditioned to only accept increasing triggers. numeric_state triggers need a threshold and mine is related to the previous state, which I do not think is accessible.

Any smart ideas? Some kind of derivative sensor between state changes?

Without seeing the automation you are using its challenging to make suggestions but have you considered acquiring the previous state value via the automation’s trigger variable?

For a State Trigger:

trigger.from_state.state

trigger.to_state.state

Simply make your automation restart mode

mode: restart

But the problem is that I have a more stringent requirement for the initial trigger (large increase in humidity) and a weak one for the second once it’s waiting (any increase). Is there some way to condition on the automation’s being restarted?

Yeah, add an ID to the trigger then choose what to do based on what trigger occurs. You’ll most likely need an input_boolean to flag that the first trigger already triggered. Otherwise you’re going to run into goofyness with the wait_for_trigger that you’re running into.

As far as I understand, this is available only once the trigger has triggered. The problem for me is that this will break the wait statement whenever the state changes, I can the do a test, but in any case the automation will proceed further. I kind of need something like this inside the trigger. Is that possible?

Aha a global variable outside. Ok this makes sense, even though I just keep on polluting my helpers with random stuff like this…

Assign it to a variable. Use the variable in the whatever “wait” template you’re using.

So I have written it as follows, using a helper. This disadvantage is that it triggers every few minutes now, since the conditioning is only occurring after the triggers have fired on every state change. This is maybe not any more resource intensive, but it makes the debugger useless more than 15 mins after a problematic execution. Suggestions for doing it differently welcome. :slight_smile:

- alias: Blinds Bedroom Door Cover during Shower
  id: "40534053475283945620745"
  trigger:
    - platform: state
      entity_id: sensor.xiaomi_shower_humidity
  condition:
    - "{{ (trigger.to_state.state|float) is number and (trigger.from_state.state|float) is number}}"
    - condition: or
      conditions:
        - "{{(trigger.to_state.state) | float > (trigger.from_state.state | float)+8}}"
        - condition: and
          conditions:
            - condition: state
              entity_id: input_boolean.blind_bedroom_shower_privacy
              state: "on"
            - "{{(trigger.to_state.state) | float > (trigger.from_state.state | float)}}"
  action:
    - choose:
        - alias: Blind not down yet, save state
          conditions:
            - condition: state
              entity_id: input_boolean.blind_bedroom_shower_privacy
              state: "off"
          sequence:
            - service: scene.create
              data:
                scene_id: blind_saved_state
                snapshot_entities:
                  - cover.blind_bedroom_right
    - service: input_boolean.turn_on
      target:
        entity_id: input_boolean.blind_bedroom_shower_privacy
    - service: scene.turn_on
      target:
        entity_id: scene.blinds_bedroom_door_covered
    - delay: 0:20:00
    - service: scene.turn_on
      target:
        entity_id: scene.blind_saved_state
    - service: input_boolean.turn_off
      target:
        entity_id: input_boolean.blind_bedroom_shower_privacy
  mode: restart

Have you taken a look at the built in utility sensor platforms? They may be helpful in reducing the number of trigger events you are experiencing, make your conditions easier to define, and/or allow you to stop relying on a delay (which seems like the root of the issue to me).

I think I’ve managed to do it with a derivative sensor – since the humidity sensor reporting is quite irregular and rare, this could have been dangerous, but the default always take only the last state change into account and the sign is all that counts if you want to know if the source sensor is increasing or decreasing.

- platform: derivative
    name: Xiaomi Shower Humidity Diff
    source: sensor.xiaomi_shower_humidity

Then a small repeat-until loop with a couple of wait_for_triggers to test if the humidity begins to go down before coming back up and Bob’s your uncle.

I paste it for posterity as a solution for when you need test if a went through a minimum (maximum) with a potential time out.

- alias: Blinds Bedroom Door Cover during Shower
  id: "40534053475283945620745"
  trigger:
    - platform: numeric_state
      entity_id: sensor.xiaomi_shower_humidity
      above: 60
  condition:
    - "{{ (trigger.to_state.state|float) is number and (trigger.from_state.state|float) is number}}"
    - "{{(trigger.to_state.state) | float > (trigger.from_state.state | float)+8}}"
  action:
    - service: scene.create
      data:
        scene_id: blind_saved_state
        snapshot_entities:
          - cover.blind_bedroom_right
    - service: scene.turn_on
      target:
        entity_id: scene.blinds_bedroom_door_covered
    - alias: Repeat if another shower = humidity down then up
      repeat:
        sequence:
          - alias: wait for humidity to go back down, or time out after 20 mins
            wait_for_trigger:
              - platform: numeric_state
                entity_id: sensor.xiaomi_shower_humidity_diff
                below: 0
            timeout: 0:20:00
          - choose:
              - alias: If it went down, Wait for it to increase again
                conditions: "{{wait.trigger is not none}}"
                sequence:
                  - wait_for_trigger:
                      - platform: numeric_state
                        entity_id: sensor.xiaomi_shower_humidity_diff
                        above: 0
                    timeout: "{{wait.remaining}}"
        until: "{{wait.remaining | float < 5}}"
    - alias: Restore saved blind position
      service: scene.turn_on
      target:
        entity_id: scene.blind_saved_state
  mode: single