#include "wifi_manager.h" // 外部变量和函数声明 extern bool deviceConnected; void sendJSONDataToBLE(const String& jsonData); void setNetworkStatus(NetworkStatus status); /** * @brief WiFi管理器构造函数 * 初始化WiFi管理器的成员变量 */ WiFiManager::WiFiManager() { savedNetworkCount = 0; currentState = WIFI_IDLE; lastReconnectAttempt = 0; isScanning = false; } /** * @brief 初始化WiFi管理器 * 开启Preferences存储,并加载保存的WiFi配置 */ void WiFiManager::begin() { preferences.begin("wifi_manager", false); loadWiFiConfigs(); } /** * @brief 加载保存的WiFi配置 * 从Flash中读取之前保存的WiFi网络配置 * @return 是否成功加载到配置 */ bool WiFiManager::loadWiFiConfigs() { savedNetworkCount = 0; for (int i = 0; i < MAX_WIFI_NETWORKS; i++) { String key = "wifi_" + String(i); String configStr = preferences.getString(key.c_str(), ""); if (configStr.length() > 0) { JsonDocument doc; DeserializationError error = deserializeJson(doc, configStr); if (!error) { const char* ssid = doc["ssid"]; const char* password = doc["password"]; if (ssid && password) { strncpy(savedNetworks[savedNetworkCount].ssid, ssid, 31); savedNetworks[savedNetworkCount].ssid[31] = '\0'; strncpy(savedNetworks[savedNetworkCount].password, password, 63); savedNetworks[savedNetworkCount].password[63] = '\0'; savedNetworkCount++; Serial.printf("📶 加载WiFi配置 %d: %s\n", savedNetworkCount, ssid); } } } } Serial.printf("✅ 共加载 %d 个WiFi配置\n", savedNetworkCount); return savedNetworkCount > 0; } /** * @brief 保存WiFi配置 * 将WiFi网络配置保存到Flash中 * @param ssid WiFi网络名称 * @param password WiFi网络密码 * @return 是否保存成功 */ bool WiFiManager::saveWiFiConfig(const char* ssid, const char* password) { // 检查是否已存在该网络配置 for (int i = 0; i < savedNetworkCount; i++) { if (strcmp(savedNetworks[i].ssid, ssid) == 0) { // 更新现有配置 strncpy(savedNetworks[i].password, password, 63); savedNetworks[i].password[63] = '\0'; JsonDocument doc; doc["ssid"] = ssid; doc["password"] = password; String configStr; serializeJson(doc, configStr); String key = "wifi_" + String(i); preferences.putString(key.c_str(), configStr); Serial.printf("🔄 更新WiFi配置: %s\n", ssid); return true; } } // 添加新配置 if (savedNetworkCount < MAX_WIFI_NETWORKS) { strncpy(savedNetworks[savedNetworkCount].ssid, ssid, 31); savedNetworks[savedNetworkCount].ssid[31] = '\0'; strncpy(savedNetworks[savedNetworkCount].password, password, 63); savedNetworks[savedNetworkCount].password[63] = '\0'; JsonDocument doc; doc["ssid"] = ssid; doc["password"] = password; String configStr; serializeJson(doc, configStr); String key = "wifi_" + String(savedNetworkCount); preferences.putString(key.c_str(), configStr); savedNetworkCount++; Serial.printf("➕ 新增WiFi配置: %s (总计: %d)\n", ssid, savedNetworkCount); return true; } Serial.println("❌ WiFi配置已满,无法添加"); return false; } /** * @brief 连接到指定WiFi网络 * 尝试连接到给定的WiFi网络 * @param ssid WiFi网络名称 * @param password WiFi网络密码 * @return 是否连接成功 */ bool WiFiManager::connectToNetwork(const char* ssid, const char* password) { Serial.printf("🌐 [WiFi] 尝试连接到 SSID: %s\n", ssid); currentState = WIFI_CONNECTING; setNetworkStatus(NET_CONNECTING); WiFi.mode(WIFI_STA); vTaskDelay(200 / portTICK_PERIOD_MS); WiFi.begin(ssid, password); unsigned long startTime = millis(); unsigned long lastStatusPrint = 0; while (WiFi.status() != WL_CONNECTED && (millis() - startTime) < WIFI_CONNECT_TIMEOUT) { if (millis() - lastStatusPrint >= 500) { Serial.printf("[WiFi] 连接中,状态: %d\n", WiFi.status()); lastStatusPrint = millis(); } yield(); vTaskDelay(50 / portTICK_PERIOD_MS); } if (WiFi.status() == WL_CONNECTED) { Serial.println("✅ [WiFi] 连接成功!"); Serial.printf("🌐 IP地址: %s\n", WiFi.localIP().toString().c_str()); Serial.printf("🔒 信号强度: %d dBm\n", WiFi.RSSI()); currentState = WIFI_CONNECTED; setNetworkStatus(NET_CONNECTED); return true; } else { Serial.println("❌ [WiFi] 连接超时"); currentState = WIFI_DISCONNECTED; setNetworkStatus(NET_DISCONNECTED); return false; } } /** * @brief 扫描并匹配WiFi网络 * 扫描附近的WiFi网络,并尝试匹配已保存的配置 * 如果找到多个匹配的网络,优先连接信号强度最强的那一组 * @return 是否成功连接到匹配的网络 */ bool WiFiManager::scanAndMatchNetworks() { if (isScanning) { Serial.println("⚠️ [WiFi] 正在扫描中,跳过本次扫描"); return false; } Serial.println("🔍 [WiFi] 开始扫描WiFi网络..."); currentState = WIFI_SCANNING; isScanning = true; if (WiFi.status() == WL_CONNECTED) { Serial.println("📶 WiFi已连接,断开后扫描"); WiFi.disconnect(false); vTaskDelay(200 / portTICK_PERIOD_MS); } WiFi.mode(WIFI_STA); vTaskDelay(200 / portTICK_PERIOD_MS); int n = WiFi.scanNetworks(); Serial.printf("🔍 扫描到 %d 个WiFi网络\n", n); if (n <= 0) { Serial.println("❌ 未扫描到任何WiFi网络或扫描失败"); currentState = WIFI_DISCONNECTED; isScanning = false; return false; } // 收集所有匹配的、信号强度符合要求的网络 struct { const char* ssid; const char* password; int rssi; } bestNetwork = {nullptr, nullptr, -1000}; // 初始化为非常弱的信号 // 遍历已保存的网络,寻找匹配的网络 for (int i = 0; i < savedNetworkCount; i++) { for (int j = 0; j < n; j++) { if (WiFi.SSID(j) == String(savedNetworks[i].ssid)) { int rssi = WiFi.RSSI(j); Serial.printf("📶 找到匹配网络: %s, 信号: %d dBm\n", savedNetworks[i].ssid, rssi); // 检查信号强度是否符合要求 if (rssi >= MIN_RSSI_THRESHOLD) { // 检查是否是当前找到的信号最强的网络 if (rssi > bestNetwork.rssi) { bestNetwork.ssid = savedNetworks[i].ssid; bestNetwork.password = savedNetworks[i].password; bestNetwork.rssi = rssi; Serial.printf("📈 更新最佳网络: %s, 信号: %d dBm\n", bestNetwork.ssid, bestNetwork.rssi); } } else { Serial.printf("⚠️ 信号强度过低,跳过\n"); } } } } // 如果找到最佳网络,尝试连接 if (bestNetwork.ssid != nullptr) { Serial.printf("✅ 选择信号最强的网络: %s, 信号: %d dBm\n", bestNetwork.ssid, bestNetwork.rssi); WiFi.scanDelete(); vTaskDelay(300 / portTICK_PERIOD_MS); if (connectToNetwork(bestNetwork.ssid, bestNetwork.password)) { isScanning = false; return true; } } Serial.println("❌ 未找到匹配的WiFi网络或信号过弱"); currentState = WIFI_DISCONNECTED; isScanning = false; return false; } /** * @brief 初始化WiFi连接 * 启动WiFi初始化过程,尝试连接到已保存的网络 * @return 是否初始化成功 */ bool WiFiManager::initializeWiFi() { Serial.println("🚀 [WiFi] 初始化WiFi连接..."); if (savedNetworkCount == 0) { Serial.println("⚠️ 未保存的WiFi配置"); currentState = WIFI_IDLE; return false; } if (scanAndMatchNetworks()) { Serial.println("✅ WiFi初始化成功"); return true; } else { Serial.println("❌ WiFi初始化失败"); currentState = WIFI_DISCONNECTED; return false; } } /** * @brief 扫描WiFi网络并发送结果 * 扫描附近的WiFi网络,过滤信号弱的网络,将结果通过BLE发送给客户端 */ void WiFiManager::scanAndSendResults() { if (isScanning) { Serial.println("⚠️ [WiFi] 正在扫描中,跳过本次扫描"); if (deviceConnected) { String errorMsg = String("{\"type\":\"scanWiFiResult\",\"success\":false,\"message\":\"正在扫描中,请稍后再试\",\"networks\":[],\"count\":0}"); sendJSONDataToBLE(errorMsg); } return; } Serial.println("📱 [BLE-WiFi] 开始WiFi扫描..."); isScanning = true; if (WiFi.status() == WL_CONNECTED) { Serial.println("📶 WiFi已连接,断开后扫描"); WiFi.disconnect(false); vTaskDelay(200 / portTICK_PERIOD_MS); } WiFi.mode(WIFI_STA); vTaskDelay(200 / portTICK_PERIOD_MS); int n = WiFi.scanNetworks(); Serial.printf("🔍 扫描到 %d 个WiFi网络\n", n); if (n <= 0) { Serial.println("❌ 未扫描到任何WiFi网络或扫描失败"); isScanning = false; if (deviceConnected) { String errorMsg = String("{\"type\":\"scanWiFiResult\",\"success\":false,\"message\":\"未扫描到任何WiFi网络或扫描失败\",\"networks\":[],\"count\":0}"); sendJSONDataToBLE(errorMsg); } return; } // 构建WiFi网络列表的JSON数据 String wifiList = String("{\"type\":\"scanWiFiResult\",\"success\":true,\"count\":") + String(n) + String(",\"networks\":["); bool first = true; for (int i = 0; i < n; ++i) { if (WiFi.RSSI(i) >= MIN_RSSI_THRESHOLD) { if (!first) { wifiList += ","; } wifiList += String("{\"ssid\":\"") + WiFi.SSID(i) + String("\",\"rssi\":") + String(WiFi.RSSI(i)) + String(",\"channel\":") + String(WiFi.channel(i)) + String(",\"encryption\":"); // 根据加密类型添加相应的描述 switch (WiFi.encryptionType(i)) { case WIFI_AUTH_OPEN: wifiList += String("\"open\""); break; case WIFI_AUTH_WEP: wifiList += String("\"WEP\""); break; case WIFI_AUTH_WPA_PSK: wifiList += String("\"WPA\""); break; case WIFI_AUTH_WPA2_PSK: wifiList += String("\"WPA2\""); break; case WIFI_AUTH_WPA_WPA2_PSK: wifiList += String("\"WPA/WPA2\""); break; case WIFI_AUTH_WPA2_ENTERPRISE: wifiList += String("\"WPA2-EAP\""); break; case WIFI_AUTH_WPA3_PSK: wifiList += String("\"WPA3\""); break; case WIFI_AUTH_WPA2_WPA3_PSK: wifiList += String("\"WPA2/WPA3\""); break; default: wifiList += String("\"unknown\""); break; } wifiList += "}"; first = false; } } wifiList += "]}"; Serial.printf("✅ 发送WiFi扫描结果,包含 %d 个可用网络\n", first ? 0 : n); WiFi.scanDelete(); isScanning = false; if (deviceConnected) { sendJSONDataToBLE(wifiList); } } /** * @brief 开始配网模式 * 进入配网模式,扫描WiFi网络并发送结果给客户端 * @return 是否成功进入配网模式 */ bool WiFiManager::startConfiguration() { Serial.println("⚙️ [WiFi] 开始配网模式..."); currentState = WIFI_CONFIGURING; scanAndSendResults(); return true; } /** * @brief 处理配网数据 * 处理从客户端收到的WiFi配网信息,先扫描WiFi是否有匹配的网络,再尝试连接并保存 * @param ssid WiFi网络名称 * @param password WiFi网络密码 * @return 是否配置成功 */ bool WiFiManager::handleConfigurationData(const char* ssid, const char* password) { Serial.printf("📱 [BLE-WiFi] 收到配网信息: SSID='%s'\n", ssid); if (ssid == nullptr || password == nullptr || strlen(ssid) == 0) { Serial.println("❌ 配网参数无效"); return false; } // 先扫描WiFi网络,检查是否存在匹配的网络 Serial.println("🔍 [WiFi] 扫描WiFi网络,检查是否存在匹配的网络..."); int n = WiFi.scanNetworks(); Serial.printf("🔍 扫描到 %d 个WiFi网络\n", n); if (n == 0) { Serial.println("❌ 未扫描到任何WiFi网络"); if (deviceConnected) { String resultMsg = String("{\"type\":\"wifiConfigResult\",\"success\":false,\"message\":\"未扫描到任何WiFi网络,请检查设备位置\"}"); sendJSONDataToBLE(resultMsg); } return false; } bool networkFound = false; bool signalTooWeak = false; int foundRssi = 0; for (int i = 0; i < n; i++) { if (WiFi.SSID(i) == String(ssid)) { foundRssi = WiFi.RSSI(i); Serial.printf("📶 找到匹配网络: %s, 信号: %d dBm\n", ssid, foundRssi); if (foundRssi >= MIN_RSSI_THRESHOLD) { Serial.printf("✅ 信号强度符合要求,准备连接...\n"); networkFound = true; break; } else { Serial.printf("⚠️ 信号强度过低,跳过\n"); signalTooWeak = true; } } } if (!networkFound) { String errorMsg; if (signalTooWeak) { errorMsg = String("{\"type\":\"wifiConfigResult\",\"success\":false,\"message\":\"目标WiFi信号过弱,请将设备靠近路由器\"}"); Serial.printf("❌ 目标WiFi信号过弱: %d dBm (阈值: %d dBm)\n", foundRssi, MIN_RSSI_THRESHOLD); } else { errorMsg = String("{\"type\":\"wifiConfigResult\",\"success\":false,\"message\":\"未找到目标WiFi网络,请检查WiFi名称是否正确\"}"); Serial.println("❌ 未找到目标WiFi网络"); } if (deviceConnected) { sendJSONDataToBLE(errorMsg); } return false; } // 尝试连接到指定网络 if (connectToNetwork(ssid, password)) { // 连接成功后保存配置 if (saveWiFiConfig(ssid, password)) { Serial.println("✅ WiFi配置成功并已保存"); if (deviceConnected) { String resultMsg = String("{\"type\":\"wifiConfigResult\",\"success\":true,\"message\":\"WiFi配置成功\"}"); sendJSONDataToBLE(resultMsg); } return true; } } Serial.println("❌ WiFi配置失败"); if (deviceConnected) { String resultMsg = String("{\"type\":\"wifiConfigResult\",\"success\":false,\"message\":\"WiFi配置失败,请检查密码是否正确\"}"); sendJSONDataToBLE(resultMsg); } return false; } /** * @brief 处理WiFi重连 * 检查WiFi连接状态,当断开连接时尝试重连 */ void WiFiManager::handleReconnect() { // 检查当前是否已连接 if (currentState == WIFI_CONNECTED) { if (WiFi.status() == WL_CONNECTED) { return; } // 连接已断开 currentState = WIFI_DISCONNECTED; setNetworkStatus(NET_DISCONNECTED); Serial.println("⚠️ WiFi连接断开"); } // 处理重连逻辑 if (currentState == WIFI_DISCONNECTED) { unsigned long currentTime = millis(); // 按照设定的间隔尝试重连 if (currentTime - lastReconnectAttempt >= WIFI_RECONNECT_INTERVAL) { lastReconnectAttempt = currentTime; if (scanAndMatchNetworks()) { Serial.println("✅ WiFi重连成功"); } else { Serial.println("❌ WiFi重连失败,2秒后重试"); } } } } /** * @brief 获取当前WiFi状态 * @return 当前的WiFi管理器状态 */ WiFiManagerState WiFiManager::getState() { return currentState; } /** * @brief 检查WiFi是否已连接 * @return WiFi是否已成功连接 */ bool WiFiManager::isConnected() { return currentState == WIFI_CONNECTED && WiFi.status() == WL_CONNECTED; } /** * @brief 断开WiFi连接 * 主动断开当前的WiFi连接 */ void WiFiManager::disconnect() { WiFi.disconnect(true); currentState = WIFI_DISCONNECTED; setNetworkStatus(NET_DISCONNECTED); } /** * @brief 添加WiFi配置 * 向保存的配置中添加新的WiFi网络 * @param ssid WiFi网络名称 * @param password WiFi网络密码 * @return 是否添加成功 */ bool WiFiManager::addWiFiConfig(const char* ssid, const char* password) { return saveWiFiConfig(ssid, password); } /** * @brief 清除所有WiFi配置 * 删除所有保存的WiFi网络配置 */ void WiFiManager::clearAllConfigs() { for (int i = 0; i < MAX_WIFI_NETWORKS; i++) { String key = "wifi_" + String(i); preferences.remove(key.c_str()); } savedNetworkCount = 0; Serial.println("🗑️ 已清除所有WiFi配置"); } /** * @brief 获取已保存的网络数量 * @return 已保存的WiFi网络配置数量 */ int WiFiManager::getSavedNetworkCount() { return savedNetworkCount; } /** * @brief 获取已保存的WiFi网络列表 * 将保存的WiFi网络配置通过BLE发送给客户端 */ void WiFiManager::getSavedNetworks() { Serial.printf("📋 [WiFi] 获取已保存的WiFi网络列表,共 %d 个\n", savedNetworkCount); if (savedNetworkCount == 0) { Serial.println("⚠️ 没有保存的WiFi网络"); if (deviceConnected) { String responseMsg = String("{\"type\":\"savedNetworks\",\"success\":true,\"count\":0,\"networks\":[]}"); sendJSONDataToBLE(responseMsg); } return; } String wifiList = String("{\"type\":\"savedNetworks\",\"success\":true,\"count\":") + String(savedNetworkCount) + String(",\"networks\":["); for (int i = 0; i < savedNetworkCount; i++) { if (i > 0) { wifiList += ","; } wifiList += String("{\"ssid\":\"") + String(savedNetworks[i].ssid) + String("\"}"); } wifiList += "]}"; Serial.printf("📤 [WiFi] 发送已保存的WiFi网络列表: %s\n", wifiList.c_str()); if (deviceConnected) { sendJSONDataToBLE(wifiList); } } /** * @brief 更新WiFi管理器状态 * 定期调用此函数,处理WiFi重连等状态管理 */ void WiFiManager::update() { handleReconnect(); }