Updating the buried ESP-01S currently means a USB-UART adapter and a
GPIO0 jumper. Add a path to change its settings without reflashing, and
lay the groundwork for full firmware updates over the existing UART.
set_config (no reflash for settings):
- ESP-01S: add saveConfig() + a set_config command — updates GoPro
SSID/password/IP and poll interval, persists to LittleFS, acks, and
re-associates Wi-Fi if creds changed
- XIAO: forward an MQTT set_camera_config down to the ESP-01S over UART
(hub -> MQTT -> XIAO -> UART -> ESP-01S/LittleFS)
UART-OTA groundwork ("XIAO as flasher"):
- reserve XIAO GPIOs ESP01_RST_PIN=D8, ESP01_PGM_PIN=D10 for driving the
ESP-01S serial bootloader (not driven yet)
- docs/design/esp01s-uart-ota.md: full design (why Wi-Fi OTA doesn't fit
the 1MB ESP-01S on the GoPro AP, bootloader entry, ROM flash protocol,
HTTP-pull delivery, scope)
- hardware/README.md: fix stale ESP32-C3 -> XIAO ESP32-C6 wiring, add the
two control lines (Notion wiring diagram updated to match)
Both firmwares build clean and are flashed; set_config round-trip needs
the broker to exercise end-to-end.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
4.2 KiB
ESP-01S firmware updates without a USB-UART adapter
Status: design / not yet implemented. Interim mitigations (config-over-UART, GPIO reservation) are shipped; see "Shipped now" below.
Problem
The ESP-01S camera bridge has no native USB. Today it is flashed with an external
3.3 V USB-UART adapter and a GPIO0 → GND jumper held during reset. On an assembled
field node that is impractical — we want to update it over the network.
Why not Wi-Fi OTA on the ESP-01S itself
- Network topology. The ESP-01S joins the GoPro AP (
10.5.5.1), not the hub / travel-router network. The hub cannot reach it to push an OTA. - 1 MB flash. Standard ESP8266 OTA stages a second copy of the sketch alongside the running one. Our sketch is ~333 KB; a 1 MB module has no room for two copies plus FS and reserved areas.
So updates must arrive through the XIAO, which is already UART-connected to the ESP-01S and sits on the hub network.
Approach: XIAO ESP32-C6 as the flasher (UART OTA)
The XIAO plays the role the USB-UART adapter plays today, driving the ESP-01S's ROM serial bootloader over the existing UART.
Hardware — two added control lines
| XIAO pin | → ESP-01S | purpose |
|---|---|---|
D8 (ESP01_RST_PIN) |
RST |
pulse low to reset the ESP-01S |
D10 (ESP01_PGM_PIN) |
GPIO0 |
hold low across reset → enter bootloader |
D6 (TX) / D7 (RX) |
RX / TX |
existing Serial1 link (crossed) |
| GND | GND | common ground |
Confirm before committing the PCB/wiring: verify
D8/D10on the actual XIAO ESP32-C6 variant do not map to ESP32-C6 strapping pins (GPIO8,GPIO9,GPIO15) or the USB-JTAG pins. Pins are reserved in firmware (ESP01_RST_PIN,ESP01_PGM_PIN) but not yet driven.
Bootloader entry
GPIO0 = LOW, pulse RST low→high → ESP-01S enters the serial bootloader on the UART.
After writing: GPIO0 = HIGH, pulse RST → run the new firmware. Always restore
GPIO0 = HIGH on give-up so the ESP can boot normally.
Flash protocol
Implement enough of the ESP8266 ROM bootloader / esptool SLIP protocol on the XIAO over
Serial1:
SYNC, thenFLASH_BEGIN/FLASH_DATA(≈1 KB blocks) /FLASH_ENDto write the app at offset0x0.- Start at 115200 baud; optionally raise after sync.
- Verify with the ROM
SPI_FLASH_MD5against the expected MD5.
Firmware delivery (hub → XIAO)
Greenfield on the Go hub (only a firmware_version field exists today). Recommended:
- HTTP pull. Hub exposes
GET /firmware/esp01s/<version>.bin(+ MD5). XIAO is triggered by an MQTT command, e.g.{"command":"update_esp01s","url":"http://<hub>/firmware/esp01s/0.4.0.bin","md5":"…"}, fetches the.binin chunks, and streams each chunk straight into aFLASH_DATAblock. - Avoid buffering the whole image in RAM — stream HTTP chunk → flash block → repeat.
- MQTT chunked transfer is possible but heavier on the broker; prefer HTTP.
Sequencing / safety
- Pause the UART JSON status/command protocol while flashing (the link is busy with the bootloader protocol).
- On failure leave the ESP recoverable and retry; report progress/result to the hub over MQTT.
XIAO self-update (separate, easy)
The XIAO (4 MB flash, on the hub network) can use standard ESP32 OTA (ArduinoOTA or
httpUpdate). No gymnastics required. Split: XIAO = native OTA; ESP-01S = flashed by
the XIAO over UART.
Scope estimate
- XIAO firmware: ESP8266 ROM-loader client over
Serial1+GPIO0/RSTcontrol + HTTP fetch + MQTT trigger. Medium–large. - Hub (Go): firmware store + HTTP endpoint + MQTT trigger command. Small–medium.
- Hardware: two control wires + confirm non-strapping pins. Small.
Shipped now (interim)
- Config-over-UART (
set_config) — change GoPro SSID/password/IP and poll interval with no reflash. Hub →set_camera_config(MQTT) → XIAO →set_config(UART) → ESP-01S persists to LittleFS. - GPIO reservation —
ESP01_RST_PIN = D8,ESP01_PGM_PIN = D10reserved in the XIAO firmware for the flasher.
References
- ESP8266 ROM serial bootloader protocol (esptool).
- Wiring: Notion "XIAO ESP32-C6 Pin-to-Pin Wiring Diagram".