1. 蓝牙Mesh概述:协议栈架构、节点类型与角色定义
各位同学好,我是老周。做蓝牙开发十几年了,从经典的BR/EDR到BLE,再到Mesh,一路踩坑过来。今天咱们开始聊蓝牙Mesh,这门课的核心是休眠唤醒与低功耗设计,但开篇得先把地基打牢——协议栈长什么样、节点分几种、角色怎么定。这些东西搞不清楚,后面讲休眠策略你肯定听得云里雾里。
1.1 蓝牙Mesh协议栈架构
蓝牙Mesh的协议栈,说白了就是分层的。每一层只管自己的事,上层调下层,下层给上层服务。我刚开始看规范时也觉得层数多,但实际做项目后发现,这种分层设计特别适合低功耗场景——你想让哪层休眠、哪层唤醒,边界很清楚。
来看这张图,我手绘的,别嫌丑:
从上往下看,一共七层。我挑几个重点说说:
- Model Layer:你写业务逻辑的地方。比如灯的开/关、调色温,都在这一层定义。说白了,这是离你最近的一层。
- Foundation Model Layer:Mesh网络的基础服务,比如配置、健康检查。你想想看,一个新设备入网,谁来给它分配地址?就是这层干的。
- Access Layer:把应用数据打包成消息,加上操作码。嗯,这里要注意,消息大小有限制,后面讲分段传输时会细说。
- Upper/Lower Transport Layer:负责消息的分段与重组、加密与认证。我在项目中遇到过,消息太长被截断,接收端拼不回来——就是下层传输层没处理好。
- Network Layer:最核心的一层。消息转发、中继、地址过滤全在这。低功耗节点的休眠唤醒,主要就是跟这一层打交道。
1.2 节点类型与角色定义
蓝牙Mesh里,节点不是千篇一律的。根据功能不同,分了好几种角色。你想想看,一个智能灯泡和一个墙壁开关,它们需要的功能能一样吗?灯泡可能一直在线,开关可能用电池供电,得省电。
规范里定义了四种节点角色,我整理了一张表:
| 角色 | 功能描述 | 典型功耗 | 是否支持休眠 |
|---|---|---|---|
| Relay Node | 中继消息,转发给其他节点 | 较高(常开) | 否 |
| Proxy Node | 桥接Mesh网络与GATT设备(如手机) | 较高(常开) | 否 |
| Friend Node | 为低功耗节点缓存消息 | 中等 | 否 |
| Low Power Node (LPN) | 大部分时间休眠,定期唤醒收消息 | 极低 | 是 |
这里有个关键点:一个节点可以同时扮演多个角色。比如一个设备既可以是Relay,也可以是Friend。但LPN不能同时做Relay——你想想看,一个天天睡觉的节点,怎么帮别人转发消息?
1.3 节点状态与地址类型
每个Mesh节点都有自己的状态。比如灯的开关状态、亮度值。这些状态通过消息来读写。地址嘛,就是节点的门牌号。
蓝牙Mesh定义了三种地址类型:
- 单播地址(Unicast):每个节点唯一。配置时由Provisioner分配。我习惯把单播地址比作身份证号。
- 组播地址(Group):一组节点共享。比如“客厅所有灯”就是一个组。发一条消息,全组都收到。
- 虚拟地址(Virtual):基于UUID的标签,用于更灵活的订阅。实际项目中用得不多,但做复杂场景时很有用。
你想想看,一个灯泡节点,它可能订阅了“客厅灯”这个组播地址,同时也拥有自己的单播地址。这样既能单独控制,也能批量控制。
1.4 消息发布/订阅机制
Mesh网络的消息传递,核心就是发布/订阅模型。节点可以发布消息到某个地址,也可以订阅某个地址的消息。说白了,就是“谁说话,谁听”。
举个例子:
// 伪代码示例:配置一个灯节点
灯节点.订阅地址 = 0xC001; // 订阅"客厅灯"组
灯节点.发布地址 = 0xC001; // 状态变化时发布到同一组
// 开关节点按下
开关节点.发布(地址=0xC001, 消息="开灯");
// 灯节点收到消息,执行开灯动作
这种机制的好处是解耦。开关不用知道灯的具体地址,灯也不用管是谁发的消息。我做过一个项目,客户要求加一个场景面板,只需要配置它发布到对应的组地址就行,其他节点完全不用改代码。
1.5 本章小结
这一章我们聊了蓝牙Mesh的协议栈架构——七层结构,每层各司其职。节点类型分四种,其中LPN是低功耗设计的核心角色。地址类型和发布/订阅机制是Mesh网络通信的基础。
嗯,这些概念看起来有点多,但别急。后面几章我们会一步步深入,尤其是LPN的休眠唤醒机制,我会把我在实际项目中踩过的坑、总结的经验,全都抖出来。你先把这张图记在脑子里,后面用得上。