smart-home/smart-home-app/报警解除状态-isActive字段说明.md
2026-02-26 09:16:34 +08:00

8.7 KiB
Raw Blame History

报警解除状态 - 基于ESP32的isActive字段

🎯 核心逻辑

利用ESP32已有的 isActive 字段来判断报警是否已解除:

  • isActive: true = 报警正在持续中
  • isActive: false = 报警已自动解除

📊 ESP32数据格式

ESP32的报警历史API (/api/alarm/history) 已经包含 isActive 字段:

{
    "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.vueparseAlarmHistory 方法中:

// 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显示

在报警卡片中:

<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在报警解除时记录解除时间

// 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响应

{
    "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) 中已经有详细的调试日志:

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会自动显示具体解除时间。