2. 核心概念解析:节点、元素、模型、状态、消息、地址
说实话,刚接触蓝牙Mesh的时候,我被这些术语搞得有点晕。节点、元素、模型、状态、消息、地址——六个概念搅在一起,文档看了三遍才理清关系。后来我带团队做项目,发现新人几乎都会在这个地方卡住。
这一章,我就用最直白的方式,把这六个核心概念拆开讲透。你搞懂了它们,Mesh协议栈的骨架就算搭起来了。
2.1 节点(Node)——网络中的“人”
节点是蓝牙Mesh网络中最基本的通信实体。说白了,一个支持Mesh的蓝牙设备加入网络后,就变成了一个节点。
我习惯把节点比作会议室里的人。每个人都能说话,也能听别人说话。但Mesh网络里有个特殊角色——中继节点。它不光自己说话,还帮别人传话。
节点类型速查:
- 中继节点(Relay):转发消息,扩大网络覆盖范围。我在智能楼宇项目里,每隔15米就放一个中继节点,整层楼信号都稳。
- 低功耗节点(Low Power):省电模式,平时睡觉,朋友叫才醒。适合电池供电的设备,比如温湿度传感器。
- 朋友节点(Friend):帮低功耗节点缓存消息。低功耗节点睡觉时,朋友替它收消息。
- 代理节点(Proxy):让不支持Mesh的手机也能通过GATT与Mesh网络通信。嗯,这个在配网阶段特别重要。
一个节点可以同时扮演多个角色。比如,它可以是中继节点,同时也是朋友节点。但要注意,角色越多,功耗越高。我曾经在一个项目中把所有节点都设成中继,结果电池设备三天就没电了……
2.2 元素(Element)——节点里的“器官”
一个节点可以包含多个元素。元素是节点内部最小的可寻址单元。每个元素都有自己的地址。
举个例子:一个智能灯泡,灯头是元素A,灯座是元素B。元素A控制亮度,元素B控制色温。它们共享同一个节点,但各自独立工作。
为什么要有元素?因为一个物理设备可能包含多个功能模块。我做过一个智能窗帘控制器,它同时控制窗帘电机和光照传感器。这两个功能放在同一个节点里,但用不同的元素来管理,逻辑清晰多了。
我的经验:元素数量在设备入网时就固定了,不能动态增减。设计产品时,提前规划好元素个数。我见过有人把每个功能都拆成独立元素,结果地址空间不够用。
2.3 模型(Model)——定义“能做什么”
模型定义了元素的行为。它有点像面向对象编程里的“类”。一个元素可以包含多个模型。
蓝牙Mesh标准定义了两类模型:
- 服务器模型(Server Model):维护状态,响应客户端请求。比如“通用开关服务器模型”维护开关状态。
- 客户端模型(Client Model):发送请求,读取或修改服务器状态。比如“通用开关客户端模型”发送开/关命令。
我举个例子你就明白了。一个灯泡节点里有个元素,这个元素包含“通用开关服务器模型”。手机App里的“通用开关客户端模型”发一条消息过来,灯泡就亮了。
注意:模型是分层的。蓝牙Mesh定义了基础模型(如Generic OnOff),厂商也可以自定义模型。但自定义模型需要申请16位或32位的模型ID,不能随便用。我曾经图省事,直接用了两个不同厂商的模型ID,结果设备互不识别……
2.4 状态(State)——设备的“记忆”
状态是模型维护的数据。它可以是开关值、亮度等级、色温数值等。状态是蓝牙Mesh的核心——所有通信最终都是为了读或写某个状态。
状态有几个关键特性:
| 特性 | 说明 | 举例 |
|---|---|---|
| 绑定 | 一个状态变化可以触发另一个状态变化 | 亮度调到0时,开关状态自动变为“关” |
| 范围 | 状态值有上下限 | 亮度状态范围0~100 |
| 持久化 | 设备掉电后状态是否保留 | 灯泡断电重启后,保持上次的亮度 |
我在做智能灯控项目时,踩过一个坑:状态绑定没配好。用户把亮度调到0,灯灭了,但开关状态还是“开”。结果App上显示灯开着,实际却不亮。后来我把亮度0和开关“关”做了绑定,问题才解决。
2.5 消息(Message)——沟通的“语言”
消息是节点之间交换的数据单元。蓝牙Mesh定义了多种消息类型,但核心就两种:
- 请求消息(Request):客户端发给服务器,要求读取或修改状态。
- 响应消息(Response):服务器回复客户端,告知操作结果。
消息的格式很固定:操作码(Opcode)+ 参数。操作码告诉接收方“这条消息要干什么”,参数是具体数据。
举个例子:
// 通用开关请求消息(开灯)
Opcode: 0x8201
参数: 0x01 (开)
// 通用开关响应消息(成功)
Opcode: 0x8202
参数: 0x00 (成功)
消息还有两个重要属性:
- TTL(生存时间):消息最多能跳转几次。TTL=0时,消息只能在本节点处理,不转发。
- 重传机制:消息发送后没收到确认,会自动重发。重传次数和间隔可以配置。
避坑指南:我曾经把TTL设得太大,结果消息在网络里转了几十圈才被丢弃,网络拥堵得一塌糊涂。一般场景下,TTL设3~5就够了。
2.6 地址(Address)——精准“定位”
地址是消息的收件人。蓝牙Mesh有三种地址类型:
| 地址类型 | 范围 | 用途 |
|---|---|---|
| 单播地址 | 0x0001 ~ 0x7FFF | 唯一标识一个元素。每个元素入网时分配一个。 |
| 组播地址 | 0xC000 ~ 0xFFFF | 一组元素的集合。发消息给组地址,所有成员都能收到。 |
| 虚拟地址 | 基于128位UUID | 类似组播,但更灵活。适合临时分组场景。 |
地址分配是配网器(Provisioner)的工作。设备入网时,配网器会给它的每个元素分配一个单播地址。组播地址则由上层应用或用户配置。
我做过一个项目,需要把一层楼的灯分成三个区域。每个区域分配一个组播地址。App发消息给组地址,对应区域的灯就亮了。简单高效。
2.7 六个概念的关系图
说了这么多,你可能觉得它们之间的关系有点乱。我画了一张图,帮你理清脉络:
这张图你看懂了吗?从上到下,节点包裹元素,元素包含模型,模型维护状态。消息带着地址在网络里跑,找到对应的元素,读写它的状态。
2.8 实战中的常见误区
最后,我总结几个新手容易犯的错:
- 地址搞混:单播地址发给一个元素,组播地址发给一组元素。别把单播地址当组播用。
- 模型不匹配:客户端模型和服务器模型必须配对。你发了个通用开关请求,对面得有个通用开关服务器模型来响应。
- 状态不同步:多个客户端同时修改同一个状态,可能导致冲突。我建议用“发布-订阅”模式来避免。
- 消息风暴:TTL太大或重传次数太多,会让网络不堪重负。合理配置这两个参数,能省不少心。
血的教训:有一次我在测试环境里,把100个节点的TTL都设成10,然后同时发消息。结果网络直接瘫痪,消息延迟从毫秒级变成了秒级。后来我改成TTL=3,重传2次,网络才恢复正常。
好了,六个核心概念就讲到这里。你只要记住:节点是设备,元素是功能模块,模型是行为定义,状态是数据,消息是通信载体,地址是定位方式。把这六个概念串起来,蓝牙Mesh的骨架你就拿下了。