Where is my logic wrong here?

For reasons that I can’t yet fathom, when the two binary sensors, drum_wash_low_level_switch and drum_low_level_switch coincide after the first boot, the final ‘then:’ actions don’t occur and on the second coincidence, the actions occur instantly rather than after the ‘for:’ time.

  - platform: gpio
    name: "Drum wash low level switch"
    pin:
      pcf8574: expander_1
      number: 4
      mode: INPUT
      inverted: False
    id: drum_wash_low_level_switch
    on_press:
      then:
        - switch.turn_off: drum_wash_pump
        - if:
            condition:
              and:
                - binary_sensor.is_on: drum_wash_low_level_switch
                - binary_sensor.is_on: drum_low_level_switch
            then:
              - binary_sensor.template.publish:
                  id: drum_empty
                  state: ON
        - if:
            condition:
              for:
                time: !lambda 'return id(drum_fault_detection_time).state * 1000;'
                condition:
                    - binary_sensor.is_on: drum_empty
            then:
              - binary_sensor.template.publish:
                  id: drum_filter_recovery_mode
                  state: ON
              - binary_sensor.template.publish:
                  id: enable_water_fill
                  state: OFF
              - switch.turn_on: water_fill_valve

Any clue what may be causing this?

Having looked at this further and further, I’ve now exhausted my capability!

In the code below I have two commented out blocks containing the desired condition: for:, that I’ve tried as options.

Neither work.

However, the simpler condition does work and the automation completes as expected.

Where am I going wrong with the ‘condition: for:’ element.

Please can somebody confirm that condition: for: actually works, as per the docs?

  - platform: gpio
    name: "Drum wash low level switch"
    pin:
      pcf8574: expander_1
      number: 4
      mode: INPUT
      inverted: False
    id: drum_wash_low_level_switch
    on_press:
      then:
        - switch.turn_off: drum_wash_pump
        - if:
            condition:
              and:
                - binary_sensor.is_on: drum_wash_low_level_switch
                - binary_sensor.is_on: drum_low_level_switch
            then:
              - binary_sensor.template.publish:
                  id: drum_empty
                  state: ON
        # - if:
        #     condition:
        #       for:
        #         time: !lambda 'return id(drum_fault_detection_time).state * 1000;'
        #         condition:
        #             - binary_sensor.is_on: drum_empty

        # - if:
        #     condition:
        #       for:
        #         time: 5s
        #         condition:
        #           - binary_sensor.is_on: drum_empty
        - if:
            condition:
              - binary_sensor.is_on: drum_empty
              
            then:
              - binary_sensor.template.publish:
                  id: drum_filter_recovery_mode
                  state: ON
              - binary_sensor.template.publish:
                  id: enable_water_fill
                  state: OFF
              - switch.turn_on: water_fill_valve

I’m not 100% sure, but each action here might be executing simultaneously. Therefore, the condition on drum_empty could be checked before it is set in the previous one.

Maybe you should nest it inside the previous one and you can get rid of the condition in the second case.

I love esphome, but the indentation becomes a nightmare in these complex cases. It will look cleaner and be easier to keep track of the indents if you break each piece into a script.

Edit:. I meant to also say that I think scripts run everything sequentially, so you could put your entire on_press action and make it a script

Thanks, Matthew. I’ve tried that already with the same result.

Before I split it into scripts, do you have experience of the condition: for: actually working?

I suspect that this isn’t correctly specified based on my reading of the docs. I would try a hard coded time first.~. I misread your second example

Oh wait,. This action probably never fires, although I don’t see the whole logic here. The drum_empty is set on then you immediately ask if it had been on for more than 10s for example. From what I see, this might not be true ever when this runs. This piece is probably better as a time automation that checks every 10s or something like that?

You may well be right there. I’ll investigate further.

Just for info, I use this elsewhere and it works fine. It takes the time from an input_number in HA.