v0.3.4: OTA updates over MQTT, with HA progress bar
Devices now ship new firmware to themselves via Home Assistant. The
publish side is a `make firmware-ota-publish` that builds the binary,
copies it to a static HTTP host on the LAN, and announces the version
on a shared retained MQTT topic. HA's `update` entity compares the
shared latest against each device's installed version and shows an
Install button on the device card; clicking it sends the device the
URL pattern, which streams the binary via `esp_https_ota` into the
inactive partition slot, with `update_percentage` republished every 5%
so HA renders a real progress bar. After reboot, the firmware confirms
itself with `esp_ota_mark_app_valid_cancel_rollback` once MQTT is back,
which arms ESP-IDF's two-slot rollback against any version that can't
reach the broker.
Notable bits in the diff:
* Two-slot OTA partition table (`firmware/partitions.csv`); a one-time
wired flash migrates a v0.2.x device to it. From v0.3 onward every
bump is OTA.
* `CONFIG_ESP_HTTPS_OTA_ALLOW_HTTP=y` — without it the C function
rejects http:// URLs at config-validation time and never opens a
socket. Plain HTTP is intentional; the trust boundary is the LAN.
* `make firmware-ota-publish` reads `OTA_LOCAL_DIR`/`OTA_URL_BASE`/
`MQTT_URL` from `.envrc.private` (gitignored). The firmware reads
`ota_url_base` from `cfg.toml`; consequently any change to that
value is a wired-flash event for now.
* `firmware/src/channels.rs` — the std::sync::mpsc + esp-idf-rs
pthread-mutex incompatibility bites the OTA worker too; we use
FreeRTOS native queues here as elsewhere.
* `reference/mqtt-contract.md` and `operating-modes.md` rewritten to
match the actually-implemented behavior: button is a `sensor` with
an idle-after-N-ms reset (the v0.2.1 change), no more `rssi`, the
`update` entity, the shared `sound-machine/firmware/latest` topic,
and the OTA flow + rollback semantics.
References:
* https://docs.espressif.com/projects/esp-idf/en/v5.3.3/esp32/api-reference/system/ota.html#app-rollback
* https://www.home-assistant.io/integrations/update.mqtt/
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>