解决保护方案告警不触发问题

This commit is contained in:
zq
2026-01-16 17:06:31 +08:00
parent fb64be5a5a
commit dd0132ab2f
6 changed files with 108 additions and 19 deletions

View File

@ -28,6 +28,7 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
@ -51,12 +52,12 @@ public class ModbusProcessor {
public boolean writeDataToDevice(DeviceConfig config) {
logger.info("writeDataToDevice: {}", JSON.toJSONString(config));
ModbusMaster master = null;
boolean result = true;
boolean result;
try {
master = connectionManager.borrowMaster(config);
// 设置了Modbus通信的超时时间为3000毫秒3秒)。当主设备与从设备通信时,若在3秒内未收到响应,则认为通信超时并抛出异常。这有助于避免长时间等待无响应的设备。
master.setTimeout(5000);
writeTagValue(master, config, config.getWriteTags());
// 设置了Modbus通信的超时时间为1000毫秒1秒)。当主设备与从设备通信时,若在1秒内未收到响应,则认为通信超时并抛出异常。这有助于避免长时间等待无响应的设备。
master.setTimeout(1000);
result = writeTagValue(master, config, config.getWriteTags());
} catch (Exception e) {
logger.error("Failed to borrow connection or write to devices '{}'", config.getDeviceName(), e);
result = false;
@ -70,7 +71,33 @@ public class ModbusProcessor {
return result;
}
public void writeTagValue(ModbusMaster master, DeviceConfig config, List<WriteTagConfig> tags) {
public boolean writeDataToDeviceWithRetry(DeviceConfig config) {
logger.info("writeDataToDevice: {}", JSON.toJSONString(config));
ModbusMaster master = null;
boolean result;
try {
master = connectionManager.borrowMaster(config);
master.setTimeout(1000); // 设置超时时间
// 使用重试装饰器
ModbusMaster finalMaster = master;
result = RetryableModbusOperation.executeWithRetry(() -> {
return writeTagValue(finalMaster, config, config.getWriteTags());
}, 1); // 最大重试1次共2次尝试
} catch (Exception e) {
logger.error("Failed to borrow connection or write to devices '{}'", config.getDeviceName(), e);
result = false;
} finally {
if (master != null) {
connectionManager.returnMaster(config, master);
}
}
return result;
}
public boolean writeTagValue(ModbusMaster master, DeviceConfig config, List<WriteTagConfig> tags) {
tags.forEach(tag -> {
Map<Integer, RegisterType> type = ModBusType.REGISTER_TYPE;
int firstDigit = Integer.parseInt(tag.getAddress().substring(0, 1));
@ -79,7 +106,8 @@ public class ModbusProcessor {
logger.info("Register type: {}, address: {}, firstDigit: {}", registerType, tag.getAddress(), firstDigit);
switch (registerType) {
case COIL: {
writeCoilRequest(master, config.getSlaveId(), address, Boolean.parseBoolean(String.valueOf(tag.getValue())));
boolean result = writeCoilRequest(master, config.getSlaveId(), address, Boolean.parseBoolean(String.valueOf(tag.getValue())));
tag.setWrite(result);
break;
}
case HOLDING_REGISTER: {
@ -89,7 +117,8 @@ public class ModbusProcessor {
if (doubleValue < -32768 || doubleValue > 32767) {
logger.warn("Value {} out of range for 16-bit signed register at address {}", doubleValue, address);
}
writeRegisterRequest(master, config.getSlaveId(), address, (int) doubleValue);
boolean result = writeRegisterRequest(master, config.getSlaveId(), address, (int) doubleValue);
tag.setWrite(result);
break;
}
default:
@ -97,9 +126,15 @@ public class ModbusProcessor {
break;
}
});
List<WriteTagConfig> collect = tags.stream().filter(tag -> !Objects.equals(tag.isWrite(), true)).collect(Collectors.toList());
if (!collect.isEmpty()) {
return false;
}
return true;
}
public static void writeCoilRequest(ModbusMaster master, int slaveId, int address, boolean value) {
public static boolean writeCoilRequest(ModbusMaster master, int slaveId, int address, boolean value) {
try {
WriteCoilRequest request = new WriteCoilRequest(slaveId, address, value);
WriteCoilResponse response = (WriteCoilResponse)master.send(request);
@ -107,10 +142,12 @@ public class ModbusProcessor {
logger.info("Write coil failed: " + response.getExceptionMessage());
} else {
logger.info("Write coil successful");
return true;
}
} catch (Exception e) {
logger.error("Failed to write coil value '{}' to address '{}'", value, address, e);
}
return false;
}
public static void writeCoilsRequest(ModbusMaster master, int slaveId, int address, boolean[] values) {
@ -127,7 +164,7 @@ public class ModbusProcessor {
}
}
public static void writeRegisterRequest(ModbusMaster master, int slaveId, int address, int value) {
public static boolean writeRegisterRequest(ModbusMaster master, int slaveId, int address, int value) {
try {
WriteRegisterRequest request = new WriteRegisterRequest(slaveId, address, value);
WriteRegisterResponse response = (WriteRegisterResponse)master.send(request);
@ -135,10 +172,12 @@ public class ModbusProcessor {
logger.info("Write register failed: " + response.getExceptionMessage());
} else {
logger.info("Write register successful");
return true;
}
} catch (Exception e) {
logger.error("Failed to write register value '{}' to address '{}'", value, address, e);
}
return false;
}
public static void writeRegistersRequest(ModbusMaster master, int slaveId, int address, short[] values) {
@ -181,8 +220,8 @@ public class ModbusProcessor {
public ModbusMaster borrowMaster(DeviceConfig config) throws Exception {
ModbusMaster master = connectionManager.borrowMaster(config);
// 设置了Modbus通信的超时时间为3000毫秒3秒)。当主设备与从设备通信时,若在3秒内未收到响应,则认为通信超时并抛出异常。这有助于避免长时间等待无响应的设备。
master.setTimeout(10000);
// 设置了Modbus通信的超时时间为5000毫秒5秒)。当主设备与从设备通信时,若在5秒内未收到响应,则认为通信超时并抛出异常。这有助于避免长时间等待无响应的设备。
master.setTimeout(5000);
return master;
}

View File

@ -0,0 +1,37 @@
package com.xzzn.common.core.modbus;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Modbus重试
*
*/
public class RetryableModbusOperation {
private static final Logger logger = LoggerFactory.getLogger(RetryableModbusOperation.class);
public interface ModbusOperation<T> {
T execute() throws Exception;
}
public static <T> T executeWithRetry(ModbusOperation<T> operation, int maxRetries) {
int retryCount = 0;
Exception lastException = null;
while (retryCount <= maxRetries) {
try {
return operation.execute();
} catch (Exception e) {
lastException = e;
retryCount++;
if (retryCount <= maxRetries) {
logger.info("Operation failed, retrying... (Attempt {})", retryCount);
}
}
}
logger.error("Max retries ({}) reached. Last error: {}", maxRetries,
lastException != null ? lastException.getMessage() : "Unknown");
throw new RuntimeException("Operation failed after " + maxRetries + " retries", lastException);
}
}

View File

@ -3,6 +3,7 @@ package com.xzzn.common.core.modbus.domain;
public class WriteTagConfig {
private Object value;
private String address;
private boolean isWrite;
public Object getValue() {
return value;
@ -19,4 +20,12 @@ public class WriteTagConfig {
public void setAddress(String address) {
this.address = address;
}
public boolean isWrite() {
return isWrite;
}
public void setWrite(boolean write) {
isWrite = write;
}
}

View File

@ -230,7 +230,7 @@ public class ModbusPoller {
// 存放mqtt原始每个设备最晚一次数据便于后面点位获取数据
redisCache.setCacheObject(RedisKeyConstants.ORIGINAL_MQTT_DATA + siteId + "_" + deviceNumber, obj);
// 存放每次同步数据,失效时间(同同步时间)-用于判断是否正常同步数据和保护策略查询
redisCache.setCacheObject(RedisKeyConstants.SYNC_DATA_ALARM + siteId + "_" + deviceNumber, obj, 1, TimeUnit.MINUTES);
redisCache.setCacheObject(RedisKeyConstants.SYNC_DATA + siteId + "_" + deviceNumber, obj, 1, TimeUnit.MINUTES);
log.info("数据已成功存储在Redis: {}", deviceNumber);
} catch (Exception e) {
log.error("无法在设备的Redis中存储数据: {}", deviceNumber, e);

View File

@ -89,9 +89,7 @@ public class ProtectionPlanTask {
Long planId = 0L;
try {
// 获取所有方案,轮询
EmsFaultProtectionPlan emsFaultProtectionPlan = new EmsFaultProtectionPlan();
emsFaultProtectionPlan.setSiteId("021_DDS_01");
List<EmsFaultProtectionPlan> planList = iEmsFaultProtectionPlanService.selectEmsFaultProtectionPlanList(emsFaultProtectionPlan);
List<EmsFaultProtectionPlan> planList = iEmsFaultProtectionPlanService.selectEmsFaultProtectionPlanList(null);
for (EmsFaultProtectionPlan plan : planList) {
planId = plan.getId();
@ -154,7 +152,7 @@ public class ProtectionPlanTask {
// 是否有保护方案有则通过modbus连接设备下发方案
String protPlanJson = plan.getProtectionPlan();
if (protPlanJson != null && !protPlanJson.isEmpty()) {
if (protPlanJson != null && !protPlanJson.isEmpty() && !"[]".equals(protPlanJson)) {
logger.info("<下发保护方案> 方案内容:{}", protPlanJson);
executeProtectionActions(protPlanJson,siteId,plan.getId(),plan.getFaultLevel()); // 执行Modbus指令
}

View File

@ -161,6 +161,7 @@ public class StrategyPoller {
}
// 判断当前时间是否在时间段内
if (!isTimeInRange(LocalTime.now(), emsStrategyTemp.getStartTime(), emsStrategyTemp.getEndTime())) {
logger.info("当前站点: {}, 策略: {}, 时间段:{} 不在时间段内", siteId, strategyId, emsStrategyTemp.getStartTime() + "-" + emsStrategyTemp.getEndTime());
continue;
}
// 查询PCS设备信息
@ -420,10 +421,14 @@ public class StrategyPoller {
boolean result = modbusProcessor.writeDataToDevice(deviceConfig);
if (!result) {
logger.info("当前站点: {}, PCS设备: {} modbus控制设备{}指令发送失败", siteId, deviceId, chargeStatus.getInfo());
continue;
} else {
if (ChargeStatus.STANDBY.equals(chargeStatus)) {
// 待机,先写功率值,再关机
switchDevice(pcsDevice, pcsSetting, WorkStatus.STOP);
if (!switchDevice(pcsDevice, pcsSetting, WorkStatus.STOP)) {
logger.info("当前站点: {}, PCS设备: {} modbus控制设备{}指令发送失败", siteId, deviceId, WorkStatus.STOP.getInfo());
continue;
}
}
}
// 记录策略执行日志
@ -432,18 +437,19 @@ public class StrategyPoller {
}
//设备开关机
private void switchDevice(EmsDevicesSetting pcsDevice, EmsPcsSetting pcsSetting, WorkStatus workStatus) {
private boolean switchDevice(EmsDevicesSetting pcsDevice, EmsPcsSetting pcsSetting, WorkStatus workStatus) {
String siteId = pcsDevice.getSiteId();
String deviceId = pcsDevice.getDeviceId();
pcsDevice.setWorkStatus(workStatus.getCode());
DeviceConfig deviceConfig = getDeviceConfig(siteId, deviceId, pcsDevice, pcsSetting , null, 1);
if (deviceConfig == null) {
return;
return false;
}
boolean result = modbusProcessor.writeDataToDevice(deviceConfig);
if (!result) {
logger.info("当前站点: {}, PCS设备: {} modbus控制设备{}指令发送失败", siteId, deviceConfig, workStatus.getInfo());
}
return result;
}
// 判断当前时间是否在时间范围内