smart-home/smart-home-app/报警解除状态-isActive字段说明.md

285 lines
8.7 KiB
Markdown
Raw Normal View History

2026-02-26 09:16:34 +08:00
# 报警解除状态 - 基于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会自动显示具体解除时间。