FirmwareUpdateModule¶
Surfaces OTA firmware flash progress as live display controls in the frontend. Auto-created on every boot if absent; can be deleted and will be restored on next reboot.
What it does¶
FirmwareUpdateModule does not perform the upload itself — that is handled by two HTTP routes in AppRoutes.cpp:
POST /api/firmware— receives a raw binary from the browser file picker and writes it chunk-by-chunk to the OTA partition without buffering in RAM.POST /api/firmware/url— fetches a firmware binary from a URL and writes it to the OTA partition in the background (ESP32 only; returns 501 on PC).
Both routes write progress into two shared globals (g_otaStatus, g_otaPct). FirmwareUpdateModule.loop() copies those globals into its controls each tick, so the WebSocket state push picks up the change and the frontend updates without polling.
After a successful flash the device reboots automatically (600 ms delay, so the browser receives the final response first).
Controls¶
| Key | Type | Description |
|---|---|---|
update_status |
display |
Status string: idle, flashing, done - rebooting, or error: <reason> |
update_pct |
progress |
Upload progress 0-100% |
Both controls are read-only. They update live via WebSocket during an active flash.
How to flash new firmware¶
From the browser (file upload)¶
- Build the firmware binary for your target (e.g.
uv run deploy/build.py -target esp32dev). The binary is written todeploy/build/esp32dev/.pio/build/esp32dev/firmware.bin. - Open the device in the browser.
- Find the FirmwareUpdate module card. Click the file picker and select
firmware.bin. - Watch
update_statuschange toflashingandupdate_pctcount up to 100%. - The device reboots automatically when done. The browser reconnects once it comes back up.
From a URL (ESP32 only)¶
Send a POST request with the firmware URL:
curl -X POST http://<device-ip>/api/firmware/url \
-H 'Content-Type: application/json' \
-d '{"url":"https://example.com/firmware.bin"}'
The device fetches and flashes in the background and returns HTTP 202 immediately. Monitor progress via the update_status and update_pct controls.
Via the deploy pipeline¶
uv run deploy/flash.py # flashes all devices marked test:true in deploy/devicelist.json
This uses the PlatformIO upload mechanism over USB serial, bypassing the HTTP OTA route entirely.
Platform notes¶
ESP32: URL-based OTA (POST /api/firmware/url) is supported. File upload OTA (POST /api/firmware) is also supported. After a successful flash, the device reboots into the new firmware.
PC: URL-based OTA returns HTTP 501 (not supported). File upload OTA compiles and links but the underlying pal::ota_begin / pal::ota_write / pal::ota_end are no-ops; this is intended for development builds only.
Source¶
- src/modules/system/FirmwareUpdateModule.h
- src/core/OtaState.h
- src/core/AppRoutes.cpp —
POST /api/firmwareandPOST /api/firmware/urlroutes