|
|
@@ -0,0 +1,551 @@
|
|
|
+package com.usky.cdi.service.impl;
|
|
|
+
|
|
|
+import com.alibaba.fastjson.JSON;
|
|
|
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
|
+import com.usky.cdi.domain.BaseAlarm;
|
|
|
+import com.usky.cdi.domain.BaseBuildFacility;
|
|
|
+import com.usky.cdi.mapper.BaseAlarmMapper;
|
|
|
+import com.usky.cdi.mapper.BaseBuildFacilityMapper;
|
|
|
+import com.usky.cdi.mapper.DmpProductMapper;
|
|
|
+import com.usky.cdi.service.mqtt.MqttConnectionTool;
|
|
|
+import com.usky.cdi.service.util.SnowflakeIdGenerator;
|
|
|
+import com.usky.cdi.service.vo.alarm.AlarmMessageVO;
|
|
|
+import com.usky.cdi.domain.enums.AlarmType;
|
|
|
+import lombok.RequiredArgsConstructor;
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
+import org.springframework.beans.factory.annotation.Autowired;
|
|
|
+import org.springframework.beans.factory.annotation.Value;
|
|
|
+import org.springframework.data.redis.core.StringRedisTemplate;
|
|
|
+import org.springframework.scheduling.annotation.Async;
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
+
|
|
|
+import javax.annotation.PostConstruct;
|
|
|
+import java.time.LocalDateTime;
|
|
|
+import java.util.HashMap;
|
|
|
+import java.util.List;
|
|
|
+import java.util.Map;
|
|
|
+import java.util.Objects;
|
|
|
+import java.util.stream.Collectors;
|
|
|
+
|
|
|
+/**
|
|
|
+ * 多租户定时任务服务
|
|
|
+ *
|
|
|
+ * @author fu
|
|
|
+ * @since 2025-12-29
|
|
|
+ */
|
|
|
+@Slf4j
|
|
|
+@Service
|
|
|
+@RequiredArgsConstructor
|
|
|
+public class AlarmDataSyncService {
|
|
|
+
|
|
|
+ @Value("${snowflake.worker-id:3}")
|
|
|
+ private long workerId;
|
|
|
+
|
|
|
+ @Value("${snowflake.data-center-id:3}")
|
|
|
+ private long dataCenterId;
|
|
|
+
|
|
|
+ private static final String PEACETIME = "peacetime";
|
|
|
+ private static final String WARTIME = "wartime";
|
|
|
+ private static final String MQTT_TOPIC = "alarm/message";
|
|
|
+ private static final String ALARM_DELIVERY_KEY_PREFIX = "alarm:delivery:";
|
|
|
+ private final MqttConnectionTool mqttConnectionTool;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private StringRedisTemplate stringRedisTemplate;
|
|
|
+ @Autowired
|
|
|
+ private BaseAlarmMapper baseAlarmMapper;
|
|
|
+ @Autowired
|
|
|
+ private DmpProductMapper dmpProductMapper;
|
|
|
+ @Autowired
|
|
|
+ private BaseBuildFacilityMapper baseBuildFacilityMapper;
|
|
|
+
|
|
|
+ private SnowflakeIdGenerator idGenerator;
|
|
|
+
|
|
|
+ @PostConstruct
|
|
|
+ public void init() {
|
|
|
+ this.idGenerator = new SnowflakeIdGenerator(workerId, dataCenterId);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取当前时间
|
|
|
+ */
|
|
|
+ private LocalDateTime getCurrentTime() {
|
|
|
+ return LocalDateTime.now();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 生成数据包ID
|
|
|
+ */
|
|
|
+ private Long generateDataPacketID() {
|
|
|
+ return idGenerator.nextPacketId();
|
|
|
+ }
|
|
|
+
|
|
|
+ @Async
|
|
|
+ public void synchronizeAlarmData(Integer tenantId, Long engineeringId, String username, String password, String status) {
|
|
|
+ log.info("租户:{}的人防告警数据推送定时任务开始执行,平战时状态:{}", tenantId, PEACETIME.equals(status) ? "平时" : "战时");
|
|
|
+
|
|
|
+ Long startTime = System.currentTimeMillis();
|
|
|
+ log.info("开始时间:{}", getCurrentTime());
|
|
|
+
|
|
|
+ // 1.查询 base_alarm 表中的告警数据,筛选条件为 tenant_id = tenantId
|
|
|
+ LambdaQueryWrapper<BaseAlarm> queryWrapper = new LambdaQueryWrapper<>();
|
|
|
+ queryWrapper.eq(BaseAlarm::getTenantId, tenantId)
|
|
|
+ .eq(BaseAlarm::getAlarmGrade, 1);
|
|
|
+ List<BaseAlarm> alarmList = baseAlarmMapper.selectList(queryWrapper);
|
|
|
+
|
|
|
+ if (alarmList.isEmpty()) {
|
|
|
+ log.warn("租户{}没有新的告警数据,任务结束", tenantId);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ log.info("查询到租户{}的告警数据总数:{}", tenantId, alarmList.size());
|
|
|
+
|
|
|
+ // 批量查询建筑设施数据,构建设备ID到设施的映射
|
|
|
+ Map<String, BaseBuildFacility> facilityMap = buildFacilityMap(alarmList, tenantId);
|
|
|
+
|
|
|
+ // 记录每一条告警数据
|
|
|
+ for (BaseAlarm alarm : alarmList) {
|
|
|
+ log.info("告警数据:ID={}, 设备ID={}, 告警类型={}, 告警时间={}, 处理状态={}, 是否误报={}",
|
|
|
+ alarm.getId(), alarm.getDeviceId(), alarm.getAlarmType(),
|
|
|
+ alarm.getAlarmTime(), alarm.getHandleStatus(), alarm.getAlarmFalse());
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ // 2.创建MQTT连接
|
|
|
+ mqttConnectionTool.connectOrRefresh(username, password);
|
|
|
+
|
|
|
+ int successCount = 0;
|
|
|
+ int failureCount = 0;
|
|
|
+
|
|
|
+ // 3.遍历告警数据,转换为AlarmMessageVO并发送
|
|
|
+ for (BaseAlarm alarm : alarmList) {
|
|
|
+ try {
|
|
|
+ // 根据告警类型映射关系转换
|
|
|
+ String alarmType = convertAlarmType(alarm.getAlarmType());
|
|
|
+ if (alarmType == null) {
|
|
|
+ log.warn("不支持的告警类型:{},跳过处理", alarm.getAlarmType());
|
|
|
+ failureCount++;
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 转换告警状态
|
|
|
+ Integer alarmStatus = convertAlarmStatus(alarm.getHandleStatus(), alarm.getAlarmFalse(), status);
|
|
|
+
|
|
|
+ // 构建AlarmMessageVO对象
|
|
|
+ AlarmMessageVO<Integer> alarmMessageVO = new AlarmMessageVO<>();
|
|
|
+ alarmMessageVO.setDataPacketID(generateDataPacketID());
|
|
|
+ alarmMessageVO.setEngineeringID(engineeringId);
|
|
|
+ alarmMessageVO.setAlarmID(alarm.getId());
|
|
|
+ // 固定值1,人防工程级物联平台自动发现
|
|
|
+ alarmMessageVO.setAlarmSource(1);
|
|
|
+ alarmMessageVO.setSensorID(alarm.getDeviceId() != null ? Integer.valueOf(alarm.getDeviceId()) : null);
|
|
|
+ alarmMessageVO.setAlarmType(alarmType);
|
|
|
+ alarmMessageVO.setAlarmStatus(alarmStatus);
|
|
|
+
|
|
|
+ // 设置告警时间:新增告警取 alarm_type 字段,更新数据则取 handle_time 字段
|
|
|
+ String alarmTime = alarm.getHandleTime() != null ?
|
|
|
+ alarm.getHandleTime().toString() : alarm.getAlarmTime().toString();
|
|
|
+ alarmMessageVO.setAlarmUpdateTime(alarmTime);
|
|
|
+
|
|
|
+ // 设置监测对象告警描述和编号
|
|
|
+ alarmMessageVO.setAlarmDesc(alarm.getAlarmAttribute());
|
|
|
+ alarmMessageVO.setMonitorObjNo(facilityMap.get(alarm.getDeviceId()).getFacilityNum());
|
|
|
+
|
|
|
+ // 设置上报时间为当前时间
|
|
|
+ alarmMessageVO.setPublishTime(getCurrentTime());
|
|
|
+
|
|
|
+ // 设置告警数据字段
|
|
|
+ alarmMessageVO.setSensorValue(alarm.getAlarmData());
|
|
|
+
|
|
|
+ // 根据告警类型填充unitName、thresholding、lineNo字段
|
|
|
+ populateAlarmFields(alarmMessageVO, alarm, tenantId, facilityMap);
|
|
|
+
|
|
|
+ // 从Redis获取缓存的投递状态,检查是否有变更
|
|
|
+ String deliveryKey = alarm.getDeviceId() + "_" + alarm.getId();
|
|
|
+ String cachedRecord = (String) stringRedisTemplate.opsForHash().get(ALARM_DELIVERY_KEY_PREFIX + tenantId, deliveryKey);
|
|
|
+ if (cachedRecord != null && !hasAlarmChanged(alarm, cachedRecord, status)) {
|
|
|
+ log.info("告警数据无变化,跳过推送:设备ID={}, 告警ID={}", alarm.getDeviceId(), alarm.getId());
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 4.将AlarmMessageVO转换为JSON字符串并发送MQTT消息
|
|
|
+ String jsonMessage = JSON.toJSONString(alarmMessageVO);
|
|
|
+ MqttConnectionTool.MqttGateway gateway = mqttConnectionTool.connectOrRefresh(username, password);
|
|
|
+ gateway.sendToMqtt(MQTT_TOPIC, jsonMessage);
|
|
|
+
|
|
|
+ successCount++;
|
|
|
+
|
|
|
+ // 更新Redis中的投递记录
|
|
|
+ saveDeliveryRecordToRedis(alarm, alarmStatus, status, tenantId);
|
|
|
+
|
|
|
+ log.info("成功发送告警消息:设备ID={}, 告警类型={}, 消息内容={}",
|
|
|
+ alarm.getDeviceId(), alarm.getAlarmType(), jsonMessage);
|
|
|
+
|
|
|
+ } catch (Exception e) {
|
|
|
+ failureCount++;
|
|
|
+ log.error("发送告警消息失败:设备ID={}, 告警类型={}, 错误信息={}",
|
|
|
+ alarm.getDeviceId(), alarm.getAlarmType(), e.getMessage(), e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 6.打印统计信息
|
|
|
+ log.info("租户{}的告警数据推送任务完成", tenantId);
|
|
|
+ log.info("告警数据总数:{}, 成功推送:{}, 失败:{}", alarmList.size(), successCount, failureCount);
|
|
|
+
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("租户{}的告警数据推送定时任务执行失败:{}", tenantId, e.getMessage(), e);
|
|
|
+ } finally {
|
|
|
+ Long endTime = System.currentTimeMillis();
|
|
|
+ log.info("结束时间:{}, 耗时:{}ms", getCurrentTime(), endTime - startTime);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 将base_alarm的alarm_type转换为AlarmMessageVO的alarmType
|
|
|
+ */
|
|
|
+ private String convertAlarmType(String alarmType) {
|
|
|
+ AlarmType type = AlarmType.fromOriginalCode(alarmType);
|
|
|
+ return type != null ? type.getMappedCode() : null;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 根据平时/战时状态转换告警状态
|
|
|
+ * 平时:handle_status=0则alarmStatus=1,handle_status=1则alarmStatus=4,alarm_false=1则alarmStatus=2
|
|
|
+ * 战时:handle_status=0则alarmStatus=1,handle_status=1则alarmStatus=3,alarm_false=1则alarmStatus=5
|
|
|
+ */
|
|
|
+ private Integer convertAlarmStatus(Integer handleStatus, Integer alarmFalse, String status) {
|
|
|
+ // 如果是误报,优先返回对应的误报状态
|
|
|
+ if (alarmFalse != null && alarmFalse == 1) {
|
|
|
+ // 平时误报=2,战时误报=5
|
|
|
+ return PEACETIME.equals(status) ? 2 : 5;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 根据处理状态和平战时状态返回对应状态
|
|
|
+ if (handleStatus != null) {
|
|
|
+ if (handleStatus == 0) {
|
|
|
+ // 未处理/待处置
|
|
|
+ return 1;
|
|
|
+ } else if (handleStatus == 1) {
|
|
|
+ // 平时已办结=4,战时已处置=3
|
|
|
+ return PEACETIME.equals(status) ? 4 : 3;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 默认返回未处理状态
|
|
|
+ return 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 批量查询建筑设施数据,构建设备ID到设施的映射
|
|
|
+ */
|
|
|
+ private Map<String, BaseBuildFacility> buildFacilityMap(List<BaseAlarm> alarmList, Integer tenantId) {
|
|
|
+ Map<String, BaseBuildFacility> facilityMap = new HashMap<>();
|
|
|
+
|
|
|
+ // 收集所有设备ID
|
|
|
+ List<String> deviceIds = alarmList.stream()
|
|
|
+ .map(BaseAlarm::getDeviceId)
|
|
|
+ .filter(id -> id != null && !id.trim().isEmpty())
|
|
|
+ .distinct()
|
|
|
+ .collect(Collectors.toList());
|
|
|
+
|
|
|
+ if (deviceIds.isEmpty()) {
|
|
|
+ return facilityMap;
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ LambdaQueryWrapper<BaseBuildFacility> queryWrapper = new LambdaQueryWrapper<>();
|
|
|
+ queryWrapper.in(BaseBuildFacility::getDeviceId, deviceIds)
|
|
|
+ .eq(BaseBuildFacility::getTenantId, tenantId)
|
|
|
+ .eq(BaseBuildFacility::getDeleteFlag, 0);
|
|
|
+
|
|
|
+ List<BaseBuildFacility> facilities = baseBuildFacilityMapper.selectList(queryWrapper);
|
|
|
+
|
|
|
+ for (BaseBuildFacility facility : facilities) {
|
|
|
+ if (facility.getDeviceId() != null) {
|
|
|
+ facilityMap.put(facility.getDeviceId(), facility);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ log.info("批量查询建筑设施数据完成:设备ID数量={}, 匹配到设施数量={}", deviceIds.size(), facilityMap.size());
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.warn("批量查询BaseBuildFacility失败:{}", e.getMessage());
|
|
|
+ }
|
|
|
+
|
|
|
+ return facilityMap;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 将投递记录保存到Redis Hash中
|
|
|
+ * 使用Hash结构:key=alarm:delivery:{tenantId}, field=deviceId_alarmId, value=JSON格式的投递状态
|
|
|
+ */
|
|
|
+ private void saveDeliveryRecordToRedis(BaseAlarm alarm, Integer currentAlarmStatus, String status, Integer tenantId) {
|
|
|
+ try {
|
|
|
+ String deliveryKey = ALARM_DELIVERY_KEY_PREFIX + tenantId;
|
|
|
+ String fieldKey = alarm.getDeviceId() + "_" + alarm.getId();
|
|
|
+
|
|
|
+ Map<String, String> recordMap = new HashMap<>();
|
|
|
+ recordMap.put("alarmStatus", String.valueOf(currentAlarmStatus));
|
|
|
+ recordMap.put("handleStatus", String.valueOf(alarm.getHandleStatus()));
|
|
|
+ recordMap.put("alarmFalse", String.valueOf(alarm.getAlarmFalse()));
|
|
|
+ recordMap.put("handleTime", alarm.getHandleTime() != null ? alarm.getHandleTime().toString() : "");
|
|
|
+ recordMap.put("handleBy", alarm.getHandleBy() != null ? alarm.getHandleBy() : "");
|
|
|
+ recordMap.put("deliveryTime", LocalDateTime.now().toString());
|
|
|
+
|
|
|
+ stringRedisTemplate.opsForHash().put(deliveryKey, fieldKey, JSON.toJSONString(recordMap));
|
|
|
+
|
|
|
+ log.debug("保存投递记录到Redis:key={}, field={}", deliveryKey, fieldKey);
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.warn("保存投递记录到Redis失败:告警ID={}, 错误={}", alarm.getId(), e.getMessage());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 检查告警数据是否有变更
|
|
|
+ * 比较handleStatus、alarmFalse、handleTime、handleBy是否发生变化
|
|
|
+ */
|
|
|
+ private boolean hasAlarmChanged(BaseAlarm alarm, String cachedRecord, String status) {
|
|
|
+ try {
|
|
|
+ Map<String, String> cachedMap = JSON.parseObject(cachedRecord, Map.class);
|
|
|
+
|
|
|
+ Integer currentAlarmStatus = convertAlarmStatus(alarm.getHandleStatus(), alarm.getAlarmFalse(), status);
|
|
|
+ Integer cachedAlarmStatus = parseInteger(cachedMap.get("alarmStatus"));
|
|
|
+ Integer cachedHandleStatus = parseInteger(cachedMap.get("handleStatus"));
|
|
|
+ Integer cachedAlarmFalse = parseInteger(cachedMap.get("alarmFalse"));
|
|
|
+
|
|
|
+ if (!Objects.equals(currentAlarmStatus, cachedAlarmStatus)) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ if (!Objects.equals(alarm.getHandleStatus(), cachedHandleStatus)) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ if (!Objects.equals(alarm.getAlarmFalse(), cachedAlarmFalse)) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ String cachedHandleTime = cachedMap.get("handleTime");
|
|
|
+ String currentHandleTime = alarm.getHandleTime() != null ? alarm.getHandleTime().toString() : "";
|
|
|
+ if (!Objects.equals(currentHandleTime, cachedHandleTime)) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ String cachedHandleBy = cachedMap.get("handleBy");
|
|
|
+ String currentHandleBy = alarm.getHandleBy() != null ? alarm.getHandleBy() : "";
|
|
|
+ if (!Objects.equals(currentHandleBy, cachedHandleBy)) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ return false;
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.warn("解析缓存的投递记录失败:告警ID={}, 错误={}", alarm.getId(), e.getMessage());
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private Integer parseInteger(String value) {
|
|
|
+ if (value == null || value.trim().isEmpty()) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ return Integer.parseInt(value);
|
|
|
+ } catch (NumberFormatException e) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 根据告警类型填充unitName、thresholding、lineNo字段
|
|
|
+ */
|
|
|
+ private void populateAlarmFields(AlarmMessageVO<Integer> alarmMessageVO, BaseAlarm alarm, Integer tenantId,
|
|
|
+ Map<String, BaseBuildFacility> facilityMap) {
|
|
|
+ String originalAlarmType = alarm.getAlarmType();
|
|
|
+ AlarmType alarmTypeEnum = AlarmType.fromOriginalCode(originalAlarmType);
|
|
|
+
|
|
|
+ try {
|
|
|
+ // 根据AlarmMessageVO字段注释中的规则填充字段
|
|
|
+ if (alarmTypeEnum != null && alarmTypeEnum.isStructureMonitoringType()) {
|
|
|
+ // 倾斜/位移/裂缝告警类型 - 设置unitName
|
|
|
+ populateUnitName(alarmMessageVO, alarm, tenantId, facilityMap);
|
|
|
+ }
|
|
|
+ if (alarmTypeEnum != null && alarmTypeEnum.isThresholdAlarmType()) {
|
|
|
+ // 温湿度、气体浓度告警类型 - 设置thresholding
|
|
|
+ populateThresholding(alarmMessageVO, alarm);
|
|
|
+ }
|
|
|
+ if (alarmTypeEnum != null && alarmTypeEnum.isLineNoAlarmType()) {
|
|
|
+ // 电气相关告警类型 - 设置lineNo
|
|
|
+ populateLineNo(alarmMessageVO, alarm);
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.warn("填充告警字段时发生异常:告警类型={}, 设备ID={}, 错误信息={}",
|
|
|
+ originalAlarmType, alarm.getDeviceId(), e.getMessage());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 填充unitName字段(倾斜才用)
|
|
|
+ * 对于711、712、713类型,实现与BaseBuildFacility表中facilityDesc字段的映射
|
|
|
+ */
|
|
|
+ private void populateUnitName(AlarmMessageVO<Integer> alarmMessageVO, BaseAlarm alarm, Integer tenantId,
|
|
|
+ Map<String, BaseBuildFacility> facilityMap) {
|
|
|
+ String originalAlarmType = alarm.getAlarmType();
|
|
|
+ AlarmType alarmTypeEnum = AlarmType.fromOriginalCode(originalAlarmType);
|
|
|
+
|
|
|
+ if (alarmTypeEnum != null && alarmTypeEnum.isStructureMonitoringType()) {
|
|
|
+ // 从Map中获取建筑设施信息
|
|
|
+ BaseBuildFacility facility = facilityMap.get(alarm.getDeviceId());
|
|
|
+ if (facility != null && facility.getFacilityDesc() != null) {
|
|
|
+ alarmMessageVO.setUnitName(facility.getFacilityDesc());
|
|
|
+ log.debug("成功映射unitName:设备ID={}, facilityDesc={}", alarm.getDeviceId(), facility.getFacilityDesc());
|
|
|
+ } else {
|
|
|
+ // 如果没有找到对应的facilityDesc,设置默认值
|
|
|
+ String defaultUnitName = alarmTypeEnum.getDefaultUnitName();
|
|
|
+ alarmMessageVO.setUnitName(defaultUnitName);
|
|
|
+ log.debug("未找到facilityDesc,使用默认值:设备ID={}, 默认值={}", alarm.getDeviceId(), defaultUnitName);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ // 其他情况,设置默认值
|
|
|
+ String defaultUnitName = alarmTypeEnum != null ? alarmTypeEnum.getDefaultUnitName() : "监测单元";
|
|
|
+ alarmMessageVO.setUnitName(defaultUnitName);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 填充thresholding字段(氧气、温湿度、一氧化碳、二氧化碳、剩余电流、供电电缆温度、电流偏大专用)
|
|
|
+ */
|
|
|
+ private void populateThresholding(AlarmMessageVO<Integer> alarmMessageVO, BaseAlarm alarm) {
|
|
|
+ // try {
|
|
|
+ // // 从告警数据中解析阈值,如果解析失败则设置默认值
|
|
|
+ // Float threshold = parseThresholdFromAlarmData(alarm.getAlarmData(), alarm.getAlarmType());
|
|
|
+ // alarmMessageVO.setThresholding(threshold);
|
|
|
+ // } catch (Exception e) {
|
|
|
+ // 解析失败时设置合理的默认值
|
|
|
+ Float defaultThreshold = getDefaultThreshold(alarm.getAlarmType());
|
|
|
+ alarmMessageVO.setThresholding(defaultThreshold);
|
|
|
+ // log.warn("解析阈值失败,使用默认值:设备ID={}, 告警类型={}, 错误={}",
|
|
|
+ // alarm.getDeviceId(), alarm.getAlarmType(), e.getMessage());
|
|
|
+ // }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 从告警数据中解析阈值
|
|
|
+ */
|
|
|
+ private Float parseThresholdFromAlarmData(String alarmData, String alarmType) {
|
|
|
+ if (alarmData == null || alarmData.trim().isEmpty()) {
|
|
|
+ return getDefaultThreshold(alarmType);
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ // 尝试从告警数据中提取数值
|
|
|
+ String cleanedData = alarmData.replaceAll("[^\\d.]", "");
|
|
|
+ if (!cleanedData.isEmpty()) {
|
|
|
+ float parsedValue = Float.parseFloat(cleanedData);
|
|
|
+
|
|
|
+ // 添加边界检查,防止异常值
|
|
|
+ if (isValidThreshold(parsedValue, alarmType)) {
|
|
|
+ return parsedValue;
|
|
|
+ } else {
|
|
|
+ log.debug("阈值超出合理范围,使用默认值:alarmData={}, alarmType={}, value={}",
|
|
|
+ alarmData, alarmType, parsedValue);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } catch (NumberFormatException e) {
|
|
|
+ log.debug("无法从告警数据中解析数值:alarmData={}", alarmData);
|
|
|
+ }
|
|
|
+
|
|
|
+ return getDefaultThreshold(alarmType);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 验证阈值是否在合理范围内
|
|
|
+ */
|
|
|
+ private boolean isValidThreshold(float value, String alarmType) {
|
|
|
+ AlarmType type = AlarmType.fromOriginalCode(alarmType);
|
|
|
+ return type == null || type.isValidThreshold(value);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取thresholding的默认值
|
|
|
+ */
|
|
|
+ private Float getDefaultThreshold(String alarmType) {
|
|
|
+ AlarmType type = AlarmType.fromOriginalCode(alarmType);
|
|
|
+ return type != null ? type.getDefaultThreshold() : 0.0f;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 填充lineNo字段(剩余电流、供电电缆温度、电流偏大专用)
|
|
|
+ */
|
|
|
+ private void populateLineNo(AlarmMessageVO<Integer> alarmMessageVO, BaseAlarm alarm) {
|
|
|
+ // try {
|
|
|
+ // // 从设备ID或告警数据中解析线路编号
|
|
|
+ // Integer lineNo = parseLineNoFromDeviceOrData(alarm.getDeviceId(), alarm.getAlarmData());
|
|
|
+ // alarmMessageVO.setLineNo(lineNo);
|
|
|
+ // } catch (Exception e) {
|
|
|
+ // 解析失败时设置默认值
|
|
|
+ alarmMessageVO.setLineNo(1); // 默认线路1
|
|
|
+ // log.warn("解析线路编号失败,使用默认值:设备ID={}, 错误={}", alarm.getDeviceId(), e.getMessage());
|
|
|
+ // }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 从设备ID或告警数据中解析线路编号
|
|
|
+ */
|
|
|
+ // private Integer parseLineNoFromDeviceOrData(String deviceId, String alarmData) {
|
|
|
+ // // 首先尝试从设备ID中解析
|
|
|
+ // if (deviceId != null && !deviceId.trim().isEmpty()) {
|
|
|
+ // // 假设设备ID格式可能包含线路信息,例如:DEV001_L1, DEV002_L2等
|
|
|
+ // if (deviceId.contains("_L")) {
|
|
|
+ // try {
|
|
|
+ // String linePart = deviceId.substring(deviceId.lastIndexOf("_L") + 2);
|
|
|
+ // int lineNo = Integer.parseInt(linePart);
|
|
|
+ // if (isValidLineNo(lineNo)) {
|
|
|
+ // return lineNo;
|
|
|
+ // } else {
|
|
|
+ // log.debug("线路编号超出范围,使用默认值:deviceId={}, lineNo={}", deviceId, lineNo);
|
|
|
+ // }
|
|
|
+ // } catch (NumberFormatException e) {
|
|
|
+ // log.debug("无法从设备ID中解析线路编号:deviceId={}", deviceId);
|
|
|
+ // }
|
|
|
+ // }
|
|
|
+ //
|
|
|
+ // // 或者尝试从设备ID末尾提取数字作为线路编号
|
|
|
+ // String numbers = deviceId.replaceAll("[^\\d]", "");
|
|
|
+ // if (!numbers.isEmpty()) {
|
|
|
+ // try {
|
|
|
+ // int lineNo = Integer.parseInt(numbers);
|
|
|
+ // if (isValidLineNo(lineNo)) {
|
|
|
+ // return lineNo;
|
|
|
+ // } else {
|
|
|
+ // log.debug("从设备ID提取的线路编号超出范围,使用默认值:deviceId={}, lineNo={}", deviceId, lineNo);
|
|
|
+ // }
|
|
|
+ // } catch (NumberFormatException e) {
|
|
|
+ // log.debug("无法从设备ID中提取有效线路编号:deviceId={}", deviceId);
|
|
|
+ // }
|
|
|
+ // }
|
|
|
+ // }
|
|
|
+ //
|
|
|
+ // // 然后尝试从告警数据中解析
|
|
|
+ // if (alarmData != null && !alarmData.trim().isEmpty()) {
|
|
|
+ // String numbers = alarmData.replaceAll("[^\\d]", "");
|
|
|
+ // if (!numbers.isEmpty()) {
|
|
|
+ // try {
|
|
|
+ // int lineNo = Integer.parseInt(numbers);
|
|
|
+ // if (isValidLineNo(lineNo)) {
|
|
|
+ // return lineNo;
|
|
|
+ // } else {
|
|
|
+ // log.debug("从告警数据中解析的线路编号超出范围,使用默认值:alarmData={}, lineNo={}", alarmData, lineNo);
|
|
|
+ // }
|
|
|
+ // } catch (NumberFormatException e) {
|
|
|
+ // log.debug("无法从告警数据中解析线路编号:alarmData={}", alarmData);
|
|
|
+ // }
|
|
|
+ // }
|
|
|
+ // }
|
|
|
+ //
|
|
|
+ // // 默认返回线路1
|
|
|
+ // return 1;
|
|
|
+ // }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 验证线路编号是否在有效范围内
|
|
|
+ */
|
|
|
+ private boolean isValidLineNo(int lineNo) {
|
|
|
+ return lineNo >= 1 && lineNo <= 20; // 限制在1-20范围内,符合实际情况
|
|
|
+ }
|
|
|
+}
|