为什么选择蓝牙 Mesh?
说到智能家居组网,很多人第一反应是 WiFi 或者 Zigbee。但蓝牙 Mesh 其实是个被低估的选手。
它有几个明显优势:
- 覆盖范围广:通过节点中继,信号可以穿墙过户,轻松覆盖 100+ 平米
- 低功耗:设备待机功耗极低,电池供电的传感器能用几个月甚至一年
- 成本低:蓝牙芯片价格亲民,ESP32 开发板几十块就能搞定
- 手机直连:不需要额外网关,手机就能直接控制设备
如果你正在搭建智能家居系统,又不想花大价钱买成套方案,蓝牙 Mesh 是个很务实的选择。
硬件清单
| 设备 | 型号 | 数量 | 单价 | 总价 |
|---|---|---|---|---|
| ESP32 开发板 | ESP32-WROOM-32 | 3 块 | ¥25 | ¥75 |
| 蓝牙 Mesh 模组 | JDY-64 | 2 个 | ¥18 | ¥36 |
| 温湿度传感器 | SHT30 | 1 个 | ¥15 | ¥15 |
| 继电器模块 | 5V 单路 | 2 个 | ¥8 | ¥16 |
| USB 数据线 | Micro-USB | 3 根 | ¥5 | ¥15 |
| 面包板 | 830 孔 | 1 个 | ¥12 | ¥12 |
| 杜邦线 | 公对公/母对母 | 20 根 | ¥8 | ¥8 |
| 合计 | – | – | – | ¥177 |
所有配件都能在淘宝或立创商城买到,总价不到 200 块就能搭建一套完整的蓝牙 Mesh 网络。
蓝牙 Mesh 基础概念
在动手之前,先搞懂几个核心概念:
节点(Node)
每个加入 Mesh 网络的设备都是一个节点。节点可以:
- 发送消息(比如温湿度传感器上报数据)
- 接收消息(比如继电器接收开关指令)
- 中继消息(帮助其他节点转发信号)
元素(Element)
一个节点可以包含多个元素。比如一个智能开关面板,可能有 3 个按键,每个按键就是一个独立的元素。
模型(Model)
模型定义了设备的功能。常见的有:
- Generic OnOff:开关控制
- Sensor:传感器数据上报
- Light Lightness:灯光亮度调节
发布/订阅(Publish/Subscribe)
这是 Mesh 网络的核心机制:
- 发布地址:设备向哪个地址发送消息
- 订阅地址:设备监听哪个地址的消息
举个例子:温湿度传感器发布到地址 0xC001,继电器订阅 0xC001,这样传感器数据就能自动触发继电器动作。
环境搭建
1. 安装 ESP-IDF
ESP32 的官方开发框架是 ESP-IDF。我们用 Docker 方式安装,避免污染系统环境:
# 拉取 ESP-IDF Docker 镜像
docker pull espressif/idf
# 创建工作目录
mkdir -p ~/esp-mesh-project
cd ~/esp-mesh-project
# 启动容器
docker run --rm -v $PWD:/project -w /project -it espressif/idf bash
2. 创建项目
# 在容器内执行
idf.py create-project bluetooth-mesh-node
cd bluetooth-mesh-node
3. 配置 Mesh 参数
编辑 sdkconfig,启用蓝牙 Mesh 支持:
idf.py menuconfig
导航到:
Component config → Bluetooth → Bluedroid Enable → Enable Bluetooth Mesh
保存退出后,执行:
idf.py fullclean
代码实现
节点主程序
创建 main/main.c:
#include
#include "esp_log.h"
#include "nvs_flash.h"
#include "esp_bt.h"
#include "esp_ble_mesh_api.h"
static const char *TAG = "MESH_NODE";
// 设备 UUID(每个设备需要唯一)
static uint8_t dev_uuid[16] = {
0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd
};
// Mesh 配置
static esp_ble_mesh_cfg_srv_t config_server = {
.relay = ESP_BLE_MESH_RELAY_DISABLED,
.beacon = ESP_BLE_MESH_BEACON_ENABLED,
};
static esp_ble_mesh_model_t models[] = {
ESP_BLE_MESH_MODEL_CFG_SRV(&config_server),
ESP_BLE_MESH_MODEL_NONE(),
};
static esp_ble_mesh_elem_t elements[] = {
ESP_BLE_MESH_ELEMENT(0, models, models, models),
};
static esp_ble_mesh_comp_t composition = {
.cid = 0x02E5,
.elements = elements,
.element_count = ARRAY_SIZE(elements),
};
static esp_ble_mesh_prov_t provision = {
.uuid = dev_uuid,
.uuid_size = sizeof(dev_uuid),
.attention_duration = 3,
};
// Mesh 事件回调
static void mesh_callback(esp_ble_mesh_event_t *event) {
switch (event->event) {
case ESP_BLE_MESH_PROVISION_NODE_EVT:
ESP_LOGI(TAG, "节点配网成功");
break;
case ESP_BLE_MESH_NODE_EVT:
ESP_LOGI(TAG, "节点收到消息");
break;
default:
break;
}
}
void app_main(void) {
esp_err_t ret;
// 初始化 NVS
ret = nvs_flash_init();
if (ret == ESP_ERR_NVS_NO_FREE_PAGES) {
ESP_ERROR_CHECK(nvs_flash_erase());
ret = nvs_flash_init();
}
ESP_ERROR_CHECK(ret);
// 初始化蓝牙
ESP_ERROR_CHECK(esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT));
esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_bt_controller_init(&bt_cfg));
ESP_ERROR_CHECK(esp_bt_controller_enable(ESP_BT_MODE_BLE));
// 初始化 Bluedroid
ESP_ERROR_CHECK(esp_bluedroid_init());
ESP_ERROR_CHECK(esp_bluedroid_enable());
// 初始化 Mesh
esp_ble_mesh_init(mesh_callback);
// 开始配网
ESP_ERROR_CHECK(esp_ble_mesh_provisioner_add_unprov_dev(
dev_uuid, sizeof(dev_uuid),
0, 0, NULL, 0
));
ESP_LOGI(TAG, "蓝牙 Mesh 节点启动完成");
}
编译烧录
# 编译项目
idf.py build
# 烧录到 ESP32(替换 /dev/ttyUSB0 为你的设备端口)
idf.py -p /dev/ttyUSB0 flash monitor
组网配置
1. 配网(Provisioning)
使用手机 App(如 nRF Mesh)进行配网:
- 打开 App,点击 "+" 添加设备
- 扫描到未配网的 ESP32 节点
- 设置设备名称(如 "Living Room Light")
- 分配单播地址(如 0x0001)
2. 配置发布/订阅
在 App 中配置:
设备:Living Room Light
├─ 订阅地址:0xC001(群组地址)
└─ 发布地址:0x0001(自身单播地址)
设备:Bedroom Sensor
├─ 订阅地址:0x0002(自身单播地址)
└─ 发布地址:0xC001(群组地址)
这样,传感器数据发布到 0xC001,所有订阅该地址的设备都能收到。
3. 创建场景
场景是一组预定义的操作:
场景名称:离家模式
触发条件:按下场景开关
执行动作:
- 关闭客厅灯(地址 0x0001)
- 关闭卧室灯(地址 0x0002)
- 开启安防模式(地址 0x0003)
常见问题排查
问题 1:设备无法配网
症状:手机 App 扫描不到设备
排查步骤:
- 检查 ESP32 是否成功启动(查看串口日志)
- 确认蓝牙已启用:
esp_bt_controller_enable(ESP_BT_MODE_BLE) - 检查 UUID 是否唯一(每个设备必须不同)
- 确保设备在配网模式(未配网状态)
问题 2:消息无法传递
症状:设备已配网,但控制指令无响应
排查步骤:
- 检查发布/订阅地址是否匹配
- 确认群组地址格式正确(0xC000-0xFFFF)
- 检查网络密钥是否一致
- 尝试增加中继节点(信号弱时)
问题 3:功耗过高
症状:电池供电设备续航短
优化方案:
- 启用低功耗节点(LPN)模式
- 增加 Friend 节点协助存储消息
- 减少消息发送频率
- 使用深度睡眠:
// 进入深度睡眠(10 秒后唤醒)
esp_deep_sleep(10 * 1000000ULL);
问题 4:覆盖范围不足
症状:远距离设备通信不稳定
解决方案:
- 增加中继节点(开启 Relay 功能)
- 调整天线位置(避免金属遮挡)
- 使用外部天线(IPEX 接口)
- 优化 PCB 布局(参考 ESP32 天线设计指南)
实战案例:智能灯光系统
让我们搭建一个完整的智能灯光系统:
系统架构
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ 场景开关 │────▶│ 网关节点 │◀────│ 手机 App │
│ (0x0001) │ │ (0x0002) │ │ │
└─────────────┘ └──────┬──────┘ └─────────────┘
│
┌────────────┼────────────┐
▼ ▼ ▼
┌─────────┐ ┌─────────┐ ┌─────────┐
│ 客厅灯 │ │ 卧室灯 │ │ 厨房灯 │
│(0x0003) │ │(0x0004) │ │(0x0005) │
└─────────┘ └─────────┘ └─────────┘
配置步骤
- 配网所有设备:按顺序配网 5 个节点
- 创建群组:
- 群组地址 0xC001:所有灯光
- 群组地址 0xC002:客厅 + 厨房
- 配置场景:
- 回家模式:开启 0xC001(全部灯光)
- 观影模式:开启 0xC002,关闭卧室灯
- 离家模式:关闭 0xC001
自动化联动
添加传感器实现自动化:
如果 光照传感器 < 100lux 且 人体传感器 = 检测到
则 开启对应区域灯光(延迟 30 秒自动关闭)
性能优化建议
1. 网络拓扑优化
- 星型拓扑:适合小范围(<50 平米)
- 网状拓扑:适合大范围,启用中继
- 混合拓扑:关键路径用网状,边缘用星型
2. 消息优先级
// 高优先级消息(立即发送)
esp_ble_mesh_generic_server_publish(..., TTL_HIGH);
// 低优先级消息(可延迟)
esp_ble_mesh_generic_server_publish(..., TTL_LOW);
3. 安全加固
- 启用应用密钥加密
- 定期更新网络密钥
- 限制配网时间窗口
- 使用 OOB 认证(如二维码)
总结
蓝牙 Mesh 是搭建智能家居的务实选择。它成本低、覆盖广、功耗低,而且不需要额外网关。
关键要点:
- 理解发布/订阅机制是组网的核心
- 合理规划网络拓扑和地址分配
- 低功耗场景启用 LPN 模式
- 信号弱的区域增加中继节点
200 块的硬件投入,就能搭建一套覆盖全屋的智能控制系统。剩下的就是发挥创意,把你的想法变成现实。
希望这篇博客文章对您有所帮助!