ESPHOME create a PulseTime like tasmota

Hello, I change my irrigation system from tasmota to esphome, in tasmota I set the PulseTime, just for safety.
Now with esphome I don’t have this possibility?
already appen the irrigation was on all night, just because I update the HA, and the automation was running! :frowning:
I need to put on the code the security in case of fails in HA, Raspberry or Wifi.

This is the code I have now, but it does not work at 100%, since the delay does not reset if I stop and start again the irrigation cicle!

switch:
  - platform: gpio
    id: pin0
    name: "PCF8574 Pin #0"
    pin:
      pcf8574: pcf8574_hub
      number: 0
      mode: OUTPUT
      inverted: False
    on_turn_on:
    - delay: 10s # or whatever max on time you want
    - switch.turn_off: pin0

Thanks

I’m just about to move from Sonoffs to ESPHome for my irrigation an dI too used PulseTime as a failsafe.
I am planning on having my ESP32 powered from a Sonoff and setting the pulsetime in the Sonoff.

But there should be some solution in the esphome, “this is the way”

Isn’t there anyone who knows how to do it?

I think you are on a right track, what I would do is this:

switch:
  - platform: gpio
    id: pin0
    name: "PCF8574 Pin #0"
    pin:
      pcf8574: pcf8574_hub
      number: 0
      mode: OUTPUT
      inverted: False
    on_turn_on:
      - script.execute: failsafe
    on_turn_off:
      - script.stop: failsafe

script:
  - id: failsafe
    then:
      - delay: 10s
      - switch.turn_off: pin0

This way, when you turn on the switch, it will start the script, this will count down and if the switched is not turned off, it will turn it off. When you manually turn off the switch, it will stop the script, so next time it will start counting again. The way you wrote it, it will actually keep counting down even after you turn off the switch, so if you turn it on again before the time runs out, it will turn it off before it is supposed to.

1 Like

I don’t suppose there is any way to make the delay in the script dynamic is there?
For example, can the script read a value from an input_number in HA? Or could it be achieved using MQTT in some way?

I’m just brain-storming here and I’m almost certain the answer is no but forgive me, I am still learning about ESPHome so I thought I’d check.

Of couse you can do this, just use platform: homeassistant sensor (you have to be using native API)

sensor:
  - platform: homeassistant
    name: "Time delay"
    id: ha_delay
    entity_id: input_number.failsafe_delay #The entity of input_number in HA
    
script:
  - id: failsafe
    then:
      - delay: !lambda |-
          return id(ha_delay).state * 1000; #Assuming the input_number in HA is in seconds, we need to convert it to milliseconds
      - switch.turn_off: pin0

The state (time) of the ha_delay sensor in ESPHome will keep in sync with the value of the input_number in HA automatically, this way you can simply read it’s state in the delay.

I would perhaps add a script to run on the reboot of ESPHome to set an initial (default) value of the sensor in case the ESPHome restarts and the HA instance is not available (i.e. connection lost).

3 Likes

This seems perfect. Thank you!

1 Like

Perfect solution.
I already implement and the results are perfect!

Thanks

@klogg , @canossa no worries, glad I could help :slight_smile:

I have now implemented this and it is perfect and so simple! Thanks again!

But…

I have a couple of questions about this if you don’t mind…

First, wouldn’t the following provide a more robust ‘failsafe’ if ESPHome restarts and HA is unavailable?

  on_boot:
    then:
      - switch.turn_off: relay1
      - switch.turn_off: relay2
      ...
      - switch.turn_off: relay8

If not, and even if so because it would be good to know the answer for the future, how can you set the value of a sensor in ESPHome?

Thanks.

If you just want to turn off the switches on reboot, you don’t have to do it this way.
All you have to do is to set restore_mode on the switch directly:

switch:
  - platform: gpio
    pin: 25
    name: "Some switch"
    restore_mode: ALWAYS_OFF #This will make it be turned off after reboot

The failsafe I was talking about was for more of a situation in case you have some kind of a HW button/switch connected directly to ESP to turn the irrigation on and you forget to turn it off after some time, this is where this manual failsafe delay would be useful. This way you could make the ESP standalone without the need for HA. You can make the sensor publish it’s state using lambda:

id(ha_delay).publish_state(10000); #To set it by default to 10s

But I am not sure if possibly there could be a case when the HA could connect earlier and sync it’s state with the sensor before the on_boot procedure is called, which would then overwrite the setting from the HA to the default value, but I think there should be some periodic sync aswell, this would have to be tested, but most probably it would be ok.

Another way would be to use global variable: more info here

 globals:
   - id: failsafe_delay_int
     type: int
     restore_value: no
     initial_value: '10000'

where you would set the initial_value to the default. Then you would use the on_value trigger on the HA sensor, which would set the globals variable to the current value of the HA sensor, and then use the global variable to read in the delay.
You could even set the restore_value to on and it should use the last value set by the HA even after reboot without HA. (keep it mind that ESP has limited count of overwrites in the flash memory, but in this case if you don’t change the value 1000 times a day, it should be ok :slight_smile: )

This way you sync the value of the HA sensor with the global variable:

sensor:
  - platform: homeassistant
    name: "Time delay"
    id: ha_delay
    entity_id: input_number.failsafe_delay #The entity of input_number in HA
    on_value:
      - globals.set:
          id: failsafe_delay_int
          value: !lambda "return x;"

Then you can read the value of the global variable simply in lambda by just calling id(failsafe_delay_int) in the failsafe script delay.

script:
  - id: failsafe
    then:
      - delay: !lambda "return id(failsafe_delay_int);"
      - switch.turn_off: pin0

This would make sure there is an initial value for the delay, and it will be set to correct HA value when HA connects or on each change of the value. But I think this is too complicated and the first example with publish_state should work aswell.
Anyway if you don’t have any other way to activate the switches then through the HA, this is not needed at all, if you set the restore_mode to ALWAYS_OFF, you won’t be able to turn on the switches anyway in case the HA is down.

1 Like

Fantastic, thank you so much.
I’ve learnt a lot here.

1 Like

@InToSSH Hi, I’d like to use this method too but I have one more need.
I’d like a default failsafe value that will be used if the cycle isn’t started by HA and that can’t be changed by HA.
So if HA starts the cycle, it set its failsafe for each relays. But if I click a button, the cycle should start with the default fixed failsafe (in case I don’t click the button to finish it).
How can I implement it?

Hi, I am not sure I understand what you mean. So you want to have one failsafe, that is configurable via HA and which will be used when the cycle is started by HA, then in case the HA fails it will shut down the cycle after the failsafe time, and then you want to have another failsafe time which is fixed (and not configurable via HA), which will be used when you click a physical button connected to the ESP?

Exactly. Is it possible?

Well, it is a bit more complicated, since using API you are switching on directly the switch from HA, there is no way to know if it was turned on via HA or the button (we just know it is turned on).

So what you would have to do is to create a new global boolean variable to track if the button was pushed. On push of a button you would first set the global variable to True, then turn on the switch, then in the failsafe script you would have a condition on the delay, if the global var is True, it means it is turned on via push button, if it is False, it means it was turned on via HA and set the delays accordingly based on that.

Then you would have to set the global variable back to False in the on_turn_off trigger on the switch, to reset it’s value.

Hi, I’m working on it and I would like your suggestions about my code.

I don’t use global variables neither HA input_number sensors. But I created template sensors in esphome for store failsafe value:

globals:
  - id: default_failsafe
    type: int
    restore_value: no
    initial_value: '600000'  # default failsafe is 10 mins

    # failsafe values in seconds
  - platform: template
    name: "${dev_name}_failsafe_station1"
    id: failsafe_station1
  - platform: template
    name: "${dev_name}_failsafe_station2"
    id: failsafe_station2
  ...

    switches:
      - name: "${dev_name}_station1"
        on_turn_on:
          - script.execute: failsafe1
        on_turn_off:
          - script.stop: failsafe1
          - sensor.template.publish:
              id: failsafe_station1
              state: 0
      - name: "${dev_name}_station2"
        on_turn_on:
          - script.execute: failsafe2
        on_turn_off:
          - script.stop: failsafe2
          - sensor.template.publish:
              id: failsafe_station2
              state: 0
      ...

script:
  - id: failsafe1
    then:
      - delay: !lambda "if (id(failsafe_station1) > 0) return id(failsafe_station1) * 1000; else return id(default_failsafe);"
      - switch.turn_off: "${dev_name}_station1"
  - id: failsafe2
    then:
      - delay: !lambda "if (id(failsafe_station2) > 0) return id(failsafe_station2) * 1000; else return id(default_failsafe);"
      - switch.turn_off: "${dev_name}_station2"
  ...

So HA set the sensor before turn on the station and if don’t turn off it the failsafe does the job.
If the sensor isn’t set when a station starts, the default failsafe stops it after the default value.