Add MQTT client + Home Assistant Discovery, verified end-to-end
Adds espressif/mqtt and mdns as the project's first external managed component dependencies (neither ships with ESP-IDF core in v6.0.2 anymore). Once Wi-Fi connects, the device advertises itself on the LAN as kvida-xxxxxx.local and serves a persistent settings page there for MQTT broker host/port and credentials -- the ongoing config channel beyond the one-time Wi-Fi captive portal. mDNS auto-discovery of _mqtt._tcp was the original plan, but verified against a real Home Assistant OS + Mosquitto add-on that it doesn't reliably answer PTR queries on the LAN (confirmed with a raw mDNS query from the host, parsed properly with dnspython after an earlier naive byte-check gave a false positive). Manual host/port entry is now the primary path; mDNS discovery still runs as a secondary fallback attempt, retried every 30s, in case it works on other networks. On MQTT_EVENT_CONNECTED, publishes retained HA MQTT Discovery for a diagnostic "connectivity" binary_sensor (grouped under a Kvida/Xylon device block) plus an online/offline availability topic driven by MQTT's own LWT. Verified end-to-end on real hardware: the device appears in Home Assistant with a "Connected" Connectivity sensor. Also extracts url_decode() (previously local to commissioning.cpp) and a new device_id() helper into shared headers, since both commissioning's Wi-Fi form and the new MQTT settings form need them. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -17,6 +17,14 @@ Future transports (Zigbee, Thread, Matter) should implement the same publish API
|
||||
- **IPv6**: once STA gets its IPv4 address (`IP_EVENT_STA_GOT_IP` -- not `WIFI_EVENT_STA_CONNECTED`, see the comment in `commissioning.cpp` for why that timing matters), `esp_netif_create_ip6_linklocal()` requests a link-local address (`CONFIG_LWIP_IPV6=y` is set explicitly in `sdkconfig.defaults`); `IP_EVENT_GOT_IP6` is logged when it arrives. Verified end-to-end on real ESP32-C6 hardware.
|
||||
- Not yet wired up: re-entering commissioning on an already-configured device needs a physical trigger (the user button) per AGENTS.md's "configuration mode requires physical user interaction" principle -- blocked on `drivers` having a real button implementation. Network scanning (SSID dropdown instead of free text) was left out of this first pass to keep scope tight.
|
||||
|
||||
TODO: built on ESP-IDF's own `esp_wifi` and `mqtt_client` (`esp-mqtt`) components once real code lands — both ship with ESP-IDF, no extra registry dependency needed.
|
||||
## MQTT + Home Assistant Discovery
|
||||
|
||||
`include/mqtt.h` / `src/mqtt.cpp`. Neither `esp_mqtt_client` (`mqtt_client.h`) nor `mdns.h` ship with ESP-IDF core in this version (both were moved to the IDF Component Registry) -- pulled in via `idf_component.yml` (`espressif/mqtt`, `mdns`), the project's first external managed dependencies.
|
||||
|
||||
- Once Wi-Fi STA has an IPv4 address, `start_mqtt()` advertises the device on the LAN as `kvida-xxxxxx.local` (mDNS hostname, matching the commissioning AP's SSID) and starts a persistent settings HTTP server there -- the ongoing configuration channel for anything beyond the one-time Wi-Fi bootstrap (MQTT broker/credentials now, more later).
|
||||
- **Broker address**: the settings page has a required host/port field, used directly and given priority over mDNS auto-discovery. mDNS discovery of `_mqtt._tcp` (`mdns_query_ptr`) is attempted as a fallback only if no manual host is saved, retried every 30s -- **verified against a real Home Assistant + Mosquitto add-on setup that this mDNS discovery does not reliably find the broker** (confirmed with a from-scratch raw mDNS query test from the host machine: no PTR answer for `_mqtt._tcp.local` was ever received on that network), hence the manual field being the primary path rather than a rarely-needed fallback.
|
||||
- **Credentials**: also collected on the same settings page (blank username = anonymous; blank password on a resubmit means "keep the current one", since the password is never echoed back into the page for basic hygiene). Real brokers, including Home Assistant's Mosquitto add-on, require auth -- confirmed on real hardware.
|
||||
- On `MQTT_EVENT_CONNECTED`: publishes (retained) an HA MQTT Discovery config for a diagnostic `connectivity` binary_sensor, grouped under a `device` block (`identifiers`/`name` = the same `kvida-xxxxxx` id, `manufacturer` "Xylon", `model` "Kvida"), then publishes `online` to the availability topic. MQTT's own LWT (`session.last_will`, set at client init) publishes `offline` to the same topic if the connection drops. Verified end-to-end: device appears in Home Assistant with a "Connected" Connectivity sensor.
|
||||
- No generic semantic `publish(topic, value)` API yet -- deferred until `profiles` has real sensor data to publish; building it now would be speculative.
|
||||
|
||||
TODO: A/B OTA update-checking belongs here, driven by ESP-IDF's native `esp_ota_ops` against the `ota_0`/`ota_1` partitions in `partitions.csv` — no extra dependency needed either.
|
||||
|
||||
Reference in New Issue
Block a user