PVE-FANCTRL CAPTIVE PORTAL
First-boot WiFi setup + theme picker — no credentials in source
CAPTIVE PORTAL FEATURES
SETUP WORKFLOW
(no saved creds)
to "PVE-FANCTRL-Setup"
at 192.168.4.1
+ pick theme
→ reboot & join
// TFT in setup mode shows:
11 BUILT-IN THEMES
Lifted from CyberNetView's theme system plus a custom default and a Matrix theme with falling kanji rain. Pick during setup, or change live from the web UI later.
RUNTIME THEME SWITCHING
No need to re-enter the portal to change theme. After WiFi is configured, the regular
web UI at http://<hostname>.local/ has a DISPLAY THEME dropdown at the bottom.
- Pick a different theme → POSTs to the ESP32 → saved to NVS → LVGL widgets restyle live, no reboot.
- Selection persists across reboots.
- Same dropdown also works as a CLI:
curl -X POST "http://PVE-FANCTRL.local/api/theme?name=matrix"
JSON API
| METHOD | ENDPOINT | RETURNS / DOES |
|---|---|---|
| GET | /api/status |
{"pct":50,"rpm":1450} |
| POST | /api/set?pct=N |
Set fan PWM 0–100. Returns {"ok":true,"pct":N,"rpm":...} |
| GET | /api/theme |
{"current":"...","themes":[{"id":"...","label":"..."},...]} |
| POST | /api/theme?name=<id> |
Switch theme live. Returns {"ok":true,"current":"<id>"} |
FACTORY RESET (re-launch portal)
- Power off the ESP32 (unplug USB-C).
- Press and hold the BOOT button on the dev board.
- Plug USB-C back in while still holding BOOT.
- Keep holding for at least 5 seconds.
- Release. Serial log prints
[portal] wifi credentials wiped. - Captive portal launches on the next boot — repeat the setup workflow.
The 5-second hold prevents accidental wipes from a momentary BOOT press during normal operation.
PORTAL HTML — SERVED BY THE ESP32
The portal page is rendered dynamically by renderPortalHtml() in the sketch — the theme dropdown is built from the in-memory themes[] array, with the currently-saved theme pre-selected. So adding a new theme to the array automatically adds it to the portal dropdown without HTML edits.
- Form posts to
/savewithssid,pass,theme - Handler saves both to separate NVS namespaces (
wifiandui) - Sends a "SAVED — rebooting" page, then calls
ESP.restart()after 1.5s - Captive-portal redirect via
DNSServersends every other lookup to192.168.4.1