RuView 无线感知接入 Home Assistant 全指南:MQTT 自动发现(HA-DISCO)与 Matter Bridge(HA-FABRIC)双协议架构实战
RuView 通过 WiFi CSI 感知可输出人体存在、人数、17 关键点姿态、呼吸率/心率、跌倒、动作能量与区域占用等遥测数据。本文以 ADR-115-home-assistant-integration.md 为骨架,结合 docs/integrations/home-assistant.md 与 docs/integrations/semantic-primitives-metrics.md 以及 v2/crates/wifi-densepose-sensing-server 的源码,完整讲解"MQTT 自动发现为主、Matter 桥接为辅"的双协议 Home Assistant 集成方案。读完本文,你将掌握:实体/主题映射规则、自动发现消息格式、QoS/限速/隐私策略、全部 CLI 配置项、10 个语义自动化原语的触发逻辑,以及可复现的端到端验收方法。
1. 背景:为什么需要一等公民的 Home Assistant 接入
RuView 与底层 WiFi-DensePose 栈已经能通过 Rust 实现的 wifi-densepose-sensing-server(源码位于 v2/crates/wifi-densepose-sensing-server)输出丰富的人体感知遥测。服务器通过 WebSocket 在 /ws/sensing 上广播三类结构化消息,它们是后续所有集成映射的数据源:
服务器消息 type |
代码位置 | 负载关键字段 |
|---|---|---|
pose_data |
见 main.rs | 每次检测 17 关键点、confidence、track_id |
edge_vitals |
同上 | node_id、presence、fall_detected、motion、breathing_rate_bpm、heartrate_bpm、n_persons、motion_energy、presence_score、rssi |
sensing_update |
同上 | 聚合检测结果 + 区域命中 |
运行 Cognitum Seed(cognitum-v0 应用,:9000)或独立 ESP32-S3 / ESP32-C6 节点的用户,希望这些遥测直接进入 Home Assistant (HA)——全球部署最广的开源家庭自动化中枢、MQTT 原生支持——以便直接用存在、生命体征、跌倒与动作来构建自动化,而不必手写代码对接 REST/WebSocket API。
ADR-115 指出两个客户侧问题的本质相同(详见 docs/adr/ADR-115-home-assistant-integration.md):
- #574:用户不想手动粘贴
seed://URL,期望中枢自动发现节点(mDNS); - #760:用户期望"单一仪表盘看到所有传感器"的 HA 式体验,而非被迫使用 RuView 自己的 UI。
两者共同诉求是:RuView 不应是"需要胶水代码才能融入智能家居的黑盒",而应是开箱即用的感知节点。
依据 ADR-115 现状记录:MQTT 主线(P1–P7、P8a、P9、P10)已于 2026-05-23 随 PR #778 落地并标记 Accepted;Matter SDK 接线部分(P8b)按文档延后至 v0.7.1。本文以文档+仓库现状为准进行说明。
1.1 行业对标与本 ADR 的边界
ADR 中对标了 espectre.dev(仅姿态、无生命体征、闭源服务器)、tommysense.com(仅生命体征且强制云)、Aqara FP2(原生 ZigBee、存在+分区)、ESPHome 刷写的 HLK-LD2410 等,行业标杆是"Aqara FP2 的 HA 原生体验 + 低成本即插即用"。RuView 的差异化能力是姿态、心率/呼吸率、跌倒、多房间,因此需要"一等公民"HA 集成来承载这些能力。
同时 ADR 明确了边界:不是 HACS Python 集成(仅作为后续项);不是单向 webhook 推送;不改动 ADR-018 CSI 帧格式或 ADR-039 边缘生命体征报文;不改固件,ESP32-S3 与 ESP32-C6 路径保持字节级不变。
2. 双协议决策:MQTT 主、Matter 次
ADR-115 的核心决策是互补而非互斥的双路径:
- 主路径 — MQTT + HA 自动发现(代号 HA-DISCO):在
wifi-densepose-sensing-server中新增 MQTT 发布器,连接用户提供的 broker(默认mqtt://localhost:1883),启动时及周期刷新(默认 600 s)时对每个 RuView 节点、每个能力发布一条 HA discovery 消息;把每次 WebSocket 广播(edge_vitals/pose_data/sensing_update)翻译为逐实体的 MQTT 状态消息;并通过--privacy-mode在发布前剥离生物特征(HR/BR/姿态关键点)。 - 次路径 — Matter Bridge(代号 HA-FABRIC):把 RuView 节点以 Matter Bridged Device 形式暴露到 WiFi 网络上,覆盖 Matter 目前标准化的子集——存在(
OccupancySensing)、动作(BooleanState)、跌倒事件(Switch作为事件)、人数(桥上的数值属性),可被 Apple Home / Google Home / Amazon Alexa / Samsung SmartThings / HA 自身任一 Matter 控制器消费。生物特征(HR/BR)与姿态在 Matter 规范添加可表达的设备类型之前,只走 MQTT。
ADR 给出了四方案对比,核心取舍如下:
| 准则 | A. MQTT 自动发现 | D. Matter Bridge | B. HACS Python 集成 | C. REST webhook |
|---|---|---|---|---|
| 端用户零代码 UX | 是(HA 自动建实体) | 是(扫码配网) | 是(安装后) | 否(手工接线) |
| 跨生态覆盖 | HA + 任意 MQTT 消费端 | Apple/Google/Alexa/SmartThings/HA | 仅 HA | 仅 HA |
| 分发与维护 | 既有 crate 一个 Rust feature | 一个 Rust feature + Matter SDK 链接 | 新 Python 仓库 + HACS 审核 | 极简 |
| 实体自动发现 | 是(homeassistant/ 主题命名空间) |
是(Matter commissioning + bridge endpoint) | 是(config flow) | 否 |
| 双向控制 | 是(订阅 command topic) | 是(Matter commands) | 是 | 仅单向 |
| 承载 HR/BR/姿态 | 是 | 否(无对应 cluster) | 是(自定义) | 是(自定义) |
| 承载存在/人数/跌倒 | 是 | 是(Matter 1.3+) | 是 | 是 |
| 无 HA 也能用 | 任意 MQTT 消费端 | 任意 Matter 控制器 | 仅 HA | 仅 HA |
| MVP 工作量 | ~2 周 | ~4–6 周 | ~4–6 周 | ~2 天 |
MQTT 是主路径,因为它能承载 100% 的差异化遥测(姿态、HR、BR),其他路径做不到;Matter 是次路径,因为它覆盖约 30% 的子集(存在/人数/跌倒),却能触及不运行 HA 的另一部分用户。webhook(C)因无实体发现、无控制平面被否决;HACS(B)体验更精致但成本更高,留待 MQTT 落地数据出来后复审。
3. 实体映射与 MQTT 主题结构
3.1 实体映射表
每个 RuView 节点对应 HA 中一个 device,每个能力对应其上一个 entity;ESP32 节点若挂在 Cognitum Seed 之后,通过 via_device 关联,HA 界面即可呈现树状拓扑。
| 能力 | HA 组件 | device_class |
state_class |
单位 | 图标 | WS 源字段 |
|---|---|---|---|---|---|---|
| Presence | binary_sensor |
occupancy |
— | — | mdi:motion-sensor |
edge_vitals.presence |
| Person count | sensor |
— | measurement |
persons | mdi:account-group |
edge_vitals.n_persons |
| Breathing rate | sensor |
— | measurement |
bpm | mdi:lungs |
edge_vitals.breathing_rate_bpm |
| Heart rate | sensor |
— | measurement |
bpm | mdi:heart-pulse |
edge_vitals.heartrate_bpm |
| Motion level | sensor |
— | measurement |
% | mdi:run |
edge_vitals.motion(0–1 → ×100) |
| Motion energy | sensor |
— | measurement |
无量纲 | mdi:waveform |
edge_vitals.motion_energy |
| Fall detected | event |
— | — | — | mdi:human-fall |
edge_vitals.fall_detected |
| Presence score | sensor |
— | measurement |
% | mdi:gauge |
edge_vitals.presence_score(×100) |
| RSSI | sensor |
signal_strength |
measurement |
dBm | mdi:wifi |
edge_vitals.rssi |
| Zone occupancy(每区) | binary_sensor |
occupancy |
— | — | mdi:map-marker |
sensing_update.zones[*] |
| Pose keypoints | sensor(JSON 属性) |
— | — | — | mdi:human |
pose_data.keypoints(opt-in) |
| Tracked persons(按 ID) | binary_sensor(动态) |
occupancy |
— | — | mdi:account |
pose_data.track_id |
姿态关键点不设为一等实体:HA 没有"17 关键点"原语,因此以 wifi_densepose_<node>_pose 传感器的属性负载暴露,高级用户可对其做 template,而默认 HA UI 保持整洁。
3.2 MQTT 主题结构
遵循 HA 官方 discovery 约定 homeassistant/<component>/<object_id>/<entity>/config;object id 取 wifi_densepose_<node_id> 以与其他设备隔离命名空间:
homeassistant/binary_sensor/wifi_densepose_<node_id>/presence/config (retained, QoS 1)
homeassistant/binary_sensor/wifi_densepose_<node_id>/presence/state (not retained, QoS 0)
homeassistant/binary_sensor/wifi_densepose_<node_id>/presence/availability (retained, QoS 1)
homeassistant/sensor/wifi_densepose_<node_id>/heart_rate/config (retained, QoS 1)
homeassistant/sensor/wifi_densepose_<node_id>/heart_rate/state (not retained, QoS 0)
homeassistant/sensor/wifi_densepose_<node_id>/breathing_rate/config
homeassistant/sensor/wifi_densepose_<node_id>/breathing_rate/state
homeassistant/event/wifi_densepose_<node_id>/fall/config (retained, QoS 1)
homeassistant/event/wifi_densepose_<node_id>/fall/state (not retained, QoS 1)
ruview/<node_id>/raw/pose (opt-in, not retained, QoS 0)
ruview/<node_id>/raw/sensing_update (opt-in, not retained, QoS 0)
ruview/<node_id>/raw/* 命名空间刻意置于 homeassistant/ 之外:它承载原始 WebSocket JSON,供 Node-RED / Grafana / 自定义脚本直接消费,避免 HA 试图把它解析为实体。
3.3 自动发现负载示例
Presence(binary_sensor) 的 discovery payload:
{
"name": "Presence",
"unique_id": "wifi_densepose_aabbccddeeff_presence",
"object_id": "wifi_densepose_aabbccddeeff_presence",
"state_topic": "homeassistant/binary_sensor/wifi_densepose_aabbccddeeff/presence/state",
"availability_topic": "homeassistant/binary_sensor/wifi_densepose_aabbccddeeff/presence/availability",
"payload_on": "ON",
"payload_off": "OFF",
"payload_available": "online",
"payload_not_available": "offline",
"device_class": "occupancy",
"qos": 1,
"device": {
"identifiers": ["wifi_densepose_aabbccddeeff"],
"name": "RuView node aabbccddeeff",
"manufacturer": "ruvnet",
"model": "ESP32-S3 CSI node",
"sw_version": "v0.6.7",
"via_device": "cognitum_seed_1"
},
"origin": {
"name": "wifi-densepose-sensing-server",
"sw_version": "0.7.0",
"support_url": "https://github.com/ruvnet/RuView"
}
}
Heart rate(sensor) 的 discovery payload:
{
"name": "Heart rate",
"unique_id": "wifi_densepose_aabbccddeeff_heart_rate",
"state_topic": "homeassistant/sensor/wifi_densepose_aabbccddeeff/heart_rate/state",
"availability_topic": "homeassistant/sensor/wifi_densepose_aabbccddeeff/heart_rate/availability",
"unit_of_measurement": "bpm",
"state_class": "measurement",
"icon": "mdi:heart-pulse",
"value_template": "{{ value_json.bpm }}",
"json_attributes_topic": "homeassistant/sensor/wifi_densepose_aabbccddeeff/heart_rate/state",
"qos": 0,
"device": { "identifiers": ["wifi_densepose_aabbccddeeff"] }
}
其状态负载形如:{ "bpm": 68.2, "confidence": 0.91, "ts": "2026-05-23T14:00:00Z" }。
Fall(event) 的 discovery payload:
{
"name": "Fall detected",
"unique_id": "wifi_densepose_aabbccddeeff_fall",
"state_topic": "homeassistant/event/wifi_densepose_aabbccddeeff/fall/state",
"event_types": ["fall_detected"],
"icon": "mdi:human-fall",
"qos": 1,
"device": { "identifiers": ["wifi_densepose_aabbccddeeff"] }
}
每次跌倒仅触发一次、不 retained 的事件状态负载:{ "event_type": "fall_detected", "ts": "2026-05-23T14:00:00.123Z", "confidence": 0.87 }。
源码佐证:上述结构的实现位于 mqtt/discovery.rs,其中 DiscoveryConfig / DeviceMeta / OriginMeta 均为 Serialize-only 结构体(只发不解析),字段名对齐 HA 官方 discovery schema(当前测试基线为 HA 2025.5)。发现模块的单元测试直接断言 unique_id == "wifi_densepose_aabbccddeeff_presence" 以及状态/可用性主题的路径形态,可作模式参考。
3.4 设备级分组
- 每个 RuView 节点(ESP32-S3 / S3-Mini / C6,或 mock 模式下的宿主)= 一个 HA device;
device.identifiers=["wifi_densepose_<node_id>"],node_id取自edge_vitals.node_id(MAC 派生);- Cognitum Seed 之后的子节点设置
device.via_device = "cognitum_seed_<seed_id>",HA 按树状渲染(Seed → 子节点); - Seed 本身作为父设备出现,携带自身的诊断实体(uptime、agent health),由 Seed 直接发布而非 sensing-server。
4. QoS、保留、刷新与 LWT 可用性
不同主题的生命周期语义差异决定了 QoS/retain/刷新策略:
| 主题 | QoS | Retain | 刷新节奏 | 理由 |
|---|---|---|---|---|
*/config |
1 | 是 | 启动时 + 每 600 s | HA 期望 retained discovery;周期重发可在 HA 重启后自愈 |
*/state(sensor) |
0 | 否 | 按 §6 限速 | best-effort,HA 容忍偶发丢帧 |
*/state(binary_sensor) |
1 | 是 | 仅变化时 | 末值重要,新订阅者应看到当前状态 |
*/state(event) |
1 | 否 | 事件发生时 | 跌倒不可漏报;绝不 retained,避免 HA 重放旧事件 |
*/availability |
1 | 是 | LWT + 30 s 心跳 | 离线检测 |
ruview/*/raw/* |
0 | 否 | 随数据发布 | 原始 firehose,消费端 opt-in |
Last Will and Testament (LWT):连接成功时 sensing-server 在每个实体 availability 主题上设置 LWT 为 offline(retained);成功连接后发布 online(retained);随后以 30 s 心跳重发 online,使 HA 能识别僵尸会话。LWT 三元组:主题 .../<entity>/availability、payload offline、QoS 1、retain true。实现见 mqtt/mod.rs 与 mqtt/discovery.rs 中的 AvailabilityPayload::for_entity。
5. 带宽控制与限速
姿态关键点以 10 fps × 17 关键点 × 3 浮点约等于每人 4–8 kbit/s,LAN 内可接受,但若用户误路由到计费的蜂窝 MQTT 桥则很危险,因此默认值整体保守:
| 实体类型 | 默认速率 | 可配置 | 覆盖 flag |
|---|---|---|---|
| Presence(binary) | 仅变化时 | 是 | — |
| Person count | 1 Hz | 是 | --mqtt-rate-count=1 |
| BR / HR | 0.2 Hz(每 5 s) | 是 | --mqtt-rate-vitals=0.2 |
| Motion level | 1 Hz | 是 | --mqtt-rate-motion=1 |
| Fall events | 事件即时 | 否(始终即时) | — |
| RSSI | 0.1 Hz | 是 | --mqtt-rate-rssi=0.1 |
| Pose keypoints | 默认关闭,开启时 1 Hz | 是 | --mqtt-publish-pose --mqtt-rate-pose=1 |
| Zones | 仅变化时 | 是 | — |
6. 配置:CLI 全量参数与环境变量
wifi-densepose-sensing-server 通过 --mqtt 门控 MQTT 发布器。完整的参数族与默认值(均以 cli.rs 的解析逻辑及 docs/integrations/home-assistant.md 为准):
--mqtt Enable MQTT publisher (default off)
--mqtt-host <HOST> MQTT broker host (default: localhost)
--mqtt-port <PORT> MQTT broker port (default: 1883, 8883 if --mqtt-tls)
--mqtt-username <USER> MQTT username
--mqtt-password-env <ENVVAR> 从环境变量读密码 (default: MQTT_PASSWORD)
--mqtt-client-id <ID> Client ID (default: wifi-densepose-<hostname>)
--mqtt-prefix <PREFIX> Discovery prefix (default: homeassistant)
--mqtt-tls 启用 TLS (default off)
--mqtt-ca-file <PATH> CA bundle (default: system trust)
--mqtt-client-cert <PATH> mTLS 客户端证书
--mqtt-client-key <PATH> mTLS 客户端私钥
--mqtt-refresh-secs <N> Discovery 刷新间隔 (default: 600)
--mqtt-rate-vitals <HZ> 生命体征发布速率 (default: 0.2)
--mqtt-rate-motion <HZ> Motion 发布速率 (default: 1.0)
--mqtt-rate-count <HZ> 人数发布速率 (default: 1.0)
--mqtt-rate-rssi <HZ> RSSI 发布速率 (default: 0.1)
--mqtt-publish-pose 发布姿态关键点 (default off)
--mqtt-rate-pose <HZ> 姿态开启时的发布速率 (default: 1.0)
--privacy-mode 发布前剥离生物特征 (HR/BR/pose)
环境变量等价形式遵循 RUVIEW_MQTT_HOST、RUVIEW_MQTT_USERNAME 等命名,方便 Docker / systemd 用户免于长参数串。配置优先级为 CLI > env > 默认值。语义原语相关参数(--semantic、--semantic-thresholds-file、--semantic-zones-file、--semantic-baseline-window-days、可重复的 --no-semantic <primitive>)与 Matter 参数(--matter、--matter-setup-file、--matter-reset、--matter-vendor-id、--matter-product-id)也统一由 cli.rs 声明。
几个值得注意的源码事实(见 Cargo.toml):
rumqttc依赖被门控在mqttCargo feature 之后,未启用--mqtt的用户零二进制/运行时成本;- feature 关闭时
--mqtt-*参数仍可解析(cli.rs无条件声明),运行时若启用--mqtt则记WARN、publisher 空转,避免用户误以为参数未生效; mqtt = ["dep:rumqttc"],并带有mqtt_throughputbench(requires-features mqtt);cli.rs单测覆盖默认值断言(--mqtt默认 false、matter_vendor_id默认0xFFF1、matter_product_id默认0x8001、semantic默认 on、semantic_baseline_window_days默认 14)以及完整参数组合解析和--no-semantic可重复性。
状态编码与限速器(mqtt/state.rs)刻意在无 rumqttc 时也能编译,从而可在 --no-default-features 下测试;只有真正持有 rumqttc::AsyncClient 的 publisher(mqtt/publisher.rs)才需要该 feature。
6.1 配置文件格式
区域标签文件(传给 --semantic-zones-file):
# semantic-zones.yaml
zones:
bathroom: ["zone_3", "zone_7"]
bedroom: ["zone_1"]
kitchen: ["zone_2"]
living: ["zone_5"]
bed_zones: ["zone_1"]
阈值覆盖文件(传给 --semantic-thresholds-file):
# semantic-thresholds.yaml
sleep_dwell_secs: 300
distress_hr_multiple: 1.5
room_active_motion_threshold: 0.10
elderly_anomaly_multiple: 2.0
meeting_min_persons: 2
no_movement_dwell_secs: 1800
fall_risk_event_threshold: 70.0
阈值在 Rust 侧位于各原语模块的 PrimitiveConfig,默认值调校偏保守(保精度舍召回),医疗/商用场景建议保留默认或上调。
7. TLS、认证与隐私模式
7.1 传输安全分级(ADR-115 §3.9)
- 推荐:专用 VLAN 上的 mTLS,broker 固定到按 Cognitum Seed 逐台签发的 CA;
- 可接受:TLS 之上的用户名+密码(如用户 HA 内现成的 Mosquitto add-on);
- 否决:与不可信设备共享网络上的明文。当前版本在非
localhostbroker 上启用--mqtt而未配--mqtt-tls时会记WARN(v0.7.0 行为);按 ADR,v0.8.0 将升级为硬失败(非零退出),详见 docs/integrations/home-assistant.md 的排障说明。
7.2 --privacy-mode
该开关在任何 MQTT 发布之前剥离生物特征及其可推导通道,无论订阅者是谁;此模式下相关实体的 discovery 消息永不发布(HA 甚至不知道它们存在):
| 通道 | 默认 | --privacy-mode |
|---|---|---|
| Presence | published | published |
| Person count | published | published |
| Motion level | published | published |
| Zone occupancy | published | published |
| RSSI | published | published |
| Breathing rate | published | stripped |
| Heart rate | published | stripped |
| Fall events | published | published(安全 > 隐私) |
| Pose keypoints | 默认关 | stripped(不可强制开启) |
这落实了 ADR-106 的 primitive-isolation 契约:HR/BR/pose 属生物特征级信号,未经操作者显式 opt-in 不得泄漏给不受约束的 MQTT broker。实现在 mqtt/privacy.rs。非 localhost broker 部署务必把 --privacy-mode 与 --mqtt-tls 组合使用。
8. Matter Bridge(HA-FABRIC)
Matter 路径运行在同一 wifi-densepose-sensing-server 进程内,由 --matter feature flag 独立于 --mqtt 门控(仓库中已有 matter/ 模块:bridge / clusters / commissioning)。桥以 Bridged Devices Aggregator(Matter Core Spec §9.13)身份呈现,为每个 RuView 节点提供一个 Bridged Device endpoint,暴露标准化子集;生物特征与姿态不通过 Matter 暴露——规范中没有对应 cluster,用 Generic Sensor 硬套会让所有控制器渲染成无名数字。
8.1 Matter 设备类型映射
| RuView 能力 | Matter cluster | Endpoint 设备类型 | 源字段 |
|---|---|---|---|
| Presence | OccupancySensing (0x0406) |
OccupancySensor (0x0107) |
edge_vitals.presence |
| Motion(布尔、超阈值) | OccupancySensing (0x0406) |
(同一 endpoint) | edge_vitals.motion > 0.1 |
| Fall event | Switch (0x003B) MultiPressComplete 事件 |
GenericSwitch (0x000F) |
edge_vitals.fall_detected(一次瞬时按压 = 一次跌倒) |
| Person count | OccupancySensing 扩展属性(厂商自定义 0xFFF1_0001) |
(同一 endpoint) | edge_vitals.n_persons |
| Zone occupancy | 每区一个 OccupancySensor endpoint |
(多 endpoint) | sensing_update.zones[*] |
| RSSI / motion energy / presence score / BR / HR / pose | 不通过 Matter 暴露 | — | (仅 MQTT) |
人数用的厂商自定义属性以 RuView 的 CSA 厂商 ID 命名(开发阶段用 0xFFF1)。不认识厂商扩展的控制器仍会看到标准 OccupancySensing.Occupancy 布尔量——优雅降级。
8.2 配网与 fabric 模型
- WiFi 配网:首次启动时桥打印 Matter setup code(11 位短码 + QR 字符串)到日志及
--matter-setup-file <PATH>;用户用 Apple Home / Google Home / HA Matter 集成扫码。 - 无需 Thread 射频:sensing-server 运行在拥有 WiFi 但无 802.15.4 的宿主(Pi 5、x86、Cognitum Seed),Matter-over-WiFi 足够;Thread 支持明确排除在范围外,直到 ESP32-C6 固件长出 Matter 协议栈(独立 ADR)。
- 多 admin / 多 fabric:桥接受多次 commissioning 会话,同一节点可同时配入 Apple Home、Home Assistant 与 Google Home——fabric 隔离由 Matter
OperationalCredentialscluster 保证。 - 重置配网:
--matter-reset擦除已存 fabric 凭据,允许针对新控制器重新配对。
8.3 SDK 选型与已知局限
ADR 对比了三类 Rust 路径:纯 Rust 的 matter-rs(无 FFI、契合 Rust-only crate 策略、MIT 许可,但成熟度较低)、project-chip/connectedhomeip 的 Rust FFI(参考实现、可认证但引入 CMake/C++ 工具链)、外部独立 Matter 守护进程(解耦 SDK 变动但多一个进程)。暂定 v0.7.0 走 matter-rs,若 P7 试配对暴露认证阻碍再回退 chip-tool FFI。
文档要求前置声明的有意设计限制(详见 docs/integrations/home-assistant.md):
- Matter 上无 HR、BR、姿态、RSSI——生物特征/详细遥测请用 MQTT;
- 跌倒事件是一次性的(一次瞬时按压),控制器须订阅事件;
- 人数是厂商扩展——Apple Home / Google Home 只显示 occupancy on/off,HA 与 SmartThings(带自定义 handler)才显示数值;
- 多 fabric 下应选定一个"主控制器"承载自动化逻辑,避免竞争触发;
- Matter 规范禁止这类设备类型携带视频/图像数据,RuView 本也不会暴露。
8.4 双路径去重
同一节点配入 HA 后会以两种方式出现:HA-DISCO 的完整 MQTT 实体集 + HA Matter 集成下的 Matter 设备。两条路径的 unique_id 都设为 wifi_densepose_<node_id>_<entity>,HA 依据 unique_id 去重,用户看不到幽灵设备;Apple Home / Google Home 则看到同一个物理节点而不重复——这正是"选两条协议而非一条"的架构理由。
9. 语义自动化原语(HA-MIND)
原始信号不是产品。用户不想要"手写 Node-RED 流程去阈值化夜间呼吸率以推断睡眠",而是想要一个能直接接进"有人在睡就把走廊灯调到 10%"自动化的 binary_sensor.bedroom_someone_sleeping。ADR-115 §3.12 定义了把 RuView 从"RF 感知"升级为"环境智能基础设施"的推理层——它必须以一等 HA 实体与 Matter 事件交付,而不是 SDK。
9.1 v1 原语目录
每个原语由一到多个原始通道经小型有限状态机(FSM)融合产生,推理在 wifi-densepose-sensing-server 内运行(与 MQTT 发布同处),由 --semantic 门控(默认开)。每个状态变化携带置信度与 explanation 字段供调试。
| 原语 | 输入(raw) | 输出形态 | 默认真值条件 | 迟滞/不应期 |
|---|---|---|---|---|
| Someone sleeping | presence + 低动作(<5% 持续 ≥300 s)+ BR 8–20 bpm + 低 HR 变异性 | binary_sensor (occupancy) |
全部条件同时成立 | 5 min 后进入;motion >15% ≥30 s 退出 |
| Possible distress | 持续 HR 升高(>1.5× 滚动基线 ≥60 s)+ 躁动动作 + 无跌倒 | binary_sensor (problem) + event |
confidence ≥ 0.75 | 退出后锁存 5 min |
| Room active | presence + 任意 5 min 窗口内 motion >10% ≥30 s | binary_sensor (occupancy) |
滚动窗口 | 空闲 10 min 退出 |
| Elderly inactivity anomaly | 无动作 + presence 稳定 > N× 滚动日间中位空闲(默认 2×) | binary_sensor (problem) + event |
模型个性化 | 每居民基线;每天最多告警 1 次 |
| Meeting in progress | 人数 ≥2 + 持续低幅动作(坐姿)+ 安装 speech_band cog 时叠加语音带微动 |
binary_sensor (occupancy) |
≥2 人 + ≥10 min | 人数 <2 持续 2 min 退出 |
| Bathroom occupied | 标记 bathroom 的区域内 presence 为真 |
binary_sensor (occupancy) |
区域+presence | 隐私模式仍保持开启(非生物特征) |
| Fall risk elevated | 近期近跌倒(无确认跌倒的急剧加速度)或步态不稳得分超阈值 | sensor(0–100)+ 越阈时 event |
模型推导 | 24 小时窗口 |
| Bed exit (overnight) | "someone sleeping" → presence 在 22:00–06:00 本地时间离开床区 | event |
边沿触发 | 每次离床一个事件 |
| No movement (safety check) | presence 为真 + motion <1% 持续 ≥N min(默认 30) | binary_sensor (problem) + event |
时长阈值 | 出现动作即清除 |
| Multi-room transition | 10 s 内 track_id 跨区域连续 | event(who_went_from_to) |
边沿触发 | 每 track 一个事件 |
v2 目录(推迟)包括 child-playing、pet-vs-human、agitation-gradient、circadian-phase,待 v1 有现场数据后由独立 ADR 承接。
仓库现状佐证:推理层已按文档结构落地于 semantic/ —— 每个原语一个文件(sleeping.rs、distress.rs、room_active.rs、elderly_anomaly.rs、meeting.rs、bathroom.rs、fall_risk.rs、bed_exit.rs、no_movement.rs、multi_room.rs),加上共享的 common.rs(PrimitiveConfig/PrimitiveState/Reason)、bus.rs(SemanticBus 聚合输出并向 MQTT + Matter 广播)。semantic/mod.rs 顶部注释明确了四项契约:服务端推理、单一事实源(新增原语=一个文件改动,无需 MQTT discovery schema 或 Matter cluster 变更)、可解释性(reason 负载)、处处迟滞 + 启动 60 s 暖机抑制。
9.2 三层表面的映射
| 层 | 语义原语如何呈现 |
|---|---|
| MQTT (HA-DISCO) | 新主题命名空间 homeassistant/binary_sensor/wifi_densepose_<node>/<primitive>/ 与 .../event/.../<primitive>/——完整 discovery 负载,explanation 以 json_attributes 承载 |
| Matter (HA-FABRIC) | sleeping/active/meeting/bathroom → OccupancySensing(独立 endpoint);distress/inactivity/no-movement/bed-exit/fall-risk-cross → 专用 GenericSwitch endpoint 上的 Switch.MultiPressComplete 事件;fall-risk 得分 → bridge endpoint 上的厂商扩展属性 |
| HA automations | 仓库 examples/ha-blueprints 提供 8 个可直接导入的入门 blueprint:01-notify-on-possible-distress.yaml、02-dim-hallway-when-sleeping.yaml、03-wake-routine-on-bed-exit.yaml、04-alert-elderly-inactivity-anomaly.yaml、05-meeting-lights-presence-mode.yaml、06-bathroom-fan-while-occupied.yaml、07-fall-risk-escalation.yaml、08-auto-arm-security-when-not-active.yaml |
| Apple Home scenes | 每个 OccupancySensor endpoint 与每个 GenericSwitch 事件经 Matter 触发 Apple Home 场景——无需 HA |
9.3 推理质量契约与可解释性
每个原语随附(详见 docs/integrations/semantic-primitives-metrics.md):
- 在 ADR-079 配对采集 + 合成压力场景构建的留出测试集上发布 precision/recall/F1 基线(v1:
someone_sleeping0.92/0.78、room_active0.96/0.94、bathroom_occupied0.99/0.97、bed_exit0.94/0.89、no_movement0.91/0.93,其余见指标文档),并给出复现命令(cargo test ... semantic::与--source replay ... --metrics-out); - 可解释性负载:每次状态变化带
reason: ["motion<5%", "br=12bpm", "presence=true"]风格的属性,HA 用户可在自动化模板中引用state_attr(..., 'reason')排查触发原因; - 置信度阈值:逐原语可用
--semantic-thresholds-file调节,文档说明默认偏保守; - 抑制契约:原语在启动后 60 s 暖机期、以及
csi_calibration_in_progress状态(ADR-014)期间绝不触发。
9.4 对架构的意义
推理位于 semantic_inference.rs 一类新模块,订阅与 MQTT/Matter 相同的 tokio::broadcast 通道,运行各原语 FSM,产出两个输出流:1)新增 broadcast 通道上的 SemanticState 事件,MQTT 与 Matter publisher 共同订阅(同一推理驱动双表面,不重复实现);2)--data-dir 下 append-only 的 semantic_events.jsonl 日志,供离线分析与 ADR-079 配对监督。
10. 快速上手与验收方法
10.1 启动发布器
# Docker(推荐非开发者)
docker run --rm --net=host \
ruvnet/wifi-densepose:0.7.0 \
--source esp32 \
--mqtt --mqtt-host 192.168.1.10 \
--mqtt-username homeassistant --mqtt-password-env MQTT_PASSWORD
# 或源码运行(Rust 1.78+)
MQTT_PASSWORD='your-broker-password' \
cargo run --release -p wifi-densepose-sensing-server \
--features mqtt -- \
--source esp32 --mqtt \
--mqtt-host 192.168.1.10 \
--mqtt-username homeassistant
启动约 5 s 内 HA 应自动创建:每节点一个 device、每设备 17+ entities(含 presence、人数、HR/BR、motion、fall、RSSI、zones 与 10 个语义原语)。优雅退出用 Ctrl-C(发布器会先向所有 availability 主题推 offline);kill -9 由 LWT 兜底,约 30 s 内同样生效。
10.2 验收命令(ADR-115 §8,测试 1–7 覆盖 MQTT,8–10 覆盖 Matter)
# 1. mock 源 + MQTT 启动
cargo run -p wifi-densepose-sensing-server -- \
--source mock --mqtt --mqtt-host localhost --mqtt-prefix homeassistant
# 2. 观察 discovery + state 消息(应见 presence/heart_rate/breathing_rate/motion/
# fall/person_count/rssi 每个节点每实体一条 config + 周期性 state)
mosquitto_sub -t 'homeassistant/#' -v
# 3. 全工作区测试套件
cd v2 && cargo test --workspace --no-default-features
# 4. discovery 负载 schema 校验
cargo test -p wifi-densepose-sensing-server --features mqtt mqtt::discovery::schema
# 5. 隐私模式剥离生物特征:订阅日志中不应出现 heart_rate/breathing_rate/pose
cargo run -p wifi-densepose-sensing-server -- --source mock --mqtt --privacy-mode &
mosquitto_sub -t 'homeassistant/#' -v | tee /tmp/privacy.log
grep -E "(heart_rate|breathing_rate|pose)" /tmp/privacy.log # 期望为空(exit 1)
# 6. HA 端到端(手动,见 docs/integrations/home-assistant.md)
# 7. LWT:运行后见 online;kill -9 后 30 s 内所有 availability 主题变 offline
# 8. Matter Bridge 配对(P7 之后)
cargo run -p wifi-densepose-sensing-server -- \
--source mock --matter --matter-setup-file /tmp/matter-qr.txt
# 期望:打印 setup code + QR;桥经 mDNS 广播
# 9. Matter 跨控制器:同一 QR 分别配入 Apple Home 与 HA Matter,
# 触发 mock presence 变化,期望两控制器 1 s 内 occupancy 翻转
# 10. Matter 隐私不变量:MQTT 可发布 HR(无 --privacy-mode),
# Matter 永不暴露 HR cluster(规范无对应 cluster)
仓库侧已有对应集成测试 tests/mqtt_integration.rs(mqtt feature 下运行),discovery 模块内含 schema/路径形态的单元测试。
10.3 排障速查(详见 docs/integrations/home-assistant.md)
- HA 无实体:
mosquitto_sub -h <broker> -t 'homeassistant/#' -v看是否有每实体一条config;有 config 但 HA 无设备,则检查 MQTT 集成是否指向同一 broker; - 实体有但状态不更新:确认
sensing-server实际收到 CSI 帧(日志[ws]/[edge_vitals]行),用wscat -c ws://localhost:8765/ws/sensing验证广播通道;诊断期可临时--mqtt-rate-vitals 1.0; - "Plaintext MQTT on non-localhost broker" WARN:v0.7.0 警告并继续,v0.8.0 将硬失败——要么加
--mqtt-tls+ CA,要么把 broker 挪到 localhost; - Matter 配对失败:检查
--matter-setup-file中的 setup code、确认宿主与控制器同一 WiFi 子网;Apple Home 提示未知厂商属预期(开发 VID0xFFF1),选 "Add anyway"。
11. 风险、收益与备选方案(承接原文档)
收益:HA 用户零代码接入;经 Matter 触达 Apple Home / Google Home / Alexa / SmartThings(把可寻址市场放大到非 HA 用户);与自有 UI 解耦(HA / Grafana / Node-RED 可在同一 MQTT firehose 上自建仪表盘);--privacy-mode 提供合规场景的"一键剥离";Matter fabric 隔离在架构上杜绝控制器窃取生物特征。
成本:rumqttc 新运行时依赖(feature 门控、默认关闭);Matter SDK(约 5 MB,仅开启时)与 CSA 规范版本漂移的年审;HA 与 Matter 两侧 schema/版本演进需按发布 pin 版本并在 docs/integrations/home-assistant.md 记录"tested against"矩阵;CI 需 mosquitto 容器 + HA schema 校验 + chip-tool 模拟器;CSA 会员费($3 k/年)仅决定正式厂商 ID,开发期用 0xFFF1。
主要风险与缓解(均已在 ADR-115 §7 记录):主题命名空间冲突靠 wifi_densepose_ 前缀 + MAC 派生 id 缓解;HA schema 变更靠 pin 版本 + CI schema 校验;pose 带宽放大靠默认关闭 + 限速;生物特征泄漏靠 --privacy-mode 源头剥离 + 明文 WARN;动态 per-track 实体基数爆炸靠上限 10 + discovery payload="" 删除约定;Matter SDK 不成熟靠 P7 三控制器试配对 + chip-tool FFI 回退。
备选与互补路径:HACS Python 集成(hass-wifi-densepose,经既有 /ws/sensing WebSocket + /api/* REST 与 config-flow,约 4–6 周,留待 MQTT 落地数据评估);REST webhook 已被否决(单向、无实体发现、无 LWT,不满足即插即用);mDNS/Zeroconf(#574)与 MQTT 正交互补——mDNS 解决"broker 在哪",MQTT auto-discovery 解决"建哪些实体"。
12. 结论
ADR-115 是 RuView 从"又一个感知平台"走向"任何 HA 安装与任何 Matter 控制器家庭均可即插即用升级件"的集成叙事:MQTT 承载丰富且有差异化的遥测(含生物特征与姿态),Matter 以标准簇把存在/人数/跌倒子集带到每个控制器生态;两者由 unique_id 去重、由同一语义推理总线驱动、由 --privacy-mode 在集成边界执行生物特征剥离。从 ADR-115 到 operator guide、指标文档、mqtt 模块、matter 模块、semantic 模块 与 blueprint 样例,构成了一条从架构决策到可运行部署的完整证据链。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0627
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00