☰
如何做到 HA 与米家云同时在线不重复?MenuBarMijia 双源设备去重算法完整解析
2026/11/6 1:38:58 网站建设 项目流程

【免费下载链接】MenuBarMijia

Control Xiaomi Mijia from your Mac menu bar or Windows tray. Home Assistant supported on macOS.

项目地址:https://gitcode.com/gh_mirrors/me/MenuBarMijia
点击查看免费下载

MenuBarMijia 是一款 Mac 菜单栏 / Windows 托盘的小米米家控制工具,支持同时接入 Home Assistant 与米家云直连两条数据源。它的双源设备去重算法(Join Key 多级匹配 + 整卡级择优评分)让同一台物理设备只出现一张卡片,并在家网络断开时自动无缝回落到云端,无需手动切换。

🎯 这篇文章用尽量少的代码,把「键怎么设计、分数怎么打、赢了怎么路由」讲清楚。

一、为什么"两边都在线"会出重复设备?

MenuBarMijia 的两种连接方式各有优势:

数据源优势短板
Home Assistant(局域网 WebSocket)低延迟、实体能力全(TTS、场景、传感器)必须部署、离开家庭网络即不可达
米家云端直连手机扫码即用、外网可远程控制新型号依赖 MIoT 云端能力,延迟略高

如果简单把两边设备列表相加,同一台空调会出现两张卡片;如果把两边字段硬拼进同一张卡片再混发指令,乐观锁、撤销快照和状态回读会在两个不同步的数据源之间产生竞态撕裂。

设计决策记录在 docs/adr/0008-dual-source-device-deduplication.md,核心结论是三个词:配对、整卡、路由——先判定"是不是同一台设备",再整卡选出唯一胜出的数据源,最后所有指令只从胜出方下发。

⚠️ 注意:跨源合并目前仅在 macOS 端执行。Windows 端支持 Home Assistant、米家云与演示模式三选一单源切换。

二、键设计:两级身份匹配(Join Key)

"两台设备是不是同一台"是整个算法的地基。MenuBarMijia 采用多级降级匹配,匹配逻辑在 Sources/MijiaCore/DeviceDeduplicator.swift。

2.1 一级:硬件标识精确匹配

解析 HA 设备注册表的identifiers与connections(含实体unique_id),用三种硬证据配对:

  1. 小米did:官方xiaomi_home集成把标识符写成<server>_<did>(如cn_123456789),xiaomi_miot则直接用裸did。MenuBarMijia 的规范化器 DeviceSourceIdentity.swift 会把这些变体拆解、小写化后还原出did候选集合;
  2. MAC 地址:去掉分隔符、转小写成 12 位十六进制后比对;
  3. 配对顺序上先跑did轮、再跑 MAC 轮,避免共享网关 MAC 抢走子设备的精确did匹配。

只有恰好一对一命中才会配对;一台 HA 设备匹配到多台米家设备时直接放弃该轮,宁可慢也不错配。

2.2 二级:同房同款唯一兜底

很多 HA 集成并不写入硬件标识。此时退到启发式规则:归一化后的同一房间内,两边各仅有唯一一台相同型号(或相同归一化名称)且相同类别的设备,才自动归并为一台。

关键设计是拒绝猜测:同房间有两台同款"小米灯"时不合并,两张卡片会原样保留,留给人工判断。兜底键的构造见 DeviceDeduplicator.swift,格式为「前缀:房间|归一化值|类别」,同名多实例会被计数排除。

三、评分策略:整卡级择优,而不是拼字段

配对成功后,两张候选卡片必须选出一个"胜出方"。规则按优先级排列(实现见 preferredCandidate):

优先级规则用户价值
① 在线优先一边在线一边离线,直接选在线方在家走 HA 低延迟;出门 HA 断连,同一张卡自动切到米家云
② 能力评分两边都在线时,按可控特性项数量打分,分高者胜自动挑"能控得动更多东西"的那一端
③ 同分 HA 优先分数相同时选局域网的 Home Assistant稳定偏向低延迟路径

能力评分(capabilityScore)怎么做?它对每种设备类别逐项累加"这张卡实际暴露的可控/可读特性",例如:

  • 🎙️ 音箱:媒体播放 +1、TTS 播报 +2、文本指令 +2、静音/睡眠等实体各 +1;
  • 💡 灯光:开关 +1、亮度 +1、色温 +1、灯效列表非空 +2;
  • 🌬️ 空调:开关/温度/模式/风速/摆风/室温各 +1;
  • 🔌 插座:开关 +1、功率 +1、电量统计 +1、童锁 +1。

评分是卡级的:不会把 HA 的亮度字段和米家云的 TTS 字段拼成一张"缝合卡"。这样HomeStore的 3 秒乐观锁、逆向指令撤销与批量操作语义完全不用重写。

胜出后还有两个贴心细节:

  • 房间互补:胜出方没分配房间、另一方有明确房间时,自动借用对方的房间归属;
  • 手动固定:卡片右键可把来源固定为 HA 或米家云;固定只有在该源在线时才生效,离线仍走自动回退。

四、Canonical ID:切换来源时设置不丢

设备源来回切换最怕的是"星标、排序、卡片大小、自定义分组全乱了"。MenuBarMijia 给配对成功的双源设备分配一个统一稳定主键(Canonical ID),注册表定义在 DeviceSourceIdentity.swift。

它的键集合同时包含pair:HA id|米家 id、ha:HA id、mi:米家 id、共享的did:与mac:前缀键——只要任意一个键能对上,卡片就复用历史主键。再配合偏好 ID 记忆(用户已在米家源下收藏过某设备时优先沿用米家 ID),两端互相回退时收藏、排序、重命名完全保留。

五、路由层:一张卡只认一个后端

合并不是终点。DualSourceHomeProvider.swift 持续监听两条数据流,任何一端快照或连接状态变化都会重跑去重合并,并为每张卡记录当前路由(后端 + 源端设备 ID):

  • 控制指令只发给胜出方,撤销逆操作也由同一后端生成;
  • 状态回读、传感器历史、摄像头取流全部按路由转发;
  • 摄像头流遇到路由切换时先停旧流再开新流,不会两条流叠播。

六、如何在你的 Mac 上体验双源去重

  1. 打开菜单栏面板的偏好设置 →「连接」页,分别填写 Home Assistant 服务器地址 + 长期访问令牌,并点击「扫码登录米家账号」完成云端直连;
  2. 两端配置完成后无需额外开关,应用会自动并行连接并合并重复设备;
  3. 面板底部状态栏展示双源连接状态,右键卡片可查看/固定当前驱动来源。

合并后,面板上每台设备只有一张卡片,常用控制、场景胶囊与全关动作照常工作:

七、延伸阅读

想深挖 HA 侧identifiers/connections线格式与各小米集成的写入差异,项目内有一份源码级调研文档:docs/research/ha-xiaomi-device-identity.md。配对与评分的回归用例在 Tests/MijiaCoreTests/DualSourceMergeTests.swift,双端集成测试见 Tests/MijiaCoreTests/DualSourceIntegrationTests.swift。

模块文件
去重合并核心Sources/MijiaCore/DeviceDeduplicator.swift
身份规范化与主键注册表Sources/MijiaCore/DeviceSourceIdentity.swift
双源 Provider 与指令路由Sources/MijiaCore/DualSourceHomeProvider.swift
设计决策记录docs/adr/0008-dual-source-device-deduplication.md

一句话总结:用硬件标识说话、用能力评分决胜负、用稳定主键守设置——这就是 MenuBarMijia 让 HA 与米家云同时在线却从不重复的完整思路。

【免费下载链接】MenuBarMijia

Control Xiaomi Mijia from your Mac menu bar or Windows tray. Home Assistant supported on macOS.

项目地址:https://gitcode.com/gh_mirrors/me/MenuBarMijia
点击查看免费下载
上一篇:Readest Android 启动崩溃修复实录:Reading Widget 缩略图 1 像素封面引发的 `width must be > 0` 进程崩溃分析
下一篇:brpc Dummy Server 实战指南:为纯 Client / 无 RPC 程序挂载内置服务与 bvar 监控

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询