A nightstand noise generator based on M5Stack Atom Echo and integrating with Home Assistant

v0.3.4: OTA updates over MQTT, with HA progress bar master

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>