feat: 按钮去抖+配网界面美化+水浸离线+LED独立任务+报警全拓展(人身优先)+有人才检测
This commit is contained in:
@@ -17,8 +17,8 @@ WiFiMgmt::WiFiMgmt()
|
||||
, _lastCheckTime(0)
|
||||
, _buttonPressTime(0)
|
||||
, _buttonPressed(false)
|
||||
, _ledLastToggle(0)
|
||||
, _ledState(false)
|
||||
, _ledTaskHandle(nullptr)
|
||||
, _ledMode(0)
|
||||
, _param_mqtt_server(nullptr)
|
||||
, _param_mqtt_port(nullptr)
|
||||
, _param_mqtt_user(nullptr)
|
||||
@@ -48,6 +48,9 @@ bool WiFiMgmt::begin() {
|
||||
pinMode(LED_WIFI_PIN, OUTPUT);
|
||||
digitalWrite(LED_WIFI_PIN, LOW);
|
||||
|
||||
// 启动 LED 独立任务 (避免 startConfigPortal 阻塞影响闪烁)
|
||||
xTaskCreate(_ledTaskFunc, "WiFiLed", 1024, nullptr, 1, &_ledTaskHandle);
|
||||
|
||||
// 初始化 LittleFS
|
||||
if (!LittleFS.begin(true)) {
|
||||
Serial.println(F("[WiFi] ❌ LittleFS 挂载失败!"));
|
||||
@@ -71,11 +74,91 @@ bool WiFiMgmt::begin() {
|
||||
_wm.setDebugOutput(false); // 关闭调试输出 (避免干扰)
|
||||
_wm.setConfigPortalTimeout(WIFI_CONFIG_TIMEOUT);
|
||||
_wm.setConnectTimeout(WIFI_CONNECT_TIMEOUT);
|
||||
_wm.setTitle("🏥 五劳无感康养监测 - 设备配网"); // 配网页面的中文标题
|
||||
_wm.setTitle("健康监测系统 - 设备配网");
|
||||
_wm.setCustomHeadElement(
|
||||
"<style>"
|
||||
"body { font-family: 'Microsoft YaHei', 'PingFang SC', sans-serif; }"
|
||||
".msg .info { font-size: 14px; }"
|
||||
/* ===== 字体与全局 ===== */
|
||||
"*{margin:0;padding:0;box-sizing:border-box}"
|
||||
"body{"
|
||||
" font-family:-apple-system,BlinkMacSystemFont,'Segoe UI','PingFang SC','Microsoft YaHei',sans-serif;"
|
||||
" background:linear-gradient(160deg, #f0f5ff 0%, #e8f0fe 40%, #f3f0ff 100%);"
|
||||
" min-height:100vh;display:flex;flex-direction:column;align-items:center;"
|
||||
" padding:20px 16px 40px;color:#1e293b"
|
||||
"}"
|
||||
"body::before{"
|
||||
" content:'';position:fixed;top:-200px;right:-200px;"
|
||||
" width:400px;height:400px;border-radius:50%;"
|
||||
" background:radial-gradient(circle, rgba(99,102,241,0.08) 0%, transparent 70%);"
|
||||
" pointer-events:none;z-index:0"
|
||||
"}"
|
||||
"body::after{"
|
||||
" content:'';position:fixed;bottom:-100px;left:-100px;"
|
||||
" width:300px;height:300px;border-radius:50%;"
|
||||
" background:radial-gradient(circle, rgba(34,197,94,0.06) 0%, transparent 70%);"
|
||||
" pointer-events:none;z-index:0"
|
||||
"}"
|
||||
/* ===== 头部卡片 ===== */
|
||||
".msg{"
|
||||
" width:100%;max-width:440px;position:relative;z-index:1;"
|
||||
" background:#fff;border-radius:20px;padding:32px 24px 24px;"
|
||||
" margin-bottom:16px;text-align:center;"
|
||||
" box-shadow:0 1px 3px rgba(0,0,0,0.04),0 8px 24px rgba(0,0,0,0.06)"
|
||||
"}"
|
||||
".msg::before{"
|
||||
" content:'';display:block;width:56px;height:56px;"
|
||||
" margin:0 auto 16px;"
|
||||
" background:linear-gradient(135deg,#6366f1,#8b5cf6);border-radius:16px;"
|
||||
" box-shadow:0 8px 24px rgba(99,102,241,0.25)"
|
||||
"}"
|
||||
".msg h1,.msg h2{font-size:20px;font-weight:700;color:#1e293b;margin-bottom:6px}"
|
||||
".msg p,.msg .info{font-size:13px;color:#94a3b8;line-height:1.5}"
|
||||
/* 隐藏 WiFiManager 默认的 h1 重复标题 */
|
||||
".msg h1{font-size:0;margin:0;padding:0}"
|
||||
".msg h1::after{content:'健康监测系统';font-size:22px;font-weight:700;color:#1e293b}"
|
||||
".msg .info{font-size:13px!important}"
|
||||
/* ===== 表单卡片 ===== */
|
||||
"form{"
|
||||
" width:100%;max-width:440px;position:relative;z-index:1;"
|
||||
" background:#fff;border-radius:20px;padding:24px;"
|
||||
" box-shadow:0 1px 3px rgba(0,0,0,0.04),0 8px 24px rgba(0,0,0,0.06)"
|
||||
"}"
|
||||
"label{"
|
||||
" display:block;font-size:11px;font-weight:600;"
|
||||
" text-transform:uppercase;letter-spacing:0.8px;"
|
||||
" color:#6366f1;margin:16px 0 6px"
|
||||
"}"
|
||||
"label:first-of-type{margin-top:0}"
|
||||
"input[type=text],input[type=password],input[type=number]{"
|
||||
" width:100%;height:46px;padding:0 14px;"
|
||||
" border:2px solid #e2e8f0;border-radius:12px;"
|
||||
" font-size:15px;color:#1e293b;background:#f8fafc;"
|
||||
" outline:none;transition:all 0.2s;-webkit-appearance:none"
|
||||
"}"
|
||||
"input:focus{"
|
||||
" border-color:#6366f1;background:#fff;"
|
||||
" box-shadow:0 0 0 4px rgba(99,102,241,0.1)"
|
||||
"}"
|
||||
"input::placeholder{color:#cbd5e1}"
|
||||
/* ===== 提交按钮 ===== */
|
||||
"button[type=submit]{"
|
||||
" width:100%;height:50px;margin-top:24px;"
|
||||
" background:linear-gradient(135deg,#6366f1,#8b5cf6);"
|
||||
" color:#fff;border:none;border-radius:14px;"
|
||||
" font-size:16px;font-weight:600;letter-spacing:1px;"
|
||||
" cursor:pointer;transition:all 0.2s;"
|
||||
" box-shadow:0 4px 16px rgba(99,102,241,0.3)"
|
||||
"}"
|
||||
"button:active{transform:scale(0.97);box-shadow:0 2px 8px rgba(99,102,241,0.3)}"
|
||||
/* ===== 页脚 ===== */
|
||||
".msg:last-of-type{"
|
||||
" background:transparent;box-shadow:none;padding:16px;margin-top:4px"
|
||||
"}"
|
||||
".msg:last-of-type::before{display:none}"
|
||||
".msg:last-of-type p,.msg:last-of-type .info{font-size:12px;color:#94a3b8}"
|
||||
/* ===== 成功/错误状态页 ===== */
|
||||
".msg .success{color:#16a34a}"
|
||||
".msg .error{color:#dc2626}"
|
||||
"a{color:#6366f1;text-decoration:none;font-weight:500}"
|
||||
"</style>"
|
||||
);
|
||||
WiFi.setAutoReconnect(true); // ESP32 自动重连
|
||||
@@ -120,12 +203,12 @@ bool WiFiMgmt::begin() {
|
||||
if (!_connected) {
|
||||
// 如果自动连接失败, 启动配网页面
|
||||
Serial.println(F("[WiFi] 自动连接失败, 启动配网模式..."));
|
||||
_setLEDMode(1); // 快闪 = 配网模式
|
||||
_setLEDMode(2); // 快闪 = 配网模式
|
||||
_connected = _connectWiFi(); // 内部会启动配网页面
|
||||
}
|
||||
|
||||
if (_connected) {
|
||||
_setLEDMode(2); // 常亮 = 已连接
|
||||
_setLEDMode(3); // 常亮 = 已连接
|
||||
}
|
||||
|
||||
_lastCheckTime = millis();
|
||||
@@ -150,25 +233,16 @@ bool WiFiMgmt::loop() {
|
||||
|
||||
if (WiFi.status() != WL_CONNECTED) {
|
||||
_connected = false;
|
||||
_setLEDMode(0); // 慢闪 = 未连接
|
||||
_setLEDMode(1); // 慢闪 = 未连接
|
||||
Serial.println(F("[WiFi] ⚠️ WiFi 断开, 尝试重连..."));
|
||||
_connectWiFi();
|
||||
} else {
|
||||
_connected = true;
|
||||
_setLEDMode(2); // 常亮
|
||||
}
|
||||
}
|
||||
|
||||
// LED 闪烁处理
|
||||
if (!_connected) {
|
||||
uint32_t interval = (_wm.getConfigPortalActive()) ? 300 : 1000;
|
||||
if (millis() - _ledLastToggle > interval) {
|
||||
_ledLastToggle = millis();
|
||||
_ledState = !_ledState;
|
||||
digitalWrite(LED_WIFI_PIN, _ledState ? HIGH : LOW);
|
||||
_setLEDMode(3); // 常亮 = 已连接
|
||||
}
|
||||
}
|
||||
|
||||
// LED 由独立 FreeRTOS 任务处理 (不受 startConfigPortal 阻塞影响)
|
||||
return _connected;
|
||||
}
|
||||
|
||||
@@ -213,11 +287,11 @@ bool WiFiMgmt::_connectWiFi() {
|
||||
|
||||
void WiFiMgmt::startConfigPortal() {
|
||||
Serial.println(F("[WiFi] 🔧 手动启动配网页面..."));
|
||||
_setLEDMode(1);
|
||||
_setLEDMode(2); // 快闪 = 配网模式
|
||||
_wm.startConfigPortal(WIFI_AP_SSID, WIFI_AP_PASSWORD);
|
||||
_connected = (WiFi.status() == WL_CONNECTED);
|
||||
if (_connected) {
|
||||
_setLEDMode(2);
|
||||
_setLEDMode(3); // 常亮 = 已连接
|
||||
}
|
||||
}
|
||||
|
||||
@@ -393,20 +467,51 @@ const char* WiFiMgmt::getEnvNote() const {
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// LED 模式控制
|
||||
// LED 模式控制 (线程安全, 仅写模式变量,由独立任务执行)
|
||||
// ============================================================
|
||||
|
||||
void WiFiMgmt::_setLEDMode(uint8_t mode) {
|
||||
// mode 由 loop() 中的闪烁逻辑处理
|
||||
// 0=慢闪 1=快闪 2=常亮
|
||||
switch (mode) {
|
||||
case 0:
|
||||
case 1:
|
||||
// 闪烁由 loop 处理
|
||||
break;
|
||||
case 2:
|
||||
digitalWrite(LED_WIFI_PIN, HIGH);
|
||||
_ledState = true;
|
||||
break;
|
||||
_ledMode = mode; // uint8_t 赋值在 ESP32 上是原子的
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// LED 闪烁独立任务 (FreeRTOS)
|
||||
// 独立于主循环,startConfigPortal 阻塞期间也能正常闪烁
|
||||
// ============================================================
|
||||
|
||||
void WiFiMgmt::_ledTaskFunc(void* param) {
|
||||
const TickType_t fastMs = pdMS_TO_TICKS(300); // 快闪 = 配网模式
|
||||
const TickType_t slowMs = pdMS_TO_TICKS(1000); // 慢闪 = 未连接
|
||||
|
||||
while (true) {
|
||||
if (!_instance) {
|
||||
vTaskDelay(slowMs);
|
||||
continue;
|
||||
}
|
||||
|
||||
uint8_t mode = _instance->_ledMode;
|
||||
|
||||
switch (mode) {
|
||||
case 0: // 灭
|
||||
digitalWrite(LED_WIFI_PIN, LOW);
|
||||
vTaskDelay(slowMs);
|
||||
break;
|
||||
case 1: // 慢闪 — WiFi 断连
|
||||
digitalWrite(LED_WIFI_PIN, HIGH);
|
||||
vTaskDelay(slowMs);
|
||||
digitalWrite(LED_WIFI_PIN, LOW);
|
||||
vTaskDelay(slowMs);
|
||||
break;
|
||||
case 2: // 快闪 — 配网模式
|
||||
digitalWrite(LED_WIFI_PIN, HIGH);
|
||||
vTaskDelay(fastMs);
|
||||
digitalWrite(LED_WIFI_PIN, LOW);
|
||||
vTaskDelay(fastMs);
|
||||
break;
|
||||
case 3: // 常亮 — 已连接
|
||||
digitalWrite(LED_WIFI_PIN, HIGH);
|
||||
vTaskDelay(slowMs);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user