/** * @file bluetooth_provisioning.cc * @brief 蓝牙配网模块实现(基于自定义 GATT Server) * * 使用自定义 BLE GATT Server + 原始广播数据(raw advertising)实现配网。 * 采用 dzbj 项目验证的 esp_ble_gap_config_adv_data_raw() 方式, * 确保手机系统蓝牙可搜索到设备名称。 * * 保留完整的 WiFi 配网业务逻辑: * - WiFi 凭据接收、验证和连接管理 * - 配网状态机和事件回调 * - WiFi 连接状态监控和报告 * - MAC 地址发送 * - 配网成功后自动保存和重启 */ #include "bluetooth_provisioning.h" #include "esp_log.h" #include "esp_timer.h" #include "esp_bt.h" #include "esp_bt_main.h" #include "esp_bt_device.h" #include "esp_gap_ble_api.h" #include "esp_gatts_api.h" #include "esp_gatt_common_api.h" #include "esp_wifi.h" #include "esp_netif.h" #include "freertos/event_groups.h" #include "freertos/timers.h" #include "freertos/task.h" #include "esp_system.h" #include "application.h" #include "assets/lang_config.h" #include #include "nvs_flash.h" #include "nvs.h" #include /// 日志标签 #define TAG "BluetoothProvisioning" /// WiFi连接成功事件位 #define WIFI_CONNECTED_BIT BIT0 /// WiFi连接失败事件位 #define WIFI_FAIL_BIT BIT1 /// 静态单例实例指针 BluetoothProvisioning* BluetoothProvisioning::instance_ = nullptr; /// WiFi事件组句柄 static EventGroupHandle_t s_wifi_event_group = nullptr; /// WiFi连接重试计数器 static int s_retry_num = 0; /// 最大重试次数 static const int MAX_RETRY = 2; /// WiFi连接超时时间(毫秒) static const int WIFI_CONNECT_TIMEOUT_MS = 30000; /// WiFi连接超时定时器句柄 static TimerHandle_t wifi_connect_timer = nullptr; // ============================================================ // GATT 静态数据定义 // ============================================================ // UUID 定义 static esp_bt_uuid_t prov_service_uuid = { .len = ESP_UUID_LEN_16, .uuid = {.uuid16 = PROV_SERVICE_UUID}, }; static esp_bt_uuid_t prov_write_char_uuid = { .len = ESP_UUID_LEN_16, .uuid = {.uuid16 = PROV_CHAR_WRITE_UUID}, }; static esp_bt_uuid_t prov_notify_char_uuid = { .len = ESP_UUID_LEN_16, .uuid = {.uuid16 = PROV_CHAR_NOTIFY_UUID}, }; static esp_bt_uuid_t cccd_uuid = { .len = ESP_UUID_LEN_16, .uuid = {.uuid16 = ESP_GATT_UUID_CHAR_CLIENT_CONFIG}, }; // 特征值缓冲区 static uint8_t prov_write_val[PROV_LOCAL_MTU] = {0}; static uint8_t prov_notify_val[PROV_LOCAL_MTU] = {0}; static uint8_t cccd_val[2] = {0x00, 0x00}; static esp_attr_value_t prov_write_attr = { .attr_max_len = PROV_LOCAL_MTU, .attr_len = 1, .attr_value = prov_write_val, }; static esp_attr_value_t prov_notify_attr = { .attr_max_len = PROV_LOCAL_MTU, .attr_len = 1, .attr_value = prov_notify_val, }; static esp_attr_value_t cccd_attr = { .attr_max_len = 2, .attr_len = 2, .attr_value = cccd_val, }; // 广播参数 (参考 dzbj: 快速广播间隔,确保手机快速发现) static esp_ble_adv_params_t prov_adv_params = { .adv_int_min = 0x20, // 20ms (dzbj 相同) .adv_int_max = 0x40, // 40ms .adv_type = ADV_TYPE_IND, .own_addr_type = BLE_ADDR_TYPE_PUBLIC, .peer_addr = {0}, .peer_addr_type = BLE_ADDR_TYPE_PUBLIC, .channel_map = ADV_CHNL_ALL, .adv_filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY, }; // 原始广播数据 (运行时动态构建) static uint8_t prov_adv_raw_data[31]; static uint8_t prov_adv_raw_len = 0; // 扫描响应数据 (携带 TX Power + BLE MAC 地址) static uint8_t prov_scan_rsp_data[31]; static uint8_t prov_scan_rsp_len = 0; // ============================================================ // 构造 / 析构 // ============================================================ BluetoothProvisioning::BluetoothProvisioning() : state_(BluetoothProvisioningState::IDLE) , callback_(nullptr) , client_connected_(false) , initialized_(false) , delayed_disconnect_(false) , wifi_connecting_(false) , mac_address_sent_(false) { wifi_credentials_.ssid.clear(); wifi_credentials_.password.clear(); memset(wifi_credentials_.bssid, 0, sizeof(wifi_credentials_.bssid)); wifi_credentials_.bssid_set = false; instance_ = this; ESP_LOGI(TAG, "蓝牙配网对象创建完成"); } BluetoothProvisioning::~BluetoothProvisioning() { if (initialized_) { Deinitialize(); } instance_ = nullptr; ESP_LOGI(TAG, "蓝牙配网对象销毁完成"); } // ============================================================ // Initialize — 初始化 BLE 栈 + GATT 服务 + WiFi 事件 // ============================================================ bool BluetoothProvisioning::Initialize() { if (initialized_) { ESP_LOGW(TAG, "蓝牙配网已经初始化"); return true; } SetState(BluetoothProvisioningState::INITIALIZING); esp_err_t ret; // 步骤1: 初始化WiFi模块 ESP_LOGI(TAG, "初始化WiFi..."); esp_netif_create_default_wifi_sta(); wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); ret = esp_wifi_init(&cfg); if (ret != ESP_OK) { ESP_LOGE(TAG, "WiFi初始化失败: %s", esp_err_to_name(ret)); SetState(BluetoothProvisioningState::FAILED); return false; } ret = esp_wifi_set_mode(WIFI_MODE_STA); if (ret != ESP_OK) { ESP_LOGE(TAG, "WiFi模式设置失败: %s", esp_err_to_name(ret)); SetState(BluetoothProvisioningState::FAILED); return false; } ret = esp_wifi_start(); if (ret != ESP_OK) { ESP_LOGE(TAG, "WiFi启动失败: %s", esp_err_to_name(ret)); SetState(BluetoothProvisioningState::FAILED); return false; } ESP_LOGI(TAG, "WiFi初始化完成"); // 步骤2: 初始化蓝牙控制器 ESP_LOGI(TAG, "初始化蓝牙控制器..."); esp_bt_controller_status_t ctl_status = esp_bt_controller_get_status(); #if CONFIG_IDF_TARGET_ESP32 ESP_ERROR_CHECK(esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT)); #else esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT); #endif if (ctl_status == ESP_BT_CONTROLLER_STATUS_ENABLED) { esp_bt_controller_disable(); ctl_status = esp_bt_controller_get_status(); } if (ctl_status == ESP_BT_CONTROLLER_STATUS_INITED) { esp_bt_controller_deinit(); } esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT(); ret = esp_bt_controller_init(&bt_cfg); if (ret != ESP_OK && ret != ESP_ERR_INVALID_STATE) { ESP_LOGE(TAG, "蓝牙控制器初始化失败: %s", esp_err_to_name(ret)); SetState(BluetoothProvisioningState::FAILED); return false; } ret = esp_bt_controller_enable(ESP_BT_MODE_BLE); if (ret != ESP_OK && ret != ESP_ERR_INVALID_STATE) { ESP_LOGE(TAG, "蓝牙控制器启用失败: %s", esp_err_to_name(ret)); SetState(BluetoothProvisioningState::FAILED); return false; } // 步骤3: 初始化 Bluedroid 协议栈 ESP_LOGI(TAG, "初始化Bluedroid协议栈..."); auto bd_status = esp_bluedroid_get_status(); if (bd_status == ESP_BLUEDROID_STATUS_ENABLED) { esp_bluedroid_disable(); bd_status = esp_bluedroid_get_status(); } if (bd_status == ESP_BLUEDROID_STATUS_INITIALIZED) { esp_bluedroid_deinit(); } ret = esp_bluedroid_init(); if (ret != ESP_OK && ret != ESP_ERR_INVALID_STATE) { ESP_LOGE(TAG, "Bluedroid初始化失败: %s", esp_err_to_name(ret)); SetState(BluetoothProvisioningState::FAILED); return false; } ret = esp_bluedroid_enable(); if (ret != ESP_OK && ret != ESP_ERR_INVALID_STATE) { ESP_LOGE(TAG, "Bluedroid启用失败: %s", esp_err_to_name(ret)); SetState(BluetoothProvisioningState::FAILED); return false; } // 步骤4: 注册 GAP 和 GATTS 回调 ESP_LOGI(TAG, "注册 BLE GAP/GATTS 回调..."); ret = esp_ble_gap_register_callback(GapEventHandler); if (ret != ESP_OK) { ESP_LOGE(TAG, "GAP回调注册失败: %s", esp_err_to_name(ret)); SetState(BluetoothProvisioningState::FAILED); return false; } ret = esp_ble_gatts_register_callback(GattsEventHandler); if (ret != ESP_OK) { ESP_LOGE(TAG, "GATTS回调注册失败: %s", esp_err_to_name(ret)); SetState(BluetoothProvisioningState::FAILED); return false; } ret = esp_ble_gatts_app_register(PROV_APP_ID); if (ret != ESP_OK) { ESP_LOGE(TAG, "GATTS App注册失败: %s", esp_err_to_name(ret)); SetState(BluetoothProvisioningState::FAILED); return false; } ret = esp_ble_gatt_set_local_mtu(PROV_LOCAL_MTU); if (ret != ESP_OK) { ESP_LOGW(TAG, "设置MTU失败: %s (可能已设置)", esp_err_to_name(ret)); } // 步骤5: 创建WiFi事件同步机制 if (s_wifi_event_group == nullptr) { s_wifi_event_group = xEventGroupCreate(); if (s_wifi_event_group == nullptr) { ESP_LOGE(TAG, "WiFi事件组创建失败"); SetState(BluetoothProvisioningState::FAILED); return false; } } // 步骤6: 注册WiFi和IP事件处理器 ESP_LOGI(TAG, "注册WiFi事件处理器..."); ret = esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &WiFiEventHandler, this); if (ret != ESP_OK) { ESP_LOGE(TAG, "WiFi事件处理器注册失败: %s", esp_err_to_name(ret)); SetState(BluetoothProvisioningState::FAILED); return false; } ret = esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &IPEventHandler, this); if (ret != ESP_OK) { ESP_LOGE(TAG, "IP事件处理器注册失败: %s", esp_err_to_name(ret)); SetState(BluetoothProvisioningState::FAILED); return false; } initialized_ = true; SetState(BluetoothProvisioningState::IDLE); ESP_LOGI(TAG, "蓝牙配网初始化完成 (GATT Server 模式)"); ESP_LOGI(TAG, "蓝牙MAC地址: " ESP_BD_ADDR_STR, ESP_BD_ADDR_HEX(esp_bt_dev_get_address())); return true; } // ============================================================ // Deinitialize // ============================================================ bool BluetoothProvisioning::Deinitialize() { if (!initialized_) { ESP_LOGW(TAG, "蓝牙配网未初始化"); return true; } ESP_LOGI(TAG, "开始反初始化蓝牙配网..."); if (state_ != BluetoothProvisioningState::IDLE && state_ != BluetoothProvisioningState::STOPPED) { StopProvisioning(); } esp_event_handler_unregister(WIFI_EVENT, ESP_EVENT_ANY_ID, &WiFiEventHandler); esp_event_handler_unregister(IP_EVENT, IP_EVENT_STA_GOT_IP, &IPEventHandler); if (s_wifi_event_group != nullptr) { vEventGroupDelete(s_wifi_event_group); s_wifi_event_group = nullptr; } esp_bluedroid_disable(); esp_bluedroid_deinit(); esp_bt_controller_disable(); esp_bt_controller_deinit(); initialized_ = false; SetState(BluetoothProvisioningState::STOPPED); ESP_LOGI(TAG, "蓝牙配网反初始化完成"); return true; } // ============================================================ // StartProvisioning — 构建原始广播数据并启动广播 // ============================================================ bool BluetoothProvisioning::StartProvisioning() { ESP_LOGI(TAG, "🔵 开始启动蓝牙配网服务 (GATT Server)..."); ESP_LOGI(TAG, "🔍 检查初始化状态: initialized_ = %s", initialized_ ? "true" : "false"); if (!initialized_) { ESP_LOGE(TAG, "❌ 蓝牙配网未初始化,无法启动"); return false; } if (state_ == BluetoothProvisioningState::ADVERTISING || state_ == BluetoothProvisioningState::CONNECTED || state_ == BluetoothProvisioningState::PROVISIONING) { ESP_LOGW(TAG, "⚠️ 蓝牙配网已在运行中"); return true; } // 重置状态 client_connected_ = false; s_retry_num = 0; ResetMacSendingState(); ESP_LOGI(TAG, "🔄 MAC地址发送状态已重置"); // 清空之前的WiFi凭据 ESP_LOGI(TAG, "🧹 清除之前的WiFi凭据..."); if (!wifi_credentials_.ssid.empty()) { ESP_LOGI(TAG, "🗑️ 删除已保存的SSID: %s", wifi_credentials_.ssid.c_str()); } if (!wifi_credentials_.password.empty()) { ESP_LOGI(TAG, "🗑️ 删除已保存的WiFi密码 (长度: %d)", (int)wifi_credentials_.password.length()); } wifi_credentials_.ssid.clear(); wifi_credentials_.password.clear(); wifi_credentials_.bssid_set = false; ESP_LOGI(TAG, "✅ WiFi凭据清除完成,准备接收新的配网信息"); // 构建设备名称: "Airhub_" + BLE MAC 明文 char ble_device_name[32]; const uint8_t* ble_addr = esp_bt_dev_get_address(); if (ble_addr) { snprintf(ble_device_name, sizeof(ble_device_name), "Airhub_%02x:%02x:%02x:%02x:%02x:%02x", ble_addr[0], ble_addr[1], ble_addr[2], ble_addr[3], ble_addr[4], ble_addr[5]); } else { strcpy(ble_device_name, "Airhub_Ble"); ESP_LOGW(TAG, "获取BLE MAC失败,使用默认名称: %s", ble_device_name); } // 设置设备名称 esp_err_t ret = esp_ble_gap_set_device_name(ble_device_name); if (ret != ESP_OK) { ESP_LOGE(TAG, "❌ 设置蓝牙设备名称失败: %s", esp_err_to_name(ret)); return false; } ESP_LOGI(TAG, "📡 蓝牙设备名称: %s", ble_device_name); // 构建广播数据 (Flags + 设备名) uint8_t name_len = strlen(ble_device_name); int offset = 0; // Flags: LE General Discoverable + BR/EDR Not Supported prov_adv_raw_data[offset++] = 0x02; prov_adv_raw_data[offset++] = ESP_BLE_AD_TYPE_FLAG; prov_adv_raw_data[offset++] = 0x06; // Complete Local Name prov_adv_raw_data[offset++] = name_len + 1; prov_adv_raw_data[offset++] = ESP_BLE_AD_TYPE_NAME_CMPL; memcpy(&prov_adv_raw_data[offset], ble_device_name, name_len); offset += name_len; prov_adv_raw_len = offset; ESP_LOGI(TAG, "📡 广播数据构建完成,长度: %d 字节", prov_adv_raw_len); // 构建扫描响应数据 (TX Power + Service UUID) int rsp_offset = 0; // TX Power Level prov_scan_rsp_data[rsp_offset++] = 0x02; prov_scan_rsp_data[rsp_offset++] = ESP_BLE_AD_TYPE_TX_PWR; prov_scan_rsp_data[rsp_offset++] = 0x09; // 16-bit Service UUID Complete prov_scan_rsp_data[rsp_offset++] = 0x03; prov_scan_rsp_data[rsp_offset++] = ESP_BLE_AD_TYPE_16SRV_CMPL; prov_scan_rsp_data[rsp_offset++] = PROV_SERVICE_UUID & 0xFF; prov_scan_rsp_data[rsp_offset++] = (PROV_SERVICE_UUID >> 8) & 0xFF; prov_scan_rsp_len = rsp_offset; ESP_LOGI(TAG, "📡 扫描响应数据构建完成,长度: %d 字节", prov_scan_rsp_len); // 配置广播数据 (GAP回调中会依次设置扫描响应数据并启动广播) ret = esp_ble_gap_config_adv_data_raw(prov_adv_raw_data, prov_adv_raw_len); if (ret != ESP_OK) { ESP_LOGE(TAG, "❌ 配置广播数据失败: %s", esp_err_to_name(ret)); return false; } SetState(BluetoothProvisioningState::ADVERTISING); ESP_LOGI(TAG, "蓝牙配网广播已启动,等待客户端连接..."); return true; } // ============================================================ // StopProvisioning // ============================================================ bool BluetoothProvisioning::StopProvisioning() { if (state_ == BluetoothProvisioningState::IDLE || state_ == BluetoothProvisioningState::STOPPED) { ESP_LOGW(TAG, "蓝牙配网未在运行"); return true; } ESP_LOGI(TAG, "停止蓝牙配网..."); esp_ble_gap_stop_advertising(); if (client_connected_ && gatts_if_ != ESP_GATT_IF_NONE) { esp_ble_gatts_close(gatts_if_, conn_id_); } client_connected_ = false; notify_enabled_ = false; SetState(BluetoothProvisioningState::IDLE); ESP_LOGI(TAG, "蓝牙配网已停止"); return true; } // ============================================================ // StartAdvertising — 启动 BLE 广播 // ============================================================ void BluetoothProvisioning::StartAdvertising() { // 重新配置原始广播数据,GAP回调中启动广播 esp_ble_gap_config_adv_data_raw(prov_adv_raw_data, prov_adv_raw_len); } // ============================================================ // GAP 事件回调 (static) // ============================================================ void BluetoothProvisioning::GapEventHandler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t* param) { switch (event) { case ESP_GAP_BLE_ADV_DATA_RAW_SET_COMPLETE_EVT: // 广播数据设置完成,接着配置扫描响应数据 ESP_LOGI(TAG, "📡 广播数据设置完成,配置扫描响应数据"); if (prov_scan_rsp_len > 0) { esp_ble_gap_config_scan_rsp_data_raw(prov_scan_rsp_data, prov_scan_rsp_len); } else { esp_ble_gap_start_advertising(&prov_adv_params); } break; case ESP_GAP_BLE_SCAN_RSP_DATA_RAW_SET_COMPLETE_EVT: // 扫描响应数据设置完成,启动广播 ESP_LOGI(TAG, "📡 扫描响应数据设置完成,启动广播"); esp_ble_gap_start_advertising(&prov_adv_params); break; case ESP_GAP_BLE_ADV_START_COMPLETE_EVT: if (param->adv_start_cmpl.status != ESP_BT_STATUS_SUCCESS) { ESP_LOGE(TAG, "❌ 广播启动失败: %d", param->adv_start_cmpl.status); } else { ESP_LOGI(TAG, "✅ 广播启动成功"); } break; case ESP_GAP_BLE_ADV_STOP_COMPLETE_EVT: ESP_LOGI(TAG, "广播已停止"); break; case ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT: ESP_LOGI(TAG, "连接参数更新: status=%d, conn_int=%d, latency=%d, timeout=%d", param->update_conn_params.status, param->update_conn_params.conn_int, param->update_conn_params.latency, param->update_conn_params.timeout); break; default: break; } } // ============================================================ // GATTS 事件回调 (static 分发) // ============================================================ void BluetoothProvisioning::GattsEventHandler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t* param) { if (event == ESP_GATTS_REG_EVT) { if (param->reg.app_id != PROV_APP_ID) { return; } } else { if (!instance_ || gatts_if != instance_->gatts_if_) { return; } } if (instance_) { instance_->HandleGattsEvent(event, gatts_if, param); } } // ============================================================ // HandleGattsEvent — 实例内处理 // ============================================================ void BluetoothProvisioning::HandleGattsEvent(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t* param) { switch (event) { // ---- App 注册完成,保存 gatts_if,创建 Service ---- case ESP_GATTS_REG_EVT: if (param->reg.status == ESP_GATT_OK) { gatts_if_ = gatts_if; ESP_LOGI(TAG, "✅ GATTS App 注册成功, gatts_if=%d", gatts_if); CreateService(gatts_if); } else { ESP_LOGE(TAG, "❌ GATTS App 注册失败, status=%d", param->reg.status); } break; // ---- Service 创建完成,添加 WRITE Characteristic ---- case ESP_GATTS_CREATE_EVT: if (param->create.status == ESP_GATT_OK) { service_handle_ = param->create.service_handle; ESP_LOGI(TAG, "Service 创建成功, handle=%d", service_handle_); // 添加 WRITE Characteristic (手机 → 设备) esp_gatt_char_prop_t write_prop = ESP_GATT_CHAR_PROP_BIT_WRITE; esp_ble_gatts_add_char(service_handle_, &prov_write_char_uuid, ESP_GATT_PERM_WRITE, write_prop, &prov_write_attr, nullptr); } else { ESP_LOGE(TAG, "Service 创建失败: %d", param->create.status); } break; // ---- Characteristic 添加完成 ---- case ESP_GATTS_ADD_CHAR_EVT: if (param->add_char.status != ESP_GATT_OK) { ESP_LOGE(TAG, "添加特征失败: uuid=0x%04x status=%d", param->add_char.char_uuid.uuid.uuid16, param->add_char.status); break; } if (param->add_char.char_uuid.uuid.uuid16 == PROV_CHAR_WRITE_UUID) { write_char_handle_ = param->add_char.attr_handle; ESP_LOGI(TAG, "WRITE 特征添加成功, handle=%d", write_char_handle_); // 添加 NOTIFY Characteristic (设备 → 手机) esp_gatt_char_prop_t notify_prop = ESP_GATT_CHAR_PROP_BIT_NOTIFY | ESP_GATT_CHAR_PROP_BIT_READ; esp_ble_gatts_add_char(service_handle_, &prov_notify_char_uuid, ESP_GATT_PERM_READ, notify_prop, &prov_notify_attr, nullptr); } else if (param->add_char.char_uuid.uuid.uuid16 == PROV_CHAR_NOTIFY_UUID) { notify_char_handle_ = param->add_char.attr_handle; ESP_LOGI(TAG, "NOTIFY 特征添加成功, handle=%d", notify_char_handle_); // 为 NOTIFY 特征添加 CCCD 描述符 esp_ble_gatts_add_char_descr(service_handle_, &cccd_uuid, ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE, &cccd_attr, nullptr); } break; // ---- CCCD 描述符添加完成,启动服务 ---- case ESP_GATTS_ADD_CHAR_DESCR_EVT: if (param->add_char_descr.status == ESP_GATT_OK) { notify_cccd_handle_ = param->add_char_descr.attr_handle; ESP_LOGI(TAG, "CCCD 添加成功, handle=%d", notify_cccd_handle_); // 所有特征添加完毕,启动服务 esp_ble_gatts_start_service(service_handle_); } else { ESP_LOGE(TAG, "CCCD 添加失败: %d", param->add_char_descr.status); } break; // ---- Service 启动完成 ---- case ESP_GATTS_START_EVT: if (param->start.status == ESP_GATT_OK) { ESP_LOGI(TAG, "✅ GATT Service 启动成功"); } break; // ---- 客户端连接 ---- case ESP_GATTS_CONNECT_EVT: { conn_id_ = param->connect.conn_id; client_connected_ = true; notify_enabled_ = false; mtu_ = 23; ESP_LOGI(TAG, "📱 客户端已连接, conn_id=%d, addr=%02x:%02x:%02x:%02x:%02x:%02x", conn_id_, param->connect.remote_bda[0], param->connect.remote_bda[1], param->connect.remote_bda[2], param->connect.remote_bda[3], param->connect.remote_bda[4], param->connect.remote_bda[5]); ESP_LOGI(TAG, "🔍 [DEBUG] 设置client_connected_为true"); // 重置MAC地址发送状态 ResetMacSendingState(); ESP_LOGI(TAG, "🔄 MAC地址发送状态已重置"); // 更新连接参数 esp_ble_conn_update_params_t conn_params = {}; memcpy(conn_params.bda, param->connect.remote_bda, sizeof(esp_bd_addr_t)); conn_params.latency = 0; conn_params.max_int = 0x20; // 40ms conn_params.min_int = 0x10; // 20ms conn_params.timeout = 400; // 4s esp_ble_gap_update_conn_params(&conn_params); // 停止广播 esp_ble_gap_stop_advertising(); SetState(BluetoothProvisioningState::CONNECTED); TriggerCallback(BluetoothProvisioningEvent::CLIENT_CONNECTED, nullptr); ESP_LOGI(TAG, "🔍 [DEBUG] BLE连接处理完成,client_connected_=%s", client_connected_ ? "true" : "false"); break; } // ---- 客户端断开 ---- case ESP_GATTS_DISCONNECT_EVT: { ESP_LOGI(TAG, "📱 客户端已断开连接, reason=0x%x, 当前状态: %s", param->disconnect.reason, GetStateString().c_str()); ESP_LOGI(TAG, "🔍 [DEBUG] 设置client_connected_为false"); client_connected_ = false; notify_enabled_ = false; mtu_ = 23; // 如果正在配网过程中,延迟处理断开事件 if (state_ == BluetoothProvisioningState::PROVISIONING) { ESP_LOGW(TAG, "⚠️ 配网过程中BLE断开,延迟5秒后处理以等待WiFi连接完成"); delayed_disconnect_ = true; xTaskCreate([](void* param) { vTaskDelay(pdMS_TO_TICKS(2000)); BluetoothProvisioning* self = static_cast(param); if (self->delayed_disconnect_) { if (self->state_ == BluetoothProvisioningState::PROVISIONING && self->wifi_connecting_) { ESP_LOGW(TAG, "⏰ BLE延迟断开,但WiFi仍在连接中,继续等待"); } else if (self->state_ == BluetoothProvisioningState::PROVISIONING) { ESP_LOGW(TAG, "⏰ 延迟处理BLE断开,WiFi连接可能已超时"); self->SetState(BluetoothProvisioningState::ADVERTISING); self->TriggerCallback(BluetoothProvisioningEvent::CLIENT_DISCONNECTED, nullptr); self->StartAdvertising(); } self->delayed_disconnect_ = false; } vTaskDelete(nullptr); }, "delayed_disconnect", 2048, instance_, 1, nullptr); } else { SetState(BluetoothProvisioningState::ADVERTISING); TriggerCallback(BluetoothProvisioningEvent::CLIENT_DISCONNECTED, nullptr); // 重新启动广播 StartAdvertising(); } break; } // ---- MTU 协商完成 ---- case ESP_GATTS_MTU_EVT: mtu_ = param->mtu.mtu; ESP_LOGI(TAG, "MTU 更新: %d", mtu_); break; // ---- WRITE 事件 ---- case ESP_GATTS_WRITE_EVT: if (param->write.handle == write_char_handle_) { // 配网协议数据 ProcessWriteData(param->write.value, param->write.len); } else if (param->write.handle == notify_cccd_handle_ && param->write.len == 2) { // CCCD 写入: 开启/关闭 NOTIFY uint16_t cccd_value = param->write.value[0] | (param->write.value[1] << 8); notify_enabled_ = (cccd_value == 0x0001); ESP_LOGI(TAG, "NOTIFY %s", notify_enabled_ ? "已启用" : "已禁用"); } if (param->write.need_rsp) { esp_ble_gatts_send_response(gatts_if_, param->write.conn_id, param->write.trans_id, ESP_GATT_OK, nullptr); } break; // ---- READ 事件 ---- case ESP_GATTS_READ_EVT: ESP_LOGD(TAG, "Read event, handle=%d", param->read.handle); break; default: break; } } // ============================================================ // CreateService // ============================================================ void BluetoothProvisioning::CreateService(esp_gatt_if_t gatts_if) { esp_gatt_srvc_id_t service_id = {}; service_id.is_primary = true; service_id.id.inst_id = 0; service_id.id.uuid.len = ESP_UUID_LEN_16; service_id.id.uuid.uuid.uuid16 = PROV_SERVICE_UUID; esp_ble_gatts_create_service(gatts_if, &service_id, PROV_HANDLE_NUM); } // ============================================================ // ProcessWriteData — 处理手机发送的配网协议数据 // ============================================================ void BluetoothProvisioning::ProcessWriteData(const uint8_t* data, uint16_t len) { if (!data || len < 1) return; uint8_t cmd = data[0]; const uint8_t* payload = data + 1; uint16_t payload_len = len - 1; switch (cmd) { // 接收到WiFi SSID case PROV_CMD_SET_SSID: ESP_LOGI(TAG, "📶 收到WiFi SSID: %.*s", payload_len, payload); wifi_credentials_.ssid.assign(reinterpret_cast(payload), payload_len); { wifi_config_t wifi_config = {}; strncpy(reinterpret_cast(wifi_config.sta.ssid), wifi_credentials_.ssid.c_str(), sizeof(wifi_config.sta.ssid) - 1); esp_wifi_set_config(WIFI_IF_STA, &wifi_config); } break; // 接收到WiFi密码 case PROV_CMD_SET_PASSWORD: ESP_LOGI(TAG, "🔐 收到WiFi密码 (长度: %d)", payload_len); wifi_credentials_.password.assign(reinterpret_cast(payload), payload_len); { wifi_config_t wifi_config = {}; strncpy(reinterpret_cast(wifi_config.sta.ssid), wifi_credentials_.ssid.c_str(), sizeof(wifi_config.sta.ssid) - 1); strncpy(reinterpret_cast(wifi_config.sta.password), wifi_credentials_.password.c_str(), sizeof(wifi_config.sta.password) - 1); ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config)); } // 重置重试计数器 s_retry_num = 0; wifi_connecting_ = true; // 启动WiFi连接超时定时器 if (wifi_connect_timer) { xTimerStop(wifi_connect_timer, 0); xTimerDelete(wifi_connect_timer, 0); } wifi_connect_timer = xTimerCreate("wifi_timeout", pdMS_TO_TICKS(WIFI_CONNECT_TIMEOUT_MS), pdFALSE, nullptr, [](TimerHandle_t timer) { ESP_LOGW(TAG, "⏰ WiFi连接超时,强制失败处理"); if (instance_ && instance_->wifi_connecting_) { instance_->wifi_connecting_ = false; instance_->delayed_disconnect_ = false; instance_->SetState(BluetoothProvisioningState::FAILED); instance_->TriggerCallback(BluetoothProvisioningEvent::WIFI_FAILED, nullptr); instance_->ReportWiFiStatus(false, WIFI_REASON_UNSPECIFIED); xEventGroupSetBits(s_wifi_event_group, WIFI_FAIL_BIT); } }); xTimerStart(wifi_connect_timer, 0); esp_wifi_connect(); ESP_LOGI(TAG, "📡 已发起WiFi连接请求,启动超时监控"); TriggerCallback(BluetoothProvisioningEvent::WIFI_CREDENTIALS, &wifi_credentials_); break; // 接收到BSSID case PROV_CMD_SET_BSSID: if (payload_len >= 6) { ESP_LOGI(TAG, "收到BSSID"); memcpy(wifi_credentials_.bssid, payload, 6); wifi_credentials_.bssid_set = true; wifi_config_t wifi_config = {}; strncpy(reinterpret_cast(wifi_config.sta.ssid), wifi_credentials_.ssid.c_str(), sizeof(wifi_config.sta.ssid) - 1); strncpy(reinterpret_cast(wifi_config.sta.password), wifi_credentials_.password.c_str(), sizeof(wifi_config.sta.password) - 1); memcpy(wifi_config.sta.bssid, wifi_credentials_.bssid, 6); wifi_config.sta.bssid_set = true; esp_wifi_set_config(WIFI_IF_STA, &wifi_config); } break; // 请求连接到AP case PROV_CMD_CONNECT_AP: ESP_LOGI(TAG, "📡 请求连接到AP,SSID: %s", wifi_credentials_.ssid.c_str()); ESP_LOGI(TAG, "🔍 [DEBUG] 当前状态: %s, client_connected_: %s", GetStateString().c_str(), client_connected_ ? "true" : "false"); SetState(BluetoothProvisioningState::PROVISIONING); delayed_disconnect_ = false; s_retry_num = 0; ESP_LOGI(TAG, "🔄 重置WiFi重试计数,开始连接流程"); esp_wifi_disconnect(); vTaskDelay(pdMS_TO_TICKS(100)); esp_wifi_connect(); ESP_LOGI(TAG, "🚀 已发起WiFi连接请求"); break; // 请求断开AP case PROV_CMD_DISCONNECT_AP: ESP_LOGI(TAG, "请求断开AP连接"); esp_wifi_disconnect(); break; // 请求WiFi列表 case PROV_CMD_GET_WIFI_LIST: ESP_LOGI(TAG, "📱 手机请求获取WiFi列表,开始扫描"); { wifi_scan_config_t scan_config = {}; scan_config.ssid = nullptr; scan_config.bssid = nullptr; scan_config.channel = 0; scan_config.show_hidden = true; scan_config.scan_type = WIFI_SCAN_TYPE_ACTIVE; scan_config.scan_time.active.min = 100; scan_config.scan_time.active.max = 300; esp_err_t ret = esp_wifi_scan_start(&scan_config, false); if (ret == ESP_OK) { ESP_LOGI(TAG, "🔍 WiFi扫描已启动"); } else { ESP_LOGE(TAG, "❌ WiFi扫描启动失败: %s", esp_err_to_name(ret)); } } break; // 请求断开BLE case PROV_CMD_DISCONNECT_BLE: ESP_LOGI(TAG, "收到断开BLE连接请求"); if (gatts_if_ != ESP_GATT_IF_NONE) { esp_ble_gatts_close(gatts_if_, conn_id_); } break; // 设置WiFi模式 case PROV_CMD_SET_WIFI_MODE: if (payload_len >= 1) { ESP_LOGI(TAG, "设置WiFi模式: %d", payload[0]); esp_wifi_set_mode((wifi_mode_t)payload[0]); } break; // 获取WiFi状态 case PROV_CMD_GET_WIFI_STATUS: ESP_LOGI(TAG, "客户端请求WiFi状态"); break; // 自定义数据 case PROV_CMD_CUSTOM_DATA: ESP_LOGI(TAG, "收到自定义数据, 长度: %d", payload_len); break; default: ESP_LOGW(TAG, "未知命令: 0x%02x", cmd); break; } } // ============================================================ // SendNotify — 通过 GATT NOTIFY 发送数据 // ============================================================ bool BluetoothProvisioning::SendNotify(const uint8_t* data, uint16_t len) { if (gatts_if_ == ESP_GATT_IF_NONE || !client_connected_) { return false; } uint16_t max_payload = mtu_ - 3; if (len > max_payload) { ESP_LOGW(TAG, "数据长度 %d 超过 MTU payload %d,截断", len, max_payload); len = max_payload; } esp_err_t ret = esp_ble_gatts_send_indicate( gatts_if_, conn_id_, notify_char_handle_, len, (uint8_t*)data, false); if (ret != ESP_OK) { ESP_LOGE(TAG, "发送 NOTIFY 失败: %s", esp_err_to_name(ret)); return false; } return true; } // ============================================================ // ReportWiFiStatus — 通过 GATT NOTIFY 报告WiFi连接状态 // ============================================================ void BluetoothProvisioning::ReportWiFiStatus(bool success, uint8_t reason) { ESP_LOGI(TAG, "🔍 [DEBUG] ReportWiFiStatus调用: success=%s, client_connected_=%s", success ? "true" : "false", client_connected_ ? "true" : "false"); if (!client_connected_) { ESP_LOGW(TAG, "客户端未连接,无法发送WiFi状态"); return; } uint8_t buf[3]; buf[0] = PROV_RESP_WIFI_STATUS; buf[1] = success ? 1 : 0; buf[2] = reason; if (notify_enabled_) { SendNotify(buf, 3); } if (success) { ESP_LOGI(TAG, "向客户端报告设备连接WiFi成功!"); } else { ESP_LOGI(TAG, "向客户端报告连接WiFi失败,原因: %d", reason); } } // ============================================================ // SendWiFiList — 通过 GATT NOTIFY 发送WiFi扫描列表 // ============================================================ void BluetoothProvisioning::SendWiFiList(const wifi_ap_record_t* ap_list, uint16_t ap_count) { if (!client_connected_) { ESP_LOGW(TAG, "客户端未连接,无法发送WiFi列表"); return; } if (ap_list == nullptr || ap_count == 0) { ESP_LOGW(TAG, "WiFi列表为空"); // 发送结束标记 if (notify_enabled_) { uint8_t end = PROV_RESP_WIFI_LIST_END; SendNotify(&end, 1); } return; } ESP_LOGI(TAG, "向客户端发送WiFi列表,共%d个AP", ap_count); if (notify_enabled_) { for (uint16_t i = 0; i < ap_count; i++) { uint8_t ssid_len = strlen(reinterpret_cast(ap_list[i].ssid)); uint8_t buf[3 + 32]; // cmd + rssi + ssid_len + ssid buf[0] = PROV_RESP_WIFI_LIST; buf[1] = (uint8_t)(ap_list[i].rssi & 0xFF); buf[2] = ssid_len; memcpy(&buf[3], ap_list[i].ssid, ssid_len); SendNotify(buf, 3 + ssid_len); vTaskDelay(pdMS_TO_TICKS(20)); // 每条之间稍作延迟 } // 发送结束标记 uint8_t end = PROV_RESP_WIFI_LIST_END; SendNotify(&end, 1); } ESP_LOGI(TAG, "📤 WiFi列表已发送给客户端,包含 %d 个热点", ap_count); } // ============================================================ // SendMacAddressReliably — 通过 GATT NOTIFY 可靠发送MAC地址 // ============================================================ bool BluetoothProvisioning::SendMacAddressReliably() { if (!client_connected_) { ESP_LOGW(TAG, "客户端未连接,无法发送MAC地址"); return false; } uint8_t mac[6]; esp_err_t ret = esp_wifi_get_mac(WIFI_IF_STA, mac); if (ret != ESP_OK) { ESP_LOGE(TAG, "获取MAC地址失败: %s", esp_err_to_name(ret)); return false; } char mac_str[18]; snprintf(mac_str, sizeof(mac_str), "%02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); if (mac_address_sent_) { ESP_LOGI(TAG, "MAC地址已发送过,跳过重复发送: %s", mac_str); return true; } ESP_LOGI(TAG, "开始可靠发送MAC地址: %s", mac_str); const int MAX_SEND_ATTEMPTS = 3; const int RETRY_DELAY_MS = 50; for (int attempt = 1; attempt <= MAX_SEND_ATTEMPTS; attempt++) { if (!client_connected_) { ESP_LOGW(TAG, "发送前检查发现客户端已断开连接 (尝试 %d/%d)", attempt, MAX_SEND_ATTEMPTS); return false; } ESP_LOGI(TAG, "发送MAC地址尝试 %d/%d: %s", attempt, MAX_SEND_ATTEMPTS, mac_str); // 构建自定义数据包 (保留原有格式) char mac_data[32]; snprintf(mac_data, sizeof(mac_data), "STA_MAC:%02x:%02x:%02x:%02x:%02x:%02x", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); uint8_t buf[1 + 32]; buf[0] = PROV_RESP_CUSTOM_DATA; uint8_t data_len = strlen(mac_data); memcpy(&buf[1], mac_data, data_len); bool ok = false; if (notify_enabled_) { ok = SendNotify(buf, 1 + data_len); } else { ESP_LOGW(TAG, "NOTIFY未启用,尝试直接发送"); ok = SendNotify(buf, 1 + data_len); } if (ok) { ESP_LOGI(TAG, "✅ MAC地址发送成功 (尝试 %d/%d): %s", attempt, MAX_SEND_ATTEMPTS, mac_str); mac_address_sent_ = true; vTaskDelay(pdMS_TO_TICKS(100)); if (client_connected_) { ESP_LOGI(TAG, "MAC地址发送完成,连接状态正常"); return true; } else { ESP_LOGW(TAG, "MAC地址发送后检测到连接断开"); return false; } } else { ESP_LOGW(TAG, "❌ MAC地址发送失败 (尝试 %d/%d): %s", attempt, MAX_SEND_ATTEMPTS, mac_str); if (attempt < MAX_SEND_ATTEMPTS) { vTaskDelay(pdMS_TO_TICKS(RETRY_DELAY_MS)); } } } ESP_LOGE(TAG, "MAC地址发送失败,已达到最大重试次数: %s", mac_str); return false; } void BluetoothProvisioning::ResetMacSendingState() { mac_address_sent_ = false; ESP_LOGI(TAG, "MAC地址发送状态已重置"); } // ============================================================ // 状态管理 // ============================================================ void BluetoothProvisioning::SetState(BluetoothProvisioningState new_state) { if (state_ != new_state) { BluetoothProvisioningState old_state = state_; state_ = new_state; const char* state_names[] = { "IDLE", "INITIALIZING", "ADVERTISING", "CONNECTED", "PROVISIONING", "SUCCESS", "FAILED", "STOPPED" }; ESP_LOGI(TAG, "🔄 配网状态变化: %s -> %s", state_names[static_cast(old_state)], state_names[static_cast(new_state)]); TriggerCallback(BluetoothProvisioningEvent::STATE_CHANGED, nullptr); } } void BluetoothProvisioning::TriggerCallback(BluetoothProvisioningEvent event, void* data) { if (callback_) { callback_(event, data); } } std::string BluetoothProvisioning::GetStateString() const { const char* state_names[] = { "IDLE", "INITIALIZING", "ADVERTISING", "CONNECTED", "PROVISIONING", "SUCCESS", "FAILED", "STOPPED" }; return std::string(state_names[static_cast(state_)]); } // ============================================================ // WiFi 事件处理 (保留原有业务逻辑) // ============================================================ void BluetoothProvisioning::WiFiEventHandler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data) { BluetoothProvisioning* self = static_cast(arg); if (event_base == WIFI_EVENT) { switch (event_id) { case WIFI_EVENT_STA_START: ESP_LOGI(TAG, "WiFi STA启动"); break; case WIFI_EVENT_STA_CONNECTED: { wifi_event_sta_connected_t* event = static_cast(event_data); ESP_LOGI(TAG, "✅ WiFi连接成功,SSID: %.*s,等待获取IP地址", event->ssid_len, event->ssid); if (wifi_connect_timer) { xTimerStop(wifi_connect_timer, 0); } self->wifi_connecting_ = false; self->delayed_disconnect_ = false; break; } case WIFI_EVENT_STA_DISCONNECTED: { wifi_event_sta_disconnected_t* event = static_cast(event_data); ESP_LOGI(TAG, "WiFi断开连接,原因: %d", event->reason); if (self->state_ != BluetoothProvisioningState::PROVISIONING) { ESP_LOGD(TAG, "非配网状态下的WiFi断开,忽略处理"); break; } if (s_retry_num < MAX_RETRY) { esp_err_t ret = esp_wifi_connect(); s_retry_num++; ESP_LOGI(TAG, "🔄 立即重试连接WiFi (%d/%d),断开原因: %d,重试结果: %s", s_retry_num, MAX_RETRY, event->reason, ret == ESP_OK ? "成功" : "失败"); if (wifi_connect_timer && ret == ESP_OK) { xTimerReset(wifi_connect_timer, 0); } } else { ESP_LOGE(TAG, "❌ WiFi连接失败,已达到最大重试次数,断开原因: %d", event->reason); if (wifi_connect_timer) { xTimerStop(wifi_connect_timer, 0); } self->wifi_connecting_ = false; self->delayed_disconnect_ = false; xEventGroupSetBits(s_wifi_event_group, WIFI_FAIL_BIT); self->SetState(BluetoothProvisioningState::FAILED); self->TriggerCallback(BluetoothProvisioningEvent::WIFI_FAILED, &event->reason); self->ReportWiFiStatus(false, event->reason); } break; } case WIFI_EVENT_SCAN_DONE: { ESP_LOGI(TAG, "📡 WiFi扫描完成,准备发送WiFi列表"); uint16_t ap_count = 0; esp_err_t ret = esp_wifi_scan_get_ap_num(&ap_count); if (ret != ESP_OK) { ESP_LOGE(TAG, "❌ 获取WiFi扫描结果数量失败: %s", esp_err_to_name(ret)); break; } ESP_LOGI(TAG, "📊 扫描到 %d 个WiFi热点", ap_count); if (ap_count > 0) { wifi_ap_record_t* ap_list = (wifi_ap_record_t*)malloc(sizeof(wifi_ap_record_t) * ap_count); if (ap_list == nullptr) { ESP_LOGE(TAG, "❌ 分配WiFi扫描结果内存失败"); break; } ret = esp_wifi_scan_get_ap_records(&ap_count, ap_list); if (ret == ESP_OK) { ESP_LOGI(TAG, "✅ 成功获取WiFi扫描结果"); // 过滤: 只保留2.4GHz频段(信道1-14),去重相同SSID(保留信号最强的) // ESP-IDF返回结果已按RSSI降序排列,第一个出现的同名SSID即为信号最强 uint16_t filtered_count = 0; for (uint16_t i = 0; i < ap_count; i++) { // 过滤5GHz频段 (信道 > 14) if (ap_list[i].primary > 14) { ESP_LOGD(TAG, "过滤5GHz: SSID=%s, 信道=%d, RSSI=%d", ap_list[i].ssid, ap_list[i].primary, ap_list[i].rssi); continue; } // 过滤空SSID(隐藏网络) uint8_t ssid_len = strlen(reinterpret_cast(ap_list[i].ssid)); if (ssid_len == 0) { continue; } // SSID去重: 检查是否已存在相同SSID bool duplicate = false; for (uint16_t j = 0; j < filtered_count; j++) { if (strcmp(reinterpret_cast(ap_list[j].ssid), reinterpret_cast(ap_list[i].ssid)) == 0) { duplicate = true; break; } } if (duplicate) { continue; } // 将符合条件的AP移到前面 if (filtered_count != i) { ap_list[filtered_count] = ap_list[i]; } filtered_count++; } ESP_LOGI(TAG, "📊 过滤后剩余 %d 个2.4GHz热点 (原始: %d)", filtered_count, ap_count); self->SendWiFiList(ap_list, filtered_count); ESP_LOGI(TAG, "📤 WiFi列表已发送,包含 %d 个热点", filtered_count); } else { ESP_LOGE(TAG, "❌ 获取WiFi扫描结果详细信息失败: %s", esp_err_to_name(ret)); } free(ap_list); } else { ESP_LOGW(TAG, "⚠️ 未扫描到任何WiFi热点"); self->SendWiFiList(nullptr, 0); } break; } default: break; } } } // ============================================================ // IP 事件处理 (保留原有业务逻辑: 保存WiFi、发送MAC、重启) // ============================================================ void BluetoothProvisioning::IPEventHandler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data) { BluetoothProvisioning* self = static_cast(arg); switch (event_id) { case IP_EVENT_STA_GOT_IP: { ip_event_got_ip_t* event = static_cast(event_data); ESP_LOGI(TAG, "✅ WiFi获取IP地址成功: " IPSTR, IP2STR(&event->ip_info.ip)); s_retry_num = 0; // 停止WiFi连接超时定时器 if (wifi_connect_timer) { xTimerStop(wifi_connect_timer, 0); xTimerDelete(wifi_connect_timer, 0); wifi_connect_timer = nullptr; } self->wifi_connecting_ = false; self->delayed_disconnect_ = false; if (s_wifi_event_group) { xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT); } // 跳过MAC地址发送,仅通过 ReportWiFiStatus 发送连接状态 // // 发送MAC地址 // if (self && self->client_connected_) { // bool mac_sent = self->SendMacAddressReliably(); // ESP_LOGI(TAG, "MAC地址发送结果: %s", mac_sent ? "成功" : "失败"); // } // 启用WiFi配置自动保存到NVS存储 ESP_LOGI(TAG, "💾 启用WiFi配置自动保存到NVS存储..."); esp_err_t storage_ret = esp_wifi_set_storage(WIFI_STORAGE_FLASH); if (storage_ret == ESP_OK) { ESP_LOGI(TAG, "✅ WiFi配置将自动保存到NVS存储"); } else { ESP_LOGW(TAG, "⚠️ 设置WiFi存储模式失败: %s", esp_err_to_name(storage_ret)); } // 手动获取当前WiFi配置并保存到NVS列表 wifi_config_t wifi_config; esp_err_t get_config_ret = esp_wifi_get_config(WIFI_IF_STA, &wifi_config); if (get_config_ret == ESP_OK) { ESP_LOGI(TAG, "📋 获取当前WiFi配置成功,SSID: %s", wifi_config.sta.ssid); auto& ssid_manager = SsidManager::GetInstance(); ssid_manager.AddSsid((const char*)wifi_config.sta.ssid, (const char*)wifi_config.sta.password); ESP_LOGI(TAG, "✅ WiFi凭据已保存到NVS列表"); } else { ESP_LOGW(TAG, "⚠️ 获取当前WiFi配置失败: %s", esp_err_to_name(get_config_ret)); } auto& application = Application::GetInstance(); bool skip_session = application.ShouldSkipDialogIdleSession(); ESP_LOGI(TAG, "BluetoothProvisioning WIFI_CONNECTED skip_session=%d", (int)skip_session); if (!skip_session) { if(strcmp(CONFIG_DEVICE_ROLE, "KAKA") == 0){ application.PlaySound(Lang::Sounds::P3_KAKA_LIANJIEWANGLUO); } else if(strcmp(CONFIG_DEVICE_ROLE, "RTC_Test") == 0){ application.PlaySound(Lang::Sounds::P3_LALA_LIANJIEWANGLUO); } } else { application.ClearDialogIdleSkipSession(); } // 更新状态和触发回调 ESP_LOGI(TAG, "🔍 准备设置状态为SUCCESS并触发回调"); self->SetState(BluetoothProvisioningState::SUCCESS); self->TriggerCallback(BluetoothProvisioningEvent::WIFI_CONNECTED, &event->ip_info.ip); self->ReportWiFiStatus(true, 0); ESP_LOGI(TAG, "📋 配网流程完成,状态: %s, client_connected_: %s", self->GetStateString().c_str(), self->client_connected_ ? "true" : "false"); // 用 esp_timer 延迟重启,避免在事件回调中直接调用 esp_restart() // 不使用 xTaskCreate,配网模式下内存紧张可能导致任务创建失败 ESP_LOGI(TAG, "⏰ 延迟2000ms后重启设备以确保配置生效..."); esp_timer_handle_t restart_timer; esp_timer_create_args_t timer_args = {}; timer_args.callback = [](void*) { ESP_LOGI("BLE_PROV", "🔄 强制重启设备..."); esp_restart(); }; timer_args.name = "prov_restart"; if (esp_timer_create(&timer_args, &restart_timer) == ESP_OK) { esp_timer_start_once(restart_timer, 2000 * 1000); // 2秒,单位微秒 } else { ESP_LOGE(TAG, "定时器创建失败,直接重启"); esp_restart(); } break; } default: break; } }