| title | Software Guide | ||||||||
|---|---|---|---|---|---|---|---|---|---|
| summary | Software development guide for the Pool Controller — PlatformIO build environment, library dependencies, REST API reference, web interface, and code architecture overview | ||||||||
| date | 2020-05-28 | ||||||||
| lastmod | 2026-07-31 | ||||||||
| draft | false | ||||||||
| toc | true | ||||||||
| type | docs | ||||||||
| featured | true | ||||||||
| tags |
|
||||||||
| menu |
|
- AsyncMqttClient @ 0.9.0
- DallasTemperature
- OneWire
- Adafruit Unified Sensor
- DHT sensor library
- NTPClient @ 3.2.1
- Timezone @ 1.2.6
- ArduinoJson @ 7.3.2
- Bounce2
- Wire
Many thanks to the maintainers of these libraries!
Within the sources at Config.hpp, the GPIO pin assignments are defined. For details,
see also the hardware guide.
constexpr uint8_t PIN_DS_SOLAR = 15; // Pin of Temp-Sensor Solar (GPIO15)
constexpr uint8_t PIN_DS_POOL = 16; // Pin of Temp-Sensor Pool (GPIO16)
constexpr uint8_t PIN_RELAY_POOL = 18; // Pin to control pool pump relay
constexpr uint8_t PIN_RELAY_SOLAR = 19; // Pin to control solar pump relay
constexpr uint8_t TEMP_READ_INTERVAL = 30;The controller includes a built-in web server on port 80 that provides a full management dashboard. It runs in two modes:
| Mode | When | Access |
|---|---|---|
| AP Mode (Access Point) | No WiFi configured (factory state) | SSID Pool-Controller-Setup, IP 192.168.4.1, no password |
| STA Mode (Station) | Normal WiFi connection | DHCP IP of the ESP32 in local network, password login required |
| Route | Auth | Function |
|---|---|---|
GET / |
Cookie | Dashboard SPA (Single Page Application) |
GET /login |
Cookie | Login page |
POST /api/login |
- | Issue session cookie (SHA-256 password check) |
GET /api/status |
❌ No | Live telemetry (temperatures, pump states, heap, RSSI, temperature thresholds) |
GET /api/scan |
Yes | Scan nearby WiFi networks |
GET /api/config |
Yes | Read current configuration |
POST /api/config |
Yes | Save configuration (type=settings|wifi|mqtt|password) |
GET /api/restart |
Yes | Reboot the ESP32 |
GET /api/factory_reset |
Yes | Wipe config file, reboot into AP setup mode |
POST /api/update |
Yes | OTA firmware update (signed .bin upload) |
GET /api/logs |
❌ No | Ring-buffered log entries (since/count/level filters) |
POST /api/logs/clear |
Yes | Clear the log ring buffer |
You can interact with the controller programmatically:
# Get live telemetry (no authentication needed)
curl http://<controller-ip>/api/status
# Get session cookie
SESSION=$(curl -s -c - -X POST -d "password=admin" \
http://<controller-ip>/api/login | grep session | awk '{print $NF}')
# Read configuration
curl -b "session=$SESSION" http://<controller-ip>/api/config
# Write settings (they persist across reboots and notify Home Assistant)
curl -b "session=$SESSION" -X POST \
-d "type=settings&mode=auto&max_pool=30.0&min_solar=55.0&hysteresis=1.0" \
http://<controller-ip>/api/configThe controller keeps a ring buffer of recent log entries and exposes them over REST:
# Read log entries (no authentication needed)
curl "http://<controller-ip>/api/logs?since=0&count=200&level=info"| Parameter | Default | Description |
|---|---|---|
since |
0 |
Only entries with seq greater than this value |
count |
200 |
Maximum number of entries (1–500) |
level |
info |
Minimum log level: debug, info, warning, error, critical |
Response:
{
"next": 43,
"entries": [
{"seq": 42, "t": 123456, "level": "warning", "msg": "SAFE MODE — ignoring relay ON request"}
]
}nextis the next sequence number to pass assincefor incremental pollingtis the entry uptime in millisecondsPOST /api/logs/clear(authenticated) empties the buffer and returns{"ok": true}
- In AP mode the web interface is unprotected (intentional for initial setup)
- In STA mode, a cookie-based session is required (15 minute timeout)
- Default password is
admin - Password is stored as SHA-256 hash in
/config.json - The dashboard always shows live temperatures and threshold values even after
session expiry, because
/api/status(unauthenticated) now includestemp_max_poolandtemp_min_solar. Configuration writes still require a valid session.
Configuration is persisted in two independent storage systems, ensuring all settings survive reboots and power failures:
| File | /config.json |
|---|---|
| Max Size | 4 KB |
| Contents | WiFi, MQTT, NTP, ControllerSettings, admin password hash |
| Management | ConfigManager::load() at boot, ConfigManager::save() on changes |
| Reset | ConfigManager::reset() → factory defaults |
| Namespace | pool-controller |
|---|---|
| Contents | opmode, poolMaxTemp, solarMinTemp, hysteresis, timerStart/End |
| API | StateManager::saveString/Float/Int/Bool → type-safe key-value storage |
Web UI / REST API MQTT (Home Assistant)
│ │
▼ ▼
────────┴────── ConfigManager ───────┴────
save() → /config.json (LittleFS)
↓
OperationModeNode
(runtime parameters)
↓
MqttPublisher::publishStates()
→ MQTT topics → Home Assistant
Note: When settings are changed via the Web UI, Home Assistant is updated on the next measurement cycle (every
loopIntervalseconds, default 10s). Changes made via MQTT are confirmed immediately.
The controller uses Home Assistant MQTT Discovery exclusively since v3.3.0. See the dedicated documentation for details:
- MQTT Configuration — Protocol, entity reference, Homie migration
- Home Assistant Integration — Lovelace dashboard, HA entity IDs
If you need to clear retained MQTT messages:
# Clear a specific Home Assistant topic
mosquitto_pub -h hostname -t "homeassistant/sensor/pool-controller/pool-temp/state" -n -rDiscovery configuration is persisted in two independent storage systems, ensuring all settings survive reboots and power failures:
The controller stores WiFi, MQTT, NTP, and device settings in a JSON file on
LittleFS. See ConfigManager for details.
Operation mode, relay states, and temperature parameters are persisted in NVS for immediate recovery after power loss.
Web UI / REST API MQTT (Home Assistant)
│ │
▼ ▼
────────┴────── ConfigManager ───────┴────
save() → /config.json (LittleFS)
↓
OperationModeNode
(runtime parameters)
↓
MqttPublisher::publishStates()
→ MQTT topics → Home Assistant
Note: When settings are changed via the Web UI, Home Assistant is updated on the next measurement cycle (every
loopIntervalseconds, default 10s). Changes made via MQTT are confirmed immediately.