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 六个概念的关系图

说了这么多,你可能觉得它们之间的关系有点乱。我画了一张图,帮你理清脉络:

蓝牙Mesh核心概念关系图 蓝牙Mesh核心概念关系图 节点(Node) 元素 A 服务器模型 客户端模型 状态:开关=开,亮度=80 元素 B 服务器模型 厂商模型 状态:色温=4000K 消息 地址:单播 0x0001(元素A)| 单播 0x0002(元素B) 组播 0xC001(全楼灯) • 节点包含多个元素,每个元素有独立地址 • 元素包含模型,模型定义行为并维护状态 • 消息在节点间传递,通过地址精准定位目标元素

这张图你看懂了吗?从上到下,节点包裹元素,元素包含模型,模型维护状态。消息带着地址在网络里跑,找到对应的元素,读写它的状态。

2.8 实战中的常见误区

最后,我总结几个新手容易犯的错:

  • 地址搞混:单播地址发给一个元素,组播地址发给一组元素。别把单播地址当组播用。
  • 模型不匹配:客户端模型和服务器模型必须配对。你发了个通用开关请求,对面得有个通用开关服务器模型来响应。
  • 状态不同步:多个客户端同时修改同一个状态,可能导致冲突。我建议用“发布-订阅”模式来避免。
  • 消息风暴:TTL太大或重传次数太多,会让网络不堪重负。合理配置这两个参数,能省不少心。

血的教训:有一次我在测试环境里,把100个节点的TTL都设成10,然后同时发消息。结果网络直接瘫痪,消息延迟从毫秒级变成了秒级。后来我改成TTL=3,重传2次,网络才恢复正常。

好了,六个核心概念就讲到这里。你只要记住:节点是设备,元素是功能模块,模型是行为定义,状态是数据,消息是通信载体,地址是定位方式。把这六个概念串起来,蓝牙Mesh的骨架你就拿下了。