☰
蓝牙Mesh组网实战:ESP32离线群聊与多跳传输完整解析
2026/10/8 18:03:42 网站建设 项目流程

大家有没有遇到过这种场景:在深山徒步、地下车库或者演唱会现场,手机明明有电,微信消息却一直在转圈。基站拥塞、信号盲区、没有Wi-Fi,互联网断掉了,人与人之间的距离不过几十米,信息却传不过去。

其实不依赖蜂窝网络和Wi-Fi,设备之间也能组成一张短距离通信网络,这就是蓝牙Mesh的核心价值。本文将围绕蓝牙Mesh组网、多跳传输和开源方案展开,完整拆解一套基于ESP32的离线群聊Demo思路,从协议概念、节点角色、配网流程,到代码框架和常见坑点,希望能帮你把蓝牙Mesh真正用起来。

如果你正在做物联网组网、智能家居、离线通信相关项目,或者想了解蓝牙Mesh开发是怎么一回事,这篇文章都可以作为一份入门到实战的参考资料。

1. 断网也能聊?蓝牙Mesh解决的是什么问题

1.1 离线通信的痛点

传统移动通信依赖基站,Wi-Fi通信依赖路由器。一旦连接互联网的“最后一跳”断了,人与人、设备与设备之间的通信就会立刻中断。

但在很多场景里,我们并不需要互联网,只需要“把消息从A传到附近的B”。比如:

  • 户外徒步时,队员之间手台没带齐,但手机通过蓝牙Mesh可以互相发消息;
  • 地下车库或大型场馆里,基站信号不稳定,巡检人员之间需要短距离离线通知;
  • 智能家居里,全屋几十个灯具、传感器需要组网联动,并不希望每次控制都经过云服务器;
  • 灾害应急场景中,公网失效时,现场设备组成临时网络完成信息上报。

这些场景有一个共同特点:距离近、节点多、要求低功耗、不希望依赖公共网络。

蓝牙Mesh正是在这种需求下出现的。

1.2 蓝牙Mesh是什么

蓝牙Mesh,英文是 Bluetooth Mesh,是蓝牙技术联盟(Bluetooth SIG)在2017年发布的网络通信规范。它不是一个新的无线硬件协议,而是基于低功耗蓝牙(BLE,Bluetooth Low Energy)之上的一种组网方式。

你可以这样理解:

  • BLE解决的是“两个设备怎么近距离传数据”;
  • 蓝牙Mesh解决的是“一大堆设备怎么互相转发消息、组成一张网络”。

它允许设备与设备之间通过**多跳(Multi-hop)**的方式传递消息。也就是说,消息不一定要从源头直接到目标,而是可以经过若干个中间节点接力转发,最终到达目标设备。

这样做的好处非常明显:单个设备的通信距离有限,但通过多跳中继,网络覆盖范围可以成倍扩展。

1.3 蓝牙Mesh适合哪些场景

蓝牙Mesh并不是万能的,它适合以下场景:

  • 智能家居:灯光、窗帘、传感器、开关组成全屋网络;
  • 楼宇自动化:照明控制、能源管理、环境监测;
  • 工业物联网:设备状态采集、告警通知;
  • 离线短距离通信:应急消息、室内定位辅助、现场指挥调度;
  • 商业零售:Beacon 信标管理、客流统计。

它不适合那些需要高速率、长距离或大带宽的场景。蓝牙Mesh的单包数据量很小,在BLE 4.x时代一般为十几字节,在BLE 5.x之后有所提升,但仍然适合控制指令、状态信息、短文本消息,不适合传图片、视频和文件。

2. 蓝牙Mesh核心概念:不懂这些,后面代码全是雾水

在写代码之前,必须先理解蓝牙Mesh的几个基础概念:节点、地址、配网、模型、发布订阅、多跳转发。这些概念决定了你写代码时每个API在做什么。

2.1 节点、元素与地址

蓝牙Mesh网络中,每一个参与组网的设备叫做一个节点(Node)。未被配网的设备叫未配网设备(Unprovisioned Device)。

一个节点至少包含一个元素(Element)。元素可以理解为节点内可独立寻址的功能单元。比如一个双路开关,可能有两个元素,分别控制两路灯光。

每个元素至少有一个地址(Address),所以一个节点可以占用多个地址。地址分为:

  • 单播地址(Unicast Address):每个节点的元素独占,相当于设备的“身份证”;
  • 组播地址(Group Address):一组元素的集合,向组播地址发消息,组内所有元素都能收到;
  • 虚拟地址(Virtual Address):类似组播,但用UUID标记,适合固定业务场景。

当你发送一条消息时,目标是“某个地址”,而不是“某个设备”。这为多个设备协同工作提供了基础。

2.2 配网(Provisioning)

一个新设备要加入蓝牙Mesh网络,必须经过**配网(Provisioning)**流程。配网过程可以简单理解为“认证+发钥匙”。

配网器(Provisioner)通常是手机App或专门的网关设备。它会扫描到未配网设备,然后与设备完成认证,分配单播地址,并下发网络密钥(Network Key)、应用密钥(AppKey)等信息。

只有拿到网络密钥的设备,才能参与同一张Mesh网络的数据解密和转发。

这一点非常关键:蓝牙Mesh不是“谁都能听”的广播网络,而是被配网流程保护起来的加密网络。即使别人也在用BLE芯片,没有密钥就听不到你的业务消息。

2.3 模型(Model)与发布/订阅

蓝牙Mesh中,业务数据通过**模型(Model)**来定义。模型约定了消息的操作码(Opcode)和数据结构。

可以近似理解为:模型就是“这个节点能干什么、能听懂哪些指令”的接口定义。

消息传递采用**发布/订阅(Publish/Subscribe)**模式:

  • 节点可以**订阅(Subscribe)**一些地址,比如订阅某个组播地址;
  • 节点也可以**发布(Publish)**消息到某个地址;
  • 当一条消息发到组播地址时,所有订阅了该地址的节点都会收到。

这种设计非常适合一对多控制。比如一个灯光开关按下后,向组播地址发布“开灯”指令,全屋订阅了该地址的灯都会同时响应,而不需要逐个给每个灯发单播消息。

2.4 多跳传输与中继

蓝牙Mesh的底层传输方式叫受管理泛洪(Managed Flooding)。

消息发出后,具备**中继(Relay)**功能的节点会帮它转发到下一跳。每转发一次,TTL(生存时间)减1,当TTL为0时不再转发,避免消息在网络中无限循环。

每个节点还维护一个消息缓存(Message Cache)。如果某条消息之前已经处理过,节点就会丢弃重复消息,避免产生环路风暴。

所以蓝牙Mesh的多跳传输并不是传统路由协议,而是一种更灵活的泛洪式转发。它不需要建立路由表,网络拓扑变化时也不需要重新计算路由,这让蓝牙Mesh在动态环境中非常稳定。

但这也带来一个代价:消息在网络中会多路径重复,可能带来一定空口占用,网络规模越大,越需要注意消息频率和TTL设置。

3. 开源方案选型:ESP32、nRF52840 还是其他?

3.1 主流开源蓝牙Mesh方案对比

目前开发者接触最多的开源蓝牙Mesh方案主要有两类:一类是芯片原厂SDK,一类是上层协议栈。

方案芯片/平台优点注意点
ESP-BLE-MESH乐鑫ESP32、ESP32-C3等生态成熟、资料多、成本低,与ESP-IDF无缝集成主要面向乐鑫芯片,不同芯片资源差异较大
nRF5 SDK for MeshNordic nRF51/nRF52系列功耗控制优秀,协议栈完整,很多商业可穿戴设备在用硬件成本偏高,上手门槛略高
Zephyr 的蓝牙Mesh协议栈多厂商SoC跨厂商、跨平台,MCU友好需要熟悉Zephyr构建系统
AliOS Things内置Mesh组件阿里系IoT平台与云平台联动方便,适合国内项目需要考虑平台绑定问题

如果你已经有明确硬件平台,直接使用原厂SDK会省很多事。如果团队还没有选型,且想快速跑通Demo,ESP32是目前性价比很高的选择。

3.2 为什么选ESP32 + ESP-BLE-MESH

在项目标题和热搜词里,很多人关注“esp32蓝牙mesh”“stm32wb55cgu6 蓝牙mesh”。STM32WB系列也可以做蓝牙Mesh,但ESP32在社区资料、示例代码、开发板价格上更有优势。

选择ESP32 + ESP-BLE-MESH的理由:

  1. 资料多:乐鑫官方的 ESP-IDF 里自带了 ESP-BLE-MESH 组件,并提供了配网器、节点、onoff model、sensor model、vendor model 等多个示例;
  2. Flash空间足够:ESP32 常见的 4MB Flash,跑蓝牙Mesh协议栈加业务代码完全够用;
  3. 支持Wi-Fi与蓝牙共存:在一些网关类项目中,设备既能通过Wi-Fi上云,又能通过蓝牙Mesh管理本地设备;
  4. 开源友好:ESP-IDF 本身是开源项目,开发板几十元就能买到。

当然,如果项目对功耗要求非常严格,比如纽扣电池供电需要跑几个月,那nRF52系列会更合适。但如果目标是快速验证、学习原理和做产品原型,ESP32更合适。

3.3 物联网组网标准横向对比

很多初学者会把蓝牙Mesh、Zigbee、LoRa、Wi-Fi放在一起比较,这里简单做个总结:

标准频段主要特点适用场景
蓝牙Mesh2.4GHz中继泛洪,手机生态好,节点成本中等智能家居、楼宇控制、离线短距离通信
Zigbee2.4GHz / 868 / 915MHz传统Mesh路由方案,节点多,生态成熟智能家居、工业传感
LoRaSub-GHz长距离、低速率、低功耗广域传感、农林业监测
Wi-Fi Mesh2.4GHz / 5GHz带宽高、覆盖大,但不适合超低功耗节点家庭无线回程、视频监控

蓝牙Mesh和Zigbee定位有重叠,但蓝牙Mesh有一个天然优势:BLE的手机生态太丰富。手机、平板、电脑几乎都内置BLE,而支持Zigbee的手机几乎没有。所以需要手机直接参与控制时,蓝牙Mesh往往更容易落地。

4. 环境准备与硬件说明

4.1 硬件清单

要跑通本文的离线群聊Demo,至少需要:

  • 2块 ESP32 开发板(推荐 ESP32-DevKitC 或任意带USB转串口的ESP32板);
  • 2根Micro USB数据线;
  • 能运行串口调试工具的电脑;
  • 手机安装 nRF Connect 或 EspBleMesh App(可选,用于观察和配网调试)。

版本说明:ESP-IDF 版本更新比较快,本文示例以 ESP-IDF 常见版本为例,重点讲解BLE Mesh开发思路。具体版本请参考乐鑫官方发布记录,建议选择一个长期支持版本进行开发。

4.2 开发环境搭建

这里以Linux或macOS环境为例,Windows用户也可以使用乐鑫官方提供的ESP-IDF Windows安装器。

首先,安装ESP-IDF。如果之前从未装过,可以按官方FAQ操作,核心步骤是克隆仓库并执行安装脚本。具体命令行如下:

# 以获取ESP-IDF仓库为例 mkdir -p ~/esp cd ~/esp git clone --recursive https://github.com/espressif/esp-idf.git cd esp-idf ./install.sh esp32 source export.sh

export.sh每次打开新终端都需要source,或者可以写入shell配置文件。安装完成后,确认环境变量生效:

idf.py --version

如果能看到版本号,说明ESP-IDF环境已经准备好。

4.3 获取ESP-BLE-MESH示例

ESP-IDF中已经包含了ESP-BLE-MESH组件和官方示例。可以先找到示例目录:

cd ~/esp/esp-idf/examples/bluetooth/esp_ble_mesh ls

你会看到多个示例,例如generic_onoff、sensor_model、vendor_model等。

其中vendor_model示例最适合改造为群聊Demo,因为Vendor Model可以自定义消息内容,而generic model大多用于标准的开关、亮度、传感器等控制,消息字段格式是规范固定的。

5. 手把手实战:基于ESP32的离线群聊Demo

5.1 系统架构

严格来说,手机系统一般不直接内置蓝牙Mesh协议栈,App无法直接以“节点”身份加入蓝牙Mesh网络。所以在真实项目里,更多采用“手机 + 蓝牙Mesh网关 + 各节点”的三层架构。

我们这里做一个简化群聊Demo,架构如下:

手机A | | BLE GATT 或 UART v ESP32网关A <=========== 蓝牙Mesh多跳网络 ===========> ESP32网关B | | BLE GATT 或 UART v 手机B

手机A把消息通过串口或BLE GATT发给ESP32网关A,ESP32网关A把文本封装到蓝牙Mesh Vendor Model消息中,经多跳转发到ESP32网关B,网关B再把内容打印到串口或转发给手机B。

如果不用手机,也可以直接用两块ESP32开发板,通过串口互相发消息,电脑串口终端作为聊天窗口。

这个架构的好处是:手机端不需要处理复杂的蓝牙Mesh配网和协议栈,只需要跟最近的网关打交道。

5.2 创建工程并配置

从官方vendor_model示例复制一份作为基础工程:

cp -r ~/esp/esp-idf/examples/bluetooth/esp_ble_mesh/vendor_model ~/esp/ble_mesh_chat cd ~/esp/ble_mesh_chat

然后打开menuconfig完成基础配置:

idf.py menuconfig

建议检查以下配置项:

  • 蓝牙使能:Component config → Bluetooth → Bluetooth设为 Enabled;
  • 蓝牙模式:选择Bluetooth Low Energy;
  • ESP-BLE-MESH 使能:Component config → Bluetooth → ESP BLE Mesh打开;
  • 配置节点作为 Provisioner 还是 Node:本文实验建议一个板子设为Node,另一个也设为Node,使用手机App配网,或一个板子作为Provisioner去配另外一个。

注意,不同版本的ESP-IDF菜单路径可能略有差异,请以当前版本显示为准。

5.3 自定义Vendor Model:定义文本消息

Vendor Model允许厂商自定义消息头,所以我们可以在消息里塞入文本数据。官方示例中已经定义了 vendor_model 的读写操作,核心思路如下。

先定义本地模型ID和消息结构:

#define CID_ESP 0x02E5 #define ESP_BLE_MESH_VND_MODEL_ID_CHAT 0x0001 #define CHAT_MSG_MAX_LEN 32 typedef struct { uint8_t msg[CHAT_MSG_MAX_LEN]; uint8_t len; } chat_message_t;

然后注册Vendor Model的接收回调。当节点收到一条针对该模型的消息时,回调会被触发,我们可以在这里解析文本并打印:

static esp_err_t example_vendor_model_cb(esp_ble_mesh_model_cb_event_t event, esp_ble_mesh_model_cb_param_t *param) { switch (event) { case ESP_BLE_MESH_MODEL_OPERATION_EVT: if (param->model_operation.opcode == ESP_BLE_MESH_VND_MODEL_OP_CHAT_SEND) { uint8_t *data = param->model_operation.msg; uint8_t len = param->model_operation.length; ESP_LOGI(TAG, "Received chat message, len=%d", len); ESP_LOG_BUFFER_HEX(TAG, data, len); /* 这里可以把 data 转成字符串并继续上抛给串口或手机 */ } break; default: break; } return ESP_OK; }

这里需要说明:ESP-BLE-MESH 的 vendor model opcode 由“厂商ID + 操作码”组成。实际编写时,需要先注册一个 vendor_model 实例,并绑定到节点元素上。完整的注册代码比较长,建议直接基于官方vendor_model示例中的board.c和main.c修改。

5.4 消息发送与接收

发送消息时,通常使用模型发布功能。先给模型设置发布地址,例如组播地址0xC000,然后调用发布接口:

static esp_err_t send_chat_message(esp_ble_mesh_model_t *model, uint8_t *payload, uint8_t len) { esp_ble_mesh_msg_ctx_t ctx = {0}; ctx.addr = 0xC000; /* 组播地址,所有订阅方都能收到 */ ctx.opcode = ESP_BLE_MESH_VND_MODEL_OP_CHAT_SEND; ctx.model = model; ctx.net_idx = 0; ctx.app_idx = 0; esp_err_t err = esp_ble_mesh_model_send_message(model, &ctx, payload, len); if (err != ESP_OK) { ESP_LOGE(TAG, "model send message failed, err=%d", err); return err; } return ESP_OK; }

实际API名称和参数结构在不同版本中有调整,写业务代码时要以当前ESP-IDF头文件为准。上面的代码用于表达数据流向,而不是某个固定版本的完整可编译代码。

串口读取用户输入并发送,可以在主循环里用esp_vfs_dev_uart_ioctl或直接使用fgets读取一行文本,然后调用send_chat_message发送。

5.5 编译、烧录与验证

编译命令非常直接:

idf.py build

烧录并打开串口监视器:

idf.py -p /dev/ttyUSB0 flash monitor

注意把/dev/ttyUSB0替换成你的实际串口设备名。Windows下可能是COM3、COM5等。

验证步骤:

  1. 板子A上电,等待配网;
  2. 板子B上电,等待配网;
  3. 用手机App或其中一个板子作为Provisioner,把两个设备加入同一网络;
  4. 在板子A的串口输入一行文字,观察板子B的串口是否打印出相同内容;
  5. 如果中间再加一块启用中继的ESP32节点,就能验证多跳传输。

5.6 预期结果

如果一切正常,你会看到板子B的串口日志里出现类似如下的内容:

I (12345) ble_mesh_chat: Received chat message, len=13 I (12345) ble_mesh_chat: 48 65 6C 6C 6F 20 4D 65 73 68 21 0A 00

其中48 65 6C 6C 6F就是 ASCII 字符串Hello。直接把消息再接一层字符串解析,就能显示中文或英文消息。

6. 多跳传输的调优要点

6.1 TTL与中继节点设置

不是所有节点都需要开启中继。中继功能会持续监听并转发消息,这会增加功耗和空口占用。对电池供电的传感器节点,建议关闭Relay。

TTL决定了消息最多经过多少跳。如果全屋设备只有两层拓扑,TTL默认值往往偏大,可以适当调小,减少无效广播。

esp_ble_mesh_set_relay_config(ESP_BLE_MESH_RELAY_ENABLE, ESP_BLE_MESH_RELAY_ON, ESP_BLE_MESH_DEFAULT_TTL);

6.2 消息缓存与去重

蓝牙Mesh节点会缓存最近处理过的消息,重复消息直接丢弃。这个缓存数量是有限的,默认配置可能无法满足高频率消息场景。

如果业务中短时间有大量消息,需要调大缓存,否则可能出现“消息明明发出去了,接收端却丢了”的现象。

6.3 低功耗节点与Friendship机制

低功耗节点(LPN)会周期性休眠,中继节点不会一直为它等待。蓝牙Mesh设计了友谊(Friendship)机制:

  • 低功耗节点与一个好友节点(Friend Node)建立关系;
  • 好友节点暂存发往低功耗节点的消息;
  • 低功耗节点醒来时,再从好友节点取回消息。

在群聊Demo里,如果某个ESP32节点使用电池供电,可以把这个节点配置为LPN,并让它选择一个Friend节点。

6.4 消息频率与风暴控制

蓝牙Mesh是小数据包、多节点转发网络,如果所有节点每秒都发消息,网络很快会拥塞。

建议业务层做几点限制:

  • 群聊消息频率控制在每节点每秒1条以内;
  • 文本长度不超过单包载荷上限;
  • 重要消息可以重发,但重发间隔要退避;
  • 慎用组播地址,能单播就单播。

特别是在Demo中展示多跳时,建议先用短文本、低频率测试,观察不同距离和跳数下的丢包情况,再逐步增加消息强度。

7. 常见问题与排查思路

问题现象常见原因解决思路
设备一直处于未配网状态未被Provisioner发现,或未开启可发现广播检查设备是否已经Enable配网广播,手机端距离不要太远
配网成功后收不到消息AppKey不一致,或模型未订阅目标地址确认两个设备使用同一网络密钥和应用密钥,检查模型订阅列表
单跳能通,多跳不通中间节点没有开启Relay,或TTL太小在中间节点启用Relay功能,调大TTL
消息偶发丢失消息缓存不足或空口冲突调大缓存,降低发送频率,缩短文本长度
串口打印乱码波特率不匹配,或消息里含不可见字符统一串口波特率,对文本做字符过滤和UTF-8处理
编译报API不存在ESP-IDF版本不同,API有变化优先查看当前版本头文件和官方示例,不要直接粘贴老代码
功耗偏高中继功能一直开启对电池节点关闭Relay,必要时配置LPN和Friendship

如果遇到启动阶段崩溃,可以先关闭蓝牙Mesh业务,单独测试BLE基础功能是否能正常扫描广播,再逐步加入Mesh相关代码,屏蔽法排查定位。

8. 最佳实践与工程建议

8.1 网络拓扑设计

不要把每个设备都开启中继。建议按设备类型划分角色:

  • 常供电节点:网关、智能插座、中继器,开启Relay;
  • 电池节点:传感器、遥控器,关闭Relay,配置为LPN;
  • 控制节点:面板开关、场景面板,可以订阅多个组播地址。

这样可以兼顾覆盖范围和电池续航。

8.2 安全与权限管理

蓝牙Mesh网络安全性取决于配网流程和密钥管理。生产环境需要注意:

  • 默认密钥必须更换,不要在产品中使用蓝牙Mesh规范推荐的默认测试密钥;
  • 配网过程建议增加认证机制,避免恶意设备加入网络;
  • 严禁在日志中打印网络密钥和应用密钥明文;
  • 生产环境需要支持OOB配网,不要使用无认证的“按下即配网”方式;
  • 当设备需要退出网络时,要及时执行节点重置,否则单播地址可能被继续占用。

8.3 日志与调试

ESP32串口日志是调试蓝牙Mesh最重要的工具。建议把日志分级:

ESP_LOGE(TAG, "error message"); ESP_LOGW(TAG, "warn message"); ESP_LOGI(TAG, "info message"); ESP_LOGD(TAG, "debug message");

发布版本时关闭调试日志,保留错误和警告日志。在Demo阶段可以把配网事件、消息接收事件都打印出来,方便观察完整流程。

8.4 生产部署注意事项

  1. 配网引导:给每个设备设计简单可靠的配网模式,比如按钮触发一段时间内可配网;
  2. 固件升级:蓝牙Mesh方案要预留OTA升级能力,尤其是网络密钥、AppKey等发生变更时,设备需要能远程更新;
  3. 兼容性测试:不同芯片厂商的蓝牙Mesh实现可能存在细节差异,设备数量多时要交叉验证;
  4. 整网规模评估:虽然蓝牙Mesh理论上支持几百个节点,但实际拓扑、消息频率、节点角色都会影响表现,部署前要做压力测试。

从工程角度看,蓝牙Mesh最容易被低估的不是“能不能通”,而是“大量节点同时在线时还能不能稳定工作”。建议从小规模Demo开始,逐步扩大节点数量和消息频率,观察网络表现,再最终确定参数。

9. 总结

写到这里,你会发现蓝牙Mesh组网的思路其实很清晰:通过配网让设备持有同一把“钥匙”,通过模型定义消息格式,通过发布订阅完成业务寻址,通过中继节点实现多跳传输。

本文从离线通信场景出发,介绍了蓝牙Mesh的核心概念,对比了开源方案,并给出了基于ESP32和ESP-BLE-MESH的群聊Demo设计思路。代码不是重点,重点是理解数据从手机到网关、从网关到Mesh网络、再由另一侧网关收下来的过程。

如果你是第一次接触蓝牙Mesh开发,建议按这个顺序动手:

  1. 先跑通官方vendor_model示例,完成两个设备的配网和收发;
  2. 再把它改造成本文描述的文本消息Demo;
  3. 然后加入第三个设备,开启中继,验证多跳传输;
  4. 最后再考虑功耗优化、安全配置和生产部署。

蓝牙Mesh不是最复杂的无线组网协议,但确实包含不少细节。希望这篇文章能帮你少走一些弯路,也欢迎在评论区交流你在设备选型、配网流程和消息格式上遇到的问题。如果感觉本文对你有帮助,可以收藏备用,后续还会继续更新更多物联网组网实战内容。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询