DCS/ruiyiweiUX/Assets/报警记录开始结束时间追踪说明.md

13 KiB
Raw Permalink Blame History

报警记录开始/结束时间追踪说明

功能概述

报警记录系统现在支持完整的报警生命周期追踪,记录每个报警的"触发"和"解除"两个关键时间点。

核心改进

1. 数据模型增强

AlarmRecordData 新增字段

public bool IsTriggered;  // true=报警触发, false=报警解除

完整数据结构

[Serializable]
public class AlarmRecordData
{
    public int Id;                  // 记录ID
    public int Priority;            // 报警优先级High/Medium/Low
    public string Reason;           // 报警原因
    public string Time;             // 记录时间yyyy-MM-dd HH:mm:ss
    public string AlarmCode;        // 报警代码0x11, 0x32等
    public bool IsTriggered;        // 报警状态(触发/解除)
}

2. 报警记录逻辑

报警触发时

// BFI异常触发
SendAlarmCommand(0x32, AlarmPriority.High, true);

// 记录内容:
{
    Id: 1,
    Priority: High,
    Reason: "BFI数值异常",
    Time: "2025-11-28 14:30:15",
    AlarmCode: "0x32",
    IsTriggered: true   标记为触发
}

报警解除时

// BFI恢复正常
SendAlarmCommand(0x32, AlarmPriority.High, false);

// 记录内容:
{
    Id: 2,
    Priority: High,
    Reason: "BFI数值异常 (已解除)",
    Time: "2025-11-28 14:35:20",
    AlarmCode: "0x32",
    IsTriggered: false   标记为解除
}

3. 去重机制优化

旧逻辑(问题):

  • 同一报警在60秒内重复触发会被去重
  • BFI异常解除后再次触发会被误认为重复

新逻辑(改进):

  • 同一报警代码 + 同一状态在60秒内重复才去重
  • 触发和解除被视为不同事件,都会记录

去重判断条件

private bool IsDuplicateRecord(byte alarmCode, string reason, DateTime time, bool isTriggered)
{
    // 必须满足以下所有条件才认为是重复:
    // 1. 报警代码相同AlarmCode
    // 2. 报警原因相同Reason
    // 3. 报警状态相同IsTriggered  ✅ 新增
    // 4. 时间间隔小于60秒
    
    if (record.AlarmCode == codeStr && 
        record.Reason == reason && 
        record.IsTriggered == isTriggered &&  // ✅ 关键判断
        timeDiff < 60)
    {
        return true;  // 重复记录
    }
}

实际使用场景

场景 1BFI异常报警完整周期

时间线:
14:30:15 - BFI值下降到阈值以下 → 触发报警
14:35:20 - BFI值恢复正常范围 → 解除报警
14:40:30 - BFI值再次异常 → 再次触发报警(不被去重)✅
14:42:10 - BFI值恢复 → 再次解除

报警记录:
┌────┬──────┬─────────────────┬─────────────────────┬──────┬────────┐
│ ID │ 优先级│ 原因             │ 时间                 │ 代码  │ 状态    │
├────┼──────┼─────────────────┼─────────────────────┼──────┼────────┤
│ 1  │ High │ BFI数值异常      │ 2025-11-28 14:30:15 │ 0x32 │ 触发    │
│ 2  │ High │ BFI数值异常(已解除)│ 2025-11-28 14:35:20 │ 0x32 │ 解除    │
│ 3  │ High │ BFI数值异常      │ 2025-11-28 14:40:30 │ 0x32 │ 触发    │
│ 4  │ High │ BFI数值异常(已解除)│ 2025-11-28 14:42:10 │ 0x32 │ 解除    │
└────┴──────┴─────────────────┴─────────────────────┴──────┴────────┘

场景 2电池电量报警

时间线:
10:00:00 - 电量降至35% → 触发低优先级报警0x11
10:05:00 - 连接充电器,电量开始上升 → 解除报警
10:10:00 - 断开充电器电量降至38% → 再次触发报警
10:15:00 - 重新连接充电器 → 再次解除

报警记录:
┌────┬──────┬──────────────────┬─────────────────────┬──────┬────────┐
│ ID │ 优先级│ 原因              │ 时间                 │ 代码  │ 状态    │
├────┼──────┼──────────────────┼─────────────────────┼──────┼────────┤
│ 5  │ Low  │ 电池电量低(<40%) │ 2025-11-28 10:00:00 │ 0x11 │ 触发    │
│ 6  │ Low  │ 电池电量低(已解除)│ 2025-11-28 10:05:00 │ 0x11 │ 解除    │
│ 7  │ Low  │ 电池电量低(<40%) │ 2025-11-28 10:10:00 │ 0x11 │ 触发    │
│ 8  │ Low  │ 电池电量低(已解除)│ 2025-11-28 10:15:00 │ 0x11 │ 解除    │
└────┴──────┴──────────────────┴─────────────────────┴──────┴────────┘

场景 3去重保护60秒窗口

时间线:
11:00:00 - BFI异常触发报警
11:00:15 - BFI仍然异常15秒内重复触发→ 被去重,不记录 ✅
11:00:45 - BFI仍然异常45秒内重复触发→ 被去重,不记录 ✅
11:01:30 - BFI恢复正常 → 解除报警(不同状态,会记录)✅

报警记录:
┌────┬──────┬─────────────────┬─────────────────────┬──────┬────────┐
│ ID │ 优先级│ 原因             │ 时间                 │ 代码  │ 状态    │
├────┼──────┼─────────────────┼─────────────────────┼──────┼────────┤
│ 9  │ High │ BFI数值异常      │ 2025-11-28 11:00:00 │ 0x32 │ 触发    │
│ 10 │ High │ BFI数值异常(已解除)│ 2025-11-28 11:01:30 │ 0x32 │ 解除    │
└────┴──────┴─────────────────┴─────────────────────┴──────┴────────┘

日志输出:
[11:00:15] [报警记录持久化] 跳过重复记录: BFI数值异常 (代码: 0x32, 状态: 触发)
[11:00:45] [报警记录持久化] 跳过重复记录: BFI数值异常 (代码: 0x32, 状态: 触发)

代码实现细节

DCSAlarmManager.cs 改动

SendAlarmCommand 方法

public void SendAlarmCommand(byte alarmCode, AlarmPriority priority, bool trigger)
{
    // ... 发送串口命令 ...
    
    // 更新活跃报警集合
    if (trigger)
    {
        _activeAlarms.Add(alarmCode);
    }
    else
    {
        _activeAlarms.Remove(alarmCode);
    }
    
    // 更新当前最高优先级
    UpdateHighestPriority();
    
    // ✅ 记录报警状态变化(触发和解除都记录)
    if (_alarmCodeMap.TryGetValue(alarmCode, out var alarmInfoForRecord))
    {
        var alarmEvent = new AlarmEvent
        {
            Id = _nextAlarmId++,
            Priority = alarmInfoForRecord.priority,
            Reason = trigger ? alarmInfoForRecord.message : $"{alarmInfoForRecord.message} (已解除)",
            Time = DateTime.Now
        };
        
        // 使用持久化服务保存记录(自动去重)
        if (_recordPersistence != null)
        {
            _recordPersistence.AddRecord(alarmEvent, alarmCode, trigger);  // ✅ 传递状态
        }
    }
    
    // 触发系统报警显示和声音(仅在触发报警时)
    if (trigger && _alarmCodeMap.TryGetValue(alarmCode, out var alarmInfo))
    {
        TriggerSystemAlarm(alarmCode, alarmInfo.priority, alarmInfo.message);
    }
}

AlarmRecordPersistenceService.cs 改动

AddRecord 方法签名

// 旧签名(不支持状态)
public void AddRecord(AlarmEvent alarmEvent, byte alarmCode)

// 新签名(支持状态)✅
public void AddRecord(AlarmEvent alarmEvent, byte alarmCode, bool isTriggered)

去重逻辑

private bool IsDuplicateRecord(byte alarmCode, string reason, DateTime time, bool isTriggered)
{
    // 从最新记录开始检查
    for (int i = _storage.Records.Count - 1; i >= 0; i--)
    {
        var record = _storage.Records[i];
        
        // ✅ 检查报警代码、原因和状态是否相同
        if (record.AlarmCode == codeStr && 
            record.Reason == reason && 
            record.IsTriggered == isTriggered)  // 新增状态判断
        {
            // 检查时间差
            var timeDiff = (time - recordTime).TotalSeconds;
            
            // 如果在去重窗口内,认为是重复记录
            if (timeDiff < 60)
            {
                return true;  // 重复
            }
        }
    }
    
    return false;  // 不重复
}

数据存储示例

alarm_records.json 文件内容

{
  "Records": [
    {
      "Id": 1,
      "Priority": 2,
      "Reason": "BFI数值异常",
      "Time": "2025-11-28 14:30:15",
      "AlarmCode": "0x32",
      "IsTriggered": true
    },
    {
      "Id": 2,
      "Priority": 2,
      "Reason": "BFI数值异常 (已解除)",
      "Time": "2025-11-28 14:35:20",
      "AlarmCode": "0x32",
      "IsTriggered": false
    },
    {
      "Id": 3,
      "Priority": 0,
      "Reason": "电池电量低(<40%",
      "Time": "2025-11-28 15:00:00",
      "AlarmCode": "0x11",
      "IsTriggered": true
    }
  ],
  "NextId": 4
}

UI 显示效果

在报警记录面板AlarmRecordPanel用户可以看到

报警记录列表
┌────────────────────────────────────────────────────┐
│ #  │ 优先级 │ 原因                    │ 时间        │
├────┼───────┼────────────────────────┼────────────┤
│ 1  │ High  │ BFI数值异常             │ 14:30:15   │
│ 2  │ High  │ BFI数值异常 (已解除)    │ 14:35:20   │  ✅ 明确标注
│ 3  │ High  │ BFI数值异常             │ 14:40:30   │
│ 4  │ Low   │ 电池电量低(<40%)        │ 15:00:00   │
│ 5  │ Low   │ 电池电量低 (已解除)     │ 15:10:00   │  ✅ 明确标注
└────┴───────┴────────────────────────┴────────────┘

优点总结

1. 完整性

  • 记录报警的完整生命周期
  • 可以计算报警持续时间
  • 便于故障分析和统计

2. 准确性

  • 触发和解除分别记录,不会混淆
  • 去重机制更智能,不会误判
  • 同一报警可以多次记录

3. 可追溯性

  • 每次报警都有开始和结束时间
  • 可以分析报警频率和持续时间
  • 便于生成报警统计报告

4. 用户友好

  • "(已解除)" 标注清晰明了
  • 列表按时间顺序排列
  • 支持筛选触发/解除事件

测试建议

1. 基本功能测试

  • 触发BFI报警 → 验证记录"BFI数值异常"
  • BFI恢复 → 验证记录"BFI数值异常 (已解除)"
  • 再次触发 → 验证新记录,未被去重

2. 去重测试

  • 15秒内重复触发 → 验证第二次被去重
  • 触发后立即解除 → 验证解除事件不被去重
  • 解除后15秒内再次解除 → 验证第二次被去重

3. 多报警测试

  • 同时触发多个报警 → 验证各自独立记录
  • 不同报警代码 → 验证不会互相干扰

4. 持久化测试

  • 应用重启 → 验证历史记录仍然存在
  • 超过1000条记录 → 验证自动删除最旧记录

数据分析示例

基于完整的触发/解除记录,可以进行以下分析:

1. 报警持续时间统计

// 计算BFI报警平均持续时间
var bfiAlarms = records.Where(r => r.AlarmCode == "0x32");
var triggered = bfiAlarms.Where(r => r.IsTriggered).OrderBy(r => r.Time);
var cleared = bfiAlarms.Where(r => !r.IsTriggered).OrderBy(r => r.Time);

// 配对触发和解除记录
for (int i = 0; i < Math.Min(triggered.Count(), cleared.Count()); i++)
{
    var duration = (cleared.ElementAt(i).Time - triggered.ElementAt(i).Time).TotalMinutes;
    Console.WriteLine($"报警持续: {duration:F1} 分钟");
}

2. 报警频率分析

// 统计每天的报警次数
var dailyCount = records
    .Where(r => r.IsTriggered)
    .GroupBy(r => DateTime.Parse(r.Time).Date)
    .Select(g => new { Date = g.Key, Count = g.Count() });

总结

通过引入 IsTriggered 状态标记,报警记录系统现在能够:

  1. 完整追踪:记录每个报警的触发和解除时间
  2. 智能去重:区分触发和解除,避免误判
  3. 数据丰富:支持报警持续时间统计和频率分析
  4. 用户友好"(已解除)" 标注清晰直观

这是一个重要的改进,使报警记录系统更加专业和实用!