ESP32S3-Day04-BLE

ESP32-S3 BLE 七个实验学习笔记

环境:ESP-IDF v5.4 · ESP32-S3 · iPhone 13

协议栈:NimBLE(实验 ①②④⑤)/ Bluedroid(实验 ⑥⑦)/ ESP-BLE-MESH(实验 ⑦)


总览:七个实验在学什么

序号 例程 ESP32 角色 核心原理 手机怎么用 状态
NimBLE_GATT_Server 从机 Peripheral GATT 服务 + 读写/订阅 nRF Connect
NimBLE_Connection 从机 Peripheral 广播 + 连接生命周期 nRF Connect
blecent 主机 Central 扫描 + 连接 + 读远端 GATT 需第二块 ESP32 ⏭ 跳过
NimBLE_Beacon 信标 Beacon 只广播、不可连接 nRF Connect 扫描
NimBLE_Security 从机 + 加密 配对 / Passkey / Bonding nRF Connect
ble_hid_device_demo HID 设备 模拟蓝牙键盘/遥控器 系统蓝牙设置
onoff_server Mesh 节点 网状网 + 配网 + 组控 nRF Mesh

第 0 章:BLE 基础概念(所有实验共用)

1.1 BLE 协议栈分层

复制代码
┌─────────────────────────────────────┐
│  应用层(你的代码:LED、心率、Mesh Model) │
├─────────────────────────────────────┤
│  GATT / GAP / Mesh Models           │  ← 主机层(Host)
├─────────────────────────────────────┤
│  HCI                                │
├─────────────────────────────────────┤
│  蓝牙控制器(Controller)              │  ← 芯片硬件
└─────────────────────────────────────┘
  • GAP(Generic Access Profile):广播、扫描、连接、配对
  • GATT(Generic Attribute Profile):服务 Service、特征 Characteristic、读写 Notify
  • Mesh:在 GAP/GATT 之上,多设备网状通信

1.2 两种经典角色

角色 英文 做什么 类比
从机 Peripheral 广播等人连,提供数据 蓝牙音箱
主机 Central 扫描并主动连接 手机、电脑

实验 ①②④⑤⑥⑦ 中 ESP32 都是从机/节点;实验 ③ 角色反转,ESP32 当主机。

1.3 NimBLE vs Bluedroid

协议栈 特点 本笔记用在
NimBLE 轻量、省 RAM 实验 ①②④⑤
Bluedroid 功能全、HID/Mesh 官方例程多 实验 ⑥⑦

实验 ①:NimBLE_GATT_Server --- GATT 从机与数据交换

例程路径

复制代码
examples/bluetooth/ble_get_started/nimble/NimBLE_GATT_Server

原理

ESP32 作为 GATT Server(从机),定义两个标准服务,等待手机连接后读写数据。

复制代码
上电 → 初始化 LED / NVS / NimBLE
     → 注册 GATT 服务表
     → 开始广播(设备名:NimBLE_GATT)
     → 手机连接
     → 手机读写 Characteristic → ESP32 回调响应

文件分工

文件 职责
main.c 总入口,启动 NimBLE Host 任务 + 心率模拟任务
gap.c 广播参数、连接/断开/订阅事件
gatt_svc.c 核心:GATT 服务表 + 读写回调
led.c 控制板载 LED
heart_rate_mock.c 模拟心率 60--80,每秒更新

提供的两个服务

服务 UUID 特征 权限 作用
Heart Rate 0x180D Heart Rate Measurement 0x2A37 读 + Indicate 模拟心率,可订阅推送
Automation IO 0x1815 LED(自定义 128-bit UUID) 手机写 0x01/0x00 开关灯

与 Arduino 对照

Arduino ESP-IDF NimBLE
BLEDevice::init() nimble_port_init()
BLEServer gatt_svc.c 服务表 gatt_svr_svcs[]
BLECharacteristic + onWrite access_cb(如 led_chr_access
setValue() + notify() ble_gatts_indicate()
startAdvertising() gap.cstart_advertising()

手机测试

  • App:nRF Connect
  • 连接 NimBLE_GATT → 写 Automation IO 控灯 → 订阅 Heart Rate 收数据

实验 ②:NimBLE_Connection --- 连接与广播

例程路径

复制代码
examples/bluetooth/ble_get_started/nimble/NimBLE_Connection

原理

比 ① 更简单:没有自定义 GATT 服务,只练三件事:

  1. 广播 --- 让手机能搜到

  2. 连接 / 断开 --- 处理连上和断开事件

  3. 连接参数 --- 连上后协商间隔、延迟等

    广播中(灯灭)
    ↓ 手机 CONNECT
    连接成功 → LED 亮 + 打印连接信息
    ↓ 手机 DISCONNECT
    断开 → LED 灭 → 自动重新广播

与 ① 的对比

GATT Server(①) Connection(②)
设备名 NimBLE_GATT NimBLE_CONN
自定义服务
连上后能干什么 读写特征值 仅连/断,看 LED
核心学习点 GATT 数据交换 GAP 连接生命周期

gap.c 三个关键事件

事件 行为
BLE_GAP_EVENT_CONNECT 连上 → 亮灯 → 更新连接参数
BLE_GAP_EVENT_DISCONNECT 断开 → 灭灯 → 重新广播
BLE_GAP_EVENT_CONN_UPDATE 连接参数协商完成

Beacon vs Connection 广播区别

Connection Beacon
conn_mode 可连接(UND) 不可连接(NON)
nRF Connect 有 CONNECT 按钮 只能看广播数据

实验 ③:blecent --- GATT 主机(已跳过)

例程路径

复制代码
examples/bluetooth/nimble/blecent

原理

角色反转:ESP32 扮演手机在实验 ① 里的角色 ------ 扫描、连接、发现服务、读写远端 Characteristic。

复制代码
ESP32(Central)扫描 → 找到带 0x1811 服务的设备
    → 连接 → 发现服务 → 读/写/订阅 Notify

为何跳过

需要 两块 ESP32 :一块烧 bleprph(从机),一块烧 blecent(主机)。iPhone 无法充当所需的对端设备。

与 ① 的关系

① GATT Server ③ blecent
你建服务,等别人读写 你主动找服务、读写别人
手机 = Central ESP32 = Central

实验 ④:NimBLE_Beacon --- 信标广播

例程路径

复制代码
examples/bluetooth/ble_get_started/nimble/NimBLE_Beacon

原理

Beacon = 只喊「我在哪、我是谁」,不接待连接。

复制代码
┌─────────────────────────────────────┐
│  Advertising Data(主广播包,≤31B)   │  ← 设备名、Flags
├─────────────────────────────────────┤
│  Scan Response(扫描响应包)          │  ← URI、MAC 等
└─────────────────────────────────────┘
  • conn_mode = NON不可连接
  • 设备名:NimBLE_Beacon
  • Scan Response 含 URI:https://espressif.com

与前面实验对比

GATT Server / Connection Beacon
能否 CONNECT
目的 连上后传数据 只被发现、传递少量信息
典型场景 智能设备 商场定位、资产标签

注意

  • 例程名是 NimBLE_Beacon ,不是 ble_ibeacon(后者是 Apple iBeacon 格式,Bluedroid)
  • nRF Connect 里搜 NimBLE_Beacon ,不应出现 NIMBLE_CONN

实验 ⑤:NimBLE_Security --- 配对与加密

例程路径

复制代码
examples/bluetooth/ble_get_started/nimble/NimBLE_Security

原理

在 ① GATT Server 基础上增加 安全机制

概念 说明
配对 Pairing 手机和 ESP32「认亲」
Passkey ESP32 串口打印 6 位密码,手机输入相同数字
连接加密 配对后数据加密传输
Bonding 记住配对,下次可自动加密
随机 MAC 每次启动可能用随机私有地址广播

与 ① 的对比

GATT Server(①) Security(⑤)
设备名 NimBLE_GATT NimBLE_SEC
连上后 直接读写 读写前弹出配对
特征权限 普通 READ_ENC / WRITE_ENC

配对流

复制代码
连接 → 尝试读写特征值
     → 触发配对(Passkey)
     → 串口:enter passkey 123456 on the peer side
     → 手机输入相同 6 位
     → connection encrypted!
     → 读写生效

实验 ⑥:ble_hid_device_demo --- BLE HID 模拟遥控器

例程路径

复制代码
examples/bluetooth/bluedroid/ble/ble_hid_device_demo

原理

ESP32 模拟 BLE HID 设备 (蓝牙人体学输入设备),走 系统级蓝牙,不是 GATT 自定义服务。

复制代码
按键/定时任务 → 发 HID 报告 → 手机系统接收 → 调音量/媒体键等
项目 内容
协议栈 Bluedroid(不是 NimBLE)
设备名 HID
模拟类型 Consumer 多媒体遥控器
连上后 每约 2 秒自动 音量+ / 音量-

与 GATT Server 的本质区别

GATT Server(①) HID(⑥)
连接方式 nRF Connect 等 App 系统蓝牙设置
谁识别 只有装了对应 App 的 系统自动识别
两个 GPIO 按键 需写 Characteristic + App 配合 直接控制音量/媒体 (改 hid_demo_task 读 GPIO 即可)

两个按键控手机

c 复制代码
// 伪代码
if (button_A) esp_hidd_send_consumer_value(conn_id, HID_CONSUMER_VOLUME_UP, true/false);
if (button_B) esp_hidd_send_consumer_value(conn_id, HID_CONSUMER_VOLUME_DOWN, true/false);

HID 报告需 先 true(按下)再 false(松开)

手机测试

  • 设置 → 蓝牙 → 连接 HID(不用 nRF Connect)
  • 配对成功后音量应自动变化

实验 ⑦:onoff_server --- BLE Mesh 组网

例程路径

复制代码
examples/bluetooth/esp_ble_mesh/onoff_models/onoff_server

原理:Mesh 与点对点 BLE 的本质区别

GATT(①--⑥) BLE Mesh(⑦)
拓扑 1 对 1 多对多网状
连接 通常需 CONNECT 多数不建传统连接,靠广播 + 中继
通信 读写 Characteristic Model + 发布/订阅
距离 约 10--30 m 多跳 Relay,可覆盖整栋楼
入网 扫到就连 必须先配网 Provisioning

五个核心概念

1. 配网 Provisioning(办户口)
复制代码
未配网设备 ──配网──→ 节点(有 NetKey、单播地址、AppKey)
         ↑
    Provisioner(手机 nRF Mesh / 另一块 ESP32)
  • NetKey:整网共用,网络身份
  • AppKey:绑定到 Model,控制哪类应用
  • 单播地址 :每个节点唯一(如 0x0001
2. 节点 · 元素 · 模型
复制代码
节点(一块 ESP32)
 └── 元素 Element 0
      ├── Configuration Server(标配)
      └── Generic OnOff Server(开关灯,UUID 相关 0x1000)

Model = 具体能力(开关、传感器、自定义协议)。

3. 发布 / 订阅(像 MQTT,但本地无 Broker)
概念 MQTT BLE Mesh
发布 往 Topic 发 往发布地址 / 组地址发 Model 消息
订阅 订阅 Topic Model 订阅组地址(如 0xC000 = 一组灯)
复制代码
[开关 Client] ──→ [中继 Relay] ──→ [灯 Server]
4. 节点特性
特性 作用
Relay 帮别人转发(组网必备)
Proxy 手机 通过 GATT 接入 Mesh(iPhone 必需
Friend + LPN 低功耗节点 + 好友存消息
5. 与 MQTT 的关系
  • Mesh:本地多设备、无 WiFi、省电、多跳 ------ 「局域网广播网」
  • MQTT :上云、远程、需 Broker ------ 常通过 Mesh 网关 + WiFi 再转 MQTT

配网流程(nRF Mesh · iPhone)

  1. 安装 nRF Mesh(不是 nRF Connect)
  2. 创建 Network
  3. 底部 Scanner → 扫未配网设备
  4. Identify → Provision(贴手机、等 30 秒)
  5. 节点页 → Add AppKey → Bind Generic OnOff Server
  6. 发 On/Off → RGB 亮灭

常见问题与处理

现象 处理
扫不到 确认 onoff_server + erase-flash;非 GATT/HID 固件
device not supported Mesh 1.1 EPA;用 Mesh 1.0;单元素节点
配网成功灯不控 Bind AppKey 到 OnOff Server
rsn 0x13 断开 nRF Mesh iOS 兼容性 → 关 V11/EPA 或换 Silicon Labs App

推荐 sdkconfig 兼容项(nRF Mesh iOS)

复制代码
# CONFIG_BLE_MESH_V11_SUPPORT is not set
# CONFIG_BLE_MESH_HCI_5_0 is not set
# CONFIG_BLE_MESH_PROV_EPA is not set
CONFIG_BLE_MESH_PB_GATT=y
CONFIG_BLE_MESH_GATT_PROXY_SERVER=y

附录 A:七个实验的学习路线

复制代码
① GATT Server     手机连 ESP32,读写 LED / 心率
       ↓
② Connection      连上亮灯、断开灭灯,理解 GAP
       ↓
③ blecent         (需两块板)ESP32 当主机 --- 可跳过
       ↓
④ Beacon          只广播不可连,理解广播包结构
       ↓
⑤ Security        Passkey 配对后才能读写
       ↓
⑥ HID             系统蓝牙遥控器,两个键可控手机
       ↓
⑦ Mesh            配网 + Model + 组控,多设备网状网

附录 B:手机 App 对照

App 用于实验 用途
nRF Connect ①②④⑤ GATT 连接、读写 Characteristic
nRF Mesh Mesh 配网、Bind AppKey、OnOff 控灯
系统蓝牙设置 配对 HID 设备
Silicon Labs Mesh ⑦ 备选 配网兼容备选
EspBleMesh ⑦ 备选 仅 Android,对 ESP 最友好

附录 C:编译常见问题

现象 处理
ninja log v6 AssertionError Full Clean / 删 build;或忽略(扩展解析日志问题)
Mesh 扫到 NIMBLE_CONN 烧错固件,应烧 NimBLE_Beacononoff_server
HID 在 nRF Connect 无效果 必须在 系统设置 → 蓝牙HID

附录 D:官方文档


文档生成自 ESP32-S3 BLE 七个实验实践记录 · ESP-IDF 5.4