Connecting Programmed ESP32 to HA - MQTT or ESPHOME

I am and old guy - new to Programming and a first time user of Home Assistant.
I have an ESP32 Dev Kit V1 , and I connected (2) push buttons, (2) Leds and (2) Contactors, to the GPIO pins. My practical application is to control (2) electric valves at my cabin. One to turn on the main water and one to open a main drain to drain all the pipes. I manually control them with a small (2) button control panel with (2) led indicators.
The application is as follows:
At startup:
• Both buttons are open (not pressed)
• Both LED’s are OFF
• Both Contactors are OFF
When I press the Water button – and if the drain valve is Closed, I open the water valve and turn on the water LED
When I press the Water button – and if the water valve is Open and the drain valve is Closed, I close the water valve and turn off the water LED.

Same goes for the Drain Valve.

My code has to make sure that the Water Valve can’t open when the Drain Valve is open or conversely can’t open the open the Drain Valve when the Water Valve is open. For instance (one of my grandkids push the buttons to see the LEDs light up)

There is also a 15 second delay when Drain button is pressed when the Water is on. In that instance, I first close the Water valve, blink the led for 15 seconds, then open the Drain valve and turn on the drain LED.

Same goes for the Water Button press when the Drian valve is Open.

A week of tinkering and I figured out how to get everything working exactly as planed by programming it with Arduino IDE and loading the sketch to the ESP32. The only thing that I can’t figure out is how to control it and monitor it in Home Assistant?

I am looking for advice on how to program and connect more ESP32’s to Home Assistant.
Do I need to re-program my existing code in ESPHOME?
Should I have used ESPHOME to start with?
Should I continue using Arduino sketches and try to figure out how to connect them via MQTT?
I am lost and don’t know the best path to take.

Below is my Arduino Code that works to control the buttons, LEDs and Contactors (valves)

Any help or advice is greatly appreciated!

void setup() {
  // Set GPIO PINS
  pinMode(16, INPUT_PULLUP);   // Water Button GPIO Input Pin
  pinMode(4, INPUT_PULLUP);    // Drain Button GPIO Input Pin
  pinMode(18, OUTPUT);         // Water LED GPIO Output PIN
  pinMode(19, OUTPUT);         // Drain LED GPIO Output Pin
  pinMode(14, OUTPUT);         // Water Valve Contactor Digital Output GPIO Pin
  pinMode(13, OUTPUT);         // Drain Valve Contactor Digital Output GPIO Pin
  Serial.begin(9600);

  // Initialize PIN STATES
  digitalWrite(14, LOW);    // SET Water Valve OFF
  digitalWrite(13, LOW);    // SET Drain Valve OFF
  digitalWrite(18, LOW);    // SET Water LED OFF
  digitalWrite(19, LOW);    // SET Drain LED OFF
}

void loop() {

  // CHECK CONDITIONS FOR WATER VALVE BUTTON PRESS
  // Check if Water Button is Pressed and Water Contactor Valve Contactor is OFF and Drain Valve is OFF
  if (digitalRead(16) == LOW && digitalRead(13) == LOW && digitalRead(14) == LOW) {
    digitalWrite(13, HIGH);  // Turn On Water Valve Contactor
    digitalWrite(18, HIGH);  // Turn On Water LED
    Serial.println("Water Button Pressed, Water Valve was Closed - Opening Water Valve "); //debug line
    delay(500);
  }

  // Check if Water Button is Pressed and Water Contactor Valve Contactor is ON and Drain Valve is OFF
  else if (digitalRead(16) == LOW && digitalRead(13) == HIGH && digitalRead(14) == LOW) {
    digitalWrite(13, LOW); // Turn Off Water Valve Contactor
    digitalWrite(18, LOW); // Turn Off Water LED
    Serial.println("Water Button Pressed, Water Valve was Open - Closing Water Valve"); //debug line
    delay(500);
  }

  // Check if Water Button is Pressed and Water Contactor Valve Contactor is OFF and Drain Valve is ON
  else if (digitalRead(16) == LOW && digitalRead(13) == LOW && digitalRead(14) == HIGH) {
    digitalWrite(14, LOW);  // Turn Off Drain Valve Contactor
    Serial.println("Water Button Pressed, Drain Valve Open - Closing Drain Valve - 30 Second Blink Delay"); //debug line
    // BLINK LEDS
    for (int i = 0; i < 10; i++) {
      digitalWrite(19, !digitalRead(19)); // Toggle Drain LED
      delay(1000); // Wait for 1 second
    }
    digitalWrite(19, LOW); // Turn Off Drain LED
    digitalWrite(13, HIGH); // Turn On Water Valve Contactor
    digitalWrite(18, HIGH); // Turn On Water LED
    Serial.println("Opening Water Valve"); //debug line
    delay(500);
  }

  // CHECK CONDITIONS FOR DRAIN VALVE BUTTON PRESS
  // Check if Drain Button is Pressed and DRAIN Valve Contactor is OFF and Water Valve is OFF

You can do all of this in esphome, which makes interfacing with HA very easy. Other than that there is mqtt. The advantages Native API Component — ESPHome

You may need interlocking

Thank you very much! I just looked over the GPIO Switch Pin that you sent and it looks very easy to set up. I will give it a try. If it works as easy as it looks, I will use ESPHOME for all my esp32 automations. It looks much easier to to set up, and understand than coding it in Arduino code.

The current board is an esp32 correct? You could use mqtt but honestly, i think that would be just as much work, if not more work than it would take to just remake it in esphome.

All you have is a few switches to setup. Using interlocks is simple and will do exactly what you need as far as “switch1 cant turn on if switch2 is on”. The only other thing you need to do is create the logic/automations to tell it any specific instructions like your 15 second delay when drain button is pushed and water is on…

This is some switch logic for one of my projects I made. This is similar logic to what you need to make so I thought i’d share it and hopefully it helps kind of visualize the syntax structure and helps point you in the direction you need to go.

That is the Esphome syntax which I think is easier to look at, read it and it’s easier to figure out whats going on than with Arduino.

on_turn_on:
  then:  
        - if:
            condition:                            
              - switch.is_off: fanspeed                                
            then:
              - switch.turn_on: fanspeed             
              - switch.turn_on: speed1
              - delay: 250ms       
            else:
              - if:              
                  condition:
                    and:
                     - switch.is_on: fanspeed  
                     - switch.is_on: speed1
                  then:              
                     - delay: 100ms
                     - switch.turn_on: speed2            
        - if:
            condition:
              and:
                - switch.is_on: fanspeed
                - switch.is_on: speed2
            then:
                - switch.turn_on: speed3

        - if:
            condition:
              and:
                - switch.is_on: fanspeed  
                - switch.is_on: speed2
            then:             
              - delay: 100ms
              - switch.turn_on: speed3    
        - if:
            condition:
              and:
                - switch.is_on: fanspeed  
                - switch.is_on: speed3
            then:              
              - delay: 100ms
              - switch.turn_on: speed4

        - if:
            condition:
              and:
                - switch.is_on: fanspeed  
                - switch.is_on: speed4
            then:
              - switch.turn_off: speed4
              - switch.turn_off: fanspeed 

This is a lambda/c++ automation that is basically the exact same as above. You basically have the choice to pick your pleasure if you like one way over the other.

on_value:
      then:
        - lambda: |-
            if (id(barn_fan_speed_select).state == "Speed 1") {
              id(speed1).turn_on();
            } else if (id(barn_fan_speed_select).state == "Speed 2") {
              id(speed2).turn_on();
            } else if (id(barn_fan_speed_select).state == "Speed 3") {
              id(speed3).turn_on();
            } else if (id(barn_fan_speed_select).state == "Speed 4") {
              id(speed4).turn_on();
            } else if (id(barn_fan_speed_select).state == "Off") {
              id(speed1).turn_off();
              id(speed2).turn_off();
              id(speed3).turn_off();
              id(speed4).turn_off();
            }

I started IOT things with Arduino code and MQTT, but over the past couple of years I am moving whatever I can into the ESPHome world. ESP32 is a bit of overkill for a few buttons, switches and LEDs; I prefer the Wemos D1 Mini.

I couldnt have said it better myself. I had only been using Arduino for about 2 years. I havnt really used it for probably 2 years since i started using esphome. About a month ago i thought id do an Arduino project just for the hell of it… you ever try to use a fork and eat with your non dominant hand? It was like that, awkward and clumsy. I hardly remember anything after being spoiled with esphome…

1 Like

Hi Justin,
I Finally got most of my valve stuff working in ESP Home and Home Assistant. It sure took some time to figure out as I originally coded it in Arduino and moving to ESPHome is way different. But after a couple weeks of tinkering, I think it is easier to read and program.
I do need some help with the automation piece. As for hardware, I am using:

  • have an esp32 dev kit 1 board,
  • 2 momentary pushbuttons,
  • 2 status LED’s
  • 2 resistors
  • 2 relays.
    I ended up creating 2 additional switches that show up in home assistant that act as my manual pushbuttons. I am controlling a water main valve and main drain valve. So, I first started by grouping the water_led, water_relay and connecting them to the water_button and water_switch and interlocking them with drain_led and drain_relay that is connected to the drain-button and drain_switch.
    So if I press the momentary water button, and the water-led is off and the drain_led is off, it turns the water switch on which turns on the water_LED and water_valve .
    If I press the water-button again and the water-led is on and the drain-led is off, it turns the water switch off which turns off the water_led and the water_valve.
    Same goes when I turn the water switch on the HA dashboard on or off.
    Since I have the Drain and Water interlocked, when I press the Drain button with Water on, it shuts the water off and the Drain on, and versa when the water button is pressed with the Drain on.
    I’m sure there is an easier way to code what I have so far, but it finally works, and that in itself is a great accomplishment for me. What I can’t figure out is how to incorporate the ELSE-IF statement in the code for when I press the water_button I need to check to see if the water_led is off and the drain_led is ON – then I want to turn off the drain_switch. Then blink the water_led for 10 seconds, then turn on the water_switch. and vice versa for pressing the drain-button when the water_led is on.
    I tried using the ELSE-IF in lambda and it passes YAML validation in ESPhome but in fails when compiling for install. I tried setting up an automation in Home Assistant , but I have no idea how to get the automation I created to work on the esp32.
    I’m close, but every time I try to write code to check for that condition it messes everything up.
    Any help would be greatly appreciated.
    Thanks,
    Matt

Attached is my code for reference:
`esphome:
name: myvalve
friendly_name: MyValve

esp32:
board: esp32dev
framework:
type: arduino

Enable logging

logger:

Enable Home Assistant API

api:
encryption:
key: “naEoBKCLxAM1v2WztYkLm60MlEJVg9j+gZcGalYye9Q=”

ota:
password: “9ebf7362ab0b020e13971efcd666175c”

wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password

binary_sensor:

  • platform: gpio
    name: “Water Button”
    id: water_button
    pin:
    number: 17
    mode: INPUT_PULLUP
    filters:

    • delayed_on: 10ms
      on_release:
      then:
      • if:
        condition:
        switch.is_on: water_led
        then:
        - switch.turn_off: water_led
        - switch.turn_off: water_relay
        - switch.turn_off: water_switch
        else:
        - switch.turn_on: water_led
        - switch.turn_on: water_relay
        - switch.turn_on: water_switch
  • platform: gpio
    name: “Drain Button”
    id: drain_button
    pin:
    number: 18
    mode: INPUT_PULLUP
    filters:

    • delayed_on: 10ms
      on_release:
      then:
      • if:
        condition:
        switch.is_on: drain_led
        then:
        - switch.turn_off: drain_led
        - switch.turn_off: drain_relay
        - switch.turn_off: drain_switch
        else:
        - switch.turn_on: drain_led
        - switch.turn_on: drain_relay
        - switch.turn_on: drain_switch

switch:

  • platform: gpio
    name: Water_Switch
    id: water_switch
    pin:
    number: 32
    mode: OUTPUT
    on_turn_on:

    • logger.log: “Water Switch Turned On!”
    • switch.turn_on: water_led
    • switch.turn_on: water_relay
    • switch.turn_on: water_switch
      on_turn_off:
    • logger.log: “Water Switch Turned Off!”
    • switch.turn_off: water_led
    • switch.turn_off: water_relay
    • switch.turn_off: water_switch
  • platform: gpio
    name: Drain_Switch
    id: drain_switch
    pin:
    number: 33
    mode: OUTPUT
    on_turn_on:

    • logger.log: “Drain Switch Turned On!”
    • switch.turn_on: drain_led
    • switch.turn_on: drain_relay
    • switch.turn_on: drain_switch
      on_turn_off:
    • logger.log: “Drain Switch Turned Off!”
    • switch.turn_off: drain_led
    • switch.turn_off: drain_relay
    • switch.turn_off: drain_switch
  • platform: gpio
    name: Water LED
    id: water_led
    pin:
    number: 22
    mode: OUTPUT

  • platform: gpio
    name: Water Relay
    id: water_relay
    pin:
    number: 25
    mode: OUTPUT
    interlock: [drain_switch, drain_led, drain_relay]

  • platform: gpio
    name: Drain LED
    id: drain_led
    pin:
    number: 23
    mode: OUTPUT

  • platform: gpio
    name: Drain Relay
    id: drain_relay
    pin:
    number: 26
    mode: OUTPUT
    interlock: [water_switch, water_led, water_relay]`

Pleasse post your yaml correctly

Three back ticks ```
new line
paste code
new line
three backticks ```

esphome:
  name: myvalve
  friendly_name: MyValve

esp32:
  board: esp32dev
  framework:
    type: arduino

# Enable logging
logger:

# Enable Home Assistant API
api:
  encryption:
    key: "naEoBKCLxAM1v2WztYkLm60MlEJVg9j+gZcGalYye9Q="

ota:
  password: "9ebf7362ab0b020e13971efcd666175c"

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password

binary_sensor:
  - platform: gpio
    name: "Water Button"
    id: water_button
    pin:
      number: 17
      mode: INPUT_PULLUP
    filters:
      - delayed_on: 10ms
    on_release:
      then:
        - if:
            condition:
              switch.is_on: water_led
            then:
              - switch.turn_off: water_led
              - switch.turn_off: water_relay
              - switch.turn_off: water_switch
            else:
              - switch.turn_on: water_led
              - switch.turn_on: water_relay
              - switch.turn_on: water_switch

  - platform: gpio
    name: "Drain Button"
    id: drain_button
    pin:
      number: 18
      mode: INPUT_PULLUP
    filters:
      - delayed_on: 10ms
    on_release:
      then:
        - if:
            condition:
              switch.is_on: drain_led
            then:
              - switch.turn_off: drain_led
              - switch.turn_off: drain_relay
              - switch.turn_off: drain_switch
            else:
              - switch.turn_on: drain_led
              - switch.turn_on: drain_relay
              - switch.turn_on: drain_switch

switch:
  - platform: gpio
    name: Water_Switch
    id: water_switch
    pin:
      number: 32
      mode: OUTPUT
    on_turn_on:
      - logger.log: "Water Switch Turned On!"
      - switch.turn_on: water_led
      - switch.turn_on: water_relay
      - switch.turn_on: water_switch
    on_turn_off:
      - logger.log: "Water Switch Turned Off!"
      - switch.turn_off: water_led
      - switch.turn_off: water_relay
      - switch.turn_off: water_switch  

  - platform: gpio
    name: Drain_Switch
    id: drain_switch
    pin:
      number: 33
      mode: OUTPUT
    on_turn_on:
      - logger.log: "Drain Switch Turned On!"
      - switch.turn_on: drain_led
      - switch.turn_on: drain_relay
      - switch.turn_on: drain_switch
    on_turn_off:
      - logger.log: "Drain Switch Turned Off!"
      - switch.turn_off: drain_led
      - switch.turn_off: drain_relay
      - switch.turn_off: drain_switch 

  - platform: gpio
    name: Water LED
    id: water_led
    pin:
      number: 22
      mode: OUTPUT

  - platform: gpio
    name: Water Relay
    id: water_relay
    pin:
      number: 25
      mode: OUTPUT
    interlock: [drain_switch, drain_led, drain_relay]

  - platform: gpio
    name: Drain LED
    id: drain_led
    pin:
      number: 23
      mode: OUTPUT

  - platform: gpio
    name: Drain Relay
    id: drain_relay
    pin:
      number: 26
      mode: OUTPUT
    interlock: [water_switch, water_led, water_relay]

Yes, please use proper code formatting. It makes it difficult to read and look at code when it’s not formatted right and forget about finding any errors in there.

There was an example of (else-if) in the code i posted above. There was one in lambda and one in yaml. If you get errors and cant work them out, dont give up. Post it here and ask. Thats how you learn and get better.


[quote="Fallingaway24, post:4, topic:685251"]
    - if:
        condition:                            
          - switch.is_off: fanspeed                                
        then:
          - switch.turn_on: fanspeed             
          - switch.turn_on: speed1
          - delay: 250ms       
        else:
          - if:              
              condition:
                and:
                 - switch.is_on: fanspeed  
                 - switch.is_on: speed1
              then:              
                 - delay: 100ms
                 - switch.turn_on: speed2
[/quote]

what you’re trying to do is a little confusing or atleast when it’s all ran together like that but, I took a stab at part of it.

binary_sensor:
 - platform: gpio
   name: “Water Button”
   id: water_button
   pin:
     number: 17
   mode: INPUT_PULLUP
   filters:
   delayed_on: 10ms
   on_release:
   then:
    - if:
        condition:
          and: # both or (all) conditions listed must be true for the condition to pass to the "then" part
            - switch.is_off: water_led
            - switch.is_on: id: drain_led

        then:         
          - switch.turn_off: drain_switch   
          - script.execute: blink_led   
          - script.wait: blink_led # this waits untill blink_led script is finished before executing the next action below   
          - switch.turn_on: water_switch   
      
       
       
# Example configuration entry
script:
  - id: blink_led
    then:
      - repeat:
          count: 20
          then:
            - switch.turn_0n: water_led
            - delay: 500ms
            - switch.turn_off: water_led

Thank you very much for your example. I definitely didn’t know how to script something but that works very nice and is simple to understand. I am still struggling with trying to check for one of the THREE conditions. I figured out how to check and doing something for TWO conditions with if then else. I changed the conditions out (2 of the 3) and can then to work. But when I try to add the third condition everything goes sideways.
In Arduino I could use If - Else-IF or a Case statement and it would only run the matching process. But I can’t figure out how to do that in ESPHome. I have attached the momentary button (sensor) code that I tried. The code compiles and loads up but does not work.

It seems so simple, but trying to code it seems impossible. Thanks again for your help!

binary_sensor:
  - platform: gpio
    name: "Water Button"
    id: water_button
    pin:
      number: 17
      mode: INPUT_PULLUP
    filters:
      - delayed_on: 10ms
    on_release:
      then:
        - if:
            condition:
              and:
                - switch.is_off: water_led
                - switch.is_off: drain_led
            then:
              - switch.turn_on: water_switch
            else:
              - if:
                  condition:
                    and:
                      - switch.is_on: water_led
                      - switch.is_off: drain_led
                  then:
                    - switch.turn_off: water_switch
            else:
              - if:
                  condition:
                    and:
                      - switch.is_off: water_led
                      - switch.is_on: drain_led
                  then:
                    - switch.turn_off: drain_relay
                    - script.execute: blink_water_led
                    - script.wait: blink_water_led
                    - switch.turn_on: water_switch

I figured it out.!!!
Thank you and everyone for helping me with this. I did change the code and did not use the blink script. Everything is working as planned. My next thing to try to figure out is how to change the ICON on the HA dashboard for the switches. Currently all I have on the dashboard is the water_switch and drain_switch (sliders) with the mdi:valve icon. What would be cool is if I could show the mdi.valve-open when the switch is on and then show the mdi.valve-closed when the switch is off.
I’m making progress - and thank all for your help!

Attached is the code that works.

esphome:
  name: myvalve
  friendly_name: MyValve

esp32:
  board: esp32dev
  framework:
    type: arduino

# Enable logging
logger:

# Enable Home Assistant API
api:
  encryption:
    key: "naEoBKCLxAM1v2WztYkLm60MlEJVg9j+gZcGalYye9Q="

ota:
  password: "9ebf7362ab0b020e13971efcd666175c"

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password

binary_sensor:
  - platform: gpio
    name: "Water Button"
    id: water_button
    pin:
      number: 17
      mode: INPUT_PULLUP
    filters:
      - delayed_on: 10ms
    on_release:
      then:
        - if:
            condition:
              switch.is_on: water_led
            then:
              - switch.turn_off: water_switch
            else:
              - switch.turn_on: water_switch

  - platform: gpio
    name: "Drain Button"
    id: drain_button
    pin:
      number: 18
      mode: INPUT_PULLUP
    filters:
      - delayed_on: 10ms
    on_release:
      then:
        - if:
            condition:
              switch.is_on: drain_led
            then:
              - switch.turn_off: drain_switch
            else:
              - switch.turn_on: drain_switch

switch:
  - platform: gpio
    name: Water_Switch
    id: water_switch
    pin:
      number: 32
      mode: OUTPUT
    on_turn_on:
      then:  
        - if:
            condition:                            
              - switch.is_on: drain_led                                
            then:
              - lambda: !lambda |-
                  id(drain_switch).publish_state(false);   
              - switch.turn_off: drain_relay 
              - repeat:
                  count: 10
                  then:
                    - switch.toggle: drain_led
                    - delay: 1s
              - switch.turn_on: water_led
              - switch.turn_on: water_relay
              - lambda: !lambda |-
                  id(water_switch).publish_state(true);  
            else:
              - if:
                  condition:                            
                    - switch.is_off: drain_led   
                  then:
                    - switch.turn_on: water_led
                    - switch.turn_on: water_relay
                    - lambda: !lambda |-
                        id(water_switch).publish_state(true); 
    on_turn_off:
      - switch.turn_off: water_led
      - switch.turn_off: water_relay
      - lambda: !lambda |-
          id(water_switch).publish_state(false);  

  - platform: gpio
    name: Drain_Switch
    id: drain_switch
    pin:
      number: 33
      mode: OUTPUT
    on_turn_on:
      then:  
        - if:
            condition:                            
              - switch.is_on: water_led                                
            then:
              - switch.turn_off: water_relay  
              - lambda: !lambda |-
                  id(water_switch).publish_state(false); 
              - repeat:
                  count: 10
                  then:
                    - switch.toggle: water_led
                    - delay: 1s
 
              - switch.turn_on: drain_led
              - switch.turn_on: drain_relay
              - lambda: !lambda |-
                  id(drain_switch).publish_state(true);   
            else:
              - if:
                  condition:                            
                    - switch.is_off: water_led   
                  then:
                    - switch.turn_on: drain_led
                    - switch.turn_on: drain_relay
                    - lambda: !lambda |-
                        id(drain_switch).publish_state(true);   
    on_turn_off:
      - switch.turn_off: drain_led
      - switch.turn_off: drain_relay
      - lambda: !lambda |-
          id(drain_switch).publish_state(false);  

  - platform: gpio
    name: Water LED
    id: water_led
    pin:
      number: 22
      mode: OUTPUT
    
  - platform: gpio
    name: Water Relay
    id: water_relay
    pin:
      number: 25
      mode: OUTPUT
    interlock: [drain_switch, drain_led, drain_relay]

  - platform: gpio
    name: Drain LED
    id: drain_led
    pin:
      number: 23
      mode: OUTPUT

  - platform: gpio
    name: Drain Relay
    id: drain_relay
    pin:
      number: 26
      mode: OUTPUT
    interlock: [water_switch, water_led, water_relay]