feat: 按钮去抖+配网界面美化+水浸离线+LED独立任务+报警全拓展(人身优先)+有人才检测

This commit is contained in:
yangzhijia
2026-07-31 15:58:09 +08:00
parent 49e3abbb34
commit 69e927c5f0
16 changed files with 1352 additions and 549 deletions

View File

@@ -1,13 +1,43 @@
/**
* @file alarm_manager.cpp
* @brief 报警管理器 - 双模式实现
* @brief 报警管理器 - 多类型分优先级实现
*
* 本地: 跌倒/水浸/心率异常/呼吸异常 → 立即蜂鸣器+LED
* 服务端: cmd/alarm, cmd/alarm/restore → 执行联动 + 回复响应
* 蜂鸣模式 (人身安全 > 环境 > 设备):
* 跌倒: 连速哔 (60ms/60ms) — 最急 ★★★★★
* 心率/呼吸: 5连急哔 (80ms/80ms) — 次急 ★★★★★
* 水浸: 3连哔 (120ms/100ms) — 中等 ★★★
* 温湿度: 2声长停 (200ms/400ms) — 温和 ★★
* 传感器: 单声长哔 (300ms/3s) — 提示 ★
*/
#include "alarm_manager.h"
// ============================================================
// 优先级定义 — 人身安全 > 环境安全 > 设备故障
// ============================================================
uint8_t AlarmManager::_priority(AlarmType t) {
switch (t) {
// ★★★★★ 人身安全 — 直接威胁生命
case ALARM_FALL: return 0;
case ALARM_HEART_ABNORMAL: return 1;
case ALARM_BREATH_ABNORMAL: return 1;
// ★★★ 环境安全 — 潜在危险
case ALARM_WATER_LEAK: return 2;
// ★★ 环境舒适 — 非紧急
case ALARM_TEMP_ABNORMAL: return 3;
case ALARM_HUMI_ABNORMAL: return 3;
// ★ 设备状态 — 仅提示
case ALARM_SENSOR_FAULT: return 4;
case ALARM_SERVER: return 5;
default: return 9;
}
}
// ============================================================
// 构造 & 析构
// ============================================================
AlarmManager::AlarmManager()
: _buzzerOn(false)
, _ledOn(false)
@@ -15,10 +45,16 @@ AlarmManager::AlarmManager()
, _buzzerToggleTime(0)
, _buzzerBeepState(false)
, _beepCount(0)
, _beepsPerCycle(3)
, _beepOnMs(150)
, _beepOffMs(100)
, _cyclePauseMs(600)
, _activeCount(0)
, _lastLEDToggle(0)
, _alarmCb(nullptr)
{
for (int i = 0; i < 4; i++) _activeAlarms[i] = ALARM_NONE;
for (uint8_t i = 0; i < MAX_ACTIVE; i++) _activeAlarms[i] = ALARM_NONE;
memset(_activeDetail, 0, sizeof(_activeDetail));
}
AlarmManager::~AlarmManager() {}
@@ -30,16 +66,12 @@ AlarmManager::~AlarmManager() {}
bool AlarmManager::begin() {
ledcSetup(BUZZER_PWM_CHANNEL, BUZZER_PWM_FREQ, BUZZER_PWM_RESOLUTION);
ledcAttachPin(BUZZER_PIN, BUZZER_PWM_CHANNEL);
ledcWrite(BUZZER_PWM_CHANNEL, 0); // 关
ledcWrite(BUZZER_PWM_CHANNEL, 0);
pinMode(LED_ALARM_PIN, OUTPUT);
digitalWrite(LED_ALARM_PIN, LOW);
_buzzerToggleTime = 0;
_buzzerBeepState = false;
_beepCount = 0;
Serial.println(F("[告警] ✅ 双模式报警 (本地+服务端)"));
Serial.println(F("[告警] ✅ 多类型分优先级报警就绪 (7种类型)"));
return true;
}
@@ -53,33 +85,129 @@ void AlarmManager::loop() {
}
// ============================================================
// 本地报警触发 (离线可用)
// 报警名称映射
// ============================================================
void AlarmManager::triggerLocal(AlarmType type) {
const char* AlarmManager::getAlarmName(AlarmType type) const {
switch (type) {
case ALARM_FALL: return "跌倒";
case ALARM_WATER_LEAK: return "水浸";
case ALARM_HEART_ABNORMAL: return "心率异常";
case ALARM_BREATH_ABNORMAL: return "呼吸异常";
case ALARM_TEMP_ABNORMAL: return "温度异常";
case ALARM_HUMI_ABNORMAL: return "湿度异常";
case ALARM_SENSOR_FAULT: return "传感器故障";
case ALARM_SERVER: return "云端指令";
default: return "未知";
}
}
// ============================================================
// 最高优先级报警
// ============================================================
AlarmManager::AlarmType AlarmManager::getHighestAlarm() const {
if (_activeCount == 0) return ALARM_NONE;
AlarmType best = ALARM_NONE;
uint8_t bestP = 99;
for (uint8_t i = 0; i < _activeCount; i++) {
uint8_t p = _priority(_activeAlarms[i]);
if (p < bestP) { bestP = p; best = _activeAlarms[i]; }
}
return best;
}
const char* AlarmManager::getActiveAlarmStr() const {
AlarmType t = getHighestAlarm();
if (t == ALARM_NONE) return "";
return getAlarmName(t);
}
// ============================================================
// 蜂鸣参数表 (按最高优先级报警驱动)
// ============================================================
uint32_t AlarmManager::_buzzerIntervalFor(AlarmType type) {
switch (type) {
case ALARM_FALL: return 200; // LED 快闪
case ALARM_WATER_LEAK: return 300;
case ALARM_HEART_ABNORMAL: return 500;
case ALARM_BREATH_ABNORMAL: return 500;
case ALARM_TEMP_ABNORMAL: return 800;
case ALARM_HUMI_ABNORMAL: return 800;
case ALARM_SENSOR_FAULT: return 1000;
default: return 500;
}
}
// ============================================================
// 更新蜂鸣参数 (根据当前最高优先级报警)
// ============================================================
static void _calcBuzzerParams(AlarmManager::AlarmType t,
uint8_t& beeps, uint32_t& onMs,
uint32_t& offMs, uint32_t& pauseMs) {
switch (t) {
// 人身安全 — 连速急哔 (最刺耳)
case AlarmManager::ALARM_FALL:
beeps = 0; onMs = 60; offMs = 60; pauseMs = 0; // 跌倒: 连速哔
break;
case AlarmManager::ALARM_HEART_ABNORMAL:
case AlarmManager::ALARM_BREATH_ABNORMAL:
beeps = 5; onMs = 80; offMs = 80; pauseMs = 400; // 心率/呼吸: 5连急哔
break;
// 环境安全 — 次急
case AlarmManager::ALARM_WATER_LEAK:
beeps = 3; onMs = 120; offMs = 100; pauseMs = 500; // 水浸: 3连哔
break;
// 环境舒适 — 温和
case AlarmManager::ALARM_TEMP_ABNORMAL:
case AlarmManager::ALARM_HUMI_ABNORMAL:
beeps = 2; onMs = 200; offMs = 400; pauseMs = 1200; // 温湿度: 2声长停
break;
// 设备状态 — 仅提示
case AlarmManager::ALARM_SENSOR_FAULT:
beeps = 1; onMs = 300; offMs = 3000; pauseMs = 0; // 传感器: 单声提醒
break;
default:
beeps = 0; onMs = 500; offMs = 500; pauseMs = 0; // 持续
break;
}
}
// ============================================================
// 本地报警触发
// ============================================================
void AlarmManager::triggerLocal(AlarmType type, const char* detail) {
// 去重
for (uint8_t i = 0; i < _activeCount; i++) {
if (_activeAlarms[i] == type) return;
}
if (_activeCount < 4) {
if (_activeCount < MAX_ACTIVE) {
_activeAlarms[_activeCount++] = type;
}
const char* name = "";
switch (type) {
case ALARM_FALL: name = "跌倒"; break;
case ALARM_WATER_LEAK: name = "水浸"; break;
case ALARM_HEART_ABNORMAL: name = "心率异常"; break;
case ALARM_BREATH_ABNORMAL: name = "呼吸异常"; break;
default: name = "未知"; break;
const char* name = getAlarmName(type);
Serial.printf("[告警] 🚨 触发: %s (活动:%d)", name, _activeCount);
if (detail && detail[0]) Serial.printf(" | %s", detail);
Serial.println();
// 更新蜂鸣参数 (按最高优先级)
AlarmType highest = getHighestAlarm();
_calcBuzzerParams(highest, _beepsPerCycle, _beepOnMs, _beepOffMs, _cyclePauseMs);
// 保存详情
if (detail) {
strncpy(_activeDetail, detail, sizeof(_activeDetail) - 1);
}
Serial.printf("[告警] 🚨 本地报警触发: %s (活动报警:%d)\n", name, _activeCount);
// 立即开启蜂鸣器和 LED
_setBuzzer(true);
_setLED(true);
// 通知外部
if (_alarmCb) _alarmCb((uint8_t)type, true, detail ? detail : name);
}
void AlarmManager::clearLocal(AlarmType type) {
@@ -94,21 +222,29 @@ void AlarmManager::clearLocal(AlarmType type) {
}
}
Serial.printf("[告警] 本地报警清除, 剩余活动:%d\n", _activeCount);
const char* name = getAlarmName(type);
Serial.printf("[告警] ✅ 清除: %s (剩余:%d)\n", name, _activeCount);
// 没有活动报警时关闭
if (_activeCount == 0) {
_setBuzzer(false);
_setLED(false);
_activeDetail[0] = '\0';
} else {
// 降级到次高优先级报警的蜂鸣参数
AlarmType highest = getHighestAlarm();
_calcBuzzerParams(highest, _beepsPerCycle, _beepOnMs, _beepOffMs, _cyclePauseMs);
}
if (_alarmCb) _alarmCb((uint8_t)type, false, name);
}
void AlarmManager::clearAllLocal() {
_activeCount = 0;
for (int i = 0; i < 4; i++) _activeAlarms[i] = ALARM_NONE;
for (uint8_t i = 0; i < MAX_ACTIVE; i++) _activeAlarms[i] = ALARM_NONE;
_activeDetail[0] = '\0';
_setBuzzer(false);
_setLED(false);
Serial.println(F("[告警] 清除所有本地报警"));
Serial.println(F("[告警] 清除所有报警"));
}
// ============================================================
@@ -116,16 +252,15 @@ void AlarmManager::clearAllLocal() {
// ============================================================
void AlarmManager::executeAlarm(const AlarmCommand& cmd) {
Serial.printf("[告警] ☁️ 服务端告警: %s (等级=%s, 蜂鸣=%d)\n",
Serial.printf("[告警] ☁️ 服务端: %s (等级=%s 蜂鸣=%d)\n",
cmd.alarmType, cmd.alarmLevel, cmd.buzzerOn);
// 映射 alarmType 到本地类型
AlarmType localType = ALARM_SERVER;
if (strcmp(cmd.alarmType, "fall") == 0) localType = ALARM_FALL;
else if (strcmp(cmd.alarmType, "water_leak") == 0) localType = ALARM_WATER_LEAK;
if (cmd.buzzerOn) {
triggerLocal(localType);
triggerLocal(localType, cmd.alarmDesc);
if (cmd.buzzerDuration > 0) {
_buzzerOffTime = millis() + (uint32_t)cmd.buzzerDuration * 1000;
} else {
@@ -138,12 +273,8 @@ void AlarmManager::executeAlarm(const AlarmCommand& cmd) {
}
}
// ============================================================
// 服务端恢复指令 (§5.2)
// ============================================================
void AlarmManager::executeRestore(const AlarmCommand& cmd) {
Serial.printf("[告警] ☁️ 服务端恢复: %s\n", cmd.alarmType);
Serial.printf("[告警] ☁️ 恢复: %s\n", cmd.alarmType);
AlarmType localType = ALARM_SERVER;
if (strcmp(cmd.alarmType, "fall") == 0) localType = ALARM_FALL;
@@ -151,12 +282,8 @@ void AlarmManager::executeRestore(const AlarmCommand& cmd) {
clearLocal(localType);
if (!cmd.buzzerOn) {
_setBuzzer(false);
}
if (!cmd.nightLight) {
_setLED(false);
}
if (!cmd.buzzerOn) _setBuzzer(false);
if (!cmd.nightLight) _setLED(false);
}
// ============================================================
@@ -164,27 +291,11 @@ void AlarmManager::executeRestore(const AlarmCommand& cmd) {
// ============================================================
void AlarmManager::buzzerTest(uint32_t durationSec) {
Serial.printf("[告警] 🔔 蜂鸣器测试 %d\n", durationSec);
Serial.printf("[告警] 🔔 蜂鸣器测试 %ds\n", durationSec);
_setBuzzer(true);
_buzzerOffTime = millis() + durationSec * 1000;
}
// ============================================================
// 状态查询
// ============================================================
const char* AlarmManager::getActiveAlarmType() const {
if (_activeCount == 0) return "";
switch (_activeAlarms[0]) {
case ALARM_FALL: return "fall";
case ALARM_WATER_LEAK: return "water_leak";
case ALARM_HEART_ABNORMAL: return "heart_abnormal";
case ALARM_BREATH_ABNORMAL: return "breath_abnormal";
case ALARM_SERVER: return "server";
default: return "";
}
}
// ============================================================
// 内部控制
// ============================================================
@@ -195,7 +306,7 @@ void AlarmManager::_setBuzzer(bool on) {
_buzzerToggleTime = 0;
_beepCount = 0;
if (on) {
_buzzerOffTime = 0; // 本地报警=无限哔哔
_buzzerOffTime = 0;
} else {
ledcWrite(BUZZER_PWM_CHANNEL, 0);
_buzzerOffTime = 0;
@@ -207,57 +318,72 @@ void AlarmManager::_setLED(bool on) {
if (!on) digitalWrite(LED_ALARM_PIN, LOW);
}
// ============================================================
// 蜂鸣器更新 (优先级驱动模式)
// ============================================================
void AlarmManager::_updateBuzzer() {
// 定时关闭检查
if (_buzzerOn && _buzzerOffTime > 0 && millis() >= _buzzerOffTime) {
if (!_buzzerOn) return;
// 定时关闭
if (_buzzerOffTime > 0 && millis() >= _buzzerOffTime) {
_buzzerOn = false;
ledcWrite(BUZZER_PWM_CHANNEL, 0);
Serial.println(F("[告警] ⏰ 蜂鸣器定时关闭"));
return;
}
// 本地报警: 三连哔 停 — 循环 (哔哔哔...哔哔哔...)
if (_buzzerOn && _buzzerOffTime == 0) {
uint32_t now = millis();
// 周期: 3声哔 (每声150ms响+100ms停) + 600ms大停顿
uint32_t now = millis();
// 云端定时: 持续响
if (_buzzerOffTime > 0) {
ledcWrite(BUZZER_PWM_CHANNEL, 128);
return;
}
// 本地报警: 按优先级模式 — 哔声/停顿交替
if (_beepsPerCycle == 0) {
// 连速哔 (跌倒): 简单翻转
if (now - _buzzerToggleTime >= (_buzzerBeepState ? _beepOnMs : _beepOffMs)) {
_buzzerToggleTime = now;
_buzzerBeepState = !_buzzerBeepState;
ledcWrite(BUZZER_PWM_CHANNEL, _buzzerBeepState ? 128 : 0);
}
} else {
// 多声一组: N声哔 + 长停顿
if (!_buzzerBeepState) {
// 停顿中,检查是否该下一声
uint32_t pause = (_beepCount >= 3) ? 600 : 100;
// 停顿中
uint32_t pause = (_beepCount >= _beepsPerCycle) ? _cyclePauseMs : _beepOffMs;
if (now - _buzzerToggleTime >= pause) {
_buzzerToggleTime = now;
if (_beepCount >= 3) _beepCount = 0; // 重置周期
if (_beepCount >= _beepsPerCycle) _beepCount = 0;
_buzzerBeepState = true;
ledcWrite(BUZZER_PWM_CHANNEL, 128);
_beepCount++;
}
} else {
// 在响中150ms后停下
if (now - _buzzerToggleTime >= 150) {
// 响声中
if (now - _buzzerToggleTime >= _beepOnMs) {
_buzzerToggleTime = now;
_buzzerBeepState = false;
ledcWrite(BUZZER_PWM_CHANNEL, 0);
}
}
}
// 云端定时: 持续响
else if (_buzzerOn && _buzzerOffTime > 0) {
ledcWrite(BUZZER_PWM_CHANNEL, 128);
}
}
// ============================================================
// LED 更新 (按最高优先级决定闪烁频率)
// ============================================================
void AlarmManager::_updateLED() {
if (!_ledOn) {
digitalWrite(LED_ALARM_PIN, LOW);
return;
}
// 根据告警类型调整闪烁频率
uint32_t interval = 500;
for (uint8_t i = 0; i < _activeCount; i++) {
if (_activeAlarms[i] == ALARM_FALL) {
interval = 200; // 跌倒快闪
break;
}
}
AlarmType highest = getHighestAlarm();
uint32_t interval = _buzzerIntervalFor(highest);
if (millis() - _lastLEDToggle >= interval) {
_lastLEDToggle = millis();