285 lines
8.7 KiB
Markdown
285 lines
8.7 KiB
Markdown
# 报警解除状态 - 基于ESP32的isActive字段
|
||
|
||
## 🎯 核心逻辑
|
||
|
||
利用ESP32已有的 `isActive` 字段来判断报警是否已解除:
|
||
|
||
- **`isActive: true`** = 报警正在持续中
|
||
- **`isActive: false`** = 报警已自动解除
|
||
|
||
## 📊 ESP32数据格式
|
||
|
||
ESP32的报警历史API (`/api/alarm/history`) 已经包含 `isActive` 字段:
|
||
|
||
```json
|
||
{
|
||
"alarms": [
|
||
{
|
||
"id": 1,
|
||
"title": "燃烧报警报警",
|
||
"desc": "热源持续升温,温度超过阈值",
|
||
"temp": 65.5,
|
||
"time": "14:26:10",
|
||
"date": "01-22",
|
||
"location": "厨房区域",
|
||
"isActive": false, // ✅ 关键字段:false表示已解除
|
||
"timestamp_ms": 1737548770000
|
||
},
|
||
{
|
||
"id": 2,
|
||
"title": "无人值守风险",
|
||
"desc": "热源持续升温,厨房无人5分钟",
|
||
"temp": 45.2,
|
||
"time": "21:30:00",
|
||
"date": "01-22",
|
||
"location": "厨房区域",
|
||
"isActive": true, // ⚠️ 仍在持续
|
||
"timestamp_ms": 1737548400000
|
||
}
|
||
],
|
||
"anyAlarmActive": true
|
||
}
|
||
```
|
||
|
||
## 🔧 前端实现逻辑
|
||
|
||
### 1. 解除状态判断
|
||
|
||
在 `pages/kitchen/history.vue` 的 `parseAlarmHistory` 方法中:
|
||
|
||
```javascript
|
||
// 1. 优先使用ESP32的isActive字段判断(isActive=false表示已解除)
|
||
if (alarm.hasOwnProperty('isActive') && alarm.isActive === false) {
|
||
resolved = true
|
||
resolvedType = 'auto' // ESP32自动检测解除
|
||
|
||
// 如果ESP32提供了解除时间,使用它
|
||
if (alarm.resolvedAt || alarm.resolved_at || alarm.resolvedTimestamp) {
|
||
const resolvedTimestamp = alarm.resolvedAt || alarm.resolved_at || alarm.resolvedTimestamp
|
||
const resolvedDate = new Date(typeof resolvedTimestamp === 'number' ? resolvedTimestamp : Date.parse(resolvedTimestamp))
|
||
resolvedTime = resolvedDate.getHours() + ':' + String(resolvedDate.getMinutes()).padStart(2, '0')
|
||
} else {
|
||
// 如果没有解除时间,显示为"已解除"(不显示具体时间)
|
||
resolvedTime = ''
|
||
}
|
||
}
|
||
```
|
||
|
||
### 2. UI显示
|
||
|
||
在报警卡片中:
|
||
|
||
```vue
|
||
<view class="alarm-resolved" v-if="alarm.resolved">
|
||
<text class="resolved-icon">✅</text>
|
||
<!-- 有解除时间时 -->
|
||
<text class="resolved-text" v-if="alarm.resolvedTime">
|
||
已于 {{alarm.resolvedTime}} {{alarm.resolvedType === 'auto' ? '自动解除' : '用户处理'}}
|
||
</text>
|
||
<!-- 没有解除时间时 -->
|
||
<text class="resolved-text" v-else>
|
||
{{alarm.resolvedType === 'auto' ? '已自动解除' : '已处理'}}
|
||
</text>
|
||
</view>
|
||
```
|
||
|
||
### 3. 显示效果
|
||
|
||
**有解除时间**:
|
||
```
|
||
无人值守风险
|
||
热源持续升温,厨房无人5分钟
|
||
热点区域: 厨房区域
|
||
✅ 已于 21:38 自动解除
|
||
```
|
||
|
||
**没有解除时间**:
|
||
```
|
||
燃烧报警报警
|
||
热源持续升温,温度超过阈值
|
||
热点区域: 厨房区域
|
||
✅ 已自动解除
|
||
```
|
||
|
||
## 🚀 ESP32端建议优化
|
||
|
||
### 当前实现
|
||
|
||
ESP32已经在报警数据中提供了 `isActive` 字段,这很好!
|
||
|
||
### 建议增强
|
||
|
||
为了提供更完整的解除信息,建议ESP32在报警解除时记录解除时间:
|
||
|
||
```cpp
|
||
// AlarmManager.cpp
|
||
struct AlarmRecord {
|
||
int id;
|
||
String title;
|
||
String desc;
|
||
float temp;
|
||
unsigned long timestamp;
|
||
String location;
|
||
bool isActive; // ✅ 已有
|
||
|
||
// 建议新增
|
||
unsigned long resolvedAt; // 解除时间戳(毫秒)
|
||
};
|
||
|
||
// 当检测到报警解除时
|
||
void checkAndResolveAlarms() {
|
||
for (auto& alarm : alarmHistory) {
|
||
if (alarm.isActive && currentTemp < SAFE_TEMP) {
|
||
alarm.isActive = false;
|
||
alarm.resolvedAt = millis(); // 记录解除时间
|
||
|
||
ESP_LOGI(TAG, "报警已解除: %s, 解除时间: %lu",
|
||
alarm.title.c_str(), alarm.resolvedAt);
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
### 增强后的API响应
|
||
|
||
```json
|
||
{
|
||
"alarms": [
|
||
{
|
||
"id": 1,
|
||
"title": "燃烧报警报警",
|
||
"desc": "热源持续升温,温度超过阈值",
|
||
"temp": 65.5,
|
||
"time": "14:26:10",
|
||
"date": "01-22",
|
||
"location": "厨房区域",
|
||
"isActive": false,
|
||
"timestamp_ms": 1737548770000,
|
||
"resolvedAt": 1737548880000 // ✨ 新增:解除时间戳
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
## 📋 数据流程
|
||
|
||
### 1. 报警触发
|
||
```
|
||
ESP32检测到高温
|
||
→ 创建报警记录 (isActive=true)
|
||
→ 推送到云端
|
||
→ APP显示报警(无解除状态)
|
||
```
|
||
|
||
### 2. 报警解除
|
||
```
|
||
ESP32检测到温度恢复
|
||
→ 更新报警记录 (isActive=false, resolvedAt=当前时间)
|
||
→ 同步到云端
|
||
→ APP显示解除状态 ✅
|
||
```
|
||
|
||
### 3. APP查询
|
||
```
|
||
APP请求报警历史
|
||
→ ESP32返回所有报警(包含isActive字段)
|
||
→ APP根据isActive判断是否显示解除状态
|
||
→ 如果有resolvedAt,显示具体解除时间
|
||
→ 如果没有resolvedAt,只显示"已自动解除"
|
||
```
|
||
|
||
## 🎨 UI效果对比
|
||
|
||
### 未解除的报警
|
||
```
|
||
┌─────────────────────────────┐
|
||
│ 🔥 高温危险 65.5°C │
|
||
│ 14:26 │
|
||
│ │
|
||
│ 热源持续升温,温度超过阈值 │
|
||
│ 热点区域: 厨房区域 │
|
||
│ │
|
||
│ [标记已读] [删除] │
|
||
└─────────────────────────────┘
|
||
```
|
||
|
||
### 已解除的报警(有时间)
|
||
```
|
||
┌─────────────────────────────┐
|
||
│ 👤 无人值守风险 45.2°C │
|
||
│ 21:30 │
|
||
│ │
|
||
│ 热源持续升温,厨房无人5分钟 │
|
||
│ 热点区域: 厨房区域 │
|
||
│ ┌─────────────────────────┐ │
|
||
│ │ ✅ 已于 21:38 自动解除 │ │
|
||
│ └─────────────────────────┘ │
|
||
│ │
|
||
│ [标记已读] [删除] │
|
||
└─────────────────────────────┘
|
||
```
|
||
|
||
### 已解除的报警(无时间)
|
||
```
|
||
┌─────────────────────────────┐
|
||
│ 🔥 燃烧报警报警 65.5°C │
|
||
│ 14:26 │
|
||
│ │
|
||
│ 热源持续升温,温度超过阈值 │
|
||
│ 热点区域: 厨房区域 │
|
||
│ ┌─────────────────────────┐ │
|
||
│ │ ✅ 已自动解除 │ │
|
||
│ └─────────────────────────┘ │
|
||
│ │
|
||
│ [标记已读] [删除] │
|
||
└─────────────────────────────┘
|
||
```
|
||
|
||
## 🔍 调试信息
|
||
|
||
在首页 (`pages/index/index.vue`) 中已经有详细的调试日志:
|
||
|
||
```javascript
|
||
console.log('📊 最新报警状态:', {
|
||
id: this.recentAlarms[0].id,
|
||
title: this.recentAlarms[0].title,
|
||
isActive: this.recentAlarms[0].isActive,
|
||
anyAlarmActive: response.data.anyAlarmActive,
|
||
shouldShowResetBtn: this.isAlarmActive(this.recentAlarms[0])
|
||
})
|
||
|
||
console.log('🔍 Alarm Reset按钮显示检查:', {
|
||
totalAlarms: this.recentAlarms.length,
|
||
firstAlarmActive: this.recentAlarms.length > 0 ? this.isAlarmActive(this.recentAlarms[0]) : false,
|
||
firstAlarmData: this.recentAlarms.length > 0 ? {
|
||
hasIsActive: this.recentAlarms[0].hasOwnProperty('isActive'),
|
||
isActiveValue: this.recentAlarms[0].isActive,
|
||
timestamp_ms: this.recentAlarms[0].timestamp_ms,
|
||
timeDiff: this.recentAlarms[0].timestamp_ms ? (Date.now() - this.recentAlarms[0].timestamp_ms) : null
|
||
} : null
|
||
})
|
||
```
|
||
|
||
这些日志可以帮助验证 `isActive` 字段是否正确传递。
|
||
|
||
## ✅ 优势
|
||
|
||
使用 `isActive` 字段的优势:
|
||
|
||
1. **无需额外开发** - ESP32已经提供了这个字段
|
||
2. **实时准确** - ESP32实时检测温度,能准确判断报警是否解除
|
||
3. **向后兼容** - 即使ESP32不提供 `resolvedAt`,也能显示解除状态
|
||
4. **逻辑清晰** - `isActive=false` 直观表示报警已解除
|
||
|
||
## 📝 总结
|
||
|
||
现在报警历史页面已经支持:
|
||
|
||
1. ✅ 读取ESP32的 `isActive` 字段
|
||
2. ✅ `isActive=false` 时显示"已自动解除"
|
||
3. ✅ 如果有 `resolvedAt` 时间,显示具体解除时间
|
||
4. ✅ 没有时间时,显示简化文案
|
||
5. ✅ 绿色背景样式,清晰易识别
|
||
|
||
**无需修改ESP32代码,即可立即使用!** 如果ESP32后续添加 `resolvedAt` 字段,APP会自动显示具体解除时间。
|