diff --git a/ems-quartz/src/main/java/com/xzzn/quartz/task/StrategyPoller.java b/ems-quartz/src/main/java/com/xzzn/quartz/task/StrategyPoller.java index 9a84f60..8c5163e 100644 --- a/ems-quartz/src/main/java/com/xzzn/quartz/task/StrategyPoller.java +++ b/ems-quartz/src/main/java/com/xzzn/quartz/task/StrategyPoller.java @@ -9,6 +9,7 @@ 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.enums.WorkStatus; import com.xzzn.common.utils.DateUtils; import com.xzzn.common.utils.StringUtils; import com.xzzn.ems.domain.EmsAmmeterData; @@ -57,6 +58,8 @@ public class StrategyPoller { private static final BigDecimal ANTI_REVERSE_THRESHOLD = new BigDecimal(30); // 逆变器下限值范围,默认为20% private static final BigDecimal ANTI_REVERSE_RANGE_PERCENT = new BigDecimal(20); + // 逆变器功率上限值,默认为50kW + private static final BigDecimal ANTI_REVERSE_UP = new BigDecimal(50); // PCS功率降幅,默认为10% private static final BigDecimal ANTI_REVERSE_POWER_DOWN_PERCENT = new BigDecimal(10); @@ -170,47 +173,74 @@ public class StrategyPoller { // 根据充电状态,处理数据 if (ChargeStatus.CHARGING.getCode().equals(emsStrategyTemp.getChargeStatus())) { // 发送Modbus命令控制设备-充电 - sendModbusCommand(Collections.singletonList(pcsDevice), pcsSetting, ChargeStatus.CHARGING, avgChargeDischargePower, emsStrategyTemp, false); + sendModbusCommand(Collections.singletonList(pcsDevice), pcsSetting, ChargeStatus.CHARGING, avgChargeDischargePower, emsStrategyTemp, false, null); } else if (ChargeStatus.DISCHARGING.getCode().equals(emsStrategyTemp.getChargeStatus())) { - // 判断是否需要防逆流,PCS降功率运行 - boolean needAntiReverseFlow = isNeedAntiReverseFlow(emsStrategyTemp); - if (needAntiReverseFlow) { - BigDecimal powerDown = ANTI_REVERSE_POWER_DOWN_PERCENT; - // 查询站点PCS功率降幅记录,如果有则累加增幅 - List strategyLogList = getStrategyLog(pcsDevice.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)); + boolean needAntiReverseFlow = false; + Integer powerDownType = null; + BigDecimal chargeDischargePower = avgChargeDischargePower; + // 查询策略运行日志 + EmsStrategyLog lastStrategyLog = getLastStrategyLog(pcsDevice.getDeviceId(), emsStrategyTemp); + if (lastStrategyLog != null) { + // 如果当前时间段已经进入待机状态,则不处理 + if (ChargeStatus.STANDBY.getCode().equals(lastStrategyLog.getChargeStatus())) { + continue; } - avgChargeDischargePower = avgChargeDischargePower.subtract(avgChargeDischargePower.multiply(powerDown).divide(new BigDecimal(100))); + chargeDischargePower = lastStrategyLog.getChargeDischargePower(); + powerDownType = lastStrategyLog.getPowerDownType(); } - if (BigDecimal.ZERO.compareTo(avgChargeDischargePower) == 0) { + + // 查询电网电表的正向有功功率 + EmsAmmeterData emsAmmeterData = emsAmmeterDataMapper.getLastData(emsStrategyTemp.getSiteId(), SiteDevice.LOAD.name()); + if (emsAmmeterData == null || emsAmmeterData.getTotalActivePower() == null) { + logger.info("当前站点: {}, 未获取到最新电表数据", emsStrategyTemp.getSiteId()); + } else { + // 判断是否需要防逆流 + needAntiReverseFlow = isNeedAntiReverseFlow(emsAmmeterData.getTotalActivePower()); + BigDecimal power = avgChargeDischargePower.multiply(ANTI_REVERSE_POWER_DOWN_PERCENT).divide(new BigDecimal(100)); + if (needAntiReverseFlow) { + // 降功率 + chargeDischargePower = chargeDischargePower.subtract(power); + powerDownType = 0; + } else { + // 判断是否需要增加功率 + if (powerDownType != null && emsAmmeterData.getTotalActivePower().compareTo(ANTI_REVERSE_UP) < 0) { + if (chargeDischargePower.compareTo(avgChargeDischargePower) == 0) { + // 功率增加到平均值则停止 + continue; + } + // 增加功率 + chargeDischargePower = chargeDischargePower.add(power); + powerDownType = 1; + needAntiReverseFlow = true; + } + } + } + + if (BigDecimal.ZERO.compareTo(chargeDischargePower) == 0) { // 如果已经降功率到0,则设备直接待机 // 发送Modbus命令控制设备-待机 - sendModbusCommand(Collections.singletonList(pcsDevice), pcsSetting, ChargeStatus.STANDBY, BigDecimal.ZERO, emsStrategyTemp, needAntiReverseFlow); + sendModbusCommand(Collections.singletonList(pcsDevice), pcsSetting, ChargeStatus.STANDBY, BigDecimal.ZERO, emsStrategyTemp, needAntiReverseFlow, powerDownType); } else { // 发送Modbus命令控制设备-放电 - sendModbusCommand(Collections.singletonList(pcsDevice), pcsSetting, ChargeStatus.DISCHARGING, avgChargeDischargePower, emsStrategyTemp, needAntiReverseFlow); + sendModbusCommand(Collections.singletonList(pcsDevice), pcsSetting, ChargeStatus.DISCHARGING, chargeDischargePower, emsStrategyTemp, needAntiReverseFlow, powerDownType); } } else { // 发送Modbus命令控制设备-待机 - sendModbusCommand(Collections.singletonList(pcsDevice), pcsSetting, ChargeStatus.STANDBY, BigDecimal.ZERO, emsStrategyTemp, false); + sendModbusCommand(Collections.singletonList(pcsDevice), pcsSetting, ChargeStatus.STANDBY, BigDecimal.ZERO, emsStrategyTemp, false, null); } } } else { // 发送Modbus命令控制设备-待机 - sendModbusCommand(pcsDeviceList, null, ChargeStatus.STANDBY, BigDecimal.ZERO, emsStrategyTemp, false); + sendModbusCommand(pcsDeviceList, null, ChargeStatus.STANDBY, BigDecimal.ZERO, emsStrategyTemp, false, null); } } } } + private void saveStrategyLog(String deviceId, BigDecimal chargeDischargePower, String chargeStatus, - EmsStrategyTemp strategyTemp, boolean needAntiReverseFlow) { + EmsStrategyTemp strategyTemp, boolean needAntiReverseFlow, Integer powerDownType) { EmsStrategyLog log = new EmsStrategyLog(); log.setStrategyId(strategyTemp.getStrategyId()); log.setTemplateId(strategyTemp.getTemplateId()); @@ -222,6 +252,7 @@ public class StrategyPoller { log.setChargeStatus(chargeStatus); log.setExecutionDate(DateUtils.toDate(LocalDateTime.now())); log.setAntiReverse(needAntiReverseFlow ? 1 : 0); + log.setPowerDownType(powerDownType); emsStrategyLogMapper.insertEmsStrategyLog(log); } @@ -240,49 +271,72 @@ public class StrategyPoller { return emsStrategyLogMapper.selectEmsStrategyLogList(query); } - 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; - } + private EmsStrategyLog getLastStrategyLog(String deviceId, EmsStrategyTemp strategyTemp) { + 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.setExecutionDate(DateUtils.toDate(LocalDateTime.now())); + return emsStrategyLogMapper.getLastStrategyLog(query); + } + + private boolean isNeedAntiReverseFlow(BigDecimal totalActivePower) { // 获取当前设定的防逆流阈值(30kW) BigDecimal threshold = ANTI_REVERSE_THRESHOLD; // 计算20%范围的上限(36kW) BigDecimal upperLimit = threshold.multiply(ANTI_REVERSE_RANGE_PERCENT).divide(new BigDecimal(100)).add(threshold); // 判断电网电表正向有功功率是否小于36kW(接近30kW的20%范围) - return emsAmmeterData.getTotalActivePower().compareTo(upperLimit) < 0; + return totalActivePower.compareTo(upperLimit) < 0; } - public List getWriteTags(EmsPcsSetting pcsSetting, - ChargeStatus chargeStatus, BigDecimal chargeDischargePower) { + public List getSwitchDeviceWriteTags(EmsPcsSetting pcsSetting, String workStatus) { + List writeTags = new ArrayList<>(); + BigDecimal power; + WriteTagConfig writeTag = new WriteTagConfig(); + writeTag.setAddress(pcsSetting.getPointAddress()); + if (WorkStatus.NORMAL.getCode().equals(workStatus)) { + // 开机 + writeTag.setValue(pcsSetting.getStartCommand()); + power = pcsSetting.getStartPower(); + } else { + // 关机 + writeTag.setValue(pcsSetting.getStopCommand()); + power = pcsSetting.getStopPower(); + } + writeTags.add(writeTag); + JSONArray array = JSON.parseArray(pcsSetting.getClusterPointAddress()); + for (int i = 0; i < pcsSetting.getClusterNum(); i++) { + Object clusterPointAddress = array.get(i); + WriteTagConfig clusterWriteTag = new WriteTagConfig(); + clusterWriteTag.setAddress(String.valueOf(clusterPointAddress)); + // 电池簇PCS有功功率给定置0 + if (power == null) { + power = BigDecimal.ZERO; + } + clusterWriteTag.setValue(power); + writeTags.add(clusterWriteTag); + } + return writeTags; + } + + public List getWriteTags(EmsPcsSetting pcsSetting, BigDecimal chargeDischargePower) { List writeTags = new ArrayList<>(); JSONArray array = JSON.parseArray(pcsSetting.getClusterPointAddress()); for (int i = 0; i < pcsSetting.getClusterNum(); i++) { Object clusterPointAddress = array.get(i); WriteTagConfig clusterWriteTag = new WriteTagConfig(); clusterWriteTag.setAddress(String.valueOf(clusterPointAddress)); -// if (ChargeStatus.CHARGING.equals(chargeStatus)) { -// writeTag.setValue(chargeDischargePower); -// } else if (ChargeStatus.DISCHARGING.equals(chargeStatus)) { -// writeTag.setValue(chargeDischargePower); -// } else { -// // 待机状态-电池簇PCS有功功率给定置0 -// writeTag.setValue(chargeDischargePower); -// } clusterWriteTag.setValue(chargeDischargePower); writeTags.add(clusterWriteTag); } return writeTags; } - public DeviceConfig getDeviceConfig(String siteId, String deviceId, EmsPcsSetting pcsSetting, ChargeStatus chargeStatus, BigDecimal chargeDischargePower) { - EmsDevicesSetting device = emsDevicesMapper.getDeviceBySiteAndDeviceId(deviceId, siteId); - if (device == null) { - logger.info("当前站点: {}, PCS设备: {} 未找到对应设备配置信息", siteId, deviceId); - return null; - } + public DeviceConfig getDeviceConfig(String siteId, String deviceId, EmsDevicesSetting device, EmsPcsSetting pcsSetting, BigDecimal chargeDischargePower, int writeType) { if (Objects.isNull(pcsSetting)) { pcsSetting = emsPcsSettingMapper.selectEmsPcsSettingByDeviceId(device.getId()); if (pcsSetting == null) { @@ -290,27 +344,47 @@ public class StrategyPoller { return null; } } + if (device.getIpPort() == null || device.getSlaveId() == null) { + logger.info("当前站点: {}, PCS设备: {} 未配置IP端口或从站号", siteId, deviceId); + return null; + } 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(pcsSetting, chargeStatus, chargeDischargePower)); + deviceConfig.setWriteTags(writeType == 0 ? getWriteTags(pcsSetting, chargeDischargePower) : getSwitchDeviceWriteTags(pcsSetting, device.getWorkStatus())); return deviceConfig; } private void sendModbusCommand(List pcsDeviceList, EmsPcsSetting pcsSetting, ChargeStatus chargeStatus, BigDecimal chargeDischargePower, - EmsStrategyTemp emsStrategyTemp, boolean needAntiReverseFlow) { + EmsStrategyTemp emsStrategyTemp, boolean needAntiReverseFlow, Integer powerDownType) { for (EmsDevicesSetting pcsDevice : pcsDeviceList) { String siteId = pcsDevice.getSiteId(); String deviceId = pcsDevice.getDeviceId(); List strategyLogList = getStrategyLog(deviceId, chargeStatus.getCode(), emsStrategyTemp, needAntiReverseFlow); - if (CollectionUtils.isNotEmpty(strategyLogList) && !ChargeStatus.DISCHARGING.equals(chargeStatus) && !needAntiReverseFlow) { + if (CollectionUtils.isNotEmpty(strategyLogList) && (!ChargeStatus.DISCHARGING.equals(chargeStatus) || !needAntiReverseFlow)) { logger.info("当前站点: {}, PCS设备: {} 当前时间段已存在策略执行记录,不再重复执行", siteId, deviceId); continue; } - DeviceConfig deviceConfig = getDeviceConfig(siteId, deviceId, pcsSetting, chargeStatus, chargeDischargePower); + + // 每次操作先判断设备工作状态 + if (WorkStatus.ABNORMAL.getCode().equals(pcsDevice.getWorkStatus())) { + // 设备故障,不发送指令 + continue; + } else if (WorkStatus.STOP.getCode().equals(pcsDevice.getWorkStatus())) { + // 设备停机 + if (ChargeStatus.STANDBY.equals(chargeStatus)) { + // 待机,则不写入功率值 + continue; + } else { + // 充、放电,则先开机设备 + switchDevice(pcsDevice, pcsSetting, WorkStatus.NORMAL); + } + } + + DeviceConfig deviceConfig = getDeviceConfig(siteId, deviceId, pcsDevice, pcsSetting, chargeDischargePower, 0); if (deviceConfig == null) { continue; } @@ -318,8 +392,27 @@ public class StrategyPoller { if (!result) { logger.info("当前站点: {}, PCS设备: {} modbus控制设备{}指令发送失败", siteId, deviceId, chargeStatus.getInfo()); } + if (ChargeStatus.STANDBY.equals(chargeStatus)) { + // 待机,先写功率值,再关机 + switchDevice(pcsDevice, pcsSetting, WorkStatus.STOP); + } // 记录策略执行日志 - saveStrategyLog(deviceId, chargeDischargePower, chargeStatus.getCode(), emsStrategyTemp, needAntiReverseFlow); + saveStrategyLog(deviceId, chargeDischargePower, chargeStatus.getCode(), emsStrategyTemp, needAntiReverseFlow, powerDownType); + } + } + + //设备开关机 + private void 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, 0); + if (deviceConfig == null) { + return; + } + boolean result = modbusProcessor.writeDataToDevice(deviceConfig); + if (!result) { + logger.info("当前站点: {}, PCS设备: {} modbus控制设备{}指令发送失败", siteId, deviceConfig, workStatus.getInfo()); } } diff --git a/ems-system/src/main/java/com/xzzn/ems/domain/EmsStrategyLog.java b/ems-system/src/main/java/com/xzzn/ems/domain/EmsStrategyLog.java index 74954e8..0c7c0a2 100644 --- a/ems-system/src/main/java/com/xzzn/ems/domain/EmsStrategyLog.java +++ b/ems-system/src/main/java/com/xzzn/ems/domain/EmsStrategyLog.java @@ -66,6 +66,10 @@ public class EmsStrategyLog extends BaseEntity @Excel(name = "防逆流, 1-是、0-否") private Integer antiReverse; + /** PCS降功率类型 */ + @Excel(name = "PCS降功率类型,0-降低功率、1-增加功率") + private Integer powerDownType; + public void setId(Long id) { this.id = id; @@ -172,6 +176,14 @@ public class EmsStrategyLog extends BaseEntity this.antiReverse = antiReverse; } + public Integer getPowerDownType() { + return powerDownType; + } + + public void setPowerDownType(Integer powerDownType) { + this.powerDownType = powerDownType; + } + @Override public String toString() { return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) @@ -187,6 +199,7 @@ public class EmsStrategyLog extends BaseEntity .append("chargeStatus", getChargeStatus()) .append("executionDate", getExecutionDate()) .append("antiReverse", getAntiReverse()) + .append("powerDownType", getPowerDownType()) .append("createBy", getCreateBy()) .append("createTime", getCreateTime()) .append("updateBy", getUpdateBy()) diff --git a/ems-system/src/main/java/com/xzzn/ems/mapper/EmsStrategyLogMapper.java b/ems-system/src/main/java/com/xzzn/ems/mapper/EmsStrategyLogMapper.java index 768b1e6..e54769d 100644 --- a/ems-system/src/main/java/com/xzzn/ems/mapper/EmsStrategyLogMapper.java +++ b/ems-system/src/main/java/com/xzzn/ems/mapper/EmsStrategyLogMapper.java @@ -59,4 +59,6 @@ public interface EmsStrategyLogMapper * @return 结果 */ public int deleteEmsStrategyLogByIds(Long[] ids); + + EmsStrategyLog getLastStrategyLog(EmsStrategyLog query); } diff --git a/ems-system/src/main/resources/mapper/ems/EmsStrategyLogMapper.xml b/ems-system/src/main/resources/mapper/ems/EmsStrategyLogMapper.xml index 485d5d2..bcf1e0f 100644 --- a/ems-system/src/main/resources/mapper/ems/EmsStrategyLogMapper.xml +++ b/ems-system/src/main/resources/mapper/ems/EmsStrategyLogMapper.xml @@ -16,6 +16,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" + @@ -24,7 +25,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" - select id, strategy_id, template_id, site_id, device_id, start_time, end_time, charge_discharge_power, charge_status, execution_date, anti_reverse, create_by, create_time, update_by, update_time, remark from ems_strategy_log + select id, strategy_id, template_id, site_id, device_id, start_time, end_time, charge_discharge_power, charge_status, execution_date, anti_reverse, power_down_type, create_by, create_time, update_by, update_time, remark from ems_strategy_log @@ -62,6 +64,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" charge_status, execution_date, anti_reverse, + power_down_type, create_by, create_time, update_by, @@ -79,6 +82,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" #{chargeStatus}, #{executionDate}, #{antiReverse}, + #{powerDownType}, #{createBy}, #{createTime}, #{updateBy}, @@ -100,6 +104,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" charge_status = #{chargeStatus}, execution_date = #{executionDate}, anti_reverse = #{antiReverse}, + power_down_type = #{powerDownType}, create_by = #{createBy}, create_time = #{createTime}, update_by = #{updateBy}, @@ -119,4 +124,23 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" #{id} + + \ No newline at end of file