Skip to content

fix(mqtt): one Home-Assistant device per node — closes #898#904

Merged
ruvnet merged 2 commits into
mainfrom
fix/898-mqtt-per-node-devices
Jun 2, 2026
Merged

fix(mqtt): one Home-Assistant device per node — closes #898#904
ruvnet merged 2 commits into
mainfrom
fix/898-mqtt-per-node-devices

Conversation

@ruvnet

@ruvnet ruvnet commented Jun 2, 2026

Copy link
Copy Markdown
Owner

Problem (#898)

After the #872 MQTT wiring shipped, --mqtt works but every node collapses into a single Home-Assistant device (identifiers:["wifi_densepose_wifi-densepose-1"]), contradicting docs/integrations/home-assistant.md ("one device per RuView node"). Root cause: the JSON→VitalsSnapshot bridge hard-coded a single node_id (the MQTT client id), and the publisher used one OwnedDiscoveryBuilder.

Fix

  • Bridge (main.rs): emit one VitalsSnapshot per node in the sensing update's nodes[] — each with its own node_id + RSSI (shared aggregate presence/vitals) — falling back to a single aggregate snapshot for wifi/simulate sources.
  • Publisher (publisher.rs): add OwnedDiscoveryBuilder::for_node(); publish discovery + availability lazily on first sight of each node_id, route state to per-node topics, and iterate all known nodes for heartbeat/refresh/offline-LWT → N distinct HA devices.

Tests

3 new unit tests (distinct nodes → distinct wifi_densepose_<node> identifiers; stable identity for repeat snapshots). Full MQTT suite 71 passed, example builds.

Note: per-node presence/vitals are still the shared aggregate (the sensing-server fuses nodes); this PR fixes the device topology (#898's complaint). True per-node sensing is a separate enhancement.

🤖 Generated with claude-flow

ruvnet added 2 commits June 2, 2026 09:43
After the #872 MQTT wiring, the JSON->VitalsSnapshot bridge hard-coded a
single node_id (the MQTT client id) and the publisher used one
OwnedDiscoveryBuilder, so every physical node collapsed into a single
Home-Assistant device (identifiers:["wifi_densepose_wifi-densepose-1"]),
contradicting the one-device-per-node docs.

- Bridge (main.rs): emit one VitalsSnapshot per node in the sensing
  update's nodes[] (each carries its own node_id + RSSI; shared aggregate
  presence/vitals), falling back to a single aggregate snapshot when
  there is no per-node data (wifi/simulate sources).
- Publisher (publisher.rs): add OwnedDiscoveryBuilder::for_node(), and
  publish discovery + availability lazily on first sight of each node_id,
  routing state to per-node topics. Heartbeat/refresh/offline-LWT iterate
  all known nodes. Result: N distinct HA devices, one per node.

3 new unit tests (distinct nodes -> distinct wifi_densepose_<node>
identifiers); full MQTT suite 71 passed, example builds.
…898

After the per-node discovery change, discovery configs are published the
first time a snapshot for a node_id arrives (not eagerly at startup). The
two discovery integration tests (discovery_topics_appear_on_broker,
privacy_mode_suppresses_biometric_discovery) spawned the publisher with an
empty broadcast channel and never sent a snapshot, so they collected []
and failed ("missing presence discovery topic in []").

Drive snapshots for the test node_id throughout the capture window (same
pattern as state_messages_published_on_snapshot_broadcast) so the per-node
device's discovery lands. Verified against a local mosquitto: 3 passed.
@ruvnet
ruvnet merged commit 9df908d into main Jun 2, 2026
21 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant