Update project with radar and wifi manager modules

This commit is contained in:
Admin
2026-02-28 14:52:02 +08:00
parent 941e842562
commit 4391c14145
9 changed files with 6179 additions and 2567 deletions

View File

View File

@@ -1,36 +0,0 @@
#ifndef RADAR_H
#define RADAR_H
// 在main.cpp顶部添加R60ABD1协议相关定义
#define FRAME_HEADER1 0x53 // 帧头字节1
#define FRAME_HEADER2 0x59 // 帧头字节2
#define FRAME_TAIL1 0x54 // 帧尾字节1
#define FRAME_TAIL2 0x43 // 帧尾字节2
// 控制字定义
#define CTRL_PRESENCE 0x80 // 人体存在检测
#define CTRL_BREATH 0x81 // 呼吸检测
#define CTRL_SLEEP 0x84 // 睡眠监测
#define CTRL_HEARTRATE 0x85 // 心率监测
// 命令字定义
#define CMD_REPORT 0x80 // 主动上报
#define CMD_QUERY 0x81 // 查询命令
#define CMD_SET 0x82 // 设置命令
// 定义R60ABD1数据结构
typedef struct {
uint8_t present; // 有人/无人状态 (DP1)
uint16_t distance; // 人体距离 (DP3) 单位cm
uint8_t heartRate; // 心率 (DP6) 单位BPM
uint8_t breathRate; // 呼吸率 (DP8) 单位次/分钟
uint8_t heartWave; // 心率波形 (DP7) 数值+128
uint8_t breathWave; // 呼吸波形 (DP10) 数值+128
uint8_t sleepState; // 睡眠状态 (DP12)
uint32_t sleepTime; // 睡眠时长 (DP13) 单位秒
uint8_t sleepScore; // 睡眠质量评分 (DP14)
uint8_t bedEntry; // 入床/离床状态 (DP11)
uint8_t abnormal; // 异常状态 (DP18)
} R60ABD1Data;
#endif

File diff suppressed because it is too large Load Diff

2582
src/main_backup.cpp.bak Normal file

File diff suppressed because it is too large Load Diff

1721
src/radar_manager.cpp Normal file

File diff suppressed because it is too large Load Diff

235
src/radar_manager.h Normal file
View File

@@ -0,0 +1,235 @@
#ifndef RADAR_MANAGER_H
#define RADAR_MANAGER_H
#include <Arduino.h>
#include <ArduinoJson.h>
#include <BLEDevice.h>
#include <BLEServer.h>
#include <BLEUtils.h>
#include <BLE2902.h>
#include <HTTPClient.h>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <freertos/queue.h>
#include <Preferences.h>
class WiFiManager;
#define SERVICE_UUID "a8c1e5c0-3d5d-4a9d-8d5e-7c8b6a4e2f1a" // BLE服务UUID
#define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8" // BLE特征值UUID
#define UART_RX_BUFFER_SIZE 4096 // UART接收缓冲区大小
#define QUEUE_SIZE 50 // 队列大小
#define TASK_STACK_SIZE 8192 // 任务堆栈大小
#define FRAME_HEADER1 0x53 // 帧头字节1
#define FRAME_HEADER2 0x59 // 帧头字节2
#define FRAME_TAIL1 0x54 // 帧尾字节1
#define FRAME_TAIL2 0x43 // 帧尾字节2
// 控制字定义
#define CTRL_PRESENCE 0x80 // 人体存在检测
#define CTRL_BREATH 0x81 // 呼吸检测
#define CTRL_SLEEP 0x84 // 睡眠监测
#define CTRL_HEARTRATE 0x85 // 心率监测
// 命令字定义
#define CMD_REPORT 0x80 // 主动上报
#define CMD_QUERY 0x81 // 查询命令
#define CMD_SET 0x82 // 设置命令
// 定义R60ABD1数据结构
typedef struct {
uint8_t present; // 有人/无人状态 (DP1)
uint16_t distance; // 人体距离 (DP3) 单位cm
uint8_t heartRate; // 心率 (DP6) 单位BPM
uint8_t breathRate; // 呼吸率 (DP8) 单位次/分钟
uint8_t heartWave; // 心率波形 (DP7) 数值+128
uint8_t breathWave; // 呼吸波形 (DP10) 数值+128
uint8_t sleepState; // 睡眠状态 (DP12)
uint32_t sleepTime; // 睡眠时长 (DP13) 单位秒
uint8_t sleepScore; // 睡眠质量评分 (DP14)
uint8_t bedEntry; // 入床/离床状态 (DP11)
uint8_t abnormal; // 异常状态 (DP18)
} R60ABD1Data; // R60ABD1雷达数据结构体
typedef struct { // 传感器数据结构体
float breath_rate; // 呼吸率
float heart_rate; // 心率
uint8_t breath_valid; // 呼吸率有效标志
uint8_t heart_valid; // 心率有效标志
uint8_t presence; // 存在状态
uint8_t motion; // 运动状态
int heartbeat_waveform; // 心跳波形
int breathing_waveform; // 呼吸波形
uint16_t distance; // 距离
uint8_t body_movement; // 身体运动
uint8_t breath_status; // 呼吸状态
uint8_t sleep_state; // 睡眠状态
uint32_t sleep_time; // 睡眠时长
uint8_t sleep_score; // 睡眠评分
uint8_t sleep_grade; // 睡眠等级
uint8_t bed_entry; // 入床状态
uint8_t abnormal_state; // 异常状态
uint8_t avg_heart_rate; // 平均心率
uint8_t avg_breath_rate; // 平均呼吸率
uint8_t turn_count; // 翻身次数
uint8_t large_move_ratio; // 大幅运动比例
uint8_t small_move_ratio; // 小幅运动比例
int16_t pos_x; // X坐标
int16_t pos_y; // Y坐标
int16_t pos_z; // Z坐标
int8_t breath_waveform[5]; // 呼吸波形数组
int8_t heart_waveform[5]; // 心跳波形数组
uint16_t deep_sleep_time; // 深度睡眠时长
uint16_t light_sleep_time; // 浅度睡眠时长
uint16_t awake_time; // 清醒时长
uint16_t sleep_total_time; // 总睡眠时长
uint8_t deep_sleep_ratio; // 深度睡眠比例
uint8_t light_sleep_ratio; // 浅度睡眠比例
uint8_t awake_ratio; // 清醒比例
uint8_t turnover_count; // 翻身计数
uint8_t struggle_alert; // 挣扎警报
uint8_t no_one_alert; // 无人警报
uint8_t bed_status; // 床状态
uint8_t bed_Out_Time; // 离床时间
uint8_t apnea_count; // 呼吸暂停次数
} SensorData; // 传感器数据结构体
typedef struct { // 相位数据结构体
int heartbeat_waveform; // 心跳波形
int breathing_waveform; // 呼吸波形
} PhaseData; // 相位数据结构体
typedef struct { // 生命体征数据结构体
float heart_rate; // 心率
float breath_rate; // 呼吸率
uint8_t presence; // 存在状态
uint8_t motion; // 运动状态
uint16_t distance; // 距离
uint8_t sleep_state; // 睡眠状态
uint8_t sleep_score; // 睡眠评分
uint8_t body_movement; // 身体运动
uint8_t breath_status; // 呼吸状态
uint32_t sleep_time; // 睡眠时长
uint8_t bed_entry; // 入床状态
uint8_t abnormal_state; // 异常状态
uint8_t avg_heart_rate; // 平均心率
uint8_t avg_breath_rate; // 平均呼吸率
uint8_t turn_count; // 翻身次数
uint8_t large_move_ratio; // 大幅运动比例
uint8_t small_move_ratio; // 小幅运动比例
int16_t pos_x; // X坐标
int16_t pos_y; // Y坐标
int16_t pos_z; // Z坐标
uint16_t deep_sleep_time; // 深度睡眠时长
uint16_t light_sleep_time; // 浅度睡眠时长
uint16_t awake_time; // 清醒时长
uint16_t sleep_total_time; // 总睡眠时长
uint8_t deep_sleep_ratio; // 深度睡眠比例
uint8_t light_sleep_ratio; // 浅度睡眠比例
uint8_t awake_ratio; // 清醒比例
uint8_t turnover_count; // 翻身计数
uint8_t struggle_alert; // 挣扎警报
uint8_t no_one_alert; // 无人警报
uint8_t bed_status; // 床状态
uint8_t apnea_count; // 呼吸暂停次数
int heartbeat_waveform; // 心跳波形
int breathing_waveform; // 呼吸波形
} VitalData; // 生命体征数据结构体
typedef struct { // 上次发送数据结构体
float heart_rate; // 心率
float breath_rate; // 呼吸率
uint8_t presence; // 存在状态
uint8_t motion; // 运动状态
uint8_t sleep_state; // 睡眠状态
} LastSentData; // 上次发送数据结构体
class BLEFlowController { // BLE流控制器类
private:
size_t maxBytesPerSecond; // 最大每秒发送字节数
size_t bytesSent; // 已发送字节数
unsigned long lastResetTime; // 上次重置时间
unsigned long lastSendTime; // 上次发送时间
public:
BLEFlowController(size_t maxBps);
bool canSend(size_t dataSize);
bool check();
void recordSend(size_t dataSize);
void reset();
};
extern SensorData sensorData; // 传感器数据
extern HardwareSerial mySerial1; // 硬件串口1
extern QueueHandle_t phaseDataQueue; // 相位数据队列
extern QueueHandle_t vitalDataQueue; // 生命体征数据队列
extern QueueHandle_t uartQueue; // UART数据队列
extern TaskHandle_t bleSendTaskHandle; // BLE发送任务句柄
extern TaskHandle_t vitalSendTaskHandle; // 生命体征发送任务句柄
extern TaskHandle_t uartProcessTaskHandle; // UART处理任务句柄
extern BLEServer* pServer; // BLE服务器指针
extern BLECharacteristic* pCharacteristic; // BLE特征值指针
extern bool deviceConnected; // 设备连接状态
extern bool oldDeviceConnected; // 旧设备连接状态
extern String receivedData; // 接收到的数据
extern String completeData; // 完整数据
extern unsigned long lastReceiveTime; // 上次接收数据时间
extern bool continuousSendEnabled; // 持续发送使能标志
extern unsigned long continuousSendInterval; // 持续发送间隔
extern BLEFlowController bleFlow; // BLE流控制器
extern unsigned long lastSensorUpdate; // 上次传感器更新时间
extern LastSentData lastSentData; // 上次发送的数据
extern unsigned long lastCheckTime; // 上次检测时间
extern uint16_t currentDeviceId; // 当前设备ID
extern Preferences preferences; // Flash存储对象
extern WiFiManager wifiManager; // WiFi管理器
void initRadarManager();
void initR60ABD1();
bool parseR60ABD1Frame(uint8_t *frame, uint16_t frameLen);
int16_t parseSignedCoordinate(uint16_t raw_value);
void sendRadarCommand(uint8_t ctrl, uint8_t cmd, uint8_t value);
void IRAM_ATTR serialRxCallback();
void bleSendTask(void *parameter);
void vitalSendTask(void *parameter);
void radarDataTask(void *parameter);
void uartProcessTask(void *parameter);
void sendDataInChunks(const String& data);
void sendJSONDataToBLE(const String& jsonData);
bool sendCustomJSONData(const String& jsonType, const String& jsonString);
void sendRadarDataToBLE();
bool processQueryRadarData(JsonDocument& doc);
bool processStartContinuousSend(JsonDocument& doc);
bool processStopContinuousSend(JsonDocument& doc);
void processBLEConfig();
bool processSetDeviceId(JsonDocument& doc);
bool processQueryStatus(JsonDocument& doc);
bool processWiFiConfigCommand(JsonDocument& doc);
bool processScanWiFi(JsonDocument& doc);
bool processGetSavedNetworks(JsonDocument& doc);
bool processEchoRequest(JsonDocument& doc);
void sendRawEchoResponse(const String& rawData);
void sendStatusToBLE();
void loadDeviceId();
void saveDeviceId();
void sendDailyDataToInfluxDB(String dailyDataLine);
void sendSleepDataToInfluxDB();
class MyServerCallbacks: public BLEServerCallbacks {
void onConnect(BLEServer* pServer);
void onDisconnect(BLEServer* pServer);
};
class MyCallbacks: public BLECharacteristicCallbacks {
void onWrite(BLECharacteristic *pCharacteristic);
};
#endif

572
src/wifi_manager.cpp Normal file
View File

@@ -0,0 +1,572 @@
#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;
}
/**
* @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);
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() {
Serial.println("🔍 [WiFi] 开始扫描WiFi网络...");
currentState = WIFI_SCANNING;
WiFi.disconnect(true);
vTaskDelay(100 / portTICK_PERIOD_MS);
WiFi.mode(WIFI_STA);
vTaskDelay(100 / portTICK_PERIOD_MS);
int n = WiFi.scanNetworks();
Serial.printf("🔍 扫描到 %d 个WiFi网络\n", n);
if (n <= 0) {
Serial.println("❌ 未扫描到任何WiFi网络或扫描失败");
currentState = WIFI_DISCONNECTED;
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);
if (connectToNetwork(bestNetwork.ssid, bestNetwork.password)) {
return true;
}
}
Serial.println("❌ 未找到匹配的WiFi网络或信号过弱");
currentState = WIFI_DISCONNECTED;
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() {
Serial.println("📱 [BLE-WiFi] 开始WiFi扫描...");
WiFi.disconnect(true);
vTaskDelay(100 / portTICK_PERIOD_MS);
WiFi.mode(WIFI_STA);
vTaskDelay(100 / portTICK_PERIOD_MS);
int n = WiFi.scanNetworks();
Serial.printf("🔍 扫描到 %d 个WiFi网络\n", n);
if (n <= 0) {
Serial.println("❌ 未扫描到任何WiFi网络或扫描失败");
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);
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();
}

121
src/wifi_manager.h Normal file
View File

@@ -0,0 +1,121 @@
#ifndef WIFI_MANAGER_H
#define WIFI_MANAGER_H
#include <Arduino.h>
#include <WiFi.h>
#include <Preferences.h>
#include <ArduinoJson.h>
/**
* @brief 最大WiFi网络配置数量
* 定义设备可以保存的WiFi网络配置的最大数量
*/
#define MAX_WIFI_NETWORKS 10
/**
* @brief 最小信号强度阈值
* 定义WiFi网络信号强度的最低要求低于此值的网络会被过滤
* 单位dBm
*/
#define MIN_RSSI_THRESHOLD -200
/**
* @brief WiFi连接超时时间
* 定义WiFi连接的最大等待时间超过此时间认为连接失败
* 单位:毫秒
*/
#define WIFI_CONNECT_TIMEOUT 15000
/**
* @brief WiFi重连间隔时间
* 定义WiFi断开后尝试重新连接的时间间隔
* 单位:毫秒
*/
#define WIFI_RECONNECT_INTERVAL 2000
/**
* @brief WiFi网络信息结构
* 存储WiFi网络的详细信息用于扫描和显示
*/
typedef struct {
char ssid[32]; // WiFi网络名称
char password[64]; // WiFi网络密码
int rssi; // 信号强度单位dBm
uint8_t channel; // WiFi通道
uint8_t encryption; // 加密类型
} WiFiNetworkInfo;
/**
* @brief WiFi配置结构
* 存储WiFi网络的配置信息用于保存和加载
*/
typedef struct {
char ssid[32]; // WiFi网络名称
char password[64]; // WiFi网络密码
} WiFiConfig;
/**
* @brief WiFi管理器状态枚举
* 定义WiFi管理器的不同工作状态
*/
enum WiFiManagerState {
WIFI_IDLE, // 空闲状态
WIFI_SCANNING, // 扫描网络中
WIFI_CONNECTING, // 连接网络中
WIFI_CONNECTED, // 已连接
WIFI_DISCONNECTED, // 断开连接
WIFI_CONFIGURING // 配网模式
};
/**
* @brief 网络状态枚举
* 定义网络的不同状态用于LED控制
*/
enum NetworkStatus {
NET_INITIAL, // 初始化/未连接 - 慢闪
NET_CONNECTING, // 连接中 - 快闪
NET_CONNECTED, // 已连接 - 呼吸灯
NET_DISCONNECTED // 断开连接 - 慢闪
};
/**
* @brief WiFi管理器类
* 负责WiFi网络的扫描、连接、配置和管理
*/
class WiFiManager {
private:
Preferences preferences; // 用于存储WiFi配置的Preferences对象
WiFiConfig savedNetworks[MAX_WIFI_NETWORKS]; // 保存的WiFi网络配置数组
int savedNetworkCount; // 已保存的网络数量
WiFiManagerState currentState; // 当前WiFi管理器状态
unsigned long lastReconnectAttempt; // 上次尝试重连的时间
bool scanAndMatchNetworks(); // 扫描并匹配网络
bool connectToNetwork(const char* ssid, const char* password); // 连接到指定网络
void sendScanResultsViaBLE(); // 发送扫描结果到BLE
bool saveWiFiConfig(const char* ssid, const char* password); // 保存WiFi配置
bool loadWiFiConfigs(); // 加载WiFi配置
public:
WiFiManager(); // 构造函数
void begin(); // 初始化WiFi管理器
bool initializeWiFi(); // 初始化WiFi连接
bool startConfiguration(); // 开始配网模式
bool handleConfigurationData(const char* ssid, const char* password); // 处理配网数据
void handleReconnect(); // 处理重连
WiFiManagerState getState(); // 获取当前状态
bool isConnected(); // 检查是否已连接
void disconnect(); // 断开连接
void scanAndSendResults(); // 扫描并发送结果
bool addWiFiConfig(const char* ssid, const char* password); // 添加WiFi配置
void clearAllConfigs(); // 清除所有配置
int getSavedNetworkCount(); // 获取已保存的网络数量
void getSavedNetworks(); // 获取已保存的WiFi网络列表
void update(); // 更新WiFi管理器状态
};
#endif