Get the state of a pin (HIGH or LOW)

Hi. I’m trying to do a basic thing from Arduino that I’m getting some complications here.
As you can see in the picture, I have a tank with a reed switch on a floater to know when the water is on that level so it will activate a water pump x seconds.

Tank|690x452

What I want is something like:
while (pin x is high)
relay stays ON

I’ve tried this code:

switch:
  - platform: gpio!
    pin: GPIO4
    name: "Reley"
    id: pump_reley

binary_sensor:
  - platform: gpio
    name: "Floater"
    pin:
      number: GPIO5
      mode: INPUT_PULLUP
    on_press: ()
      then:
        - switch.turn_on: pump_reley
        - delay: 50s
        - switch.turn_off: pump_reley

There are multiple problems with this logic.
1- If the reed switch is pressed, and stay pressed, the action is not done until I “unpress” it.
2- If the water still above the switch limit and the time (50s) is over, it will not do the action again.

I was trying the while, if, wait until, etc, without success :frowning:
Thank you for any help.

I’m going to assume that you simply have typos when writing this out here. There seems to be an errant ! after gpio and a set of parentheses where there shouldn’t be.

What is the functionality you want to happen? Turn on when pin high and turn off when pin low? It is unclear what your ideal operation is.

It could be as simple as this if you want it to be on when high and off when low.

on_press:
  then:
    - switch.turn_on: pump_reley
on_release:
  then:
    - switch.turn_off: pump_reley

After reading this again, I think you are trying to have the pump run for 50s, then check if the float is still physically high then run again if it is and repeat.

I would use a script that first turns the pump on then has a while loop that runs until the binary sensor is off. Inside the while loop, it pauses for 50s, or whatever you want. After the while loop finishes, it turns the pump off. Then you execute the script in your on_press, but first check if the script is already running first. You don’t want the script to turn on again if it is already running.

Can you share what you did with the while loop?

Thanks for your help.
I have this on Arduino:

  if (digitalRead(reed_switch_floater) == HIGH) {
    digitalWrite(pump_relay, HIGH);   
    while (digitalRead(reed_switch_floater) == HIGH) {
      delay(50000);
    }
    digitalWrite(pump_relay, LOW);         // Turn Off Relay
    Serial.println("OFF");
  }

On ESPHome it should be something like this:

switch:
  - platform: gpio
    pin: GPIO4
    name: "Pump Relay"
    id: pump_relay

binary_sensor:
  - platform: gpio
    name: "Boia WC"
    id: reed_switch_floater
    pin:
      number: GPIO5
      mode: INPUT_PULLUP
    on_press:
      then:
        - switch.turn_on: pump_relay # I cant use recursivity here...
        - delay: 50s
        - while:
              condition:
                binary_sensor.is_on: reed_switch_floater
              then:
              - delay: 50s

        - switch.turn_off: pump_relay

Other than the misaligned delay after the then this looks like it should work. But beware that any sensor bouncing around low and high will call this sequence to restart. This is why I recommended putting this all in a script and check if it is already running before calling it.

I was looking for scripts examples but there are not much thing :frowning:

I was able to do it (not 100%) but it works
The only problem is:
If the thank is already full and the ESP is powered ON, the signal is inverted…
Later I will try something on ON_BOOT that I’ve seen some where.

switch:
  - platform: gpio
    pin: GPIO4
    name: "Rele Bomba"
    id: pump_relay

binary_sensor:
      
  - platform: gpio
    name: "Boia WC"
    id: reed_switch_floater
    pin:
      number: GPIO5
      mode: INPUT_PULLUP
      inverted: True
    # ...
    on_press:
      then:
        - switch.toggle: pump_relay
        - lambda: !lambda |-
            if (id(reed_switch_floater).state) {
              delay(10000);
            } else {
            }
    on_release:
      then:
        - switch.toggle: pump_relay

The code you have posted will shut off as soon as the level sensor is physically low. This makes the delay loop not needed.

Edit: also why did you change to use toggle?

Ok, I made a script but its not working 100%
On PRESS it will turn on the switch and delay the 10 seconds.
The problems:
1- if it is always on, when release the button, the 2nd delay will be the remaining time of the delay and not the 10s
2- If Powered ON with the switch pressed, it will not activate de relay until I release and press again.
:sweat:

switch:
  - platform: gpio
    pin: GPIO4
    name: "Rele Bomba"
    id: pump_relay

binary_sensor:
  - platform: gpio
    name: "Boia WC"
    id: reed_switch_floater
    pin:
      number: GPIO5
      mode: INPUT_PULLUP
      inverted: True
    # ...
    on_press:
      then:
        - switch.turn_on: pump_relay
        - script.execute: floater_delay_script

script:
  - id: floater_delay_script
    then:
      - while:
          condition:
            binary_sensor.is_on: reed_switch_floater
          then:
          - delay: 10s
      - switch.turn_off: pump_relay

For point 1) you can add another delay after the while and before the turn off. An even more elegant approach is to only turn on the relay for on_press and then only turn it off after 10s on_release. No while loop needed. Many methods here, but it comes down to your preference and what works best.

For point 2, use an on_boot automation to turn on the relay if the pin is on

If I add the extra delay like this:

script:
  - id: floater_delay_script
    then:
      - while:
          condition:
            binary_sensor.is_on: reed_switch_floater
          then:
          - delay: 10s
      - delay: 10s #EXTRA DELAY
      - switch.turn_off: pump_relay

It will not work because it will always do the delay after the while. Not what I want.

For point 2
I’ve tried this:

  on_boot:
    priority: 300
    # ...
    then:
      - if:
          condition:
            binary_sensor.is_on: reed_switch_floater
          then:
            - switch.turn_on: pump_relay
            - while:
                condition:
                  binary_sensor.is_on: reed_switch_floater
                then:
                  - delay: 10s
            - switch.turn_off: pump_relay

It will not work 100% for the same reason/problem I have since the beginning.
On Arduino when I make a delay, the code stops until the time is over. Then it will execute the next code.
Here the remaining code stills running and it will complicate this.
For example, if I keep pressing the switch (reed switch) for more than 10s and than release it, depending of the moment I release it, the pump will turn off after 1 to 10s. Not OK.
What I want is to release it and the pump keeps running more 10s.

Thins code is for a toilet sink.
This is what can happen:

  1. The electricity can fail, someone can flush the water and the tank is full. When the electricity gets back, the pump should start and just stop 10s after the level sensor (reed switch) are reached.
  2. When use it normally, when the the level sensor are reached )on) the pump starts. If the water come faster then the pump can push, when the water stops and the level sensor are reached (off), it have to keep running for 10s.

MatthewFlamm, thank you very much for the patience to teach me and trying to show me the way.

If you need control of whether code snippets are running use scripts like I suggested. Although I still think that one option is equivalent to the Arduino code you posted. It may turn off only 1s after going low.

If you want it to always run for 10s after going low, don’t use a while loop and just turn on the pump on_press then delay 10s before turning pump off in on_release. Why doesn’t this work?

    on_press:
      then:
        - switch.turn_on: pump_relay
    on_release:
      then:
        - delay: 10s
        - switch.turn_off: pump_relay

The problem with this code is:
If I press the switch the pump starts.
Then, I release the switch and the time starts.
If I press again the switch, for example, at second 6 and release it again, the time will not start again and will switch off the pump in the next 4s.

If so, you need to use script with the delay and switch turn off. Execute the script if the pin goes low, but first check if it is already running. Maybe you want to cancel any running scripts and restart?

Then turn the script off when the pump turns on. This way the script is running fresh when it goes low.

:slight_smile: Finally it look ok!

   on_boot:
    priority: 300
    # ...
    then:
      - if:
          condition:
            binary_sensor.is_on: reed_switch_floater
          then:
            - switch.turn_on: pump_relay
            - script.execute: floater_delay_script
            - script.wait: floater_delay_script
#...other code then

switch:
  - platform: gpio
    pin: GPIO4
    name: "Rele Bomba"
    id: pump_relay

binary_sensor:
  - platform: gpio
    name: "Boia WC"
    id: reed_switch_floater
    pin:
      number: GPIO5
      mode: INPUT_PULLUP
      inverted: True
    # ...
    on_press:
      then:
        - switch.turn_on: pump_relay
        - script.execute: floater_delay_script
        - script.wait: floater_delay_script
    on_release:
      then:
        - while:
            condition:
              script.is_running: floater_delay_script
            then:
              - delay: 1s
        - switch.turn_off: pump_relay

script:
  - id: floater_delay_script
    then:
      - while:
          condition:
            binary_sensor.is_on: reed_switch_floater
          then:
            - delay: 10s

@MatthewFlamm, thank you very much for showing me the light :wink:

1 Like