/** * @file bluetooth_provisioning_example.cc * @brief 蓝牙配网使用示例 * * 本文件展示了如何在ESP32项目中集成和使用蓝牙配网功能 * 包括初始化、启动配网、处理回调事件等完整流程 */ #include "bluetooth_provisioning.h" #include "esp_log.h" #include "esp_wifi.h" #include "esp_netif.h" #include "esp_event.h" #include "nvs_flash.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" #define TAG "BluetoothProvisioningExample" // 全局蓝牙配网对象 static BluetoothProvisioning* g_bt_provisioning = nullptr; /** * @brief 蓝牙配网事件回调函数 * * 处理蓝牙配网过程中的各种事件,包括状态变化、WiFi连接等 * * @param event 事件类型 * @param data 事件数据指针 */ void bluetooth_provisioning_callback(BluetoothProvisioningEvent event, void* data) { switch (event) { case BluetoothProvisioningEvent::STATE_CHANGED: { BluetoothProvisioningState state = g_bt_provisioning->GetState(); const char* state_names[] = { "空闲", "初始化中", "广播中", "已连接", "配网中", "成功", "失败", "已停止" }; ESP_LOGI(TAG, "配网状态变更: %s", state_names[static_cast(state)]); break; } case BluetoothProvisioningEvent::CLIENT_CONNECTED: ESP_LOGI(TAG, "蓝牙客户端已连接,可以开始配网"); break; case BluetoothProvisioningEvent::CLIENT_DISCONNECTED: ESP_LOGI(TAG, "蓝牙客户端已断开连接"); break; case BluetoothProvisioningEvent::WIFI_CREDENTIALS: { WiFiCredentials* credentials = static_cast(data); ESP_LOGI(TAG, "收到WiFi凭据:"); ESP_LOGI(TAG, " SSID: %s", credentials->ssid.c_str()); ESP_LOGI(TAG, " 密码长度: %d", credentials->password.length()); if (credentials->bssid_set) { ESP_LOGI(TAG, " BSSID: %02x:%02x:%02x:%02x:%02x:%02x", credentials->bssid[0], credentials->bssid[1], credentials->bssid[2], credentials->bssid[3], credentials->bssid[4], credentials->bssid[5]); } break; } case BluetoothProvisioningEvent::WIFI_CONNECTED: { esp_ip4_addr_t* ip = static_cast(data); ESP_LOGI(TAG, "WiFi连接成功!IP地址: " IPSTR, IP2STR(ip)); // WiFi连接成功后,可以选择停止蓝牙配网以节省资源 // 延迟5秒后停止配网,给客户端足够时间接收状态 vTaskDelay(pdMS_TO_TICKS(5000)); if (g_bt_provisioning) { g_bt_provisioning->StopProvisioning(); ESP_LOGI(TAG, "配网成功,已停止蓝牙配网服务"); } break; } case BluetoothProvisioningEvent::WIFI_FAILED: { uint8_t* reason = static_cast(data); ESP_LOGE(TAG, "WiFi连接失败,错误代码: %d", *reason); // WiFi连接失败,可以选择重新开始配网或进行其他处理 ESP_LOGI(TAG, "WiFi连接失败,配网服务继续运行等待重新配置"); break; } default: ESP_LOGW(TAG, "未处理的配网事件: %d", static_cast(event)); break; } } /** * @brief 初始化WiFi * * 配置WiFi为STA模式,为蓝牙配网做准备 */ esp_err_t init_wifi() { ESP_LOGI(TAG, "初始化WiFi..."); // 创建默认WiFi STA网络接口 esp_netif_create_default_wifi_sta(); // 初始化WiFi配置 wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); esp_err_t ret = esp_wifi_init(&cfg); if (ret != ESP_OK) { ESP_LOGE(TAG, "WiFi初始化失败: %s", esp_err_to_name(ret)); return ret; } // 设置WiFi模式为STA ret = esp_wifi_set_mode(WIFI_MODE_STA); if (ret != ESP_OK) { ESP_LOGE(TAG, "WiFi模式设置失败: %s", esp_err_to_name(ret)); return ret; } // 启动WiFi ret = esp_wifi_start(); if (ret != ESP_OK) { ESP_LOGE(TAG, "WiFi启动失败: %s", esp_err_to_name(ret)); return ret; } ESP_LOGI(TAG, "WiFi初始化完成"); return ESP_OK; } /** * @brief 蓝牙配网任务 * * 独立任务处理蓝牙配网的整个生命周期 * * @param pvParameters 任务参数(未使用) */ void bluetooth_provisioning_task(void* pvParameters) { ESP_LOGI(TAG, "启动蓝牙配网任务"); // 1. 创建蓝牙配网对象 g_bt_provisioning = new BluetoothProvisioning(); if (g_bt_provisioning == nullptr) { ESP_LOGE(TAG, "蓝牙配网对象创建失败"); vTaskDelete(nullptr); return; } // 2. 设置事件回调 g_bt_provisioning->SetCallback(bluetooth_provisioning_callback); // 3. 初始化蓝牙配网 if (!g_bt_provisioning->Initialize()) { ESP_LOGE(TAG, "蓝牙配网初始化失败"); delete g_bt_provisioning; g_bt_provisioning = nullptr; vTaskDelete(nullptr); return; } // 4. 启动配网服务 const char* device_name = BLU_NAME; if (!g_bt_provisioning->StartProvisioning(device_name)) { ESP_LOGE(TAG, "蓝牙配网启动失败"); g_bt_provisioning->Deinitialize(); delete g_bt_provisioning; g_bt_provisioning = nullptr; vTaskDelete(nullptr); return; } ESP_LOGI(TAG, "蓝牙配网服务已启动,设备名称: %s", device_name); ESP_LOGI(TAG, "请使用ESP-IDF官方配网APP或自定义APP进行配网"); // 5. 任务主循环 - 监控配网状态 while (true) { BluetoothProvisioningState state = g_bt_provisioning->GetState(); // 检查是否需要处理特殊状态 switch (state) { case BluetoothProvisioningState::SUCCESS: ESP_LOGI(TAG, "配网成功完成"); // 可以在这里添加配网成功后的处理逻辑 break; case BluetoothProvisioningState::FAILED: ESP_LOGE(TAG, "配网失败,尝试重新启动"); // 配网失败,尝试重新启动 g_bt_provisioning->StopProvisioning(); vTaskDelay(pdMS_TO_TICKS(2000)); g_bt_provisioning->StartProvisioning(device_name); break; case BluetoothProvisioningState::STOPPED: ESP_LOGI(TAG, "配网服务已停止"); // 配网服务已停止,可以选择退出任务或重新启动 break; default: // 其他状态正常运行 break; } // 每5秒检查一次状态 vTaskDelay(pdMS_TO_TICKS(5000)); } // 清理资源(通常不会执行到这里) if (g_bt_provisioning) { g_bt_provisioning->Deinitialize(); delete g_bt_provisioning; g_bt_provisioning = nullptr; } vTaskDelete(nullptr); } /** * @brief 应用程序主函数 * * 演示如何集成蓝牙配网到现有的ESP32应用程序中 */ extern "C" void app_main() { ESP_LOGI(TAG, "=== 蓝牙配网示例程序启动 ==="); // 1. 初始化NVS(用于存储WiFi配置) esp_err_t ret = nvs_flash_init(); if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) { ESP_ERROR_CHECK(nvs_flash_erase()); ret = nvs_flash_init(); } ESP_ERROR_CHECK(ret); // 2. 初始化网络接口 ESP_ERROR_CHECK(esp_netif_init()); // 3. 创建默认事件循环 ESP_ERROR_CHECK(esp_event_loop_create_default()); // 4. 初始化WiFi ESP_ERROR_CHECK(init_wifi()); // 5. 创建蓝牙配网任务 BaseType_t task_ret = xTaskCreate( bluetooth_provisioning_task, // 任务函数 "bt_provisioning", // 任务名称 8192, // 栈大小(字节) nullptr, // 任务参数 5, // 任务优先级 nullptr // 任务句柄 ); if (task_ret != pdPASS) { ESP_LOGE(TAG, "蓝牙配网任务创建失败"); return; } ESP_LOGI(TAG, "应用程序初始化完成"); // 6. 主程序循环(可以在这里添加其他应用逻辑) while (true) { // 这里可以添加应用程序的主要逻辑 // 例如:传感器读取、数据处理、用户交互等 ESP_LOGI(TAG, "主程序运行中..."); vTaskDelay(pdMS_TO_TICKS(30000)); // 每30秒打印一次状态 } } /** * @brief 获取当前配网状态(供其他模块调用) * * @return BluetoothProvisioningState 当前配网状态 */ BluetoothProvisioningState get_provisioning_state() { if (g_bt_provisioning) { return g_bt_provisioning->GetState(); } return BluetoothProvisioningState::STOPPED; } /** * @brief 检查WiFi是否已连接(供其他模块调用) * * @return true WiFi已连接 * @return false WiFi未连接 */ bool is_wifi_connected() { BluetoothProvisioningState state = get_provisioning_state(); return (state == BluetoothProvisioningState::SUCCESS); } /** * @brief 手动启动配网(供其他模块调用) * * 可以在用户按下配网按钮或其他触发条件时调用 * * @return true 启动成功 * @return false 启动失败 */ bool start_provisioning_manually() { if (g_bt_provisioning == nullptr) { ESP_LOGE(TAG, "蓝牙配网对象未初始化"); return false; } BluetoothProvisioningState state = g_bt_provisioning->GetState(); if (state == BluetoothProvisioningState::ADVERTISING || state == BluetoothProvisioningState::CONNECTED || state == BluetoothProvisioningState::PROVISIONING) { ESP_LOGW(TAG, "配网已在运行中"); return true; } ESP_LOGI(TAG, "手动启动蓝牙配网"); return g_bt_provisioning->StartProvisioning("小智AI-手动配网"); } /** * @brief 手动停止配网(供其他模块调用) * * @return true 停止成功 * @return false 停止失败 */ bool stop_provisioning_manually() { if (g_bt_provisioning == nullptr) { ESP_LOGE(TAG, "蓝牙配网对象未初始化"); return false; } ESP_LOGI(TAG, "手动停止蓝牙配网"); return g_bt_provisioning->StopProvisioning(); }