2. Mesh 网络基础概念:节点、元素、模型、状态、消息
好,咱们正式开始啃 Mesh 协议栈的核心概念。说实话,刚接触蓝牙 Mesh 的时候,我也被这一堆术语搞得有点晕——节点、元素、模型、状态、消息,它们之间到底是什么关系?
别急,我带你一个一个拆开看。搞懂了这五个概念,Mesh 协议栈的骨架你就抓住了。
2.1 节点(Node)——网络中的“人”
节点,说白了就是加入了 Mesh 网络的设备。一个灯泡、一个开关、一个传感器,只要它成功入网了,就是一个节点。
但这里有个坑:没入网的设备不叫节点,叫“未配置设备”(Unprovisioned Device)。只有通过 Provisioning(配置)流程拿到网络密钥后,它才正式成为节点。
关键点:节点是 Mesh 网络的最小通信单元。每个节点至少有一个元素,至少有一个模型。
我记得有一次调试客户的产品,设备死活连不上网。查了半天,发现是 Provisioning 流程中网络密钥没写对。嗯,从那以后我每次都会先确认密钥的写入顺序。
2.2 元素(Element)——节点里的“房间”
一个节点可以有多个元素。你可以把元素理解成节点内部的独立功能单元。
举个例子:一个智能插座,它可能有一个开关功能(控制通断),还有一个电量计量功能。这两个功能就可以放在两个不同的元素里。
每个元素都有一个唯一的地址(Element Address),这个地址在节点入网时自动分配。元素地址的格式是:
元素地址 = 节点主地址 + 元素索引
例如:节点主地址 0x0100
元素 0 地址:0x0100
元素 1 地址:0x0101
元素 2 地址:0x0102
我的习惯:设计产品时,尽量把功能独立、地址独立的模块拆成不同元素。这样后续扩展和维护都方便。比如一个三路开关,每路开关放一个元素,地址清晰,调试也省心。
2.3 模型(Model)——元素里的“功能模块”
模型定义了元素能做什么。它是蓝牙 Mesh 协议栈里最核心的抽象层。
模型分为三类:
| 模型类型 | 说明 | 典型例子 |
|---|---|---|
| 服务器模型(Server Model) | 维护状态,响应客户端请求 | Generic OnOff Server |
| 客户端模型(Client Model) | 发送请求,读取或修改服务器状态 | Generic OnOff Client |
| 控制模型(Control Model) | 既有服务器功能,又有客户端功能 | Light Lightness Control |
你想想看,一个灯泡节点里,灯控元素可能包含一个 Generic OnOff Server 模型,用来接收开关指令。而开关节点里,按键元素可能包含一个 Generic OnOff Client 模型,用来发送开关指令。
模型之间通过消息通信。服务器模型和客户端模型必须配对使用,否则消息没人处理。
我曾经踩过的坑:开发一个传感器产品时,只实现了传感器服务器模型,忘了加对应的客户端模型来上报数据。结果数据采集到了,但发不出去。后来才意识到,模型之间的配对关系必须在设计阶段就规划好。
2.4 状态(State)——模型里的“数据”
状态就是模型维护的数据。比如灯的开关状态(On/Off)、亮度值(Lightness)、色温(CTL)等。
状态有几种类型:
- 布尔状态:只有 0 和 1,比如开关
- 数值状态:一个范围内的数值,比如亮度 0~65535
- 复合状态:多个数值组合,比如色温包含温度值和 delta UV
状态的变化会触发消息的发送。比如灯的状态从 Off 变成 On,服务器模型会发送一条状态消息给订阅者。
这里有个重要的概念叫状态绑定(State Binding)。什么意思呢?就是一个状态的变化会影响另一个状态。比如你调节亮度,实际功率也会跟着变。这种关联关系就是状态绑定。
// 状态绑定示例(伪代码)
void lightness_set(uint16_t new_lightness) {
actual_state.lightness = new_lightness;
// 绑定:亮度变化后,自动更新功率状态
power_state = calculate_power(new_lightness);
// 发送状态变化消息
send_state_message();
}
2.5 消息(Message)——网络里的“语言”
消息是节点之间通信的载体。所有操作——读状态、写状态、通知状态变化——都是通过消息完成的。
消息分为两大类:
| 消息类型 | 方向 | 用途 |
|---|---|---|
| Get 消息 | Client → Server | 请求读取状态 |
| Set 消息 | Client → Server | 请求修改状态 |
| Status 消息 | Server → Client | 返回当前状态 |
消息的格式是固定的,包含操作码(Opcode)和参数(Parameters)。操作码告诉接收方“这条消息是干什么的”,参数携带具体数据。
// 消息格式示例
消息 = 操作码(2字节) + 参数(可变长度)
例如:Generic OnOff Set 消息
操作码:0x8202
参数:0x01 (表示开)
调试技巧:抓包时,我习惯先看操作码。操作码对了,消息类型就定了,剩下的就是解析参数。如果操作码不对,直接跳过,不用浪费时间看参数。
2.6 五者关系——一张图说清楚
好了,五个概念都讲完了。它们之间的关系,我用一张图来总结:
从这张图可以看得很清楚:
- 节点是物理设备,元素是节点内的功能单元
- 模型是元素的功能实现,状态是模型维护的数据
- 消息是模型之间通信的桥梁
说白了,整个 Mesh 网络就是:节点里的元素通过模型来管理状态,模型之间用消息来同步和操作这些状态。
2.7 实际项目中的设计思路
我做一个智能照明项目时,是这样设计的:
- 物理设备:一个三路开关面板(1 个节点)
- 元素划分:每路开关一个元素,共 3 个元素
- 模型选择:每个元素放一个 Generic OnOff Client 模型
- 状态维护:每个 Client 模型维护一个按键状态(按下/释放)
- 消息交互:按键按下时,Client 模型发送 Set 消息给对应的灯节点
这样设计的好处是:每个元素独立编址,调试时可以单独控制每路开关,互不干扰。
总结一下:节点是躯壳,元素是器官,模型是功能,状态是数据,消息是语言。五者缺一不可,共同构成了 Mesh 网络的通信基础。