Gpio from pi to esp (wifi, ethernet and zigbee)

GPIO Access
This guide provides instructions for utilizing various esp32 devices to monitor contact sensors. I’ll have to come back and refine this another day.

Originally I utilized gpio pins on my odroid N2+ to monitor my wired door contract sensors, which I documented here. HA OS doesn’t provide access to the GPIO pins, so I needed an alternative approach. My first approach was to integrate a raspberry pi 4 into the equation, as I also have routing requirements that aren’t an option with HA OS. The thread here gives the full details on the requirements I was trying to address. The GPIO specific implementation are the second post in that thread. While this worked, I didn’t like the extra power it required. The threads I include previously had some good alternative recommendation. As a result this post documents three other alternatives for accessing the contact sensor via ESP boards. Each board provides a different type of interface to HA.

Via ESP with Wired Ethernet
My first shot was utilizing an esp board that included a hardwired Ethernet interface. I selected the WT32-ETH01 ESP32 Development Board.

For this board you need a USB to TTL adapter.

The board has two sets of txd/rxd pins. With the board position as in the picture, the pins that worked for me were the two on the right hand side furthest from the Ethernet socket. You also need 5V and ground, both which are located on the left hand side close to the Ethernet outlet. These 4 pin need to be connected to the USB to TTL adapter.

In order to get this board into flash mode you have to short the IO0 pin, which is right next to the RTD pin you use. You run a wire from IO0 to ground. Thenyou apply power to the board. After power has been applied to the board you remove this wire and the board can be flashed from ESPHome.

I have the ESPHome addon installed on my HA controller. I plugged the board into my windows 11 laptop. I used the ESPhome addon Web Interface and selected the “+ NEW DEVICE” button. If you save the yaml below in a file name gpio-via-eth.yaml, you can then import it create the sensor and flash the code.

esphome:
  name: gpio-via-eth
  friendly_name: gpio-via-eth

esp32:
  #board: esp32dev
  board: esp-wrover-kit

  framework:
    type: esp-idf

# Enable logging
logger:
  level: INFO
#  level: DEBUG

# Enable Home Assistant API
api:
  encryption:
    key: !secret api_key

ota:
  platform: esphome
  password: !secret ota_password

ethernet:
  type: LAN8720
  mdc_pin: GPIO23
  mdio_pin: GPIO18
  clk_mode: GPIO0_IN
  phy_addr: 1
  power_pin: GPIO16

  # Optional manual IP
  manual_ip:
    static_ip: 192.168.10.121
    gateway: 192.168.10.2
    subnet: 255.255.255.0
    dns1: 192.168.10.2

# Enable Web server.
web_server:
  port: 80

binary_sensor:
  - platform: gpio
    pin: 
      number: GPIO2
#      inverted: true
      mode:
        input: true
        pullup: true
    name: "Front Door"
    device_class: door
    
  - platform: gpio
    pin: 
      number: GPIO4
#      inverted: true
      mode:
        input: true
        pullup: true 
    name: "Back Door"
    device_class: door

  - platform: gpio
    pin: 
      number: GPIO12
#      inverted: true
      mode:
        input: true
        pullup: true       
    name: "Basement Door"
    device_class: door

  - platform: gpio
    pin: 
      number: GPIO14
#      inverted: true
      mode:
        input: true
        pullup: true
    name: "Garage Door R"
    device_class: garage_door

  - platform: gpio
    pin: 
      number: GPIO15
#      inverted: true
      mode:
        input: true
        pullup: true
    name: "Garage Door L"
    device_class: garage_door

I have 5 wired contact sensors that I needed to monitor. All the GPIO pins on the board are not appropriate for utilization with the internal pullup resister. I believe pins 35-39 generated an error. The pins I’ve selected worked. I also away use a static IP for my device. If you don’t want fixed IPs just comment out that section from the configuration.

As I previously stated the IO0 wire need to be connected to ground before you apply power to the board. Once power is applied you can remove the IO0 wire and the device is ready to flash.

One side of each contact sensors needs to be connected to the configured GPIO pins and the other side needs to be connected to ground.

With the above configuration you end up with a device named “gpio-via-eth” with 5 entities, 3 house doors and 2 garage doors.

This approach might have been alright if I could get the HA development team to add the routing capabilities I need in my setup. We’ll see that happens, but nothing yet.

Via ESP with WiFi
The next approach was to utilize a WiFi enabled ESP, which is how most of them are enabled. I had multiple sitting around and so I grabbed the Flutesan ESP32 Development board. This one is no longer available, but just about any other ESP32 development board should work. If you have the full size one like this one, it’ll most like expose all the same pins.

On this one the TTL is built in, so I just connected it to my laptop with an appropriate USB cable. I don’t remember doing anything special to get it into flash mode.

This was the configuration for this device:

esphome:
  name: gpio-via-wifi
  friendly_name: gpio-via-wifi

esp32:
  board: esp32dev
  framework:
    type: esp-idf

external_components:
  - source:
      type: git
      url: https://github.com/trombik/esphome-component-ping
      ref: main

# Enable logging
logger:

# Enable Home Assistant API
api:
  encryption:
    key: !secret api_key

ota:
  - platform: esphome
    password: !secret ota_password

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password
  manual_ip:
    static_ip: 192.168.10.202
    gateway: 192.168.10.2
    subnet: 255.255.255.0
    dns1: 192.168.10.2
  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "Gpio-Via-Wifi Fallback Hotspot"
    password: "Usecase2Config"

captive_portal:

# Enable Web server.
web_server:
  port: 80
  
binary_sensor:
  - platform: gpio
    pin: 
      number: GPIO27
#      inverted: true
      mode:
        input: true
        pullup: true
    name: "Front Door"
    device_class: door
    
  - platform: gpio
    pin: 
      number: GPIO26
#      inverted: true
      mode:
        input: true
        pullup: true 
    name: "Back Door"
    device_class: door

  - platform: gpio
    pin: 
      number: GPIO25
#      inverted: true
      mode:
        input: true
        pullup: true       
    name: "Basement Door"
    device_class: door

  - platform: gpio
    pin: 
      number: GPIO33
#      inverted: true
      mode:
        input: true
        pullup: true
    name: "Garage Door R"
    device_class: garage_door

  - platform: gpio
    pin: 
      number: GPIO32
#      inverted: true
      mode:
        input: true
        pullup: true
    name: "Garage Door L"
    device_class: garage_door


sensor:
  - platform: ping
    setup_priority: -100
    update_interval: 30s
    ip_address: 8.8.8.8
    num_attempts: 2
    timeout: 1sec
    loss:
      name: Packet loss
#    latency:
#      name: Latency
#      accuracy_decimals: 3

Once flashed via the USB, subsequent updates can be done over wifi. When you flash and reboot the board, the device will be available to add in HA. The device is gpio-via-wifi, with 5 contact sensors and a ping sensor entities.

This solution requires me to add a wifi router to my battery backed up system. Also not optimal.

Via ESP with zigbee
I already had a lot of zigbee devices in my setup so I figured I give this approach a go. I liked this approach because it doesn’t require any additional hardware, beyond the ESP, being added to my battery backed up components. The device I utilized was the ESP32-C6-DevKitC-1-N8

ESPHome doesn’t currently support zigbee. It turns out that luar123 has done some amazing work, available on github. He currently has a PR in with ESPHome that is making it’s way though the process. Until that PR gets approved and integrated you have to utilize his code as an external component.

This device also has the TTL capabilities built in, so you just need to connect an appropriate USB cable. You have two choices for plugging into this device. While I successfully flashed via both USB sockets, it seemed in some cases the left side would not automatically go into flash mode, while the right side always did.

One thing about this device that you need to know, you can not have both zigbee and WiFi enabled together. I first configured this device like it was just a WiFi adapter and then I moved on to making the zigbee part work. As such I’ve left the WiFi configuration information in the file as comments. Here’s the configuration:

esphome:
  name: gpio-via-zigbee
  friendly_name: gpio-via-zigbee

esp32:
  board: esp32-c6-devkitc-1
  flash_size: 8MB
  partitions: partitions_zb.csv
  framework:
    type: esp-idf
    sdkconfig_options:
      CONFIG_ESPTOOLPY_FLASHSIZE_8MB: y
 
external_components:
  - source: github://luar123/zigbee_esphome
    components: [zigbee]

# Enable logging
logger:

# Enable Home Assistant API
#api:
#  encryption:
#    key: !secret api_key

#ota:
#  - platform: esphome
#    password: !secret ota_password

#wifi:
#  ssid: !secret wifi_ssid
#  password: !secret wifi_password
#  manual_ip:
#    static_ip: 192.168.10.203
#    gateway: 192.168.10.2
#    subnet: 255.255.255.0
#    dns1: 192.168.10.2

# Enable fallback hotspot (captive portal) in case wifi connection fails
#  ap:
#    ssid: "Gpio-Via-Wifi Fallback Hotspot"
#    password: "Use2Config"

#captive_portal:

# Enable Web server.
#web_server:
#  port: 80
  
binary_sensor:
  - platform: gpio
    name: "Front Door"
    device_class: door
    pin: 
      number: GPIO18
#      inverted: true
      mode:
        input: true
        pullup: true
    on_state:
      then:
        - zigbee.report: zb    
    
    
  - platform: gpio
    name: "Back Door"
    device_class: door
    pin: 
      number: GPIO19
#      inverted: true
      mode:
        input: true
        pullup: true 
    on_state:
      then:
        - zigbee.report: zb    

  - platform: gpio
    name: "Basement Door"
    device_class: door
    pin: 
      number: GPIO20
#      inverted: true
      mode:
        input: true
        pullup: true   
    on_state:
      then:
        - zigbee.report: zb

  - platform: gpio
    name: "Garage Door L"
    device_class: garage_door
    pin: 
      number: GPIO21
#      inverted: true
      mode:
        input: true
        pullup: true
    on_state:
      then:
        - zigbee.report: zb    

  - platform: gpio
    name: "Garage Door R"
    device_class: garage_door
    pin: 
      number: GPIO22
#      inverted: true
      mode:
        input: true
        pullup: true
    on_state:
      then:
        - zigbee.report: zb    


zigbee:
  id: "zb"
  components: all  
  on_join:
    then:
      - logger.log: "GPIO zigbee Joined network"

If you start with the wifi part, you will need to comment out the zigbee parts. Once you’ve flashed the zigbee code your only option to update the board or monitor the logs is via USB.

The configuration of this board requires you to include a partiton table for the zigbee code. A table that should work for you is include on github. I’ve include here to keep you from having to look for it.

otadata,  data, ota,     ,        0x2000,
phy_init, data, phy,     ,        0x1000,
app0,     app,  ota_0,   ,        0x1B0000,
app1,     app,  ota_1,   ,        0x1B0000,
nvs,      data, nvs,     ,        0x6D000,
zb_storage, data, fat,   , 16K,
zb_fct,     data, fat,   , 1K,

You have to save this file on you HA controller in the ESPHome directory. You need the Advanced SSH & Web Terminal addon installed on your controller.
You can use it to put this file in place. Once you start the terminal window you get in the right directory

cd config/esphome

Copy the partition records above and then in the terminal do the following

nano partitions_zb.csv

Paste the contents from above, and then enter the ctrl key and x key at the same time. You then enter the Y key followed by the enter/return key to save the file.

With this file in place, the configuration above and the device connected via USB, you should be able to flash the board.

To get the board to join your zigbee network you unplug it after it has been flashed. You go to your zigbee integration on the HA Web interface and use it to add a new device. I use ZHA, but this is code also works with zigbee2MQTT. You then plug the board in and the first thing it does is try to join a zigbee network. The new device will be called esphome gpio-via-zigbee and it will contain the 5 entities for the contact sensor.

Like the other board you connect one side of the contact sensor to the specified GPIO pins and the other size to ground.

With this board I found it to be very useful to have the device connected to my laptop. This way I could connect to the device via USB to see the logs.

When I first got the code running it would only report the events to HA at some time interval. As such I missed a lot of open and closed events. Using the logs, I could see the events happening in real-time. I then figured out that adding the on_state lines under each gpio sensor got the events passed to HA when they happened.

1 Like