第 7 篇:BLE 蓝牙------近场通信与智能配网
WiFi 让 ESP32 连上了互联网,但有个鸡生蛋的问题:设备第一次怎么知道 WiFi 密码? BLE 蓝牙解决了这个问题------用手机通过蓝牙把 WiFi 凭据传给设备。同时,BLE 本身也是一个近场通信方案。
1. BLE 核心概念速览
在写代码之前,先搞清楚 BLE 的几个关键概念:
BLE 角色:
├── Central(中心设备)→ 手机(主动扫描、发起连接)
└── Peripheral(外设) → ESP32(广播、等待连接)
GATT 数据层次:
Profile(配置文件)
└── Service(服务) ← UUID 标识,如 0x1809 = 健康温度计
└── Characteristic(特征值)← 实际数据载体
├── Value(值)
└── Descriptor(描述符)
Characteristics 的操作类型:
| 属性 | 含义 | 方向 |
|---|---|---|
| Read | 手机主动读 | 外设→手机 |
| Write | 手机主动写 | 手机→外设 |
| Notify | 外设主动推 | 外设→手机(无需手机轮询) |
| Indicate | 带确认的推送 | 外设→手机(手机必须确认) |
2. ESP32 作为 BLE 外设------完整代码
c
// ble_sensor.c ------ BLE GATT 服务器,暴露温湿度服务
#include "esp_gap_ble_api.h"
#include "esp_gatts_api.h"
#include "esp_bt_main.h"
#include "esp_bt.h"
#define GATTS_SERVICE_UUID 0x00FF
#define GATTS_CHAR_TEMP_UUID 0xFF01
#define GATTS_CHAR_HUMI_UUID 0xFF02
#define GATTS_NUM_HANDLE 8
static uint8_t adv_config_done = 0;
// 广播数据:设备名 + 16-bit Service UUID
static esp_ble_adv_data_t adv_data = {
.set_scan_rsp = false,
.include_name = true,
.include_txpower = true,
.flag = (ESP_BLE_ADV_FLAG_GEN_DISC | ESP_BLE_ADV_FLAG_BREDR_NOT_SPT),
};
static esp_ble_adv_params_t adv_params = {
.adv_int_min = 0x20, // 32 × 0.625ms = 20ms
.adv_int_max = 0x40, // 64 × 0.625ms = 40ms
.adv_type = ADV_TYPE_IND,
.own_addr_type = BLE_ADDR_TYPE_PUBLIC,
.channel_map = ADV_CHNL_ALL,
.adv_filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY,
};
// GATT 事件回调
static void gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if,
esp_ble_gatts_cb_param_t *param) {
switch (event) {
case ESP_GATTS_REG_EVT:
// 注册成功 → 设置广播数据
esp_ble_gap_set_device_name("ESP32-Sensor");
esp_ble_gap_config_adv_data(&adv_data);
break;
case ESP_GATTS_READ_EVT:
// 手机读取温湿度
if (param->read.handle == temp_handle) {
float temp = 25.6f; // 实际从传感器读
esp_ble_gatts_send_response(gatts_if, param->read.conn_id,
param->read.trans_id, ESP_GATT_OK, NULL);
}
break;
case ESP_GATTS_CONNECT_EVT:
// 手机连上了,可以降低广播间隔省电
esp_ble_gap_stop_advertising();
break;
case ESP_GATTS_DISCONNECT_EVT:
// 手机断开了,重新开始广播
esp_ble_gap_start_advertising(&adv_params);
break;
default:
break;
}
}
// Gap 事件回调
static void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param) {
switch (event) {
case ESP_GAP_BLE_ADV_DATA_SET_COMPLETE_EVT:
adv_config_done = 1;
esp_ble_gap_start_advertising(&adv_params);
break;
default:
break;
}
}
// 初始化 BLE
void ble_sensor_init(void) {
esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT); // 只开 BLE,释放经典蓝牙内存
esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
esp_bt_controller_init(&bt_cfg);
esp_bt_controller_enable(ESP_BT_MODE_BLE);
esp_bluedroid_init();
esp_bluedroid_enable();
esp_ble_gatts_register_callback(gatts_event_handler);
esp_ble_gap_register_callback(gap_event_handler);
esp_ble_gatts_app_register(GATTS_SERVICE_UUID);
}
3. BLE 配网------解决"第一次联网"问题
市面上几乎所有智能家居设备都用 BLE 配网。流程如下:
┌──────┐ ┌────────┐
│ 手机 │ │ ESP32 │
│ App │ │ │
└──┬───┘ └───┬────┘
│ 1. 扫描 BLE 设备 │
│←─────────────────────────────│ 广播 "ESP32-Sensor"
│ 2. 连接 │
│─────────────────────────────→│
│ 3. 写入 WiFi SSID+Password │
│ (Write Characteristic) │
│─────────────────────────────→│ 收到凭据 → 存 NVS
│ 4. 断开连接 │
│←─────────────────────────────│ 重启,用新凭据连 WiFi
│ │
│ 5. 设备 via WiFi 上报状态 │
│←═════════════════════════════│ "配网成功,IP=192.168.1.100"
ESP32 端的关键代码:
c
// 定义配网专用的 Characteristic
// UUID: 0xFF03, 属性: Write, 最大长度: 64 字节
// 手机写入的 JSON: {"ssid":"MyWiFi","password":"12345678"}
static void gatts_event_handler(esp_gatts_cb_event_t event, ...) {
case ESP_GATTS_WRITE_EVT: {
// 收到手机发来的 WiFi 凭据
char ssid[33] = {0}, pass[65] = {0};
// 解析 JSON → 写入 NVS
nvs_set_str(nvs_handle, "ssid", ssid);
nvs_set_str(nvs_handle, "pass", pass);
nvs_commit(nvs_handle);
// 告诉手机"收到"
esp_ble_gatts_send_response(gatts_if, param->write.conn_id, ...);
// 延迟 1 秒后重启
vTaskDelay(pdMS_TO_TICKS(1000));
esp_restart();
}
}
重启后 app_main 里:
c
// 从 NVS 读凭据
nvs_get_str(nvs_handle, "ssid", ssid, &len);
nvs_get_str(nvs_handle, "pass", pass, &len2);
if (strlen(ssid) > 0) {
wifi_connect(ssid, pass); // 正常连 WiFi
} else {
ble_provisioning_start(); // 没有凭据 → 进入配网模式
}
4. BLE 配网 vs SmartConfig vs 网页配网
| 方式 | 优点 | 缺点 |
|---|---|---|
| BLE 配网 | 稳定、成功率高、支持回传状态 | 需要蓝牙 |
| SmartConfig | 不需要蓝牙 | 部分路由器不兼容、成功率约 70% |
| 网页配网(AP模式) | 不需要 App | 用户操作繁琐(连热点→填表单) |
| 声波配网 | 酷炫 | 环境噪声影响大 |
推荐方案:BLE 为主,AP 模式为备份。
下一篇:OTA 远程升级------设备装到天花板上了,怎么更新固件?