Skip to content

sensing-server (mqtt): per-node presence/presence_score topics carry array-global values — binaries publish in lockstep, score dynamics ~fully correlated across nodes #1541

Description

@jkuscevic

Summary

The per-node MQTT entities presence (binary) and presence_score do not reflect the individual node's state — they carry an array-global value stamped into each node's snapshot. The engine demonstrably computes per-node state (visible in /ws/sensingsensing_update.node_features[]), but what reaches the per-node MQTT topics makes room-level attribution impossible for any multi-node deployment consuming the Home Assistant integration.

Environment

  • Docker image ruvnet/wifi-densepose:v2051 (--features mqtt), host networking
  • 5× M5Stack Atom S3 Lite (esp32-csi-node) in five different rooms of a residential deployment, one node per room
  • Independent per-room ground truth (mmWave presence + PIR sensors in a separate Home Assistant) used to label the observations below

Observation 1 — per-node presence binaries publish in lockstep

Over a 21 h capture, all five per-node binary_sensor .../presence/state topics published identical transition streams: 52,916 transitions each, same timestamps, same intervals — including sub-second flaps (peaks ~42 transitions/min). Rooms were occupied/empty in completely different patterns per ground truth. The value appears to be the array-level presence copied into every node snapshot.

Observation 2 — per-node presence_score excursions are ~fully correlated across nodes

With the rate-limiter starvation fixed locally (#1540) so all five nodes publish at an equal 2 Hz (~82k samples/node overnight):

  • Score distributions are identical across all five nodes in every condition (occupied room, empty room, whole house asleep): median ≈ 50, p95 ≈ 53.4, ~2 % of samples ≥ 65.
  • Sustained excursions (score ≥ 65 held ≥ 60 s) fire simultaneously across nodes: of 112 sustained-episode clusters in one night, 41 spanned all five nodes with near-identical start/end times; only 29 were single-node.
  • Pairwise Pearson correlation of 30-second mean score between nodes, during 6.7 h in which ground truth confirms the entire household asleep in one room: +0.62 to +0.89 for every pair.
  • Per ground truth, each node produced ~35–45 sustained 1–3 min "presence" episodes in that window with its room verifiably empty.

The per-sample values do differ slightly between nodes (noise), but the dynamics are a common component — so neither single-node thresholds nor cross-node comparison can attribute presence to a room from these topics.

The engine has the per-node data

/ws/sensing sensing_update.node_features[] carries genuinely per-node classification (nodes concurrently report e.g. present_still vs present_moving, with per-node variance/band-power features). It appears the MQTT snapshot path (VitalsSnapshot construction) receives array-global presence / presence_score values rather than that node's own state.

Expected

Per-node MQTT topics reflect the node's own presence/score (as node_features does on the WebSocket), so that a one-node-per-room deployment can do room-level presence in Home Assistant.

Related: #1540 (rate limiter; fixing it is what made this measurable at equal rates).

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions