Automation - trigger for state - crazy behaviour (maybe a bug?)

I’ve created simple automation that starts a pump when one of five valves gets open and stops the pump when all valves are closed.

Below is my code:

- alias: Turn on the pump after 5 seconds
  trigger:
    platform: state
    entity_id: switch.podlogowka_salon, switch.podlogowka_sypialnia, switch.podlogowka_dzieciecy, switch.podlogowka_korytarz, switch.podlogowka_lazienka
    to: 'on'
  action:
    - delay: '00:00:05'
    - service: homeassistant.turn_on
      entity_id: switch.podlogowka_pompa
      
- alias: Turn off the pump
  trigger:
    platform: state
    entity_id: switch.podlogowka_salon, switch.podlogowka_sypialnia, switch.podlogowka_dzieciecy, switch.podlogowka_korytarz, switch.podlogowka_lazienka
    to: 'off'
  condition:
    condition: and
    conditions:
      - condition: state
        entity_id: switch.podlogowka_salon
        state: 'off'
      - condition: state
        entity_id: switch.podlogowka_sypialnia
        state: 'off'
      - condition: state
        entity_id: switch.podlogowka_dzieciecy
        state: 'off'
      - condition: state
        entity_id: switch.podlogowka_korytarz
        state: 'off'
      - condition: state
        entity_id: switch.podlogowka_lazienka
        state: 'off'
  action:
    - service: homeassistant.turn_off
      entity_id: switch.podlogowka_pompa

This works fine when everything is slow. When I change the first switch from off to on and wait 5 seconds, the pump switch change state. When I change the same switch to off then the pump switch change to off.

But when I change the first switch off->on->off->on then I don’t get that 5 seconds delay.
Here are gifs showing two behaviors:

correct (slow change):
switch_slow

incorrect (fast change):
switch_fast

I even removed all extra switches and left only two:

- alias: Turn on the pump after 5 seconds
  trigger:
    platform: state
    entity_id: switch.podlogowka_salon 
    to: 'on'
  action:
    - delay: '00:00:05'
    - service: homeassistant.turn_on
      entity_id: switch.podlogowka_pompa
      
- alias: Turn off the pump
  trigger:
    platform: state
    entity_id: switch.podlogowka_salon
    to: 'off'
  condition:
    condition: and
    conditions:
      - condition: state
        entity_id: switch.podlogowka_salon
        state: 'off'
  action:
    - service: homeassistant.turn_off
      entity_id: switch.podlogowka_pompa

I don’t know why this works like that. It looks like HA doesn’t wait the defined time when I trigger the same action two times in a row.

Is this a bug? Or maybe I messed something out?

I had a similar problem, and it looks like there is no “official” expected behavior for what should happen when an automation fires while that same automation is still executing:

according to pnbrucker if an automation fires again (during it’s execution) it will bypass all conditions and move straight to execution (action:)
Could that explain what you are seeing ?

Yes, this is very similar - in my case the delay in action is bypassed.
I want my automation to turn on a switch X seconds after first one was turn on, but if the first switch got turn off during that delay I’d like my automation to cancel (I don’t want the second switch on).

I think this is a serious limitation or even a bug. Automation shouldn’t bypass conditions or delays and there should be an option to cancel current automation - in my case when I turn the first switch off the automation that turns second switch on should cancel.

Typically in this situation you should get your automation to set a bit and then fire a script (the bit prevents the automation triggering again).
If you have an event that interrupts the script just turn off the script and turn off the bit (which would be turned off at the end of the script anyway)

@Mutt suggestion is the way to go I think.

Also check out this thread, which might be helpful.

This can be easily overcome using timers instead of delays. Simply use the switch on to trigger timer.start and switch off to timer.cancel. Then use the timer.finished trigger to start the pump.

@Mutt I’m new to HA and I never used scripts before. Could you share a sample script that is doing such a thing?

I have a slightly different requirement than You described.
I want to cancel the automation that is pending (I use a delay in the actions).
I need to cancel the trigger (action) from another trigger.
Something like this:

- alias: Turn on the pump
  trigger:
    platform: state
    entity_id: switch.podlogowka_salon 
    to: 'on'
  action:
    - delay: '00:00:05'
    - service: homeassistant.turn_on
      entity_id: switch.podlogowka_pompa
      
- alias: Turn off the pump
  trigger:
    platform: state
    entity_id: switch.podlogowka_salon
    to: 'off'
  condition:
    condition: and
    conditions:
      - condition: state
        entity_id: switch.podlogowka_salon
        state: 'off'
  action:
    - service: automation.cancel #this is what I need        
      entity_id: automation.turn_on_the_pump
    - service: homeassistant.turn_off
      entity_id: switch.podlogowka_pompa

I think not only I will find this useful.
Do you think this would be a valid feature request?

In my case the condition is valid (my switch is turn on), but the delay action is skipped.
So this is a bug?

Depends on how you look at it.
It has always been this way, so most people code around it as described previously.
Your coding looks quite clean and tidy so I assume you’ll be able to get my sample in quite easily.
You will need to create an input_boolean I’ll assume it’s called script1_running, but you can just rename it as you like.
I’ll post the code below, though give me 15 mins as I’ll have to write and check it

@Mutt take your time :slightly_smiling_face:
I know that there are workarounds, I was thinking about using timer and counter and start the timer and reset the counter when I change state to on and stop the timer when I change the state to off. THen the logic could be done when the timer hits X seconds.
I don’t know the internals of HA, but I think that having the ability to cancel automation when it is running would be helpful - in many cases it would remove the need to write workarounds.

No, Automations are triggered, and they carry out actions. The Triggers are loaded into the State Machine Memory and are watched for. This is how those actions are triggered on event rather than missing the event if the timing is off on a scan. Cancelling the Automation is like trying to rewrite the memory, you will get leaks which will cause instability.
Instead offload the actions into a script which is easily cancelled.
You will not change the behaviour of automations, give up now.

Below is my code, it is based on your last sample, so extend it from there. It is written in a package so your yaml spacing may require a different offset, but it will give you the idea (it passes config check on my machine). You still have two automations. You have the timer script (actually a delay, there are some issues with timers, so I steer clear of them (relates to retriggering durring running and the status’s not being updated thereafter). I have also given you the input_boolean. Get it working - THEN change the names to your preference.

input_boolean:
  ib_script1_running:
    name: Script1 Running
    initial: 'off'

automation:
  - alias: Turn on the pump
    trigger:
      - platform: state
        entity_id: switch.podlogowka_salon 
        to: 'on'
    condition:
      - condition: state
        entity_id: input_boolean.ib_script1_running
        state: 'off'
    action:
      - service: script.turn_off
        entity_id: script.sc_pump_timer
      - service: script.sc_pump_timer
      
  - alias: Turn off the pump
    trigger:
      - platform: state
        entity_id: switch.podlogowka_salon
        to: 'off'
    action:
      - service: script.turn_off
        entity_id: script.sc_pump_timer
      - service: switch.turn_off
        entity_id: switch.podlogowka_pompa
      - service: input_boolean.turn_off
        entity_id: input_boolean.ib_script1_running

script:
  sc_pump_timer:
    alias: Pump Timer Script
    sequence:
      - service: input_boolean.turn_on
        entity_id: input_boolean.ib_script1_running
      - delay: "00:00:05"
      - service: switch.turn_on
        entity_id: switch.podlogowka_pompa
      - service: input_boolean.turn_off
        entity_id: input_boolean.ib_script1_running
1 Like

@Mutt thank You so much for posting the sample.
I was able to do my custom version (I’ll post it below).

I’m still thinking about automations bypassing conditions and delays when triggered same time (during the delay). I think this shouldn’t happen and it is a bug. The current workaround (using a script) is working, but this is just a workaround.

configuration:

input_boolean:
  turn_on_pump:
    name: Should I turn on the pump
    initial: 'off'

automations:

- alias: Set flag to on
  trigger:
    platform: state
    entity_id: switch.podlogowka_salon, switch.podlogowka_sypialnia
    to: 'on'
  action:
    - service: input_boolean.turn_on
      entity_id: input_boolean.turn_on_pump
     
####
     
- alias: Set flag off
  trigger:
    platform: state
    entity_id: switch.podlogowka_salon, switch.podlogowka_sypialnia
    to: 'off'
  condition:
    condition: and
    conditions:
      - condition: state
        entity_id: switch.podlogowka_salon
        state: 'off'
      - condition: state
        entity_id: switch.podlogowka_sypialnia
        state: 'off'
  action:
    - service: input_boolean.turn_off
      entity_id: input_boolean.turn_on_pump
   
####   
      
- alias: Turn on the pump if any switch is on
  trigger:
    platform: state
    entity_id: switch.podlogowka_salon, switch.podlogowka_sypialnia
    to: 'on'
  condition:
    - condition: state
      entity_id: input_boolean.turn_on_pump
      state: 'off'
  action:
      - service: script.turn_on_the_pump

####
      
- alias: Turn off the pump when all are off
  trigger:
    platform: state
    entity_id: switch.podlogowka_salon, switch.podlogowka_sypialnia
    from: 'on'
    to: 'off'
  condition:
    condition: and
    conditions:
      - condition: state
        entity_id: switch.podlogowka_salon
        state: 'off'
      - condition: state
        entity_id: switch.podlogowka_sypialnia
        state: 'off'
  action:
    - service: script.turn_off
      entity_id: script.turn_on_the_pump
    - service: homeassistant.turn_off
      entity_id: switch.podlogowka_pompa

scripts:

turn_on_the_pump:
    alias: Turn the pump on
    sequence:
      - delay: "00:00:05"
      - service: switch.turn_on
        entity_id: switch.podlogowka_pompa

Logic is like this:

  • when I turn at least 1 switch I start the script
  • the script starts the pump after 5 seconds
  • if I turn on the second switch nothing happens
  • if I turn off all switches my script is turn off and the pump doesn’t start

Unfortunately, I use four automations - two to set the flag and two to start or stop the script.
I was trying to minimize that to only two, but without any luck :worried:
Maybe you could help?

I’m not sure I understand.
You only have 1 pump ? What is it for ?
How many switches are there.? What are they ? Where are they ? Do they all start the pump ? Why is there a 5s delay ?
What happens if two switches are switched 1. Together, 2. Within the 5s 3. 10s apart? You need to be specific

@Mutt sorry for the late reply.
Let me describe a bit more about what devices I have and what I’m trying to do.
I’m trying to build a floor heating control system using 5 valves, 5 DS18B20 sensors, and 1 pump.
I’m using the generic thermostat integration to open/close a relay that controls valve.
Each set (from five) contains, 1 DS18B20, 1 relay, 1 valve.

The logic is very simple - if at least one valve is open then I must turn on the pump. If all valves are closed I must turn off the pump.

In the first version, I didn’t use any delay, so when relay (that controls the valve) was turned on I started the pump right away. But after talking to the guy that mounted the floor heating I decided to add a delay before starting the pump. He said that the valves open really long (about a minute), so I should wait at least 30 seconds before starting the pomp, this way the pump will last longer (it won’t get damaged).

I hope that now you will have a clear image of what I’m trying to do.
The current version works, but I think it is too complex and I would like to simplify it.

So, I assume you can’t see the valves ? Only the outputs to the relays that drive them ?
You just switch the relay wait 30 secs and hope it’s open enough to allow flow ? So these are solenoid valves ??? or ??? do they stay open with the relay energised and close when the relay de-energises ?
The thermostat integration - I assume you have a set point exposed and you manage the setpoint according to zone, time of day and occupancy (or elements of these) ?
does the thermostat expose a boolean ‘heating’ state that we use to drive the relay ?
What is the list of stats and their paired relay output ?
Any 1 valve open for 30 secs and the pump runs, ALL valves closed, pump stops imediately ?
Do we want the pump to stop, wait 5 secs and the last valve to close ?
I write code in packages so that’s how it will be written, you will either need to implement packages or more likely adapt the code to fit in with your current configuration.
Confirm the details above and we can start
Cheers

@Mutt I’m able to see the valves, so the 30 seconds will be adjusted, for now I used 10 seconds for tests.
Yes, the valves open when I energize the relay and close when de-energize.
I use https://www.home-assistant.io/integrations/generic_thermostat/ for thermostats

In configuration.yaml I have defined DS18B20 temperature sensors (using onewire platform) and switches (using rpi_gpio platform)

example thermostat is configured like this:

climate:
  - platform: generic_thermostat
    name: Kitchen
    heater: switch.floor_kitchen
    target_sensor: sensor.temp_kitchen

So for five zones, I have 5 DS18B20 sensors and 6 relays - 5 for valves and 1 for the pump.

Nothing fancy. I’m able to set setpoints using Lovelace, eventually, turn off the thermostat.
Yes, if at least one relay gets energized (valve will start to open) for at least 30 seconds the pump must start, if all relays get de-energized the pump stops immediately.

Currently, I didn’t configure away mode or any scheduler. If I do that in the future if will probably only change setpoints.

Okay,
So the ‘climate.kitchen’ has ‘sensor.temp_kitchen’ for its input and ‘switch.floor_kitchen’ for its heating output
And it will switch the ‘switch.floor_kitchen’ on and off depending on ‘sensor.temp_kitchen’ and there is hysteresis built-in to your climate integration ? (how much ? - just curious, I assume the default (0.3) each way) ?
so what are the names of the other 4 switch.floor_???

Are you okay with the package concept or not ? can you adapt if necessary ?

@Mutt I never used packages (still new to HA and never got a chance to try that out), but the code from your previous post was easy to read and I was able to adopt it easily.
I have all the devices named in Polish, English names are only to facilitate readability on the forum.
So the names are:
-kitchen
-bathroom
-corridor
-bedroom
-kids_room

I didn’t change the default of climate integration, but I know how to adjust them :slight_smile:

Basically, with what we now know.
We can watch for any valve coming on (or going off), (that’s the entity list in the binary_sensor)
this will update the sensor using the template.
If the template evaluates to true, one of the valves is on (2, 3, 4 or all 5 - it doesn’t matter)
the delay_on means it has to wait (30 secs in this case) before outputting the true state (as ‘on’)
If they are all off, then the output drops imediately to ‘off’

We can then use this to drive the pump relay on and off in the same automation
All done in 22 lines of code, I could make it smaller but it would not be as easy to maintain.
(for example you could put all the valves in a group and drive it from there) or put all the logic on one (very long) line.

I’m not able to test this but come back if : - you make, or need, further alterations (helps the next guy)

binary_sensor:
  - platform: template
    sensors:
      bs_pump_enable:
        entity_id: switch.floor_kitchen, switch.floor_bathroom, switch.floor_coridor, switch.floor_bedroom, switch.floor_kids_room
        value_template: >
          {% set vkit = is_state('switch.floor_kitchen', 'on') %}
          {% set vbth = is_state('switch.floor_bathroom', 'on') %}
          {% set vcdr = is_state('switch.floor_coridor', 'on') %}
          {% set vbed = is_state('switch.floor_bedroom', 'on') %}
          {% set vkid = is_state('switch.floor_kids_room', 'on') %}
          {{ vkit or vbth or vcdr or vbed or vkid }}
        delay_on: '00:00:30'
        friendly_name: Pump Enable

automation:
  - alias: Pump Control
    trigger:
      - platform: state
        entity_id: binary_sensor.bs_pump_enable
    action:
      - service_template: switch.turn_{{trigger.to_state.state}}
        entity_id: switch.podlogowka_pompa

Edit : code corrected from feedback :rofl:

2 Likes