Help requested using interval

I have a Sonoff basic running ESPHome that is used to open and close a water valve for a set amount of time. It is automated in HA and all that works perfectly.

I wanted to build in a failsafe mechanism so that if HA crashes while the valve is open, ‘ESPHome’ on the Sonoff would makes sure the valve closes after a reasonable amount of time. The code below is what I was trying.

For some reason which I can’t work out, it doesn’t always work as expected. I’m not expecting anyone to actually write me a working solution (but go ahead if you like!) but is there something in this that I have missed or do you agree that it should work and I must have missed something elsewhere?

(Full disclosure, I did get some, ahem, artificially intelligent help with this)

Briefly (as I understand it)

  1. The failsafe_time sensor retrieves its value from the HA entity input_number.failsafe_time_in_seconds).
  2. The interval runs every 10 seconds
  3. The Failsafe Logic is:
    When the relay is ON:
    A static variable start_time is used to track when it was turned on.
    If start_time is 0, it is initialized to the current time using millis().
    The elapsed time (millis() - start_time) is compared to the failsafe time.state * 1000.
    If the elapsed time exceeds the failsafe time, the relay is turned off, and the timer is reset.
    When the relay is OFF:
    The timer is reset to 0 to ensure it starts fresh the next time it is turned on.
#============
#=== Sensors
#============
sensor:
  #=== Failsafe time
  - platform: homeassistant
    id: failsafe_time
    entity_id: input_number.failsafe_time_in_seconds

#=============
#=== Switches
#=============
switch:
  #=== Switch
  - platform: gpio
    name: ${friendly_name}
    pin: GPIO12
    id: relay

#=============
#=== Interval
#=============
interval:
  - interval: 10s
    then:
      - if:
          condition:
            switch.is_on: relay
          then:
            - lambda: |
                static unsigned long start_time = 0;
                if (start_time == 0) {
                  start_time = millis();
                }
                if (millis() - start_time > id(failsafe_time).state * 1000) {
                  id(relay).turn_off();
                  start_time = 0;
                }
          else:
            - lambda: |
                static unsigned long start_time = 0;
                start_time = 0;


and this is the problem. It will not tell you it doesn’t know how to do something. It will just make something up that sounds plausible.

I was pretty sure the code wasn’t going to do what you/it thought it would. This post shows the issue: Global variables within lambdas?

start_time is a different variable in the two different contexts, so the second one does nothing.

I suspect your relay is turning off when you expect it to stay on, but you didn’t specify HOW the code was not working.

1 Like

might give you a path to success

1 Like

Thanks for the reply and,

…yes I am more than aware that AI is a risky strategy but writing lambdas for ESPHome is not my strong suit so I thought I would use it to get a start but I am under no illusions as to it’s ability to actually get things right.

Thanks for the links, I’ll look into them and probably find them more useful.

This pointer alone was worth asking the question for. Thanks again.

And yes it was turning off when I expected it to stay on.


As a side note this was the end of my ‘conversation’

Just in case any one is interested (I see there have been 27 views of this post) I solved this with the following simple code:

switch:
  #=== Switch
  - platform: gpio
    name: ${friendly_name}
    pin: GPIO12
    id: relay
    on_turn_on:
      then:
        - delay: !lambda 'return (id(failsafe_time).state * 1000);'
        - switch.turn_off: relay

Many thanks again to Neel for the push in the right direction.

1 Like