您好!
您希望将之前的内容整合在一起,设计一个基于 ESP32-C3 实现 BLE Mesh Provisioner 的详细示例代码,且不依赖手机 SDK,全程由 ESP32-C3 完成配置和控制,并提供通过 串口 或 按键 的用户交互界面。我将为您提供尽可能详细的设计和完整的代码。
项目概述
BLE Mesh 是一种基于蓝牙低功耗(BLE)的网状网络协议,允许设备之间形成自组织、自愈合的网络。Provisioner(配置器) 是 BLE Mesh 网络中的关键角色,负责将未配置的节点添加到网络中,分配地址和密钥。
本项目旨在使用 ESP32-C3 作为 BLE Mesh Provisioner,不依赖手机或其他设备,全程由 ESP32-C3 完成所有配置和控制。用户可以通过 串口 或 按键 与设备交互,实现对网络的管理。
目录
- 环境准备
- 项目创建
- 代码实现
- 3.1 头文件和宏定义
- 3.2 全局变量
- 3.3 用户交互接口
- 3.3.1 串口交互
- 3.3.2 按键处理
- 3.4 回调函数
- 3.5 初始化函数
- 3.6
app_main
函数
- 编译和烧录
- 测试与验证
- 注意事项
- 总结
1. 环境准备
-
硬件设备:
- ESP32-C3 开发板
- 其他支持 BLE Mesh 的设备(作为节点)
- 按键和 LED(如果开发板上未集成,可以自行连接)
-
软件工具:
- ESP-IDF(建议使用 v4.4 或以上版本,支持 ESP32-C3)
- ESP-IDF 工具链(包含编译器、调试器等)
- 串口调试工具(如 PuTTY、minicom 等)
-
必要的驱动:
- 安装 USB 串口驱动,以便电脑识别开发板
2. 项目创建
-
设置 ESP-IDF 环境:
确保已正确安装和配置 ESP-IDF。可以通过以下命令检查版本:
idf.py --version
-
创建项目目录:
在工作空间创建一个新的项目目录:
mkdir -p ~/esp/ble_mesh_provisioner cd ~/esp/ble_mesh_provisioner
-
创建项目:
使用 ESP-IDF 提供的模板创建新项目:
idf.py create-project my_ble_mesh_provisioner cd my_ble_mesh_provisioner
-
配置项目:
在项目目录下运行:
idf.py menuconfig
-
导航到 Bluetooth 配置:
Component config ---> Bluetooth ---> Bluetooth mesh support
-
启用 BLE Mesh:
- 勾选 Enable Bluetooth Mesh
-
设置设备角色:
- 将 Device Role 设置为 Provisioner
-
-
启用 UART 串口:
确保串口配置正确,波特率设置为 115200(或根据需要调整)。
-
3. 代码实现
下面将详细介绍主要代码的实现,包括每个部分的功能和解释。
3.1 头文件和宏定义
// main.c
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "esp_system.h"
#include "nvs_flash.h"
#include "esp_log.h"
#include "esp_err.h"
#include "driver/uart.h"
#include "driver/gpio.h"
#include "esp_bt.h"
#include "esp_bt_main.h"
#include "esp_ble_mesh_common_api.h"
#include "esp_ble_mesh_defs.h"
#include "esp_ble_mesh_provisioning_api.h"
#include "esp_ble_mesh_config_model_api.h"
#define TAG "BLE_MESH_PROVISIONER"
// UART 配置
#define UART_NUM UART_NUM_0
#define UART_TX_PIN GPIO_NUM_1
#define UART_RX_PIN GPIO_NUM_3
#define UART_BAUD_RATE 115200
#define UART_BUF_SIZE 256
// 按键和 LED 配置
#define BUTTON_GPIO GPIO_NUM_9
#define LED_GPIO GPIO_NUM_10
-
包含必要的头文件:
- FreeRTOS、ESP 系统相关头文件
- UART 和 GPIO 驱动
- 蓝牙 和 BLE Mesh API
-
定义日志标签和硬件配置宏:
TAG
:用于日志输出时标识模块- UART 和 GPIO 的引脚和参数
3.2 全局变量
/* 定义 Provisioner 的组成元素 */
static esp_ble_mesh_prov_t provisioner_prov = {
.prov_uuid = {0x32, 0x10}, // Provisioner 的 UUID,可以自行定义
// 其他配置项可以根据需要添加
};
/* 定义配置客户端模型 */
static esp_ble_mesh_client_t config_client;
/* 定义元素和模型 */
ESP_BLE_MESH_MODEL_PUB_DEFINE(config_client_pub, 16, ROLE_PROVISIONER);
static esp_ble_mesh_model_t root_models[] = {
ESP_BLE_MESH_MODEL_CFG_CLI(&config_client_pub, &config_client),
};
static esp_ble_mesh_elem_t elements[] = {
ESP_BLE_MESH_ELEMENT(0, root_models, ESP_BLE_MESH_MODEL_NONE),
};
static esp_ble_mesh_comp_t composition = {
.cid = 0xFFFF, // 公司 ID,0xFFFF 表示未定义
.elements = elements,
.element_count = ARRAY_SIZE(elements),
};
/* UART 事件队列句柄 */
static QueueHandle_t uart_queue;
/* Provisioned 节点列表 */
typedef struct {
uint16_t unicast_addr;
uint8_t dev_uuid[16];
} node_info_t;
#define MAX_NODES 10
static node_info_t nodes[MAX_NODES];
static uint8_t node_count = 0;
-
Provisioner 配置:
esp_ble_mesh_prov_t
结构体包含了配置器的配置信息,如 UUID。
-
配置客户端模型:
esp_ble_mesh_client_t
用于处理模型的客户端操作。config_client_pub
是模型的发布上下文。
-
模型和元素:
root_models
定义了根元素的模型,这里添加了配置客户端模型。elements
定义了设备的元素列表。
-
设备组成(Composition):
composition
包含了设备的公司 ID、元素等信息。
-
UART 事件队列和节点信息:
uart_queue
:用于接收 UART 事件。nodes
:存储已配置的节点信息。
3.3 用户交互接口
3.3.1 串口交互
/* UART 初始化 */
static void uart_init(void)
{
const uart_config_t uart_config = {
.baud_rate = UART_BAUD_RATE,
.data_bits = UART_DATA_8_BITS,
.parity = UART_PARITY_DISABLE,
.stop_bits = UART_STOP_BITS_1,
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
};
uart_param_config(UART_NUM, &uart_config);
uart_set_pin(UART_NUM, UART_TX_PIN, UART_RX_PIN, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
uart_driver_install(UART_NUM, UART_BUF_SIZE * 2, UART_BUF_SIZE * 2, 20, &uart_queue, 0);
}
/* UART 事件处理任务 */
static void uart_task(void *arg)
{
uart_event_t event;
uint8_t data[UART_BUF_SIZE];
while (1) {
if (xQueueReceive(uart_queue, &event, portMAX_DELAY)) {
switch (event.type) {
case UART_DATA:
memset(data, 0, UART_BUF_SIZE);
int len = uart_read_bytes(UART_NUM, data, event.size, portMAX_DELAY);
if (len > 0) {
data[len] = '\0';
ESP_LOGI(TAG, "Received command: %s", data);
// 解析命令并执行相应操作
if (strcmp((char *)data, "scan\n") == 0) {
// 开始扫描未配置节点
esp_ble_mesh_provisioner_prov_enable(BLE_MESH_PROV_ADV | BLE_MESH_PROV_GATT);
ESP_LOGI(TAG, "Start scanning unprovisioned devices");
} else if (strcmp((char *)data, "list\n") == 0) {
// 列出已配置节点
for (int i = 0; i < node_count; i++) {
ESP_LOGI(TAG, "Node %d: Unicast Addr: 0x%04x", i, nodes[i].unicast_addr);
}
} else {
ESP_LOGW(TAG, "Unknown command");
}
}
break;
default:
break;
}
}
}
vTaskDelete(NULL);
}
-
UART 初始化:
- 配置 UART 参数,安装 UART 驱动,并创建事件队列。
-
UART 任务:
- 等待 UART 事件队列中的事件。
- 当接收到数据时,读取并解析命令,执行相应的操作。
-
支持的命令示例:
scan
:开始扫描未配置的设备。list
:列出已配置的节点。
3.3.2 按键处理
/* 按键中断服务程序 */
static void IRAM_ATTR button_isr_handler(void* arg)
{
// 通知主任务执行相应操作,例如开始扫描
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
uint32_t gpio_num = (uint32_t) arg;
xQueueSendFromISR(uart_queue, &gpio_num, &xHigherPriorityTaskWoken);
if (xHigherPriorityTaskWoken) {
portYIELD_FROM_ISR();
}
}
/* GPIO 初始化 */
static void gpio_init(void)
{
gpio_config_t io_conf = {};
// 配置按键引脚
io_conf.intr_type = GPIO_INTR_NEGEDGE;
io_conf.mode = GPIO_MODE_INPUT;
io_conf.pin_bit_mask = (1ULL << BUTTON_GPIO);
io_conf.pull_up_en = GPIO_PULLUP_ENABLE;
gpio_config(&io_conf);
// 安装 GPIO 中断服务程序
gpio_install_isr_service(0);
gpio_isr_handler_add(BUTTON_GPIO, button_isr_handler, (void*) BUTTON_GPIO);
// 配置 LED 引脚
gpio_set_direction(LED_GPIO, GPIO_MODE_OUTPUT);
}
-
按键中断处理:
- 配置按键引脚为输入模式,设置下降沿中断。
- 安装中断服务程序,在中断中通知主任务执行操作。
-
GPIO 初始化:
- 初始化按键和 LED 引脚。
3.4 回调函数
/* 配置客户端模型回调函数 */
static void config_client_cb(esp_ble_mesh_cfg_client_cb_event_t event,
esp_ble_mesh_cfg_client_cb_param_t *param)
{
// 处理配置客户端模型事件
// 根据需要添加代码
}
/* BLE Mesh 事件回调函数 */
static void ble_mesh_provisioning_cb(esp_ble_mesh_prov_cb_event_t event,
esp_ble_mesh_prov_cb_param_t *param)
{
switch (event) {
case ESP_BLE_MESH_PROV_REGISTER_COMP_EVT:
ESP_LOGI(TAG, "Provisioner registered");
break;
case ESP_BLE_MESH_PROV_UNPROV_DEV_ADV_PKT_EVT:
ESP_LOGI(TAG, "Unprovisioned device found, UUID:");
esp_log_buffer_hex(TAG, param->unprov_dev_adv_pkt.dev_uuid, 16);
// 自动将发现的设备添加到网络
esp_ble_mesh_unprov_dev_add_t add_dev = {};
memcpy(add_dev.addr, param->unprov_dev_adv_pkt.addr, 6);
add_dev.addr_type = param->unprov_dev_adv_pkt.addr_type;
memcpy(add_dev.uuid, param->unprov_dev_adv_pkt.dev_uuid, 16);
esp_ble_mesh_provisioner_add_unprov_dev(&add_dev, ADD_DEV_RM_AFTER_PROV);
break;
case ESP_BLE_MESH_PROV_PROVISIONER_PROV_COMPLETE_EVT:
ESP_LOGI(TAG, "Provisioning complete, Node Unicast Addr: 0x%04x", param->provisioner_prov_complete.addr);
// 保存节点信息
if (node_count < MAX_NODES) {
nodes[node_count].unicast_addr = param->provisioner_prov_complete.addr;
memcpy(nodes[node_count].dev_uuid, param->provisioner_prov_complete.dev_uuid, 16);
node_count++;
} else {
ESP_LOGW(TAG, "Node list is full");
}
break;
default:
break;
}
}
-
配置客户端模型回调:
- 处理配置客户端模型的事件。
-
BLE Mesh 配置器回调:
ESP_BLE_MESH_PROV_UNPROV_DEV_ADV_PKT_EVT
:发现未配置的设备,自动添加到网络。ESP_BLE_MESH_PROV_PROVISIONER_PROV_COMPLETE_EVT
:配置完成,保存节点信息。
3.5 初始化函数
/* 初始化蓝牙和 BLE Mesh */
static esp_err_t ble_mesh_init(void)
{
esp_err_t err;
/* 初始化 NVS */
err = nvs_flash_init();
if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) {
ESP_ERROR_CHECK(nvs_flash_erase());
err = nvs_flash_init();
}
ESP_ERROR_CHECK(err);
/* 初始化蓝牙控制器 */
esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
err = esp_bt_controller_init(&bt_cfg);
if (err) {
ESP_LOGE(TAG, "Bluetooth controller init failed");
return err;
}
err = esp_bt_controller_enable(ESP_BT_MODE_BLE);
if (err) {
ESP_LOGE(TAG, "Bluetooth controller enable failed");
return err;
}
/* 初始化 Bluedroid 栈 */
err = esp_bluedroid_init();
if (err) {
ESP_LOGE(TAG, "Bluedroid stack init failed");
return err;
}
err = esp_bluedroid_enable();
if (err) {
ESP_LOGE(TAG, "Bluedroid stack enable failed");
return err;
}
/* 注册回调函数 */
esp_ble_mesh_register_prov_callback(ble_mesh_provisioning_cb);
esp_ble_mesh_register_config_client_callback(config_client_cb);
/* 初始化 Mesh 栈 */
esp_ble_mesh_init_param_t init_param = {
.prov = &provisioner_prov,
.comp = &composition,
};
err = esp_ble_mesh_init(&init_param);
if (err) {
ESP_LOGE(TAG, "BLE Mesh init failed");
return err;
}
/* 设置设备为 Provisioner */
err = esp_ble_mesh_provisioner_set_dev_uuid(provisioner_prov.prov_uuid, 16);
if (err) {
ESP_LOGE(TAG, "Set device UUID failed");
return err;
}
/* 分配地址池 */
err = esp_ble_mesh_provisioner_set_node_name(0x0005, "Node1");
if (err) {
ESP_LOGE(TAG, "Set node name failed");
return err;
}
ESP_LOGI(TAG, "BLE Mesh Provisioner initialized");
return ESP_OK;
}
- 蓝牙和 BLE Mesh 初始化:
- 初始化 NVS、蓝牙控制器、Bluedroid 栈。
- 注册回调函数。
- 初始化 BLE Mesh 协议栈,设置设备为 Provisioner。
3.6 app_main
函数
void app_main(void)
{
esp_err_t err;
/* 初始化 UART */
uart_init();
/* 初始化 GPIO */
gpio_init();
/* 初始化 BLE Mesh */
err = ble_mesh_init();
if (err) {
ESP_LOGE(TAG, "BLE Mesh init failed");
return;
}
/* 创建 UART 任务 */
xTaskCreate(uart_task, "uart_task", 4096, NULL, 10, NULL);
ESP_LOGI(TAG, "ESP32-C3 BLE Mesh Provisioner started");
/* 主循环 */
while (1) {
// 可添加其他逻辑,例如 LED 指示
vTaskDelay(pdMS_TO_TICKS(1000));
}
}
-
初始化 UART、GPIO 和 BLE Mesh:
- 调用各自的初始化函数。
-
创建 UART 任务:
- 创建用于处理 UART 事件的任务。
-
主循环:
- 在循环中可以添加其他逻辑,例如 LED 指示。
4. 编译和烧录
-
配置项目:
在项目目录下,运行以下命令进入菜单配置:
idf.py menuconfig
-
导航到 Bluetooth 配置:
Component config ---> Bluetooth ---> Bluetooth mesh support
-
启用 BLE Mesh:
- 勾选 Enable Bluetooth Mesh
-
设置设备角色:
- 将 Device Role 设置为 Provisioner
-
-
其他配置:
- 根据需要调整日志等级、串口波特率等。
-
-
编译项目:
idf.py build
-
烧录固件:
idf.py -p /dev/ttyUSB0 flash
- 将
/dev/ttyUSB0
替换为实际的串口端口。
- 将
-
监控日志:
idf.py -p /dev/ttyUSB0 monitor
5. 测试与验证
-
启动 ESP32-C3:
- 上电或复位 ESP32-C3 开发板,观察串口日志,确认 BLE Mesh 初始化成功。
-
通过串口与设备交互:
- 使用串口调试工具连接到 ESP32-C3,设置波特率为 115200。
- 输入命令
scan
,设备将开始扫描未配置的节点。 - 在串口日志中,可以看到发现的未配置设备信息。
-
准备待配置的节点设备:
- 将其他支持 BLE Mesh 的设备设置为未配置状态,等待被配置。
-
观察配置过程:
-
ESP32-C3 将自动将发现的设备添加到网络中,完成配置。
-
在串口日志中,您应该能够看到类似以下的输出:
I (10000) BLE_MESH_PROVISIONER: Provisioning complete, Node Unicast Addr: 0x0005
-
-
列出已配置节点:
- 在串口输入命令
list
,可以查看已配置的节点列表。
- 在串口输入命令
-
通过按键触发操作(可选):
- 按下按键,触发扫描或其他预设操作。
6. 注意事项
-
兼容性:
- 确保节点设备支持标准的 BLE Mesh 协议,以实现互操作性。
-
OOB 认证:
- 如果节点设备使用 OOB(Out-of-Band)认证,需要在配置器代码中处理相应的逻辑。
-
日志等级:
- 在
menuconfig
中调整日志等级为Info
或Debug
,以获取更详细的调试信息。
- 在
-
安全性:
- 正确管理网络密钥、应用密钥和设备密钥,确保网络通信的安全。
-
资源管理:
- 注意任务的堆栈大小和内存使用,避免内存泄漏和溢出。
7. 总结
通过上述步骤,您已经成功地设计并实现了一个基于 ESP32-C3 的 BLE Mesh Provisioner,不依赖手机 SDK,全程由 ESP32-C3 完成配置和控制。用户可以通过 串口 或 按键 与设备交互,实现对网络的管理。
扩展功能:
-
添加对节点的控制:
- 实现对节点的具体控制,如开关灯等,需要在配置器中添加相应的模型支持。
-
丰富用户界面:
- 使用 OLED 显示屏 或 网页服务器,提供更友好的用户界面。
-
数据持久化:
- 将已配置节点的信息保存到 NVS 中,断电重启后能够继续管理网络。
参考资料:
如果您在实现过程中遇到任何问题,或者需要进一步的帮助,请随时告诉我!
标签:err,ESP,UART,esp,mesh,BLE,Mesh,Provisioner,C3 From: https://blog.csdn.net/qq_41126242/article/details/144037222