Files
Rader_IQ/test/app.cpp

1178 lines
42 KiB
C++
Raw Normal View History

2025-12-15 09:19:47 +08:00
#include <Arduino.h>
#include <WiFi.h>
#include <esp_task_wdt.h>
#include <ArduinoJson.h>
#include <Preferences.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>
#define BUFFER_SIZE 2000 // 固定存储2000个数据点
// 环形缓冲区结构
struct CircularBuffer {
float data[BUFFER_SIZE];
unsigned long timestamps[BUFFER_SIZE]; // 存储时间戳
int head; // 最新数据位置
int tail; // 最旧数据位置
int count; // 当前有效数据数量
bool isFull; // 缓冲区是否已满
float sum; // 当前数据总和
};
CircularBuffer heartRateBuffer = {{0}, {0}, 0, 0, 0, false, 0};
// 滤波器定义
#define FILTER_SIZE 5 // 滤波器窗口大小
Preferences preferences;
// 设备ID变量
uint16_t currentDeviceId = 1001; // 默认设备ID为1001
const uint16_t MIN_DEVICE_ID = 1000; // 设备ID最小值
const uint16_t MAX_DEVICE_ID = 1999; // 设备ID最大值
const uint32_t PHASE_SEND_INTERVAL = 1;
const uint32_t VITAL_SEND_INTERVAL = 10;
#define SERVICE_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914b"
#define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8"
BLEServer* pServer = NULL;
BLECharacteristic* pCharacteristic = NULL;
bool deviceConnected = false;
bool oldDeviceConnected = false;
String receivedData = "";
String completeData = "";
unsigned long lastReceiveTime = 0;
WiFiClient client;
char ssid[32] = "13-205";
char password[64] = "12345678";
bool wifiConfigured = false;
const char* influxDBHost = "8.134.11.76";
const int influxDBPort = 8086;
const char* influxDBToken = "KuTa5ZsqoHIhi2IglOO06zExUYw1_mJ6K0mcA9X1y6O6CJDog3_Cgr8mUw1SwpuCCKRElqxa6wAhrrhsYPytkg==";
const char* influxDBOrg = "gzlg";
const char* influxDBBucket = "gzlg";
const unsigned long SENSOR_TIMEOUT = 40000;
static uint32_t packetCounter = 0;
static bool shouldSendOtherData = false;
unsigned long lastSensorUpdate = 0;
typedef struct {
float breath_rate;
float heart_rate;
int rssi;
uint8_t breath_valid;
uint8_t heart_valid;
uint8_t presence;
uint8_t motion;
int heartbeat_waveform;
int breathing_waveform;
int raw_signal;
} SensorData;
SensorData sensorData = {0};
// 呼吸率滤波相关变量定义
// 添加滤波器数组和索引(仅用于呼吸率)
float breathRateFilter[FILTER_SIZE] = {0};
int filterIndex = 0;
bool filterInitialized = false;
HardwareSerial mySerial2(2);
const int BAUD_RATE = 576000;
const int UART2_RX = 16;
const int UART2_TX = 17;
String rxBuffer = "";
// FreeRTOS任务和队列定义
QueueHandle_t phaseDataQueue;
QueueHandle_t vitalDataQueue;
TaskHandle_t bleSendTaskHandle = NULL;
TaskHandle_t vitalSendTaskHandle = NULL;
// 注意bleSendTaskHandle现在用于蓝牙发送任务
#define QUEUE_SIZE 50
#define TASK_STACK_SIZE 8192
#define TASK_PRIORITY 1
typedef struct {
int heartbeat_waveform;
int breathing_waveform;
} PhaseData;
typedef struct {
float heart_rate;
float breath_rate;
uint8_t presence;
uint8_t motion;
int rssi;
} VitalData;
// 添加流量控制类
class BLEFlowController {
private:
size_t maxBytesPerSecond;
size_t bytesSent;
unsigned long lastResetTime;
unsigned long lastSendTime;
public:
BLEFlowController(size_t maxBps) : maxBytesPerSecond(maxBps), bytesSent(0) {
lastResetTime = millis();
lastSendTime = 0;
}
bool canSend(size_t dataSize) {
unsigned long currentTime = millis();
// 每秒重置计数器
if(currentTime - lastResetTime >= 1000) {
bytesSent = 0;
lastResetTime = currentTime;
}
// 检查速率限制(放宽限制)
if((bytesSent + dataSize) > maxBytesPerSecond) {
return false;
}
// 最小发送间隔控制(重要!)
if(currentTime - lastSendTime < 5) { // 进一步减小最小间隔到5ms
return false;
}
return true;
}
bool check() {
// 这是一个简化版本的检查方法,只检查最小发送间隔
unsigned long currentTime = millis();
if(currentTime - lastSendTime < 5) { // 最小间隔5ms
return false;
}
return true;
}
void recordSend(size_t dataSize) {
bytesSent += dataSize;
lastSendTime = millis();
}
void reset() {
bytesSent = 0;
lastResetTime = millis();
lastSendTime = 0;
}
};
// 全局变量用于控制持续发送
bool continuousSendEnabled = false;
unsigned long continuousSendInterval = 1000; // 默认1秒发送一次
BLEFlowController bleFlow(500); // 提高到500 B/s限制进一步提高数据传输速率
void processBLEConfig();
void saveWiFiConfig();
void loadWiFiConfig();
bool connectWiFi();
void processRadarData();
bool parseSensorLine(String line);
void sendRadarCommand(String cmd);
void updateStatusFlags();
void loadDeviceId(); // 加载设备ID
void saveDeviceId(); // 保存设备ID
bool processSetDeviceId(JsonDocument& doc); // 处理设置设备ID命令
void sendStatusToBLE(); // 发送状态信息到BLE
bool processQueryStatus(JsonDocument& doc); // 处理查询状态命令
bool processQueryRadarData(JsonDocument& doc); // 处理查询雷达数据命令
bool processStartContinuousSend(JsonDocument& doc); // 处理开始持续发送命令
bool processStopContinuousSend(JsonDocument& doc); // 处理停止持续发送命令
void sendRadarDataToBLE(); // 发送雷达数据到BLE
void sendDataInChunks(const String& data); // 分包发送函数
float addDataAndCalculateAverage(float newData); // 计算平均值并添加新数据
// FreeRTOS任务函数声明
void bleSendTask(void *parameter);
void vitalSendTask(void *parameter);
class MyServerCallbacks: public BLEServerCallbacks {
void onConnect(BLEServer* pServer) {
deviceConnected = true;
// 注释掉这行以减少串口输出
// Serial.println("BLE客户端已连接");
// 发送连接状态信息
sendStatusToBLE();
};
void onDisconnect(BLEServer* pServer) {
deviceConnected = false;
// 注释掉这行以减少串口输出
// Serial.println("BLE客户端已断开");
// 重置持续发送状态
continuousSendEnabled = false;
// 注释掉这行以减少串口输出
// Serial.println("重置持续发送状态");
}
};
class MyCallbacks: public BLECharacteristicCallbacks {
void onWrite(BLECharacteristic *pCharacteristic) {
std::string value = pCharacteristic->getValue();
// 注释掉这行以减少串口输出
// Serial.printf("🔵 收到BLE写入数据长度: %d 字节\n", value.length());
if (value.length() > 0) {
String fragment = "";
for (int i = 0; i < value.length(); i++)
fragment += value[i];
// 注释掉这行以减少串口输出
// Serial.printf("📄 接收数据片段: %s\n", fragment.c_str());
completeData += fragment;
lastReceiveTime = millis();
// 检查是否收到完整的JSON数据
int openBrace = completeData.indexOf('{');
int closeBrace = completeData.lastIndexOf('}');
if (openBrace >= 0 && closeBrace > openBrace) {
String jsonData = completeData.substring(openBrace, closeBrace + 1);
completeData = completeData.substring(closeBrace + 1);
// 注释掉这行以减少串口输出
// Serial.printf("📥 完整JSON数据: %s\n", jsonData.c_str());
// 将JSON数据存储到receivedData变量中供后续处理
receivedData = jsonData;
}
}
}
};
void setup() {
// 启用串口通信以便观察滤波后的数据
Serial.begin(115200);
sensorData.breath_rate = 0;
sensorData.heart_rate = 0;
sensorData.rssi = 0;
sensorData.breath_valid = 0;
sensorData.heart_valid = 0;
esp_task_wdt_init(30, true);
esp_task_wdt_add(NULL);
// 增加串口缓冲区大小到4096字节以处理大量雷达数据
mySerial2.setRxBufferSize(4096);
mySerial2.begin(BAUD_RATE, SERIAL_8N1, UART2_RX, UART2_TX);
// 注释掉这行以减少串口输出
// Serial.println("UART2配置完成缓冲区大小: 4096字节");
delay(1000);
String startCmd = "{\"cmd\":\"setMonitor\",\"para\":1}\n";
mySerial2.print(startCmd);
delay(1000);
// 注释掉这行以减少串口输出
// Serial.println("启动雷达数据传输");
preferences.begin("radar_data", false);
// 加载设备ID和WiFi配置
loadDeviceId();
loadWiFiConfig();
// 创建FreeRTOS队列
phaseDataQueue = xQueueCreate(QUEUE_SIZE, sizeof(PhaseData));
vitalDataQueue = xQueueCreate(QUEUE_SIZE, sizeof(VitalData));
// bleDataQueue = xQueueCreate(QUEUE_SIZE, sizeof(BLEData)); // 移除:不再需要创建蓝牙数据队列
// 注释掉这行以减少串口输出
/*
if (phaseDataQueue == NULL || vitalDataQueue == NULL) { // 移除:不再检查蓝牙数据队列
Serial.println("❌ 队列创建失败");
} else {
Serial.println("✅ FreeRTOS队列创建成功");
}
*/
// 创建FreeRTOS任务
xTaskCreatePinnedToCore(
bleSendTask,
"BleSendTask",
TASK_STACK_SIZE,
NULL,
TASK_PRIORITY,
&bleSendTaskHandle,
1
);
xTaskCreatePinnedToCore(
vitalSendTask,
"VitalSendTask",
TASK_STACK_SIZE,
NULL,
TASK_PRIORITY,
&vitalSendTaskHandle,
1
);
// 注释掉这行以减少串口输出
// Serial.println("✅ FreeRTOS任务创建成功");
BLEDevice::init("ESP32-Radar");
pServer = BLEDevice::createServer();
pServer->setCallbacks(new MyServerCallbacks());
BLEService *pService = pServer->createService(SERVICE_UUID);
pCharacteristic = pService->createCharacteristic(
CHARACTERISTIC_UUID,
BLECharacteristic::PROPERTY_READ |
BLECharacteristic::PROPERTY_WRITE |
BLECharacteristic::PROPERTY_NOTIFY
);
pCharacteristic->setCallbacks(new MyCallbacks());
pCharacteristic->addDescriptor(new BLE2902());
pService->start();
BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();
pAdvertising->addServiceUUID(SERVICE_UUID);
pAdvertising->setScanResponse(true);
pAdvertising->setMinPreferred(0x06);
pAdvertising->setMinPreferred(0x12);
BLEDevice::startAdvertising();
// 注释掉这行以减少串口输出
// Serial.println("BLE已启动设备名称: ESP32-Radar");
if (wifiConfigured) {
// 注释掉这行以减少串口输出
// Serial.println("检测到已保存的WiFi配置尝试连接...");
if (connectWiFi()) {
// 注释掉这行以减少串口输出
// Serial.println("WiFi连接成功");
} else {
// 注释掉这行以减少串口输出
// Serial.println("WiFi连接失败请通过BLE重新配置");
wifiConfigured = false;
}
}
}
void loop() {
esp_task_wdt_reset();
if (!deviceConnected && oldDeviceConnected) {
delay(500);
pServer->startAdvertising();
// 注释掉这行以减少串口输出
// Serial.println("开始BLE广播");
oldDeviceConnected = deviceConnected;
}
if (deviceConnected && !oldDeviceConnected) {
oldDeviceConnected = deviceConnected;
}
processBLEConfig();
// 移除WiFi连接检查使雷达数据处理不依赖WiFi连接
esp_task_wdt_reset();
processRadarData();
esp_task_wdt_reset();
updateStatusFlags();
// 注意持续发送雷达数据的逻辑已移至FreeRTOS任务处理
// 主循环不再直接处理蓝牙数据发送,避免影响雷达数据接收和解析
delay(1);
}
// 处理查询状态命令
bool processQueryStatus(JsonDocument& doc) {
const char* command = doc["command"];
if (command != nullptr && strcmp(command, "queryStatus") == 0) {
// 发送设备状态信息
if (deviceConnected) {
String statusMsg = String("{\"type\":\"deviceStatus\",\"success\":true,\"deviceId\":") +
String(currentDeviceId) +
String(",\"wifiConfigured\":") +
String(wifiConfigured ? "true" : "false") +
String(",\"wifiConnected\":") +
String(WiFi.status() == WL_CONNECTED ? "true" : "false") +
String(",\"ipAddress\":\"") +
(WiFi.status() == WL_CONNECTED ? WiFi.localIP().toString() : "") +
String("\"}");
// 直接发送状态查询响应数据(不使用队列,因为这是即时响应)
pCharacteristic->setValue(statusMsg.c_str());
pCharacteristic->notify();
Serial.println("已发送设备状态信息");
}
return true;
}
return false;
}
// 处理查询雷达数据命令
bool processQueryRadarData(JsonDocument& doc) {
const char* command = doc["command"];
if (command != nullptr && strcmp(command, "queryRadarData") == 0) {
Serial.println("收到查询雷达数据命令");
// 发送最新的雷达数据
if (deviceConnected) {
String radarDataMsg = String("{\"type\":\"radarData\",\"success\":true") +
String(",\"deviceId\":") + String(currentDeviceId) +
String(",\"timestamp\":") + String(millis()) +
String(",\"presence\":") + String(sensorData.presence) +
String(",\"heartRate\":") + String(sensorData.heart_rate, 1) +
String(",\"breathRate\":") + String(sensorData.breath_rate, 1) +
String(",\"motion\":") + String(sensorData.motion) +
String(",\"rssi\":") + String(sensorData.rssi) +
String(",\"heartbeatWaveform\":") + String(sensorData.heartbeat_waveform) +
String(",\"breathingWaveform\":") + String(sensorData.breathing_waveform) +
String(",\"rawSignal\":") + String(sensorData.raw_signal) +
String("}");
// 直接发送查询响应数据(不使用队列,因为这是即时响应)
pCharacteristic->setValue(radarDataMsg.c_str());
pCharacteristic->notify();
Serial.println("已发送雷达数据");
Serial.printf("发送的数据: %s\n", radarDataMsg.c_str());
} else {
Serial.println("BLE未连接无法发送雷达数据");
}
return true;
}
return false;
}
// 处理开始持续发送命令
bool processStartContinuousSend(JsonDocument& doc) {
const char* command = doc["command"];
if (command != nullptr && strcmp(command, "startContinuousSend") == 0) {
// 获取发送间隔参数可选默认1000ms
if (doc.containsKey("interval")) {
continuousSendInterval = doc["interval"];
// 限制最小间隔为100ms最大间隔为10000ms
if (continuousSendInterval < 100) continuousSendInterval = 100;
if (continuousSendInterval > 10000) continuousSendInterval = 10000;
}
continuousSendEnabled = true;
bleFlow.reset(); // 重置流量控制器
Serial.printf("⚙️ 启动持续发送模式,间隔: %lu ms\n", continuousSendInterval);
// 发送清晰格式的确认消息
if (deviceConnected) {
String confirmMsg = String("[START]Interval:") + String(continuousSendInterval);
// 直接发送确认消息
pCharacteristic->setValue(confirmMsg.c_str());
pCharacteristic->notify();
Serial.println("✅ 启动确认消息发送成功");
delay(5); // 减少延迟以提高实时性
Serial.println("🚀 已启动持续发送模式");
} else {
Serial.println("❌ BLE未连接无法发送确认消息");
}
return true;
}
return false;
}
// 处理停止持续发送命令
bool processStopContinuousSend(JsonDocument& doc) {
const char* command = doc["command"];
if (command != nullptr && strcmp(command, "stopContinuousSend") == 0) {
continuousSendEnabled = false;
Serial.println("🛑 停止持续发送模式");
// 发送清晰格式的确认消息
if (deviceConnected) {
String confirmMsg = String("[STOP]ContinuousSend");
// 直接发送确认消息
pCharacteristic->setValue(confirmMsg.c_str());
pCharacteristic->notify();
Serial.println("✅ 停止确认消息发送成功");
delay(5); // 减少延迟以提高实时性
Serial.println("⏹️ 已停止持续发送模式");
} else {
Serial.println("❌ BLE未连接无法发送确认消息");
}
return true;
}
return false;
}
// 分包发送函数 - 优化版本,解决分包混乱和数据截断问题
void sendDataInChunks(const String& data) {
const int MAX_PACKET_SIZE = 20; // BLE最大包大小
const int HEADER_SIZE = 6; // 包头大小 "[N/M]"
const int CHUNK_SIZE = MAX_PACKET_SIZE - HEADER_SIZE; // 实际数据大小
int totalLength = data.length();
int numChunks = (totalLength + CHUNK_SIZE - 1) / CHUNK_SIZE;
// 只有在数据较长需要分包时才显示分包信息
// 注释掉这行以减少串口输出
// Serial.printf("📦 开始分包发送,总长度: %d, 分包数: %d\n", totalLength, numChunks);
for(int i = 0; i < numChunks; i++) {
int start = i * CHUNK_SIZE;
int chunkLength = min(CHUNK_SIZE, totalLength - start);
String chunk = data.substring(start, start + chunkLength);
// 构造简单包头: "[序号/总数]"确保总长度不超过6字符
// 例如: "[1/5]" = 4字符
String packetHeader = String("[") + String(i+1) + String("/") + String(numChunks) + String("]");
// 确保总包大小不超过20字节
int maxDataLength = MAX_PACKET_SIZE - packetHeader.length();
if (chunk.length() > maxDataLength) {
chunk = chunk.substring(0, maxDataLength);
}
String packet = packetHeader + chunk;
// 注释掉这行以减少串口输出
// Serial.printf("📤 发送分包 %s: %s\n", packetHeader.c_str(), chunk.c_str());
// 检查BLE连接状态
if (!deviceConnected) {
// 注释掉这行以减少串口输出
// Serial.println("❌ BLE未连接无法发送数据");
return;
}
// 发送数据包
pCharacteristic->setValue(packet.c_str());
pCharacteristic->notify();
// 注释掉这行以减少串口输出
// Serial.println("✅ 分包发送成功");
// 等待一段时间确保接收端处理完成,避免数据丢失
if (i < numChunks - 1) {
// 注释掉这行以减少串口输出
// Serial.printf("⏳ 等待接收端处理第%d个包...\n", i+1);
delay(20); // 进一步减少等待时间以提高实时性
}
}
// 注释掉这行以减少串口输出
// Serial.println("📦 分包发送完成");
}
// 发送雷达数据到BLE已移至FreeRTOS任务处理
void sendRadarDataToBLE() {
// 此函数已废弃雷达数据发送现在由FreeRTOS任务处理
// 保留此函数以防其他代码引用
Serial.println(" 雷达数据发送已移至FreeRTOS任务处理");
}
// 处理BLE配置和命令
void processBLEConfig() {
// 增强超时处理机制
if (completeData.length() > 0 && (millis() - lastReceiveTime > 3000)) {
completeData = "";
}
if (receivedData.length() > 0) {
String bleData = receivedData;
receivedData = "";
bleData.trim();
if (bleData.startsWith("{") && bleData.endsWith("}")) {
JsonDocument doc;
DeserializationError error = deserializeJson(doc, bleData);
if (error) {
if (deviceConnected) {
String responseMsg = String("{\"type\":\"error\",\"message\":\"配置格式错误请使用JSON格式\"}");
// 使用分包发送函数发送错误消息
sendDataInChunks(responseMsg);
}
} else {
// 处理各种命令
bool processed = false;
// 处理设置设备ID命令
if (!processed) processed = processSetDeviceId(doc);
// 处理查询状态命令
if (!processed) processed = processQueryStatus(doc);
// 处理开始持续发送命令
if (!processed) processed = processStartContinuousSend(doc);
// 处理停止持续发送命令
if (!processed) processed = processStopContinuousSend(doc);
// 如果没有处理任何命令,发送错误响应
if (!processed) {
if (deviceConnected) {
String responseMsg = String("{\"type\":\"error\",\"message\":\"未知命令\"}");
// 使用分包发送函数发送错误消息
sendDataInChunks(responseMsg);
}
}
}
} else {
}
}
}
void processRadarData() {
static unsigned long lastDataTime = 0;
static unsigned long noDataWarningTime = 0;
static uint32_t totalLinesReceived = 0;
static uint32_t validLinesReceived = 0;
static uint32_t phasePacketCounter = 0;
static uint32_t vitalPacketCounter = 0;
static bool processingData = false;
if (processingData) {
return;
}
int available = mySerial2.available();
if (available > 0) {
processingData = true;
lastDataTime = millis();
bool lineProcessed = false;
while (mySerial2.available() > 0 && !lineProcessed) {
char c = mySerial2.read();
rxBuffer += c;
// 增加缓冲区大小检查,防止溢出
if (rxBuffer.length() > 1000) {
rxBuffer = "";
}
if (c == '\n' || c == '\r') {
if (rxBuffer.length() > 0) {
totalLinesReceived++;
bool parseResult = parseSensorLine(rxBuffer);
if (parseResult) {
validLinesReceived++;
// 更新全局传感器数据
lastSensorUpdate = millis();
// 使用FreeRTOS队列发送数据到任务
phasePacketCounter++;
if (phasePacketCounter >= PHASE_SEND_INTERVAL) {
PhaseData phaseData;
phaseData.heartbeat_waveform = sensorData.heartbeat_waveform;
phaseData.breathing_waveform = sensorData.breathing_waveform;
if (xQueueSend(phaseDataQueue, &phaseData, 0) == pdTRUE) {
} else {
}
phasePacketCounter = 0;
}
vitalPacketCounter++;
if (vitalPacketCounter >= VITAL_SEND_INTERVAL) {
VitalData vitalData;
vitalData.heart_rate = sensorData.heart_rate;
vitalData.breath_rate = sensorData.breath_rate;
vitalData.presence = sensorData.presence;
vitalData.motion = sensorData.motion;
vitalData.rssi = sensorData.rssi;
if (xQueueSend(vitalDataQueue, &vitalData, 0) == pdTRUE) {
} else {
}
vitalPacketCounter = 0;
}
} else {
}
rxBuffer = "";
lineProcessed = true;
}
}
esp_task_wdt_reset();
}
if (!lineProcessed && available > 0) {
}
processingData = false;
} else {
if (millis() - lastDataTime > 5000 && millis() - noDataWarningTime > 5000) {
noDataWarningTime = millis();
}
}
}
// FreeRTOS任务蓝牙数据发送精简格式以节省空间
void bleSendTask(void *parameter) {
while (1) {
PhaseData phaseData;
// 从队列接收相位数据用于蓝牙发送
if (xQueueReceive(phaseDataQueue, &phaseData, portMAX_DELAY) == pdTRUE) {
esp_task_wdt_reset();
// 蓝牙传输 - 构造并发送完整的雷达数据包含所有7个字段无标识符以节省空间
if (deviceConnected && continuousSendEnabled) {
// 构造完整雷达数据格式(去掉"radar"标识以节省空间)
// 格式: "heartRate|breathRate|heartbeatWaveform|breathingWaveform|presence|motion|rssi|checksum"
String radarDataCore = String(sensorData.heart_rate, 1) + String("|") +
String(sensorData.breath_rate, 1) + String("|") +
String(phaseData.heartbeat_waveform) + String("|") +
String(phaseData.breathing_waveform) + String("|") +
String(sensorData.presence) + String("|") +
String(sensorData.motion) + String("|") +
String(sensorData.rssi);
// 计算CRC校验和
unsigned int crc = 0xFFFF;
for (int i = 0; i < radarDataCore.length(); i++) {
crc ^= (unsigned int)radarDataCore.charAt(i);
for (int j = 0; j < 8; j++) {
if (crc & 0x0001) {
crc >>= 1;
crc ^= 0xA001;
} else {
crc >>= 1;
}
}
}
// 添加校验和到数据末尾
String radarDataMsg = radarDataCore + String("|") + String(crc, HEX);
// 注释掉这行以减少串口输出
// Serial.printf("📤 通过蓝牙发送完整雷达数据: %s\n", radarDataMsg.c_str());
// 检查数据长度决定发送方式
const int MAX_BLE_PACKET_SIZE = 20; // BLE最大包大小
if (radarDataMsg.length() <= MAX_BLE_PACKET_SIZE) {
// 数据较短,直接发送
pCharacteristic->setValue(radarDataMsg.c_str());
pCharacteristic->notify();
// 注释掉这行以减少串口输出
// Serial.println("✅ 完整雷达数据蓝牙发送成功");
} else {
// 数据较长,使用分包发送
// 注释掉这行以减少串口输出
// Serial.println("🔄 雷达数据较长,使用分包发送");
sendDataInChunks(radarDataMsg);
}
}
esp_task_wdt_reset();
}
vTaskDelay(1 / portTICK_PERIOD_MS); // 减少延迟以提高实时性
}
}
// FreeRTOS任务发送生命体征数据
void vitalSendTask(void *parameter) {
while (1) {
VitalData vitalData;
// 从队列接收生命体征数据用于WiFi数据库发送
if (xQueueReceive(vitalDataQueue, &vitalData, portMAX_DELAY) == pdTRUE) {
esp_task_wdt_reset();
// WiFi数据库传输 - 一直发送生命体征数据(不通过蓝牙)
if (WiFi.status() == WL_CONNECTED) {
HTTPClient http;
http.setTimeout(2000);
String url = String("http://") + String(influxDBHost) + ":" + String(influxDBPort) + "/api/v2/write?org=" + String(influxDBOrg) + "&bucket=" + String(influxDBBucket) + "&precision=ns";
http.begin(url);
http.addHeader("Authorization", String("Token ") + String(influxDBToken));
http.addHeader("Content-Type", "text/plain");
http.setReuse(true);
// 使用可变的设备ID
String deviceId = String(currentDeviceId);
String vitalDataStr = "";
bool firstField = true;
// 心率数据 - 使用浮点数格式
if (vitalData.heart_rate > 0) {
if (!firstField) vitalDataStr += ",";
vitalDataStr += "heartRate=";
vitalDataStr += String(vitalData.heart_rate / 1.0, 1);
firstField = false;
}
// 呼吸率数据 - 使用浮点数格式
if (vitalData.breath_rate > 0) {
if (!firstField) vitalDataStr += ",";
vitalDataStr += "breathingRate=";
vitalDataStr += String(vitalData.breath_rate / 1.0, 1);
firstField = false;
}
// 人检数据 - 确保值为0或1使用整数格式
if (true) { // 总是发送人检数据
if (!firstField) vitalDataStr += ",";
vitalDataStr += "personDetected=";
// 确保值为0或1
int presenceValue = (vitalData.presence > 0) ? 1 : 0;
vitalDataStr += String(presenceValue) + "i"; // 整数格式
firstField = false;
}
// 人体活动数据 - 确保值为0或1使用整数格式
if (true) { // 总是发送人体活动数据
if (!firstField) vitalDataStr += ",";
vitalDataStr += "humanActivity=";
// 确保值为0或1
int motionValue = (vitalData.motion > 0) ? 1 : 0;
vitalDataStr += String(motionValue) + "i"; // 整数格式
firstField = false;
}
// RSSI数据 - 使用整数格式
if (vitalData.rssi != 0) {
if (!firstField) vitalDataStr += ",";
vitalDataStr += "rssi=";
vitalDataStr += String(vitalData.rssi) + "i"; // 整数格式
firstField = false;
}
// 如果有数据要发送,则构造完整的行协议字符串
if (vitalDataStr.length() > 0) {
vitalDataStr = "device_data,deviceId=" + deviceId + " " + vitalDataStr;
//Serial.println("📤 发送生命体征数据到数据库: " + vitalDataStr);
int httpResponseCode = http.POST(vitalDataStr);
if (httpResponseCode == 204) {
//Serial.println("✅ 生命体征数据发送到数据库成功");
} else {
String errorMsg = String("❌ 生命体征数据发送到数据库失败: ") + String(httpResponseCode);
Serial.println(errorMsg);
}
}
http.end();
} else {
Serial.println("❌ WiFi未连接无法发送生命体征数据到数据库");
}
esp_task_wdt_reset();
}
vTaskDelay(5 / portTICK_PERIOD_MS);
}
}
void updateStatusFlags() {
static unsigned long lastStatusUpdate = 0;
}
bool parseSensorLine(String line) {
if (!line.startsWith("HBR01")) {
// 注释掉这行以减少串口输出
// Serial.println("❌ 数据行不以HBR01开头");
return false;
}
int colonIndex = line.indexOf(':');
if (colonIndex == -1) {
// 注释掉这行以减少串口输出
// Serial.println("❌ 数据行缺少冒号分隔符");
return false;
}
String dataPart = line.substring(colonIndex + 1);
dataPart.trim();
// 注释掉这行以减少串口输出
// Serial.printf("🔍 解析数据部分: %s\n", dataPart.c_str());
int values[8];
int startIndex = 0;
int commaIndex;
int fieldCount = 0;
for (int i = 0; i < 8; i++) {
commaIndex = dataPart.indexOf(',', startIndex);
if (commaIndex == -1 && i == 7) {
String valueStr = dataPart.substring(startIndex);
valueStr.trim();
values[i] = valueStr.toInt();
fieldCount++;
// 注释掉这行以减少串口输出
// Serial.printf(" 字段%d: %s -> %d\n", i+1, valueStr.c_str(), values[i]);
} else if (commaIndex != -1) {
String valueStr = dataPart.substring(startIndex, commaIndex);
valueStr.trim();
values[i] = valueStr.toInt();
startIndex = commaIndex + 1;
fieldCount++;
// 注释掉这行以减少串口输出
// Serial.printf(" 字段%d: %s -> %d\n", i+1, valueStr.c_str(), values[i]);
} else {
// 注释掉这行以减少串口输出
// Serial.printf("❌ 解析错误: 字段%d缺失总共找到%d个字段\n", i+1, fieldCount);
return false;
}
}
sensorData.presence = values[0];
sensorData.heart_rate = (float)values[1];
sensorData.breath_rate = (float)values[2];
sensorData.motion = values[3];
sensorData.rssi = values[4];
sensorData.heartbeat_waveform = values[5];
sensorData.breathing_waveform = values[6];
sensorData.raw_signal = values[7];
sensorData.heart_valid = (sensorData.heart_rate > 0 && sensorData.heart_rate < 200);
sensorData.breath_valid = (sensorData.breath_rate >= 0.1f && sensorData.breath_rate <= 60.0f);
// 只有在检测到人的情况下才进行心率滤波处理
if (sensorData.presence > 0) {
sensorData.heart_rate = addDataAndCalculateAverage(sensorData.heart_rate);
}
// 只有在检测到人的情况下才进行呼吸率滤波处理
if (sensorData.presence > 0) {
// 对呼吸率继续使用原有的移动平均滤波器
breathRateFilter[filterIndex] = sensorData.breath_rate;
// 计算滤波后的呼吸率值(移动平均)
float filteredBreathRate = 0;
int count = filterInitialized ? FILTER_SIZE : (filterIndex + 1);
for (int i = 0; i < count; i++) {
filteredBreathRate += breathRateFilter[i];
}
filteredBreathRate /= count;
// 更新滤波器索引
filterIndex = (filterIndex + 1) % FILTER_SIZE;
if (filterIndex == 0) {
filterInitialized = true;
}
// 使用滤波后的呼吸率值
sensorData.breath_rate = filteredBreathRate;
}
lastSensorUpdate = millis();
// 按照指定格式输出心率和呼吸率的原始数据
Serial.printf("Heart_Rate_RAW:%.2f\n", sensorData.heart_rate);
Serial.printf("Breath_Rate_RAW:%.2f\n", sensorData.breath_rate);
/*
// 注释掉原来的详细输出
Serial.printf("✅ 解析成功: 有人=%d, 心率=%.1f, 呼吸=%.1f, 运动=%d, 波形=%d/%d\n",
sensorData.presence, sensorData.heart_rate,
sensorData.breath_rate, sensorData.motion,
sensorData.heartbeat_waveform, sensorData.breathing_waveform);
*/
return true;
}
void saveWiFiConfig() {
preferences.putString("ssid", ssid);
preferences.putString("password", password);
preferences.putBool("configured", true);
Serial.println("WiFi配置已保存到Flash");
}
void loadWiFiConfig() {
wifiConfigured = preferences.getBool("configured", false);
if (wifiConfigured) {
preferences.getString("ssid", ssid, sizeof(ssid));
preferences.getString("password", password, sizeof(password));
Serial.printf("从Flash加载WiFi配置 - SSID: %s\n", ssid);
}
}
bool connectWiFi() {
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
Serial.println("[WiFi] 正在尝试连接...");
int attempts = 0;
while (WiFi.status() != WL_CONNECTED && attempts < 20) {
delay(500);
Serial.printf("[WiFi] 尝试连接中,当前状态: %d\n", WiFi.status());
attempts++;
}
if (WiFi.status() == WL_CONNECTED) {
Serial.println("[WiFi] 连接成功!");
Serial.printf("[WiFi] 分配的IP地址: %s\n", WiFi.localIP().toString().c_str());
return true;
} else {
Serial.println("[WiFi] 连接超时未能成功连接到WiFi。");
Serial.printf("[WiFi] 最终状态码: %d\n", WiFi.status());
return false;
}
}
void sendRadarCommand(String cmd) {
if (!cmd.endsWith("\n")) {
cmd += "\n";
}
mySerial2.print(cmd);
Serial.println("📤 [雷达命令] " + cmd);
}
// 处理设置设备ID命令
bool processSetDeviceId(JsonDocument& doc) {
const char* command = doc["command"];
if (command != nullptr && strcmp(command, "setDeviceId") == 0) {
// 处理设置设备ID的命令
uint16_t newDeviceId = doc["newDeviceId"];
// 验证设备ID范围
if (newDeviceId < MIN_DEVICE_ID || newDeviceId > MAX_DEVICE_ID) {
Serial.printf("[错误] 设备ID超出范围有效范围: %d-%d\n", MIN_DEVICE_ID, MAX_DEVICE_ID);
if (deviceConnected) {
String errorMsg = String("{\"type\":\"error\",\"message\":\"设备ID超出范围有效范围: ") +
String(MIN_DEVICE_ID) + "-" + String(MAX_DEVICE_ID) + "\"}";
// 直接发送错误响应数据
pCharacteristic->setValue(errorMsg.c_str());
pCharacteristic->notify();
}
return true; // 已处理该命令
}
currentDeviceId = newDeviceId;
Serial.printf("[设备ID] 已设置新的设备ID: %u\n", currentDeviceId);
// 保存设备ID到Preferences
saveDeviceId();
// 发送确认消息
if (deviceConnected) {
String confirmMsg = String("{\"type\":\"setDeviceIdResult\",\"success\":true,\"message\":\"设备ID设置成功\",\"newDeviceId\":") +
String(newDeviceId) + "}";
// 直接发送设置设备ID响应数据
pCharacteristic->setValue(confirmMsg.c_str());
pCharacteristic->notify();
// 发送更新后的状态信息
sendStatusToBLE();
}
return true;
}
return false;
}
// 加载设备ID
void loadDeviceId() {
currentDeviceId = preferences.getUShort("deviceId", 1001);
Serial.printf("从Flash加载设备ID: %u\n", currentDeviceId);
}
// 保存设备ID
void saveDeviceId() {
preferences.putUShort("deviceId", currentDeviceId);
Serial.printf("设备ID已保存到Flash: %u\n", currentDeviceId);
}
// 发送状态信息到BLE
void sendStatusToBLE() {
if (deviceConnected) {
String statusMsg = String("{\"type\":\"status\",\"wifiConfigured\":") +
String(wifiConfigured ? "true" : "false") +
String(",\"wifiConnected\":") +
String(WiFi.status() == WL_CONNECTED ? "true" : "false") +
String(",\"ipAddress\":\"") +
(WiFi.status() == WL_CONNECTED ? WiFi.localIP().toString() : "") + "\"" +
String(",\"deviceId\":") +
String(currentDeviceId) + "}";
// 直接发送状态信息数据
pCharacteristic->setValue(statusMsg.c_str());
pCharacteristic->notify();
Serial.println("已发送连接状态信息");
}
}
float addDataAndCalculateAverage(float newData) {
// 只有在检测到人的情况下才进行滤波处理
if (sensorData.presence == 0) {
return newData; // 没有检测到人时,直接返回原始数据
}
unsigned long currentTime = millis();
unsigned long oneMinuteAgo = currentTime - 60000; // 一分钟前的时间
// 移除过期的旧数据(一分钟前的数据)
while (heartRateBuffer.count > 0 && heartRateBuffer.timestamps[heartRateBuffer.tail] < oneMinuteAgo) {
heartRateBuffer.sum -= heartRateBuffer.data[heartRateBuffer.tail];
heartRateBuffer.tail = (heartRateBuffer.tail + 1) % BUFFER_SIZE;
heartRateBuffer.count--;
heartRateBuffer.isFull = (heartRateBuffer.count == BUFFER_SIZE);
}
// 添加新数据
if (heartRateBuffer.count < BUFFER_SIZE) {
// 缓冲区未满,直接添加
heartRateBuffer.head = (heartRateBuffer.head + 1) % BUFFER_SIZE;
if (heartRateBuffer.count == 0) heartRateBuffer.tail = heartRateBuffer.head;
heartRateBuffer.data[heartRateBuffer.head] = newData;
heartRateBuffer.timestamps[heartRateBuffer.head] = currentTime;
heartRateBuffer.sum += newData;
heartRateBuffer.count++;
heartRateBuffer.isFull = (heartRateBuffer.count == BUFFER_SIZE);
} else {
// 缓冲区已满,替换最旧数据
heartRateBuffer.sum -= heartRateBuffer.data[heartRateBuffer.tail]; // 移除最旧数据
heartRateBuffer.tail = (heartRateBuffer.tail + 1) % BUFFER_SIZE; // 移动尾指针
heartRateBuffer.head = (heartRateBuffer.head + 1) % BUFFER_SIZE; // 移动头指针
heartRateBuffer.data[heartRateBuffer.head] = newData; // 存储新数据
heartRateBuffer.timestamps[heartRateBuffer.head] = currentTime;
heartRateBuffer.sum += newData; // 添加新数据到总和
}
// 计算并返回平均值
if (heartRateBuffer.count > 0) {
return heartRateBuffer.sum / heartRateBuffer.count;
} else {
return 0;
}
}