OPNpool meets ESPHome (Pentair SunTouch controller into Home Assistant)

This is a port of my original OPNpool to the ESPHome platform.

OPNpool meets ESPHome brings advanced pool automation to your smart home. By bridging legacy pool controllers with modern IoT platforms, OPNpool enables real-time monitoring, remote control, and seamless integration with Home Assistant. Whether you want to automate your pool pump based on temperature, monitor chlorinator status, or simply enjoy the convenience of remote access, OPNpool provides a robust and extensible platform for pool management.

How it works

At its core, OPNpool connects an ESP32 microcontroller to your pool controller’s RS-485 bus. The ESP32 runs ESPHome firmware, which translates pool equipment data into Home Assistant entities. This allows you to view and control your pool’s thermostats, pumps, circuits, and chlorinator directly from your smart home dashboard.

Features

  • Smart Home Integration: Native support for Home Assistant and ESPHome.
  • Remote Monitoring & Control: Access your pool’s status and controls from anywhere.
  • Community Driven: Built on the work of pool automation enthusiasts and reverse engineers.
  • Open Source: Fully transparent hardware and software—customize and extend as needed.

Getting started

The documentation below will guide you through hardware assembly, wiring, firmware installation, and Home Assistant integration. If you have questions or need help, join this discussion for community support.

This device was tested with the Pentair SunTouch controller with firmware 2.080, connected to an IntelliFlo pump and IntelliChlor salt water chlorinator.

This open source and hardware project is intended to comply with the October 2016 exemption to the Digital Millennium Copyright Act allowing “good-faith” testing," in a controlled environment designed to avoid any harm to individuals or to the public.

Acknowledgements

We proudly acknowledge the work of reverse engineering pioneers Joshua Bloch, Michael Russe, and George Saw. (Drop me a line if if I forgot you.)

Usage

Start with installing the ESPHome environment on a beefy computer. In my case, this cut the compilation time to a minute, compared to half an hour when running it as an addon to Home Assistant.

In an empty directory, create a opnpool-1.yaml configuration file as shown below.

substitutions:
  device_name: opnpool-1
  friendly_name: "OPNpool meets ESPHome"
  description: "External component, see https://github.com/cvonk/OPNpool_meets_ESPHome"

esphome:
  name: ${device_name}
  comment: ${description}
  friendly_name: ${friendly_name}

esp32:
  variant: esp32c6          # or esp32     for <= r3 boards
  board: esp32-c6-devkitc-1 # or lolin_d32 for <= r3 boards
  framework:
    type: esp-idf

wifi:
  domain: !secret domain_name # only needed if not on the same subnet
  min_auth_mode: WPA2
  reboot_timeout: 0s
  networks:
  - ssid: !secret wifi_ssid
    password: !secret wifi_password

api:

ota:
  - platform: esphome
    password: !secret ota_password

external_components:
  - source: github://cvonk/OPNpool_meets_ESPHome
    components: [ opnpool ]

logger:
  level: VERBOSE          # build includes ESP_LOGx up to VERBOSE
  initial_level: WARN     # only show up to WARN globally
  logs:
    poolstate_rx: VERBOSE # show decoded messages

opnpool:
  id: opnpool_1
  RS-485:
    tx_pin:  21  # or 26 for <= r3 boards 
    rx_pin:  22  # or 25 for <= r3 boards
    rts_pin: 23  # or 27 for <= r3 boards

Specify your own secrets in secrets.yaml

wifi_ssid: "REDACTED"
wifi_password: "REDACTED"
domain_name: ".iot.example.com" # appended to base fname to create FQDN for OTA updates
ota_password: "REDACTED"
api_encryption_key: "REDACTED"

Compile and upload the code using

esphome run opnpool-1.yaml

The first time, you need to upload over USB Serial, but after that you can use over-the-air updates.

In the output, you should see something like:

[16:26:54.983]I (423) boot: Loaded app from partition at offset 0x10000
[16:26:55.024]I (465) boot: Set actual ota_seq=1 in otadata[0]
[16:26:55.029]I (465) boot: Disabling RNG early entropy source...
[16:26:55.268][W][component:333]: api set Warning flag: unspecified
[16:26:55.273][W][component:342]: wifi set Warning flag: scanning for networks
[16:27:01.293][W][component:373]: wifi cleared Warning flag
[16:27:25.143][E][RS-485:108][pool_req_task]: tx_q full
[16:27:55.144][E][RS-485:108][pool_req_task]: tx_q full

In the above trace, the tx_q full indicates that it can’t transmit to the pool controller.

If you haven’t already, add the ESPHome integration to Home Assistant.

Open your Home Assistant instance and start setting up a new integration.

Under Integrations, you will find now notice that Home Assistant auto discovered your new device.

Open your Home Assistant instance and show your integrations.

Add it, and specify your API key. Name the device and assign it an area. You should then see the entities although their values are unknown. Time to populate those entities by connecting it to the pool controller :wink:

Connect

At the core this project is an ESP32 module and a 3.3 Volt RS-485 adapter. You can breadboard this using:

  • Any ESP32 module that has an USB connector and three GPIO pins available.
  • Any “Max485 Module TTL”. To make it 3.3 Volt compliant, change the chip to a MAX3485CSA+. While you’re at it, you may as well remove the 10 kΩ pullup resistors (typically labeled R1 to R4).
  • A piece of Cat5 ethernet cable to connect to the pool controller.

If you prefer to make this a more permanent solution, I suggest rolling a printed circuit board and housing it in a IP68 waterproof case with IP68 connectors. More about this later.

:warning: THIS PROJECT IS OFFERED AS IS. IF YOU USE IT YOU ASSUME ALL RISKS. NO WARRANTIES. At the very least, turn off the power while you work on your pool equipment. Be careful, THERE IS ALWAYS A RISK OF BREAKING YOUR POOL EQUIPMENT.

Understanding the above warning … the RS-485 header can be found on the back of the control board. There are probably already wires connected that go to the devices such as pump and chlorinator.

To minimize electromagnetic interference, use a twisted pairs from e.g. CAT-5 cable to connect the A/B pair to the RS-485 adapter as shown in the table below.

Controller RS-485 adapter idle state
-DATA (green) A negative
+DATA (yellow) B positive

Connect the RS-485 adapter to the ESP32 module. I also pulled GPIO#27 down with a 10 kΩ resistor, to keep it from transmitting while the ESP32 is booting.

RS-485 adapter ESP32 module
RO GPIO#25
DI GPIO#26
DE and RE GPIO#27
GND GND

The serial monitor will start to show decoded messages such as:

{CTRL_VERSION_REQ: {}}
{CTRL_VERSION_RESP: {"firmware":"2.80"}}
{CTRL_TIME_REQ: {}}
{CTRL_TIME_RESP: {"tod":{"time":"18:51","date":"2026-01-18"}}}
{CTRL_HEAT_REQ: {}}
{CTRL_HEAT_RESP: {"thermos":{"POOL":{"temp":54,"sp":63,"src":"NONE"},"SPA":{"temp":54,"sp"}

:bulb: If you don’t see such messages, make sure you didn’t swap the data leads, or oddly enough some people report that they do need to swap the data leads. To debug the datalink framing, set the datalink_rx logger level to VERBOSE and build and upload the code again. See further below.

In Home Assistant the entities should populate, and show on your favorite Lovelace UI.

PCB

For a robust and weatherproof installation, we recommend building a custom printed circuit board (PCB) to house the ESP32-C6 module, RS-485 adapter, and DC/DC converter. This approach ensures reliable connections, easier mounting, and long-term durability—especially for outdoor or poolside environments.

Note that the photo above is from a rev 1 board.

Schematic

The hardware design features a buck converter that supplies 5V to the 5V0 pin on the ESP32-C6 DevKitC-1-N8 daughterboard. The scotty diode prevent issues when the board is also powered via USB.

The main data path runs between the RS-485 connector and the ESP32-C6 on the DevKitC-1-N8. An optional termination resistor is included to minimize signal reflections on the RS-485 bus.

Board Layout

The entire schematic fits comfortably on a compact two-layer PCB. The board was designed using the free version of Autodesk EAGLE, and all source files — including layout and schematics — are available in the hardware directory of this repository.

Bill of materials

Name Description Suggested mfr/part# Price paid
PBC r4 Printed circuit board OSHPark $9.43
Enclosure 158x90x60mm ABS Plastic Junction Box, IP65 white label $9.81
RS-485_CONN 5P Plug+socket, 5-pin, 16mm aviation, IP68 SP16 5P $3.98
RS-485-TERM Fixed terminal block, 4-pin, screwless, 5 mm pitch Phoenix-Contact 1862437 $2.02
ESP32-C6 DevKitC-1-N8 ESP32-C6 dev board with 8MB flash, based on ESP32-C6-WROOM ESP32-C6 DevKitC-1-N8 $9.00
MAX3485 Maxim MAX3485CSA, RS-485/UART interface IC 3.3V, 8-SOIC Analog-Devices MAX3485CSA+T $5.64
DC1 DC/DC Converter R-78E5.0-0.5, 7-28V to 5V, 0.5A, 3-SIP RECOM-Power R-78E5.0-0.5 $3.30
D1, D2 Schottky Diode, 1N5818, 30V, 1A, DO-41 Diodes Incorporated 1N5818-T $0.30
LED1 LED, Green Clear 571nm, 1206 Lite-On LTST-C150KGKT $0.15
LED2 LED, Amber Clear 602nm, 1206 Lite-On LTST-C150AKT $0.15
C1, C2 Capacitor, 10 µF, 25 V, multi-layer ceramic, 0805 KEMET C0805C106K3PACTU $0.22
C3 Capacitor, 0.1 µF, 6.3 V, multi-layer ceramic, 0805 KEMET C0805C104M3RACTU $0.12
R1, R2 Resistor, 68 Ω, 1/8 W, 0805 YAGEO RC0805FR-0768RL $0.20
R3 Not stuffed, resistor, 120 Ω, 1/4 W, 0805 KAO SG73S2ATTD121J $0.00
PCB Screws Machine screw, #6-32 x x 3/16", panhead Keystone-Electronics 9306 $0.10
CONN Screws Machine screw, M2-0.4 x 16 mm, cheese head Essentra 50M020040D016 $0.28
CONN Nuts Hex nut, M2-0.4, nylon Essentra 04M020040HN $0.15

Note that tariffs and shipping will add to the cost.

Troubleshooting

Not all controller firmwares are created equally. If you are not using firmware version 2.080, you will need dive down to the byte level and to tweak the network layer. If you succeed, please send me an pull request, and I will iinclude it in the next release.

To show more (or less) debug information, specify the levels in opnpoool-1.yaml

logger:
  level: VERBOSE       # build includes ESP_LOGx up to VERBOSE
  initial_level: WARN  # only show up to WARN globally
  logs:
    rs485: WARN
    datalink_rx: WARN
    datalink_tx: WARN
    network_rx: WARN
    network_create: WARN
    pool_task: WARN
    ipc: WARN
    poolstate: WARN
    poolstate_rx: VERBOSE
    opnpool: WARN
    opnpool_climate: WARN
    opnpool_switch: WARN
    opnpool_sensor: WARN
    opnpool_binary_sensor: WARN
    opnpool_text_sensor: WARN
    enum_helpers: WARN

For the logger component, it is recommended to use the following levels: WARN, which shows only warnings and errors; INFO, which includes informational messages such as configuration details, warnings, and errors; and VERBOSE, which provides very detailed logs, info, warnings, and errors. Be careful not to enable too much logging, as excessive output can negatively impact the connection between Home Assistant and the ESP32-C6.

2 Likes