Baumann Works logo
Baumann Works Tools, code, and hardware
Baumann Works

ESP32 Device Framework

Mar 2026 ·Active ·source

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


Building and flashing

The project uses PlatformIO.

# Build
pio run -e esp32dev

# Flash firmware
pio run -e esp32dev --target upload

# Upload filesystem image (logo, etc.) — only needed when data/ changes
pio run -e esp32dev --target uploadfs

# Open serial monitor (115 200 baud)
pio device monitor

Note: close the serial monitor before uploading — it holds the serial port exclusively.

Board targets: esp32dev, esp32-s3-devkitc-1, esp32-C3-devkitm-1, esp32-c6-devkitc-1, rpipico2w


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, max 63 characters).
  3. Click Save. The device connects to your network and restarts.

After connecting, the device is reachable at:

Factory reset

Power-cycle (or press EN) rapidly before the 3-second boot window expires. The reset counter accumulates across rapid reboots:

CyclesEffect
5 – 9Clears hostname, auth, and MQTT config; restarts into normal Wi-Fi
10+Clears all of the above plus stored Wi-Fi credentials; restarts into captive portal

Serial output shows the accumulated count:

[BOOT] reset count 3
[BOOT] reset count 4
...
[BOOT] reset count 5, triggering factory reset
[BOOT] factory reset triggered (clearWifi=0)!
[BOOT] factory reset complete, restarting...

Web UI

Browse to the device address to open the configuration page.

Place a logo.png in the data/ directory and upload the filesystem image once. The logo appears in the top-left of the configuration page. The data/logo.png included in this repo is a 200×200 px transparent PNG.

Info panel

Shows the current hostname and IP address.

Hostname

Sets the mDNS name (<hostname>.local). Changing the hostname automatically restarts the device so mDNS re-registers with the new name.

Security

FieldDescription
Require passwordEnables HTTP Basic Auth on the web UI
PasswordPassword for the admin account. Leave blank to keep the existing password

MQTT

FieldDescription
EnableToggle MQTT on/off
BrokerHostname or IP of your MQTT broker
PortDefault 1883
User / PassBroker credentials (leave Pass blank to keep the existing value)
PrefixTopic prefix (default device)

Click Save to persist all settings. Click Reset Device to restart the device immediately.


MQTT / Home Assistant

Connection behaviour

On connect the device publishes online to <prefix>/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:

FunctionPurpose
mqttSubscribe()Subscribe to command topics after connecting
mqttCallback()Handle incoming messages
mqttPublishDiscovery()Publish Home Assistant discovery payloads

HTTP API

MethodPathDescription
GET/HTML configuration page
GET/logo.pngLogo image served from LittleFS
POST/configSave configuration; redirects to /. Restarts if hostname changed
POST/resetRestart the device immediately

Configuration reference

Config is stored as JSON in LittleFS at /config.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().
  6. Place static files (images, etc.) in data/ and upload the filesystem image with pio run --target uploadfs.
← E440-Scale M1730-ESP32 →