智能家居 ·

用 Rust 写 Matter 网关:怎么让 Apple Home 看到网关下面的设备?

用 Rust 和 rs-matter 开发 Matter 网关:记录桥接设备的端点、设备表、开关控制、状态上报与数据保存,以及原型尚未验证的部分。

上一篇,我们用电脑和手机做了一次演示:没有等开发板,也没有接真实的蓝牙 Mesh 模组,先让自写的网关接入 Apple Home,再用手机模拟一盏灯。

这次往代码里走一步,聊聊网关的 Matter 部分是怎么搭起来的。

我用的是 Rust 实现的 Matter 协议库 rs-matter。先说明一下进度:这还是一个原型。Matter 配对和桥接设备展示已经在演示里验证过;真实蓝牙 Mesh 互通、Linux 开发板运行和大量设备同时在线,还需要后续验证。

网关不是一盏大灯

做网关时,第一个问题是:一台网关下面有很多设备,Apple Home 应该怎么看到它们?

比如家里有三盏蓝牙灯,用户希望在 Apple Home 里分别看到客厅灯、卧室灯和书房灯,而不是只看到一个叫“蓝牙网关”的开关。

在这个原型里,网关作为一个 Matter 节点出现,下面再为每个被桥接的设备建立一个端点:

Matter 网关
├── 端点 0:网关自身的基础功能
├── 端点 1:聚合器
├── 端点 2:客厅灯
├── 端点 3:卧室灯
└── 端点 4:书房灯

端点可以理解成网关对外展示的一个功能或设备入口。每个灯端点里再配置相应能力,比如开关状态和桥接设备信息。

一盏灯,需要告诉控制端什么?

网关不能只说“我这里有个 2 号设备”,还得告诉控制端:它是什么、能做什么、现在是什么状态。

原型给每盏灯配置了设备类型,以及 Descriptor、On/Off、Bridged Device Basic Information 和 Groups 等 Cluster。说得直白一点,分别要回答三件事:

  1. 这是哪一类设备?
  2. 它提供哪些功能,比如开关和切换?
  3. 它现在是什么状态,比如灯是否开启、设备是否可达?

这样 Apple Home 才能把它当作一盏可操作的灯来展示,而不只是一个编号。

网关里先有一张设备表

Matter 端点是对 Apple Home 展示的那一面。网关内部还得知道:这个端点对应哪盏设备。

原型里有一张简化的设备表,记录端点号、设备地址、名称、当前开关状态和是否可达。例如:

端点 2 → 地址 0003 → 客厅灯 → 当前关闭
端点 3 → 地址 0004 → 卧室灯 → 当前开启

Apple Home 发来“打开端点 2”的命令时,网关就能查到要操作哪盏灯。

真实产品不能只靠这些数据。配网信息、设备能力、密钥和故障处理都需要继续设计。现在这张表只负责先把 Matter 端点和下层设备对应起来。

点一下开关,网关里发生了什么?

以 Apple Home 打开客厅灯为例,原型中的流程是:

Apple Home 点击「开」
        ↓
Matter On/Off 处理器收到命令
        ↓
按端点号找到设备
        ↓
更新本地状态并发送下层控制命令
        ↓
收到设备状态后,以返回结果更新状态

这里用的是乐观更新:收到命令后,网关先把本地状态改成“开”,再发送控制命令;之后如果收到设备状态,就用上报结果修正。

好处是界面响应直接。但如果设备没有收到命令,也没有返回状态,界面可能暂时显示“已开”,实际灯还是关的。

所以后面接真设备时,还要处理超时、重试、主动查询和离线判断。按钮变亮,不等于真实设备一定执行成功。

设备变化,也要告诉 Apple Home

假设用户走到墙边,按下实体开关。如果网关不把变化报告上去,Apple Home 就会一直显示旧状态。

原型的反向流程是:收到状态上报后,根据设备地址找到对应端点,更新设备表,再通知 Matter 属性变化。

前一篇的手机演示中,我们还碰到一个具体问题:手机会重复广播同一条状态。如果每收到一次都当成新变化,可能出现 Apple Home 刚把灯关掉,旧广播又把状态改回去。演示里因此加了去重:内容没有变化,就不重复当成新状态处理。

这里的手机明文广播只是演示手段,不能当作真实蓝牙 Mesh 状态上报已经验证。

设备可以增删,端点号怎么处理?

用户可能今天加一盏灯,明天又删除一个开关。原型支持运行时增删设备:新增时分配端点号,更新设备表和 Matter 对外展示的端点结构,再发送变化通知。

我在原型里采用了一个保守做法:端点号递增,删除设备后不马上把旧号码分配给新设备。

比如端点 2 原来是客厅灯,删除后立刻分给另一台设备,控制端可能还留有旧设备信息。不同控制端的表现还需要分别测试;现阶段先避免立即复用,设备映射也更容易追踪。

这并不是已经解决了长期运行的端点管理。频繁增删、备份恢复和端点号耗尽等问题,后续都要继续考虑。

重启以后,设备不能全忘了

设备加进来以后,网关一重启就消失,显然不行。

当前原型把端点号、设备地址和名称写入本地设备表;Matter 自身数据则使用 rs-matter 的持久化存储。写设备表时,先写临时文件再改名替换,减少直接覆盖时写到一半造成损坏的风险。

这还不是完整的断电保护方案。原型恢复的是基本映射;启动后设备真实状态仍需要重新确认。以后接入真实 Mesh 后,配网信息和密钥怎么安全保存、备份和恢复,也要单独处理。

编译体积和设备信息

在电脑上做原型时,编译出来的程序大一点不算什么;以后放进网关板,就需要留意存储占用。当前项目的 Rust release 配置启用了体积优化、LTO 和符号裁剪。此前在电脑上的一次构建约为 2.3 MB;换平台、工具链或功能后,大小还要重新测。

制造商、产品名和版本信息也可以在网关配置中设置。前面的演示里,修改部分显示信息后不一定要重新配对,但 Apple Home 可能缓存旧信息,刷新时机也不能保证。测试证书和正式设备证书是不同阶段的事,做正式产品时还需要按实际认证要求配置。

目前做到哪一步?

前面的演示已经验证:自写网关能被 Apple Home 识别和配对;模拟设备可以作为独立设备展示;下行命令和模拟设备的上行状态可以走通,也测试了设备增删与重启后的基本表现。

还没有验证的包括:真实蓝牙 Mesh 互通、目标 Linux 开发板运行、通信异常下的可靠性,以及几十上百台设备同时在线时的表现。当前仍是开发原型,也不能把测试配置当成正式认证结果。

下一步,最想验证的是把软件模拟部分换成真实蓝牙模组:网关发出的命令能不能到设备,设备状态能不能稳定回到 Apple Home,断开和重连之后又会发生什么。等硬件和软件路径跑起来,再把实际遇到的问题继续记录下来。

如果你也在做 Matter Bridge、蓝牙 Mesh 网关,或者正在用 Rust 写智能家居设备,欢迎交流:联系入口。

微信扫码阅读与分享

本文链接二维码

扫码打开,再从微信右上角分享。