feat(alarm): 实现报警延时确认机制- 新增报警确认计数器、报警开始时间、恢复开始时间等状态跟踪映射- 修改阈值检查方法,引入延时确认逻辑和最小持续时间判断
- 调整报警触发条件,需满足确认次数和持续时间双重阈值 -优化报警恢复逻辑,支持恢复延时确认及状态清理- 统一模拟量和开关量报警处理流程,增强稳定性与准确性dev
parent
5b82275226
commit
73db177562
|
|
@ -39,6 +39,24 @@ public class AppPosiDeviceController {
|
||||||
|
|
||||||
// 用于跟踪设备节点的报警状态
|
// 用于跟踪设备节点的报警状态
|
||||||
private final Map<String, PageData> alarmStatusMap = new ConcurrentHashMap<>();
|
private final Map<String, PageData> alarmStatusMap = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
// 用于报警延时确认机制的计数器
|
||||||
|
private final Map<String, Integer> alarmConfirmCount = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
// 用于跟踪报警开始时间的映射
|
||||||
|
private final Map<String, Long> alarmStartTimeMap = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
// 用于跟踪报警恢复开始时间的映射
|
||||||
|
private final Map<String, Long> alarmRecoverStartTimeMap = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
// 用于存储当前报警信息的映射(避免存入过期的报警信息)
|
||||||
|
private final Map<String, Map<String, Object>> currentAlarmInfo = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
// 报警确认次数阈值
|
||||||
|
private static final int ALARM_CONFIRM_THRESHOLD = 3;
|
||||||
|
|
||||||
|
// 最小报警持续时间(毫秒),默认10秒
|
||||||
|
private static final long MIN_ALARM_DURATION = 10 * 1000;
|
||||||
|
|
||||||
@PostMapping("/test1")
|
@PostMapping("/test1")
|
||||||
public R test1(@RequestBody HashMap<String, String> parma) throws Exception {
|
public R test1(@RequestBody HashMap<String, String> parma) throws Exception {
|
||||||
|
|
@ -191,7 +209,7 @@ public class AppPosiDeviceController {
|
||||||
|
|
||||||
// REPORT_ID不为空且不为空串时必须检查(即使OPEN_ALARM为1也检查)
|
// REPORT_ID不为空且不为空串时必须检查(即使OPEN_ALARM为1也检查)
|
||||||
if (reportId != null && !"".equals(reportId.trim())) {
|
if (reportId != null && !"".equals(reportId.trim())) {
|
||||||
checkThreshold(data);
|
checkThresholdWithDelayConfirmation(data);
|
||||||
}
|
}
|
||||||
// OPEN_ALARM为1时不检查
|
// OPEN_ALARM为1时不检查
|
||||||
else if ("1".equals(openAlarm)) {
|
else if ("1".equals(openAlarm)) {
|
||||||
|
|
@ -199,7 +217,7 @@ public class AppPosiDeviceController {
|
||||||
}
|
}
|
||||||
// 其他情况正常检查(OPEN_ALARM为0或其他值)
|
// 其他情况正常检查(OPEN_ALARM为0或其他值)
|
||||||
else {
|
else {
|
||||||
checkThreshold(data);
|
checkThresholdWithDelayConfirmation(data);
|
||||||
}
|
}
|
||||||
dataList.add(data);
|
dataList.add(data);
|
||||||
}
|
}
|
||||||
|
|
@ -285,63 +303,120 @@ public class AppPosiDeviceController {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 检查阈值是否超出范围
|
* 检查阈值是否超出范围(带延时确认机制)
|
||||||
* @param data 数据项
|
* @param data 数据项
|
||||||
*/
|
*/
|
||||||
private void checkThreshold(Map<String, Object> data) {
|
private void checkThresholdWithDelayConfirmation(Map<String, Object> data) {
|
||||||
try {
|
try {
|
||||||
String currentValueStr = String.valueOf(data.get("CURRENT_VALUE"));
|
String currentValueStr = String.valueOf(data.get("CURRENT_VALUE"));
|
||||||
String thresholdUpLimitStr = (String) data.get("THRESHOLD_UP_LIMIT");
|
String thresholdUpLimitStr = (String) data.get("THRESHOLD_UP_LIMIT");
|
||||||
String thresholdUpUpLimitStr = (String) data.get("THRESHOLD_UP_UP_LIMIT");
|
String thresholdUpUpLimitStr = (String) data.get("THRESHOLD_UP_UP_LIMIT");
|
||||||
String thresholdDownLimitStr = (String) data.get("THRESHOLD_DOWN_LIMIT");
|
String thresholdDownLimitStr = (String) data.get("THRESHOLD_DOWN_LIMIT");
|
||||||
String thresholdDownDownLimitStr = (String) data.get("THRESHOLD_DOWN_DOWN_LIMIT");
|
String thresholdDownDownLimitStr = (String) data.get("THRESHOLD_DOWN_DOWN_LIMIT");
|
||||||
|
String equipmentId = (String) data.get("EQUIPMENT_ID");
|
||||||
|
String plcId = (String) data.get("PLC_ID");
|
||||||
|
|
||||||
if (currentValueStr == null || "null".equals(currentValueStr)) {
|
if (currentValueStr == null || "null".equals(currentValueStr)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
double currentValue = Double.parseDouble(currentValueStr);
|
double currentValue = Double.parseDouble(currentValueStr);
|
||||||
|
String equipmentKey = equipmentId + "_" + plcId;
|
||||||
|
|
||||||
|
boolean isAlarm = false;
|
||||||
|
String alarmType = "";
|
||||||
|
|
||||||
// 检查高高报
|
// 检查高高报
|
||||||
if (thresholdUpUpLimitStr != null && !"".equals(thresholdUpUpLimitStr) && !"null".equals(thresholdUpUpLimitStr)) {
|
if (thresholdUpUpLimitStr != null && !"".equals(thresholdUpUpLimitStr) && !"null".equals(thresholdUpUpLimitStr)) {
|
||||||
double thresholdUpUpLimit = Double.parseDouble(thresholdUpUpLimitStr);
|
double thresholdUpUpLimit = Double.parseDouble(thresholdUpUpLimitStr);
|
||||||
if (currentValue >= thresholdUpUpLimit) {
|
if (currentValue >= thresholdUpUpLimit) {
|
||||||
data.put("WARNING", 1);
|
isAlarm = true;
|
||||||
data.put("OVERVIEW_OF_ALERTS", "高高报警");
|
alarmType = "高高报警";
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检查高报
|
// 检查高报
|
||||||
if (thresholdUpLimitStr != null && !"".equals(thresholdUpLimitStr) && !"null".equals(thresholdUpLimitStr)) {
|
if (!isAlarm && thresholdUpLimitStr != null && !"".equals(thresholdUpLimitStr) && !"null".equals(thresholdUpLimitStr)) {
|
||||||
double thresholdUpLimit = Double.parseDouble(thresholdUpLimitStr);
|
double thresholdUpLimit = Double.parseDouble(thresholdUpLimitStr);
|
||||||
if (currentValue >= thresholdUpLimit) {
|
if (currentValue >= thresholdUpLimit) {
|
||||||
data.put("WARNING", 1);
|
isAlarm = true;
|
||||||
data.put("OVERVIEW_OF_ALERTS", "高报警");
|
alarmType = "高报警";
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检查低报
|
// 检查低报
|
||||||
if (thresholdDownLimitStr != null && !"".equals(thresholdDownLimitStr) && !"null".equals(thresholdDownLimitStr)) {
|
if (!isAlarm && thresholdDownLimitStr != null && !"".equals(thresholdDownLimitStr) && !"null".equals(thresholdDownLimitStr)) {
|
||||||
double thresholdDownLimit = Double.parseDouble(thresholdDownLimitStr);
|
double thresholdDownLimit = Double.parseDouble(thresholdDownLimitStr);
|
||||||
if (currentValue >= thresholdDownLimit) {
|
if (currentValue >= thresholdDownLimit) {
|
||||||
data.put("WARNING", 1);
|
isAlarm = true;
|
||||||
data.put("OVERVIEW_OF_ALERTS", "低报警");
|
alarmType = "低报警";
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检查低低报
|
// 检查低低报
|
||||||
if (thresholdDownDownLimitStr != null && !"".equals(thresholdDownDownLimitStr) && !"null".equals(thresholdDownDownLimitStr)) {
|
if (!isAlarm && thresholdDownDownLimitStr != null && !"".equals(thresholdDownDownLimitStr) && !"null".equals(thresholdDownDownLimitStr)) {
|
||||||
double thresholdDownDownLimit = Double.parseDouble(thresholdDownDownLimitStr);
|
double thresholdDownDownLimit = Double.parseDouble(thresholdDownDownLimitStr);
|
||||||
if (currentValue >= thresholdDownDownLimit) {
|
if (currentValue >= thresholdDownDownLimit) {
|
||||||
data.put("WARNING", 1);
|
isAlarm = true;
|
||||||
data.put("OVERVIEW_OF_ALERTS", "低低报警");
|
alarmType = "低低报警";
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
long currentTimestamp = System.currentTimeMillis();
|
||||||
|
|
||||||
|
// 处理报警确认逻辑
|
||||||
|
if (isAlarm) {
|
||||||
|
// 如果超过阈值,增加计数
|
||||||
|
int currentCount = alarmConfirmCount.getOrDefault(equipmentKey, 0) + 1;
|
||||||
|
alarmConfirmCount.put(equipmentKey, currentCount);
|
||||||
|
|
||||||
|
// 记录首次报警时间
|
||||||
|
if (!alarmStartTimeMap.containsKey(equipmentKey)) {
|
||||||
|
alarmStartTimeMap.put(equipmentKey, currentTimestamp);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 清除恢复计时(如果有的话)
|
||||||
|
alarmRecoverStartTimeMap.remove(equipmentKey);
|
||||||
|
|
||||||
|
// 保存当前报警信息,确保后续处理的是最新的报警数据
|
||||||
|
currentAlarmInfo.put(equipmentKey, new HashMap<>(data));
|
||||||
|
|
||||||
|
// 检查是否满足最小持续时间要求
|
||||||
|
Long startTime = alarmStartTimeMap.get(equipmentKey);
|
||||||
|
if (startTime != null) {
|
||||||
|
long duration = currentTimestamp - startTime;
|
||||||
|
if (duration >= MIN_ALARM_DURATION) {
|
||||||
|
// 持续时间达到要求,真正触发报警
|
||||||
|
if (currentCount >= ALARM_CONFIRM_THRESHOLD) {
|
||||||
|
data.put("WARNING", 1);
|
||||||
|
data.put("OVERVIEW_OF_ALERTS", alarmType);
|
||||||
|
XxlJobHelper.log("设备 {} 触发报警: {} (值: {},持续时间: {}ms)",
|
||||||
|
equipmentKey, alarmType, currentValue, duration);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 数据恢复正常,检查是否需要开始恢复计时
|
||||||
|
if (alarmStatusMap.containsKey(equipmentKey)) {
|
||||||
|
// 如果之前有报警状态,开始恢复计时
|
||||||
|
if (!alarmRecoverStartTimeMap.containsKey(equipmentKey)) {
|
||||||
|
alarmRecoverStartTimeMap.put(equipmentKey, currentTimestamp);
|
||||||
|
XxlJobHelper.log("设备 {} 开始恢复计时", equipmentKey);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 如果之前没有报警状态,直接清除计数器和开始时间
|
||||||
|
alarmConfirmCount.remove(equipmentKey);
|
||||||
|
alarmStartTimeMap.remove(equipmentKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 清除当前报警信息
|
||||||
|
currentAlarmInfo.remove(equipmentKey);
|
||||||
|
|
||||||
|
// 确保WARNING字段为0,表示未报警
|
||||||
|
data.put("WARNING", 0);
|
||||||
|
data.put("OVERVIEW_OF_ALERTS", "");
|
||||||
|
}
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
XxlJobHelper.log("检查阈值时发生异常: {}", e.getMessage());
|
XxlJobHelper.log("检查阈值时发生异常: {}", e.getMessage());
|
||||||
}
|
}
|
||||||
|
|
@ -356,11 +431,11 @@ public class AppPosiDeviceController {
|
||||||
ArrayList<PageData> activeAlarms = new ArrayList<>();
|
ArrayList<PageData> activeAlarms = new ArrayList<>();
|
||||||
|
|
||||||
for (Map<String, Object> item : mesSaveList) {
|
for (Map<String, Object> item : mesSaveList) {
|
||||||
// 检查是否有报警且是模拟量
|
// 检查是否有报警
|
||||||
Object warningObj = item.get("WARNING");
|
Object warningObj = item.get("WARNING");
|
||||||
|
|
||||||
if (warningObj != null && "1".equals(String.valueOf(warningObj))) {
|
if (warningObj != null && "1".equals(String.valueOf(warningObj))) {
|
||||||
// 有告警 且是模拟量
|
// 只有当WARNING为1时才创建报警记录,这表示已经通过了延时确认机制
|
||||||
PageData itemPageData = new PageData();
|
PageData itemPageData = new PageData();
|
||||||
itemPageData.put("ALARM_MONITORING_ID", UuidUtil.get32UUID());
|
itemPageData.put("ALARM_MONITORING_ID", UuidUtil.get32UUID());
|
||||||
itemPageData.put("PLC_NAME", item.get("PLC_NAME"));
|
itemPageData.put("PLC_NAME", item.get("PLC_NAME"));
|
||||||
|
|
@ -410,6 +485,7 @@ public class AppPosiDeviceController {
|
||||||
private void processWarnInfo(ArrayList<PageData> activeAlarms) {
|
private void processWarnInfo(ArrayList<PageData> activeAlarms) {
|
||||||
// 获取当前时间
|
// 获取当前时间
|
||||||
String currentTime = DateUtil.date2Str(new Date());
|
String currentTime = DateUtil.date2Str(new Date());
|
||||||
|
long currentTimestamp = System.currentTimeMillis();
|
||||||
|
|
||||||
// 处理新产生的报警
|
// 处理新产生的报警
|
||||||
for (PageData alarm : activeAlarms) {
|
for (PageData alarm : activeAlarms) {
|
||||||
|
|
@ -448,6 +524,9 @@ public class AppPosiDeviceController {
|
||||||
// 保存到alarmStatusMap中,用于跟踪状态
|
// 保存到alarmStatusMap中,用于跟踪状态
|
||||||
alarmStatusMap.put(key, warnInfo);
|
alarmStatusMap.put(key, warnInfo);
|
||||||
|
|
||||||
|
// 清除恢复计时(如果有的话)
|
||||||
|
alarmRecoverStartTimeMap.remove(key);
|
||||||
|
|
||||||
XxlJobHelper.log("创建新的告警信息: 设备ID={}, PLC_ID={}, 报警内容={}",
|
XxlJobHelper.log("创建新的告警信息: 设备ID={}, PLC_ID={}, 报警内容={}",
|
||||||
alarm.get("EQUIPMENT_ID"), alarm.get("PLC_ID"), alarm.get("OVERVIEW_OF_ALERTS"));
|
alarm.get("EQUIPMENT_ID"), alarm.get("PLC_ID"), alarm.get("OVERVIEW_OF_ALERTS"));
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -456,6 +535,9 @@ public class AppPosiDeviceController {
|
||||||
existingWarn.put("MESSAGE", "设备名称:"+ alarm.get("DEVICE_ID")+",监测节点:"+ alarm.get("PLC_NAME")+",报警内容:"+ alarm.get("OVERVIEW_OF_ALERTS"));
|
existingWarn.put("MESSAGE", "设备名称:"+ alarm.get("DEVICE_ID")+",监测节点:"+ alarm.get("PLC_NAME")+",报警内容:"+ alarm.get("OVERVIEW_OF_ALERTS"));
|
||||||
existingWarn.put("OPERATTIME", currentTime);
|
existingWarn.put("OPERATTIME", currentTime);
|
||||||
alarmStatusMap.put(key, existingWarn);
|
alarmStatusMap.put(key, existingWarn);
|
||||||
|
|
||||||
|
// 清除恢复计时(如果有的话)
|
||||||
|
alarmRecoverStartTimeMap.remove(key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -474,7 +556,24 @@ public class AppPosiDeviceController {
|
||||||
PageData warnInfo = entry.getValue();
|
PageData warnInfo = entry.getValue();
|
||||||
|
|
||||||
if (!activeAlarmKeys.contains(key)) {
|
if (!activeAlarmKeys.contains(key)) {
|
||||||
// 该节点之前报警,但现在不报警了,需要更新状态为已消警
|
// 检查是否满足最小恢复持续时间要求
|
||||||
|
Long recoverStartTime = alarmRecoverStartTimeMap.get(key);
|
||||||
|
if (recoverStartTime != null) {
|
||||||
|
long recoverDuration = currentTimestamp - recoverStartTime;
|
||||||
|
if (recoverDuration < MIN_ALARM_DURATION) {
|
||||||
|
// 未达到最小恢复持续时间,暂不处理消警
|
||||||
|
XxlJobHelper.log("设备 {} 恢复未达到最小持续时间 {}ms,当前持续时间 {}ms,暂不消警",
|
||||||
|
key, MIN_ALARM_DURATION, recoverDuration);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 如果还没有开始恢复计时,开始计时
|
||||||
|
alarmRecoverStartTimeMap.put(key, currentTimestamp);
|
||||||
|
XxlJobHelper.log("设备 {} 开始恢复计时", key);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 该节点之前报警,现在已经满足恢复条件,需要更新状态为已消警
|
||||||
warnInfo.put("WARN_STATUS", "1"); // 1表示已消警
|
warnInfo.put("WARN_STATUS", "1"); // 1表示已消警
|
||||||
warnInfo.put("END_TIME", currentTime); // 预警结束时间
|
warnInfo.put("END_TIME", currentTime); // 预警结束时间
|
||||||
warnInfo.put("OPERATTIME", currentTime);
|
warnInfo.put("OPERATTIME", currentTime);
|
||||||
|
|
@ -487,6 +586,12 @@ public class AppPosiDeviceController {
|
||||||
|
|
||||||
// 从跟踪map中移除
|
// 从跟踪map中移除
|
||||||
iterator.remove();
|
iterator.remove();
|
||||||
|
|
||||||
|
// 同时清除报警确认计数器、开始时间记录和恢复开始时间记录
|
||||||
|
alarmConfirmCount.remove(key);
|
||||||
|
alarmStartTimeMap.remove(key);
|
||||||
|
alarmRecoverStartTimeMap.remove(key);
|
||||||
|
currentAlarmInfo.remove(key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -54,6 +54,24 @@ public class MesDataScheduled extends IJobHandler {
|
||||||
|
|
||||||
// 用于跟踪设备节点的报警状态
|
// 用于跟踪设备节点的报警状态
|
||||||
private final Map<String, PageData> alarmStatusMap = new ConcurrentHashMap<>();
|
private final Map<String, PageData> alarmStatusMap = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
// 用于报警延时确认机制的计数器
|
||||||
|
private final Map<String, Integer> alarmConfirmCount = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
// 用于跟踪报警开始时间的映射
|
||||||
|
private final Map<String, Long> alarmStartTimeMap = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
// 用于跟踪报警恢复开始时间的映射
|
||||||
|
private final Map<String, Long> alarmRecoverStartTimeMap = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
// 用于存储当前报警信息的映射(避免存入过期的报警信息)
|
||||||
|
private final Map<String, Map<String, Object>> currentAlarmInfo = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
// 报警确认次数阈值
|
||||||
|
private static final int ALARM_CONFIRM_THRESHOLD = 3;
|
||||||
|
|
||||||
|
// 最小报警持续时间(毫秒),默认10秒
|
||||||
|
private static final long MIN_ALARM_DURATION = 10 * 1000;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@XxlJob(value = "mesDataJob")
|
@XxlJob(value = "mesDataJob")
|
||||||
|
|
@ -325,7 +343,7 @@ public class MesDataScheduled extends IJobHandler {
|
||||||
|
|
||||||
// REPORT_ID不为空且不为空串时必须检查(即使OPEN_ALARM为1也检查)
|
// REPORT_ID不为空且不为空串时必须检查(即使OPEN_ALARM为1也检查)
|
||||||
if (reportId != null && !"".equals(reportId.trim())) {
|
if (reportId != null && !"".equals(reportId.trim())) {
|
||||||
checkThreshold(mesData);
|
checkThresholdWithDelayConfirmation(mesData);
|
||||||
}
|
}
|
||||||
// OPEN_ALARM为1时不检查
|
// OPEN_ALARM为1时不检查
|
||||||
else if ("1".equals(openAlarm)) {
|
else if ("1".equals(openAlarm)) {
|
||||||
|
|
@ -333,7 +351,7 @@ public class MesDataScheduled extends IJobHandler {
|
||||||
}
|
}
|
||||||
// 其他情况正常检查(OPEN_ALARM为0或其他值)
|
// 其他情况正常检查(OPEN_ALARM为0或其他值)
|
||||||
else {
|
else {
|
||||||
checkThreshold(mesData);
|
checkThresholdWithDelayConfirmation(mesData);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -418,10 +436,10 @@ public class MesDataScheduled extends IJobHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 检查阈值是否超出范围
|
* 检查阈值是否超出范围(带延时确认机制)
|
||||||
* @param data 数据项
|
* @param data 数据项
|
||||||
*/
|
*/
|
||||||
private void checkThreshold(Map<String, Object> data) {
|
private void checkThresholdWithDelayConfirmation(Map<String, Object> data) {
|
||||||
try {
|
try {
|
||||||
String signalType = (String) data.get("SIGNAL_TYPE");
|
String signalType = (String) data.get("SIGNAL_TYPE");
|
||||||
// 只处理模拟量数据(信号类型为"1")
|
// 只处理模拟量数据(信号类型为"1")
|
||||||
|
|
@ -431,52 +449,109 @@ public class MesDataScheduled extends IJobHandler {
|
||||||
String thresholdUpUpLimitStr = (String) data.get("THRESHOLD_UP_UP_LIMIT");
|
String thresholdUpUpLimitStr = (String) data.get("THRESHOLD_UP_UP_LIMIT");
|
||||||
String thresholdDownLimitStr = (String) data.get("THRESHOLD_DOWN_LIMIT");
|
String thresholdDownLimitStr = (String) data.get("THRESHOLD_DOWN_LIMIT");
|
||||||
String thresholdDownDownLimitStr = (String) data.get("THRESHOLD_DOWN_DOWN_LIMIT");
|
String thresholdDownDownLimitStr = (String) data.get("THRESHOLD_DOWN_DOWN_LIMIT");
|
||||||
|
String equipmentId = (String) data.get("EQUIPMENT_ID");
|
||||||
|
String plcId = (String) data.get("PLC_ID");
|
||||||
|
|
||||||
if (currentValueStr == null || "null".equals(currentValueStr)) {
|
if (currentValueStr == null || "null".equals(currentValueStr)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
double currentValue = Double.parseDouble(currentValueStr);
|
double currentValue = Double.parseDouble(currentValueStr);
|
||||||
|
String equipmentKey = equipmentId + "_" + plcId;
|
||||||
|
|
||||||
|
boolean isAlarm = false;
|
||||||
|
String alarmType = "";
|
||||||
|
|
||||||
// 检查高高报
|
// 检查高高报
|
||||||
if (thresholdUpUpLimitStr != null && !"".equals(thresholdUpUpLimitStr) && !"null".equals(thresholdUpUpLimitStr)) {
|
if (thresholdUpUpLimitStr != null && !"".equals(thresholdUpUpLimitStr) && !"null".equals(thresholdUpUpLimitStr)) {
|
||||||
double thresholdUpUpLimit = Double.parseDouble(thresholdUpUpLimitStr);
|
double thresholdUpUpLimit = Double.parseDouble(thresholdUpUpLimitStr);
|
||||||
if (currentValue >= thresholdUpUpLimit) {
|
if (currentValue >= thresholdUpUpLimit) {
|
||||||
data.put("WARNING", 1);
|
isAlarm = true;
|
||||||
data.put("OVERVIEW_OF_ALERTS", "高高报警");
|
alarmType = "高高报警";
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检查高报
|
// 检查高报
|
||||||
if (thresholdUpLimitStr != null && !"".equals(thresholdUpLimitStr) && !"null".equals(thresholdUpLimitStr)) {
|
if (!isAlarm && thresholdUpLimitStr != null && !"".equals(thresholdUpLimitStr) && !"null".equals(thresholdUpLimitStr)) {
|
||||||
double thresholdUpLimit = Double.parseDouble(thresholdUpLimitStr);
|
double thresholdUpLimit = Double.parseDouble(thresholdUpLimitStr);
|
||||||
if (currentValue >= thresholdUpLimit) {
|
if (currentValue >= thresholdUpLimit) {
|
||||||
data.put("WARNING", 1);
|
isAlarm = true;
|
||||||
data.put("OVERVIEW_OF_ALERTS", "高报警");
|
alarmType = "高报警";
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检查低报
|
// 检查低报
|
||||||
if (thresholdDownLimitStr != null && !"".equals(thresholdDownLimitStr) && !"null".equals(thresholdDownLimitStr)) {
|
if (!isAlarm && thresholdDownLimitStr != null && !"".equals(thresholdDownLimitStr) && !"null".equals(thresholdDownLimitStr)) {
|
||||||
double thresholdDownLimit = Double.parseDouble(thresholdDownLimitStr);
|
double thresholdDownLimit = Double.parseDouble(thresholdDownLimitStr);
|
||||||
if (currentValue <= thresholdDownLimit) {
|
if (currentValue <= thresholdDownLimit) {
|
||||||
data.put("WARNING", 1);
|
isAlarm = true;
|
||||||
data.put("OVERVIEW_OF_ALERTS", "低报警");
|
alarmType = "低报警";
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检查低低报
|
// 检查低低报
|
||||||
if (thresholdDownDownLimitStr != null && !"".equals(thresholdDownDownLimitStr) && !"null".equals(thresholdDownDownLimitStr)) {
|
if (!isAlarm && thresholdDownDownLimitStr != null && !"".equals(thresholdDownDownLimitStr) && !"null".equals(thresholdDownDownLimitStr)) {
|
||||||
double thresholdDownDownLimit = Double.parseDouble(thresholdDownDownLimitStr);
|
double thresholdDownDownLimit = Double.parseDouble(thresholdDownDownLimitStr);
|
||||||
if (currentValue <= thresholdDownDownLimit) {
|
if (currentValue <= thresholdDownDownLimit) {
|
||||||
data.put("WARNING", 1);
|
isAlarm = true;
|
||||||
data.put("OVERVIEW_OF_ALERTS", "低低报警");
|
alarmType = "低低报警";
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
long currentTimestamp = System.currentTimeMillis();
|
||||||
|
|
||||||
|
// 处理报警确认逻辑
|
||||||
|
if (isAlarm) {
|
||||||
|
// 如果超过阈值,增加计数
|
||||||
|
int currentCount = alarmConfirmCount.getOrDefault(equipmentKey, 0) + 1;
|
||||||
|
alarmConfirmCount.put(equipmentKey, currentCount);
|
||||||
|
|
||||||
|
// 记录首次报警时间
|
||||||
|
if (!alarmStartTimeMap.containsKey(equipmentKey)) {
|
||||||
|
alarmStartTimeMap.put(equipmentKey, currentTimestamp);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 清除恢复计时(如果有的话)
|
||||||
|
alarmRecoverStartTimeMap.remove(equipmentKey);
|
||||||
|
|
||||||
|
// 保存当前报警信息,确保后续处理的是最新的报警数据
|
||||||
|
currentAlarmInfo.put(equipmentKey, new HashMap<>(data));
|
||||||
|
|
||||||
|
// 检查是否满足最小持续时间要求
|
||||||
|
Long startTime = alarmStartTimeMap.get(equipmentKey);
|
||||||
|
if (startTime != null) {
|
||||||
|
long duration = currentTimestamp - startTime;
|
||||||
|
if (duration >= MIN_ALARM_DURATION) {
|
||||||
|
// 持续时间达到要求,真正触发报警
|
||||||
|
if (currentCount >= ALARM_CONFIRM_THRESHOLD) {
|
||||||
|
data.put("WARNING", 1);
|
||||||
|
data.put("OVERVIEW_OF_ALERTS", alarmType);
|
||||||
|
XxlJobHelper.log("设备 {} 触发报警: {} (值: {},持续时间: {}ms)",
|
||||||
|
equipmentKey, alarmType, currentValue, duration);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 数据恢复正常,检查是否需要开始恢复计时
|
||||||
|
if (alarmStatusMap.containsKey(equipmentKey)) {
|
||||||
|
// 如果之前有报警状态,开始恢复计时
|
||||||
|
if (!alarmRecoverStartTimeMap.containsKey(equipmentKey)) {
|
||||||
|
alarmRecoverStartTimeMap.put(equipmentKey, currentTimestamp);
|
||||||
|
XxlJobHelper.log("设备 {} 开始恢复计时", equipmentKey);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 如果之前没有报警状态,直接清除计数器和开始时间
|
||||||
|
alarmConfirmCount.remove(equipmentKey);
|
||||||
|
alarmStartTimeMap.remove(equipmentKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 清除当前报警信息
|
||||||
|
currentAlarmInfo.remove(equipmentKey);
|
||||||
|
|
||||||
|
// 确保WARNING字段为0,表示未报警
|
||||||
|
data.put("WARNING", 0);
|
||||||
|
data.put("OVERVIEW_OF_ALERTS", "");
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// 处理开关量报警
|
// 处理开关量报警
|
||||||
String currentValueStr = String.valueOf(data.get("CURRENT_VALUE"));
|
String currentValueStr = String.valueOf(data.get("CURRENT_VALUE"));
|
||||||
|
|
@ -492,7 +567,15 @@ public class MesDataScheduled extends IJobHandler {
|
||||||
if (currentValue == alarmValue) {
|
if (currentValue == alarmValue) {
|
||||||
data.put("WARNING", 1);
|
data.put("WARNING", 1);
|
||||||
data.put("OVERVIEW_OF_ALERTS", "联锁投入报警");
|
data.put("OVERVIEW_OF_ALERTS", "联锁投入报警");
|
||||||
|
} else {
|
||||||
|
// 确保WARNING字段为0,表示未报警
|
||||||
|
data.put("WARNING", 0);
|
||||||
|
data.put("OVERVIEW_OF_ALERTS", "");
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// 确保WARNING字段为0,表示未报警
|
||||||
|
data.put("WARNING", 0);
|
||||||
|
data.put("OVERVIEW_OF_ALERTS", "");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
|
@ -513,7 +596,7 @@ public class MesDataScheduled extends IJobHandler {
|
||||||
Object warningObj = item.get("WARNING");
|
Object warningObj = item.get("WARNING");
|
||||||
|
|
||||||
if (warningObj != null && "1".equals(String.valueOf(warningObj))) {
|
if (warningObj != null && "1".equals(String.valueOf(warningObj))) {
|
||||||
// 有告警 且是模拟量
|
// 只有当WARNING为1时才创建报警记录,这表示已经通过了延时确认机制
|
||||||
PageData itemPageData = new PageData();
|
PageData itemPageData = new PageData();
|
||||||
itemPageData.put("ALARM_MONITORING_ID", UuidUtil.get32UUID());
|
itemPageData.put("ALARM_MONITORING_ID", UuidUtil.get32UUID());
|
||||||
itemPageData.put("PLC_NAME", item.get("PLC_NAME"));
|
itemPageData.put("PLC_NAME", item.get("PLC_NAME"));
|
||||||
|
|
@ -564,6 +647,7 @@ public class MesDataScheduled extends IJobHandler {
|
||||||
private void processWarnInfo(ArrayList<PageData> activeAlarms, ArrayList<Map<String, Object>> allData) {
|
private void processWarnInfo(ArrayList<PageData> activeAlarms, ArrayList<Map<String, Object>> allData) {
|
||||||
// 获取当前时间
|
// 获取当前时间
|
||||||
String currentTime = DateUtil.date2Str(new Date());
|
String currentTime = DateUtil.date2Str(new Date());
|
||||||
|
long currentTimestamp = System.currentTimeMillis();
|
||||||
|
|
||||||
// 处理新产生的报警
|
// 处理新产生的报警
|
||||||
for (PageData alarm : activeAlarms) {
|
for (PageData alarm : activeAlarms) {
|
||||||
|
|
@ -576,11 +660,11 @@ public class MesDataScheduled extends IJobHandler {
|
||||||
warnInfo.put("WARN_ID", UuidUtil.get32UUID());
|
warnInfo.put("WARN_ID", UuidUtil.get32UUID());
|
||||||
warnInfo.put("WARN_STATUS", "0"); // 0表示未消警
|
warnInfo.put("WARN_STATUS", "0"); // 0表示未消警
|
||||||
warnInfo.put("WARN_ORG", "山西新泰钢铁有限公司"); // 0表示未消警
|
warnInfo.put("WARN_ORG", "山西新泰钢铁有限公司"); // 0表示未消警
|
||||||
if (alarm.get("OVERVIEW_OF_ALERTS")=="低低报警" || alarm.get("OVERVIEW_OF_ALERTS")=="低报警"){
|
if ("低低报警".equals(alarm.get("OVERVIEW_OF_ALERTS")) || "低报警".equals(alarm.get("OVERVIEW_OF_ALERTS"))){
|
||||||
warnInfo.put("WARN_RANK", "3");
|
warnInfo.put("WARN_RANK", "3");
|
||||||
}else if (alarm.get("OVERVIEW_OF_ALERTS")=="高报警"){
|
}else if ("高报警".equals(alarm.get("OVERVIEW_OF_ALERTS"))){
|
||||||
warnInfo.put("WARN_RANK", "2");
|
warnInfo.put("WARN_RANK", "2");
|
||||||
}else if (alarm.get("OVERVIEW_OF_ALERTS")=="高高报警"){
|
}else if ("高高报警".equals(alarm.get("OVERVIEW_OF_ALERTS"))){
|
||||||
warnInfo.put("WARN_RANK", "1");
|
warnInfo.put("WARN_RANK", "1");
|
||||||
}
|
}
|
||||||
warnInfo.put("MESSAGE", "设备名称:"+ alarm.get("DEVICE_ID")+",监测节点:"+ alarm.get("PLC_NAME")+",报警内容:"+ alarm.get("OVERVIEW_OF_ALERTS"));
|
warnInfo.put("MESSAGE", "设备名称:"+ alarm.get("DEVICE_ID")+",监测节点:"+ alarm.get("PLC_NAME")+",报警内容:"+ alarm.get("OVERVIEW_OF_ALERTS"));
|
||||||
|
|
@ -602,6 +686,9 @@ public class MesDataScheduled extends IJobHandler {
|
||||||
// 保存到alarmStatusMap中,用于跟踪状态
|
// 保存到alarmStatusMap中,用于跟踪状态
|
||||||
alarmStatusMap.put(key, warnInfo);
|
alarmStatusMap.put(key, warnInfo);
|
||||||
|
|
||||||
|
// 清除恢复计时(如果有的话)
|
||||||
|
alarmRecoverStartTimeMap.remove(key);
|
||||||
|
|
||||||
XxlJobHelper.log("创建新的告警信息: 设备ID={}, PLC_ID={}, 报警内容={}",
|
XxlJobHelper.log("创建新的告警信息: 设备ID={}, PLC_ID={}, 报警内容={}",
|
||||||
alarm.get("EQUIPMENT_ID"), alarm.get("PLC_ID"), alarm.get("OVERVIEW_OF_ALERTS"));
|
alarm.get("EQUIPMENT_ID"), alarm.get("PLC_ID"), alarm.get("OVERVIEW_OF_ALERTS"));
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -610,6 +697,9 @@ public class MesDataScheduled extends IJobHandler {
|
||||||
existingWarn.put("MESSAGE", "设备名称:"+ alarm.get("DEVICE_ID")+",监测节点:"+ alarm.get("PLC_NAME")+",报警内容:"+ alarm.get("OVERVIEW_OF_ALERTS"));
|
existingWarn.put("MESSAGE", "设备名称:"+ alarm.get("DEVICE_ID")+",监测节点:"+ alarm.get("PLC_NAME")+",报警内容:"+ alarm.get("OVERVIEW_OF_ALERTS"));
|
||||||
existingWarn.put("OPERATTIME", currentTime);
|
existingWarn.put("OPERATTIME", currentTime);
|
||||||
alarmStatusMap.put(key, existingWarn);
|
alarmStatusMap.put(key, existingWarn);
|
||||||
|
|
||||||
|
// 清除恢复计时(如果有的话)
|
||||||
|
alarmRecoverStartTimeMap.remove(key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -628,7 +718,24 @@ public class MesDataScheduled extends IJobHandler {
|
||||||
PageData warnInfo = entry.getValue();
|
PageData warnInfo = entry.getValue();
|
||||||
|
|
||||||
if (!activeAlarmKeys.contains(key)) {
|
if (!activeAlarmKeys.contains(key)) {
|
||||||
// 该节点之前报警,但现在不报警了,需要更新状态为已消警
|
// 检查是否满足最小恢复持续时间要求
|
||||||
|
Long recoverStartTime = alarmRecoverStartTimeMap.get(key);
|
||||||
|
if (recoverStartTime != null) {
|
||||||
|
long recoverDuration = currentTimestamp - recoverStartTime;
|
||||||
|
if (recoverDuration < MIN_ALARM_DURATION) {
|
||||||
|
// 未达到最小恢复持续时间,暂不处理消警
|
||||||
|
XxlJobHelper.log("设备 {} 恢复未达到最小持续时间 {}ms,当前持续时间 {}ms,暂不消警",
|
||||||
|
key, MIN_ALARM_DURATION, recoverDuration);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 如果还没有开始恢复计时,开始计时
|
||||||
|
alarmRecoverStartTimeMap.put(key, currentTimestamp);
|
||||||
|
XxlJobHelper.log("设备 {} 开始恢复计时", key);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 该节点之前报警,现在已经满足恢复条件,需要更新状态为已消警
|
||||||
warnInfo.put("WARN_STATUS", "1"); // 1表示已消警
|
warnInfo.put("WARN_STATUS", "1"); // 1表示已消警
|
||||||
warnInfo.put("END_TIME", currentTime); // 预警结束时间
|
warnInfo.put("END_TIME", currentTime); // 预警结束时间
|
||||||
warnInfo.put("OPERATTIME", currentTime);
|
warnInfo.put("OPERATTIME", currentTime);
|
||||||
|
|
@ -641,6 +748,12 @@ public class MesDataScheduled extends IJobHandler {
|
||||||
|
|
||||||
// 从跟踪map中移除
|
// 从跟踪map中移除
|
||||||
iterator.remove();
|
iterator.remove();
|
||||||
|
|
||||||
|
// 同时清除报警确认计数器、开始时间记录和恢复开始时间记录
|
||||||
|
alarmConfirmCount.remove(key);
|
||||||
|
alarmStartTimeMap.remove(key);
|
||||||
|
alarmRecoverStartTimeMap.remove(key);
|
||||||
|
currentAlarmInfo.remove(key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue