标签:#SpringBoot #地铁ISCS #告警确认 #告警屏蔽 #SCADA运维功能

摘要:地铁综合监控系统核心运维三大功能:告警人工确认、故障自动消除、检修临时屏蔽。区别于普通物联网平台,地铁严格遵循「未确认、已确认、已消除、已屏蔽」四状态流转。本文基于前七篇告警引擎,实现轨交标准告警状态机,完美适配地铁BAS/ISCS现场运维流程,代码可直接投产。

一、前言

前几篇我们完成了:告警判定 → 防抖滤波 → 分级 HMI 弹窗 + 底部闪烁。
能弹出告警 ≠ 能交付项目

真正的地铁 ISCS 验收,必须具备完整告警生命周期:

  1. 告警产生(底部闪烁 / 弹窗声光)
  2. 操作员人工确认告警
  3. 故障恢复自动消除告警
  4. 设备检修时临时屏蔽告警

普通物联网项目没有这么严格的状态流转,
地铁运维、监理验收、甲方考核必须要这套机制

本篇基于 8 年轨交现场经验,实现地铁标准告警四状态管理。

二、地铁 ISCS 告警四大状态(行业标准)

  1. 未确认未消除(NEW)
    刚产生故障,底部闪烁 + 弹窗声光,运维未处理

  2. 已确认未消除(CONFIRM)
    运维已知晓故障,但设备还在故障,故障继续存在

  3. 已消除已确认(CLEAR)
    设备恢复正常,告警消失,已归档

  4. 检修屏蔽状态(SHIELD)
    设备检修、断电调试,临时屏蔽该点位,不再产生告警

三、新增告警状态枚举(轨交规范)

/**
 * 地铁 ISCS 告警状态枚举
 * 完全对标真实综合监控系统
 */
public enum AlarmStatusEnum {
    // 1. 未确认
    UN_CONFIRM(0, "未确认"),
    // 2. 已确认
    CONFIRMED(1, "已确认"),
    // 3. 已消除
    CLEARED(2, "已消除"),
    // 4. 检修屏蔽
    SHIELD(3, "检修屏蔽");

    private final int code;
    private final String desc;

    AlarmStatusEnum(int code, String desc) {
        this.code = code;
        this.desc = desc;
    }

    public int getCode() {
        return code;
    }
}

四、告警缓存实体升级(支持状态机 + 屏蔽标记)

import lombok.Data;

@Data
public class AlarmCacheInfo {
    // 连续异常次数
    private int errorCount;
    // 连续正常次数
    private int normalCount;
    // 当前告警状态 0 未确认 1 已确认 2 已消除
    private int alarmStatus;
    // 是否检修屏蔽 true = 屏蔽不产生告警
    private boolean isShield;
}

五、告警规则新增检修屏蔽字段

// 是否检修屏蔽
private boolean shieldFlag;
// 屏蔽截止时间
private Long shieldEndTime;

六、核心升级:带状态机的完整告警引擎(地铁生产级)

import org.springframework.stereotype.Component;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@Component
public class AlarmStateEngine {

    // 点位告警状态缓存
    private final Map<String, AlarmCacheInfo> alarmStateMap = new ConcurrentHashMap<>();

    /**
     * 地铁标准告警状态流转校验
     */
    public boolean checkAlarmState(CollectDataDTO data, AlarmRule rule) {
        String pointId = data.getPointId();
        double currVal = data.getValue();
        AlarmCacheInfo cache = alarmStateMap.getOrDefault(pointId, new AlarmCacheInfo());

        // 检修屏蔽中:直接跳过所有告警判断
        if (cache.isShield() || rule.isShieldFlag()) {
            return false;
        }

        // 1. 判断当前数据是否异常
        boolean isError = isOverLimit(currVal, rule) || isValueJump(pointId, currVal, rule);

        if (isError) {
            // 数据异常,累加异常次数
            cache.setErrorCount(cache.getErrorCount() + 1);
            cache.setNormalCount(0);

            // 首次触发告警:进入【未确认】状态
            if (!cache.isAlarmStatus() && cache.getErrorCount() >= rule.getFilterCount()) {
                cache.setAlarmStatus(AlarmStatusEnum.UN_CONFIRM.getCode());
                alarmStateMap.put(pointId, cache);
                // 返回 true:推送弹窗 + 底部闪烁
                return true;
            }

        } else {
            // 数据恢复正常
            cache.setNormalCount(cache.getNormalCount() + 1);
            cache.setErrorCount(0);

            // 告警状态存在 + 持续正常达到恢复阈值 → 自动消除告警
            if (cache.getAlarmStatus() == AlarmStatusEnum.UN_CONFIRM.getCode()
                    || cache.getAlarmStatus() == AlarmStatusEnum.CONFIRMED.getCode()) {
                if (cache.getNormalCount() >= rule.getRecoverFilterCount()) {
                    // 状态流转为:已消除
                    cache.setAlarmStatus(AlarmStatusEnum.CLEARED.getCode());
                }
            }
        }

        alarmStateMap.put(pointId, cache);
        return false;
    }

    // 越限判断
    private boolean isOverLimit(double val, AlarmRule rule) {
        return val > rule.getMaxValue() || val < rule.getMinValue();
    }

    // 突变判断
    private boolean isValueJump(String pointId, double curr, AlarmRule rule) {
        Double lastVal = LastValueCache.get(pointId);
        if (lastVal == null) return false;
        return Math.abs(curr - lastVal) > rule.getChangeThreshold();
    }
}

七、两大运维操作接口(后台可直接调用)

1、人工确认告警

/**
 * 人工确认告警
 * 状态:未确认 → 已确认
 */
public void confirmAlarm(String pointId) {
    AlarmCacheInfo cache = alarmStateMap.get(pointId);
    if (cache != null && cache.getAlarmStatus() == AlarmStatusEnum.UN_CONFIRM.getCode()) {
        cache.setAlarmStatus(AlarmStatusEnum.CONFIRMED.getCode());
        alarmStateMap.put(pointId, cache);
    }
}

2、设备检修屏蔽告警

/**
 * 检修屏蔽点位告警
 */
public void shieldPointAlarm(String pointId, long shieldTime) {
    AlarmCacheInfo cache = alarmStateMap.getOrDefault(pointId, new AlarmCacheInfo());
    cache.setShield(true);
    // 可设置定时解除屏蔽
    alarmStateMap.put(pointId, cache);
}

八、地铁告警完整状态流转逻辑(重点)

首次故障触发
底部状态栏闪烁 + 一二三级弹窗声光 → 状态 = 未确认

运维点击确认
弹窗关闭、声音停止 → 状态 = 已确认
底部状态栏继续闪烁(地铁规范:未消除一直闪)

设备恢复正常
延时防抖校验通过 → 自动消除告警 → 状态 = 已消除
底部停止闪烁、归档历史告警

设备检修屏蔽
无论数据是否异常,全程不产生任何告警,适合夜间检修、设备断电调试

九、8 年轨交落地踩坑总结

  1. 地铁绝对不允许告警自动消失
    必须人工确认 + 设备恢复双重条件,符合国网 / 轨交运维规范

  2. 已确认未消除必须一直闪烁
    很多开源框架做错,地铁现场必须持续提示

  3. 检修屏蔽功能是验收必查项
    每条线路调试、设备更换都需要临时屏蔽点位

  4. 状态必须落库
    重启服务不丢失告警状态,是商用 ISCS 硬性要求

十、本篇总结

本篇完成了地铁 ISCS 完整告警生命周期:
未确认 → 已确认 → 已消除 → 检修屏蔽

完全对标商用地铁综合监控系统,告别玩具级告警逻辑,达到项目交付、监理验收标准。

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐