蓝牙 Mesh 配网成功,为什么灯还不受控?从 Provisioning 到模型绑定
Bluetooth Mesh 的 Provisioning 成功为什么不等于可以控制?从 NetKey、AppKey、DevKey 到模型绑定、单播、发布订阅与状态回读,梳理新设备真正可用之前的配置流程。
设备出现在扫描列表里,点一下“添加”,日志提示 Provisioning 成功。网关里多了一条记录,看起来已经大功告成。
接着发出开灯命令,灯却没有反应。
这时候很容易先怀疑无线信号、芯片兼容性,或者串口发错了。但在 SIG Mesh 里,还有一个更应该先检查的问题:设备加入了网络,不代表它已经配置好怎样参与应用。
上一篇讨论自定义广播怎样演进成多跳网络。这篇回到标准方案,用“控制器接入一盏灯”这个例子,把发现、Provisioning、密钥、模型绑定和发布订阅接起来。
这里的流程用于解释机制,不是一份已经完成的实机测试报告,也不依赖某款芯片的串口命令格式。

看到设备,只能说明它正在等待接入
尚未加入 Mesh 网络的设备,可以通过 Unprovisioned Device Beacon 表明自己可以被配置。手机或网关发现它,再由承担 Provisioner 角色的一方启动流程。
Provisioner 是一种角色,不必永远是手机,也不必与网关绑定。产品可以把配网、网络配置和日常控制做在同一个程序里,但理解协议时最好先把这些职责分开。
扫描到设备,并不能证明它就是你准备添加的那盏灯。广播可以帮助发现目标,真正的接入还需要身份确认和安全过程。
如果附近有多盏同型号的灯,用户怎样认出目标?是按键进入配网、扫描产品提供的信息,还是通过设备支持的输入输出方式确认?这个交互最好在产品设计时想清楚,不要等到现场出现一串相似名称再补。
Provisioning 给设备的是网络身份
Provisioning 不只是把一个密码写进设备。
Provisioner 与设备会交换能力,选择支持的认证方式,完成公钥相关交换和认证,再安全地建立加入网络所需的状态。设备的输入输出能力、所选认证方式和实现,都会影响这个过程;“通信经过加密”不能代替对接入对象的确认。
完成后,设备成为一个 Mesh 节点。它拥有初始 NetKey、IV Index、分配的单播地址等信息,也建立了自己的 DevKey。
这里有个值得记住的细节:DevKey 由双方分别计算得到,不是作为明文配置项在空中发送给设备。 它与网络共享的 NetKey 承担不同职责。
到这一步,节点有了网络身份。但是“用哪个应用密钥控制灯”“哪个模型接受开灯命令”“要监听哪个灯组”,通常还没有全部配置完成。
所以我更愿意把界面上的这个状态叫作“已入网,待配置”,而不是直接标成“添加成功,可使用”。
三把钥匙,各管一层事情
Mesh 文档里很容易同时遇到 NetKey、AppKey 和 DevKey。如果只把它们都理解成“蓝牙密码”,后面的配置就会越来越难排查。
| 密钥 | 主要职责 | 不代表什么 |
|---|---|---|
| NetKey | 建立网络或子网层面的安全关系,支持网络层处理 | 持有它不等于能解读所有应用消息 |
| AppKey | 保护特定应用的消息,配合模型绑定参与业务通信 | 写入节点不等于所有模型都已能使用它 |
| DevKey | 保护针对该节点的配置通信 | 不应当作整个灯组共享的日常控制密钥 |
为什么要分开?设想走廊里的一盏灯兼任中继,帮助转发别的设备的消息。它需要处理网络层信息,但不应该仅因为承担中继,就能读取所有应用内容。
NetKey 与 AppKey 的分工,让“帮助传递”和“理解业务”可以分开。能转发一条消息,并不能证明设备具备执行那条应用命令的权限和模型。
另外,日志里的 AppKey Index 是索引,不是密钥本身。排查时只看两个地方都写着同一个数字,并不能证明它们装载的密钥值和上下文真的一致。应从可信的配置记录核对映射,不要把实际密钥打印进普通日志或截图。
先读设备组成,别猜灯住在哪个地址
接下来,由 Configuration Client 与节点的 Configuration Server 交互,读取和修改节点配置。
先读 Composition Data 很有价值:它会告诉我们节点有哪些元素、每个元素实现了哪些模型,以及相关的能力信息。
节点、元素、模型不是同一层东西。 一个外壳通常让用户觉得它是一台设备,但内部可以有多个可独立描述的元素,每个元素又可以包含多个模型。
例如一台多路控制器,几路功能怎样分布,需要看实际 Composition Data,不能假定每个通道都在主元素,也不能只用“设备主地址+开关命令”控制所有通道。地址分配也要为节点的元素预留适当空间,避免不同节点占用冲突。
对这篇里的单灯例子,我们先确认灯所在的元素,以及它是否提供 Generic OnOff Server。控制器这边则需要能够发送相应消息,并处理需要的状态响应。
能发现一个设备,甚至能给它完成 Provisioning,都不能证明它支持你想要的业务模型。模型找错了,继续调整发射功率也解决不了。
AppKey Add 和 Model App Bind,是两件事
这是“已入网却不能控制”最值得优先检查的地方。
第一步,把所需 AppKey 添加到目标节点,并指定相应的 NetKey 关联。
第二步,把这个 AppKey 绑定到需要使用它的应用模型。
这两步不能互相代替。密钥已经存在于节点中,不代表某个模型已经接受这把密钥保护的业务消息。反过来,如果绑定目标的元素或模型选错了,配置记录看起来有变化,也不能说明真正的灯控模型配置正确。
控制端同样需要正确的应用密钥和相应模型配置。只配置灯、不配置发送方,依旧无法形成完整的通信关系。
这不是说所有模型都要绑定 AppKey。用于管理配置的 Configuration 模型使用 DevKey,不能照着灯控模型的方式一概处理。
在 Silicon Labs 的配置客户端 API里,添加 AppKey 和绑定模型就是两个独立操作,各自有结果事件。这个拆分很能说明问题:本地接口接受了请求、远端返回了配置结果、设备已经具备目标能力,是三个需要分别确认的事实。
不要看到主机函数返回成功,就马上把下一阶段全部标成完成。需要按所选 SDK 的约定等待对应结果,核对节点、元素、模型和状态码。超时表示结果尚不确定,不一定表示远端完全没有执行。
先让单盏灯响应,再把它放进灯组
排查时,我会先走一条最短路径:向已确认的灯控元素发送单播命令,观察对应状态响应。
单播的目的地址已经指向具体元素,不需要先把它加入一个组地址的订阅列表,才能控制它。 同样,对于支持显式指定目标的发送接口,也不能把“必须先设置模型发布地址”当成所有发送方式的前提。
如果单播已经能工作,再引入分组,问题就容易定位得多。
比如我们希望墙上的开关同时控制几盏灯,可以安排一个表示“走廊灯”的组地址:
- 开关上的相关客户端模型向这个组地址发布控制消息;
- 各盏灯的相关服务器模型订阅这个组地址;
- 参与通信的两端使用匹配的 AppKey 和模型配置。
以后增加一盏灯,完成入网与应用配置,再让它订阅同一组,就可以参与控制,不必逐个修改开关中的目标设备名单。
注意,组名只是管理界面给人的提示。“走廊灯”这几个字并没有自动建立订阅关系。订阅配置针对的是节点上的具体模型,不能把“在 App 里拖进同一个房间”直接等同于无线侧已经完成了组配置。
发布地址也决定了状态往哪里走
控制命令的方向只是整个系统的一半。
灯被网关控制后,可以对需要响应的请求返回状态;设备本地按键改变了状态,又可能需要主动上报。这两种路径不能混为一谈。
模型的发布配置可以包含目标地址、使用的 AppKey,以及模型和实现支持的相关发布参数。但配置发布目的地,并不意味着所有模型都会按你想象的周期自动上报,也不意味着所有本地变化都已被应用正确处理。
因此,“网关能开灯”和“网关始终知道灯的当前状态”应分开验收。
做 Matter 桥接时,这一点尤其重要。如果墙壁开关改变了灯的状态,网关却一直保存旧值,上层 App 显示的就只是上一次下发的命令,而不是最新的设备报告。
即便收到了状态报告,也要尊重设备的观测边界:控制器报告输出已开启,不一定证明实际灯光正常,除非产品有相应的物理反馈能力。
不要把配置流程写成一串只会向前跑的命令
真实现场里,配到一半断电、某一步响应丢失、主机重启,都是需要处理的情况。
如果程序只是依次发送“加密钥、绑模型、加订阅、设发布”,中间失败后就很难知道该从哪里继续。更合适的方式,是记录期望配置和已确认的结果,并在恢复时读取必要的状态,再补齐差异。
例如 AppKey 添加请求超时后,先按协议和 SDK 能力核对远端状态,再判断是否需要重试。重复操作的行为要依照具体命令处理,不能假定所有配置操作重复执行都没有副作用。
管理端也需要持久保存地址分配、节点身份和必要的密钥及配置记录,并做好访问控制和备份。否则设备还在原来的网络里,管理端却忘了怎样管理它,后续就会变成恢复问题。
恢复出厂设置不是排查任何错误的第一选择。它会改变设备状态,还可能打断现有绑定。先区分“设备真的未入网”“已经入网但未配置”和“配置完成但管理端记录丢失”,通常能少走很多弯路。
看见什么现象,就往哪一层查
| 现象 | 优先检查 |
|---|---|
| 扫描得到,但 Provisioning 失败 | 接入模式、承载支持、认证方式及双方报告的失败原因 |
| Provisioning 成功,后续配置超时 | 地址、DevKey 和网络上下文、无线可达性、响应关联;低功耗节点还要考虑接收时序 |
| 配置能完成,但单播不能控制 | 元素地址、模型能力、AppKey 添加与绑定、发送方配置 |
| 单播正常,组控不响应 | 实际目标组地址、目标模型订阅、密钥与发送配置 |
| 能控制,界面状态却不更新 | 请求响应、主动发布、接收处理和上层状态映射 |
| 重启后失效 | 主机与节点的持久化、地址记录、配置恢复和密钥上下文 |
这张表给的是排查顺序,不是仅凭症状就能确定的故障结论。最终仍要结合状态查询、日志和必要的抓包,确认消息停在哪一步。
第一次验证,也不必把所有功能一起打开。可以先证明单播控制与状态回读,再验证组控、设备本地变化后的上报,最后测试中途断电与重启恢复。每一步都留下明确的成功条件,比最后只记录一句“灯亮了”更有用。
对网关来说,“添加设备”是一段流程
用户看到的可以只有一个添加按钮,底层却需要维护好几个状态:发现目标、完成 Provisioning、识别设备组成、应用配置就绪、控制与状态验证通过。
把这些阶段分开,并不是要让用户理解所有协议细节,而是让程序能够如实报告:现在完成了什么,哪里还没完成,失败后可以从哪里继续。
SIG Mesh 为这些工作提供了共同机制。它没有承诺只要配网成功,所有品牌、所有模型、所有生态就会自动互通。对网关开发来说,真正需要补齐的,正是从“一个节点加入网络”到“一个设备可以被可靠管理”的这段过程。
下一篇再回到小米 Mesh:当标准网络和设备模型已经存在,米家接入又增加了哪些产品定义、身份和平台要求?
参考资料
- Bluetooth SIG:The Bluetooth Mesh Networking Primer,重点参见地址、发布订阅、密钥、Provisioning 与 Configuration 章节。
- Silicon Labs:Configuration Client API,可对照读取组成数据、添加应用密钥、模型绑定、订阅和发布配置等操作。具体调用以采用的 SDK 版本为准。