2. Mesh网络基础概念:节点、元素、模型、状态、消息
好,咱们正式开始啃Mesh网络的核心概念。说实话,我刚接触蓝牙Mesh那会儿,被这些术语绕得够呛。什么节点、元素、模型,听着像哲学课。但搞嵌入式的人都知道,概念不清,后面写代码就是给自己挖坑。
这一章,我就用最直白的方式,把这五个核心概念——节点(Node)、元素(Element)、模型(Model)、状态(State)、消息(Message)——给你讲透。它们之间的关系,说白了就是一句话:节点是物理设备,元素是功能单元,模型定义行为,状态是数据,消息是通信手段。
核心记忆口诀:一个节点包含多个元素,每个元素包含多个模型,模型操作状态,状态通过消息传递。
2.1 节点(Node)——Mesh网络中的“人”
节点,就是加入Mesh网络的每一个设备。一个灯泡、一个开关、一个传感器,只要它加入了Mesh网络,就是一个节点。
我个人习惯把节点比作一个公司里的员工。每个员工都有自己的工号(单播地址),有自己的岗位职责(模型),也能跟其他员工沟通(收发消息)。
节点有几个关键属性:
- 单播地址(Unicast Address):节点在网内的唯一ID,由配网器分配。我见过有人把地址写死在固件里,结果两个设备冲突,调试了一整天——嗯,千万别这么干。
- 中继能力(Relay):节点是否转发别人的消息。不是所有节点都需要中继,比如电池供电的传感器,为了省电,通常不当中继。
- 朋友节点(Friend):低功耗节点的“保姆”,帮它缓存消息。
避坑指南:我曾经在一个项目中,把所有节点都配置成中继节点,结果网络拥塞得一塌糊涂。后来才明白,中继节点数量控制在30%左右就够了,不是越多越好。
2.2 元素(Element)——节点里的“部门”
一个节点可以有多个元素。元素是什么?它是节点内部一个独立的功能单元,拥有自己的地址。
举个例子:一个三路开关面板,里面有三个物理按键。每个按键可以独立控制不同的灯。那这个面板节点,就至少需要三个元素——每个元素对应一个按键。
元素的特点:
- 每个元素都有一个元素地址(Element Address),是节点单播地址的偏移。
- 元素是模型的容器。模型必须挂载在元素上。
- 一个节点至少有一个元素(主元素),最多可以有N个。
我记得有一次做智能灯项目,客户要求一个灯同时支持调光、色温和场景切换。我就在一个节点里设计了三个元素:一个负责调光,一个负责色温,一个负责场景。这样每个功能独立,互不干扰。
2.3 模型(Model)——元素里的“岗位说明书”
模型定义了元素能做什么。它是一组行为、状态和消息的集合。
蓝牙Mesh规范里把模型分为三类:
| 模型类型 | 说明 | 例子 |
|---|---|---|
| 服务器模型(Server Model) | 维护状态,响应客户端请求 | Generic OnOff Server |
| 客户端模型(Client Model) | 发送请求,读取或修改服务器状态 | Generic OnOff Client |
| 控制模型(Control Model) | 既当服务器又当客户端,通常用于场景控制 | Scene Control Model |
你想想看,一个灯泡节点里,通常有一个Generic OnOff Server模型,它维护着“开关”这个状态。而开关节点里,有一个Generic OnOff Client模型,它发送“开”或“关”的消息。
注意:模型不能独立存在,必须挂载在元素上。一个元素可以挂载多个模型,但同一个模型不能重复挂载在同一个元素上。
2.4 状态(State)——模型里的“数据”
状态,就是模型当前的值。比如灯的亮度、开关的通断、色温的数值。
状态有几个重要特性:
- 绑定(Binding):一个状态的变化可以触发另一个状态的变化。比如,你把灯关了(OnOff状态变为0),亮度状态(Level)也应该变为0。
- 状态类型:分为布尔型、整型、枚举型等。蓝牙Mesh规范里对每个状态都有明确的字节定义。
- 状态持久化:设备掉电后,状态是否保存?我建议关键状态(如开关、亮度)一定要保存到Flash,否则用户断电再上电,灯突然亮了,会吓一跳。
我曾经遇到过一个坑:客户反馈灯偶尔会自己亮。查了半天,发现是状态绑定没做好——调光模型把亮度设为0,但开关模型没跟着关。后来加了绑定逻辑,问题解决。
2.5 消息(Message)——设备间的“对话”
消息,就是节点之间通信的数据包。客户端模型发消息,服务器模型收消息并响应。
消息分为几类:
- GET:客户端请求读取状态。服务器回复STATUS。
- SET:客户端请求设置状态。服务器回复STATUS(可选)。
- STATUS:服务器返回当前状态。
- PUBLISH:服务器主动发布状态变化,不需要客户端请求。
消息的格式是固定的,包含操作码(Opcode)和参数。比如开关消息的操作码是0x8201,参数是一个字节:0x00表示关,0x01表示开。
// 伪代码示例:发送开关消息
uint8_t onoff = 0x01; // 开
mesh_message_t msg;
msg.opcode = 0x8201; // Generic OnOff Set
msg.params = &onoff;
msg.length = 1;
mesh_send(&msg, target_address);
2.6 五者关系——一张图看懂
说了这么多,咱们用一张SVG图把关系理清楚。这张图我画了很多遍,每次给团队新人培训都用它。
从这张图可以清楚看到:一个节点包含两个元素,每个元素挂载了不同的模型,模型维护着状态,而客户端和服务器模型之间通过消息通信。
2.7 实战中的关系理解
咱们用一个实际场景串一遍:
- 物理设备:一个智能灯泡,它是一个节点。
- 功能划分:灯泡里有调光和开关两个功能,所以设计两个元素。
- 行为定义:开关元素挂载Generic OnOff Server模型,调光元素挂载Light Lightness Server模型。
- 数据存储:模型维护状态——OnOff状态(0或1)和Lightness状态(0~65535)。
- 通信:手机App(客户端节点)发送消息(SET),灯泡收到后更新状态,并回复STATUS消息。
我的建议:设计产品时,先画一张类似上面的关系图。把节点、元素、模型、状态、消息都标清楚。我每次做新项目都这么干,能省掉后面至少一半的调试时间。
2.8 常见误区
| 误区 | 正确理解 |
|---|---|
| 一个节点只能有一个元素 | 一个节点可以有多个元素,每个元素独立编址 |
| 模型就是状态 | 模型是行为的集合,状态是模型维护的数据 |
| 消息只能由客户端发 | 服务器也可以主动发布(Publish)消息 |
| 状态只存在于服务器 | 客户端也可以有状态,比如缓存的上次读取值 |
嗯,这一章的内容就到这里。概念虽然多,但搞清楚了,后面学配置、学模型、学通信,就会顺畅很多。记住那张关系图,它就是Mesh网络的骨架。