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 网络五要素关系图 节点 (Node) 元素 (Element) 模型 (Model) 状态 (State) 消息 (Message) 关系说明 一个节点包含多个元素,一个元素包含多个模型 模型维护状态,并通过消息与其他模型的客户端/服务器通信

从这张图可以看得很清楚:

  • 节点是物理设备,元素是节点内的功能单元
  • 模型是元素的功能实现,状态是模型维护的数据
  • 消息是模型之间通信的桥梁

说白了,整个 Mesh 网络就是:节点里的元素通过模型来管理状态,模型之间用消息来同步和操作这些状态。

2.7 实际项目中的设计思路

我做一个智能照明项目时,是这样设计的:

  1. 物理设备:一个三路开关面板(1 个节点)
  2. 元素划分:每路开关一个元素,共 3 个元素
  3. 模型选择:每个元素放一个 Generic OnOff Client 模型
  4. 状态维护:每个 Client 模型维护一个按键状态(按下/释放)
  5. 消息交互:按键按下时,Client 模型发送 Set 消息给对应的灯节点

这样设计的好处是:每个元素独立编址,调试时可以单独控制每路开关,互不干扰。

总结一下:节点是躯壳,元素是器官,模型是功能,状态是数据,消息是语言。五者缺一不可,共同构成了 Mesh 网络的通信基础。