diff --git a/ems-admin/src/main/java/com/xzzn/web/controller/ems/EmsStatisticalReportController.java b/ems-admin/src/main/java/com/xzzn/web/controller/ems/EmsStatisticalReportController.java index 330ecb0..d18840b 100644 --- a/ems-admin/src/main/java/com/xzzn/web/controller/ems/EmsStatisticalReportController.java +++ b/ems-admin/src/main/java/com/xzzn/web/controller/ems/EmsStatisticalReportController.java @@ -12,7 +12,9 @@ import com.xzzn.ems.domain.vo.ClusterStatisListVo; import com.xzzn.ems.domain.vo.DateSearchRequest; import com.xzzn.ems.domain.vo.StatisAmmeterDateRequest; import com.xzzn.ems.domain.vo.StatisClusterDateRequest; +import com.xzzn.ems.domain.vo.WeatherSyncResultVo; import com.xzzn.ems.service.IEmsStatsReportService; +import com.xzzn.ems.service.IEmsWeatherSyncService; import java.util.ArrayList; import java.util.List; @@ -38,6 +40,8 @@ public class EmsStatisticalReportController extends BaseController @Autowired private IEmsStatsReportService ieEmsStatsReportService; + @Autowired + private IEmsWeatherSyncService iEmsWeatherSyncService; /** * 概率统计-收益指标查询 @@ -176,4 +180,19 @@ public class EmsStatisticalReportController extends BaseController } } + /** + * 手动触发天气同步 + */ + @PostMapping("/syncWeatherByDateRange") + public AjaxResult syncWeatherByDateRange(StatisAmmeterDateRequest requestVo) + { + if (StringUtils.isEmpty(requestVo.getSiteId()) + || StringUtils.isEmpty(requestVo.getStartTime()) + || StringUtils.isEmpty(requestVo.getEndTime())) { + return error("缺少必传项: siteId/startTime/endTime"); + } + WeatherSyncResultVo resultVo = iEmsWeatherSyncService.syncWeatherByDateRange(requestVo); + return success(resultVo); + } + } diff --git a/ems-admin/src/main/java/com/xzzn/web/controller/ems/MqttMessageController.java b/ems-admin/src/main/java/com/xzzn/web/controller/ems/MqttMessageController.java index 47ed489..405efa7 100644 --- a/ems-admin/src/main/java/com/xzzn/web/controller/ems/MqttMessageController.java +++ b/ems-admin/src/main/java/com/xzzn/web/controller/ems/MqttMessageController.java @@ -6,11 +6,7 @@ import com.xzzn.common.enums.TopicHandleType; import com.xzzn.common.utils.StringUtils; import com.xzzn.ems.domain.EmsMqttTopicConfig; import com.xzzn.ems.mapper.EmsMqttTopicConfigMapper; -import com.xzzn.ems.service.IDDSDataProcessService; import com.xzzn.ems.service.IDeviceDataProcessService; -import com.xzzn.ems.service.IEmsStrategyService; -import com.xzzn.ems.service.IFXXAlarmDataProcessService; -import com.xzzn.ems.service.IFXXDataProcessService; import com.xzzn.ems.service.IMqttSyncLogService; import com.xzzn.framework.manager.MqttLifecycleManager; import com.xzzn.framework.web.service.MqttPublisher; @@ -38,22 +34,13 @@ public class MqttMessageController implements MqttPublisher, MqttSubscriber { private final MqttLifecycleManager mqttLifecycleManager; - @Autowired - private IFXXDataProcessService fXXDataProcessService; - - @Autowired - private IDDSDataProcessService dDSDataProcessService; @Autowired private IDeviceDataProcessService deviceDataProcessService; - @Autowired - private IFXXAlarmDataProcessService fXXAlarmDataProcessService; @Autowired private EmsMqttTopicConfigMapper emsMqttTopicConfigMapper; @Autowired - private IEmsStrategyService emsStrategyService; - @Autowired private IMqttSyncLogService iMqttSyncLogService; @Autowired diff --git a/ems-admin/src/main/resources/application-local.yml b/ems-admin/src/main/resources/application-local.yml index 7654dc9..49882e6 100644 --- a/ems-admin/src/main/resources/application-local.yml +++ b/ems-admin/src/main/resources/application-local.yml @@ -205,3 +205,10 @@ modbus: poll: interval: "0 */5 * * * *" # 5分钟间隔 timeout: 30000 # 30秒超时 + +weather: + api: + enabled: true + base-url: https://archive-api.open-meteo.com/v1/archive + api-key: + timezone: Asia/Shanghai diff --git a/ems-admin/src/main/resources/application-prod.yml b/ems-admin/src/main/resources/application-prod.yml index fee9ed4..6b6ecc0 100644 --- a/ems-admin/src/main/resources/application-prod.yml +++ b/ems-admin/src/main/resources/application-prod.yml @@ -205,3 +205,10 @@ modbus: poll: interval: "0 */5 * * * *" # 5分钟间隔 timeout: 30000 # 30秒超时 + +weather: + api: + enabled: true + base-url: https://archive-api.open-meteo.com/v1/archive + api-key: + timezone: Asia/Shanghai diff --git a/ems-admin/src/main/resources/application.yml b/ems-admin/src/main/resources/application.yml index 46df20a..01cabff 100644 --- a/ems-admin/src/main/resources/application.yml +++ b/ems-admin/src/main/resources/application.yml @@ -221,3 +221,10 @@ modbus: poll: interval: "0 */5 * * * *" # 5分钟间隔 timeout: 30000 # 30秒超时 + +weather: + api: + enabled: true + base-url: https://archive-api.open-meteo.com/v1/archive + api-key: + timezone: Asia/Shanghai diff --git a/ems-common/src/main/java/com/xzzn/common/constant/RedisKeyConstants.java b/ems-common/src/main/java/com/xzzn/common/constant/RedisKeyConstants.java index 0936828..b5aedc8 100644 --- a/ems-common/src/main/java/com/xzzn/common/constant/RedisKeyConstants.java +++ b/ems-common/src/main/java/com/xzzn/common/constant/RedisKeyConstants.java @@ -103,6 +103,9 @@ public class RedisKeyConstants /** 设备信息初始化 */ public static final String INIT_DEVICE_INFO = "init_device_info"; + + /** 设备配置缓存(按站点+设备) */ + public static final String DEVICE_SETTING = "DEVICE_SETTING_"; /** 告警匹配信息 */ public static final String ALARM_MATCH_INFO = "alarm_message_info"; @@ -126,6 +129,9 @@ public class RedisKeyConstants /** 点位配置缓存(按站点+设备) */ public static final String POINT_CONFIG_DEVICE = "POINT_CONFIG_DEVICE_"; + /** 点位配置缓存(按站点+pointId) */ + public static final String POINT_CONFIG_POINT = "POINT_CONFIG_POINT_"; + /** 单站监控最新数据(按站点+模块) */ public static final String SITE_MONITOR_LATEST = "SITE_MONITOR_LATEST_"; diff --git a/ems-quartz/src/main/java/com/xzzn/quartz/task/ModbusPoller.java b/ems-quartz/src/main/java/com/xzzn/quartz/task/ModbusPoller.java index 97be991..126a4b4 100644 --- a/ems-quartz/src/main/java/com/xzzn/quartz/task/ModbusPoller.java +++ b/ems-quartz/src/main/java/com/xzzn/quartz/task/ModbusPoller.java @@ -2,31 +2,25 @@ package com.xzzn.quartz.task; import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.JSONObject; -import com.fasterxml.jackson.databind.ObjectMapper; import com.serotonin.modbus4j.ModbusMaster; import com.xzzn.common.constant.RedisKeyConstants; import com.xzzn.common.core.modbus.ModbusProcessor; import com.xzzn.common.core.modbus.domain.DeviceConfig; +import com.xzzn.common.core.modbus.domain.TagConfig; import com.xzzn.common.core.redis.RedisCache; import com.xzzn.common.enums.DeviceRunningStatus; -import com.xzzn.common.utils.DateUtils; +import com.xzzn.common.utils.StringUtils; import com.xzzn.ems.domain.EmsDevicesSetting; +import com.xzzn.ems.domain.EmsPointConfig; import com.xzzn.ems.mapper.EmsDevicesSettingMapper; +import com.xzzn.ems.mapper.EmsPointConfigMapper; import com.xzzn.ems.service.IEmsAlarmRecordsService; import com.xzzn.ems.service.impl.DeviceDataProcessServiceImpl; -import com.xzzn.framework.manager.MqttLifecycleManager; import com.xzzn.framework.web.service.MqttPublisher; -import com.xzzn.quartz.config.ScheduledTask; -import com.xzzn.quartz.domain.SysJob; -import com.xzzn.quartz.service.ISysJobService; -import com.xzzn.quartz.util.CronUtils; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; import java.util.ArrayList; import java.util.Collections; +import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -54,10 +48,8 @@ import org.springframework.util.CollectionUtils; @Component("modbusPoller") public class ModbusPoller { private static final Logger log = LoggerFactory.getLogger(ModbusPoller.class); + private static final int SITE_DEVICE_OFFLINE_THRESHOLD = 6; - private final MqttLifecycleManager mqttLifecycleManager; - private final ScheduledTask scheduledTask; - private final ObjectMapper objectMapper = new ObjectMapper(); private final Map deviceFailureCounts = new ConcurrentHashMap<>(); private final AtomicBoolean polling = new AtomicBoolean(false); @@ -69,77 +61,46 @@ public class ModbusPoller { @Autowired private IEmsAlarmRecordsService iEmsAlarmRecordsService; - @Autowired - private ISysJobService iSysJobService; @Autowired private DeviceDataProcessServiceImpl deviceDataProcessServiceImpl; @Autowired private EmsDevicesSettingMapper emsDevicesSettingMapper; @Autowired + private EmsPointConfigMapper emsPointConfigMapper; + @Autowired private RedisCache redisCache; @Autowired private MqttPublisher mqttPublisher; @Value("${mqtt.topic}") private String topic; - @Value("${mqtt.siteId}") - private String siteId; - - @Autowired - public ModbusPoller(MqttLifecycleManager mqttLifecycleManager, ScheduledTask scheduledTask) { - this.mqttLifecycleManager = mqttLifecycleManager; - this.scheduledTask = scheduledTask; - } public void pollAllDevices() { if (!polling.compareAndSet(false, true)) { log.warn("上一次轮询尚未完成,本次轮询跳过"); return; } - Path devicesDir = Paths.get(System.getProperty("user.dir"), "devices"); - if (!Files.exists(devicesDir)) { - log.error("Devices目录不存在: {}", devicesDir); + List pollingTasks = buildPollingTasks(); + if (CollectionUtils.isEmpty(pollingTasks)) { + log.warn("未查询到可用的Modbus采集点位配置,跳过本轮轮询"); polling.set(false); return; } - List jsonFiles = null; - try { - jsonFiles = Files.list(devicesDir) - .filter(path -> path.toString().endsWith(".json")) - .collect(Collectors.toList()); - } catch (IOException e) { - log.error("modbusPoller.loadConfigs 获取设备配置文件失败: {}", devicesDir, e); - polling.set(false); - return; - } + // 按主机IP分组,同一网关串行访问,避免连接抖动 + Map> groupedByHost = pollingTasks.stream() + .collect(Collectors.groupingBy( + task -> task.getDeviceConfig().getHost(), + HashMap::new, + Collectors.toList())); - // 按主机IP分组(同一网关的不同端口也归为一组,避免并发访问导致Connection Reset) - Map> groupedByHost = new HashMap<>(); - for (Path filePath : jsonFiles) { - DeviceConfig config = null; - try { - config = objectMapper.readValue(filePath.toFile(), DeviceConfig.class); - } catch (IOException e) { - log.error("modbusPoller.loadConfigs 解析设备配置文件失败: {}", filePath, e); - continue; - } - if (config.isEnabled()) { - // 只按主机IP分组,确保同一网关的所有端口串行访问 - String hostKey = config.getHost(); - groupedByHost.computeIfAbsent(hostKey, k -> new ArrayList<>()).add(config); - } - } - - // 使用单线程 executor 串行执行所有主机的 Modbus 操作 - // 将所有主机的设备按顺序串行处理,避免任何并发访问 Future future = modbusExecutor.submit(() -> { - for (Map.Entry> entry : groupedByHost.entrySet()) { + for (Map.Entry> entry : groupedByHost.entrySet()) { String hostKey = entry.getKey(); - List configs = entry.getValue(); - for (DeviceConfig config : configs) { + List tasks = entry.getValue(); + for (PollingTask task : tasks) { try { - scheduledStart(config); + scheduledStart(task.getSiteId(), task.getDeviceConfig()); // 每次读取后等待200ms,给Modbus网关足够的处理时间 Thread.sleep(200); } catch (InterruptedException ie) { @@ -147,7 +108,8 @@ public class ModbusPoller { log.warn("Modbus轮询被中断"); return; } catch (Exception e) { - log.error("采集设备数据异常: {}", config.getDeviceName(), e); + log.error("采集设备数据异常: siteId={}, deviceId={}", + task.getSiteId(), task.getDeviceConfig().getDeviceNumber(), e); } } log.info("采集设备数据{}轮询任务执行完成", hostKey); @@ -165,7 +127,139 @@ public class ModbusPoller { } } - public void scheduledStart(DeviceConfig config) { + private List buildPollingTasks() { + List pointConfigs = emsPointConfigMapper.selectModbusCollectPointConfigs(null); + if (CollectionUtils.isEmpty(pointConfigs)) { + return Collections.emptyList(); + } + + List allDevices = emsDevicesSettingMapper.selectEmsDevicesSettingList(null); + Map deviceMap = allDevices.stream() + .filter(Objects::nonNull) + .filter(device -> StringUtils.isNoneBlank(device.getSiteId(), device.getDeviceId())) + .collect(Collectors.toMap( + this::buildSiteDeviceKey, + device -> device, + (left, right) -> left)); + + Map> pointsByDevice = pointConfigs.stream() + .filter(Objects::nonNull) + .filter(point -> StringUtils.isNoneBlank(point.getSiteId(), point.getDeviceId())) + .collect(Collectors.groupingBy( + point -> point.getSiteId() + "_" + point.getDeviceId(), + HashMap::new, + Collectors.toList())); + + List tasks = new ArrayList<>(); + for (Map.Entry> entry : pointsByDevice.entrySet()) { + String siteDeviceKey = entry.getKey(); + EmsDevicesSetting device = deviceMap.get(siteDeviceKey); + if (device == null) { + log.warn("未找到设备连接配置,跳过采集: key={}", siteDeviceKey); + continue; + } + DeviceConfig deviceConfig = buildDeviceConfig(device, entry.getValue()); + if (deviceConfig == null) { + continue; + } + tasks.add(new PollingTask(device.getSiteId(), deviceConfig)); + } + return tasks; + } + + private DeviceConfig buildDeviceConfig(EmsDevicesSetting device, List pointConfigs) { + if (device == null || CollectionUtils.isEmpty(pointConfigs)) { + return null; + } + if (StringUtils.isBlank(device.getIpAddress()) || device.getIpPort() == null || device.getSlaveId() == null) { + log.warn("设备连接参数不完整,跳过采集: siteId={}, deviceId={}", device.getSiteId(), device.getDeviceId()); + return null; + } + List tags = pointConfigs.stream() + .sorted(Comparator.comparing(point -> point.getModbusReadOrder() == null ? 0 : point.getModbusReadOrder())) + .map(this::toTagConfig) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + if (CollectionUtils.isEmpty(tags)) { + log.warn("设备无有效Modbus点位配置,跳过采集: siteId={}, deviceId={}", device.getSiteId(), device.getDeviceId()); + return null; + } + + DeviceConfig deviceConfig = new DeviceConfig(); + deviceConfig.setEnabled(true); + deviceConfig.setDeviceName(device.getDeviceName()); + deviceConfig.setDeviceNumber(device.getDeviceId()); + deviceConfig.setHost(device.getIpAddress()); + deviceConfig.setPort(device.getIpPort().intValue()); + deviceConfig.setSlaveId(device.getSlaveId().intValue()); + deviceConfig.setTags(tags); + return deviceConfig; + } + + private TagConfig toTagConfig(EmsPointConfig pointConfig) { + if (pointConfig == null) { + return null; + } + if (StringUtils.isBlank(pointConfig.getDataKey())) { + return null; + } + String address = normalizeAddress(pointConfig.getRegisterAddress(), pointConfig.getModbusRegisterType()); + if (StringUtils.isBlank(address)) { + return null; + } + if (StringUtils.isBlank(pointConfig.getModbusDataType())) { + return null; + } + + TagConfig tag = new TagConfig(); + tag.setKey(pointConfig.getDataKey().trim()); + tag.setAddress(address); + tag.setDataType(pointConfig.getModbusDataType().trim()); + tag.setA(pointConfig.getDataA() == null ? 0F : pointConfig.getDataA().floatValue()); + tag.setK(pointConfig.getDataK() == null ? 1F : pointConfig.getDataK().floatValue()); + tag.setB(pointConfig.getDataB() == null ? 0F : pointConfig.getDataB().floatValue()); + tag.setBit(pointConfig.getDataBit()); + return tag; + } + + private String normalizeAddress(String registerAddress, String registerType) { + if (StringUtils.isBlank(registerAddress)) { + return null; + } + String normalizedAddress = registerAddress.trim(); + if (!normalizedAddress.chars().allMatch(Character::isDigit)) { + log.warn("寄存器地址必须为数字,当前值: {}", normalizedAddress); + return null; + } + if (normalizedAddress.length() > 1) { + char first = normalizedAddress.charAt(0); + if (first >= '0' && first <= '4') { + return normalizedAddress; + } + } + return getRegisterPrefix(registerType) + normalizedAddress; + } + + private String getRegisterPrefix(String registerType) { + String normalized = StringUtils.defaultString(registerType).trim().toUpperCase(); + switch (normalized) { + case "COIL": + return "0"; + case "DISCRETE_INPUT": + return "1"; + case "INPUT_REGISTER": + return "3"; + case "HOLDING_REGISTER": + default: + return "4"; + } + } + + private String buildSiteDeviceKey(EmsDevicesSetting device) { + return device.getSiteId() + "_" + device.getDeviceId(); + } + + public void scheduledStart(String siteId, DeviceConfig config) { if (config.isEnabled()) { log.info("Reading data from devices: {}", config.getDeviceName()); @@ -205,7 +299,7 @@ public class ModbusPoller { log.info("Data from {}: {}", config.getDeviceName(), data); String deviceNumber = config.getDeviceNumber(); //处理数据并发送MQTT消息、保存Redis数据和数据入库 - processingData(data, deviceNumber); + processingData(siteId, data, deviceNumber); } } @@ -254,24 +348,25 @@ public class ModbusPoller { return data; } - private void processingData(Map data, String deviceNumber) { + private void processingData(String siteId, Map data, String deviceNumber) { + String siteDeviceKey = siteId + "_" + deviceNumber; if (CollectionUtils.isEmpty(data)) { // 增加失败计数 - int failureCount = deviceFailureCounts.getOrDefault(deviceNumber, 0) + 1; - deviceFailureCounts.put(deviceNumber, failureCount); + int failureCount = deviceFailureCounts.getOrDefault(siteDeviceKey, 0) + 1; + deviceFailureCounts.put(siteDeviceKey, failureCount); - log.warn("设备 {} 数据读取失败,当前连续失败次数: {}", deviceNumber, failureCount); + log.warn("设备 {} 数据读取失败,当前连续失败次数: {}", siteDeviceKey, failureCount); // 连续6次失败触发报警 - if (failureCount >= 6) { + if (failureCount >= SITE_DEVICE_OFFLINE_THRESHOLD) { addDeviceOfflineRecord(siteId, deviceNumber); - log.error("设备 {} 连续 {} 次未读取到数据,触发报警", deviceNumber, failureCount); + log.error("设备 {} 连续 {} 次未读取到数据,触发报警", siteDeviceKey, failureCount); } return; } // 数据读取成功,重置计数器 - deviceFailureCounts.remove(deviceNumber); + deviceFailureCounts.remove(siteDeviceKey); // 读取到数据后告警自恢复 deleteDeviceOfflineRecord(siteId, deviceNumber); @@ -281,9 +376,42 @@ public class ModbusPoller { json.put("Data", data); json.put("timestamp", timestamp); json.put("Device", deviceNumber); - sendMqttMsg(json); - saveRedisData(json, deviceNumber); - saveDataToDatabase(data, deviceNumber, timestamp); + if (shouldSendMqttOnChange(siteId, deviceNumber, data)) { + sendMqttMsg(json); + } else { + sendMqttHeartbeat(deviceNumber, timestamp); + log.info("设备 {} 数据无变化,已发送心跳MQTT", siteDeviceKey); + } + saveRedisData(siteId, json, deviceNumber); + saveDataToDatabase(siteId, data, deviceNumber, timestamp); + } + + /** + * 逢变上送:仅当Data发生变化时才发送MQTT + */ + private boolean shouldSendMqttOnChange(String siteId, String deviceNumber, Map currentData) { + JSONObject lastPayload = redisCache.getCacheObject(RedisKeyConstants.ORIGINAL_MQTT_DATA + siteId + "_" + deviceNumber); + if (lastPayload == null) { + return true; + } + + Object lastDataObj = lastPayload.get("Data"); + if (lastDataObj == null) { + return true; + } + + JSONObject lastData = JSON.parseObject(JSON.toJSONString(lastDataObj)); + JSONObject currentDataJson = JSON.parseObject(JSON.toJSONString(currentData)); + return !Objects.equals(lastData, currentDataJson); + } + + private void sendMqttHeartbeat(String deviceNumber, Long timestamp) { + JSONObject heartbeat = new JSONObject(); + heartbeat.put("Device", deviceNumber); + heartbeat.put("timestamp", timestamp); + heartbeat.put("Heartbeat", 1); + heartbeat.put("Data", new JSONObject()); + sendMqttMsg(heartbeat); } public void sendMqttMsg(JSONObject json) { @@ -296,7 +424,7 @@ public class ModbusPoller { } - public void saveRedisData(JSONObject obj, String deviceNumber) { + public void saveRedisData(String siteId, JSONObject obj, String deviceNumber) { try { // 存放mqtt原始每个设备最晚一次数据,便于后面点位获取数据 redisCache.setCacheObject(RedisKeyConstants.ORIGINAL_MQTT_DATA + siteId + "_" + deviceNumber, obj); @@ -308,8 +436,12 @@ public class ModbusPoller { } } - private void saveDataToDatabase(Map data, String deviceNumber, Long timestamp) { - deviceDataProcessServiceImpl.processingDeviceData(siteId, deviceNumber, JSON.toJSONString(data), DateUtils.convertUpdateTime(timestamp)); + private void saveDataToDatabase(String siteId, Map data, String deviceNumber, Long timestamp) { + JSONObject payload = new JSONObject(); + payload.put("Device", deviceNumber); + payload.put("Data", JSON.toJSONString(data)); + payload.put("timestamp", timestamp); + deviceDataProcessServiceImpl.handleDeviceData(Collections.singletonList(payload).toString(), siteId); } //处理设备连接失败的情况,更新设备状态为离线,添加报警记录 @@ -333,11 +465,22 @@ public class ModbusPoller { } } - private int getScheduledTaskInterval() { - SysJob query = new SysJob(); - query.setInvokeTarget("modbusPoller.pollAllDevices"); - List sysJobs = iSysJobService.selectJobList(query); - return Math.toIntExact(CronUtils.getNextExecutionIntervalMillis(sysJobs.get(0).getCronExpression())); + private static class PollingTask { + private final String siteId; + private final DeviceConfig deviceConfig; + + private PollingTask(String siteId, DeviceConfig deviceConfig) { + this.siteId = siteId; + this.deviceConfig = deviceConfig; + } + + public String getSiteId() { + return siteId; + } + + public DeviceConfig getDeviceConfig() { + return deviceConfig; + } } } 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 311feda..c9b1f56 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 @@ -7,8 +7,11 @@ 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.core.redis.RedisCache; +import com.xzzn.common.enums.BusinessStatus; +import com.xzzn.common.enums.BusinessType; import com.xzzn.common.enums.ChargeStatus; import com.xzzn.common.enums.DeviceCategory; +import com.xzzn.common.enums.OperatorType; import com.xzzn.common.enums.SiteDevice; import com.xzzn.common.enums.SocLimit; import com.xzzn.common.enums.WorkStatus; @@ -33,6 +36,8 @@ import com.xzzn.ems.mapper.EmsStrategyRuntimeConfigMapper; import com.xzzn.ems.mapper.EmsStrategyRunningMapper; import com.xzzn.ems.mapper.EmsStrategyTempMapper; import com.xzzn.ems.mapper.EmsStrategyTimeConfigMapper; +import com.xzzn.system.domain.SysOperLog; +import com.xzzn.system.service.ISysOperLogService; import java.math.BigDecimal; import java.math.RoundingMode; @@ -115,6 +120,8 @@ public class StrategyPoller { private RedisCache redisCache; @Autowired private ModbusProcessor modbusProcessor; + @Autowired + private ISysOperLogService operLogService; @Resource(name = "modbusExecutor") private ExecutorService modbusExecutor; @@ -511,8 +518,10 @@ public class StrategyPoller { boolean result = modbusProcessor.writeDataToDeviceWithRetry(deviceConfig); if (!result) { logger.info("当前站点: {}, PCS设备: {} modbus控制设备{}指令发送失败", siteId, deviceId, chargeStatus.getInfo()); + recordDeviceOperationLog(siteId, deviceId, "写功率", chargeDischargePower, false, chargeStatus.getInfo() + "功率下发失败"); continue; } else { + recordDeviceOperationLog(siteId, deviceId, "写功率", chargeDischargePower, true, null); if (ChargeStatus.STANDBY.equals(chargeStatus)) { // 待机,先写功率值,再关机 if (!switchDevice(pcsDevice, pcsSetting, WorkStatus.STOP)) { @@ -541,10 +550,42 @@ public class StrategyPoller { if (!result) { pcsDevice.setWorkStatus(originalWorkStatus); logger.info("当前站点: {}, PCS设备: {} modbus控制设备{}指令发送失败", siteId, deviceId, workStatus.getInfo()); + recordDeviceOperationLog(siteId, deviceId, "开关机", workStatus.getInfo(), false, workStatus.getInfo() + "指令发送失败"); + } else { + recordDeviceOperationLog(siteId, deviceId, "开关机", workStatus.getInfo(), true, null); } return result; } + private void recordDeviceOperationLog(String siteId, String deviceId, String action, Object param, boolean success, String errorMsg) { + try { + SysOperLog operLog = new SysOperLog(); + operLog.setTitle("策略设备控制-" + action); + operLog.setBusinessType(BusinessType.UPDATE.ordinal()); + operLog.setMethod(this.getClass().getName() + "." + action); + operLog.setRequestMethod("SCHEDULE"); + operLog.setOperatorType(OperatorType.OTHER.ordinal()); + operLog.setOperName("system"); + operLog.setOperIp("127.0.0.1"); + operLog.setOperUrl("/quartz/strategyPoller"); + operLog.setOperTime(DateUtils.getNowDate()); + Map operParam = new HashMap<>(); + operParam.put("siteId", siteId); + operParam.put("deviceId", deviceId); + operParam.put("action", action); + operParam.put("param", param); + operLog.setOperParam(StringUtils.substring(JSON.toJSONString(operParam), 0, 2000)); + operLog.setJsonResult(StringUtils.substring(JSON.toJSONString(Collections.singletonMap("success", success)), 0, 2000)); + operLog.setStatus(success ? BusinessStatus.SUCCESS.ordinal() : BusinessStatus.FAIL.ordinal()); + if (!success) { + operLog.setErrorMsg(StringUtils.substring(errorMsg, 0, 2000)); + } + operLogService.insertOperlog(operLog); + } catch (Exception e) { + logger.error("记录sys_oper_log失败, siteId={}, deviceId={}, action={}", siteId, deviceId, action, e); + } + } + private ProtectionConstraintVo getProtectionConstraint(String siteId) { ProtectionConstraintVo constraint = redisCache.getCacheObject(RedisKeyConstants.PROTECTION_CONSTRAINT + siteId); if (constraint == null) { diff --git a/ems-system/src/main/java/com/xzzn/ems/config/WeatherApiProperties.java b/ems-system/src/main/java/com/xzzn/ems/config/WeatherApiProperties.java new file mode 100644 index 0000000..6d0a79c --- /dev/null +++ b/ems-system/src/main/java/com/xzzn/ems/config/WeatherApiProperties.java @@ -0,0 +1,61 @@ +package com.xzzn.ems.config; + +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +@Component +@ConfigurationProperties(prefix = "weather.api") +public class WeatherApiProperties { + + /** + * 是否启用天气同步 + */ + private boolean enabled = false; + + /** + * 天气接口基础地址 + */ + private String baseUrl = "https://archive-api.open-meteo.com/v1/archive"; + + /** + * 可选接口鉴权字段 + */ + private String apiKey; + + /** + * 时区参数 + */ + private String timezone = "Asia/Shanghai"; + + public boolean isEnabled() { + return enabled; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + public String getBaseUrl() { + return baseUrl; + } + + public void setBaseUrl(String baseUrl) { + this.baseUrl = baseUrl; + } + + public String getApiKey() { + return apiKey; + } + + public void setApiKey(String apiKey) { + this.apiKey = apiKey; + } + + public String getTimezone() { + return timezone; + } + + public void setTimezone(String timezone) { + this.timezone = timezone; + } +} diff --git a/ems-system/src/main/java/com/xzzn/ems/domain/EmsPointConfig.java b/ems-system/src/main/java/com/xzzn/ems/domain/EmsPointConfig.java index c8a144b..2f2040a 100644 --- a/ems-system/src/main/java/com/xzzn/ems/domain/EmsPointConfig.java +++ b/ems-system/src/main/java/com/xzzn/ems/domain/EmsPointConfig.java @@ -63,6 +63,24 @@ public class EmsPointConfig extends BaseEntity { @Excel(name = "计算表达式") private String calcExpression; + @Excel(name = "是否启用采集", readConverterExp = "0=否,1=是") + private Integer collectEnabled; + + @Excel(name = "采集来源") + private String collectSource; + + @Excel(name = "Modbus寄存器类型") + private String modbusRegisterType; + + @Excel(name = "Modbus数据类型") + private String modbusDataType; + + @Excel(name = "Modbus读取顺序") + private Integer modbusReadOrder; + + @Excel(name = "Modbus分组") + private String modbusGroup; + public Long getId() { return id; } @@ -199,6 +217,54 @@ public class EmsPointConfig extends BaseEntity { this.calcExpression = calcExpression; } + public Integer getCollectEnabled() { + return collectEnabled; + } + + public void setCollectEnabled(Integer collectEnabled) { + this.collectEnabled = collectEnabled; + } + + public String getCollectSource() { + return collectSource; + } + + public void setCollectSource(String collectSource) { + this.collectSource = collectSource; + } + + public String getModbusRegisterType() { + return modbusRegisterType; + } + + public void setModbusRegisterType(String modbusRegisterType) { + this.modbusRegisterType = modbusRegisterType; + } + + public String getModbusDataType() { + return modbusDataType; + } + + public void setModbusDataType(String modbusDataType) { + this.modbusDataType = modbusDataType; + } + + public Integer getModbusReadOrder() { + return modbusReadOrder; + } + + public void setModbusReadOrder(Integer modbusReadOrder) { + this.modbusReadOrder = modbusReadOrder; + } + + public String getModbusGroup() { + return modbusGroup; + } + + public void setModbusGroup(String modbusGroup) { + this.modbusGroup = modbusGroup; + } + @Override public String toString() { return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE) @@ -219,6 +285,12 @@ public class EmsPointConfig extends BaseEntity { .append("isAlarm", getIsAlarm()) .append("pointType", getPointType()) .append("calcExpression", getCalcExpression()) + .append("collectEnabled", getCollectEnabled()) + .append("collectSource", getCollectSource()) + .append("modbusRegisterType", getModbusRegisterType()) + .append("modbusDataType", getModbusDataType()) + .append("modbusReadOrder", getModbusReadOrder()) + .append("modbusGroup", getModbusGroup()) .append("createBy", getCreateBy()) .append("createTime", getCreateTime()) .append("updateBy", getUpdateBy()) diff --git a/ems-system/src/main/java/com/xzzn/ems/domain/vo/AmmeterRevenueStatisListVo.java b/ems-system/src/main/java/com/xzzn/ems/domain/vo/AmmeterRevenueStatisListVo.java index c0acd13..4f9dd7e 100644 --- a/ems-system/src/main/java/com/xzzn/ems/domain/vo/AmmeterRevenueStatisListVo.java +++ b/ems-system/src/main/java/com/xzzn/ems/domain/vo/AmmeterRevenueStatisListVo.java @@ -11,6 +11,15 @@ public class AmmeterRevenueStatisListVo { /** 类别 */ private String dataTime; + /** 是否工作日:1-工作日 0-节假日 */ + private Integer isWorkday; + + /** 日期类型 */ + private String dayType; + + /** 天气情况 */ + private String weatherDesc; + /** 组合有功-总 */ private BigDecimal activeTotalPrice = BigDecimal.ZERO; @@ -52,6 +61,30 @@ public class AmmeterRevenueStatisListVo { this.dataTime = dataTime; } + public Integer getIsWorkday() { + return isWorkday; + } + + public void setIsWorkday(Integer isWorkday) { + this.isWorkday = isWorkday; + } + + public String getDayType() { + return dayType; + } + + public void setDayType(String dayType) { + this.dayType = dayType; + } + + public String getWeatherDesc() { + return weatherDesc; + } + + public void setWeatherDesc(String weatherDesc) { + this.weatherDesc = weatherDesc; + } + public BigDecimal getActiveTotalPrice() { return activeTotalPrice; } diff --git a/ems-system/src/main/java/com/xzzn/ems/domain/vo/DevicePointDataList.java b/ems-system/src/main/java/com/xzzn/ems/domain/vo/DevicePointDataList.java index 3d9d2f0..29bcb25 100644 --- a/ems-system/src/main/java/com/xzzn/ems/domain/vo/DevicePointDataList.java +++ b/ems-system/src/main/java/com/xzzn/ems/domain/vo/DevicePointDataList.java @@ -24,11 +24,25 @@ public class DevicePointDataList private BigDecimal avgValue; // 差值(max - min) private BigDecimal diffValue; + // 第一四分位数 + private BigDecimal q1; + // 中位数 + private BigDecimal median; + // 第三四分位数 + private BigDecimal q3; public DevicePointDataList(String deviceId, List pointValueList,String parentDeviceId, BigDecimal maxValue, BigDecimal minValue, BigDecimal avgValue, BigDecimal diffValue, String maxDate, String minDate) { + this(deviceId, pointValueList, parentDeviceId, maxValue, minValue, avgValue, diffValue, maxDate, minDate, null, null, null); + } + + public DevicePointDataList(String deviceId, List pointValueList,String parentDeviceId, + BigDecimal maxValue, BigDecimal minValue, + BigDecimal avgValue, BigDecimal diffValue, + String maxDate, String minDate, + BigDecimal q1, BigDecimal median, BigDecimal q3) { this.deviceId = deviceId; this.pointValueList = pointValueList; this.parentDeviceId = parentDeviceId; @@ -38,6 +52,9 @@ public class DevicePointDataList this.diffValue = diffValue; this.maxDate = maxDate; this.minDate = minDate; + this.q1 = q1; + this.median = median; + this.q3 = q3; } public DevicePointDataList(String deviceId, String parentDeviceId, List pointValueList) { @@ -121,4 +138,28 @@ public class DevicePointDataList public void setDiffValue(BigDecimal diffValue) { this.diffValue = diffValue; } + + public BigDecimal getQ1() { + return q1; + } + + public void setQ1(BigDecimal q1) { + this.q1 = q1; + } + + public BigDecimal getMedian() { + return median; + } + + public void setMedian(BigDecimal median) { + this.median = median; + } + + public BigDecimal getQ3() { + return q3; + } + + public void setQ3(BigDecimal q3) { + this.q3 = q3; + } } diff --git a/ems-system/src/main/java/com/xzzn/ems/domain/vo/WeatherSyncResultVo.java b/ems-system/src/main/java/com/xzzn/ems/domain/vo/WeatherSyncResultVo.java new file mode 100644 index 0000000..9b1da54 --- /dev/null +++ b/ems-system/src/main/java/com/xzzn/ems/domain/vo/WeatherSyncResultVo.java @@ -0,0 +1,76 @@ +package com.xzzn.ems.domain.vo; + +public class WeatherSyncResultVo { + private String siteId; + private String startTime; + private String endTime; + private int totalDays; + private int successDays; + private int insertedDays; + private int updatedDays; + private String message; + + public String getSiteId() { + return siteId; + } + + public void setSiteId(String siteId) { + this.siteId = siteId; + } + + public String getStartTime() { + return startTime; + } + + public void setStartTime(String startTime) { + this.startTime = startTime; + } + + public String getEndTime() { + return endTime; + } + + public void setEndTime(String endTime) { + this.endTime = endTime; + } + + public int getTotalDays() { + return totalDays; + } + + public void setTotalDays(int totalDays) { + this.totalDays = totalDays; + } + + public int getSuccessDays() { + return successDays; + } + + public void setSuccessDays(int successDays) { + this.successDays = successDays; + } + + public int getInsertedDays() { + return insertedDays; + } + + public void setInsertedDays(int insertedDays) { + this.insertedDays = insertedDays; + } + + public int getUpdatedDays() { + return updatedDays; + } + + public void setUpdatedDays(int updatedDays) { + this.updatedDays = updatedDays; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } +} diff --git a/ems-system/src/main/java/com/xzzn/ems/mapper/EmsPointConfigMapper.java b/ems-system/src/main/java/com/xzzn/ems/mapper/EmsPointConfigMapper.java index 4784df8..324e5ed 100644 --- a/ems-system/src/main/java/com/xzzn/ems/mapper/EmsPointConfigMapper.java +++ b/ems-system/src/main/java/com/xzzn/ems/mapper/EmsPointConfigMapper.java @@ -47,4 +47,6 @@ public interface EmsPointConfigMapper { List selectBySiteIdAndPointIds(@Param("siteId") String siteId, @Param("pointIds") List pointIds); + + List selectModbusCollectPointConfigs(@Param("siteId") String siteId); } diff --git a/ems-system/src/main/java/com/xzzn/ems/mapper/EmsSiteWeatherDayMapper.java b/ems-system/src/main/java/com/xzzn/ems/mapper/EmsSiteWeatherDayMapper.java new file mode 100644 index 0000000..d7f16bb --- /dev/null +++ b/ems-system/src/main/java/com/xzzn/ems/mapper/EmsSiteWeatherDayMapper.java @@ -0,0 +1,19 @@ +package com.xzzn.ems.mapper; + +import org.apache.ibatis.annotations.Param; + +public interface EmsSiteWeatherDayMapper { + + int updateWeatherDesc(@Param("siteId") String siteId, + @Param("calendarDate") String calendarDate, + @Param("weatherDesc") String weatherDesc, + @Param("weatherCode") Integer weatherCode); + + int selectCountBySiteAndDate(@Param("siteId") String siteId, @Param("calendarDate") String calendarDate); + + int insertSiteWeatherDay(@Param("siteId") String siteId, + @Param("calendarDate") String calendarDate, + @Param("weatherDesc") String weatherDesc, + @Param("weatherCode") Integer weatherCode, + @Param("source") String source); +} diff --git a/ems-system/src/main/java/com/xzzn/ems/service/IDDSDataProcessService.java b/ems-system/src/main/java/com/xzzn/ems/service/IDDSDataProcessService.java deleted file mode 100644 index c1ab276..0000000 --- a/ems-system/src/main/java/com/xzzn/ems/service/IDDSDataProcessService.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.xzzn.ems.service; - -public interface IDDSDataProcessService { - - public void handleDdsData(String message); - -} diff --git a/ems-system/src/main/java/com/xzzn/ems/service/IEmsWeatherSyncService.java b/ems-system/src/main/java/com/xzzn/ems/service/IEmsWeatherSyncService.java new file mode 100644 index 0000000..0a70e6b --- /dev/null +++ b/ems-system/src/main/java/com/xzzn/ems/service/IEmsWeatherSyncService.java @@ -0,0 +1,8 @@ +package com.xzzn.ems.service; + +import com.xzzn.ems.domain.vo.StatisAmmeterDateRequest; +import com.xzzn.ems.domain.vo.WeatherSyncResultVo; + +public interface IEmsWeatherSyncService { + WeatherSyncResultVo syncWeatherByDateRange(StatisAmmeterDateRequest requestVo); +} diff --git a/ems-system/src/main/java/com/xzzn/ems/service/IFXXDataProcessService.java b/ems-system/src/main/java/com/xzzn/ems/service/IFXXDataProcessService.java deleted file mode 100644 index c9610c7..0000000 --- a/ems-system/src/main/java/com/xzzn/ems/service/IFXXDataProcessService.java +++ /dev/null @@ -1,6 +0,0 @@ -package com.xzzn.ems.service; - -public interface IFXXDataProcessService { - - public void handleFxData(String message); -} diff --git a/ems-system/src/main/java/com/xzzn/ems/service/impl/DDSDataProcessServiceImpl.java b/ems-system/src/main/java/com/xzzn/ems/service/impl/DDSDataProcessServiceImpl.java deleted file mode 100644 index ba48224..0000000 --- a/ems-system/src/main/java/com/xzzn/ems/service/impl/DDSDataProcessServiceImpl.java +++ /dev/null @@ -1,1228 +0,0 @@ -package com.xzzn.ems.service.impl; - -import com.alibaba.fastjson2.JSON; -import com.alibaba.fastjson2.JSONObject; -import com.alibaba.fastjson2.TypeReference; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.xzzn.common.constant.Constants; -import com.xzzn.common.constant.RedisKeyConstants; -import com.xzzn.common.core.redis.RedisCache; -import com.xzzn.common.enums.BranchStatus; -import com.xzzn.common.enums.ChargeStatus; -import com.xzzn.common.enums.CommunicationStatus; -import com.xzzn.common.enums.ControlModeStatus; -import com.xzzn.common.enums.DeviceRunningStatus; -import com.xzzn.common.enums.GridStatus; -import com.xzzn.common.enums.SwitchStatus; -import com.xzzn.common.enums.WorkStatus; -import com.xzzn.common.utils.DateUtils; -import com.xzzn.common.utils.StringUtils; -import com.xzzn.ems.domain.EmsAmmeterData; -import com.xzzn.ems.domain.EmsBatteryCluster; -import com.xzzn.ems.domain.EmsBatteryData; -import com.xzzn.ems.domain.EmsBatteryDataDailyLatest; -import com.xzzn.ems.domain.EmsBatteryDataMinutes; -import com.xzzn.ems.domain.EmsBatteryGroup; -import com.xzzn.ems.domain.EmsBatteryStack; -import com.xzzn.ems.domain.EmsDailyChargeData; -import com.xzzn.ems.domain.EmsDailyEnergyData; -import com.xzzn.ems.domain.EmsDevicesSetting; -import com.xzzn.ems.domain.EmsDhData; -import com.xzzn.ems.domain.EmsPcsBranchData; -import com.xzzn.ems.domain.EmsPcsData; -import com.xzzn.ems.domain.EmsXfData; -import com.xzzn.ems.domain.vo.EnergyPriceVo; -import com.xzzn.ems.mapper.EmsAmmeterDataMapper; -import com.xzzn.ems.mapper.EmsBatteryClusterMapper; -import com.xzzn.ems.mapper.EmsBatteryDataMapper; -import com.xzzn.ems.mapper.EmsBatteryDataMinutesMapper; -import com.xzzn.ems.mapper.EmsBatteryGroupMapper; -import com.xzzn.ems.mapper.EmsBatteryStackMapper; -import com.xzzn.ems.mapper.EmsDailyChargeDataMapper; -import com.xzzn.ems.mapper.EmsDailyEnergyDataMapper; -import com.xzzn.ems.mapper.EmsDevicesSettingMapper; -import com.xzzn.ems.mapper.EmsDhDataMapper; -import com.xzzn.ems.mapper.EmsPcsBranchDataMapper; -import com.xzzn.ems.mapper.EmsPcsDataMapper; -import com.xzzn.ems.mapper.EmsXfDataMapper; -import com.xzzn.ems.service.IDDSDataProcessService; -import com.xzzn.ems.service.IEmsAlarmRecordsService; -import com.xzzn.ems.service.IEmsDeviceSettingService; -import com.xzzn.ems.utils.AbstractBatteryDataProcessor; - -import java.math.BigDecimal; -import java.time.LocalDate; -import java.time.LocalDateTime; -import java.time.format.DateTimeFormatter; -import java.time.temporal.ChronoUnit; -import java.util.ArrayList; -import java.util.Date; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.TimeUnit; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.springframework.beans.BeanUtils; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; -import org.springframework.util.CollectionUtils; - -@Service -public class DDSDataProcessServiceImpl extends AbstractBatteryDataProcessor implements IDDSDataProcessService { - private static final Log log = LogFactory.getLog(DDSDataProcessServiceImpl.class); - private static final String SITE_ID = "021_DDS_01"; - // 正则表达式匹配BMS设备编号和属性 - private static final Pattern PATTERN = Pattern.compile("(BMSD\\d{2})(ZT|SOC|SOH|DL|DY|BDSC)"); - // 匹配DTDC+数字格式的正则(提取序号) - private static final Pattern DTDC_PATTERN = Pattern.compile("DTDC(\\d+)([A-Za-z]*)"); - - @Autowired - private EmsBatteryClusterMapper emsBatteryClusterMapper; - - @Autowired - private EmsBatteryStackMapper emsBatteryStackMapper; - - @Autowired - private EmsBatteryDataMapper emsBatteryDataMapper; - - @Autowired - private EmsPcsDataMapper emsPcsDataMapper; - - @Autowired - private EmsPcsBranchDataMapper emsPcsBranchDataMapper; - - @Autowired - private RedisCache redisCache; - - @Autowired - private EmsDevicesSettingMapper emsDevicesSettingMapper; - - @Autowired - private EmsAmmeterDataMapper emsAmmeterDataMapper; - @Autowired - private EmsBatteryDailyLatestServiceImpl emsBatteryDailyLatestServiceImpl; - @Autowired - private EmsDhDataMapper emsDhDataMapper; - @Autowired - private EmsBatteryGroupMapper emsBatteryGroupMapper; - @Autowired - private EmsBatteryDataMinutesMapper emsBatteryDataMinutesMapper; - @Autowired - private EmsDailyChargeDataMapper emsDailyChargeDataMapper; - @Autowired - private IEmsAlarmRecordsService iEmsAlarmRecordsService; - @Autowired - private EmsDailyEnergyDataMapper emsDailyEnergyDataMapper; - @Autowired - private IEmsDeviceSettingService iEmsDeviceSettingService; - @Autowired - private EmsXfDataMapper emsXfDataMapper; - - public DDSDataProcessServiceImpl(ObjectMapper objectMapper) { - super(objectMapper); - } - - @Override - public void handleDdsData(String message) { - JSONObject obj = JSONObject.parseObject(message); - - String deviceId = obj.get("Device").toString(); - String jsonData = obj.get("Data").toString(); - Long timestamp = Long.valueOf(obj.get("timestamp").toString()); - Date dataUpdateTime = DateUtils.convertUpdateTime(timestamp); - - log.info("deviceId:" + deviceId); - boolean isEmpty = checkJsonDataEmpty(jsonData); - if (isEmpty) { - // 添加设备告警 - iEmsAlarmRecordsService.addEmptyDataAlarmRecord(SITE_ID,deviceId); - return; - } - - // 存放mqtt原始每个设备最晚一次数据,便于后面点位获取数据 - redisCache.setCacheObject(RedisKeyConstants.ORIGINAL_MQTT_DATA + SITE_ID + "_" + deviceId, obj); - // 存放每次同步数据,失效时间(同同步时间)-用于判断是否正常同步数据 - redisCache.setCacheObject(RedisKeyConstants.SYNC_DATA + SITE_ID + "_" + deviceId, obj, 2, TimeUnit.MINUTES); - - // 处理相关数据 - if (deviceId.contains("BMSD")) { - batteryStackDataProcess(deviceId, jsonData); - batteryGroupDataProcess(deviceId, jsonData); - batteryDataProcess(deviceId, jsonData, dataUpdateTime); - } else if (deviceId.contains("PCS")) { - pcsDataProcess(deviceId, jsonData); - pcsBranchDataProcess(deviceId, jsonData); - batteryClusterDataProcess(deviceId, jsonData); - } else if (deviceId.contains("LOAD")) { - loadDataProcess(deviceId, jsonData); - } else if (deviceId.contains("METEGF")) { - meteGFDataProcess(deviceId, jsonData); - } else if (deviceId.equals("METE")) { - meteDataProcess(deviceId, jsonData); - } else if (deviceId.contains("METE0")) { - meteBranchDataProcess(deviceId, jsonData); - } else if (deviceId.contains("XF")) { - meteXFProcess(deviceId, jsonData, dataUpdateTime); - } else if (deviceId.contains("DH")) { - dhDataProcess(deviceId, jsonData); - } - } - - private void dhDataProcess(String deviceId, String dataJson) { - //动环 - Map obj = JSON.parseObject(dataJson, new TypeReference>() { - }); - - //DH - EmsDhData dhData = new EmsDhData(); - - dhData.setHumidity(StringUtils.getBigDecimal(obj.get("SD"))); - dhData.setTemperature(StringUtils.getBigDecimal(obj.get("WD"))); - - dhData.setCreateBy("system"); - dhData.setCreateTime(DateUtils.getNowDate()); - dhData.setUpdateBy("system"); - dhData.setUpdateTime(DateUtils.getNowDate()); - dhData.setSiteId(SITE_ID); - dhData.setDeviceId(deviceId); - emsDhDataMapper.insertEmsDhData(dhData); - - redisCache.setCacheObject(RedisKeyConstants.DH + SITE_ID + "_" +deviceId, dhData); - } - - private void meteXFProcess(String deviceId, String dataJson, Date dataUpdateTime) { - //消防 - Map obj = JSON.parseObject(dataJson, new TypeReference>() { - }); - - // 暂时只更新设备表的设备状态 ZDYBYDCZT-主电源备用电池状态 - // 数据存表 - EmsXfData xfData = new EmsXfData(); - xfData.setDataTimestamp(dataUpdateTime); - xfData.setDcfzt(StringUtils.getBigDecimal(obj.get("YLKGDCFZT"))); - xfData.setDczt(StringUtils.getBigDecimal(obj.get("ZDYBYDCZT"))); - xfData.setPszt(StringUtils.getBigDecimal(obj.get("QDQTPSZT"))); - xfData.setYszt(StringUtils.getBigDecimal(obj.get("SZDYSZT"))); - - xfData.setCreateBy("system"); - xfData.setCreateTime(DateUtils.getNowDate()); - xfData.setUpdateBy("system"); - xfData.setUpdateTime(DateUtils.getNowDate()); - xfData.setSiteId(SITE_ID); - xfData.setDeviceId(deviceId); - emsXfDataMapper.insertEmsXfData(xfData); - - redisCache.setCacheObject(RedisKeyConstants.XF + SITE_ID + "_" +deviceId, xfData); - // 状态枚举还没有提供 - EmsDevicesSetting emsDevicesSetting = emsDevicesSettingMapper.getDeviceBySiteAndDeviceId(deviceId, SITE_ID); - emsDevicesSetting.setCommunicationStatus(StringUtils.getString(obj.get("ZDYBYDCZT"))); - emsDevicesSetting.setUpdatedAt(DateUtils.getNowDate()); - emsDevicesSettingMapper.updateEmsDevicesSetting(emsDevicesSetting); - } - - private void batteryStackDataProcess(String deviceId, String dataJson) { - - //电池堆 - Map obj = JSON.parseObject(dataJson, new TypeReference>() { - }); - - // 将原始数据存一下方便后面簇数据使用 - redisCache.setCacheObject(RedisKeyConstants.ORIGINAL_BMSD + SITE_ID + "_" + deviceId, obj); - //BMS 电池堆 - EmsBatteryStack dataStack = new EmsBatteryStack(); - - // 其他非 BigDecimal 字段 - dataStack.setWorkStatus(WorkStatus.NORMAL.getCode()); // 或其他默认值 - dataStack.setPcsCommunicationStatus(CommunicationStatus.OK.getCode()); - dataStack.setEmsCommunicationStatus(CommunicationStatus.OK.getCode()); - - // 电压极值信息 - dataStack.setMaxCellVoltage(StringUtils.getBigDecimal(obj.get("DTZDDY"))); - dataStack.setMaxVoltageGroupId(StringUtils.getLong(obj.get("DTZDDYXH"))); - dataStack.setMinCellVoltage(StringUtils.getBigDecimal(obj.get("DTZXDY"))); - dataStack.setMinVoltageGroupId(StringUtils.getLong(obj.get("DTZXDYXH"))); - - // 温度极值信息 - dataStack.setMaxCellTemp(StringUtils.getBigDecimal(obj.get("DTZGWD"))); - dataStack.setMaxTempGroupId(StringUtils.getLong(obj.get("DTZGWDXH"))); - dataStack.setMinCellTemp(StringUtils.getBigDecimal(obj.get("DTZDWD"))); - dataStack.setMinTempGroupId(StringUtils.getLong(obj.get("DTZDWDXH"))); - - // 干节点信号状态 - dataStack.setBatteryNumber(StringUtils.getLong(obj.get("DTGS"))); - dataStack.setBatteryAvgVoltage(StringUtils.getBigDecimal(obj.get("DTPJDY"))); - dataStack.setBatteryDifferentPressure(StringUtils.getBigDecimal(obj.get("DTDCYC"))); - dataStack.setAvgTemperature(StringUtils.getBigDecimal(obj.get("DTPJWD"))); - dataStack.setBatteryDifferentTemperature(StringUtils.getBigDecimal(obj.get("DTDCWC"))); - dataStack.setMaxInternalResistance(StringUtils.getBigDecimal(obj.get("DTZDNZ"))); - dataStack.setMinInternalResistance(StringUtils.getBigDecimal(obj.get("DTZXNZ"))); - dataStack.setAvgInternalResistance(StringUtils.getBigDecimal(obj.get("DTPJNZ"))); - dataStack.setBatteryDefferentResistance(StringUtils.getBigDecimal(obj.get("DTDCNZC"))); - dataStack.setMaxResistanceCellId(StringUtils.getLong(obj.get("DTZDNZXH"))); - dataStack.setMinResistanceCellId(StringUtils.getLong(obj.get("DTZXNZXH"))); - dataStack.setEnvironmentTemperature(StringUtils.getBigDecimal(obj.get("HJWD"))); - dataStack.setEnvironmentHumidity(StringUtils.getBigDecimal(obj.get("HJSD"))); - dataStack.setCircuitBreakerStatus(StringUtils.getString(obj.get("LDQZT"))); - - // 页面字段临时填充 - dataStack.setStackVoltage(StringUtils.getBigDecimal(obj.get("BMSD01DY"))); - dataStack.setStackCurrent(StringUtils.getBigDecimal(obj.get("BMSD01DL"))); - dataStack.setStackSoc(StringUtils.getBigDecimal(obj.get("BMSD01SOC"))); - dataStack.setStackSoh(StringUtils.getBigDecimal(obj.get("BMSD01SOH"))); - dataStack.setOperatingTemp(StringUtils.getBigDecimal(obj.get("HJWD"))); - - dataStack.setCreateBy("system"); - dataStack.setCreateTime(DateUtils.getNowDate()); - dataStack.setUpdateBy("system"); - dataStack.setUpdateTime(DateUtils.getNowDate()); - dataStack.setSiteId(SITE_ID); - dataStack.setDeviceId(deviceId); - - emsBatteryStackMapper.insertEmsBatteryStack(dataStack); - - redisCache.setCacheObject(RedisKeyConstants.STACK + SITE_ID + "_" +deviceId, dataStack); - } - - private void batteryGroupDataProcess(String deviceId, String jsonData) { - //电池组 - Map obj = JSON.parseObject(jsonData, new TypeReference>() { - }); - - Map groupMap = new HashMap<>(); - for (Map.Entry entry : obj.entrySet()) { - String key = entry.getKey(); - // 跳过空键 - if (key == null || key.trim().isEmpty()) { - continue; - } - Matcher matcher = PATTERN.matcher(key); - if (matcher.matches()) { - String groupDeviceId = matcher.group(1); - String property = matcher.group(2); - EmsBatteryGroup dataGroup = groupMap.getOrDefault(groupDeviceId, new EmsBatteryGroup()); - dataGroup.setDeviceId(groupDeviceId); - dataGroup.setSiteId(SITE_ID); - dataGroup.setCreateBy("system"); - dataGroup.setCreateTime(DateUtils.getNowDate()); - dataGroup.setUpdateBy("system"); - dataGroup.setUpdateTime(DateUtils.getNowDate()); - - setPropertyValue(dataGroup, property, entry.getValue()); - groupMap.put(groupDeviceId, dataGroup); - } - } - - // 批量插入数据库 - if (!CollectionUtils.isEmpty(groupMap)) { - List batteryGroupList = new ArrayList<>(groupMap.values()); - emsBatteryGroupMapper.batchInsertGroupData(batteryGroupList); - redisCache.setCacheObject(RedisKeyConstants.GROUP + SITE_ID + "_" +deviceId, batteryGroupList); - } - - } - //根据属性名设置对应的值 - private static void setPropertyValue(EmsBatteryGroup groupData, String property, Object value) { - BigDecimal numberValue = null; - if (value instanceof Number) { - numberValue = new BigDecimal(value.toString()); - } - - switch (property) { - case "ZT": - if (numberValue != null) { - groupData.setStatus(numberValue.toString()); - } - break; - case "SOC": - groupData.setSoc(numberValue); - break; - case "SOH": - groupData.setSoh(numberValue); - break; - case "DL": - groupData.setCurrent(numberValue); - break; - case "DY": - groupData.setVoltage(numberValue); - break; - case "BDSC": - groupData.setEstimatedBackupDuration(numberValue); - break; - } - } - private void batteryDataProcess(String deviceId, String dataJson, Date dataUpdateTime) { - //电池组 - Map obj = JSON.parseObject(dataJson, new TypeReference>() { - }); - List dataList = new ArrayList<>(); - - // 前一个小时 - LocalDateTime oneHourAgo = LocalDateTime.now().minus(1, ChronoUnit.HOURS); - DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); - String oneHourAgoStr = oneHourAgo.format(formatter); - - Map dataMap = new HashMap<>(); - Map dailyMap = new HashMap<>(); - Map minutesMap = new HashMap<>(); - - String clusterId = getClusterDeviceIdByParentDeviceId(deviceId); - for (Map.Entry entry : obj.entrySet()) { - String key = entry.getKey(); - - if (key.startsWith("DTDC")) { - Matcher matcher = DTDC_PATTERN.matcher(key); - if (matcher.matches()) { - String batteryCellId = matcher.group(1); - String property = matcher.group(2); - - EmsBatteryData data = dataMap.getOrDefault(batteryCellId, new EmsBatteryData()); - if (StringUtils.isNotEmpty(batteryCellId)) { - data.setDataTimestamp(dataUpdateTime); - data.setBatteryPack(deviceId); - data.setBatteryCluster(clusterId); - data.setClusterDeviceId(clusterId); - data.setBatteryCellId(batteryCellId); - data.setSiteId(SITE_ID); - data.setDeviceId(batteryCellId); - data.setCreateBy("system"); - data.setCreateTime(DateUtils.getNowDate()); - data.setUpdateBy("system"); - data.setUpdateTime(DateUtils.getNowDate()); - } - // 根据后缀设置对应属性 - setDTDCPropertyValue(data, property, entry.getValue()); - dataMap.put(batteryCellId, data); - - // 每日最新数据:按batteryCellId去重 - EmsBatteryDataDailyLatest daily = dailyMap.getOrDefault(batteryCellId, new EmsBatteryDataDailyLatest()); - BeanUtils.copyProperties(data, daily); - daily.setDateDay(DateUtils.getNowDate()); - dailyMap.put(batteryCellId, daily); - - // 分钟级的表,上报的数据直接存入,数据上限是 1 个小时 - EmsBatteryDataMinutes minutes = minutesMap.getOrDefault(batteryCellId, new EmsBatteryDataMinutes()); - BeanUtils.copyProperties(data, minutes); - minutesMap.put(batteryCellId, minutes); - } - } - } - if (!CollectionUtils.isEmpty(dataMap)) { - dataList = new ArrayList<>(dataMap.values()); - emsBatteryDataMapper.insertEmsBatteryDataList(new ArrayList<>(dataList)); - - redisCache.deleteList(RedisKeyConstants.BATTERY + SITE_ID + "_" + clusterId); - redisCache.setCacheList(RedisKeyConstants.BATTERY + SITE_ID + "_" + clusterId , dataList); - } - // 批量处理每日最新数据 - List dailyList = new ArrayList<>(dailyMap.values()); - if (!dailyList.isEmpty()) { - dailyList = new ArrayList<>(dailyMap.values()); - emsBatteryDailyLatestServiceImpl.batchProcessBatteryData(dailyList); - } - - // 实时插入每分钟数据 - List minutesList = new ArrayList<>(minutesMap.values()); - if (!minutesList.isEmpty()) { - emsBatteryDataMinutesMapper.insertMinutesBatteryDataList(minutesList); - } - // 清理分钟级表里一小时前数据 - emsBatteryDataMinutesMapper.deleteByTimeBeforeOneHour(oneHourAgoStr); - - // 分片处理时级,天级,月级数据 - if (dataList.size() > 0) { - super.processBatch(dataList); - } - } - - private String getClusterDeviceIdByParentDeviceId(String deviceId) { - String clusterId = "BMSC01"; - Map> map = redisCache.getCacheObject(RedisKeyConstants.INIT_DEVICE_INFO); - if (map == null || map.isEmpty()) { - map = iEmsDeviceSettingService.initDeviceInfo(); - } - // 不为空,则查找子类的簇id - if (map != null && !map.isEmpty()) { - List list = map.get(SITE_ID); - if (list != null && list.size() > 0) { - for (EmsDevicesSetting emsDevicesSetting : list) { - if (deviceId.equals(emsDevicesSetting.getParentId())) { - clusterId = emsDevicesSetting.getDeviceId(); - } - } - } - } - return clusterId; - } - - private void setDTDCPropertyValue(EmsBatteryData data, String property, Object value) { - BigDecimal numberValue = null; - if (value instanceof Number) { - numberValue = new BigDecimal(value.toString()); - } - switch (property) { - case "DY": - data.setVoltage(numberValue); - break; - case "WD": - data.setTemperature(numberValue); - break; - case "NZ": - data.setInterResistance(numberValue); - break; - } - } - - private void batteryClusterDataProcess(String deviceId, String dataJson) { - - Map obj = JSON.parseObject(dataJson, new TypeReference>() { - }); - EmsDevicesSetting joken = new EmsDevicesSetting(); - - - //BMSC 电池簇 - EmsBatteryCluster data = new EmsBatteryCluster(); - // 其他非 BigDecimal 字段 - data.setWorkStatus(WorkStatus.NORMAL.getCode()); // 或其他默认值 - data.setPcsCommunicationStatus(CommunicationStatus.OK.getCode()); - data.setEmsCommunicationStatus(CommunicationStatus.OK.getCode()); - data.setCreateBy("system"); - data.setCreateTime(DateUtils.getNowDate()); - data.setUpdateBy("system"); - data.setUpdateTime(DateUtils.getNowDate()); - data.setSiteId(SITE_ID); - // BMSC02 电流电压功率 - deviceId = "BMSC02"; - String stackDeviceId = getDeviceParent(deviceId); - if (StringUtils.isNotBlank(stackDeviceId)) { - data.setStackDeviceId(stackDeviceId); - } else { - data.setStackDeviceId("1"); - } - // 获取redis获取最新的BMSD数据 - Map stackObj = redisCache.getCacheObject(RedisKeyConstants.ORIGINAL_BMSD +SITE_ID+"_"+stackDeviceId); - data.setDeviceId(deviceId); - data.setClusterVoltage(StringUtils.getBigDecimal(obj.get("BMSC02ZLDY"))); - data.setClusterCurrent(StringUtils.getBigDecimal(obj.get("BMSC02ZLDL"))); - data.setMaxAllowedChargePower(StringUtils.getBigDecimal(obj.get("BMSC02ZLSCGL"))); - // 取堆里面数据 - data.setSoh(StringUtils.getBigDecimal(stackObj.get("BMSD02SOH"))); - data.setCurrentSoc(StringUtils.getBigDecimal(stackObj.get("BMSD02SOC"))); - data.setBatteryPackVoltage(StringUtils.getBigDecimal(stackObj.get("BMSD02DY"))); - data.setBatteryPackCurrent(StringUtils.getBigDecimal(stackObj.get("BMSD02DL"))); - data.setBatteryPackSoc(StringUtils.getBigDecimal(stackObj.get("BMSD02SOC"))); - data.setBatteryPackSoh(StringUtils.getBigDecimal(stackObj.get("BMSD02SOH"))); - data.setAvgCellTemp(StringUtils.getBigDecimal(stackObj.get("DTPJWD"))); - data.setMaxCellVoltage(StringUtils.getBigDecimal(stackObj.get("DTZDDY"))); - data.setMaxCellVoltageId(StringUtils.getString(stackObj.get("DTZDDYXH"))); - data.setMinCellVoltage(StringUtils.getBigDecimal(stackObj.get("DTZXDY"))); - data.setMinCellVoltageId(StringUtils.getString(stackObj.get("DTZXDYXH"))); - data.setMaxCellTemp(StringUtils.getBigDecimal(stackObj.get("DTZGWD"))); - data.setMaxCellTempId(StringUtils.getString(stackObj.get("DTZGWDXH"))); - data.setMinCellTemp(StringUtils.getBigDecimal(stackObj.get("DTZDWD"))); - data.setMinCellTempId(StringUtils.getString(stackObj.get("DTZDWDXH"))); - - emsBatteryClusterMapper.insertEmsBatteryCluster(data); - redisCache.setCacheObject(RedisKeyConstants.CLUSTER + SITE_ID + "_" +deviceId, data); - - // BMSC01 电流电压功率 - deviceId = "BMSC01"; - stackDeviceId = getDeviceParent(deviceId); - if (StringUtils.isNotBlank(stackDeviceId)) { - data.setStackDeviceId(stackDeviceId); - } else { - data.setStackDeviceId("1"); - } - // 获取redis获取最新的BMSD数据 - stackObj = redisCache.getCacheObject(RedisKeyConstants.ORIGINAL_BMSD +SITE_ID+"_"+stackDeviceId); - data.setDeviceId(deviceId); - data.setClusterVoltage(StringUtils.getBigDecimal(obj.get("BMSC01ZLDY"))); - data.setClusterCurrent(StringUtils.getBigDecimal(obj.get("BMSC01ZLDL"))); - data.setMaxAllowedChargePower(StringUtils.getBigDecimal(obj.get("BMSC01ZLSCGL"))); - // 取堆里面数据 - data.setSoh(StringUtils.getBigDecimal(stackObj.get("BMSD01SOH"))); - data.setCurrentSoc(StringUtils.getBigDecimal(stackObj.get("BMSD01SOC"))); - data.setBatteryPackVoltage(StringUtils.getBigDecimal(stackObj.get("BMSD01DY"))); - data.setBatteryPackCurrent(StringUtils.getBigDecimal(stackObj.get("BMSD01DL"))); - data.setBatteryPackSoc(StringUtils.getBigDecimal(stackObj.get("BMSD01SOC"))); - data.setBatteryPackSoh(StringUtils.getBigDecimal(stackObj.get("BMSD01SOH"))); - data.setAvgCellTemp(StringUtils.getBigDecimal(stackObj.get("DTPJWD"))); - data.setMaxCellVoltage(StringUtils.getBigDecimal(stackObj.get("DTZDDY"))); - data.setMaxCellVoltageId(StringUtils.getString(stackObj.get("DTZDDYXH"))); - data.setMinCellVoltage(StringUtils.getBigDecimal(stackObj.get("DTZXDY"))); - data.setMinCellVoltageId(StringUtils.getString(stackObj.get("DTZXDYXH"))); - data.setMaxCellTemp(StringUtils.getBigDecimal(stackObj.get("DTZGWD"))); - data.setMaxCellTempId(StringUtils.getString(stackObj.get("DTZGWDXH"))); - data.setMinCellTemp(StringUtils.getBigDecimal(stackObj.get("DTZDWD"))); - data.setMinCellTempId(StringUtils.getString(stackObj.get("DTZDWDXH"))); - - emsBatteryClusterMapper.insertEmsBatteryCluster(data); - redisCache.setCacheObject(RedisKeyConstants.CLUSTER + SITE_ID + "_" +deviceId, data); - } - - private String getDeviceParent(String deviceId) { - Map> map = redisCache.getCacheObject(RedisKeyConstants.INIT_DEVICE_INFO); - if (map == null || map.isEmpty()) { - map = iEmsDeviceSettingService.initDeviceInfo(); - } - // 不为空,则查找父类 - String stackDeviceId = "1"; - if (map != null && !map.isEmpty()) { - List list = map.get(SITE_ID); - if (list == null || list.isEmpty()) { - EmsDevicesSetting deviceInfo = new EmsDevicesSetting(); - deviceInfo.setDeviceId(deviceId); - deviceInfo.setSiteId(SITE_ID); - list = emsDevicesSettingMapper.selectEmsDevicesSettingList(deviceInfo); - if (list == null || list.isEmpty()) { - return stackDeviceId; - } - } - for (EmsDevicesSetting emsDevicesSetting : list) { - if (deviceId.equals(emsDevicesSetting.getDeviceId())) { - stackDeviceId = emsDevicesSetting.getParentId(); - } - } - } - return stackDeviceId; - } - - private void meteBranchDataProcess(String deviceId, String dataJson) { - Map obj = JSON.parseObject(dataJson, new TypeReference>() { - }); - //pcs电表数据 - EmsAmmeterData data = new EmsAmmeterData(); - // 更新时间 - data.setDataUpdateTime(new Date()); - - // 当月有功电能 - data.setCurrentForwardActiveTotal(StringUtils.getBigDecimal(obj.get("DQYZZXYGDN"))); - data.setCurrentForwardActivePeak(StringUtils.getBigDecimal(obj.get("DQYJZXYGDN"))); - data.setCurrentForwardActiveHigh(StringUtils.getBigDecimal(obj.get("DQYFZXYGDN"))); - data.setCurrentForwardActiveFlat(StringUtils.getBigDecimal(obj.get("DQYPZXYGDN"))); - data.setCurrentForwardActiveValley(StringUtils.getBigDecimal(obj.get("DQYGZXYGDN"))); - data.setCurrentReverseActiveTotal(StringUtils.getBigDecimal(obj.get("DQYZFXYGDN"))); - data.setCurrentReverseActivePeak(StringUtils.getBigDecimal(obj.get("DQYJFXYGDN"))); - data.setCurrentReverseActiveHigh(StringUtils.getBigDecimal(obj.get("DQYFFXYGDN"))); - data.setCurrentReverseActiveFlat(StringUtils.getBigDecimal(obj.get("DQYPFXYGDN"))); - data.setCurrentReverseActiveValley(StringUtils.getBigDecimal(obj.get("DQYGFXYGDN"))); - - // 总有功电能 - data.setTotalForwardActiveTwo(StringUtils.getBigDecimal(obj.get("ZZXYGDN2"))); - data.setTotalPeakForwardActive(StringUtils.getBigDecimal(obj.get("ZJZXYGDN"))); - data.setTotalHighForwardActive(StringUtils.getBigDecimal(obj.get("ZFZXYGDN"))); - data.setTotalFlatForwardActive(StringUtils.getBigDecimal(obj.get("ZPZXYGDN"))); - data.setTotalValleyForwardActive(StringUtils.getBigDecimal(obj.get("ZGZXYGDN"))); - data.setTotalReverseActiveTwo(StringUtils.getBigDecimal(obj.get("ZFXYGDN2"))); - data.setTotalPeakReverseActive(StringUtils.getBigDecimal(obj.get("ZJFXYGDN"))); - data.setTotalHighReverseActive(StringUtils.getBigDecimal(obj.get("ZFFXYGDN"))); - data.setTotalFlatReverseActive(StringUtils.getBigDecimal(obj.get("ZPFXYGDN"))); - data.setTotalValleyReverseActive(StringUtils.getBigDecimal(obj.get("ZGFXYGDN"))); - - // 其他字段 - data.setVoltagePercent(StringUtils.getBigDecimal(obj.get("DYBB"))); - data.setDisconnectDetectionIndication(StringUtils.getString(obj.get("DXJCZS"))); - data.setRatedPrimaryCurrentValue(StringUtils.getBigDecimal(obj.get("EDYCDLZ"))); - data.setSwitchInputOutputStatus(StringUtils.getString(obj.get("KGLSRSCZT"))); - data.setAlarmStatus(StringUtils.getString(obj.get("BJZT"))); - data.setCurrentTotalVoltagePercent(StringUtils.getBigDecimal(obj.get("DQZDYBFB"))); - data.setVoltageContentPercent(StringUtils.getBigDecimal(obj.get("DYZLHLBFB"))); - data.setVoltageAcPercent(StringUtils.getBigDecimal(obj.get("DYJLHLBFB"))); - data.setCurrentTotalCurrentPercent(StringUtils.getBigDecimal(obj.get("DQZDLBFB"))); - data.setCurrentContentPercent(StringUtils.getBigDecimal(obj.get("DLZLHLBFB"))); - data.setCurrentAcPercent(StringUtils.getBigDecimal(obj.get("DLJLHLBFB"))); - data.setCurrentTotalPowerPercent(StringUtils.getBigDecimal(obj.get("DQZGLBFB"))); - data.setPowerContentPercent(StringUtils.getBigDecimal(obj.get("GLZLHLBFB"))); - data.setPowerAcPercent(StringUtils.getBigDecimal(obj.get("GLJLHLBFB"))); - data.setDataSettingYearMonth(StringUtils.getString(obj.get("RQSJSZNY"))); - data.setDataSettingDayHour(StringUtils.getString(obj.get("RQSJSZRS"))); - data.setDataSettingMinutesSeconds(StringUtils.getString(obj.get("RQSJSZFM"))); - data.setCurrentRate(StringUtils.getBigDecimal(obj.get("DQCBRFL"))); - data.setVersionNumber(StringUtils.getString(obj.get("RJBBH"))); - data.setVoltage(StringUtils.getBigDecimal(obj.get("DY"))); - data.setCurrent(StringUtils.getBigDecimal(obj.get("DL"))); - data.setPower(StringUtils.getBigDecimal(obj.get("GL"))); - data.setInternalTemp(StringUtils.getBigDecimal(obj.get("NBWD"))); - data.setTotalForwardActiveOne(StringUtils.getBigDecimal(obj.get("ZZXYGDN1"))); - data.setTotalReverseActiveOne(StringUtils.getBigDecimal(obj.get("ZFXYGDN1"))); - - data.setCreateBy("system"); - data.setCreateTime(DateUtils.getNowDate()); - data.setUpdateBy("system"); - data.setUpdateTime(DateUtils.getNowDate()); - data.setSiteId(SITE_ID); - data.setDeviceId(deviceId); - emsAmmeterDataMapper.insertEmsAmmeterData(data); - redisCache.setCacheObject(RedisKeyConstants.AMMETER + SITE_ID + "_" +deviceId, data); - } - - private void pcsDataProcess(String deviceId, String dataJson) { - Map obj = JSON.parseObject(dataJson, new TypeReference>() { - }); - //pcs - EmsPcsData pcsData = new EmsPcsData(); - // 时间与状态类字段 - pcsData.setDataUpdateTime(new Date()); - pcsData.setWorkStatus(WorkStatus.NORMAL.getCode()); - pcsData.setGridStatus(GridStatus.GRID.getCode()); - pcsData.setDeviceStatus(DeviceRunningStatus.ONLINE.getCode()); - pcsData.setControlMode(ControlModeStatus.REMOTE.getCode()); - - // 电流 - pcsData.setaPhaseCurrent(StringUtils.getBigDecimal(obj.get("PCSJLDLIA"))); - pcsData.setbPhaseCurrent(StringUtils.getBigDecimal(obj.get("PCSJLDLIB"))); - pcsData.setcPhaseCurrent(StringUtils.getBigDecimal(obj.get("PCSJLDLIC"))); - - // 功率与能量类字段 - pcsData.setDcPower(StringUtils.getBigDecimal(obj.get("ZLZGL"))); - pcsData.setDcVoltage(StringUtils.getBigDecimal(obj.get("ZLDY"))); - pcsData.setDcCurrent(StringUtils.getBigDecimal(obj.get("ZLDL"))); - pcsData.setTotalActivePower(StringUtils.getBigDecimal(obj.get("JLYGGL"))); - pcsData.setTotalReactivePower(StringUtils.getBigDecimal(obj.get("JLWGGL"))); - pcsData.setTotalAcChargeEnergy(StringUtils.getBigDecimal(obj.get("CDDN"))); - pcsData.setTotalAcDischargeEnergy(StringUtils.getBigDecimal(obj.get("FDDN"))); - - // 电网频率 - pcsData.setDwFrequency(StringUtils.getBigDecimal(obj.get("DWPL"))); - - // 状态指示类 - pcsData.setBranchStatus(BranchStatus.NORMAL.getCode()); - pcsData.setDischargeStatus(ChargeStatus.CHARGING.getCode()); - String acSwitchStatus = StringUtils.getString(obj.get("JLKGZT")); - pcsData.setAcSwitchStatus(SwitchStatus.CLOSED.getCode()); - String dcSwitchStatus = StringUtils.getString(obj.get("ZLKGZT")); - pcsData.setDcSwitchStatus(SwitchStatus.CLOSED.getCode()); - String controlMode = StringUtils.getString(obj.get("YCTT")); - pcsData.setRemoteControlStatus(ControlModeStatus.REMOTE.getCode()); - - // 电流参数 - pcsData.setSysUCurrent(StringUtils.getBigDecimal(obj.get("XTSCUXDL"))); - pcsData.setSysVCurrent(StringUtils.getBigDecimal(obj.get("XTSCVXDL"))); - pcsData.setSysWCurrent(StringUtils.getBigDecimal(obj.get("XTSCWXDL"))); - - // 页面字段填充 - pcsData.setAcFrequency(StringUtils.getBigDecimal(obj.get("DWPL"))); - pcsData.setTotalApparentPower(StringUtils.getBigDecimal(obj.get("ZLZGL"))); - pcsData.setTotalPowerFactor(new BigDecimal(0)); - - // 模块温度 - pcsData.setModule1Temp(StringUtils.getBigDecimal(obj.get("IGBYZGWD1"))); - pcsData.setModule2Temp(StringUtils.getBigDecimal(obj.get("IGBYZGWD2"))); - pcsData.setModule3Temp(StringUtils.getBigDecimal(obj.get("IGBYZGWD3"))); - pcsData.setModule4Temp(StringUtils.getBigDecimal(obj.get("IGBYZGWD4"))); - - // 系统管理字段 - pcsData.setCreateBy("system"); - pcsData.setCreateTime(DateUtils.getNowDate()); - pcsData.setUpdateBy("system"); - pcsData.setUpdateTime(DateUtils.getNowDate()); - pcsData.setSiteId(SITE_ID); - pcsData.setDeviceId(deviceId); - pcsData.setDateMonth(DateUtils.getNowMonthLong()); - pcsData.setDateDay(DateUtils.getNowDayLong()); - - emsPcsDataMapper.insertEmsPcsData(pcsData); - redisCache.setCacheObject(RedisKeyConstants.PCS + SITE_ID + "_" +deviceId, pcsData); - - } - - private void pcsBranchDataProcess(String deviceId, String dataJson) { - - Map records = JSON.parseObject(dataJson, new TypeReference>() { - }); - List list = new ArrayList<>(); - - EmsPcsBranchData data = new EmsPcsBranchData(); - data.setDeviceId(deviceId); - data.setSiteId(SITE_ID); - data.setGridStatus(GridStatus.GRID.getCode()); - - data.setGridUVoltage(StringUtils.getBigDecimal(records.get("DWXDYUAB"))); - data.setGridVVoltage(StringUtils.getBigDecimal(records.get("DWXDYUBC"))); - data.setGridWVoltage(StringUtils.getBigDecimal(records.get("DWXDYUCA"))); - data.setOutputUCurrent(StringUtils.getBigDecimal(records.get("PCSJLDLIA"))); - data.setOutputVCurrent(StringUtils.getBigDecimal(records.get("PCSJLDLIB"))); - data.setOutputWCurrent(StringUtils.getBigDecimal(records.get("PCSJLDLIC"))); - - // 页面字段填充 - data.setDcPower(StringUtils.getBigDecimal(records.get("ZLZGL"))); - data.setDcVoltage(StringUtils.getBigDecimal(records.get("ZLDY"))); - data.setDcCurrent(StringUtils.getBigDecimal(records.get("ZLDL"))); - - data.setBranchId("DY1"); - data.setCreateBy("system"); - data.setCreateTime(DateUtils.getNowDate()); - data.setUpdateBy("system"); - data.setUpdateTime(DateUtils.getNowDate()); - list.add(data); - emsPcsBranchDataMapper.insertPcsBranchDataList(list); - redisCache.setCacheObject(RedisKeyConstants.BRANCH + SITE_ID + "_" +deviceId, list); - } - - private void meteGFDataProcess(String deviceId, String dataJson) { - - //总表 - Map obj = JSON.parseObject(dataJson, new TypeReference>() { - }); - - EmsAmmeterData dataGF = new EmsAmmeterData(); - // 更新时间 - dataGF.setDataUpdateTime(new Date()); - - // 电压+电流 - dds字段 - dataGF.setPhaseAVoltage(StringUtils.getBigDecimal(obj.get("AXDY"))); - dataGF.setPhaseBVoltage(StringUtils.getBigDecimal(obj.get("BXDY"))); - dataGF.setPhaseCVoltage(StringUtils.getBigDecimal(obj.get("CXDY"))); - dataGF.setPhaseACurrent(StringUtils.getBigDecimal(obj.get("AXDL"))); - dataGF.setPhaseBCurrent(StringUtils.getBigDecimal(obj.get("BXDL"))); - dataGF.setPhaseCCurrent(StringUtils.getBigDecimal(obj.get("CXDL"))); - - dataGF.setAbLineVoltage(StringUtils.getBigDecimal(obj.get("ABXDY"))); - dataGF.setCbLineVoltage(StringUtils.getBigDecimal(obj.get("BCXDY"))); - dataGF.setAcLineVoltage(StringUtils.getBigDecimal(obj.get("CAXDY"))); - - // 频率 - dataGF.setFrequency(StringUtils.getBigDecimal(obj.get("PL"))); - - // 功率 有功+总+无功+无总+视在 - dataGF.setPhaseAActivePower(StringUtils.getBigDecimal(obj.get("AXYGGL"))); - dataGF.setPhaseBActivePower(StringUtils.getBigDecimal(obj.get("BXYGGL"))); - dataGF.setPhaseCActivePower(StringUtils.getBigDecimal(obj.get("CXYGGL"))); - dataGF.setTotalActivePower(StringUtils.getBigDecimal(obj.get("ZYGGL"))); - dataGF.setPhaseAReactivePower(StringUtils.getBigDecimal(obj.get("AXWGGL"))); - dataGF.setPhaseBReactivePower(StringUtils.getBigDecimal(obj.get("BXWGGL"))); - dataGF.setPhaseCReactivePower(StringUtils.getBigDecimal(obj.get("CXWGGL"))); - dataGF.setTotalReactivePower(StringUtils.getBigDecimal(obj.get("ZWGGL"))); - dataGF.setPhaseAApparentPower(StringUtils.getBigDecimal(obj.get("AXSZGL"))); - dataGF.setPhaseBApparentPower(StringUtils.getBigDecimal(obj.get("BXSZGL"))); - dataGF.setPhaseCApparentPower(StringUtils.getBigDecimal(obj.get("CXSZGL"))); - dataGF.setTotalApparentPower(StringUtils.getBigDecimal(obj.get("ZSZGL"))); - - // 功率因数 - dataGF.setPhaseAPowerFactor(StringUtils.getBigDecimal(obj.get("AXGLYS"))); - dataGF.setPhaseBPowerFactor(StringUtils.getBigDecimal(obj.get("BXGLYS"))); - dataGF.setPhaseCPowerFactor(StringUtils.getBigDecimal(obj.get("CXGLYS"))); - dataGF.setTotalPowerFactor(StringUtils.getBigDecimal(obj.get("ZGLYS"))); - - // 其他字段 - dataGF.setPositiveReactiveEnergyEqPlus(StringUtils.getBigDecimal(obj.get("WGDN"))); - dataGF.setPositiveActiveEnergyEpPlus(StringUtils.getBigDecimal(obj.get("YGDN"))); - dataGF.setCurrentPercent(StringUtils.getBigDecimal(obj.get("DLBB"))); - dataGF.setVoltagePercent(StringUtils.getBigDecimal(obj.get("DYBB"))); - dataGF.setAvgCurrent(StringUtils.getBigDecimal(obj.get("PJDL"))); - - dataGF.setCreateBy("system"); - dataGF.setCreateTime(DateUtils.getNowDate()); - dataGF.setUpdateBy("system"); - dataGF.setUpdateTime(DateUtils.getNowDate()); - dataGF.setSiteId(SITE_ID); - dataGF.setDeviceId(deviceId); - - emsAmmeterDataMapper.insertEmsAmmeterData(dataGF); - - redisCache.setCacheObject(RedisKeyConstants.AMMETER + SITE_ID + "_" +deviceId, dataGF); - } - - private void loadDataProcess(String deviceId, String dataJson) { - - //总表 - Map obj = JSON.parseObject(dataJson, new TypeReference>() { - }); - - EmsAmmeterData dataLoad = new EmsAmmeterData(); - // 更新时间 - dataLoad.setDataUpdateTime(new Date()); - - // 电压+电流 - dds字段 - dataLoad.setPhaseAVoltage(StringUtils.getBigDecimal(obj.get("XDYUA"))); - dataLoad.setPhaseBVoltage(StringUtils.getBigDecimal(obj.get("XDYUB"))); - dataLoad.setPhaseCVoltage(StringUtils.getBigDecimal(obj.get("XDYUC"))); - dataLoad.setPhaseACurrent(StringUtils.getBigDecimal(obj.get("XDLIA"))); - dataLoad.setPhaseBCurrent(StringUtils.getBigDecimal(obj.get("XDLIB"))); - dataLoad.setPhaseCCurrent(StringUtils.getBigDecimal(obj.get("XDLIC"))); - - dataLoad.setAbLineVoltage(StringUtils.getBigDecimal(obj.get("XDYUAB"))); - dataLoad.setCbLineVoltage(StringUtils.getBigDecimal(obj.get("XDYUBC"))); - dataLoad.setAcLineVoltage(StringUtils.getBigDecimal(obj.get("XDYUCA"))); - - // 频率 - dataLoad.setFrequency(StringUtils.getBigDecimal(obj.get("PL"))); - - // 功率 有功+总+无功+无总+视在 - dataLoad.setPhaseAActivePower(StringUtils.getBigDecimal(obj.get("AXYGGL"))); - dataLoad.setPhaseBActivePower(StringUtils.getBigDecimal(obj.get("BXYGGL"))); - dataLoad.setPhaseCActivePower(StringUtils.getBigDecimal(obj.get("CXYGGL"))); - dataLoad.setTotalActivePower(StringUtils.getBigDecimal(obj.get("YGZGL"))); - dataLoad.setPhaseAReactivePower(StringUtils.getBigDecimal(obj.get("AXWGGL"))); - dataLoad.setPhaseBReactivePower(StringUtils.getBigDecimal(obj.get("BXWGGL"))); - dataLoad.setPhaseCReactivePower(StringUtils.getBigDecimal(obj.get("CXWGGL"))); - dataLoad.setTotalReactivePower(StringUtils.getBigDecimal(obj.get("WGZGL"))); - dataLoad.setPhaseAApparentPower(StringUtils.getBigDecimal(obj.get("AXSZGL"))); - dataLoad.setPhaseBApparentPower(StringUtils.getBigDecimal(obj.get("BXSZGL"))); - dataLoad.setPhaseCApparentPower(StringUtils.getBigDecimal(obj.get("CXSZGL"))); - dataLoad.setTotalApparentPower(StringUtils.getBigDecimal(obj.get("ZSZGL"))); - - // 功率因数 - dataLoad.setPhaseAPowerFactor(StringUtils.getBigDecimal(obj.get("AXGLYS"))); - dataLoad.setPhaseBPowerFactor(StringUtils.getBigDecimal(obj.get("BXGLYS"))); - dataLoad.setPhaseCPowerFactor(StringUtils.getBigDecimal(obj.get("CXGLYS"))); - dataLoad.setTotalPowerFactor(StringUtils.getBigDecimal(obj.get("ZGLYS"))); - - // 电度 - dataLoad.setSecondaryReverseReactiveEnergy(StringUtils.getBigDecimal(obj.get("GXWGDDECC"))); - dataLoad.setSecondaryNegativeActiveEnergy(StringUtils.getBigDecimal(obj.get("SFTGDDECC"))); - dataLoad.setSecondaryPositiveReactiveEnergy(StringUtils.getBigDecimal(obj.get("RXWGDDECC"))); - dataLoad.setSecondaryPositiveActiveEnergy(StringUtils.getBigDecimal(obj.get("XSYGDDECC"))); - dataLoad.setReverseReactiveEnergyEqMinus(StringUtils.getBigDecimal(obj.get("RXWGDDYCC"))); - dataLoad.setReverseActiveEnergyEpMinus(StringUtils.getBigDecimal(obj.get("SFYGDDYCC"))); - dataLoad.setPositiveReactiveEnergyEqPlus(StringUtils.getBigDecimal(obj.get("GXWGDDYCC"))); - dataLoad.setPositiveActiveEnergyEpPlus(StringUtils.getBigDecimal(obj.get("XSYGDDYCC"))); - - // 正向反向有功无功电能 - dataLoad.setCurrentForwardActiveTotal(StringUtils.getBigDecimal(obj.get("XSYGDDYCC"))); - dataLoad.setCurrentReverseActiveTotal(StringUtils.getBigDecimal(obj.get("SFYGDDYCC"))); - dataLoad.setCurrentForwardReactiveTotal(StringUtils.getBigDecimal(obj.get("GXWGDDYCC"))); - dataLoad.setCurrentReverseReactiveTotal(StringUtils.getBigDecimal(obj.get("RXWGDDYCC"))); - - dataLoad.setCreateBy("system"); - dataLoad.setCreateTime(DateUtils.getNowDate()); - dataLoad.setUpdateBy("system"); - dataLoad.setUpdateTime(DateUtils.getNowDate()); - dataLoad.setSiteId(SITE_ID); - dataLoad.setDeviceId(deviceId); - - emsAmmeterDataMapper.insertEmsAmmeterData(dataLoad); - - redisCache.setCacheObject(RedisKeyConstants.AMMETER + SITE_ID + "_" +deviceId, dataLoad); - } - - private void meteDataProcess(String deviceId, String dataJson) { - - //总表 - Map obj = JSON.parseObject(dataJson, new TypeReference>() { - }); - - EmsAmmeterData dataMete = new EmsAmmeterData(); - // 更新时间 - dataMete.setDataUpdateTime(new Date()); - - // 电压+电流 - dataMete.setPhaseAVoltage(StringUtils.getBigDecimal(obj.get("AXDY"))); - dataMete.setPhaseBVoltage(StringUtils.getBigDecimal(obj.get("BXDY"))); - dataMete.setPhaseCVoltage(StringUtils.getBigDecimal(obj.get("CXDY"))); - dataMete.setPhaseACurrent(StringUtils.getBigDecimal(obj.get("AXDL"))); - dataMete.setPhaseBCurrent(StringUtils.getBigDecimal(obj.get("BXDL"))); - dataMete.setPhaseCCurrent(StringUtils.getBigDecimal(obj.get("CXDL"))); - - dataMete.setAbLineVoltage(StringUtils.getBigDecimal(obj.get("ABXDY"))); - dataMete.setCbLineVoltage(StringUtils.getBigDecimal(obj.get("BCXDY"))); - dataMete.setAcLineVoltage(StringUtils.getBigDecimal(obj.get("CAXDY"))); - - // 频率 - dataMete.setFrequency(StringUtils.getBigDecimal(obj.get("DWPL"))); - - // 功率 - dataMete.setPhaseAActivePower(StringUtils.getBigDecimal(obj.get("AXYGGL"))); - dataMete.setPhaseBActivePower(StringUtils.getBigDecimal(obj.get("BXYGGL"))); - dataMete.setPhaseCActivePower(StringUtils.getBigDecimal(obj.get("CXYGGL"))); - dataMete.setTotalActivePower(StringUtils.getBigDecimal(obj.get("ZYGGL"))); - dataMete.setPhaseAReactivePower(StringUtils.getBigDecimal(obj.get("AXWGGL"))); - dataMete.setPhaseBReactivePower(StringUtils.getBigDecimal(obj.get("BXWGGL"))); - dataMete.setPhaseCReactivePower(StringUtils.getBigDecimal(obj.get("CXWGGL"))); - dataMete.setTotalReactivePower(StringUtils.getBigDecimal(obj.get("ZWGGL"))); - dataMete.setPhaseAApparentPower(StringUtils.getBigDecimal(obj.get("AXSZGL"))); - dataMete.setPhaseBApparentPower(StringUtils.getBigDecimal(obj.get("BXSZGL"))); - dataMete.setPhaseCApparentPower(StringUtils.getBigDecimal(obj.get("CXSZGL"))); - dataMete.setTotalApparentPower(StringUtils.getBigDecimal(obj.get("ZSZGL"))); - dataMete.setPhaseAPowerFactor(StringUtils.getBigDecimal(obj.get("AXGLYS"))); - dataMete.setPhaseBPowerFactor(StringUtils.getBigDecimal(obj.get("BXGLYS"))); - dataMete.setPhaseCPowerFactor(StringUtils.getBigDecimal(obj.get("CXGLYS"))); - dataMete.setTotalPowerFactor(StringUtils.getBigDecimal(obj.get("ZGLYS"))); - - // 电能设置-组合有功 - dataMete.setCurrentCombActiveTotal(StringUtils.getBigDecimal(obj.get("DQZHYGZDN"))); - dataMete.setCurrentCombActivePeak(StringUtils.getBigDecimal(obj.get("DQZHYGJDN"))); - dataMete.setCurrentCombActiveHigh(StringUtils.getBigDecimal(obj.get("DQZHYGFDN"))); - dataMete.setCurrentCombActiveFlat(StringUtils.getBigDecimal(obj.get("DQZHYGPDN"))); - dataMete.setCurrentCombActiveValley(StringUtils.getBigDecimal(obj.get("DQZHYGGDN"))); - // 电能设置-正向有功 - dataMete.setCurrentForwardActiveTotal(StringUtils.getBigDecimal(obj.get("DQZXZYGDN"))); - dataMete.setCurrentForwardActivePeak(StringUtils.getBigDecimal(obj.get("DQZXYGJDN"))); - dataMete.setCurrentForwardActiveHigh(StringUtils.getBigDecimal(obj.get("DQZXYGFDN"))); - dataMete.setCurrentForwardActiveFlat(StringUtils.getBigDecimal(obj.get("DQZXYGPDN"))); - dataMete.setCurrentForwardActiveValley(StringUtils.getBigDecimal(obj.get("DQZXYGGDN"))); - // 电能设置-反向有功 - dataMete.setCurrentReverseActiveTotal(StringUtils.getBigDecimal(obj.get("DQFXZYGDN"))); - dataMete.setCurrentReverseActivePeak(StringUtils.getBigDecimal(obj.get("DQFXYGJDN"))); - dataMete.setCurrentReverseActiveHigh(StringUtils.getBigDecimal(obj.get("DQFXYGFDN"))); - dataMete.setCurrentReverseActiveFlat(StringUtils.getBigDecimal(obj.get("DQFXYGPDN"))); - dataMete.setCurrentReverseActiveValley(StringUtils.getBigDecimal(obj.get("DQFXYGGDN"))); - // 电能设置-组合无功 - dataMete.setCurrentCombReactiveTotal(StringUtils.getBigDecimal(obj.get("DQZHWGZDN"))); - dataMete.setCurrentCombReactivePeak(StringUtils.getBigDecimal(obj.get("DQZHWGJDN"))); - dataMete.setCurrentCombReactiveHigh(StringUtils.getBigDecimal(obj.get("DQZHWGFDN"))); - dataMete.setCurrentCombReactiveFlat(StringUtils.getBigDecimal(obj.get("DQZHWGPDN"))); - dataMete.setCurrentCombReactiveValley(StringUtils.getBigDecimal(obj.get("DQZHWGGDN"))); - // 电能设置-正向无功 - dataMete.setCurrentForwardReactiveTotal(StringUtils.getBigDecimal(obj.get("DQZXZWGDN"))); - dataMete.setCurrentForwardReactivePeak(StringUtils.getBigDecimal(obj.get("DQZXWGJDN"))); - dataMete.setCurrentForwardReactiveHigh(StringUtils.getBigDecimal(obj.get("DQZXWGFDN"))); - dataMete.setCurrentForwardReactiveFlat(StringUtils.getBigDecimal(obj.get("DQZXWGPDN"))); - dataMete.setCurrentForwardReactiveValley(StringUtils.getBigDecimal(obj.get("DQZXWGGDN"))); - // 电能设置-反向无功 - dataMete.setCurrentReverseReactiveTotal(StringUtils.getBigDecimal(obj.get("DQFXZWGDN"))); - dataMete.setCurrentReverseReactivePeak(StringUtils.getBigDecimal(obj.get("DQFXWGJDN"))); - dataMete.setCurrentReverseReactiveHigh(StringUtils.getBigDecimal(obj.get("DQFXWGFDN"))); - dataMete.setCurrentReverseReactiveFlat(StringUtils.getBigDecimal(obj.get("DQFXWGPDN"))); - dataMete.setCurrentReverseReactiveValley(StringUtils.getBigDecimal(obj.get("DQFXWGGDN"))); - // abc相 - dataMete.setaForwardActiveEnergy(StringUtils.getBigDecimal(obj.get("AXZXYGDN"))); - dataMete.setbForwardActiveEnergy(StringUtils.getBigDecimal(obj.get("BXZXYGDN"))); - dataMete.setcForwardActiveEnergy(StringUtils.getBigDecimal(obj.get("CXZXYGDN"))); - - // 变比 - dataMete.setCurrentPercent(StringUtils.getBigDecimal(obj.get("DLBBCT"))); - dataMete.setVoltagePercent(StringUtils.getBigDecimal(obj.get("DYBBPT"))); - - // 需量 - dataMete.setForwardAcMaxDemand(StringUtils.getBigDecimal(obj.get("ZXYGZDXL"))); - dataMete.setReverseAcMaxDemand(StringUtils.getBigDecimal(obj.get("FXYGZDXL"))); - dataMete.setDailyForwardMaxDemand(StringUtils.getBigDecimal(obj.get("DRZXYGZDXL"))); - dataMete.setForwardReactiveMaxDemand(StringUtils.getBigDecimal(obj.get("ZXWGZDXL"))); - dataMete.setReverseReactiveMaxDemand(StringUtils.getBigDecimal(obj.get("FXWGZDXL"))); - dataMete.setDailyReverseAcMaxDemand(StringUtils.getBigDecimal(obj.get("DRFXYGZDXL"))); - dataMete.setDailyForwardReacMaxDemand(StringUtils.getBigDecimal(obj.get("DRZXWGZDXL"))); - dataMete.setDailyReverseReacMaxDemand(StringUtils.getBigDecimal(obj.get("DRFXWGZDXL"))); - - dataMete.setPreDayForwardAcMaxDemand(StringUtils.getBigDecimal(obj.get("S1RZXYGZDXL"))); - dataMete.setPreDayReverseAcMaxDemand(StringUtils.getBigDecimal(obj.get("S1RFXYGZDXL"))); - dataMete.setPreDayForwardReacMaxDemand(StringUtils.getBigDecimal(obj.get("S1RZXWGZDX"))); - dataMete.setPreDayReverseReacMaxDemand(StringUtils.getBigDecimal(obj.get("S1RFXWGZDX"))); - dataMete.setPre2dForwardAcMaxDemand(StringUtils.getBigDecimal(obj.get("S2RZXYGZDXL"))); - dataMete.setPre2dReverseAcMaxDemand(StringUtils.getBigDecimal(obj.get("S2RFXYGZDXL"))); - dataMete.setPre2dForwardReacMaxDemand(StringUtils.getBigDecimal(obj.get("S2RZXWGZDXL"))); - dataMete.setPre2dReverseReacMaxDemand(StringUtils.getBigDecimal(obj.get("S2RFXWGZDXL"))); - - dataMete.setCurrentForwardAcDemand(StringUtils.getBigDecimal(obj.get("DQZXYGXL"))); - dataMete.setCurrentReverseAcDemand(StringUtils.getBigDecimal(obj.get("DQFXYGXL"))); - dataMete.setCurrentForwardReacDemand(StringUtils.getBigDecimal(obj.get("DQZXWGXL"))); - dataMete.setCurrentReverseReacDemand(StringUtils.getBigDecimal(obj.get("DQFXWGXL"))); - - // 其他字段 - dataMete.setDidoStatus(StringUtils.getString(obj.get("DIDOZTSYZT"))); - dataMete.setRunningStatus(StringUtils.getString(obj.get("YXZT"))); - dataMete.setZeroSeqCurrent(StringUtils.getBigDecimal(obj.get("LXDL"))); - dataMete.setVoltageUnbalanceDegree(StringUtils.getBigDecimal(obj.get("DYBPHD"))); - dataMete.setCurrentUnbalanceDegree(StringUtils.getBigDecimal(obj.get("DLBPHD"))); - - // 储能功率 - dataMete.setSecondaryTotalActivePower(StringUtils.getBigDecimal(obj.get("ZYGGL"))); - - dataMete.setCreateBy("system"); - dataMete.setCreateTime(DateUtils.getNowDate()); - dataMete.setUpdateBy("system"); - dataMete.setUpdateTime(DateUtils.getNowDate()); - dataMete.setSiteId(SITE_ID); - dataMete.setDeviceId(deviceId); - - emsAmmeterDataMapper.insertEmsAmmeterData(dataMete); - - redisCache.setCacheObject(RedisKeyConstants.AMMETER + SITE_ID + "_" +deviceId, dataMete); - - // 处理每日充放电数据 - dealDDSDailyChargeDate(obj,deviceId); - } - - private EmsDailyEnergyData initEnergyData() { - EmsDailyEnergyData energyData = new EmsDailyEnergyData(); - energyData.setSiteId(SITE_ID); - energyData.setDataDate(DateUtils.getNowDate()); - energyData.setCreateBy("system"); - energyData.setCreateTime(DateUtils.getNowDate()); - energyData.setUpdateBy("system"); - energyData.setUpdateTime(DateUtils.getNowDate()); - return energyData; - } - - private void dealDDSDailyChargeDate(Map obj, String deviceId) { - // 初始化今日充放电 - BigDecimal dailyDisChargeDate = new BigDecimal(0); - BigDecimal dailyChargeDate = new BigDecimal(0); - - BigDecimal nowTotalDisChargeDate = StringUtils.getBigDecimal(obj.get("DQFXZYGDN")); - BigDecimal nowTotalChargeDate = StringUtils.getBigDecimal(obj.get("DQZXZYGDN")); - // 初始化当日数据-总的 - EmsDailyChargeData emsDailyChargeData = initDailyChargeData(deviceId,nowTotalChargeDate,nowTotalDisChargeDate); - // 获取redis存放昨日最晚数据 - String yestDate = DateUtils.getYesterdayDate(); - String yestDateRedisKey = RedisKeyConstants.AMMETER + SITE_ID + "_" + deviceId + "_" + yestDate; - EmsAmmeterData yestData = redisCache.getCacheObject(yestDateRedisKey); - if (yestData == null) { - // redis没有这查电表总数据表取截止到昨日最新第一条数据 - yestData = emsAmmeterDataMapper.getYestLatestDate(SITE_ID,deviceId,yestDate); - // 数据存redis-有效期1天 - redisCache.setCacheObject(yestDateRedisKey, yestData , Constants.DATE_VALID_TIME, TimeUnit.DAYS); - } - if (yestData != null) { - // 今日总数据-昨日总数据=今日充放电 - BigDecimal yestTotalDisChargeDate = yestData.getCurrentReverseActiveTotal(); - BigDecimal yestTotalChargeDate = yestData.getCurrentForwardActiveTotal(); - - dailyChargeDate = nowTotalChargeDate.subtract(yestTotalChargeDate); - dailyDisChargeDate = nowTotalDisChargeDate.subtract(yestTotalDisChargeDate); - emsDailyChargeData.setChargeData(dailyChargeDate); - emsDailyChargeData.setDischargeData(dailyDisChargeDate); - } - - // 插入或更新每日充放电数据表 - emsDailyChargeDataMapper.insertOrUpdateData(emsDailyChargeData); - - // 初始化数据-尖峰平谷 - EmsDailyEnergyData energyData = initEnergyData(); - // 计算尖峰平谷差值,更新表 - calcEnergyDiffAndRevenue(energyData,obj,yestData); - energyData.setCalcTime(DateUtils.getNowDate()); - // 插入或更新电表每日差值数据表 - emsDailyEnergyDataMapper.insertOrUpdateData(energyData); - } - - private void calcEnergyDiffAndRevenue(EmsDailyEnergyData energyData, Map obj, EmsAmmeterData yestData) { - - // 获取当月电价 - String key = RedisKeyConstants.ENERGY_PRICE_TIME + SITE_ID + "_" + LocalDate.now().getYear() + LocalDate.now().getMonthValue(); - EnergyPriceVo priceVo = redisCache.getCacheObject(key); - - // 计算尖峰平谷差值 - // 正反向-尖 - BigDecimal peakChargeDiff = StringUtils.getBigDecimal(obj.get("DQZXYGJDN")) - .subtract(yestData == null ? new BigDecimal(0) : yestData.getCurrentForwardActivePeak()); - energyData.setPeakChargeDiff(peakChargeDiff); - BigDecimal peakDischargeDiff = StringUtils.getBigDecimal(obj.get("DQFXYGJDN")) - .subtract(yestData == null ? new BigDecimal(0) : yestData.getCurrentReverseActivePeak()); - energyData.setPeakDischargeDiff(peakDischargeDiff); - // 正反向-峰 - BigDecimal highChargeDiff = StringUtils.getBigDecimal(obj.get("DQZXYGFDN")) - .subtract(yestData == null ? new BigDecimal(0) : yestData.getCurrentForwardActiveHigh()); - energyData.setHighChargeDiff(highChargeDiff); - BigDecimal highDischargeDiff = StringUtils.getBigDecimal(obj.get("DQFXYGFDN")) - .subtract(yestData == null ? new BigDecimal(0) : yestData.getCurrentReverseActiveHigh()); - energyData.setHighDischargeDiff(highDischargeDiff); - // 正反向-平 - BigDecimal flatChargeDiff = StringUtils.getBigDecimal(obj.get("DQZXYGPDN")) - .subtract(yestData == null ? new BigDecimal(0) : yestData.getCurrentForwardActiveFlat()); - energyData.setFlatChargeDiff(flatChargeDiff); - BigDecimal flatDisChargeDiff = StringUtils.getBigDecimal(obj.get("DQFXYGPDN")) - .subtract(yestData == null ? new BigDecimal(0) : yestData.getCurrentReverseActiveFlat()); - energyData.setFlatDischargeDiff(flatDisChargeDiff); - // 正反向-谷 - BigDecimal valleyChargeDiff = StringUtils.getBigDecimal(obj.get("DQZXYGGDN")) - .subtract(yestData == null ? new BigDecimal(0) : yestData.getCurrentForwardActiveValley()); - energyData.setValleyChargeDiff(valleyChargeDiff); - BigDecimal valleyDisChargeDiff = StringUtils.getBigDecimal(obj.get("DQFXYGGDN")) - .subtract(yestData == null ? new BigDecimal(0) : yestData.getCurrentReverseActiveValley()); - energyData.setValleyDischargeDiff(valleyDisChargeDiff); - - - BigDecimal totalRevenue = getYestLastData(SITE_ID); - BigDecimal dayRevenue = BigDecimal.ZERO; - BigDecimal price = BigDecimal.ZERO; - // 计算当日收益,尖峰平谷收益累加,(放电量-充电量)*电价 - if (priceVo != null) { - price = priceVo.getPeak() == null ? BigDecimal.ZERO : priceVo.getPeak(); - BigDecimal peakRevenue = peakDischargeDiff.subtract(peakChargeDiff).multiply(price); - dayRevenue = dayRevenue.add(peakRevenue); - price = priceVo.getHigh() == null ? BigDecimal.ZERO : priceVo.getHigh(); - BigDecimal highRevenue = highDischargeDiff.subtract(highChargeDiff).multiply(price); - dayRevenue = dayRevenue.add(highRevenue); - price = priceVo.getFlat() == null ? BigDecimal.ZERO : priceVo.getFlat(); - BigDecimal flatRevenue = flatDisChargeDiff.subtract(flatChargeDiff).multiply(price); - dayRevenue = dayRevenue.add(flatRevenue); - price = priceVo.getValley() == null ? BigDecimal.ZERO : priceVo.getValley(); - BigDecimal valleyRevenue = valleyDisChargeDiff.subtract(valleyChargeDiff).multiply(price); - dayRevenue = dayRevenue.add(valleyRevenue); - energyData.setDayRevenue(dayRevenue); - } - // 总收益 = 昨日总收益+今日实时收益 - totalRevenue = totalRevenue.add(dayRevenue); - energyData.setTotalRevenue(totalRevenue); - } - - private BigDecimal getYestLastData(String siteId) { - // dds存的是累计到昨日总收益 - String yestDate = DateUtils.getYesterdayDayString(); - String redisKey = RedisKeyConstants.DDS_TOTAL_REVENUE + siteId + "_" + yestDate; - BigDecimal yestLastTotalRevenue = redisCache.getCacheObject(redisKey); - if (yestLastTotalRevenue == null) { - yestLastTotalRevenue = emsDailyEnergyDataMapper.getLastTotalRevenue(siteId); - if (yestLastTotalRevenue == null) { - yestLastTotalRevenue = BigDecimal.ZERO; - } - redisCache.setCacheObject(redisKey, yestLastTotalRevenue, 1 , TimeUnit.DAYS); - } - return yestLastTotalRevenue; - } - - private EmsDailyChargeData initDailyChargeData(String deviceId, BigDecimal nowTotalChargeDate, - BigDecimal nowTotalDisChargeDate) { - EmsDailyChargeData emsDailyChargeData = new EmsDailyChargeData(); - emsDailyChargeData.setSiteId(SITE_ID); - emsDailyChargeData.setDeviceId(deviceId); - emsDailyChargeData.setDateTime(DateUtils.getNowDate()); - emsDailyChargeData.setTotalChargeData(nowTotalChargeDate); - emsDailyChargeData.setTotalDischargeData(nowTotalDisChargeDate); - emsDailyChargeData.setCreateBy("system"); - emsDailyChargeData.setCreateTime(DateUtils.getNowDate()); - emsDailyChargeData.setUpdateBy("system"); - emsDailyChargeData.setUpdateTime(DateUtils.getNowDate()); - return emsDailyChargeData; - } - - // 数据分组处理 - private static Map> processData(Map rawData) { - Map> records = new HashMap<>(); - - for (Map.Entry entry : rawData.entrySet()) { - String key = entry.getKey(); - // 提取记录ID(最后3位) - String recordId = key.substring(key.length() - 3); - try { - Long.parseLong(recordId); - } catch (Exception e) { - continue; - } - - // 提取字段类型(前缀) - String fieldType = key.substring(0, key.length() - 3); - - // 初始化记录 - records.putIfAbsent(recordId, new HashMap<>()); - // 存入字段值 - records.get(recordId).put(fieldType, entry.getValue()); - } - return records; - } - - // 空数据不处理 - private boolean checkJsonDataEmpty(String jsonData) { - boolean flag = false; - try { - if (StringUtils.isEmpty(jsonData)) { - flag = true; - } - JsonNode jsonNode = objectMapper.readTree(jsonData); - // 判断是否为空对象({}) - if (jsonNode.isObject() && jsonNode.isEmpty()) { - flag = true ; - } - } catch (JsonProcessingException e) { - throw new RuntimeException(e); - } - return flag; - } - -} diff --git a/ems-system/src/main/java/com/xzzn/ems/service/impl/DeviceDataProcessServiceImpl.java b/ems-system/src/main/java/com/xzzn/ems/service/impl/DeviceDataProcessServiceImpl.java index 06685e1..a5c2b19 100644 --- a/ems-system/src/main/java/com/xzzn/ems/service/impl/DeviceDataProcessServiceImpl.java +++ b/ems-system/src/main/java/com/xzzn/ems/service/impl/DeviceDataProcessServiceImpl.java @@ -49,6 +49,7 @@ import com.xzzn.ems.mapper.EmsPcsAlarmDataMapper; import com.xzzn.ems.mapper.EmsPcsBranchDataMapper; import com.xzzn.ems.mapper.EmsPcsDataMapper; import com.xzzn.ems.mapper.EmsPointConfigMapper; +import com.xzzn.ems.mapper.EmsSiteMonitorPointMatchMapper; import com.xzzn.ems.mapper.EmsStackAlarmDataMapper; import com.xzzn.ems.mapper.EmsXfDataMapper; import com.xzzn.ems.service.IDeviceDataProcessService; @@ -118,6 +119,25 @@ public class DeviceDataProcessServiceImpl extends AbstractBatteryDataProcessor i private static final long POINT_ENQUEUE_RETRY_WAIT_MS = 10; private static final long POINT_FLUSH_INTERVAL_MS = 100; private static final String SITE_LEVEL_CALC_DEVICE_ID = "SITE_CALC"; + private static final int MONITOR_POINT_MATCH_REDIS_TTL_SECONDS = 300; + private static final String DELETED_FIELD_MARK = "__DELETED__"; + private static final String DAILY_ENERGY_RAW_CACHE_PREFIX = "DAILY_ENERGY_RAW_"; + private static final String ENERGY_METRIC_PEAK_CHARGE = "peakCharge"; + private static final String ENERGY_METRIC_PEAK_DISCHARGE = "peakDischarge"; + private static final String ENERGY_METRIC_HIGH_CHARGE = "highCharge"; + private static final String ENERGY_METRIC_HIGH_DISCHARGE = "highDischarge"; + private static final String ENERGY_METRIC_FLAT_CHARGE = "flatCharge"; + private static final String ENERGY_METRIC_FLAT_DISCHARGE = "flatDischarge"; + private static final String ENERGY_METRIC_VALLEY_CHARGE = "valleyCharge"; + private static final String ENERGY_METRIC_VALLEY_DISCHARGE = "valleyDischarge"; + private static final String[] FIELD_SUFFIX_PEAK_CHARGE = {"activePeakKwh", "peakChargeDiff", "peakCharge"}; + private static final String[] FIELD_SUFFIX_PEAK_DISCHARGE = {"reActivePeakKwh", "peakDischargeDiff", "peakDischarge"}; + private static final String[] FIELD_SUFFIX_HIGH_CHARGE = {"activeHighKwh", "highChargeDiff", "highCharge"}; + private static final String[] FIELD_SUFFIX_HIGH_DISCHARGE = {"reActiveHighKwh", "highDischargeDiff", "highDischarge"}; + private static final String[] FIELD_SUFFIX_FLAT_CHARGE = {"activeFlatKwh", "flatChargeDiff", "flatCharge"}; + private static final String[] FIELD_SUFFIX_FLAT_DISCHARGE = {"reActiveFlatKwh", "flatDischargeDiff", "flatDischarge"}; + private static final String[] FIELD_SUFFIX_VALLEY_CHARGE = {"activeValleyKwh", "valleyChargeDiff", "valleyCharge"}; + private static final String[] FIELD_SUFFIX_VALLEY_DISCHARGE = {"reActiveValleyKwh", "valleyDischargeDiff", "valleyDischarge"}; @Autowired private EmsBatteryClusterMapper emsBatteryClusterMapper; @@ -151,6 +171,8 @@ public class DeviceDataProcessServiceImpl extends AbstractBatteryDataProcessor i private EmsBatteryGroupMapper emsBatteryGroupMapper; @Autowired private EmsEmsDataMapper emsEmsDataMapper; + @Autowired + private EmsSiteMonitorPointMatchMapper emsSiteMonitorPointMatchMapper; @Autowired private EmsCoolingAlarmDataMapper emsCoolingAlarmDataMapper; @@ -233,15 +255,18 @@ public class DeviceDataProcessServiceImpl extends AbstractBatteryDataProcessor i } try { + String mergedJsonData = mergeWithLatestRedisData(siteId, deviceId, jsonData); + obj.put("Data", mergedJsonData); // 保留每个设备最新一条原始报文,供“点位最新值”从 Redis 读取 redisCache.setCacheObject(RedisKeyConstants.ORIGINAL_MQTT_DATA + siteId + "_" + deviceId, obj); redisCache.setCacheObject(RedisKeyConstants.SYNC_DATA + siteId + "_" + deviceId, obj, 1, TimeUnit.MINUTES); String deviceCategory = resolveDeviceCategory(siteId, deviceId, deviceCategoryMap); - Map pointIdValueMap = processPointConfigData(siteId, deviceId, deviceCategory, jsonData, dataUpdateTime); + // 旧设备表落库链路已下线,MQTT 数据仅走点位映射与站点监控数据同步。 + Map pointIdValueMap = processPointConfigData(siteId, deviceId, deviceCategory, mergedJsonData, dataUpdateTime); iEmsDeviceSettingService.syncSiteMonitorDataByMqtt(siteId, deviceId, JSON.toJSONString(pointIdValueMap), dataUpdateTime); } catch (Exception e) { - log.warn("点位映射数据处理失败,siteId: {}, deviceId: {}, err: {}", + log.warn("设备数据处理失败,siteId: {}, deviceId: {}, err: {}", siteId, deviceId, e.getMessage(), e); } } @@ -318,9 +343,468 @@ public class DeviceDataProcessServiceImpl extends AbstractBatteryDataProcessor i enqueuePointData(siteId, deviceId, pointId, convertedValue, dataUpdateTime); pointIdValueMap.put(pointId, convertedValue); } + updateDailyEnergyDataByMqtt(siteId, deviceId, deviceCategory, pointIdValueMap, dataUpdateTime); return pointIdValueMap; } + private String mergeWithLatestRedisData(String siteId, String deviceId, String currentJsonData) { + Map currentDataMap = parseDataJsonToMap(currentJsonData); + if (StringUtils.isAnyBlank(siteId, deviceId)) { + return JSON.toJSONString(currentDataMap); + } + String redisKey = RedisKeyConstants.ORIGINAL_MQTT_DATA + siteId + "_" + deviceId; + Object latestObj = redisCache.getCacheObject(redisKey); + Map latestDataMap = extractDataMapFromLatest(latestObj); + if (latestDataMap.isEmpty()) { + return JSON.toJSONString(currentDataMap); + } + Map merged = new LinkedHashMap<>(latestDataMap); + currentDataMap.forEach((key, value) -> { + if (StringUtils.isBlank(key) || value == null) { + return; + } + merged.put(key, value); + }); + return JSON.toJSONString(merged); + } + + private Map extractDataMapFromLatest(Object latestObj) { + if (latestObj == null) { + return new LinkedHashMap<>(); + } + JSONObject latestJson; + if (latestObj instanceof JSONObject) { + latestJson = (JSONObject) latestObj; + } else if (latestObj instanceof String) { + latestJson = JSON.parseObject((String) latestObj); + } else if (latestObj instanceof Map) { + latestJson = new JSONObject((Map) latestObj); + } else { + latestJson = JSON.parseObject(JSON.toJSONString(latestObj)); + } + if (latestJson == null || latestJson.isEmpty()) { + return new LinkedHashMap<>(); + } + Object dataObj = latestJson.get("Data"); + if (dataObj == null) { + return new LinkedHashMap<>(); + } + if (dataObj instanceof JSONObject) { + return new LinkedHashMap<>(((JSONObject) dataObj)); + } + if (dataObj instanceof Map) { + return new LinkedHashMap<>((Map) dataObj); + } + if (dataObj instanceof String) { + return parseDataJsonToMap((String) dataObj); + } + return parseDataJsonToMap(JSON.toJSONString(dataObj)); + } + + private Map parseDataJsonToMap(String jsonData) { + if (StringUtils.isBlank(jsonData)) { + return new LinkedHashMap<>(); + } + Map parsed = JSON.parseObject(jsonData, new TypeReference>() { + }); + return parsed == null ? new LinkedHashMap<>() : new LinkedHashMap<>(parsed); + } + + private void updateDailyEnergyDataByMqtt(String siteId, String deviceId, String deviceCategory, + Map pointIdValueMap, + Date dataUpdateTime) { + if (StringUtils.isBlank(siteId) || StringUtils.isBlank(deviceId) + || org.apache.commons.collections4.MapUtils.isEmpty(pointIdValueMap)) { + return; + } + // 仅处理储能电表,避免其它设备误触发日报计算 + if (!SiteDevice.METE.name().equalsIgnoreCase(deviceId) + && !DeviceCategory.AMMETER.getCode().equalsIgnoreCase(StringUtils.defaultString(deviceCategory))) { + return; + } + + Map mappingByFieldAndDevice = getMonitorPointMappingByFieldAndDevice(siteId); + if (mappingByFieldAndDevice.isEmpty()) { + return; + } + + Map normalizedPointValueMap = new HashMap<>(); + for (Map.Entry entry : pointIdValueMap.entrySet()) { + if (StringUtils.isBlank(entry.getKey()) || entry.getValue() == null) { + continue; + } + normalizedPointValueMap.put(entry.getKey().trim().toUpperCase(), entry.getValue()); + } + if (normalizedPointValueMap.isEmpty()) { + return; + } + + String peakChargePointId = firstNonBlankPointByFieldSuffix(mappingByFieldAndDevice, deviceId, FIELD_SUFFIX_PEAK_CHARGE); + String peakDischargePointId = firstNonBlankPointByFieldSuffix(mappingByFieldAndDevice, deviceId, FIELD_SUFFIX_PEAK_DISCHARGE); + String highChargePointId = firstNonBlankPointByFieldSuffix(mappingByFieldAndDevice, deviceId, FIELD_SUFFIX_HIGH_CHARGE); + String highDischargePointId = firstNonBlankPointByFieldSuffix(mappingByFieldAndDevice, deviceId, FIELD_SUFFIX_HIGH_DISCHARGE); + String flatChargePointId = firstNonBlankPointByFieldSuffix(mappingByFieldAndDevice, deviceId, FIELD_SUFFIX_FLAT_CHARGE); + String flatDischargePointId = firstNonBlankPointByFieldSuffix(mappingByFieldAndDevice, deviceId, FIELD_SUFFIX_FLAT_DISCHARGE); + String valleyChargePointId = firstNonBlankPointByFieldSuffix(mappingByFieldAndDevice, deviceId, FIELD_SUFFIX_VALLEY_CHARGE); + String valleyDischargePointId = firstNonBlankPointByFieldSuffix(mappingByFieldAndDevice, deviceId, FIELD_SUFFIX_VALLEY_DISCHARGE); + + Map currentTotals = new HashMap<>(); + currentTotals.put(ENERGY_METRIC_PEAK_CHARGE, getPointValueById(normalizedPointValueMap, peakChargePointId)); + currentTotals.put(ENERGY_METRIC_PEAK_DISCHARGE, getPointValueById(normalizedPointValueMap, peakDischargePointId)); + currentTotals.put(ENERGY_METRIC_HIGH_CHARGE, getPointValueById(normalizedPointValueMap, highChargePointId)); + currentTotals.put(ENERGY_METRIC_HIGH_DISCHARGE, getPointValueById(normalizedPointValueMap, highDischargePointId)); + currentTotals.put(ENERGY_METRIC_FLAT_CHARGE, getPointValueById(normalizedPointValueMap, flatChargePointId)); + currentTotals.put(ENERGY_METRIC_FLAT_DISCHARGE, getPointValueById(normalizedPointValueMap, flatDischargePointId)); + currentTotals.put(ENERGY_METRIC_VALLEY_CHARGE, getPointValueById(normalizedPointValueMap, valleyChargePointId)); + currentTotals.put(ENERGY_METRIC_VALLEY_DISCHARGE, getPointValueById(normalizedPointValueMap, valleyDischargePointId)); + log.info("日电量分时映射命中, siteId: {}, deviceId: {}, points[尖充:{} 尖放:{} 峰充:{} 峰放:{} 平充:{} 平放:{} 谷充:{} 谷放:{}]", + siteId, deviceId, + peakChargePointId, peakDischargePointId, + highChargePointId, highDischargePointId, + flatChargePointId, flatDischargePointId, + valleyChargePointId, valleyDischargePointId); + boolean hasAnyCurrentTotal = currentTotals.values().stream().anyMatch(Objects::nonNull); + if (!hasAnyCurrentTotal) { + log.info("日电量累计未匹配到有效点位值, siteId: {}, deviceId: {}, pointKeys: {}", + siteId, deviceId, normalizedPointValueMap.keySet()); + return; + } + log.info("日电量累计当前值, siteId: {}, deviceId: {}, currentTotals: {}", + siteId, deviceId, currentTotals); + + Map lastTotals = getCachedDailyEnergyRawTotals(siteId, deviceId); + if (org.apache.commons.collections4.MapUtils.isEmpty(lastTotals)) { + lastTotals = loadYesterdayAmmeterTotals(siteId, deviceId); + if (!org.apache.commons.collections4.MapUtils.isEmpty(lastTotals)) { + log.info("日电量累计使用昨日末值作为基线, siteId: {}, deviceId: {}, lastTotals: {}", + siteId, deviceId, lastTotals); + } + } + if (org.apache.commons.collections4.MapUtils.isEmpty(lastTotals)) { + log.info("日电量累计缺少上一条基线, 仅缓存当前值等待下一次计算, siteId: {}, deviceId: {}, currentTotals: {}", + siteId, deviceId, currentTotals); + String redisKey = buildDailyEnergyRawCacheKey(siteId, deviceId); + redisCache.setCacheObject(redisKey, currentTotals, 2, TimeUnit.DAYS); + return; + } + EmsDailyEnergyData energyData = initEnergyData(siteId); + accumulateDailyEnergyDiff(energyData, currentTotals, lastTotals, siteId, deviceId); + recalculateDailyEnergyRevenue(siteId, energyData); + energyData.setCalcTime(dataUpdateTime == null ? DateUtils.getNowDate() : dataUpdateTime); + emsDailyEnergyDataMapper.insertOrUpdateData(energyData); + log.info("日电量累计落库完成, siteId: {}, deviceId: {}, diff[尖充:{} 尖放:{} 峰充:{} 峰放:{} 平充:{} 平放:{} 谷充:{} 谷放:{}], dayRevenue: {}, totalRevenue: {}", + siteId, deviceId, + energyData.getPeakChargeDiff(), energyData.getPeakDischargeDiff(), + energyData.getHighChargeDiff(), energyData.getHighDischargeDiff(), + energyData.getFlatChargeDiff(), energyData.getFlatDischargeDiff(), + energyData.getValleyChargeDiff(), energyData.getValleyDischargeDiff(), + energyData.getDayRevenue(), energyData.getTotalRevenue()); + + String redisKey = buildDailyEnergyRawCacheKey(siteId, deviceId); + redisCache.setCacheObject(redisKey, currentTotals, 2, TimeUnit.DAYS); + } + + private Map loadYesterdayAmmeterTotals(String siteId, String deviceId) { + if (StringUtils.isAnyBlank(siteId, deviceId)) { + return Collections.emptyMap(); + } + String yestDate = DateUtils.getYesterdayDate(); + EmsAmmeterData yestData = emsAmmeterDataMapper.getYestLatestDate(siteId, deviceId, yestDate); + if (yestData == null) { + return Collections.emptyMap(); + } + Map lastTotals = new HashMap<>(); + lastTotals.put(ENERGY_METRIC_PEAK_CHARGE, safeBigDecimal(yestData.getCurrentForwardActivePeak())); + lastTotals.put(ENERGY_METRIC_PEAK_DISCHARGE, safeBigDecimal(yestData.getCurrentReverseActivePeak())); + lastTotals.put(ENERGY_METRIC_HIGH_CHARGE, safeBigDecimal(yestData.getCurrentForwardActiveHigh())); + lastTotals.put(ENERGY_METRIC_HIGH_DISCHARGE, safeBigDecimal(yestData.getCurrentReverseActiveHigh())); + lastTotals.put(ENERGY_METRIC_FLAT_CHARGE, safeBigDecimal(yestData.getCurrentForwardActiveFlat())); + lastTotals.put(ENERGY_METRIC_FLAT_DISCHARGE, safeBigDecimal(yestData.getCurrentReverseActiveFlat())); + lastTotals.put(ENERGY_METRIC_VALLEY_CHARGE, safeBigDecimal(yestData.getCurrentForwardActiveValley())); + lastTotals.put(ENERGY_METRIC_VALLEY_DISCHARGE, safeBigDecimal(yestData.getCurrentReverseActiveValley())); + return lastTotals; + } + + private void accumulateDailyEnergyDiff(EmsDailyEnergyData energyData, + Map currentTotals, + Map lastTotals, + String siteId, + String deviceId) { + if (energyData == null || org.apache.commons.collections4.MapUtils.isEmpty(currentTotals)) { + return; + } + addMetricIncrement(energyData, ENERGY_METRIC_PEAK_CHARGE, currentTotals, lastTotals, siteId, deviceId); + addMetricIncrement(energyData, ENERGY_METRIC_PEAK_DISCHARGE, currentTotals, lastTotals, siteId, deviceId); + addMetricIncrement(energyData, ENERGY_METRIC_HIGH_CHARGE, currentTotals, lastTotals, siteId, deviceId); + addMetricIncrement(energyData, ENERGY_METRIC_HIGH_DISCHARGE, currentTotals, lastTotals, siteId, deviceId); + addMetricIncrement(energyData, ENERGY_METRIC_FLAT_CHARGE, currentTotals, lastTotals, siteId, deviceId); + addMetricIncrement(energyData, ENERGY_METRIC_FLAT_DISCHARGE, currentTotals, lastTotals, siteId, deviceId); + addMetricIncrement(energyData, ENERGY_METRIC_VALLEY_CHARGE, currentTotals, lastTotals, siteId, deviceId); + addMetricIncrement(energyData, ENERGY_METRIC_VALLEY_DISCHARGE, currentTotals, lastTotals, siteId, deviceId); + } + + private void addMetricIncrement(EmsDailyEnergyData energyData, + String metric, + Map currentTotals, + Map lastTotals, + String siteId, + String deviceId) { + BigDecimal current = currentTotals.get(metric); + if (current == null) { + return; + } + BigDecimal last = lastTotals == null ? null : lastTotals.get(metric); + if (last == null) { + return; + } + BigDecimal delta = current.subtract(last); + if (delta.compareTo(BigDecimal.ZERO) < 0) { + log.warn("日电量累计值回退,跳过本次增量,siteId: {}, deviceId: {}, metric: {}, current: {}, last: {}", + siteId, deviceId, metric, current, last); + return; + } + + if (ENERGY_METRIC_PEAK_CHARGE.equals(metric)) { + energyData.setPeakChargeDiff(safeBigDecimal(energyData.getPeakChargeDiff()).add(delta)); + return; + } + if (ENERGY_METRIC_PEAK_DISCHARGE.equals(metric)) { + energyData.setPeakDischargeDiff(safeBigDecimal(energyData.getPeakDischargeDiff()).add(delta)); + return; + } + if (ENERGY_METRIC_HIGH_CHARGE.equals(metric)) { + energyData.setHighChargeDiff(safeBigDecimal(energyData.getHighChargeDiff()).add(delta)); + return; + } + if (ENERGY_METRIC_HIGH_DISCHARGE.equals(metric)) { + energyData.setHighDischargeDiff(safeBigDecimal(energyData.getHighDischargeDiff()).add(delta)); + return; + } + if (ENERGY_METRIC_FLAT_CHARGE.equals(metric)) { + energyData.setFlatChargeDiff(safeBigDecimal(energyData.getFlatChargeDiff()).add(delta)); + return; + } + if (ENERGY_METRIC_FLAT_DISCHARGE.equals(metric)) { + energyData.setFlatDischargeDiff(safeBigDecimal(energyData.getFlatDischargeDiff()).add(delta)); + return; + } + if (ENERGY_METRIC_VALLEY_CHARGE.equals(metric)) { + energyData.setValleyChargeDiff(safeBigDecimal(energyData.getValleyChargeDiff()).add(delta)); + return; + } + if (ENERGY_METRIC_VALLEY_DISCHARGE.equals(metric)) { + energyData.setValleyDischargeDiff(safeBigDecimal(energyData.getValleyDischargeDiff()).add(delta)); + } + } + + private void recalculateDailyEnergyRevenue(String siteId, EmsDailyEnergyData energyData) { + if (StringUtils.isBlank(siteId) || energyData == null) { + return; + } + String priceKey = RedisKeyConstants.ENERGY_PRICE_TIME + siteId + "_" + LocalDate.now().getYear() + LocalDate.now().getMonthValue(); + EnergyPriceVo priceVo = redisCache.getCacheObject(priceKey); + if (priceVo == null) { + priceVo = emsEnergyPriceConfigService.getCurrentMonthPrice(siteId); + redisCache.setCacheObject(priceKey, priceVo, 31, TimeUnit.DAYS); + } + if (priceVo == null) { + energyData.setDayRevenue(BigDecimal.ZERO); + energyData.setTotalRevenue(getYestLastData(siteId)); + return; + } + + BigDecimal peakRevenue = safeBigDecimal(energyData.getPeakDischargeDiff()) + .subtract(safeBigDecimal(energyData.getPeakChargeDiff())) + .multiply(safeBigDecimal(priceVo.getPeak())); + BigDecimal highRevenue = safeBigDecimal(energyData.getHighDischargeDiff()) + .subtract(safeBigDecimal(energyData.getHighChargeDiff())) + .multiply(safeBigDecimal(priceVo.getHigh())); + BigDecimal flatRevenue = safeBigDecimal(energyData.getFlatDischargeDiff()) + .subtract(safeBigDecimal(energyData.getFlatChargeDiff())) + .multiply(safeBigDecimal(priceVo.getFlat())); + BigDecimal valleyRevenue = safeBigDecimal(energyData.getValleyDischargeDiff()) + .subtract(safeBigDecimal(energyData.getValleyChargeDiff())) + .multiply(safeBigDecimal(priceVo.getValley())); + + BigDecimal dayRevenue = peakRevenue.add(highRevenue).add(flatRevenue).add(valleyRevenue); + energyData.setDayRevenue(dayRevenue); + energyData.setTotalRevenue(getYestLastData(siteId).add(dayRevenue)); + } + + private BigDecimal resolveEnergyMetricValue(Map mappingByFieldAndDevice, + String deviceId, + Map pointIdValueMap, + String[] fieldSuffixes) { + String pointId = firstNonBlankPointByFieldSuffix(mappingByFieldAndDevice, deviceId, fieldSuffixes); + if (StringUtils.isBlank(pointId)) { + return null; + } + return pointIdValueMap.get(pointId.trim().toUpperCase()); + } + + private BigDecimal getPointValueById(Map pointIdValueMap, String pointId) { + if (pointIdValueMap == null || pointIdValueMap.isEmpty() || StringUtils.isBlank(pointId)) { + return null; + } + return pointIdValueMap.get(pointId.trim().toUpperCase()); + } + + private String firstNonBlankPointByFieldSuffix(Map mappingByFieldAndDevice, + String deviceId, + String[] fieldSuffixes) { + if (mappingByFieldAndDevice == null || fieldSuffixes == null || fieldSuffixes.length == 0) { + return null; + } + String normalizedDeviceId = StringUtils.defaultString(deviceId).trim(); + for (String suffix : fieldSuffixes) { + if (StringUtils.isBlank(suffix)) { + continue; + } + String normalizedSuffix = suffix.trim().toLowerCase(); + EmsSiteMonitorPointMatch exactMatch = resolvePointMatchByFieldSuffix(mappingByFieldAndDevice, normalizedDeviceId, normalizedSuffix); + if (exactMatch != null && StringUtils.isNotBlank(exactMatch.getDataPoint())) { + return exactMatch.getDataPoint().trim(); + } + EmsSiteMonitorPointMatch fallbackMatch = resolvePointMatchByFieldSuffix(mappingByFieldAndDevice, "", normalizedSuffix); + if (fallbackMatch != null && StringUtils.isNotBlank(fallbackMatch.getDataPoint())) { + return fallbackMatch.getDataPoint().trim(); + } + } + return null; + } + + private EmsSiteMonitorPointMatch resolvePointMatchByFieldSuffix(Map mappingByFieldAndDevice, + String deviceId, + String suffixLowerCase) { + if (mappingByFieldAndDevice == null || StringUtils.isBlank(suffixLowerCase)) { + return null; + } + for (Map.Entry entry : mappingByFieldAndDevice.entrySet()) { + EmsSiteMonitorPointMatch mapping = entry.getValue(); + if (mapping == null || StringUtils.isBlank(mapping.getFieldCode())) { + continue; + } + String mappingDeviceId = StringUtils.defaultString(mapping.getDeviceId()).trim(); + if (!StringUtils.equals(mappingDeviceId, StringUtils.defaultString(deviceId).trim())) { + continue; + } + String dataPoint = StringUtils.defaultString(mapping.getDataPoint()).trim(); + if (StringUtils.isBlank(dataPoint) || DELETED_FIELD_MARK.equalsIgnoreCase(dataPoint)) { + continue; + } + String fieldCode = mapping.getFieldCode().trim().toLowerCase(); + if (fieldCode.endsWith(suffixLowerCase)) { + return mapping; + } + } + return null; + } + + private Map getMonitorPointMappingByFieldAndDevice(String siteId) { + List mappingList = getPointMatchesBySiteId(siteId); + if (CollectionUtils.isEmpty(mappingList)) { + return Collections.emptyMap(); + } + return mappingList.stream() + .filter(item -> item != null && StringUtils.isNotBlank(item.getFieldCode())) + .collect(Collectors.toMap( + item -> buildFieldDeviceKey(item.getFieldCode(), item.getDeviceId()), + item -> item, + (a, b) -> b + )); + } + + private List getPointMatchesBySiteId(String siteId) { + if (StringUtils.isBlank(siteId)) { + return Collections.emptyList(); + } + String normalizedSiteId = siteId.trim(); + String redisKey = RedisKeyConstants.SITE_MONITOR_POINT_MATCH + normalizedSiteId; + Object cacheObj = redisCache.getCacheObject(redisKey); + List cached = parsePointMatchCache(cacheObj); + if (cached != null) { + return cached; + } + List latest = emsSiteMonitorPointMatchMapper.selectBySiteId(normalizedSiteId); + if (latest == null) { + latest = Collections.emptyList(); + } + redisCache.setCacheObject(redisKey, latest, MONITOR_POINT_MATCH_REDIS_TTL_SECONDS, TimeUnit.SECONDS); + return latest; + } + + private List parsePointMatchCache(Object cacheObj) { + if (cacheObj == null) { + return null; + } + try { + if (cacheObj instanceof String) { + return JSON.parseArray((String) cacheObj, EmsSiteMonitorPointMatch.class); + } + if (cacheObj instanceof List) { + List cacheList = (List) cacheObj; + if (cacheList.isEmpty()) { + return Collections.emptyList(); + } + if (cacheList.get(0) instanceof EmsSiteMonitorPointMatch) { + return (List) cacheList; + } + return JSON.parseArray(JSON.toJSONString(cacheObj), EmsSiteMonitorPointMatch.class); + } + return JSON.parseArray(JSON.toJSONString(cacheObj), EmsSiteMonitorPointMatch.class); + } catch (Exception ex) { + log.warn("解析单站监控点位映射缓存失败,key类型={}, err={}", + cacheObj.getClass().getName(), ex.getMessage()); + return null; + } + } + + private String buildFieldDeviceKey(String fieldCode, String deviceId) { + return StringUtils.defaultString(fieldCode).trim() + "|" + StringUtils.defaultString(deviceId).trim(); + } + + private Map getCachedDailyEnergyRawTotals(String siteId, String deviceId) { + String redisKey = buildDailyEnergyRawCacheKey(siteId, deviceId); + Object cacheObj = redisCache.getCacheObject(redisKey); + if (cacheObj == null) { + return Collections.emptyMap(); + } + try { + if (cacheObj instanceof Map) { + Map mapObj = (Map) cacheObj; + Map parsed = new HashMap<>(); + for (Map.Entry entry : mapObj.entrySet()) { + if (entry.getKey() == null || entry.getValue() == null) { + continue; + } + String key = String.valueOf(entry.getKey()).trim(); + if (StringUtils.isBlank(key)) { + continue; + } + BigDecimal value = StringUtils.getBigDecimal(entry.getValue()); + if (value != null) { + parsed.put(key, value); + } + } + return parsed; + } + return JSON.parseObject(JSON.toJSONString(cacheObj), new TypeReference>() { + }); + } catch (Exception e) { + log.warn("解析日电量原始累计缓存失败,siteId: {}, deviceId: {}, err: {}", + siteId, deviceId, e.getMessage()); + return Collections.emptyMap(); + } + } + + private String buildDailyEnergyRawCacheKey(String siteId, String deviceId) { + return DAILY_ENERGY_RAW_CACHE_PREFIX + StringUtils.defaultString(siteId).trim() + "_" + StringUtils.defaultString(deviceId).trim(); + } + + private BigDecimal safeBigDecimal(BigDecimal value) { + return value == null ? BigDecimal.ZERO : value; + } + private Map buildDeviceCategoryMap(String siteId, JSONArray arraylist) { Map deviceCategoryMap = new HashMap<>(); if (arraylist == null || arraylist.isEmpty()) { @@ -1372,51 +1856,8 @@ public class DeviceDataProcessServiceImpl extends AbstractBatteryDataProcessor i return null; } - public void processingDeviceData(String siteId, String deviceId, String jsonData, Date dataUpdateTime) { - // 判断设备类型,并调用对应的方法处理数据 - String deviceCategory = getDeviceCategory(siteId, deviceId); - if (deviceId.contains(SiteDevice.BMSD.name())) { - batteryStackDataProcess(siteId, deviceId, jsonData, dataUpdateTime); - if (SiteEnum.DDS.getCode().equals(siteId)) { - batteryGroupDataProcess(siteId, deviceId, jsonData); - batteryDataProcessFromBmsd(siteId, deviceId, jsonData, dataUpdateTime); - } - } else if (deviceId.contains(SiteDevice.BMSC.name())) { - batteryClusterDataProcess(siteId, deviceId, jsonData, dataUpdateTime); - batteryDataProcessFromBmsc(siteId, deviceId, jsonData, dataUpdateTime); - } else if (deviceId.contains(SiteDevice.PCS.name()) - || DeviceCategory.PCS.getCode().equals(deviceCategory)) { - pcsDataProcess(siteId, deviceId, jsonData, dataUpdateTime); - pcsBranchDataProcess(siteId, deviceId, jsonData); - if (SiteEnum.DDS.getCode().equals(siteId)) { - batteryClusterDataProcess(siteId, jsonData, dataUpdateTime); - } - } else if (deviceId.contains(SiteDevice.LOAD.name()) - || deviceId.contains(SiteDevice.METEGF.name()) - || deviceId.contains(SiteDevice.METE.name()) - || deviceId.contains(SiteDevice.METE0.name()) - || DeviceCategory.AMMETER.getCode().equals(deviceCategory)) { - meteDataProcess(siteId, deviceId, jsonData, dataUpdateTime); - } else if (deviceId.contains(SiteDevice.XF.name()) - || DeviceCategory.XF.getCode().equals(deviceCategory)) { - meteXFProcess(siteId, deviceId, jsonData, dataUpdateTime); - } else if (deviceId.contains(SiteDevice.DH.name()) - || deviceId.contains(SiteDevice.donghuan.name()) - || DeviceCategory.DH.getCode().equals(deviceCategory)) { - dhDataProcess(siteId, deviceId, jsonData, dataUpdateTime); - } else if (deviceId.contains(SiteDevice.ZSLQ.name()) - || DeviceCategory.COOLING.getCode().equals(deviceCategory)) { - coolingDataProcess(siteId, deviceId, jsonData, dataUpdateTime); - } else if (deviceId.contains(SiteDevice.EMS.name()) - || DeviceCategory.EMS.getCode().equals(deviceCategory)) { - emsDataProcess(siteId, deviceId, jsonData, dataUpdateTime); - } else { - log.info("未找到匹配的设备类型,无法处理数据,siteId: " + siteId + ",deviceId: " + deviceId); - } - } - private String getDeviceCategory(String siteId, String deviceId) { - EmsDevicesSetting emsDevicesSetting = emsDevicesSettingMapper.getDeviceBySiteAndDeviceId(deviceId, siteId); + EmsDevicesSetting emsDevicesSetting = getDeviceSettingWithCache(siteId, deviceId); if (emsDevicesSetting != null) { return emsDevicesSetting.getDeviceCategory(); } @@ -1508,10 +1949,13 @@ public class DeviceDataProcessServiceImpl extends AbstractBatteryDataProcessor i redisCache.setCacheObject(RedisKeyConstants.XF + siteId + "_" + deviceId, xfData); // 状态枚举还没有提供 - EmsDevicesSetting emsDevicesSetting = emsDevicesSettingMapper.getDeviceBySiteAndDeviceId(deviceId, siteId); - emsDevicesSetting.setCommunicationStatus(StringUtils.getString(xfData.getDczt())); - emsDevicesSetting.setUpdatedAt(DateUtils.getNowDate()); - emsDevicesSettingMapper.updateEmsDevicesSetting(emsDevicesSetting); + EmsDevicesSetting emsDevicesSetting = getDeviceSettingWithCache(siteId, deviceId); + if (emsDevicesSetting != null) { + emsDevicesSetting.setCommunicationStatus(StringUtils.getString(xfData.getDczt())); + emsDevicesSetting.setUpdatedAt(DateUtils.getNowDate()); + emsDevicesSettingMapper.updateEmsDevicesSetting(emsDevicesSetting); + cacheDeviceSetting(siteId, deviceId, emsDevicesSetting); + } } private void dhDataProcess(String siteId, String deviceId, String dataJson, Date dateUpdateTime) { @@ -2104,6 +2548,9 @@ public class DeviceDataProcessServiceImpl extends AbstractBatteryDataProcessor i }); // 点位匹配数据 List pointMatchList = devicePointMatchDataProcessor.getDevicePointMatch(siteId, deviceId, DeviceMatchTable.AMMETER.getCode()); + if (CollectionUtils.isEmpty(pointMatchList)) { + pointMatchList = devicePointMatchDataProcessor.getDeviceDefaultPointMatch(siteId, DeviceMatchTable.AMMETER.getCode()); + } if (CollectionUtils.isEmpty(pointMatchList)) { log.info("未找到匹配的点位数据,无法处理LOAD总表数据,siteId: " + siteId + ",deviceId: " + deviceId); return; @@ -2210,10 +2657,59 @@ public class DeviceDataProcessServiceImpl extends AbstractBatteryDataProcessor i // workStatus = enumMatch.get().getEnumCode(); // } // } - EmsDevicesSetting emsDevicesSetting = emsDevicesSettingMapper.getDeviceBySiteAndDeviceId(deviceId, siteId); + EmsDevicesSetting emsDevicesSetting = getDeviceSettingWithCache(siteId, deviceId); + if (emsDevicesSetting == null) { + return; + } emsDevicesSetting.setWorkStatus(workStatus); emsDevicesSetting.setUpdatedAt(DateUtils.getNowDate()); emsDevicesSettingMapper.updateEmsDevicesSetting(emsDevicesSetting); + cacheDeviceSetting(siteId, deviceId, emsDevicesSetting); + } + + private EmsDevicesSetting getDeviceSettingWithCache(String siteId, String deviceId) { + if (StringUtils.isAnyBlank(siteId, deviceId)) { + return null; + } + String cacheKey = RedisKeyConstants.DEVICE_SETTING + siteId + "_" + deviceId; + EmsDevicesSetting cached = redisCache.getCacheObject(cacheKey); + if (cached != null) { + return cached; + } + EmsDevicesSetting fromInitCache = getDeviceSettingFromInitCache(siteId, deviceId); + if (fromInitCache != null) { + cacheDeviceSetting(siteId, deviceId, fromInitCache); + return fromInitCache; + } + EmsDevicesSetting fromDb = emsDevicesSettingMapper.getDeviceBySiteAndDeviceId(deviceId, siteId); + if (fromDb != null) { + cacheDeviceSetting(siteId, deviceId, fromDb); + } + return fromDb; + } + + private EmsDevicesSetting getDeviceSettingFromInitCache(String siteId, String deviceId) { + Map> map = redisCache.getCacheObject(RedisKeyConstants.INIT_DEVICE_INFO); + if (map == null || map.isEmpty()) { + return null; + } + List list = map.get(siteId); + if (CollectionUtils.isEmpty(list)) { + return null; + } + for (EmsDevicesSetting item : list) { + if (item != null && deviceId.equals(item.getDeviceId())) { + return item; + } + } + return null; + } + + private void cacheDeviceSetting(String siteId, String deviceId, EmsDevicesSetting setting) { + if (StringUtils.isAnyBlank(siteId, deviceId) || setting == null) { + return; + } + redisCache.setCacheObject(RedisKeyConstants.DEVICE_SETTING + siteId + "_" + deviceId, setting, 10, TimeUnit.MINUTES); } private String getDeviceParent(String siteId, String deviceId) { @@ -2276,6 +2772,9 @@ public class DeviceDataProcessServiceImpl extends AbstractBatteryDataProcessor i }); // 点位匹配数据 List pointMatchList = devicePointMatchDataProcessor.getDevicePointMatch(siteId, deviceId, DeviceMatchTable.AMMETER.getCode()); + if (CollectionUtils.isEmpty(pointMatchList)) { + pointMatchList = devicePointMatchDataProcessor.getDeviceDefaultPointMatch(siteId, DeviceMatchTable.AMMETER.getCode()); + } if (CollectionUtils.isEmpty(pointMatchList)) { log.info("未找到匹配的点位数据,无法处理电表数据,siteId: " + siteId + ",deviceId: " + deviceId); return; @@ -2531,6 +3030,9 @@ public class DeviceDataProcessServiceImpl extends AbstractBatteryDataProcessor i } private void dealAmmeterDailyDate(String siteId, EmsAmmeterData currentData, Date dataUpdateTime, EmsAmmeterData lastData) { + EmsDailyEnergyData energyData = initEnergyData(siteId); + energyData.setCalcTime(DateUtils.getNowDate()); + // 先获取当月电价配置,redis没有这查数据库,都没有则返回 String priceKey = RedisKeyConstants.ENERGY_PRICE_TIME + siteId + "_" + LocalDate.now().getYear() + LocalDate.now().getMonthValue(); EnergyPriceVo priceVo = redisCache.getCacheObject(priceKey); @@ -2538,11 +3040,13 @@ public class DeviceDataProcessServiceImpl extends AbstractBatteryDataProcessor i priceVo = emsEnergyPriceConfigService.getCurrentMonthPrice(siteId); redisCache.setCacheObject(priceKey, priceVo, 31, TimeUnit.DAYS); if (priceVo == null) { + emsDailyEnergyDataMapper.insertOrUpdateData(energyData); return; } } List timeRanges = priceVo.getRange(); if (timeRanges == null) { + emsDailyEnergyDataMapper.insertOrUpdateData(energyData); return; } @@ -2557,12 +3061,10 @@ public class DeviceDataProcessServiceImpl extends AbstractBatteryDataProcessor i } } if (StringUtils.isEmpty(costType)) { + emsDailyEnergyDataMapper.insertOrUpdateData(energyData); return; } - //初始化电表每日差值对象 - EmsDailyEnergyData energyData = initEnergyData(siteId); - // 根据 costType,计算本次与上次数据差值,累加到对应的数据类型里面 setDiffByCostType(siteId, costType, energyData, lastData, currentData, priceVo); diff --git a/ems-system/src/main/java/com/xzzn/ems/service/impl/EmsDeviceSettingServiceImpl.java b/ems-system/src/main/java/com/xzzn/ems/service/impl/EmsDeviceSettingServiceImpl.java index 38b0539..aa9bd62 100644 --- a/ems-system/src/main/java/com/xzzn/ems/service/impl/EmsDeviceSettingServiceImpl.java +++ b/ems-system/src/main/java/com/xzzn/ems/service/impl/EmsDeviceSettingServiceImpl.java @@ -9,8 +9,11 @@ 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.core.redis.RedisCache; +import com.xzzn.common.enums.BusinessStatus; +import com.xzzn.common.enums.BusinessType; import com.xzzn.common.enums.DeviceCategory; import com.xzzn.common.enums.DeviceType; +import com.xzzn.common.enums.OperatorType; import com.xzzn.common.enums.PointType; import com.xzzn.common.enums.WorkStatus; import com.xzzn.common.exception.ServiceException; @@ -45,6 +48,8 @@ import com.xzzn.ems.mapper.EmsSiteMonitorPointMatchMapper; import com.xzzn.ems.service.IEmsDeviceSettingService; import com.xzzn.ems.service.InfluxPointDataWriter; import com.xzzn.ems.utils.DevicePointMatchDataProcessor; +import com.xzzn.system.domain.SysOperLog; +import com.xzzn.system.service.ISysOperLogService; import java.math.BigDecimal; import java.util.ArrayList; @@ -144,6 +149,8 @@ public class EmsDeviceSettingServiceImpl implements IEmsDeviceSettingService private EmsSiteMonitorDataMapper emsSiteMonitorDataMapper; @Autowired private InfluxPointDataWriter influxPointDataWriter; + @Autowired + private ISysOperLogService operLogService; private volatile List monitorItemCache = Collections.emptyList(); private volatile long monitorItemCacheExpireAt = 0L; @@ -2119,11 +2126,37 @@ public class EmsDeviceSettingServiceImpl implements IEmsDeviceSettingService log.info("设备控制指令发送数据: {}", JSON.toJSONString(deviceConfig)); boolean result = modbusProcessor.writeDataToDevice(deviceConfig); if (!result) { + recordDeviceOperationLog(request, false, "设备控制指令发送失败"); throw new ServiceException("设备控制指令发送失败"); } + recordDeviceOperationLog(request, true, null); return true; } + private void recordDeviceOperationLog(DeviceUpdateRequest request, boolean success, String errorMsg) { + try { + SysOperLog operLog = new SysOperLog(); + operLog.setTitle("设备控制-开关机/写功率"); + operLog.setBusinessType(BusinessType.UPDATE.ordinal()); + operLog.setMethod(this.getClass().getName() + ".updateDeviceStatus"); + operLog.setRequestMethod("SERVICE"); + operLog.setOperatorType(OperatorType.OTHER.ordinal()); + operLog.setOperName("system"); + operLog.setOperIp("127.0.0.1"); + operLog.setOperUrl("/ems/siteConfig/updateDeviceStatus"); + operLog.setOperTime(DateUtils.getNowDate()); + operLog.setOperParam(StringUtils.substring(JSON.toJSONString(request), 0, 2000)); + operLog.setJsonResult(StringUtils.substring(JSON.toJSONString(Collections.singletonMap("success", success)), 0, 2000)); + operLog.setStatus(success ? BusinessStatus.SUCCESS.ordinal() : BusinessStatus.FAIL.ordinal()); + if (!success) { + operLog.setErrorMsg(StringUtils.substring(errorMsg, 0, 2000)); + } + operLogService.insertOperlog(operLog); + } catch (Exception e) { + log.error("记录sys_oper_log失败, siteId={}, deviceId={}", request.getSiteId(), request.getDeviceId(), e); + } + } + public DeviceConfig getDeviceConfig(EmsDevicesSetting device) { DeviceConfig deviceConfig = new DeviceConfig(); deviceConfig.setDeviceNumber(device.getDeviceId()); diff --git a/ems-system/src/main/java/com/xzzn/ems/service/impl/EmsPointConfigServiceImpl.java b/ems-system/src/main/java/com/xzzn/ems/service/impl/EmsPointConfigServiceImpl.java index bc019e8..21178d7 100644 --- a/ems-system/src/main/java/com/xzzn/ems/service/impl/EmsPointConfigServiceImpl.java +++ b/ems-system/src/main/java/com/xzzn/ems/service/impl/EmsPointConfigServiceImpl.java @@ -398,6 +398,10 @@ public class EmsPointConfigServiceImpl implements IEmsPointConfigService { if (keys != null && !keys.isEmpty()) { redisCache.deleteObject(keys); } + Collection pointKeys = redisCache.keys(RedisKeyConstants.POINT_CONFIG_POINT + siteId + "_*"); + if (pointKeys != null && !pointKeys.isEmpty()) { + redisCache.deleteObject(pointKeys); + } } private JSONObject toJsonObject(Object raw) { @@ -501,6 +505,11 @@ public class EmsPointConfigServiceImpl implements IEmsPointConfigService { if (StringUtils.isAnyBlank(siteId, pointId)) { return null; } + String cacheKey = RedisKeyConstants.POINT_CONFIG_POINT + siteId + "_" + pointId; + EmsPointConfig cached = redisCache.getCacheObject(cacheKey); + if (cached != null) { + return cached; + } EmsPointConfig query = new EmsPointConfig(); query.setSiteId(siteId); query.setPointId(pointId); @@ -508,7 +517,9 @@ public class EmsPointConfigServiceImpl implements IEmsPointConfigService { if (CollectionUtils.isEmpty(pointConfigs)) { return null; } - return pointConfigs.get(0); + EmsPointConfig latest = pointConfigs.get(0); + redisCache.setCacheObject(cacheKey, latest); + return latest; } private BigDecimal convertPointValue(BigDecimal sourceValue, EmsPointConfig pointConfig) { diff --git a/ems-system/src/main/java/com/xzzn/ems/service/impl/EmsStatsReportServiceImpl.java b/ems-system/src/main/java/com/xzzn/ems/service/impl/EmsStatsReportServiceImpl.java index 6efa8ca..f9d36d6 100644 --- a/ems-system/src/main/java/com/xzzn/ems/service/impl/EmsStatsReportServiceImpl.java +++ b/ems-system/src/main/java/com/xzzn/ems/service/impl/EmsStatsReportServiceImpl.java @@ -379,20 +379,90 @@ public class EmsStatsReportServiceImpl implements IEmsStatsReportService @Override public List getAmmeterRevenueDataResult(StatisAmmeterDateRequest requestVo) { - List resultList = emsDailyEnergyDataMapper.getRevenueDataBySiteId(requestVo.getSiteId(),requestVo.getStartTime(),requestVo.getEndTime()); + log.info("收益报表查询开始, siteId: {}, startTime: {}, endTime: {}", + requestVo.getSiteId(), requestVo.getStartTime(), requestVo.getEndTime()); + List resultList = emsDailyEnergyDataMapper.getRevenueDataBySiteId( + requestVo.getSiteId(), requestVo.getStartTime(), requestVo.getEndTime()); if (CollectionUtils.isEmpty(resultList)) { + log.warn("收益报表查询结果为空, siteId: {}, startTime: {}, endTime: {}", + requestVo.getSiteId(), requestVo.getStartTime(), requestVo.getEndTime()); return Collections.emptyList(); } //计算每天总收益和当日实际收益(放电总-充电总) resultList.forEach(ammeterRevenue -> { - ammeterRevenue.setActiveTotalPrice(ammeterRevenue.getActivePeakPrice().add(ammeterRevenue.getActiveHighPrice()).add(ammeterRevenue.getActiveFlatPrice()).add(ammeterRevenue.getActiveValleyPrice())); - ammeterRevenue.setReActiveTotalPrice(ammeterRevenue.getReActivePeakPrice().add(ammeterRevenue.getReActiveHighPrice()).add(ammeterRevenue.getReActiveFlatPrice()).add(ammeterRevenue.getReActiveValleyPrice())); - ammeterRevenue.setActualRevenue(ammeterRevenue.getReActiveTotalPrice().subtract(ammeterRevenue.getActiveTotalPrice())); + BigDecimal activePeakPrice = nz(ammeterRevenue.getActivePeakPrice()); + BigDecimal activeHighPrice = nz(ammeterRevenue.getActiveHighPrice()); + BigDecimal activeFlatPrice = nz(ammeterRevenue.getActiveFlatPrice()); + BigDecimal activeValleyPrice = nz(ammeterRevenue.getActiveValleyPrice()); + BigDecimal reActivePeakPrice = nz(ammeterRevenue.getReActivePeakPrice()); + BigDecimal reActiveHighPrice = nz(ammeterRevenue.getReActiveHighPrice()); + BigDecimal reActiveFlatPrice = nz(ammeterRevenue.getReActiveFlatPrice()); + BigDecimal reActiveValleyPrice = nz(ammeterRevenue.getReActiveValleyPrice()); + + ammeterRevenue.setActiveTotalPrice(activePeakPrice.add(activeHighPrice).add(activeFlatPrice).add(activeValleyPrice)); + ammeterRevenue.setReActiveTotalPrice(reActivePeakPrice.add(reActiveHighPrice).add(reActiveFlatPrice).add(reActiveValleyPrice)); + // 实际收益=放电价格(尖峰平谷)-充电价格(尖峰平谷) + ammeterRevenue.setActualRevenue( + reActivePeakPrice.subtract(activePeakPrice) + .add(reActiveHighPrice.subtract(activeHighPrice)) + .add(reActiveFlatPrice.subtract(activeFlatPrice)) + .add(reActiveValleyPrice.subtract(activeValleyPrice)) + ); }); + int weatherMissingCount = 0; + int allPriceZeroCount = 0; + for (AmmeterRevenueStatisListVo row : resultList) { + String weatherDesc = row.getWeatherDesc(); + if (weatherDesc == null || weatherDesc.trim().isEmpty() || "--".equals(weatherDesc.trim())) { + weatherMissingCount++; + } + boolean allPriceZero = safeCompareToZero(row.getActivePeakPrice()) + && safeCompareToZero(row.getActiveHighPrice()) + && safeCompareToZero(row.getActiveFlatPrice()) + && safeCompareToZero(row.getActiveValleyPrice()) + && safeCompareToZero(row.getReActivePeakPrice()) + && safeCompareToZero(row.getReActiveHighPrice()) + && safeCompareToZero(row.getReActiveFlatPrice()) + && safeCompareToZero(row.getReActiveValleyPrice()); + if (allPriceZero) { + allPriceZeroCount++; + } + log.info("收益报表明细, date: {}, dayType: {}, weather: {}, charge[尖:{} 峰:{} 平:{} 谷:{} 总:{}], discharge[尖:{} 峰:{} 平:{} 谷:{} 总:{}], actualRevenue: {}", + row.getDataTime(), + row.getDayType(), + row.getWeatherDesc(), + row.getActivePeakPrice(), + row.getActiveHighPrice(), + row.getActiveFlatPrice(), + row.getActiveValleyPrice(), + row.getActiveTotalPrice(), + row.getReActivePeakPrice(), + row.getReActiveHighPrice(), + row.getReActiveFlatPrice(), + row.getReActiveValleyPrice(), + row.getReActiveTotalPrice(), + row.getActualRevenue()); + } + log.info("收益报表查询完成, siteId: {}, startTime: {}, endTime: {}, totalRows: {}, weatherMissingRows: {}, allPriceZeroRows: {}", + requestVo.getSiteId(), + requestVo.getStartTime(), + requestVo.getEndTime(), + resultList.size(), + weatherMissingCount, + allPriceZeroCount); + return resultList; } + private boolean safeCompareToZero(BigDecimal value) { + return value == null || value.compareTo(BigDecimal.ZERO) == 0; + } + + private BigDecimal nz(BigDecimal value) { + return value == null ? BigDecimal.ZERO : value; + } + public static AmmeterRevenueStatisListVo calculateDailyBill(AmmeterStatisListVo ammeter, List priceList) { AmmeterRevenueStatisListVo ammeterRevenue = new AmmeterRevenueStatisListVo(); ammeterRevenue.setDataTime(ammeter.getDataTime()); @@ -798,19 +868,19 @@ public class EmsStatsReportServiceImpl implements IEmsStatsReportService Row row1 = sheet.createRow(0); Cell cell1 = row1.createCell(0); cell1.setCellValue("汇总"); - Cell cell2 = row1.createCell(1); + Cell cell2 = row1.createCell(3); cell2.setCellValue("充电价格"); - Cell cell3 = row1.createCell(6); + Cell cell3 = row1.createCell(8); cell3.setCellValue("放电价格"); - Cell cell4 = row1.createCell(11); + Cell cell4 = row1.createCell(13); cell4.setCellValue(""); // 合并充电量列 - CellRangeAddress mergeRegion1 = new CellRangeAddress(0, 0, 1, 5); + CellRangeAddress mergeRegion1 = new CellRangeAddress(0, 0, 3, 7); sheet.addMergedRegion(mergeRegion1); // 合并放电量列 - CellRangeAddress mergeRegion2 = new CellRangeAddress(0, 0, 6, 10); + CellRangeAddress mergeRegion2 = new CellRangeAddress(0, 0, 8, 12); sheet.addMergedRegion(mergeRegion2); // 设置第二行 @@ -818,27 +888,31 @@ public class EmsStatsReportServiceImpl implements IEmsStatsReportService Cell cell5 = row2.createCell(0); cell5.setCellValue("日期"); Cell cell6 = row2.createCell(1); - cell6.setCellValue("尖"); + cell6.setCellValue("日期类型"); Cell cell7 = row2.createCell(2); - cell7.setCellValue("峰"); + cell7.setCellValue("天气情况"); Cell cell8 = row2.createCell(3); - cell8.setCellValue("平"); + cell8.setCellValue("尖"); Cell cell9 = row2.createCell(4); - cell9.setCellValue("谷"); + cell9.setCellValue("峰"); Cell cell10 = row2.createCell(5); - cell10.setCellValue("总"); + cell10.setCellValue("平"); Cell cell11 = row2.createCell(6); - cell11.setCellValue("尖"); + cell11.setCellValue("谷"); Cell cell12 = row2.createCell(7); - cell12.setCellValue("峰"); + cell12.setCellValue("总"); Cell cell13 = row2.createCell(8); - cell13.setCellValue("平"); + cell13.setCellValue("尖"); Cell cell14 = row2.createCell(9); - cell14.setCellValue("谷"); + cell14.setCellValue("峰"); Cell cell15 = row2.createCell(10); - cell15.setCellValue("总"); + cell15.setCellValue("平"); Cell cell16 = row2.createCell(11); - cell16.setCellValue("实际收益"); + cell16.setCellValue("谷"); + Cell cell17 = row2.createCell(12); + cell17.setCellValue("总"); + Cell cell18 = row2.createCell(13); + cell18.setCellValue("实际收益"); // 设置背景颜色 CellStyle headerStyle = workbook.createCellStyle(); @@ -908,27 +982,31 @@ public class EmsStatsReportServiceImpl implements IEmsStatsReportService Cell dataCell1 = dataRow.createCell(0); dataCell1.setCellValue(ammeterRevenueStatisVo.getDataTime()); Cell dataCell2 = dataRow.createCell(1); - dataCell2.setCellValue(ammeterRevenueStatisVo.getActivePeakPrice().doubleValue()); + dataCell2.setCellValue(ammeterRevenueStatisVo.getDayType() == null ? "" : ammeterRevenueStatisVo.getDayType()); Cell dataCell3 = dataRow.createCell(2); - dataCell3.setCellValue(ammeterRevenueStatisVo.getActiveHighPrice().doubleValue()); + dataCell3.setCellValue(ammeterRevenueStatisVo.getWeatherDesc() == null ? "" : ammeterRevenueStatisVo.getWeatherDesc()); Cell dataCell4 = dataRow.createCell(3); - dataCell4.setCellValue(ammeterRevenueStatisVo.getActiveFlatPrice().doubleValue()); + dataCell4.setCellValue(ammeterRevenueStatisVo.getActivePeakPrice().doubleValue()); Cell dataCell5 = dataRow.createCell(4); - dataCell5.setCellValue(ammeterRevenueStatisVo.getActiveValleyPrice().doubleValue()); + dataCell5.setCellValue(ammeterRevenueStatisVo.getActiveHighPrice().doubleValue()); Cell dataCell6 = dataRow.createCell(5); - dataCell6.setCellValue(ammeterRevenueStatisVo.getActiveTotalPrice().doubleValue()); + dataCell6.setCellValue(ammeterRevenueStatisVo.getActiveFlatPrice().doubleValue()); Cell dataCell7 = dataRow.createCell(6); - dataCell7.setCellValue(ammeterRevenueStatisVo.getReActivePeakPrice().doubleValue()); + dataCell7.setCellValue(ammeterRevenueStatisVo.getActiveValleyPrice().doubleValue()); Cell dataCell8 = dataRow.createCell(7); - dataCell8.setCellValue(ammeterRevenueStatisVo.getReActiveHighPrice().doubleValue()); + dataCell8.setCellValue(ammeterRevenueStatisVo.getActiveTotalPrice().doubleValue()); Cell dataCell9 = dataRow.createCell(8); - dataCell9.setCellValue(ammeterRevenueStatisVo.getReActiveFlatPrice().doubleValue()); + dataCell9.setCellValue(ammeterRevenueStatisVo.getReActivePeakPrice().doubleValue()); Cell dataCell10 = dataRow.createCell(9); - dataCell10.setCellValue(ammeterRevenueStatisVo.getReActiveValleyPrice().doubleValue()); + dataCell10.setCellValue(ammeterRevenueStatisVo.getReActiveHighPrice().doubleValue()); Cell dataCell11 = dataRow.createCell(10); - dataCell11.setCellValue(ammeterRevenueStatisVo.getReActiveValleyPrice().doubleValue()); + dataCell11.setCellValue(ammeterRevenueStatisVo.getReActiveFlatPrice().doubleValue()); Cell dataCell12 = dataRow.createCell(11); - dataCell12.setCellValue(ammeterRevenueStatisVo.getActualRevenue().doubleValue()); + dataCell12.setCellValue(ammeterRevenueStatisVo.getReActiveValleyPrice().doubleValue()); + Cell dataCell13 = dataRow.createCell(12); + dataCell13.setCellValue(ammeterRevenueStatisVo.getReActiveTotalPrice().doubleValue()); + Cell dataCell14 = dataRow.createCell(13); + dataCell14.setCellValue(ammeterRevenueStatisVo.getActualRevenue().doubleValue()); // 根据行号设置背景色 if (i % 2 == 0) { @@ -961,27 +1039,31 @@ public class EmsStatsReportServiceImpl implements IEmsStatsReportService Cell lastRowCell1 = lastRow.createCell(0); lastRowCell1.setCellValue("合计"); Cell lastRowCell2 = lastRow.createCell(1); - lastRowCell2.setCellValue(activePeakPrice.doubleValue()); + lastRowCell2.setCellValue("-"); Cell lastRowCell3 = lastRow.createCell(2); - lastRowCell3.setCellValue(activeHighPrice.doubleValue()); + lastRowCell3.setCellValue("-"); Cell lastRowCell4 = lastRow.createCell(3); - lastRowCell4.setCellValue(activeFlatPrice.doubleValue()); + lastRowCell4.setCellValue(activePeakPrice.doubleValue()); Cell lastRowCell5 = lastRow.createCell(4); - lastRowCell5.setCellValue(activeValleyPrice.doubleValue()); + lastRowCell5.setCellValue(activeHighPrice.doubleValue()); Cell lastRowCell6 = lastRow.createCell(5); - lastRowCell6.setCellValue(activeTotalPrice.doubleValue()); + lastRowCell6.setCellValue(activeFlatPrice.doubleValue()); Cell lastRowCell7 = lastRow.createCell(6); - lastRowCell7.setCellValue(reActivePeakPrice.doubleValue()); + lastRowCell7.setCellValue(activeValleyPrice.doubleValue()); Cell lastRowCell8 = lastRow.createCell(7); - lastRowCell8.setCellValue(reActiveHighPrice.doubleValue()); + lastRowCell8.setCellValue(activeTotalPrice.doubleValue()); Cell lastRowCell9 = lastRow.createCell(8); - lastRowCell9.setCellValue(reActiveFlatPrice.doubleValue()); + lastRowCell9.setCellValue(reActivePeakPrice.doubleValue()); Cell lastRowCell10 = lastRow.createCell(9); - lastRowCell10.setCellValue(reActiveValleyPrice.doubleValue()); + lastRowCell10.setCellValue(reActiveHighPrice.doubleValue()); Cell lastRowCell11 = lastRow.createCell(10); - lastRowCell11.setCellValue(reActiveTotalPrice.doubleValue()); + lastRowCell11.setCellValue(reActiveFlatPrice.doubleValue()); Cell lastRowCell12 = lastRow.createCell(11); - lastRowCell12.setCellValue(actualRevenue.doubleValue()); + lastRowCell12.setCellValue(reActiveValleyPrice.doubleValue()); + Cell lastRowCell13 = lastRow.createCell(12); + lastRowCell13.setCellValue(reActiveTotalPrice.doubleValue()); + Cell lastRowCell14 = lastRow.createCell(13); + lastRowCell14.setCellValue(actualRevenue.doubleValue()); Iterator lastRowCellIterator = lastRow.cellIterator(); while (lastRowCellIterator.hasNext()) { int i = lastRowCellIterator.next().getColumnIndex(); diff --git a/ems-system/src/main/java/com/xzzn/ems/service/impl/EmsWeatherSyncServiceImpl.java b/ems-system/src/main/java/com/xzzn/ems/service/impl/EmsWeatherSyncServiceImpl.java new file mode 100644 index 0000000..da4ff65 --- /dev/null +++ b/ems-system/src/main/java/com/xzzn/ems/service/impl/EmsWeatherSyncServiceImpl.java @@ -0,0 +1,199 @@ +package com.xzzn.ems.service.impl; + +import com.alibaba.fastjson2.JSONArray; +import com.alibaba.fastjson2.JSONObject; +import com.xzzn.common.exception.ServiceException; +import com.xzzn.common.utils.StringUtils; +import com.xzzn.common.utils.http.HttpUtils; +import com.xzzn.ems.config.WeatherApiProperties; +import com.xzzn.ems.domain.EmsSiteSetting; +import com.xzzn.ems.domain.vo.StatisAmmeterDateRequest; +import com.xzzn.ems.domain.vo.WeatherSyncResultVo; +import com.xzzn.ems.mapper.EmsSiteSettingMapper; +import com.xzzn.ems.mapper.EmsSiteWeatherDayMapper; +import com.xzzn.ems.service.IEmsWeatherSyncService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.io.UnsupportedEncodingException; +import java.math.BigDecimal; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; + +@Service +public class EmsWeatherSyncServiceImpl implements IEmsWeatherSyncService { + private static final Logger log = LoggerFactory.getLogger(EmsWeatherSyncServiceImpl.class); + private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd"); + + @Autowired + private WeatherApiProperties weatherApiProperties; + @Autowired + private EmsSiteSettingMapper emsSiteSettingMapper; + @Autowired + private EmsSiteWeatherDayMapper emsSiteWeatherDayMapper; + + @Override + public WeatherSyncResultVo syncWeatherByDateRange(StatisAmmeterDateRequest requestVo) { + if (!weatherApiProperties.isEnabled()) { + throw new ServiceException("天气同步未启用,请先设置 weather.api.enabled=true"); + } + if (requestVo == null || StringUtils.isEmpty(requestVo.getSiteId()) + || StringUtils.isEmpty(requestVo.getStartTime()) + || StringUtils.isEmpty(requestVo.getEndTime())) { + throw new ServiceException("siteId、startTime、endTime 不能为空"); + } + LocalDate startDate = parseDate(requestVo.getStartTime(), "startTime"); + LocalDate endDate = parseDate(requestVo.getEndTime(), "endTime"); + if (endDate.isBefore(startDate)) { + throw new ServiceException("endTime 不能早于 startTime"); + } + + EmsSiteSetting siteSetting = emsSiteSettingMapper.selectEmsSiteSettingBySiteId(requestVo.getSiteId()); + if (siteSetting == null) { + throw new ServiceException("未找到站点配置,siteId=" + requestVo.getSiteId()); + } + BigDecimal latitude = siteSetting.getLatitude(); + BigDecimal longitude = siteSetting.getLongitude(); + if (latitude == null || longitude == null) { + throw new ServiceException("站点缺少经纬度配置,siteId=" + requestVo.getSiteId()); + } + + String url = buildWeatherUrl(latitude, longitude, startDate, endDate); + String response = HttpUtils.sendGet(url); + if (StringUtils.isEmpty(response)) { + throw new ServiceException("调用天气接口失败,返回为空"); + } + JSONObject root = JSONObject.parseObject(response); + JSONObject daily = root == null ? null : root.getJSONObject("daily"); + JSONArray dates = daily == null ? null : daily.getJSONArray("time"); + JSONArray codes = daily == null ? null : daily.getJSONArray("weather_code"); + if (dates == null || codes == null || dates.size() == 0 || dates.size() != codes.size()) { + throw new ServiceException("天气接口返回格式异常,daily.time/weather_code 不可用"); + } + + WeatherSyncResultVo resultVo = new WeatherSyncResultVo(); + resultVo.setSiteId(requestVo.getSiteId()); + resultVo.setStartTime(requestVo.getStartTime()); + resultVo.setEndTime(requestVo.getEndTime()); + resultVo.setTotalDays(dates.size()); + + int updated = 0; + int inserted = 0; + for (int i = 0; i < dates.size(); i++) { + String dateStr = dates.getString(i); + int weatherCode = codes.getIntValue(i); + String weatherDesc = mapWeatherDesc(weatherCode); + + int updateRows = emsSiteWeatherDayMapper.updateWeatherDesc( + requestVo.getSiteId(), dateStr, weatherDesc, weatherCode); + if (updateRows > 0) { + updated++; + continue; + } + + int count = emsSiteWeatherDayMapper.selectCountBySiteAndDate(requestVo.getSiteId(), dateStr); + if (count == 0) { + emsSiteWeatherDayMapper.insertSiteWeatherDay( + requestVo.getSiteId(), dateStr, weatherDesc, weatherCode, "open-meteo"); + inserted++; + continue; + } + + // 理论上不会到这里,防御性兜底再更新一次 + updated += emsSiteWeatherDayMapper.updateWeatherDesc( + requestVo.getSiteId(), dateStr, weatherDesc, weatherCode); + } + resultVo.setUpdatedDays(updated); + resultVo.setInsertedDays(inserted); + resultVo.setSuccessDays(updated + inserted); + resultVo.setMessage("天气同步完成"); + + log.info("天气同步完成, siteId: {}, startTime: {}, endTime: {}, totalDays: {}, updatedDays: {}, insertedDays: {}", + requestVo.getSiteId(), requestVo.getStartTime(), requestVo.getEndTime(), + resultVo.getTotalDays(), updated, inserted); + return resultVo; + } + + private LocalDate parseDate(String value, String fieldName) { + try { + return LocalDate.parse(value, DATE_FORMATTER); + } catch (Exception e) { + throw new ServiceException(fieldName + " 格式错误,应为 yyyy-MM-dd"); + } + } + + private String buildWeatherUrl(BigDecimal latitude, BigDecimal longitude, LocalDate startDate, LocalDate endDate) { + StringBuilder builder = new StringBuilder(); + builder.append(weatherApiProperties.getBaseUrl()) + .append("?latitude=").append(latitude.stripTrailingZeros().toPlainString()) + .append("&longitude=").append(longitude.stripTrailingZeros().toPlainString()) + .append("&start_date=").append(startDate.format(DATE_FORMATTER)) + .append("&end_date=").append(endDate.format(DATE_FORMATTER)) + .append("&daily=weather_code") + .append("&timezone=").append(urlEncode(weatherApiProperties.getTimezone())); + if (StringUtils.isNotEmpty(weatherApiProperties.getApiKey())) { + builder.append("&apikey=").append(urlEncode(weatherApiProperties.getApiKey())); + } + return builder.toString(); + } + + private String urlEncode(String value) { + try { + return URLEncoder.encode(value, StandardCharsets.UTF_8.name()); + } catch (UnsupportedEncodingException e) { + throw new ServiceException("URL 编码失败"); + } + } + + private String mapWeatherDesc(int weatherCode) { + switch (weatherCode) { + case 0: + return "晴"; + case 1: + case 2: + case 3: + return "多云"; + case 45: + case 48: + return "雾"; + case 51: + case 53: + case 55: + return "毛毛雨"; + case 56: + case 57: + return "冻毛毛雨"; + case 61: + case 63: + case 65: + return "雨"; + case 66: + case 67: + return "冻雨"; + case 71: + case 73: + case 75: + return "雪"; + case 77: + return "雪粒"; + case 80: + case 81: + case 82: + return "阵雨"; + case 85: + case 86: + return "阵雪"; + case 95: + return "雷暴"; + case 96: + case 99: + return "雷暴伴冰雹"; + default: + return "未知(" + weatherCode + ")"; + } + } +} diff --git a/ems-system/src/main/java/com/xzzn/ems/service/impl/FXXDataProcessServiceImpl.java b/ems-system/src/main/java/com/xzzn/ems/service/impl/FXXDataProcessServiceImpl.java deleted file mode 100644 index e95ac48..0000000 --- a/ems-system/src/main/java/com/xzzn/ems/service/impl/FXXDataProcessServiceImpl.java +++ /dev/null @@ -1,1122 +0,0 @@ -package com.xzzn.ems.service.impl; - -import com.alibaba.fastjson2.JSON; -import com.alibaba.fastjson2.JSONArray; -import com.alibaba.fastjson2.JSONObject; -import com.alibaba.fastjson2.TypeReference; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.xzzn.common.constant.RedisKeyConstants; -import com.xzzn.common.core.redis.RedisCache; -import com.xzzn.common.enums.BranchStatus; -import com.xzzn.common.enums.ChargeStatus; -import com.xzzn.common.enums.CommunicationStatus; -import com.xzzn.common.enums.ControlModeStatus; -import com.xzzn.common.enums.DeviceRunningStatus; -import com.xzzn.common.enums.GridStatus; -import com.xzzn.common.enums.SwitchStatus; -import com.xzzn.common.enums.WorkStatus; -import com.xzzn.common.utils.DateUtils; -import com.xzzn.common.utils.StringUtils; -import com.xzzn.ems.domain.EmsAmmeterData; -import com.xzzn.ems.domain.EmsBatteryCluster; -import com.xzzn.ems.domain.EmsBatteryData; -import com.xzzn.ems.domain.EmsBatteryDataDailyLatest; -import com.xzzn.ems.domain.EmsBatteryDataMinutes; -import com.xzzn.ems.domain.EmsBatteryStack; -import com.xzzn.ems.domain.EmsCoolingData; -import com.xzzn.ems.domain.EmsDailyChargeData; -import com.xzzn.ems.domain.EmsDailyEnergyData; -import com.xzzn.ems.domain.EmsDevicesSetting; -import com.xzzn.ems.domain.EmsDhData; -import com.xzzn.ems.domain.EmsPcsBranchData; -import com.xzzn.ems.domain.EmsPcsData; -import com.xzzn.ems.domain.EmsPointMatch; -import com.xzzn.ems.domain.vo.EnergyPriceTimeRange; -import com.xzzn.ems.domain.vo.EnergyPriceVo; -import com.xzzn.ems.enums.DeviceMatchTable; -import com.xzzn.ems.mapper.EmsAmmeterDataMapper; -import com.xzzn.ems.mapper.EmsBatteryClusterMapper; -import com.xzzn.ems.mapper.EmsBatteryDataMapper; -import com.xzzn.ems.mapper.EmsBatteryDataMinutesMapper; -import com.xzzn.ems.mapper.EmsBatteryStackMapper; -import com.xzzn.ems.mapper.EmsCoolingDataMapper; -import com.xzzn.ems.mapper.EmsDailyChargeDataMapper; -import com.xzzn.ems.mapper.EmsDailyEnergyDataMapper; -import com.xzzn.ems.mapper.EmsDevicesSettingMapper; -import com.xzzn.ems.mapper.EmsDhDataMapper; -import com.xzzn.ems.mapper.EmsEnergyPriceConfigMapper; -import com.xzzn.ems.mapper.EmsPcsBranchDataMapper; -import com.xzzn.ems.mapper.EmsPcsDataMapper; -import com.xzzn.ems.service.IEmsAlarmRecordsService; -import com.xzzn.ems.service.IEmsEnergyPriceConfigService; -import com.xzzn.ems.service.IFXXDataProcessService; -import com.xzzn.ems.utils.AbstractBatteryDataProcessor; -import com.xzzn.ems.utils.DevicePointMatchDataProcessor; - -import java.lang.reflect.Field; -import java.math.BigDecimal; -import java.time.LocalDate; -import java.time.LocalDateTime; -import java.time.format.DateTimeFormatter; -import java.time.temporal.ChronoUnit; -import java.util.ArrayList; -import java.util.Date; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.TimeUnit; -import java.util.stream.Collectors; - -import org.apache.commons.collections4.CollectionUtils; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.springframework.beans.BeanUtils; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - -@Service -public class FXXDataProcessServiceImpl extends AbstractBatteryDataProcessor implements IFXXDataProcessService { - private static final Log log = LogFactory.getLog(FXXDataProcessServiceImpl.class); - private static final String SITE_ID = "021_FXX_01"; - - @Autowired - private EmsBatteryClusterMapper emsBatteryClusterMapper; - - @Autowired - private EmsBatteryStackMapper emsBatteryStackMapper; - - @Autowired - private EmsBatteryDataMapper emsBatteryDataMapper; - - @Autowired - private EmsPcsDataMapper emsPcsDataMapper; - - @Autowired - private EmsPcsBranchDataMapper emsPcsBranchDataMapper; - - @Autowired - private RedisCache redisCache; - - @Autowired - private EmsDevicesSettingMapper emsDevicesSettingMapper; - - @Autowired - private EmsAmmeterDataMapper emsAmmeterDataMapper; - @Autowired - private EmsBatteryDailyLatestServiceImpl emsBatteryDailyLatestServiceImpl; - @Autowired - private EmsBatteryDataMinutesMapper emsBatteryDataMinutesMapper; - @Autowired - private EmsDailyChargeDataMapper emsDailyChargeDataMapper; - @Autowired - private EmsDhDataMapper emsDhDataMapper; - @Autowired - private IEmsAlarmRecordsService iEmsAlarmRecordsService; - @Autowired - private EmsCoolingDataMapper emsCoolingDataMapper; - @Autowired - private EmsDailyEnergyDataMapper emsDailyEnergyDataMapper; - @Autowired - private EmsEnergyPriceConfigMapper emsEnergyPriceConfigMapper; - @Autowired - private IEmsEnergyPriceConfigService emsEnergyPriceConfigService; - @Autowired - private IEmsEnergyPriceConfigService iEmsEnergyPriceConfigService; - @Autowired - private DevicePointMatchDataProcessor devicePointMatchDataProcessor; - - // 构造方法(调用父类构造) - public FXXDataProcessServiceImpl(ObjectMapper objectMapper) { - super(objectMapper); - } - - @Override - public void handleFxData(String message) { - JSONArray arraylist = JSONArray.parseArray(message); - - for (int i = 0; i < arraylist.size(); i++) { - JSONObject obj = JSONObject.parseObject(arraylist.get(i).toString()); - - String deviceId = obj.get("Device").toString(); - String jsonData = obj.get("Data").toString(); - Long timestamp = Long.valueOf(obj.get("timestamp").toString()); - Date dataUpdateTime = DateUtils.convertUpdateTime(timestamp); - - log.info("deviceId:" + deviceId); - boolean isEmpty = checkJsonDataEmpty(jsonData); - if (isEmpty) { - // 添加设备告警 - iEmsAlarmRecordsService.addEmptyDataAlarmRecord(SITE_ID,deviceId); - return; - } - - // 存放mqtt原始每个设备最晚一次数据,便于后面点位获取数据 - redisCache.setCacheObject(RedisKeyConstants.ORIGINAL_MQTT_DATA + SITE_ID + "_" + deviceId, obj); - // 存放每次同步数据,失效时间(同同步时间)-用于判断是否正常同步数据 - redisCache.setCacheObject(RedisKeyConstants.SYNC_DATA + SITE_ID + "_" + deviceId, obj, 1, TimeUnit.MINUTES); - - if (deviceId.contains("BMSD")) { - batteryStackDataProcess(deviceId, jsonData); - - } else if (deviceId.contains("BMSC")) { - batteryClusterDataProcess(deviceId, jsonData); - batteryDataProcess(deviceId, jsonData,dataUpdateTime); - - } else if (deviceId.contains("PCS")) { - pcsDataProcess(deviceId, jsonData,dataUpdateTime); - pcsBranchDataProcess(deviceId, jsonData); - dealFXXDailyChargeDate(deviceId, jsonData); - } else if (deviceId.contains("LOAD")) { - loadDataProcess(deviceId, jsonData, dataUpdateTime); - } else if (deviceId.contains("METE")) { - meteDataProcess(deviceId, jsonData, dataUpdateTime); - } else if (deviceId.contains("donghuan")) { - dhDataProcess(deviceId, jsonData); - } else if (deviceId.contains("ZSLQ")) { - coolingDataProcess(deviceId, jsonData); - } - } - } - - private void coolingDataProcess(String deviceId, String jsonData) { - //中水冷却 - Map obj = JSON.parseObject(jsonData, new TypeReference>() { - }); - - EmsCoolingData coolingData = new EmsCoolingData(); - - coolingData.setGsTemp(StringUtils.getBigDecimal(obj.get("GSWD"))); - coolingData.setHsTemp(StringUtils.getBigDecimal(obj.get("HSWD"))); - coolingData.setGsPressure(StringUtils.getBigDecimal(obj.get("GSYL"))); - coolingData.setHsPressure(StringUtils.getBigDecimal(obj.get("HSYL"))); - coolingData.setLysTemp(StringUtils.getBigDecimal(obj.get("LYSWD"))); - coolingData.setVb01Kd(StringUtils.getBigDecimal(obj.get("VB1KD"))); - coolingData.setVb02Kd(StringUtils.getBigDecimal(obj.get("VB2KD"))); - - coolingData.setCreateBy("system"); - coolingData.setCreateTime(DateUtils.getNowDate()); - coolingData.setUpdateBy("system"); - coolingData.setUpdateTime(DateUtils.getNowDate()); - coolingData.setSiteId(SITE_ID); - coolingData.setDeviceId(deviceId); - - emsCoolingDataMapper.insertEmsCoolingData(coolingData); - - redisCache.setCacheObject(RedisKeyConstants.COOLING + SITE_ID + "_" +deviceId, coolingData); - - } - - private void dhDataProcess(String deviceId, String dataJson) { - //动环 - Map obj = JSON.parseObject(dataJson, new TypeReference>() { - }); - - //DH - EmsDhData dhData = new EmsDhData(); - dhData.setHumidity(StringUtils.getBigDecimal(obj.get("SD3"))); - dhData.setTemperature(StringUtils.getBigDecimal(obj.get("WD3"))); - - dhData.setCreateBy("system"); - dhData.setCreateTime(DateUtils.getNowDate()); - dhData.setUpdateBy("system"); - dhData.setUpdateTime(DateUtils.getNowDate()); - dhData.setSiteId(SITE_ID); - dhData.setDeviceId(deviceId); - emsDhDataMapper.insertEmsDhData(dhData); - - redisCache.setCacheObject(RedisKeyConstants.DH + SITE_ID + "_" +deviceId, dhData); - - } - - private void batteryStackDataProcess(String deviceId, String dataJson) { - - //电池堆 - Map obj = JSON.parseObject(dataJson, new TypeReference>() { - }); - - //BMS 电池簇 - EmsBatteryStack dataStack = new EmsBatteryStack(); - - // 其他非 BigDecimal 字段 - dataStack.setWorkStatus(WorkStatus.NORMAL.getCode()); // 或其他默认值 - dataStack.setPcsCommunicationStatus(CommunicationStatus.OK.getCode()); - dataStack.setEmsCommunicationStatus(CommunicationStatus.OK.getCode()); - - // 电池堆状态数据设置 - dataStack.setOperationStatus(StringUtils.getString(obj.get("DCZT"))); - dataStack.setStackVoltage(StringUtils.getBigDecimal(obj.get("DCDDY"))); - dataStack.setStackCurrent(StringUtils.getBigDecimal(obj.get("DCDDL"))); - dataStack.setStackSoc(StringUtils.getBigDecimal(obj.get("DCDSOC"))); - dataStack.setStackSoh(StringUtils.getBigDecimal(obj.get("DCDSOH"))); - - // 电压极值信息 - dataStack.setMaxCellVoltage(StringUtils.getBigDecimal(obj.get("ZGDCDY"))); - dataStack.setMaxVoltageGroupId(StringUtils.getLong(obj.get("ZGDCDYZH"))); - dataStack.setMaxVoltageCellId(StringUtils.getLong(obj.get("ZGDCDYZHDH"))); - dataStack.setMinCellVoltage(StringUtils.getBigDecimal(obj.get("ZDDCDY"))); - dataStack.setMinVoltageGroupId(StringUtils.getLong(obj.get("ZDDCDYZH"))); - dataStack.setMinVoltageCellId(StringUtils.getLong(obj.get("ZDDCDYZHDH"))); - - // 温度极值信息 - dataStack.setMaxCellTemp(StringUtils.getBigDecimal(obj.get("ZGDCWD"))); - dataStack.setMaxTempGroupId(StringUtils.getLong(obj.get("ZGDCWDZH"))); - dataStack.setMaxTempCellId(StringUtils.getLong(obj.get("ZGDCWDZHDH"))); - dataStack.setMinCellTemp(StringUtils.getBigDecimal(obj.get("ZDDCWD"))); - dataStack.setMinTempGroupId(StringUtils.getLong(obj.get("ZDDCWDZH"))); - dataStack.setMinTempCellId(StringUtils.getLong(obj.get("ZDDCWDZHDH"))); - - // 电量统计信息 - dataStack.setTotalChargeCapacity(StringUtils.getBigDecimal(obj.get("DLJCDDL"))); - dataStack.setTotalDischargeCapacity(StringUtils.getBigDecimal(obj.get("DLCFDDL"))); - dataStack.setSessionChargeCapacity(StringUtils.getBigDecimal(obj.get("DDCLJCDDL"))); - dataStack.setSessionDischargeCapacity(StringUtils.getBigDecimal(obj.get("DDCLJFDDL"))); - dataStack.setAvailableChargeCapacity(StringUtils.getBigDecimal(obj.get("DKCDL"))); - dataStack.setAvailableDischargeCapacity(StringUtils.getBigDecimal(obj.get("DKFDL"))); - - // 时间信息 - dataStack.setRemainingDischargeTime(StringUtils.getLong(obj.get("KYFDSJ"))); - dataStack.setRemainingChargeTime(StringUtils.getLong(obj.get("KYCDSJ"))); - - // 功率/电流限制 - dataStack.setMaxDischargePower(StringUtils.getBigDecimal(obj.get("YXZDFDGL"))); - dataStack.setMaxChargePower(StringUtils.getBigDecimal(obj.get("YXZDCDGL"))); - dataStack.setMaxDischargeCurrent(StringUtils.getBigDecimal(obj.get("YXZDFDDL"))); - dataStack.setMaxChargeCurrent(StringUtils.getBigDecimal(obj.get("YXZDCDDL"))); - - // 当日统计 - dataStack.setDailyDischargeCycles(StringUtils.getLong(obj.get("DTFDCS"))); - dataStack.setDailyChargeCycles(StringUtils.getLong(obj.get("DTCDCS"))); - dataStack.setDailyDischargeCapacity(StringUtils.getBigDecimal(obj.get("DTFDDL"))); - dataStack.setDailyChargeCapacity(StringUtils.getBigDecimal(obj.get("DTCDDL"))); - - // 系统状态 - dataStack.setOperatingTemp(StringUtils.getBigDecimal(obj.get("YXWD"))); - dataStack.setBmsStatus(StringUtils.getString(obj.get("BMSDDQZT"))); - dataStack.setBmsChargeStatus(StringUtils.getString(obj.get("BMSCFDZT"))); - dataStack.setStackInsulationResistance(StringUtils.getBigDecimal(obj.get("DCDJYDZ"))); - - - dataStack.setCreateBy("system"); - dataStack.setCreateTime(DateUtils.getNowDate()); - dataStack.setUpdateBy("system"); - dataStack.setUpdateTime(DateUtils.getNowDate()); - dataStack.setSiteId(SITE_ID); - dataStack.setDeviceId(deviceId); - - emsBatteryStackMapper.insertEmsBatteryStack(dataStack); - - redisCache.setCacheObject(RedisKeyConstants.STACK + SITE_ID + "_" +deviceId, dataStack); - - } - - private void saveDeviceData(List pointMatchList, Map obj, Object entity) { - Map pointMatchMap = pointMatchList.stream().collect(Collectors.toMap(data -> StringUtils.toCamelCase(data.getMatchField()), EmsPointMatch::getDataPoint)); - Field[] fields = entity.getClass().getDeclaredFields(); - for (Field field : fields) { - if (pointMatchMap.containsKey(field.getName())) { - field.setAccessible(true); - try { - Object matchValue = obj.get(pointMatchMap.get(field.getName())); - Class fieldType = field.getType(); - if (String.class.equals(fieldType)) { - matchValue = StringUtils.getString(matchValue); - } else if (Long.class.equals(fieldType)) { - matchValue = StringUtils.getLong(matchValue); - } else if (BigDecimal.class.equals(fieldType)) { - matchValue = StringUtils.getBigDecimal(matchValue); - } - field.set(entity, matchValue); - } catch (IllegalAccessException e) { - log.warn("batteryStackDataProcess 设置字段值时出错", e); - } - } - } - } - - private void saveDevicePointMatchData(List pointMatchList, String deviceId, - DeviceMatchTable pointMatchType, String dataDevice){ - if (CollectionUtils.isNotEmpty(pointMatchList)) { - return; - } - devicePointMatchDataProcessor.saveDevicePointMatch(SITE_ID, deviceId, pointMatchType, dataDevice); - } - - private void batteryClusterDataProcess(String deviceId, String dataJson) { - - Map obj = JSON.parseObject(dataJson, new TypeReference>() { - }); - EmsDevicesSetting joken = new EmsDevicesSetting(); - joken.setDeviceId(deviceId); - List up = emsDevicesSettingMapper.selectEmsDevicesSettingList(joken); - String stackDeviceId = ""; - if (up != null && up.size() >0) { - stackDeviceId = up.get(0).getParentId(); - if (stackDeviceId == null || stackDeviceId.isEmpty()) { - stackDeviceId = "1"; - } - } - //BMS 电池簇 - EmsBatteryCluster data = new EmsBatteryCluster(); - // 设置所有 BigDecimal 类型字段为 ZERO - data.setChargeableCapacity(StringUtils.getBigDecimal(obj.get("KCDL"))); - data.setClusterVoltage(StringUtils.getBigDecimal(obj.get("ZDY"))); - data.setClusterCurrent(StringUtils.getBigDecimal(obj.get("ZDL"))); - data.setTotalChargedCapacity(StringUtils.getBigDecimal(obj.get("LJCDDL"))); - data.setDischargeableCapacity(StringUtils.getBigDecimal(obj.get("KFDL"))); - data.setTotalDischargedCapacity(StringUtils.getBigDecimal(obj.get("LJFDDL"))); - data.setSoh(StringUtils.getBigDecimal(obj.get("ZSOH"))); - data.setAverageTemperature(StringUtils.getBigDecimal(obj.get("MKWD"))); - data.setInsulationResistance(StringUtils.getBigDecimal(obj.get("ZJYDZ"))); - data.setCurrentSoc(StringUtils.getBigDecimal(obj.get("ZSOC"))); - data.setMaxAllowedChargePower(StringUtils.getBigDecimal(obj.get("YXCDZDGL"))); - data.setMaxAllowedDischargePower(StringUtils.getBigDecimal(obj.get("YXFDZDGL"))); - data.setMaxAllowedChargeVoltage(StringUtils.getBigDecimal(obj.get("YXCDZDDY"))); - data.setMaxAllowedDischargeVoltage(StringUtils.getBigDecimal(obj.get("YXFDZDDY"))); - data.setMaxAllowedChargeCurrent(StringUtils.getBigDecimal(obj.get("YXCDZDDL"))); - data.setMaxAllowedDischargeCurrent(StringUtils.getBigDecimal(obj.get("YXFDZDDL"))); - data.setBatteryPackVoltage(StringUtils.getBigDecimal(obj.get("ZDY"))); - data.setBatteryPackCurrent(StringUtils.getBigDecimal(obj.get("ZDL"))); - data.setBatteryPackTemp(StringUtils.getBigDecimal(obj.get("MKWD"))); - data.setBatteryPackSoc(StringUtils.getBigDecimal(obj.get("ZSOC"))); - data.setBatteryPackSoh(StringUtils.getBigDecimal(obj.get("ZSOH"))); - data.setBatteryPackInsulationResistance(StringUtils.getBigDecimal(obj.get("ZJYDZ"))); - data.setAvgCellVoltage(StringUtils.getBigDecimal(obj.get("PJDTDY"))); - data.setAvgCellTemp(StringUtils.getBigDecimal(obj.get("PJDTWD"))); - data.setMaxCellVoltage(StringUtils.getBigDecimal(obj.get("ZGDTDY"))); - data.setMinCellVoltage(StringUtils.getBigDecimal(obj.get("ZDDTDY"))); - data.setMaxCellTemp(StringUtils.getBigDecimal(obj.get("ZGDTWD"))); - data.setMinCellTemp(StringUtils.getBigDecimal(obj.get("ZDDTWD"))); - data.setMaxCellSoc(StringUtils.getBigDecimal(obj.get("ZGDTSOC"))); - data.setMinCellSoc(StringUtils.getBigDecimal(obj.get("ZDDTSOC"))); - data.setMaxCellSoh(StringUtils.getBigDecimal(obj.get("ZGDTSOH"))); - data.setMinCellSoh(StringUtils.getBigDecimal(obj.get("ZDDTSOH"))); - data.setTotalChargeEnergy(StringUtils.getBigDecimal(obj.get("DCLJCDDL"))); - data.setTotalDischargeEnergy(StringUtils.getBigDecimal(obj.get("DCLJFDDL"))); - - // 其他非 BigDecimal 字段 - data.setMaxCellVoltageId(StringUtils.getString(obj.get("ZGDTDYDYD"))); - data.setMinCellVoltageId(StringUtils.getString(obj.get("ZDDTDYDYD"))); - data.setMaxCellTempId(StringUtils.getString(obj.get("ZGDTWDDYD"))); - data.setMinCellTempId(StringUtils.getString(obj.get("ZDDTWDDYD"))); - data.setMaxCellSocId(StringUtils.getString(obj.get("ZGDTSOCDYD"))); - data.setMinCellSocId(StringUtils.getString(obj.get("ZDDTSOCDYD"))); - data.setMaxCellSohId(StringUtils.getString(obj.get("ZGDTSOHDYD"))); - data.setMinCellSohId(StringUtils.getString(obj.get("ZDDTSOHDYD"))); - - data.setWorkStatus(WorkStatus.NORMAL.getCode()); // 或其他默认值 - data.setPcsCommunicationStatus(CommunicationStatus.OK.getCode()); - data.setEmsCommunicationStatus(CommunicationStatus.OK.getCode()); - data.setCreateBy("system"); - data.setCreateTime(DateUtils.getNowDate()); - data.setUpdateBy("system"); - data.setUpdateTime(DateUtils.getNowDate()); - data.setSiteId(SITE_ID); - data.setDeviceId(deviceId); - if (StringUtils.isNotBlank(stackDeviceId)) { - data.setStackDeviceId(stackDeviceId); - } else { - data.setStackDeviceId("1"); - } - emsBatteryClusterMapper.insertEmsBatteryCluster(data); - - redisCache.setCacheObject(RedisKeyConstants.CLUSTER + SITE_ID + "_" +deviceId, data); - - } - - private void batteryDataProcess(String deviceId, String dataJson, Date dataUpdateTime) { - EmsDevicesSetting joken = new EmsDevicesSetting(); - joken.setDeviceId(deviceId); - List up = emsDevicesSettingMapper.selectEmsDevicesSettingList(joken); - String stackDeviceId = ""; - if (up != null && up.size() >0) { - stackDeviceId = up.get(0).getParentId(); - if (stackDeviceId == null || stackDeviceId.isEmpty()) { - stackDeviceId = "1"; - } - } - //单体电池 - Map> records = processData(JSON.parseObject(dataJson, new TypeReference>() {})); - List list = new ArrayList<>(); - List dailyList = new ArrayList<>(); - List minutesList = new ArrayList<>(); - // 前一个小时 - LocalDateTime oneHourAgo = LocalDateTime.now().minus(1, ChronoUnit.HOURS); - DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); - String oneHourAgoStr = oneHourAgo.format(formatter); - //单体电池 - for (Map.Entry> record : records.entrySet()) { - String recordId = record.getKey(); - Map fields = record.getValue(); - - EmsBatteryData batteryData = new EmsBatteryData(); - batteryData.setDeviceId(recordId); - batteryData.setBatteryCellId(recordId); - - batteryData.setSoc(StringUtils.getBigDecimal(fields.get("DTSOC"))); - batteryData.setSoh(StringUtils.getBigDecimal(fields.get("DTSOH"))); - batteryData.setTemperature(StringUtils.getBigDecimal(fields.get("DTWD"))); - batteryData.setVoltage(StringUtils.getBigDecimal(fields.get("DTDY"))); - - batteryData.setBatteryCluster(deviceId); - batteryData.setBatteryPack(stackDeviceId); - - // 时间戳 - batteryData.setDataTimestamp(dataUpdateTime); - // 系统管理字段 - batteryData.setCreateBy("system"); - batteryData.setCreateTime(DateUtils.getNowDate()); - batteryData.setUpdateBy("system"); - batteryData.setUpdateTime(DateUtils.getNowDate()); - // ID字段 - batteryData.setSiteId(SITE_ID); - batteryData.setClusterDeviceId(deviceId); - list.add(batteryData); - - // 每日最新数据 - EmsBatteryDataDailyLatest daily = new EmsBatteryDataDailyLatest(); - BeanUtils.copyProperties(batteryData, daily); - daily.setDateDay(DateUtils.getNowDate()); - dailyList.add(daily); - - // 分钟级的表,上报的数据直接存入,数据上限是 1 个小时 - EmsBatteryDataMinutes minutes = new EmsBatteryDataMinutes(); - BeanUtils.copyProperties(batteryData, minutes); - minutesList.add(minutes); - } - if (list.size() > 0) { - emsBatteryDataMapper.insertEmsBatteryDataList(list); - - redisCache.deleteList(RedisKeyConstants.BATTERY + SITE_ID + "_" + deviceId); - redisCache.setCacheList(RedisKeyConstants.BATTERY + SITE_ID + "_" + deviceId, list); - - } - - // 批量处理每日最新数据 - if (dailyList != null && dailyList.size() > 0) { - emsBatteryDailyLatestServiceImpl.batchProcessBatteryData(dailyList); - } - // 实时插入每分钟数据 - if (minutesList != null && minutesList.size() > 0) { - emsBatteryDataMinutesMapper.insertMinutesBatteryDataList(minutesList); - } - // 清理分钟级表里一小时前数据 - emsBatteryDataMinutesMapper.deleteByTimeBeforeOneHour(oneHourAgoStr); - - // 分片处理时级,天级,月级数据 - if (list.size() > 0) { - super.processBatch(list); - } - } - - private void pcsDataProcess(String deviceId, String dataJson, Date dataUpdateTime) { - Map obj = JSON.parseObject(dataJson, new TypeReference>() { - }); - - //pcs - EmsPcsData pcsData = new EmsPcsData(); - - // 功率与能量类字段 - pcsData.setTotalActivePower(StringUtils.getBigDecimal(obj.get("YGGL"))); - pcsData.setDailyAcChargeEnergy(StringUtils.getBigDecimal(obj.get("RCDL"))); - pcsData.setTotalReactivePower(StringUtils.getBigDecimal(obj.get("XTWGGL"))); - pcsData.setDailyAcDischargeEnergy(StringUtils.getBigDecimal(obj.get("RFDL"))); - pcsData.setTotalApparentPower(StringUtils.getBigDecimal(obj.get("XTSZGL"))); - pcsData.setTotalPowerFactor(StringUtils.getBigDecimal(obj.get("GLYS"))); - pcsData.setDcPower(StringUtils.getBigDecimal(obj.get("XTSZGL"))); - pcsData.setTotalAcChargeEnergy(StringUtils.getBigDecimal(obj.get("ZCDL"))); - pcsData.setTotalAcDischargeEnergy(StringUtils.getBigDecimal(obj.get("ZFDL"))); - pcsData.setAcChargeActivePower(StringUtils.getBigDecimal(obj.get("JLCCDYGGL"))); - pcsData.setAcCapacitiveReactivePower(StringUtils.getBigDecimal(obj.get("JLCRXWGGL"))); - pcsData.setAcDischargeActivePower(StringUtils.getBigDecimal(obj.get("JLCFDYGGL"))); - pcsData.setAcInductiveReactivePower(StringUtils.getBigDecimal(obj.get("JLCGXWGGL"))); - pcsData.setMaxCapacitivePowerCapacity(StringUtils.getBigDecimal(obj.get("ZDRXWGNL"))); - pcsData.setMaxInductivePowerCapacity(StringUtils.getBigDecimal(obj.get("ZDGXWGNL"))); - pcsData.setMaxChargePowerCapacity(StringUtils.getBigDecimal(obj.get("ZDKCGL"))); - pcsData.setMaxDischargePowerCapacity(StringUtils.getBigDecimal(obj.get("ZDKFGL"))); - - - // 温度与环境参数 -// pcsData.setPcsModuleTemperature(StringUtils.getBigDecimal(obj.get("ChargeableCapacity"))); -// pcsData.setPcsEnvironmentTemperature(StringUtils.getBigDecimal(obj.get("ChargeableCapacity"))); -// pcsData.setAcFrequency(StringUtils.getBigDecimal(obj.get("ChargeableCapacity"))); - - // 状态指示类 - pcsData.setBranchStatus(BranchStatus.NORMAL.getCode()); - pcsData.setDischargeStatus(ChargeStatus.CHARGING.getCode()); - String acSwitchStatus = StringUtils.getString(obj.get("JLKGZT")); - pcsData.setAcSwitchStatus(SwitchStatus.CLOSED.getCode()); - String dcSwitchStatus = StringUtils.getString(obj.get("ZLKGZT")); - pcsData.setDcSwitchStatus(SwitchStatus.CLOSED.getCode()); - String controlMode = StringUtils.getString(obj.get("YCTT")); - pcsData.setRemoteControlStatus(ControlModeStatus.REMOTE.getCode()); - - // 电流参数 - pcsData.setSysUCurrent(StringUtils.getBigDecimal(obj.get("XTSCUXDL"))); - pcsData.setSysVCurrent(StringUtils.getBigDecimal(obj.get("XTSCVXDL"))); - pcsData.setSysWCurrent(StringUtils.getBigDecimal(obj.get("XTSCWXDL"))); - - // 直流参数 -// pcsData.setDcVoltage(StringUtils.getBigDecimal(obj.get("ChargeableCapacity"))); -// pcsData.setDcCurrent(StringUtils.getBigDecimal(obj.get("ChargeableCapacity"))); - - // 三相温度 - pcsData.setuTemperature(StringUtils.getBigDecimal(obj.get("DY1UXIGBTWD"))); - pcsData.setvTemperature(StringUtils.getBigDecimal(obj.get("DY1VXIGBTWD"))); - pcsData.setwTemperature(StringUtils.getBigDecimal(obj.get("DY1WXIGBTWD"))); - - // 时间与状态类字段 - pcsData.setDataUpdateTime(dataUpdateTime); - pcsData.setWorkStatus(WorkStatus.NORMAL.getCode()); - pcsData.setGridStatus(GridStatus.GRID.getCode()); - pcsData.setDeviceStatus(DeviceRunningStatus.ONLINE.getCode()); - pcsData.setControlMode(ControlModeStatus.REMOTE.getCode()); - - // 系统管理字段 - pcsData.setCreateBy("system"); - pcsData.setCreateTime(DateUtils.getNowDate()); - pcsData.setUpdateBy("system"); - pcsData.setUpdateTime(DateUtils.getNowDate()); - pcsData.setSiteId(SITE_ID); - pcsData.setDeviceId(deviceId); - pcsData.setDateMonth(DateUtils.getNowMonthLong()); - pcsData.setDateDay(DateUtils.getNowDayLong()); - - emsPcsDataMapper.insertEmsPcsData(pcsData); - redisCache.setCacheObject(RedisKeyConstants.PCS + SITE_ID + "_" +deviceId, pcsData); - - } - - private void pcsBranchDataProcess(String deviceId, String dataJson) { - - Map> records = processDataPrefix(JSON.parseObject(dataJson, new TypeReference>() {})); - List list = new ArrayList<>(); - - //PCS支路 - for (Map.Entry> record : records.entrySet()) { - String recordId = record.getKey(); - Map fields = record.getValue(); - - EmsPcsBranchData data = new EmsPcsBranchData(); - data.setDeviceId(deviceId); - data.setSiteId(SITE_ID); - data.setGridStatus(GridStatus.GRID.getCode()); - data.setDcPower(StringUtils.getBigDecimal(fields.get("ZLGL"))); - data.setDcVoltage(StringUtils.getBigDecimal(fields.get("ZLDY"))); - data.setDcCurrent(StringUtils.getBigDecimal(fields.get("ZLDL"))); - data.setGridUVoltage(StringUtils.getBigDecimal(fields.get("DWUXDY"))); - data.setGridVVoltage(StringUtils.getBigDecimal(fields.get("DWVXDY"))); - data.setGridWVoltage(StringUtils.getBigDecimal(fields.get("DWWXDY"))); - data.setOutputUCurrent(StringUtils.getBigDecimal(fields.get("SCUXDL"))); - data.setOutputVCurrent(StringUtils.getBigDecimal(fields.get("SCVXDL"))); - data.setOutputWCurrent(StringUtils.getBigDecimal(fields.get("SCWXDL"))); - data.setApparentPower(StringUtils.getBigDecimal(fields.get("SZGL"))); - data.setActivePower(StringUtils.getBigDecimal(fields.get("YGGL"))); - data.setReactivePower(StringUtils.getBigDecimal(fields.get("WGGL"))); - data.setPowerFactor(StringUtils.getBigDecimal(fields.get("GLYS"))); - data.setFrequency(StringUtils.getBigDecimal(fields.get("PL"))); - data.setInternalTemp(StringUtils.getBigDecimal(fields.get("DY1WD"))); - data.setuIgbtTemp(StringUtils.getBigDecimal(fields.get("UXIGBTWD"))); - data.setvIgbtTemp(StringUtils.getBigDecimal(fields.get("VXIGBTWD"))); - data.setwIgbtTemp(StringUtils.getBigDecimal(fields.get("WXIGBTWD"))); - data.setAvailablePower(StringUtils.getBigDecimal(fields.get("KYGL"))); - data.setTotalLoadRatio(StringUtils.getBigDecimal(fields.get("ZFZB"))); - data.setAcLeakageCurrent(StringUtils.getBigDecimal(fields.get("JLLDL"))); - data.setInsulationResistance(StringUtils.getBigDecimal(fields.get("JYZK"))); - data.setBranchId(recordId); - data.setCreateBy("system"); - data.setCreateTime(DateUtils.getNowDate()); - data.setUpdateBy("system"); - data.setUpdateTime(DateUtils.getNowDate()); - list.add(data); - } - if (list.size() > 0 ) { - emsPcsBranchDataMapper.insertPcsBranchDataList(list); - - redisCache.setCacheObject(RedisKeyConstants.BRANCH + SITE_ID + "_" +deviceId, list); - - } - - } - - private void loadDataProcess(String deviceId, String dataJson, Date dataUpdateTime) { - - //总表 - Map obj = JSON.parseObject(dataJson, new TypeReference>() { - }); - - EmsAmmeterData dataLoad = new EmsAmmeterData(); - // 更新时间 - dataLoad.setDataUpdateTime(dataUpdateTime); - - // 电能设置-组合有功 - dataLoad.setCurrentCombActiveTotal(StringUtils.getBigDecimal(obj.get("DQZHYGZDN"))); - dataLoad.setCurrentCombActivePeak(StringUtils.getBigDecimal(obj.get("DQZHYGJDN"))); - dataLoad.setCurrentCombActiveHigh(StringUtils.getBigDecimal(obj.get("DQZHYGFDN"))); - dataLoad.setCurrentCombActiveFlat(StringUtils.getBigDecimal(obj.get("DQZHYGPDN"))); - dataLoad.setCurrentCombActiveValley(StringUtils.getBigDecimal(obj.get("DQZHYGGDN"))); - // 电能设置-正向有功 - dataLoad.setCurrentForwardActiveTotal(StringUtils.getBigDecimal(obj.get("DQZXYGZDN"))); - dataLoad.setCurrentForwardActivePeak(StringUtils.getBigDecimal(obj.get("DQZXYGJDN"))); - dataLoad.setCurrentForwardActiveHigh(StringUtils.getBigDecimal(obj.get("DQZXYGFDN"))); - dataLoad.setCurrentForwardActiveFlat(StringUtils.getBigDecimal(obj.get("DQZXYGPDN"))); - dataLoad.setCurrentForwardActiveValley(StringUtils.getBigDecimal(obj.get("DQZXYGGDN"))); - // 电能设置-反向有功 - dataLoad.setCurrentReverseActiveTotal(StringUtils.getBigDecimal(obj.get("DQFXYGZDN"))); - dataLoad.setCurrentReverseActivePeak(StringUtils.getBigDecimal(obj.get("DQFXYGJDN"))); - dataLoad.setCurrentReverseActiveHigh(StringUtils.getBigDecimal(obj.get("DQFXYGFDN"))); - dataLoad.setCurrentReverseActiveFlat(StringUtils.getBigDecimal(obj.get("DQFXYGPDN"))); - dataLoad.setCurrentReverseActiveValley(StringUtils.getBigDecimal(obj.get("DQFXYGGDN"))); - // 电能设置-组合无功 - dataLoad.setCurrentCombReactiveTotal(StringUtils.getBigDecimal(obj.get("DQZHWGZDN"))); - dataLoad.setCurrentCombReactivePeak(StringUtils.getBigDecimal(obj.get("DQZHWGJDN"))); - dataLoad.setCurrentCombReactiveHigh(StringUtils.getBigDecimal(obj.get("DQZHWGFDN"))); - dataLoad.setCurrentCombReactiveFlat(StringUtils.getBigDecimal(obj.get("DQZHWGPDN"))); - dataLoad.setCurrentCombReactiveValley(StringUtils.getBigDecimal(obj.get("DQZHWGGDN"))); - // 电能设置-正向无功 - dataLoad.setCurrentForwardReactiveTotal(StringUtils.getBigDecimal(obj.get("DQZXWGZDN"))); - dataLoad.setCurrentForwardReactivePeak(StringUtils.getBigDecimal(obj.get("DQZXWGJDN"))); - dataLoad.setCurrentForwardReactiveHigh(StringUtils.getBigDecimal(obj.get("DQZXWGFDN"))); - dataLoad.setCurrentForwardReactiveFlat(StringUtils.getBigDecimal(obj.get("DQZXWGPDN"))); - dataLoad.setCurrentForwardReactiveValley(StringUtils.getBigDecimal(obj.get("DQZXWGGDN"))); - // 电能设置-反向无功 - dataLoad.setCurrentReverseReactiveTotal(StringUtils.getBigDecimal(obj.get("DQFXWGZDN"))); - dataLoad.setCurrentReverseReactivePeak(StringUtils.getBigDecimal(obj.get("DQFXWGJDN"))); - dataLoad.setCurrentReverseReactiveHigh(StringUtils.getBigDecimal(obj.get("DQFXWGFDN"))); - dataLoad.setCurrentReverseReactiveFlat(StringUtils.getBigDecimal(obj.get("DQFXWGPDN"))); - dataLoad.setCurrentReverseReactiveValley(StringUtils.getBigDecimal(obj.get("DQFXWGGDN"))); - - // 电压+电流 - dataLoad.setPhaseAVoltage(StringUtils.getBigDecimal(obj.get("AXDY"))); - dataLoad.setPhaseBVoltage(StringUtils.getBigDecimal(obj.get("BXDY"))); - dataLoad.setPhaseCVoltage(StringUtils.getBigDecimal(obj.get("CXDY"))); - dataLoad.setPhaseACurrent(StringUtils.getBigDecimal(obj.get("AXDL"))); - dataLoad.setPhaseBCurrent(StringUtils.getBigDecimal(obj.get("BXDL"))); - dataLoad.setPhaseCCurrent(StringUtils.getBigDecimal(obj.get("CXDL"))); - - dataLoad.setAbLineVoltage(StringUtils.getBigDecimal(obj.get("ABXDY"))); - dataLoad.setCbLineVoltage(StringUtils.getBigDecimal(obj.get("CBXDY"))); - dataLoad.setAcLineVoltage(StringUtils.getBigDecimal(obj.get("ACXDY"))); - - // 频率 - dataLoad.setFrequency(StringUtils.getBigDecimal(obj.get("PL"))); - - // 功率 有功+总+无功+无总+视在 - dataLoad.setPhaseAActivePower(StringUtils.getBigDecimal(obj.get("AXYGGL"))); - dataLoad.setPhaseBActivePower(StringUtils.getBigDecimal(obj.get("BXYGGL"))); - dataLoad.setPhaseCActivePower(StringUtils.getBigDecimal(obj.get("CXYGGL"))); - dataLoad.setTotalActivePower(StringUtils.getBigDecimal(obj.get("ZYGGL"))); - dataLoad.setPhaseAReactivePower(StringUtils.getBigDecimal(obj.get("AXWGGL"))); - dataLoad.setPhaseBReactivePower(StringUtils.getBigDecimal(obj.get("BXWGGL"))); - dataLoad.setPhaseCReactivePower(StringUtils.getBigDecimal(obj.get("CXWGGL"))); - dataLoad.setTotalReactivePower(StringUtils.getBigDecimal(obj.get("ZWGGL"))); - dataLoad.setPhaseAApparentPower(StringUtils.getBigDecimal(obj.get("AXSZGL"))); - dataLoad.setPhaseBApparentPower(StringUtils.getBigDecimal(obj.get("BXSZGL"))); - dataLoad.setPhaseCApparentPower(StringUtils.getBigDecimal(obj.get("CXSZGL"))); - dataLoad.setTotalApparentPower(StringUtils.getBigDecimal(obj.get("ZSZGL"))); - - // 功率因数 - dataLoad.setPhaseAPowerFactor(StringUtils.getBigDecimal(obj.get("AXGLYS"))); - dataLoad.setPhaseBPowerFactor(StringUtils.getBigDecimal(obj.get("BXGLYS"))); - dataLoad.setPhaseCPowerFactor(StringUtils.getBigDecimal(obj.get("CXGLYS"))); - dataLoad.setTotalPowerFactor(StringUtils.getBigDecimal(obj.get("ZGLYS"))); - - // 需量 - dataLoad.setForwardAcMaxDemand(StringUtils.getBigDecimal(obj.get("ZXYGZDXL"))); - dataLoad.setReverseAcMaxDemand(StringUtils.getBigDecimal(obj.get("FXYGZDXL"))); - dataLoad.setDailyForwardMaxDemand(StringUtils.getBigDecimal(obj.get("DRZXYGZDXL"))); - - dataLoad.setCreateBy("system"); - dataLoad.setCreateTime(DateUtils.getNowDate()); - dataLoad.setUpdateBy("system"); - dataLoad.setUpdateTime(DateUtils.getNowDate()); - dataLoad.setSiteId(SITE_ID); - dataLoad.setDeviceId(deviceId); - - emsAmmeterDataMapper.insertEmsAmmeterData(dataLoad); - - redisCache.setCacheObject(RedisKeyConstants.AMMETER + SITE_ID + "_" +deviceId, dataLoad); - - } - - private void dealFXXDailyChargeDate(String deviceId, String dataJson) { - log.info("start dealFXXDailyChargeDate"); - //日充放电数据 - Map obj = JSON.parseObject(dataJson, new TypeReference>() { - }); - - // 初始化当日数据 - EmsDailyChargeData emsDailyChargeData = new EmsDailyChargeData(); - emsDailyChargeData.setSiteId(SITE_ID); - emsDailyChargeData.setDeviceId(deviceId); - emsDailyChargeData.setDateTime(DateUtils.getNowDate()); - emsDailyChargeData.setTotalChargeData(StringUtils.getBigDecimal(obj.get("ZCDL"))); - emsDailyChargeData.setTotalDischargeData(StringUtils.getBigDecimal(obj.get("ZFDL"))); - emsDailyChargeData.setChargeData(StringUtils.getBigDecimal(obj.get("RCDL"))); - emsDailyChargeData.setDischargeData(StringUtils.getBigDecimal(obj.get("RFDL"))); - emsDailyChargeData.setCreateBy("system"); - emsDailyChargeData.setCreateTime(DateUtils.getNowDate()); - emsDailyChargeData.setUpdateBy("system"); - emsDailyChargeData.setUpdateTime(DateUtils.getNowDate()); - // 插入或更新每日充放电数据表 - emsDailyChargeDataMapper.insertOrUpdateData(emsDailyChargeData); - log.info("end dealFXXDailyChargeDate"); - } - - private void meteDataProcess(String deviceId, String dataJson, Date dataUpdateTime) { - - //总表 - Map obj = JSON.parseObject(dataJson, new TypeReference>() { - }); - - // 获取上次数据,便于后面计算差值均无则默认0 - EmsAmmeterData lastAmmeterData = getLastAmmeterData(deviceId); - - EmsAmmeterData dataLoad = new EmsAmmeterData(); - // 更新时间 - dataLoad.setDataUpdateTime(dataUpdateTime); - // 电压+电流 - dataLoad.setPhaseAVoltage(StringUtils.getBigDecimal(obj.get("AXDY"))); - dataLoad.setPhaseBVoltage(StringUtils.getBigDecimal(obj.get("BXDY"))); - dataLoad.setPhaseCVoltage(StringUtils.getBigDecimal(obj.get("CXDY"))); - dataLoad.setPhaseACurrent(StringUtils.getBigDecimal(obj.get("AXDL"))); - dataLoad.setPhaseBCurrent(StringUtils.getBigDecimal(obj.get("BXDL"))); - dataLoad.setPhaseCCurrent(StringUtils.getBigDecimal(obj.get("CXDL"))); - - dataLoad.setAbLineVoltage(StringUtils.getBigDecimal(obj.get("ABXDY"))); - dataLoad.setCbLineVoltage(StringUtils.getBigDecimal(obj.get("BCXDY"))); - dataLoad.setAcLineVoltage(StringUtils.getBigDecimal(obj.get("CAXDY"))); - - // 频率 - dataLoad.setFrequency(StringUtils.getBigDecimal(obj.get("DWPL"))); - - // 功率 - dataLoad.setPhaseAActivePower(StringUtils.getBigDecimal(obj.get("AXYGGL"))); - dataLoad.setPhaseBActivePower(StringUtils.getBigDecimal(obj.get("BXYGGL"))); - dataLoad.setPhaseCActivePower(StringUtils.getBigDecimal(obj.get("CXYGGL"))); - dataLoad.setTotalActivePower(StringUtils.getBigDecimal(obj.get("ZYGGL"))); - dataLoad.setPhaseAReactivePower(StringUtils.getBigDecimal(obj.get("AXWGGL"))); - dataLoad.setPhaseBReactivePower(StringUtils.getBigDecimal(obj.get("BXWGGL"))); - dataLoad.setPhaseCReactivePower(StringUtils.getBigDecimal(obj.get("CXWGGL"))); - dataLoad.setTotalReactivePower(StringUtils.getBigDecimal(obj.get("ZWGGL"))); - - dataLoad.setTotalApparentPower(StringUtils.getBigDecimal(obj.get("ZSZGL"))); - dataLoad.setTotalPowerFactor(StringUtils.getBigDecimal(obj.get("ZGLYS"))); - - // 二次相关数据 - dataLoad.setSecondaryAbLineVoltage(StringUtils.getBigDecimal(obj.get("ECABXDY"))); - dataLoad.setSecondaryAPhaseCurrent(StringUtils.getBigDecimal(obj.get("ECAXDL"))); - dataLoad.setSecondaryAPhaseVoltage(StringUtils.getBigDecimal(obj.get("ECAXDY"))); - dataLoad.setSecondaryAPowerFactor(StringUtils.getBigDecimal(obj.get("ECAXGLYS"))); - dataLoad.setSecondaryAApparentPower(StringUtils.getBigDecimal(obj.get("ECAXSZGL"))); - dataLoad.setSecondaryAReactivePower(StringUtils.getBigDecimal(obj.get("ECAXWGGL"))); - dataLoad.setSecondaryAActivePower(StringUtils.getBigDecimal(obj.get("ECAXYGGL"))); - dataLoad.setSecondaryBcLineVoltage(StringUtils.getBigDecimal(obj.get("ECBCXDY"))); - dataLoad.setSecondaryBPhaseCurrent(StringUtils.getBigDecimal(obj.get("ECBXDL"))); - dataLoad.setSecondaryBPhaseVoltage(StringUtils.getBigDecimal(obj.get("ECBXDY"))); - dataLoad.setSecondaryBPowerFactor(StringUtils.getBigDecimal(obj.get("ECBXGLYS"))); - dataLoad.setSecondaryBApparentPower(StringUtils.getBigDecimal(obj.get("ECBXSZGL"))); - dataLoad.setSecondaryBReactivePower(StringUtils.getBigDecimal(obj.get("ECBXWGGL"))); - dataLoad.setSecondaryBActivePower(StringUtils.getBigDecimal(obj.get("ECBXYGGL"))); - dataLoad.setSecondaryCaLineVoltage(StringUtils.getBigDecimal(obj.get("ECCAXDY"))); - dataLoad.setSecondaryCPhaseCurrent(StringUtils.getBigDecimal(obj.get("ECCXDL"))); - dataLoad.setSecondaryCPhaseVoltage(StringUtils.getBigDecimal(obj.get("ECCXDY"))); - dataLoad.setSecondaryCPowerFactor(StringUtils.getBigDecimal(obj.get("ECCXGLYS"))); - dataLoad.setSecondaryCApparentPower(StringUtils.getBigDecimal(obj.get("ECCXSZGL"))); - dataLoad.setSecondaryCReactivePower(StringUtils.getBigDecimal(obj.get("ECCXWGGL"))); - dataLoad.setSecondaryCActivePower(StringUtils.getBigDecimal(obj.get("ECCXYGGL"))); - dataLoad.setSecondaryGridFrequency(StringUtils.getBigDecimal(obj.get("ECDWPL"))); - dataLoad.setSecondaryReverseReactiveEnergy(StringUtils.getBigDecimal(obj.get("ECFXWGDN"))); - dataLoad.setSecondaryNegativeActiveEnergy(StringUtils.getBigDecimal(obj.get("ECFXYGDN"))); - dataLoad.setSecondaryTotalPowerFactor(StringUtils.getBigDecimal(obj.get("ECZGLYS"))); - dataLoad.setSecondaryTotalApparentPower(StringUtils.getBigDecimal(obj.get("ECZSZFL"))); - dataLoad.setSecondaryTotalReactivePower(StringUtils.getBigDecimal(obj.get("ECZWGGL"))); - dataLoad.setSecondaryPositiveReactiveEnergy(StringUtils.getBigDecimal(obj.get("ECZXWGDN"))); - dataLoad.setSecondaryPositiveActiveEnergy(StringUtils.getBigDecimal(obj.get("ECZXYGDN"))); - dataLoad.setSecondaryTotalActivePower(StringUtils.getBigDecimal(obj.get("ECZYGGL"))); - - // 需量 - dataLoad.setReverseReactiveEnergyEqMinus(StringUtils.getBigDecimal(obj.get("FXWGDN"))); - dataLoad.setReverseActiveEnergyEpMinus(StringUtils.getBigDecimal(obj.get("FXYGDN"))); - dataLoad.setPositiveReactiveEnergyEqPlus(StringUtils.getBigDecimal(obj.get("ZXWGDN"))); - dataLoad.setPositiveActiveEnergyEpPlus(StringUtils.getBigDecimal(obj.get("ZXYGDN"))); - - // 正反向有功无功电能 - dataLoad.setCurrentForwardActiveTotal(StringUtils.getBigDecimal(obj.get("ZXYGDN"))); - dataLoad.setCurrentReverseActiveTotal(StringUtils.getBigDecimal(obj.get("FXYGDN"))); - dataLoad.setCurrentForwardReactiveTotal(StringUtils.getBigDecimal(obj.get("ZXWGDN"))); - dataLoad.setCurrentReverseReactiveTotal(StringUtils.getBigDecimal(obj.get("FXWGDN"))); - - dataLoad.setCreateBy("system"); - dataLoad.setCreateTime(DateUtils.getNowDate()); - dataLoad.setUpdateBy("system"); - dataLoad.setUpdateTime(DateUtils.getNowDate()); - dataLoad.setSiteId(SITE_ID); - dataLoad.setDeviceId(deviceId); - - emsAmmeterDataMapper.insertEmsAmmeterData(dataLoad); - - redisCache.setCacheObject(RedisKeyConstants.AMMETER + SITE_ID + "_" +deviceId, dataLoad); - - // 处理电表每日充放电数据 - dealAmmeterDailyDate(obj, dataUpdateTime, lastAmmeterData); - } - - private EmsAmmeterData getLastAmmeterData(String deviceId) { - // 先从redis取,取不到查数据 - EmsAmmeterData lastData = redisCache.getCacheObject(RedisKeyConstants.AMMETER + SITE_ID + "_" +deviceId); - if (lastData == null) { - lastData = emsAmmeterDataMapper.getLastData(SITE_ID,deviceId); - if (lastData == null) { - lastData = new EmsAmmeterData(); - lastData.setSiteId(SITE_ID); - lastData.setDeviceId(deviceId); - lastData.setCurrentForwardActiveTotal(BigDecimal.ZERO); - lastData.setCurrentReverseActiveTotal(BigDecimal.ZERO); - } - } - return lastData; - } - - private void dealAmmeterDailyDate(Map obj, Date dataUpdateTime, EmsAmmeterData lastData) { - // 先获取当月电价配置,redis没有这查数据库,都没有则返回 - String priceKey = RedisKeyConstants.ENERGY_PRICE_TIME + SITE_ID + "_" + LocalDate.now().getYear() + LocalDate.now().getMonthValue(); - EnergyPriceVo priceVo = redisCache.getCacheObject(priceKey); - if (priceVo == null) { - priceVo = emsEnergyPriceConfigService.getCurrentMonthPrice(SITE_ID); - redisCache.setCacheObject(priceKey, priceVo, 31, TimeUnit.DAYS); - if (priceVo == null) { - return; - } - } - List timeRanges = priceVo.getRange(); - if (timeRanges == null) { - return; - } - - // 根据时间范围判断数据类型(尖峰平谷),无法确定数据类型则不处理 - String costType = ""; - String startTime = ""; - for (EnergyPriceTimeRange timeRange : timeRanges) { - startTime = timeRange.getStartTime(); - if (isInPriceTimeRange(startTime, timeRange.getEndTime(), dataUpdateTime)) { - costType = timeRange.getCostType(); - break; - } - } - if (StringUtils.isEmpty(costType)) { - return; - } - - //初始化电表每日差值对象 - EmsDailyEnergyData energyData = initEnergyData(); - - // 根据 costType,计算本次与上次数据差值,累加到对应的数据类型里面 - setDiffByCostType(costType,energyData,lastData,obj,priceVo); - - // 插入或更新电表每日差值数据表 - emsDailyEnergyDataMapper.insertOrUpdateData(energyData); - } - - private void setDiffByCostType(String costType, EmsDailyEnergyData energyData, EmsAmmeterData lastData, - Map obj, EnergyPriceVo priceVo) { - BigDecimal currentChargeData = StringUtils.getBigDecimal(obj.get("ZXYGDN")); - BigDecimal currentDischargeData = StringUtils.getBigDecimal(obj.get("FXYGDN")); - currentChargeData = currentChargeData != null ? currentChargeData : BigDecimal.ZERO; - currentDischargeData = currentDischargeData != null ? currentDischargeData : BigDecimal.ZERO; - - // 获取上次实时总收益+当日实时总收益,初始化电价 - Map revenueMap = getRealTimeData(SITE_ID); - BigDecimal totalRevenue = revenueMap.get("totalRevenue") == null ? BigDecimal.ZERO : revenueMap.get("totalRevenue"); - BigDecimal dayRevenue = revenueMap.get("dayRevenue") == null ? BigDecimal.ZERO : revenueMap.get("dayRevenue"); - BigDecimal price = BigDecimal.ZERO; - // 计算时段差值,按照数据类型累加 - // 计算当日累加收益,尖峰平谷收益在当日原基础累加,(放电量-充电量)*电价 - BigDecimal chargeDiffData = currentChargeData.subtract( - lastData.getCurrentForwardActiveTotal() == null ? BigDecimal.ZERO : lastData.getCurrentForwardActiveTotal()); - BigDecimal disChargeDiffData = currentDischargeData.subtract( - lastData.getCurrentReverseActiveTotal() == null ? BigDecimal.ZERO : lastData.getCurrentReverseActiveTotal() - ); - switch (costType) { - case "peak": - // 增加电量 - BigDecimal peakCharge = energyData.getPeakChargeDiff() == null ? BigDecimal.ZERO : energyData.getPeakChargeDiff(); - energyData.setPeakChargeDiff(peakCharge.add(chargeDiffData)); - BigDecimal peakDischarge = energyData.getPeakDischargeDiff() == null ? BigDecimal.ZERO : energyData.getPeakDischargeDiff(); - energyData.setPeakDischargeDiff(peakDischarge.add(disChargeDiffData)); - - // 电价 - price = priceVo.getPeak() == null ? BigDecimal.ZERO : priceVo.getPeak(); - break; - case "high": - // 增加电量 - BigDecimal highCharge = energyData.getHighChargeDiff() == null ? BigDecimal.ZERO : energyData.getHighChargeDiff(); - energyData.setHighChargeDiff(highCharge.add(chargeDiffData)); - BigDecimal highDischarge = energyData.getHighDischargeDiff() == null ? BigDecimal.ZERO : energyData.getHighDischargeDiff(); - energyData.setHighDischargeDiff(highDischarge.add(disChargeDiffData)); - - // 电价 - price = priceVo.getHigh() == null ? BigDecimal.ZERO : priceVo.getHigh(); - break; - case "flat": - // 增加电量 - BigDecimal flatCharge = energyData.getFlatChargeDiff() == null ? BigDecimal.ZERO : energyData.getFlatChargeDiff(); - energyData.setFlatChargeDiff(flatCharge.add(chargeDiffData)); - BigDecimal flatDischarge = energyData.getFlatDischargeDiff() == null ? BigDecimal.ZERO : energyData.getFlatDischargeDiff(); - energyData.setFlatDischargeDiff(flatDischarge.add(disChargeDiffData)); - - // 电价 - price = priceVo.getFlat() == null ? BigDecimal.ZERO : priceVo.getFlat(); - break; - case "valley": - // 增加电量 - BigDecimal valleyCharge = energyData.getValleyChargeDiff() == null ? BigDecimal.ZERO : energyData.getValleyChargeDiff(); - energyData.setValleyChargeDiff(valleyCharge.add(chargeDiffData)); - BigDecimal valleyDischarge = energyData.getValleyDischargeDiff() == null ? BigDecimal.ZERO : energyData.getValleyDischargeDiff(); - energyData.setValleyDischargeDiff(valleyDischarge.add(disChargeDiffData)); - - // 电价 - price = priceVo.getValley() == null ? BigDecimal.ZERO : priceVo.getValley(); - break; - default: - return; - } - - // 计算本次累加收益 - BigDecimal addRevenue = disChargeDiffData.subtract(chargeDiffData).multiply(price); - dayRevenue = dayRevenue.add(addRevenue); - energyData.setDayRevenue(dayRevenue); - // 总收益 = 上次实时总收益+今日实时增加的收益 - totalRevenue = totalRevenue.add(addRevenue); - energyData.setTotalRevenue(totalRevenue); - - // 存redis便于下次取用 - String today = DateUtils.getDate(); - String redisKey = RedisKeyConstants.FXX_REALTIME_REVENUE + SITE_ID + "_" + today; - Map realTimeRevenue = new HashMap<>(); - realTimeRevenue.put("totalRevenue", totalRevenue); - realTimeRevenue.put("dayRevenue",dayRevenue); - redisCache.setCacheObject(redisKey, realTimeRevenue, 1, TimeUnit.DAYS); - } - - private Map getRealTimeData(String siteId) { - // fx取实时总收益和当天实时收益 - String today = DateUtils.getDate(); - String redisKey = RedisKeyConstants.FXX_REALTIME_REVENUE + siteId + "_" + today; - Map realTimeRevenue = redisCache.getCacheObject(redisKey); - if (realTimeRevenue == null) { - // 查数据库 - realTimeRevenue = iEmsEnergyPriceConfigService.getDayRevenueMap(SITE_ID); - if (realTimeRevenue == null) { - realTimeRevenue = new HashMap<>(); - realTimeRevenue.put("totalRevenue", BigDecimal.ZERO); - realTimeRevenue.put("dayRevenue", BigDecimal.ZERO); - } - redisCache.setCacheObject(redisKey, realTimeRevenue, 1, TimeUnit.DAYS); - } - return realTimeRevenue; - } - - private boolean isInPriceTimeRange(String startTime, String endTime, Date dataUpdateTime) { - if (startTime == null || endTime == null || dataUpdateTime == null) { - return false; - } - LocalDateTime time = DateUtils.toLocalDateTime(dataUpdateTime); - DateTimeFormatter formatter = DateTimeFormatter.ofPattern("HH:mm"); - String dataTimeStr = time.format(formatter); - // 比较时间范围 - return dataTimeStr.compareTo(startTime) >= 0 - && dataTimeStr.compareTo(endTime) < 0; - } - - private EmsDailyEnergyData initEnergyData() { - // 先获取数据库当天数据,存在则更新时间,不存在则初始化 - EmsDailyEnergyData energyData = emsDailyEnergyDataMapper.getDataByDate(SITE_ID,DateUtils.getDate()); - if (energyData == null) { - energyData = new EmsDailyEnergyData(); - energyData.setSiteId(SITE_ID); - energyData.setDataDate(DateUtils.getNowDate()); - energyData.setCreateBy("system"); - energyData.setCreateTime(DateUtils.getNowDate()); - } - energyData.setUpdateBy("system"); - energyData.setCalcTime(DateUtils.getNowDate()); - return energyData; - } - - // 数据分组处理 - private static Map> processData(Map rawData) { - Map> records = new HashMap<>(); - - for (Map.Entry entry : rawData.entrySet()) { - String key = entry.getKey(); - // 提取记录ID(最后3位) - String recordId = key.substring(key.length() - 3); - try { - Long.parseLong(recordId); - } catch (Exception e) { - continue; - } - - // 提取字段类型(前缀) - String fieldType = key.substring(0, key.length() - 3); - - // 初始化记录 - records.putIfAbsent(recordId, new HashMap<>()); - // 存入字段值 - records.get(recordId).put(fieldType, entry.getValue()); - } - return records; - } - - private static Map> processDataPrefix(Map rawData) { - Map> records = new HashMap<>(); - - for (Map.Entry entry : rawData.entrySet()) { - String key = entry.getKey(); - // 确保键长度足够 - if (key.length() < 3) { - continue; - } - - // 提取记录ID(前3位) - String recordId = key.substring(0, 3); - if (!recordId.startsWith("DY")) { - continue; - } - - // 提取字段类型(剩余部分) - String fieldType = key.substring(3); - - // 初始化记录 - records.putIfAbsent(recordId, new HashMap<>()); - // 存入字段值 - records.get(recordId).put(fieldType, entry.getValue()); - } - return records; - } - - @Override - public void processBatch(List batchData) { - super.processBatch(batchData); - } - - // 空数据不处理 - private boolean checkJsonDataEmpty(String jsonData) { - boolean flag = false; - try { - if (StringUtils.isEmpty(jsonData)) { - flag = true; - } - JsonNode jsonNode = objectMapper.readTree(jsonData); - // 判断是否为空对象({}) - if (jsonNode.isObject() && jsonNode.isEmpty()) { - flag = true ; - } - } catch (JsonProcessingException e) { - throw new RuntimeException(e); - } - return flag; - } -} diff --git a/ems-system/src/main/java/com/xzzn/ems/service/impl/GeneralQueryServiceImpl.java b/ems-system/src/main/java/com/xzzn/ems/service/impl/GeneralQueryServiceImpl.java index 990be5c..07a28ea 100644 --- a/ems-system/src/main/java/com/xzzn/ems/service/impl/GeneralQueryServiceImpl.java +++ b/ems-system/src/main/java/com/xzzn/ems/service/impl/GeneralQueryServiceImpl.java @@ -477,7 +477,8 @@ public class GeneralQueryServiceImpl implements IGeneralQueryService // 4. 构建DeviceItem return new DevicePointDataList(deviceId, pointValueList,parentDeviceId, - stats.max, stats.min,stats.avg,stats.diff,stats.maxDate,stats.minDate); + stats.max, stats.min,stats.avg,stats.diff,stats.maxDate,stats.minDate, + stats.q1, stats.median, stats.q3); })// 关键排序步骤:先按deviceId升序,再按parentDeviceId升序 .sorted( Comparator.comparing(DevicePointDataList::getDeviceId) // 第一排序键:deviceId @@ -513,7 +514,8 @@ public class GeneralQueryServiceImpl implements IGeneralQueryService Stats stats = clacStats(deviceDataList); return new DevicePointDataList(deviceId, deviceDataList,null, - stats.max, stats.min,stats.avg,stats.diff,stats.maxDate,stats.minDate); + stats.max, stats.min,stats.avg,stats.diff,stats.maxDate,stats.minDate, + stats.q1, stats.median, stats.q3); }) .collect(Collectors.toList()); @@ -536,7 +538,7 @@ public class GeneralQueryServiceImpl implements IGeneralQueryService .collect(Collectors.toList()); if (validPairs.isEmpty()) { - return new Stats(null, null, null, null, null, null); + return new Stats(null, null, null, null, null, null, null, null, null); } // 计算最大最小值 Optional maxPair = validPairs.stream().max((p1, p2) -> p1.value.compareTo(p2.value)); @@ -546,8 +548,17 @@ public class GeneralQueryServiceImpl implements IGeneralQueryService BigDecimal avgValue = sum.divide(BigDecimal.valueOf(validPairs.size()), 4, BigDecimal.ROUND_HALF_UP); // 增量数据,计算差值 BigDecimal diff = maxPair.get().value.subtract(minPair.get().value); + // 计算分位数统计值 + List sortedValues = validPairs.stream() + .map(pair -> pair.value) + .sorted() + .collect(Collectors.toList()); + BoxPlotData boxStats = calculateBoxPlotData(sortedValues); - return new Stats(maxPair.get().value,minPair.get().value,avgValue,diff,maxPair.get().time,minPair.get().time); + return new Stats(maxPair.get().value,minPair.get().value,avgValue,diff,maxPair.get().time,minPair.get().time, + boxStats == null ? null : boxStats.q1, + boxStats == null ? null : boxStats.median, + boxStats == null ? null : boxStats.q3); } private BigDecimal convertToBigDecimal(Object pointValue) { @@ -800,15 +811,22 @@ public class GeneralQueryServiceImpl implements IGeneralQueryService private final String minDate; private final BigDecimal avg; private final BigDecimal diff; + private final BigDecimal q1; + private final BigDecimal median; + private final BigDecimal q3; public Stats(BigDecimal max, BigDecimal min, BigDecimal avg, BigDecimal diff, - String maxDate, String minDate) { + String maxDate, String minDate, + BigDecimal q1, BigDecimal median, BigDecimal q3) { this.max = max; this.maxDate = maxDate; this.min = min; this.minDate = minDate; this.avg = avg; this.diff = diff; + this.q1 = q1; + this.median = median; + this.q3 = q3; } } diff --git a/ems-system/src/main/resources/mapper/ems/EmsBatteryStackMapper.xml b/ems-system/src/main/resources/mapper/ems/EmsBatteryStackMapper.xml index 3a3b74c..03fb24c 100644 --- a/ems-system/src/main/resources/mapper/ems/EmsBatteryStackMapper.xml +++ b/ems-system/src/main/resources/mapper/ems/EmsBatteryStackMapper.xml @@ -512,10 +512,16 @@ - \ No newline at end of file + diff --git a/ems-system/src/main/resources/mapper/ems/EmsDailyEnergyDataMapper.xml b/ems-system/src/main/resources/mapper/ems/EmsDailyEnergyDataMapper.xml index 3b34ab5..fe40a83 100644 --- a/ems-system/src/main/resources/mapper/ems/EmsDailyEnergyDataMapper.xml +++ b/ems-system/src/main/resources/mapper/ems/EmsDailyEnergyDataMapper.xml @@ -236,26 +236,40 @@ - \ No newline at end of file + diff --git a/ems-system/src/main/resources/mapper/ems/EmsPointConfigMapper.xml b/ems-system/src/main/resources/mapper/ems/EmsPointConfigMapper.xml index 741f34d..b4e3bd6 100644 --- a/ems-system/src/main/resources/mapper/ems/EmsPointConfigMapper.xml +++ b/ems-system/src/main/resources/mapper/ems/EmsPointConfigMapper.xml @@ -22,6 +22,12 @@ + + + + + + @@ -32,6 +38,7 @@ select id, point_id, site_id, device_category, device_id, point_name, data_key, point_desc, register_address, data_unit, data_a, data_k, data_b, data_bit, is_alarm, point_type, calc_expression, + collect_enabled, collect_source, modbus_register_type, modbus_data_type, modbus_read_order, modbus_group, create_by, create_time, update_by, update_time, remark from ems_point_config @@ -51,6 +58,10 @@ and data_key like concat('%', #{dataKey}, '%') and point_desc like concat('%', #{pointDesc}, '%') and point_type = #{pointType} + and collect_enabled = #{collectEnabled} + and collect_source = #{collectSource} + and modbus_register_type = #{modbusRegisterType} + and modbus_data_type = #{modbusDataType} and register_address = #{registerAddress} order by update_time desc, id desc @@ -75,6 +86,12 @@ is_alarm, point_type, calc_expression, + collect_enabled, + collect_source, + modbus_register_type, + modbus_data_type, + modbus_read_order, + modbus_group, create_by, create_time, update_by, @@ -98,6 +115,12 @@ #{isAlarm}, #{pointType}, #{calcExpression}, + #{collectEnabled}, + #{collectSource}, + #{modbusRegisterType}, + #{modbusDataType}, + #{modbusReadOrder}, + #{modbusGroup}, #{createBy}, #{createTime}, #{updateBy}, @@ -110,6 +133,7 @@ insert into ems_point_config ( point_id, site_id, device_category, device_id, point_name, data_key, point_desc, register_address, data_unit, data_a, data_k, data_b, data_bit, is_alarm, point_type, calc_expression, + collect_enabled, collect_source, modbus_register_type, modbus_data_type, modbus_read_order, modbus_group, create_by, create_time, update_by, update_time, remark ) values @@ -131,6 +155,12 @@ #{item.isAlarm}, #{item.pointType}, #{item.calcExpression}, + #{item.collectEnabled}, + #{item.collectSource}, + #{item.modbusRegisterType}, + #{item.modbusDataType}, + #{item.modbusReadOrder}, + #{item.modbusGroup}, #{item.createBy}, now(), #{item.updateBy}, @@ -159,6 +189,12 @@ is_alarm = #{isAlarm}, point_type = #{pointType}, calc_expression = #{calcExpression}, + collect_enabled = #{collectEnabled}, + collect_source = #{collectSource}, + modbus_register_type = #{modbusRegisterType}, + modbus_data_type = #{modbusDataType}, + modbus_read_order = #{modbusReadOrder}, + modbus_group = #{modbusGroup}, update_by = #{updateBy}, update_time = #{updateTime}, remark = #{remark}, @@ -192,11 +228,13 @@ insert into ems_point_config ( point_id, site_id, device_category, device_id, point_name, data_key, point_desc, register_address, data_unit, data_a, data_k, data_b, data_bit, is_alarm, point_type, calc_expression, + collect_enabled, collect_source, modbus_register_type, modbus_data_type, modbus_read_order, modbus_group, create_by, create_time, update_by, update_time, remark ) select concat('PT_', replace(uuid(), '-', '')), #{targetSiteId}, device_category, device_id, point_name, data_key, point_desc, register_address, data_unit, data_a, data_k, data_b, data_bit, is_alarm, point_type, calc_expression, + collect_enabled, collect_source, modbus_register_type, modbus_data_type, modbus_read_order, modbus_group, #{operName}, now(), #{operName}, now(), remark from ems_point_config where site_id = #{templateSiteId} @@ -287,4 +325,19 @@ + + diff --git a/ems-system/src/main/resources/mapper/ems/EmsSiteWeatherDayMapper.xml b/ems-system/src/main/resources/mapper/ems/EmsSiteWeatherDayMapper.xml new file mode 100644 index 0000000..93acc0f --- /dev/null +++ b/ems-system/src/main/resources/mapper/ems/EmsSiteWeatherDayMapper.xml @@ -0,0 +1,28 @@ + + + + + + update ems_site_weather_day + set weather_desc = #{weatherDesc}, + weather_code = #{weatherCode}, + update_time = now() + where site_id = #{siteId} + and calendar_date = #{calendarDate} + + + + + + insert into ems_site_weather_day(site_id, calendar_date, weather_desc, weather_code, source, create_time, update_time) + values (#{siteId}, #{calendarDate}, #{weatherDesc}, #{weatherCode}, #{source}, now(), now()) + + +