Project: Pool Control Upgrade

When we bought our house, we were excited that it came with a pool. Several years and several dollars in upkeep later, it’s still pretty nice to have a cool oasis in the summer Georgia heat. Unfortunately, the controller is failing and that cool, crystal clear water can turn into a swamp fast when the filter pump just … stops working.

The Problem

Our pool has an Aqualink controller with a bunch of sweet bells and whistles that don’t work anymore. The local control panel is unresponsive and Aqualink PDA has seen a few too many hot summer days. The LCD screen is blank most days and it eats batteries faster than I can change them. So, what does an engineer with laughably little leisure time do? Dream of building my own controller of course! And maybe I’ll get around to implementing it too.

The Options

  • Upgrade Aqualink: Jandy still makes Aqualink gear and for the price of a janky car I could have the latest and greatest proprietary gear delivered to my door.
    • Pro: Support! Jandy maintains a hotline and the internet has lots of documentation out there. If I get hit by a bus, my wife can call a number and have The Pool Guy take over with minimal learning curve.
    • Pro: Exists! This solution exists and just needs a credit card to order.
    • Pro: OTS Spares! When Murphy (or lightning) strikes, drop-in replacement parts are only a web order away.
    • Pro: Remote Control! Aqualink has their PDA or an app available.
    • Con: Proprietary App! Aqualink’s phone app probably sends analytics (at minimum) to some data center God knows where.
    • Con: Expensive! Expletively expensive even, to my penny pinching standards. In an age where I can talk to my dad, watch a cat video, and compose this post from almost anywhere in the world for less than $200, it seems outrageous that an RF enable handheld with poor range and crappy response time is over $1,000 and that doesn’t include the local controls.
  • Dumb it down: I could rip all this newfangled push-button remote control nonsense out and just use the local breakers and switches. This works, but who wants to fiddle in a panel box with wet hands or traipse across the yard after a cold-weather spa session?
    • Pro: Cheap! Each piece of equipment has a breaker, on/off switch, or selector switch anyway, so this is just using the existing controls.
    • Pro: Simple! It doesn’t get more complicated than on/off.
    • Con: Simple! It CAN’T get more complicated than on/off, which is not ideal for the heater controlling spa temperature.
    • Con: Local Control Only! The pool equipment is on the backside of the pool, across a grass and dirt span, which could be uncomfortable on a cold day after a hot spa or with wet feet making muddy footprints. Also, electric breakers and wet hands seem like a bad time.
  • Go Bespoke: I’ve dabbled with microcontrollers before on much smaller projects and this seems like a perfect way to spend more time and money than necessary to solve a minor inconvenience.
    • Pro: Cheap! While not as cheap as it used to be, eBay has every electronic component Asia has to offer available in quantity for less than the cost of my daily caffeine habit.
    • Pro: Open Source! Thanks to the Internet and the open-source community, almost all of the code or scripting is available for use online for free.
    • Pro: Remote Control! Using free tools, I can set up a simple webpage accessible from my home network that allows anyone with the password to login and control the pool, beit from a phone or laptop. Open source phone apps can tie in as well.
    • Pro: Self-Hosted! All data will go to my own machine on my own network, that way only I see it. [Citation needed]
    • Con: Complicated! I better document the duck out of this, otherwise my wife will be in a pickle if I get hit by a bus.
    • Con: Custom! Hopefully everything works right the first time and nothing bad happens without a spare part on the shelf. Local controls will still work but that defeats the purpose.

Writing all this up, the expensive Aqualink proprietary solution makes a strong argument from a convienience and continuity perspective (please watch for speeding buses). But that’s no fun and (probably) somebody else’s problem1. So let’s Go Bespoke and explore a custom controls system.

The Plan

Initial searches online yield a few stale Github repos using RaspberryPis and a relay hat, which is nice. I have a spare Pi or three in my shop and have tinkered with them enough to be comfortable. I spent several hours fighting insomnia chasing this RPi path before I remembered we live in an age of Literal Logical Magic. 20 minutes on ChatGPT and I have a solid action plan in order that seems as good a starting point as any:

### Step-by-Step Summary for Pool Control System Project

This project aims to replace a faulty Jandy Aqualink PDA with a system that uses an ESP32 microcontroller to control pool equipment via both local physical buttons and a web interface. The system will be installed outdoors, requiring robust protection against the elements.

#### Components and Setup

1. **ESP32 Dev Board:**
   - Recommended: ESP32-WROOM-32 Dev Board.
   - Protection: Use a weatherproof and waterproof enclosure (IP65 or higher).

2. **Enclosure:**
   - Use a durable material like ABS plastic or polycarbonate.
   - Ensure the enclosure has adequate ventilation and includes silica gel packets to control humidity.

3. **Power Supply:**
   - Use a waterproof power supply rated for outdoor use.
   - Consider a battery backup.

4. **Connections:**
   - Use waterproof connectors or seal connections with silicone or epoxy.

5. **Mounting:**
   - Securely mount the enclosure in a location that avoids extreme conditions like direct sunlight or standing water.

#### Simplified and Durable Design

- **Microcontroller:** ESP32 with built-in Wi-Fi for local and web control.
- **Relay Module:** To control pumps, heater, and valves.
- **Push Buttons and LEDs:** For local control and status indication.
- **Software:** Use MicroPython to run a web server and handle button presses.

#### Complete Code with Comments

```python
import machine
import network
import time
import uasyncio as asyncio
from machine import Pin

# Define GPIO pins for relays, buttons, and LEDs
devices = {
    "pump1": {"led": 17, "button": 18, "relay": 27},
    "pump2": {"led": 22, "button": 23, "relay": 10},
    "heater": {"led": 24, "button": 25, "relay": 9},
    "valve1": {"led": 5, "button": 6, "relay": 11},
    "valve2": {"led": 12, "button": 13, "relay": 8},
    "valve3": {"led": 19, "button": 20, "relay": 7},
    "all_stop": {"button": 21}  # Button for All Stop functionality
}

# Set up GPIO pins
for device, pins in devices.items():
    if "led" in pins:
        Pin(pins["led"], Pin.OUT).value(1)  # LED off
    if "button" in pins:
        Pin(pins["button"], Pin.IN, Pin.PULL_UP)
    if "relay" in pins:
        Pin(pins["relay"], Pin.OUT).value(1)  # Relay off

# Connect to Wi-Fi
ssid = 'your_ssid'
password = 'your_password'

def connect_wifi():
    wlan = network.WLAN(network.STA_IF)
    wlan.active(True)
    wlan.connect(ssid, password)
    while not wlan.isconnected():
        pass
    print('Network config:', wlan.ifconfig())

connect_wifi()

# Web server to display status and allow control via web interface
async def web_server():
    import uhttpd
    server = uhttpd.Server()
    @server.route('/')
    async def index(req, resp):
        await resp.start_html()
        await resp.send('<html><body><h1>Pool Control</h1>')
        for i, relay in enumerate(devices.values()):
            if "relay" in relay:
                status = 'ON' if Pin(relay["relay"]).value() == 0 else 'OFF'
                await resp.send(f'<p>Device {i+1}: {status}</p>')
        await resp.send('</body></html>')
    await server.start(port=80)
    print('Web server running')

# Callback function to handle button presses
def button_callback(pin):
    for device, pins in devices.items():
        if "button" in pins and pin == pins["button"]:
            relay = Pin(pins["relay"])
            led = Pin(pins["led"])
            if relay.value() == 1:  # If relay is off
                relay.value(0)  # Turn relay on
                led.value(0)  # Turn LED on
                print(f"{device} is ON")
            else:
                relay.value(1)  # Turn relay off
                led.value(1)  # Turn LED off
                print(f"{device} is OFF")

# Function to stop all devices
def stop_all_devices(pin):
    for device, pins in devices.items():
        if "relay" in pins:
            Pin(pins["relay"]).value(1)  # Turn all relays off
        if "led" in pins:
            Pin(pins["led"]).value(1)  # Turn all LEDs off
    print("All devices are OFF")

# Set up button interrupts
for device, pins in devices.items():
    if "button" in pins and device != "all_stop":
        Pin(pins["button"]).irq(trigger=Pin.IRQ_FALLING, handler=button_callback)
# Set up All Stop button interrupt
Pin(devices["all_stop"]["button"]).irq(trigger=Pin.IRQ_FALLING, handler=stop_all_devices)

# Main loop to run the web server
async def main():
    await web_server()
    while True:
        await asyncio.sleep(1)  # Keep the script running

asyncio.run(main())
```

### Summary

1. **Select an ESP32 dev board and protect it in a weatherproof enclosure.**
2. **Set up GPIO pins for relays, buttons, and LEDs.**
3. **Connect the ESP32 to Wi-Fi.**
4. **Implement a web server to allow web-based control and status monitoring.**
5. **Add button callbacks for local control, including an All Stop button to stop all devices.**
6. **Ensure the system is protected from environmental factors and has a stable power supply.**

By following these steps and using the provided code, you can create a durable and simplified pool control system with both local and web control capabilities.

I am not a Python expert, but I assume some modifications will be needed to the code. Already I can see that I want the local control panel LEDs to read the actual state rather than program state. Or maybe both would be nice.

I’ll update this post as the project progresses. Cheers!

  1. This is generally regarded as poor form and only included in jest. ↩︎

Leave a comment