# ESP32 Device Framework A reusable ESP32 firmware base with Wi-Fi, web configuration UI, authentication, MQTT / Home Assistant integration, and factory reset. Add device-specific logic on top without re-implementing the boilerplate. ## Table of contents - [Features](#features) - [Building and flashing](#building-and-flashing) - [First-time Wi-Fi setup](#first-time-wi-fi-setup) - [Web UI](#web-ui) - [MQTT / Home Assistant](#mqtt--home-assistant) - [HTTP API](#http-api) - [Configuration reference](#configuration-reference) - [Extending the framework](#extending-the-framework) --- ## Features - **Wi-Fi** via WiFiManager — captive-portal setup on first boot, credentials stored in flash - **mDNS** — device reachable as `.local` - **Web UI** — responsive configuration page served from the device - **Authentication** — optional HTTP Basic Auth to protect the web UI - **MQTT** — connects to any broker, publishes an availability topic, reconnects automatically without blocking the web server - **Home Assistant discovery** — stub ready for your entities - **Factory reset** — rapid 5× power-cycle clears all settings and restarts - **Config persistence** — all settings stored as JSON in LittleFS (`/config.json`) --- ## Building and flashing The project uses [PlatformIO](https://platformio.org/). ```bash # Build pio run # Flash pio run --target upload # Open serial monitor (115200 baud) pio device monitor ``` Board target: `esp32-s3-devkitc-1` --- ## First-time Wi-Fi setup On first boot (or when stored Wi-Fi credentials are missing), the device starts an access point named **ESP32-Device**. Connect to it with any phone or laptop — a captive portal will appear automatically. 1. Enter your Wi-Fi SSID and password. 2. Optionally change the **Device hostname** (default: `esp32-device`). 3. Click **Save**. The device connects to your network and restarts. After connecting, the device is reachable at: - `http://.local` (default `http://esp32-device.local`) — mDNS, works on most local networks - `http://` — shown in the serial monitor on boot ### Factory reset If you lose the web UI password or need to clear all settings, **reset the device 5 times in quick succession** (press EN or cycle power 5× within a few seconds, before boot completes). All settings are wiped and the device restarts into the Wi-Fi captive portal. Serial output shows the progress: ``` [BOOT] reset count 1/5 [BOOT] reset count 2/5 ... [BOOT] reset count 5/5, triggering factory reset [BOOT] factory reset triggered! [BOOT] factory reset complete, restarting... ``` --- ## Web UI Browse to the device address to open the configuration page. ### Info panel Shows the current hostname and IP address. ### Hostname Sets the mDNS name (`.local`) and the MQTT client ID. Saved across reboots. ### Security | Field | Description | |-------|-------------| | Require password | Enables HTTP Basic Auth on the web UI | | Password | Password for the `admin` account. Leave blank to keep the existing password | ### MQTT | Field | Description | |-------|-------------| | Enable | Toggle MQTT on/off | | Broker | Hostname or IP of your MQTT broker | | Port | Default `1883` | | User / Pass | Broker credentials (leave Pass blank to keep the existing value) | | Prefix | Topic prefix (default `device`) | Click **Save** to persist all settings. --- ## MQTT / Home Assistant ### Connection behaviour On connect the device publishes `online` to `/status` (retained) and sets `offline` as the LWT. If the broker is unreachable, the firmware probes the TCP port before attempting a full MQTT connect and retries every 30 seconds without blocking the web server. ### Extending with discovery and topics Three stubs in `main.cpp` are the intended extension points: | Function | Purpose | |----------|---------| | `mqttSubscribe()` | Subscribe to command topics after connecting | | `mqttCallback()` | Handle incoming messages | | `mqttPublishDiscovery()` | Publish Home Assistant discovery payloads | --- ## HTTP API ### `GET /` Returns the HTML configuration page. ### `POST /config` Saves all configuration submitted by the HTML form. Redirects back to `/`. --- ## Configuration reference Config is stored as JSON in LittleFS at `/config.json`. ```json { "hostname": "esp32-device", "mqtt": { "en": true, "host": "192.168.1.10", "port": 1883, "user": "ha", "pass": "secret", "prefix": "device" }, "auth": { "en": true, "pass": "secret" } } ``` The file is written by the web UI. To erase everything including flash, use `pio run --target erase`. --- ## Extending the framework 1. Add your hardware setup in `setup()` after the framework initialises. 2. Add your per-loop logic in `loop()` alongside `server.handleClient()` and `mqttLoop()`. 3. Fill in the three MQTT stubs to subscribe, receive, and publish discovery payloads. 4. Add extra web routes with `server.on(...)` in `startServer()` if you need device-specific endpoints. 5. Persist extra config fields by adding keys to `loadConfig()` and `saveConfig()`.