fix(sensing-server): feature_state path keeps last raw amplitudes

After 3393c1e8 made FW emit ~80 % feature_state packets and ~20 % raw
CSI, the server's feature_state path was overwriting NodeInfo.amplitude
with vec![] on every feature_state tick. raw.html's per-node bar chart
ended up freezing for hundreds of milliseconds between rare raw-CSI
packets, and /api/v1/sensing/latest mostly snapshotted an empty amps
vector even though raw CSI was flowing.

Fix: in the feature_state SensingUpdate builder, hand out
ns.frame_history.back() (the last raw amps vector that the raw-CSI
path pushed) instead of an empty Vec. Bars now refresh on every WS
update (verified: 100/100 updates carry amps in a 4-s sample, was
~20/100 before the patch).

Classifier behaviour unchanged — amp_presence_override still runs only
when actual raw CSI arrives; this only affects what the UI displays.
This commit is contained in:
arsen 2026-05-17 02:54:37 +07:00
parent 2f12a2236b
commit 7535dff3e4
1 changed files with 16 additions and 6 deletions

View File

@ -4400,14 +4400,24 @@ async fn udp_receiver_task(state: SharedState, udp_port: u16) {
}
// Build nodes array with all active nodes.
// ADR-101 follow-up: feature_state packets carry no
// raw CSI of their own, but the raw-CSI path has
// been pushing amplitudes into ns.frame_history.
// Hand the most recent vector out so raw.html bars
// don't go blank between rare raw-CSI packets
// (current FW emits ~80 % feature_state, ~20 % raw).
let active_nodes: Vec<NodeInfo> = s.node_states.iter()
.filter(|(_, n)| n.last_frame_time.map_or(false, |t| now.duration_since(t).as_secs() < 10))
.map(|(&id, n)| NodeInfo {
node_id: id,
rssi_dbm: n.rssi_history.back().copied().unwrap_or(0.0),
position: [2.0, 0.0, 1.5],
amplitude: vec![],
subcarrier_count: 0,
.map(|(&id, n)| {
let last_amps = n.frame_history.back().cloned().unwrap_or_default();
let sub_count = last_amps.len();
NodeInfo {
node_id: id,
rssi_dbm: n.rssi_history.back().copied().unwrap_or(0.0),
position: [2.0, 0.0, 1.5],
amplitude: last_amps,
subcarrier_count: sub_count,
}
})
.collect();