新增运行策略轮询功能

This commit is contained in:
zq
2025-12-29 15:47:28 +08:00
parent 22415df926
commit 5456d4742e
13 changed files with 835 additions and 109 deletions

View File

@ -12,29 +12,45 @@ import com.xzzn.common.enums.AlarmStatus;
import com.xzzn.common.enums.ProtPlanStatus;
import com.xzzn.common.enums.StrategyStatus;
import com.xzzn.common.utils.StringUtils;
import com.xzzn.ems.domain.*;
import com.xzzn.ems.domain.EmsAlarmRecords;
import com.xzzn.ems.domain.EmsDevicesSetting;
import com.xzzn.ems.domain.EmsFaultIssueLog;
import com.xzzn.ems.domain.EmsFaultProtectionPlan;
import com.xzzn.ems.domain.EmsStrategyRunning;
import com.xzzn.ems.domain.vo.ProtectionPlanVo;
import com.xzzn.ems.domain.vo.ProtectionSettingVo;
import com.xzzn.ems.mapper.*;
import com.xzzn.ems.mapper.EmsAlarmRecordsMapper;
import com.xzzn.ems.mapper.EmsDevicesSettingMapper;
import com.xzzn.ems.mapper.EmsFaultIssueLogMapper;
import com.xzzn.ems.mapper.EmsFaultProtectionPlanMapper;
import com.xzzn.ems.mapper.EmsStrategyRunningMapper;
import com.xzzn.ems.service.IEmsFaultProtectionPlanService;
import com.xzzn.framework.manager.ModbusConnectionManager;
import com.xzzn.framework.manager.ModbusConnectionWrapper;
import com.xzzn.framework.web.service.ModbusService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.UUID;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.annotation.Resource;
import org.apache.commons.collections4.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
/**
* 告警保护方案轮询
*
@ -113,7 +129,7 @@ public class ProtectionPlanTask {
final Integer isAlertAlarm = plan.getIsAlert();
final Long status = plan.getStatus();
// 看方案是否启用,走不同判断
if (status == ProtPlanStatus.STOP.getCode()) {
if (Objects.equals(status, ProtPlanStatus.STOP.getCode())) {
// 未启用,获取方案的故障值与最新数据判断是否需要下发方案
if(checkIsNeedIssuedPlan(protSettings, siteId)){
if("3".equals(plan.getFaultLevel())){
@ -143,6 +159,9 @@ public class ProtectionPlanTask {
logger.info("<方案已启用> 方案ID:{}", plan.getId());
plan.setStatus(ProtPlanStatus.RUNNING.getCode());
emsFaultProtectionPlanMapper.updateEmsFaultProtectionPlan(plan);
// 更新该站点策略为暂停状态
updateStrategyRunningStatus(siteId, StrategyStatus.SUSPENDED.getCode());
}
}, faultDelay, TimeUnit.SECONDS);
}
@ -167,8 +186,8 @@ public class ProtectionPlanTask {
plan.setStatus(ProtPlanStatus.STOP.getCode());
plan.setUpdateBy("system");
emsFaultProtectionPlanMapper.updateEmsFaultProtectionPlan(plan);
// 更新该站点策略为启用
updateStrategyRunning(siteId);
// 更新该站点策略为启用状态
updateStrategyRunningStatus(siteId, StrategyStatus.RUNNING.getCode());
}, releaseDelay, TimeUnit.SECONDS);
}
}
@ -326,6 +345,22 @@ public class ProtectionPlanTask {
return StringUtils.getBigDecimal(obj.get(point));
}
// 更新站点策略为启用
private void updateStrategyRunningStatus(String siteId, String status) {
// 获取是否有正在运行的策略,如果有则不更改
EmsStrategyRunning query = new EmsStrategyRunning();
query.setSiteId(siteId);
query.setStatus(StrategyStatus.RUNNING.getCode().equals(status) ? StrategyStatus.SUSPENDED.getCode() : StrategyStatus.RUNNING.getCode());
List<EmsStrategyRunning> strategyRunningList = emsStrategyRunningMapper.selectEmsStrategyRunningList(query);
if (CollectionUtils.isNotEmpty(strategyRunningList)) {
// 获取已存在并且状态为:未启用和已暂停的最晚一条策略,更新为已启用
strategyRunningList.forEach(emsStrategyRunning -> {
emsStrategyRunning.setStatus(status);
emsStrategyRunningMapper.updateEmsStrategyRunning(emsStrategyRunning);
});
}
}
// 更新站点策略为启用
private void updateStrategyRunning(String siteId) {
// 获取是否有正在运行的策略,如果有则不更改

View File

@ -1,44 +1,67 @@
package com.xzzn.quartz.task;
import com.alibaba.fastjson2.JSON;
import com.xzzn.common.core.modbus.ModbusProcessor;
import com.xzzn.common.core.modbus.domain.DeviceConfig;
import com.xzzn.common.core.modbus.domain.WriteTagConfig;
import com.xzzn.common.enums.ChargeStatus;
import com.xzzn.common.enums.DeviceCategory;
import com.xzzn.common.enums.SiteDevice;
import com.xzzn.common.enums.SocLimit;
import com.xzzn.common.utils.DateUtils;
import com.xzzn.common.utils.StringUtils;
import com.xzzn.ems.domain.EmsStrategyCurve;
import com.xzzn.ems.domain.EmsAmmeterData;
import com.xzzn.ems.domain.EmsBatteryStack;
import com.xzzn.ems.domain.EmsDevicesSetting;
import com.xzzn.ems.domain.EmsPcsData;
import com.xzzn.ems.domain.EmsPointMatch;
import com.xzzn.ems.domain.EmsStrategyLog;
import com.xzzn.ems.domain.EmsStrategyTemp;
import com.xzzn.ems.domain.EmsStrategyTimeConfig;
import com.xzzn.ems.domain.vo.StrategyPowerDataVo;
import com.xzzn.ems.domain.vo.DeviceUpdateRequest;
import com.xzzn.ems.domain.vo.StrategyRunningVo;
import com.xzzn.ems.mapper.*;
import com.xzzn.framework.manager.ModbusConnectionManager;
import com.xzzn.framework.manager.MqttLifecycleManager;
import com.xzzn.framework.web.service.ModbusService;
import com.xzzn.ems.mapper.EmsAmmeterDataMapper;
import com.xzzn.ems.mapper.EmsBatteryStackMapper;
import com.xzzn.ems.mapper.EmsDevicesSettingMapper;
import com.xzzn.ems.mapper.EmsPcsDataMapper;
import com.xzzn.ems.mapper.EmsPointMatchMapper;
import com.xzzn.ems.mapper.EmsStrategyLogMapper;
import com.xzzn.ems.mapper.EmsStrategyRunningMapper;
import com.xzzn.ems.mapper.EmsStrategyTempMapper;
import com.xzzn.ems.mapper.EmsStrategyTimeConfigMapper;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
import org.apache.commons.collections4.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.time.LocalDate;
import java.time.YearMonth;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
@Component("strategyPoller")
public class StrategyPoller {
private static final Logger logger = LoggerFactory.getLogger(StrategyPoller.class);
private final MqttLifecycleManager mqttLifecycleManager;
// SOC 上下限值默认为0%-100%
private static final BigDecimal SOC_DOWN = new BigDecimal(0);
private static final BigDecimal SOC_UP = new BigDecimal(100);
// 逆变器功率下限值默认为30kW
private static final BigDecimal ANTI_REVERSE_THRESHOLD = new BigDecimal(30);
// 逆变器下限值范围默认为20%
private static final BigDecimal ANTI_REVERSE_RANGE_PERCENT = new BigDecimal(20);
// PCS功率降幅默认为10%
private static final BigDecimal ANTI_REVERSE_POWER_DOWN_PERCENT = new BigDecimal(10);
private final Map<String, BigDecimal> sitePcsPowerDown = new ConcurrentHashMap<>();
@Autowired
private ModbusConnectionManager connectionManager;
@Autowired
private ModbusService modbusService;
@Autowired
private EmsDevicesSettingMapper deviceRepo;
@Autowired
private EmsMqttMessageMapper emsMqttMessageMapper;
@Autowired
private EmsStrategyRunningMapper emsStrategyRunningMapper;
@Autowired
@ -46,15 +69,22 @@ public class StrategyPoller {
@Autowired
private EmsStrategyTimeConfigMapper emsStrategyTimeConfigMapper;
@Autowired
private EmsStrategyCurveMapper emsStrategyCurveMapper;
private EmsBatteryStackMapper emsBatteryStackMapper;
@Autowired
public StrategyPoller(MqttLifecycleManager mqttLifecycleManager) {
this.mqttLifecycleManager = mqttLifecycleManager;
}
private EmsPcsDataMapper emsPcsDataMapper;
@Autowired
private EmsDevicesSettingMapper emsDevicesMapper;
@Autowired
private EmsPointMatchMapper emsPointMatchMapper;
@Autowired
private EmsAmmeterDataMapper emsAmmeterDataMapper;
@Autowired
private EmsStrategyLogMapper emsStrategyLogMapper;
@Autowired
private ModbusProcessor modbusProcessor;
public void pollAllDevices() {
logger.info("开始执行策略数据轮询...");
logger.info("开始执行运行策略数据轮询...");
List<StrategyRunningVo> strategyRunningVoList = emsStrategyRunningMapper.getPendingPollerStrategy(null);
strategyRunningVoList.forEach(strategyVo -> {
try {
@ -62,17 +92,17 @@ public class StrategyPoller {
processData(strategyVo);
})
.exceptionally(e -> {
logger.error("策略{}轮询异常", strategyVo.getId(), e);
logger.error("运行策略{}轮询异常", strategyVo.getId(), e);
return null;
});
} catch (Exception e) {
logger.error("策略下方{}任务失败", strategyVo.getId(), e);
logger.error("运行策略{}任务失败", strategyVo.getId(), e);
}
});
}
// 处理获取到的数据发到mqtt服务上
// 处理获取到的运行策略数据modbus发送指定的命令控制设备
private void processData(StrategyRunningVo strategyVo) {
logger.info("策略下发数据处理开始");
logger.info("运行策略数据处理开始");
// 根据运行策略获取主副策略的模板数据
Long mainStrategyId = strategyVo.getMainStrategyId();
Long auxStrategyId = strategyVo.getAuxStrategyId();
@ -86,78 +116,249 @@ public class StrategyPoller {
dealStrategyCurveData(auxStrategyId, siteId);
}
// 策略数据下发-下方格式暂无
logger.info("策略下发结束");
logger.info("运行策略轮询处理结束");
}
private void dealStrategyCurveData(Long mainStrategyId, String siteId) {
// 获取当前策略的所有模板
List<Map<String, String>> temps = emsStrategyTempMapper.getTempNameList(mainStrategyId,siteId);
if (temps != null && temps.size() > 0) {
for (Map<String, String> temp : temps) {
String tempId = temp.get("templateId");
List<EmsStrategyTimeConfig> timeConfigs = emsStrategyTimeConfigMapper.getAllTimeConfigByTempId(tempId);
if (timeConfigs != null && timeConfigs.size() > 0) {
for (EmsStrategyTimeConfig timeConfig : timeConfigs) {
EmsStrategyCurve curve = new EmsStrategyCurve();
curve.setStrategyId(mainStrategyId);
curve.setSiteId(siteId);
curve.setTemplateId(tempId);
curve.setCreateBy("system");
curve.setCreateTime(DateUtils.getNowDate());
curve.setUpdateBy("system");
curve.setUpdateTime(DateUtils.getNowDate());
// 时间设置
int month = Integer.parseInt(timeConfig.getMonth().toString());
String[] dateList= dealWithMonth(month);
curve.setMonth(Long.valueOf(month));
curve.setStartDate(DateUtils.dateTime(DateUtils.YYYY_MM_DD,dateList[0]));
curve.setEndDate(DateUtils.dateTime(DateUtils.YYYY_MM_DD,dateList[1]));
// powerData-存json格式
List<EmsStrategyTemp> powerConfig = emsStrategyTempMapper.selectStrategyTempByTempId(tempId);
List<StrategyPowerDataVo> powerDataVoList = new ArrayList<>();
for (int i = 0; i < powerConfig.size(); i++) {
EmsStrategyTemp powerTemp = powerConfig.get(i);
StrategyPowerDataVo powerDataVo = new StrategyPowerDataVo();
powerDataVo.setPowerData(powerTemp.getChargeDischargePower());
powerDataVo.setEndTime(DateUtils.parseDateToStr("HH:mm:ss",powerTemp.getEndTime()));
powerDataVo.setStartTime(DateUtils.parseDateToStr("HH:mm:ss",powerTemp.getStartTime()));
powerDataVoList.add(powerDataVo);
private void dealStrategyCurveData(Long strategyId, String siteId) {
// 1.获取当前策略的所有模板
List<Map<String, String>> temps = emsStrategyTempMapper.getTempNameList(strategyId, siteId);
if (CollectionUtils.isEmpty(temps)) {
logger.info("当前站点: {}, 策略: {} 没有模板数据", siteId, strategyId);
return;
}
for (Map<String, String> temp : temps) {
// 2.查询当月配置的运行策略
String tempId = temp.get("templateId");
int month = LocalDateTime.now().getMonthValue();
List<EmsStrategyTimeConfig> timeConfigs = emsStrategyTimeConfigMapper.getTimeConfigByTempIdAndMonth(tempId, month);
if (CollectionUtils.isEmpty(timeConfigs)) {
continue;
}
logger.info("当前站点: {}, 策略: {}, {}月配置模版:{}", siteId, strategyId, month, tempId);
// 3.查询当月配置的运行策略时间阶段数据
List<EmsStrategyTemp> powerConfig = emsStrategyTempMapper.selectStrategyTempByTempId(tempId);
if (CollectionUtils.isEmpty(powerConfig)) {
logger.info("当前站点: {}, 策略: {}, 模版:{} 未配置数据", siteId, strategyId, tempId);
continue;
}
// 4.遍历时间段数据,判断当前时间是否在时间段内,在时间段内的进行处理
for (EmsStrategyTemp emsStrategyTemp : powerConfig) {
if (emsStrategyTemp.getStartTime() == null || emsStrategyTemp.getEndTime() == null) {
logger.info("当前站点: {}, 策略: {}, 模版:{} 未配置时间阶段数据", siteId, strategyId, tempId);
continue;
}
// 判断当前时间是否在时间段内
if (!isTimeInRange(LocalTime.now(), emsStrategyTemp.getStartTime(), emsStrategyTemp.getEndTime())) {
continue;
}
// 查询PCS设备信息
List<EmsPcsData> pcsDataList = emsPcsDataMapper.getSitePcsDataInfo(siteId);
if (CollectionUtils.isEmpty(pcsDataList)) {
logger.info("当前站点: {} 未配置PCS设备", siteId);
continue;
}
// 判断SOC上限和下限是否在范围内
if (isSocInRange(emsStrategyTemp)) {
BigDecimal avgChargeDischargePower = emsStrategyTemp.getChargeDischargePower().divide(new BigDecimal(pcsDataList.size()));
for (EmsPcsData pcsData : pcsDataList) {
if (pcsData.getClusterNum() == null || pcsData.getClusterNum() < 1) {
logger.info("当前站点: {}, PCS设备: {} 未获取电池簇数量", siteId, pcsData.getDeviceId());
continue;
}
// 平均功率值,根据电池簇数量进行平均分配
avgChargeDischargePower = avgChargeDischargePower.divide(new BigDecimal(pcsData.getClusterNum()));
// 根据充电状态,处理数据
if (ChargeStatus.CHARGING.getCode().equals(emsStrategyTemp.getChargeStatus())) {
// 发送Modbus命令控制设备-充电
sendModbusCommand(Collections.singletonList(pcsData), ChargeStatus.CHARGING, avgChargeDischargePower, emsStrategyTemp, false);
} else if (ChargeStatus.DISCHARGING.getCode().equals(emsStrategyTemp.getChargeStatus())) {
// 判断是否需要防逆流PCS降功率运行
boolean needAntiReverseFlow = isNeedAntiReverseFlow(emsStrategyTemp);
if (needAntiReverseFlow) {
BigDecimal powerDown = ANTI_REVERSE_POWER_DOWN_PERCENT;
// 查询站点PCS功率降幅记录如果有则累加增幅
List<EmsStrategyLog> strategyLogList = getStrategyLog(pcsData.getDeviceId(), emsStrategyTemp.getChargeStatus(), emsStrategyTemp, needAntiReverseFlow);
if (CollectionUtils.isNotEmpty(strategyLogList)) {
// 判断上次防逆流时间是否已经过了15分钟
if (DateUtils.differentMinutesByMillisecond(strategyLogList.get(0).getExecutionDate(), new Date()) < 15) {
continue;
}
powerDown = powerDown.multiply(new BigDecimal(strategyLogList.size() + 1));
}
avgChargeDischargePower = avgChargeDischargePower.subtract(avgChargeDischargePower.multiply(powerDown).divide(new BigDecimal(100)));
}
if (BigDecimal.ZERO.compareTo(avgChargeDischargePower) == 0) {
// 如果已经降功率到0则设备直接待机
// 发送Modbus命令控制设备-待机
sendModbusCommand(Collections.singletonList(pcsData), ChargeStatus.STANDBY, BigDecimal.ZERO, emsStrategyTemp, needAntiReverseFlow);
} else {
// 发送Modbus命令控制设备-放电
sendModbusCommand(Collections.singletonList(pcsData), ChargeStatus.DISCHARGING, avgChargeDischargePower, emsStrategyTemp, needAntiReverseFlow);
}
} else {
// 发送Modbus命令控制设备-待机
sendModbusCommand(Collections.singletonList(pcsData), ChargeStatus.STANDBY, BigDecimal.ZERO, emsStrategyTemp, false);
}
curve.setPowerData(powerDataVoList !=null ? JSON.toJSON(powerDataVoList).toString() : "");
// 记录推送记录
emsStrategyCurveMapper.insertEmsStrategyCurve(curve);
// 设置已下发
timeConfig.setIsPost(0);
emsStrategyTimeConfigMapper.updateEmsStrategyTimeConfig(timeConfig);
}
} else {
// 发送Modbus命令控制设备-待机
sendModbusCommand(pcsDataList, ChargeStatus.STANDBY, BigDecimal.ZERO, emsStrategyTemp, false);
}
}
}
}
private String[] dealWithMonth(int month) {
// 获取当前年份
int currentYear = LocalDate.now().getYear();
private void saveStrategyLog(String deviceId, BigDecimal chargeDischargePower, String chargeStatus,
EmsStrategyTemp strategyTemp, boolean needAntiReverseFlow) {
EmsStrategyLog log = new EmsStrategyLog();
log.setStrategyId(strategyTemp.getStrategyId());
log.setTemplateId(strategyTemp.getTemplateId());
log.setSiteId(strategyTemp.getSiteId());
log.setDeviceId(deviceId);
log.setStartTime(strategyTemp.getStartTime());
log.setEndTime(strategyTemp.getEndTime());
log.setChargeDischargePower(chargeDischargePower);
log.setChargeStatus(chargeStatus);
log.setExecutionDate(DateUtils.toDate(LocalDateTime.now()));
log.setAntiReverse(needAntiReverseFlow ? 1 : 0);
emsStrategyLogMapper.insertEmsStrategyLog(log);
}
private List<EmsStrategyLog> getStrategyLog(String deviceId, String chargeStatus,
EmsStrategyTemp strategyTemp, boolean needAntiReverseFlow) {
EmsStrategyLog query = new EmsStrategyLog();
query.setStrategyId(strategyTemp.getStrategyId());
query.setTemplateId(strategyTemp.getTemplateId());
query.setSiteId(strategyTemp.getSiteId());
query.setDeviceId(deviceId);
query.setStartTime(strategyTemp.getStartTime());
query.setEndTime(strategyTemp.getEndTime());
query.setChargeStatus(chargeStatus);
query.setExecutionDate(DateUtils.toDate(LocalDateTime.now()));
query.setAntiReverse(needAntiReverseFlow ? 1 : 0);
return emsStrategyLogMapper.selectEmsStrategyLogList(query);
}
// 创建YearMonth对象表示当年指定的月份
YearMonth yearMonth = YearMonth.of(currentYear, month);
private boolean isNeedAntiReverseFlow(EmsStrategyTemp emsStrategyTemp) {
EmsAmmeterData emsAmmeterData = emsAmmeterDataMapper.getLastData(emsStrategyTemp.getSiteId(), SiteDevice.LOAD.name());
if (emsAmmeterData == null || emsAmmeterData.getTotalActivePower() == null) {
logger.info("当前站点: {}, 未获取到最新电表数据", emsStrategyTemp.getSiteId());
return false;
}
// 获取当前设定的防逆流阈值(30kW)
BigDecimal threshold = ANTI_REVERSE_THRESHOLD;
// 计算20%范围的上限(36kW)
BigDecimal upperLimit = threshold.multiply(ANTI_REVERSE_RANGE_PERCENT).divide(new BigDecimal(100)).add(threshold);
// 获取当月的第一天和最后一天
LocalDate firstDay = yearMonth.atDay(1);
LocalDate lastDay = yearMonth.atEndOfMonth();
// 判断电网电表正向有功功率是否小于36kW(接近30kW的20%范围)
return emsAmmeterData.getTotalActivePower().compareTo(upperLimit) < 0;
}
// 定义日期格式(年月日)
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
public List<WriteTagConfig> getWriteTags(List<EmsPointMatch> pointMatchList,
ChargeStatus chargeStatus, BigDecimal chargeDischargePower) {
List<WriteTagConfig> writeTags = new ArrayList<>();
for (EmsPointMatch pointMatch : pointMatchList) {
WriteTagConfig writeTag = new WriteTagConfig();
writeTag.setAddress(pointMatch.getIpAddress());
if (ChargeStatus.CHARGING.equals(chargeStatus)) {
writeTag.setValue(chargeDischargePower);
} else if (ChargeStatus.DISCHARGING.equals(chargeStatus)) {
writeTag.setValue(chargeDischargePower.negate());
} else {
// 待机状态-电池簇PCS有功功率给定置0
writeTag.setValue(chargeDischargePower);
}
writeTags.add(writeTag);
}
return writeTags;
}
// 格式化日期
return new String[]{
firstDay.format(formatter),
lastDay.format(formatter)
};
private List<String> getMatchFields(Integer clusterNum) {
List<String> matchFields = new ArrayList<>();
for (int i = 1; i <= clusterNum; i++) {
//电池簇PCS有功功率给定
matchFields.add("cluster"+ i +"_active_power");
}
return matchFields;
}
public DeviceConfig getDeviceConfig(EmsPcsData pcsData, ChargeStatus chargeStatus, BigDecimal chargeDischargePower) {
EmsDevicesSetting device = emsDevicesMapper.getDeviceBySiteAndDeviceId(pcsData.getDeviceId(), pcsData.getSiteId());
if (device == null) {
logger.info("当前站点: {}, PCS设备: {} 未找到对应设备配置信息", pcsData.getSiteId(), pcsData.getDeviceId());
return null;
}
DeviceUpdateRequest query = new DeviceUpdateRequest();
query.setSiteId(device.getSiteId());
query.setDeviceId(device.getDeviceId());
query.setMatchFields(getMatchFields(pcsData.getClusterNum()));
query.setDeviceCategory(DeviceCategory.PCS.getCode());
List<EmsPointMatch> pointMatchList = emsPointMatchMapper.selectDeviceStatusPoint(query);
if (CollectionUtils.isEmpty(pointMatchList)) {
logger.info("当前站点: {}, PCS设备: {} 未找到对应设备点位字段配置", pcsData.getSiteId(), pcsData.getDeviceId());
return null;
}
if (pointMatchList.size() != pcsData.getClusterNum()) {
logger.info("当前站点: {}, PCS设备: {} 设备点位字段配置数量与电池簇数不一致", pcsData.getSiteId(), pcsData.getDeviceId());
}
DeviceConfig deviceConfig = new DeviceConfig();
deviceConfig.setDeviceNumber(device.getDeviceId());
deviceConfig.setDeviceName(device.getDeviceName());
deviceConfig.setSlaveId(device.getSlaveId().intValue());
deviceConfig.setHost(device.getIpAddress());
deviceConfig.setPort(device.getIpPort().intValue());
deviceConfig.setWriteTags(getWriteTags(pointMatchList, chargeStatus, chargeDischargePower));
return deviceConfig;
}
private void sendModbusCommand(List<EmsPcsData> pcsDataList, ChargeStatus chargeStatus, BigDecimal chargeDischargePower,
EmsStrategyTemp emsStrategyTemp, boolean needAntiReverseFlow) {
for (EmsPcsData pcsData : pcsDataList) {
List<EmsStrategyLog> strategyLogList = getStrategyLog(pcsData.getDeviceId(), chargeStatus.getCode(), emsStrategyTemp, needAntiReverseFlow);
if (CollectionUtils.isNotEmpty(strategyLogList) && !ChargeStatus.DISCHARGING.equals(chargeStatus) && !needAntiReverseFlow) {
logger.info("当前站点: {}, PCS设备: {} 当前时间段已存在策略执行记录,不再重复执行", pcsData.getSiteId(), pcsData.getDeviceId());
continue;
}
DeviceConfig deviceConfig = getDeviceConfig(pcsData, chargeStatus, chargeDischargePower);
if (deviceConfig == null) {
continue;
}
boolean result = modbusProcessor.writeDataToDevice(deviceConfig);
if (!result) {
logger.info("当前站点: {}, PCS设备: {} modbus控制设备{}指令发送失败", pcsData.getSiteId(), pcsData.getDeviceId(), chargeStatus.getInfo());
}
// 记录策略执行日志
saveStrategyLog(pcsData.getDeviceId(), chargeDischargePower, chargeStatus.getCode(), emsStrategyTemp, needAntiReverseFlow);
}
}
// 判断当前时间是否在时间范围内
private static boolean isTimeInRange(LocalTime now, Date startTime, Date endTime) {
ZoneId zoneId = ZoneId.of("Asia/Shanghai");
LocalTime startLocalTime = startTime.toInstant()
.atZone(zoneId)
.toLocalTime();
LocalTime endLocalTime = endTime.toInstant()
.atZone(zoneId)
.toLocalTime();
return now.equals(startLocalTime) || (now.isAfter(startLocalTime) && now.isBefore(endLocalTime));
}
// 判断SOC上限和下限是否在范围内
private boolean isSocInRange(EmsStrategyTemp emsStrategyTemp) {
BigDecimal socDown = SOC_DOWN;
BigDecimal socUp = SOC_UP;
if (SocLimit.ON.getCode().equals(emsStrategyTemp.getSdcLimit())) {
socDown = emsStrategyTemp.getSdcDown();
socUp = emsStrategyTemp.getSdcUp();
}
// 查询电池堆(BMSD) SOC
EmsBatteryStack emsBatteryStack = emsBatteryStackMapper.getSiteSumStackInfo(emsStrategyTemp.getSiteId());
if (emsBatteryStack != null && emsBatteryStack.getStackSoc() != null) {
return emsBatteryStack.getStackSoc().compareTo(socDown) > 0 && emsBatteryStack.getStackSoc().compareTo(socUp) < 0;
}
return true;
}
}