不买硬件,先用电脑和手机把 Matter 网关跑通
开发板还没到,先用一台 Windows 电脑当网关、一部手机装 nRF Connect 当蓝牙设备,在 Apple Home 里把 Matter 桥接的配对、下行控制和上行状态都跑通,附广播格式和踩过的坑。
上一篇讲了整体方案:在蓝牙设备和 Apple Home 之间加一台 Matter 网关,让网关把两边的消息互相翻译。
方案写在纸上都很顺。真动手之前,我最想先确认一件事:Apple Home 真的能认出一台自己写的网关,并通过它控制下面的蓝牙设备吗?
这件事不需要等硬件。开发板还在路上,我先用手头现成的东西,一台 Windows 电脑加一部手机,把整条链路跑了一遍。
先跑软件,再上硬件
做硬件项目,很容易一上来就买板子、焊模组、刷固件。问题是链路一长,出了问题很难判断是哪一层的错:是 Matter 配对没成功,是网关程序有 bug,是串口丢了字节,还是蓝牙信号不好?
先用软件把最上面两层走通,后面换上真硬件时,要排查的范围就小多了。而且这一步几乎零成本,有电脑和手机就能做。
谁来扮演谁
| 角色 | 在真实产品里 | 在这次演示里 |
|---|---|---|
| 控制端 | Apple Home | Apple Home(真的) |
| 网关 | Linux 网关板 + 蓝牙模组 | Windows 电脑,用电脑自带的蓝牙 |
| 蓝牙设备 | 开关、灯 | 手机,装一个 nRF Connect |
Apple Home 是真的,网关程序也是后面要用在产品里的那一份,只有最底下的「蓝牙设备」是手机扮演的。
nRF Connect 是 Nordic 出的免费蓝牙调试工具,Android 和 iPhone 都有。它能扫描周围的蓝牙广播,也能自己发广播,正好用来扮演设备。
为什么不直接模拟蓝牙 Mesh 设备
真实产品里,设备和网关之间走的是 SIG Mesh。但手机扮演不了 Mesh 设备:Android 和 iOS 都没有开放「当一个 Mesh 节点」的能力,nRF Mesh 这类 App 只能当配网工具和遥控器。
所以演示里我换了个更简单的办法:设备和网关之间直接用明文蓝牙广播通信。网关想开灯,就广播一条「开」;设备状态变了,也广播一条告诉网关。
这套格式没有加密,也不防重放,只用来验证链路,不会用在产品里。它的价值在于:除了最底层的通信方式,网关里的其他部分都是真的,包括 Matter 配对、设备表、命令翻译和状态同步。
演示用的广播格式
格式越简单越好,用手机 App 就能手动拼出来。
网关 → 设备(下行):一条厂商数据(Manufacturer Data),Company ID 用 0xFFFF。这是蓝牙联盟留给测试用的编号,不能用在正式产品上。
| 字节 | 内容 | 例子 |
|---|---|---|
| 1~2 | 固定的 GW |
47 57 |
| 3~4 | 设备地址,小端 | 02 00 表示 0002 |
| 5 | 开关状态 | 01 开,00 关 |
| 6 | 序号,每次加 1 | 05 |
设备 → 网关(上行):Android 和 iPhone 各用一种写法。
- Android:同样发厂商数据,Company ID 填
0xFFFF,数据填4456020001。4456是DV,0200是地址 0002,最后的01表示开。 - iPhone:iOS 不允许 App 在广播里放自定义的厂商数据,只能改设备名。所以把设备名设成
DV0002:1,意思是地址 0002、开。
网关端的解析也就几行,两种写法都认:
pub fn uplink(sections: &[(u8, Vec<u8>)]) -> Option<(u16, bool)> {
sections.iter().find_map(|(t, d)| match (*t, d.as_slice()) {
// Android:厂商数据 FF FF 'D' 'V' 地址 状态
(0xFF, [0xFF, 0xFF, b'D', b'V', a0, a1, on, ..]) => {
Some((u16::from_le_bytes([*a0, *a1]), *on != 0))
}
// iPhone:设备名 DV0002:1
(0x08 | 0x09, name) => {
let s = std::str::from_utf8(name).ok()?.strip_prefix("DV")?;
let (addr, on) = s.split_once(':')?;
Some((u16::from_str_radix(addr, 16).ok()?, match on {
"1" => true,
"0" => false,
_ => return None,
}))
}
_ => None,
})
}
网关程序
网关用 Rust 写,Matter 部分用的是开源的 rs-matter。电脑上的蓝牙收发调的是 Windows 自带的蓝牙接口,不用装额外驱动。
程序启动后做三件事:
- 对外当 Matter 网关:在局域网里广播自己,等 Apple Home 来配对。没配对过的话,终端里会直接打印出配对二维码。
- 维护设备表:在终端里输入
add 0002 客厅灯,就加了一盏灯。每个设备在 Matter 里是一个独立的「桥接设备」。 - 收发蓝牙广播:Apple Home 发来命令,就翻译成下行广播发出去;扫到手机的上行广播,就更新状态,同步回 Apple Home。
设备表和配对信息都存在本地文件里,重启程序后不用重新配对。
在 Apple Home 里添加
用 iPhone 的「家庭」App 扫终端里的二维码就能添加。有几点要注意:
- 会提示「未认证的配件」。开发阶段用的是 Matter 官方提供的测试证书,没有经过认证,iOS 会提醒一下,选「仍然添加」即可。量产时要换成认证后的正式证书。
- 电脑和 iPhone 要在同一个局域网,Windows 防火墙要允许这个程序收发网络数据。配对超时的话,先查这一项。
- 家里要有家居中枢。Apple Home 控制 Matter 设备需要 HomePod 或 Apple TV 当中枢。
添加成功后,Apple Home 里会出现一个网关,下面挂着「客厅灯」「书房灯」,可以像普通的灯一样分别放进不同房间。
下行:在 Apple Home 里开灯
- 手机上打开 nRF Connect,进入扫描(Scanner)页面。
- 在 Apple Home 里点一下「客厅灯」。
- 电脑终端打印一行
BLE TX -> 0002,网关把这条命令广播 1 秒。 - nRF Connect 的扫描列表里会多出一个设备,厂商数据是
0xFFFF加4757 0200 01 xx,也就是「网关说:0002 号设备,开」。
电脑每次发广播用的蓝牙地址都可能变,列表里不好找的话,按厂商数据或信号强度筛一下。
上行:设备告诉 Apple Home
- 在 nRF Connect 里新建一条广播(Advertiser):Android 填厂商数据
0xFFFF/4456020001;iPhone 把设备名设成DV0002:1。 - 开始广播。
- 电脑终端打印
BLE RX <- 0002 (客厅灯): ON。 - Apple Home 里的客厅灯变成开着的状态。
这一步模拟的是用户在墙上按了开关。它比下行更重要:如果设备状态不能回传,Apple Home 显示的就和实际对不上。
踩过的几个坑
整个过程不复杂,但有几个地方第一次做很容易卡住。
1. 手机广播的状态,会把刚关掉的灯又打开。 手机会不停地重复广播同一包数据。一开始网关每收到一次都更新状态,结果在 Apple Home 里关了灯,下一秒又被手机那包「开」改了回去。后来改成只有内容变化时才算一次上报,问题就没了。真实设备上也一样,重复的消息必须去重。
2. iPhone 的设备名在扫描响应里。 iPhone 广播时,设备名不在第一包广播里,而是放在「扫描响应」里。电脑默认的被动扫描收不到,要改成主动扫描。
3. 不能靠蓝牙地址识别设备。 手机和电脑发广播用的都是随机地址,过一阵就会换。所以设备身份放在广播内容里,也就是那两个字节的地址。这和 Mesh 的思路一致:Mesh 设备靠的也是分配给它的单播地址,不是 MAC。
4. Windows 同时开多个广播会互相干扰。 连续点几盏灯时,几条广播同时发会互相覆盖。改成排队,一条发完再发下一条。
5. 发广播会卡住 Matter。 Windows 发一次广播要持续一段时间,如果在 Matter 的处理流程里直接调用,这段时间里 Apple Home 发来的其他命令都得等着。所以发广播单独放到一个线程里。
6. 改了网关的制造商和型号,不用重新配对。 这些信息是 Apple Home 从网关读取的,网关重启后会带上新值。不过 Apple Home 有缓存,什么时候刷新说不准,急着看效果的话只能删掉重新添加。注意,删掉网关会连带删掉下面所有设备。
另外,程序刚编译出来时体积挺大,改成按体积优化、去掉调试信息后,发布版只有 2.3 MB 左右,放进网关板的存储里完全没压力。
这个演示证明了什么
证明了的:
- 自己写的网关能被 Apple Home 识别、配对;
- 桥接出来的设备能在 Apple Home 里单独控制;
- 下行命令和上行状态都能走通;
- 设备增删、断线后重启,Apple Home 里的状态能跟上。
还没证明的:
- 真实蓝牙 Mesh 的配网、加密和组网;
- 芯科模组和泰凌设备能不能互通;
- 在 Linux 网关板上的运行情况;
- 几十上百个设备同时在线时的表现。
换句话说,Matter 这一半已经验证完了,蓝牙 Mesh 那一半还要等真硬件。下一步就是把电脑上的明文广播,换成通过串口连接的蓝牙模组。网关程序里,这部分只是换一个适配层。
最后
这一步最大的收获,是在花钱买硬件之前,就确认了最关键的一件事:Apple Home 认可这个网关。后面遇到问题,至少不用再怀疑 Matter 这一层。
如果你也在做类似的网关,或者想在没有硬件的情况下先跑通 Matter,欢迎来聊,代码细节和踩过的坑都可以交流:linktr.ee/weiyii
演示代码正在整理成一个精简版本,准备开源,放出来后会更新到这篇文章里。