|
|
@@ -1,1190 +0,0 @@
|
|
|
-package com.ruoyi.ems.handle;
|
|
|
-
|
|
|
-import com.alibaba.fastjson2.JSON;
|
|
|
-import com.alibaba.fastjson2.JSONArray;
|
|
|
-import com.alibaba.fastjson2.JSONObject;
|
|
|
-import com.huashe.common.exception.Assert;
|
|
|
-import com.huashe.common.exception.BusinessException;
|
|
|
-import com.huashe.common.utils.DateUtils;
|
|
|
-import com.ruoyi.common.redis.service.RedisService;
|
|
|
-import com.ruoyi.ems.config.BaCtlConfig;
|
|
|
-import com.ruoyi.ems.core.BaCtlEnergyTemplate;
|
|
|
-import com.ruoyi.ems.domain.ElecMeterH;
|
|
|
-import com.ruoyi.ems.domain.ElecPgSupplyH;
|
|
|
-import com.ruoyi.ems.domain.EmsDevice;
|
|
|
-import com.ruoyi.ems.domain.EmsObjAttrValue;
|
|
|
-import com.ruoyi.ems.domain.FdEnergyPriceConfig;
|
|
|
-import com.ruoyi.ems.domain.MeterDevice;
|
|
|
-import com.ruoyi.ems.domain.WaterMeterH;
|
|
|
-import com.ruoyi.ems.enums.DevObjType;
|
|
|
-import com.ruoyi.ems.model.AbilityPayload;
|
|
|
-import com.ruoyi.ems.model.BoundaryObj;
|
|
|
-import com.ruoyi.ems.model.CallData;
|
|
|
-import com.ruoyi.ems.model.CallResponse;
|
|
|
-import com.ruoyi.ems.model.Price;
|
|
|
-import com.ruoyi.ems.model.QueryDevice;
|
|
|
-import com.ruoyi.ems.model.idenergy.CodesVal;
|
|
|
-import com.ruoyi.ems.model.idenergy.CodesValReq;
|
|
|
-import com.ruoyi.ems.model.idenergy.CodesValSetReq;
|
|
|
-import com.ruoyi.ems.service.IEmsObjAttrValueService;
|
|
|
-import org.apache.commons.collections4.CollectionUtils;
|
|
|
-import org.apache.commons.lang3.StringUtils;
|
|
|
-import org.slf4j.Logger;
|
|
|
-import org.slf4j.LoggerFactory;
|
|
|
-import org.springframework.beans.factory.annotation.Autowired;
|
|
|
-import org.springframework.stereotype.Service;
|
|
|
-
|
|
|
-import javax.annotation.Resource;
|
|
|
-import java.util.ArrayList;
|
|
|
-import java.util.Arrays;
|
|
|
-import java.util.Date;
|
|
|
-import java.util.HashMap;
|
|
|
-import java.util.List;
|
|
|
-import java.util.Map;
|
|
|
-import java.util.Set;
|
|
|
-import java.util.concurrent.ConcurrentHashMap;
|
|
|
-import java.util.function.Function;
|
|
|
-import java.util.stream.Collectors;
|
|
|
-
|
|
|
-/**
|
|
|
- * BA楼控处理类
|
|
|
- * <功能详细描述>
|
|
|
- *
|
|
|
- * @author lvwenbin
|
|
|
- * @version [版本号, 2025/8/15]
|
|
|
- * @see [相关类/方法]
|
|
|
- * @since [产品/模块版本]
|
|
|
- */
|
|
|
-@Service
|
|
|
-public class BaCtlHandler extends BaseMeterDevHandler {
|
|
|
- private static final Logger log = LoggerFactory.getLogger(BaCtlHandler.class);
|
|
|
-
|
|
|
- // 网关模型代码
|
|
|
- private static final String GATEWAY_MODEL = "M_W4_DEV_BA_GA";
|
|
|
-
|
|
|
- // 电表测点模型代码
|
|
|
- private static final String METER_MODEL_E = "M_W4_DEV_BA_METER_E";
|
|
|
-
|
|
|
- // 水表测点模型代码
|
|
|
- private static final String METER_MODEL_W = "M_W4_DEV_BA_METER_W";
|
|
|
-
|
|
|
- // 新风设备模型代码
|
|
|
- private static final String METER_MODEL_XF = "M_Z020_DEV_BA_XF";
|
|
|
-
|
|
|
- // 空调设备模型代码
|
|
|
- private static final String METER_MODEL_AHU = "M_Z020_DEV_BA_AHU";
|
|
|
-
|
|
|
- // 水箱设备模型代码
|
|
|
- private static final String METER_MODEL_WT = "M_Z020_DEV_BA_WT";
|
|
|
-
|
|
|
- // 水泵设备模型代码
|
|
|
- private static final String METER_MODEL_WP = "M_Z020_DEV_BA_WP";
|
|
|
-
|
|
|
- // 照明模型代码
|
|
|
- private static final String METER_MODEL_LIGHT = "M_Z020_DEV_BA_LIGHT";
|
|
|
-
|
|
|
- // 设备子系统代码
|
|
|
- private static final String SUBSYSTEM_CODE = "SYS_NHJC";
|
|
|
-
|
|
|
- // 单小时最大增长量(度)
|
|
|
- private static final double MAX_HOUR_INCREASE_RATE = 1000.0;
|
|
|
-
|
|
|
- // 允许的最小负增长(考虑精度误差)
|
|
|
- private static final double MIN_REASONABLE_DECREASE_RATE = -0.1;
|
|
|
-
|
|
|
- // 异常数据连续确认次数
|
|
|
- private static final int ABNORMAL_DATA_CONFIRM_COUNT = 3;
|
|
|
-
|
|
|
- @Resource
|
|
|
- private IEmsObjAttrValueService objAttrValueService;
|
|
|
-
|
|
|
- @Resource
|
|
|
- private BaCtlConfig config;
|
|
|
-
|
|
|
- @Autowired
|
|
|
- private RedisService redisService;
|
|
|
-
|
|
|
- @Override
|
|
|
- public List<MeterDevice> getMeterDeviceList() {
|
|
|
- QueryDevice queryDevice = new QueryDevice();
|
|
|
- queryDevice.setDeviceModel(METER_MODEL_E);
|
|
|
- queryDevice.setDeviceEnable(1);
|
|
|
- List<MeterDevice> list = new ArrayList<>(meterDeviceService.selectMeterDeviceList(queryDevice));
|
|
|
-
|
|
|
- QueryDevice queryDevice2 = new QueryDevice();
|
|
|
- queryDevice2.setDeviceModel(METER_MODEL_W);
|
|
|
- queryDevice2.setDeviceEnable(1);
|
|
|
- list.addAll(meterDeviceService.selectMeterDeviceList(queryDevice2));
|
|
|
-
|
|
|
- return list;
|
|
|
- }
|
|
|
-
|
|
|
- public List<MeterDevice> getMeterDeviceList(String modelCode) {
|
|
|
- QueryDevice queryDevice = new QueryDevice();
|
|
|
- queryDevice.setDeviceModel(modelCode);
|
|
|
- queryDevice.setDeviceEnable(1);
|
|
|
- return meterDeviceService.selectMeterDeviceList(queryDevice);
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public List<EmsDevice> getDeviceList() {
|
|
|
- throw new UnsupportedOperationException();
|
|
|
- }
|
|
|
-
|
|
|
- public List<EmsDevice> getDeviceList(String modelCode) {
|
|
|
- QueryDevice queryDevice = new QueryDevice();
|
|
|
- queryDevice.setDeviceModel(modelCode);
|
|
|
- return deviceService.selectList(queryDevice);
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public CallResponse<Void> call(AbilityPayload param) {
|
|
|
- CallResponse<Void> callResponse = null;
|
|
|
-
|
|
|
- try {
|
|
|
- if (DevObjType.SYSTEM.getCode() == param.getObjType()) {
|
|
|
- if (StringUtils.equals("MeterReadingTotal", param.getAbilityKey())) {
|
|
|
- List<EmsDevice> deviceList = getDeviceList(GATEWAY_MODEL);
|
|
|
-
|
|
|
- for (EmsDevice device : deviceList) {
|
|
|
- meterReadingGw(device.getDeviceModel(), "MeterReadingGw", device.getDeviceCode());
|
|
|
- }
|
|
|
- }
|
|
|
- else if (StringUtils.equals("SyncXfDevAttr", param.getAbilityKey())) {
|
|
|
- xfCollect();
|
|
|
- }
|
|
|
- else if (StringUtils.equals("SyncAuhDevAttr", param.getAbilityKey())) {
|
|
|
- ahuCollect();
|
|
|
- }
|
|
|
- else if (StringUtils.equals("SyncWtDevAttr", param.getAbilityKey())) {
|
|
|
- wtCollect();
|
|
|
- }
|
|
|
- else if (StringUtils.equals("SyncWpDevAttr", param.getAbilityKey())) {
|
|
|
- wpCollect();
|
|
|
- }
|
|
|
- else if (StringUtils.equals("SyncLightDevAttr", param.getAbilityKey())) {
|
|
|
- lightCollect();
|
|
|
- }
|
|
|
-
|
|
|
- callResponse = new CallResponse<>(0, "成功");
|
|
|
- }
|
|
|
- else if (DevObjType.DEVC.getCode() == param.getObjType()) {
|
|
|
- if (StringUtils.equals("MeterReadingGw", param.getAbilityKey()) && StringUtils.equals(
|
|
|
- param.getModelCode(), GATEWAY_MODEL)) {
|
|
|
- meterReadingGw(param.getModelCode(), param.getAbilityKey(), param.getObjCode());
|
|
|
- }
|
|
|
- else if (StringUtils.equals("StartStopCtl", param.getAbilityKey()) && StringUtils.equals(
|
|
|
- param.getModelCode(), METER_MODEL_XF)) {
|
|
|
- Map<String, String> xfMapper = config.getXfMapper();
|
|
|
- String pointId = xfMapper.get(String.format("%s.%s", param.getObjCode(), "setCtl-StartStop"));
|
|
|
- Assert.notEmpty(pointId, -1, "该设备未配置控制测点pointId.");
|
|
|
- devAbilityCall(METER_MODEL_XF, param.getObjCode(), pointId, param.getAbilityKey(),
|
|
|
- param.getAbilityParam());
|
|
|
- }
|
|
|
- else if (StringUtils.equals("StartStopCtl", param.getAbilityKey()) && StringUtils.equals(
|
|
|
- param.getModelCode(), METER_MODEL_AHU)) {
|
|
|
- Map<String, String> ahuMapper = config.getAhuMapper();
|
|
|
- String pointId = ahuMapper.get(String.format("%s.%s", param.getObjCode(), "setCtl-StartStop"));
|
|
|
- Assert.notEmpty(pointId, -1, "该设备未配置控制测点pointId.");
|
|
|
- devAbilityCall(METER_MODEL_AHU, param.getObjCode(), pointId, param.getAbilityKey(),
|
|
|
- param.getAbilityParam());
|
|
|
- }
|
|
|
- else if (StringUtils.equals("OnOffCtl", param.getAbilityKey()) && StringUtils.equals(
|
|
|
- param.getModelCode(), METER_MODEL_AHU)) {
|
|
|
- Map<String, String> lightMapper = config.getLightMapper();
|
|
|
- String pointId = lightMapper.get(String.format("%s.%s", param.getObjCode(), "setCtl-OnOff"));
|
|
|
- Assert.notEmpty(pointId, -1, "该设备未配置控制测点pointId.");
|
|
|
- devAbilityCall(METER_MODEL_LIGHT, param.getObjCode(), pointId, param.getAbilityKey(),
|
|
|
- param.getAbilityParam());
|
|
|
- }
|
|
|
-
|
|
|
- callResponse = new CallResponse<>(0, "成功");
|
|
|
- }
|
|
|
- else {
|
|
|
- callResponse = new CallResponse<>(-1, "不支持的能力key:" + param.getAbilityKey());
|
|
|
- }
|
|
|
- }
|
|
|
- catch (BusinessException e) {
|
|
|
- callResponse = new CallResponse<>(e.getCode(), e.getMessage());
|
|
|
- }
|
|
|
-
|
|
|
- return callResponse;
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public void refreshOnline() {
|
|
|
- }
|
|
|
-
|
|
|
- public void devAbilityCall(String modelCode, String deviceId, String pointId, String abilityKey,
|
|
|
- String paramValue) {
|
|
|
- CodesVal codesVal = new CodesVal();
|
|
|
- codesVal.setPointId(pointId);
|
|
|
- codesVal.setValue(paramValue);
|
|
|
-
|
|
|
- BaCtlEnergyTemplate template = new BaCtlEnergyTemplate(config.getUrl());
|
|
|
- CallData<String> callData = template.setCodesVal(new CodesValSetReq(codesVal));
|
|
|
-
|
|
|
- saveCallLog(deviceId, modelCode, abilityKey, callData.getCallStatus(), callData.getCallPayload(),
|
|
|
- callData.getResPayload());
|
|
|
- }
|
|
|
-
|
|
|
- private void meterReadingGw(String modeCode, String abilityKey, String objCode) {
|
|
|
- // 查询当前设备的接口属性值
|
|
|
- EmsObjAttrValue subDevAttr = objAttrValueService.selectObjAttrValue(modeCode, objCode, "subDev");
|
|
|
-
|
|
|
- if (null != subDevAttr && StringUtils.isNotEmpty(subDevAttr.getAttrValue())) {
|
|
|
- JSONArray subDevs = JSON.parseArray(subDevAttr.getAttrValue());
|
|
|
- Set<String> pointIdSet = subDevs.stream().map(item -> ((JSONObject) item).getString("deviceCode"))
|
|
|
- .collect(Collectors.toSet());
|
|
|
-
|
|
|
- CodesValReq req = new CodesValReq(pointIdSet);
|
|
|
-
|
|
|
- // 调用能耗数据接口获取实时数据
|
|
|
- CallData<String> callData = new BaCtlEnergyTemplate(config.getUrl()).getCodesVal(req);
|
|
|
- String callRes = callData.getResPayload();
|
|
|
- JSONObject resJson = JSONObject.parseObject(callRes);
|
|
|
-
|
|
|
- if (resJson.getInteger("code") == 200) {
|
|
|
- saveCallLog(objCode, modeCode, abilityKey, 0, JSON.toJSONString(req), callRes);
|
|
|
-
|
|
|
- String dataStr = resJson.getString("ResultPointObjArr");
|
|
|
- List<CodesVal> retList = JSON.parseArray(dataStr, CodesVal.class);
|
|
|
- // 更新设备属性
|
|
|
- updateMeterDeviceAttrList(objCode, subDevs, retList);
|
|
|
- }
|
|
|
- else {
|
|
|
- saveCallLog(objCode, modeCode, abilityKey, 2, JSON.toJSONString(req), callRes);
|
|
|
- throw new BusinessException(-1, resJson.getString("error"));
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 采集室内能耗计量数据
|
|
|
- *
|
|
|
- * @return 采集条数
|
|
|
- */
|
|
|
- public int meterCollect() {
|
|
|
- int cnt = 0;
|
|
|
-
|
|
|
- try {
|
|
|
- List<EmsObjAttrValue> gwDeviceList = objAttrValueService.selectByAttrKey(GATEWAY_MODEL, "subDev");
|
|
|
-
|
|
|
- // 遍历每个网关设备
|
|
|
- if (CollectionUtils.isNotEmpty(gwDeviceList)) {
|
|
|
- // 调用能耗数据接口获取实时数据
|
|
|
- BaCtlEnergyTemplate template = new BaCtlEnergyTemplate(config.getUrl());
|
|
|
-
|
|
|
- for (EmsObjAttrValue gwDevice : gwDeviceList) {
|
|
|
- cnt += meterDevCollect(template, gwDevice);
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- catch (Exception e) {
|
|
|
- log.error("能耗数据抄报异常", e);
|
|
|
- }
|
|
|
-
|
|
|
- return cnt;
|
|
|
- }
|
|
|
-
|
|
|
- public void xfCollect() {
|
|
|
- try {
|
|
|
- List<EmsDevice> deviceList = getDeviceList(METER_MODEL_XF);
|
|
|
-
|
|
|
- if (CollectionUtils.isNotEmpty(deviceList)) {
|
|
|
- for (EmsDevice device : deviceList) {
|
|
|
- xfDeviceCollect(device);
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- catch (Exception e) {
|
|
|
- log.error("新风采集异常", e);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- public void ahuCollect() {
|
|
|
- try {
|
|
|
- List<EmsDevice> deviceList = getDeviceList(METER_MODEL_AHU);
|
|
|
-
|
|
|
- if (CollectionUtils.isNotEmpty(deviceList)) {
|
|
|
- for (EmsDevice device : deviceList) {
|
|
|
- auhDeviceCollect(device);
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- catch (Exception e) {
|
|
|
- log.error("新风采集异常", e);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- public void wtCollect() {
|
|
|
- try {
|
|
|
- List<EmsDevice> deviceList = getDeviceList(METER_MODEL_WT);
|
|
|
-
|
|
|
- if (CollectionUtils.isNotEmpty(deviceList)) {
|
|
|
- for (EmsDevice device : deviceList) {
|
|
|
- wtDeviceCollect(device);
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- catch (Exception e) {
|
|
|
- log.error("水箱采集异常", e);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- public void wpCollect() {
|
|
|
- try {
|
|
|
- List<EmsDevice> deviceList = getDeviceList(METER_MODEL_WP);
|
|
|
-
|
|
|
- if (CollectionUtils.isNotEmpty(deviceList)) {
|
|
|
- for (EmsDevice device : deviceList) {
|
|
|
- wpDeviceCollect(device);
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- catch (Exception e) {
|
|
|
- log.error("水泵采集异常", e);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- public void lightCollect() {
|
|
|
- try {
|
|
|
- List<EmsDevice> deviceList = getDeviceList(METER_MODEL_LIGHT);
|
|
|
-
|
|
|
- if (CollectionUtils.isNotEmpty(deviceList)) {
|
|
|
- for (EmsDevice device : deviceList) {
|
|
|
- lightDeviceCollect(device);
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- catch (Exception e) {
|
|
|
- log.error("照明采集异常", e);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- private int meterDevCollect(BaCtlEnergyTemplate template, EmsObjAttrValue subDevAttr) {
|
|
|
- int cnt = 0;
|
|
|
-
|
|
|
- try {
|
|
|
-
|
|
|
- if (null != subDevAttr && StringUtils.isNotEmpty(subDevAttr.getAttrValue())) {
|
|
|
- JSONArray subDevs = JSON.parseArray(subDevAttr.getAttrValue());
|
|
|
- Set<String> pointIdSet = subDevs.stream().map(item -> ((JSONObject) item).getString("deviceCode"))
|
|
|
- .collect(Collectors.toSet());
|
|
|
-
|
|
|
- CodesValReq req = new CodesValReq(pointIdSet);
|
|
|
-
|
|
|
- // 调用能耗数据接口获取实时数据
|
|
|
- CallData<String> callData = template.getCodesVal(req);
|
|
|
- String callRes = callData.getResPayload();
|
|
|
- JSONObject resJson = JSONObject.parseObject(callRes);
|
|
|
- Assert.isTrue(StringUtils.equals(resJson.getString("code"), "200"), resJson.getInteger("code"),
|
|
|
- resJson.getString("error"));
|
|
|
- int callStatus = StringUtils.equals(resJson.getString("code"), "200") ? 0 : 2;
|
|
|
- saveCallLog(subDevAttr.getObjCode(), GATEWAY_MODEL, "MeterReadingGw", callStatus,
|
|
|
- JSON.toJSONString(req), callRes);
|
|
|
-
|
|
|
- String dataStr = resJson.getString("ResultPointObjArr");
|
|
|
- List<CodesVal> retList = JSON.parseArray(dataStr, CodesVal.class);
|
|
|
-
|
|
|
- // 更新设备属性
|
|
|
- updateMeterDeviceAttrList(subDevAttr.getObjCode(), subDevs, retList);
|
|
|
- }
|
|
|
- }
|
|
|
- catch (Exception e) {
|
|
|
- log.error("meterDevHourProd error! deviceCode:{}", subDevAttr.getObjCode(), e);
|
|
|
- }
|
|
|
-
|
|
|
- return cnt;
|
|
|
- }
|
|
|
-
|
|
|
- private void xfDeviceCollect(EmsDevice device) {
|
|
|
- String deviceCode = device.getDeviceCode();
|
|
|
- Map<String, String> paramKeys = config.getXfMapper();
|
|
|
-
|
|
|
- Set<String> pointIds = paramKeys.entrySet().stream().filter(
|
|
|
- entry -> StringUtils.startsWith(entry.getKey(), deviceCode) && !StringUtils.startsWith(entry.getKey(),
|
|
|
- deviceCode + ".setCtl-")).flatMap(entry -> Arrays.stream(StringUtils.split(entry.getValue(), ",")))
|
|
|
- .map(String::trim).collect(Collectors.toSet());
|
|
|
-
|
|
|
- if (CollectionUtils.isNotEmpty(pointIds)) {
|
|
|
- CodesValReq req = new CodesValReq(pointIds);
|
|
|
-
|
|
|
- // 调用能耗数据接口获取实时数据
|
|
|
- CallData<String> callData = new BaCtlEnergyTemplate(config.getUrl()).getCodesVal(req);
|
|
|
- String callRes = callData.getResPayload();
|
|
|
- saveCallLog(device.getDeviceCode(), device.getDeviceModel(), "SyncXfDevAttr", 0, JSON.toJSONString(req), callRes);
|
|
|
-
|
|
|
- JSONObject resJson = JSONObject.parseObject(callRes);
|
|
|
- Assert.isTrue(StringUtils.equals(resJson.getString("code"), "200"), resJson.getInteger("code"),
|
|
|
- resJson.getString("error"));
|
|
|
- String dataStr = resJson.getString("ResultPointObjArr");
|
|
|
- List<CodesVal> retList = JSON.parseArray(dataStr, CodesVal.class);
|
|
|
- Map<String, CodesVal> retMap = retList.stream()
|
|
|
- .collect(Collectors.toMap(CodesVal::getPointId, Function.identity()));
|
|
|
-
|
|
|
- List<EmsObjAttrValue> dbAttrList = objAttrValueService.selectByObjCode(METER_MODEL_XF, deviceCode);
|
|
|
- Map<String, EmsObjAttrValue> dbMap = dbAttrList.stream()
|
|
|
- .collect(Collectors.toMap(EmsObjAttrValue::getAttrKey, Function.identity()));
|
|
|
-
|
|
|
- baDevAttrCheckAndUpdate(METER_MODEL_XF, deviceCode, "xfTemp", paramKeys, dbMap, retMap);
|
|
|
- baDevAttrCheckAndUpdate(METER_MODEL_XF, deviceCode, "sfTemp", paramKeys, dbMap, retMap);
|
|
|
- baDevAttrCheckAndUpdate(METER_MODEL_XF, deviceCode, "hfTemp", paramKeys, dbMap, retMap);
|
|
|
- baDevAttrCheckAndUpdate(METER_MODEL_XF, deviceCode, "pfTemp", paramKeys, dbMap, retMap);
|
|
|
- baDevAttrCheckAndUpdate(METER_MODEL_XF, deviceCode, "ppm", paramKeys, dbMap, retMap);
|
|
|
- baDevAttrCheckAndUpdate(METER_MODEL_XF, deviceCode, "wCv", paramKeys, dbMap, retMap);
|
|
|
- baDevAttrCheckAndUpdate(METER_MODEL_XF, deviceCode, "xfCv", paramKeys, dbMap, retMap);
|
|
|
- baDevAttrCheckAndUpdate(METER_MODEL_XF, deviceCode, "pfCv", paramKeys, dbMap, retMap);
|
|
|
- baDevAttrCheckAndUpdate(METER_MODEL_XF, deviceCode, "lwDpAlarm", paramKeys, dbMap, retMap);
|
|
|
- baDevAttrCheckAndUpdate(METER_MODEL_XF, deviceCode, "fjUvAlarm", paramKeys, dbMap, retMap);
|
|
|
- baDevAttrCheckAndUpdate(METER_MODEL_XF, deviceCode, "afAlarm", paramKeys, dbMap, retMap);
|
|
|
- baDevAttrCheckAndUpdate(METER_MODEL_XF, deviceCode, "xfStatus", paramKeys, dbMap, retMap);
|
|
|
- baDevAttrCheckAndUpdate(METER_MODEL_XF, deviceCode, "xfMA", paramKeys, dbMap, retMap);
|
|
|
- baDevAttrCheckAndUpdate(METER_MODEL_XF, deviceCode, "xfFault", paramKeys, dbMap, retMap);
|
|
|
- baDevAttrCheckAndUpdate(METER_MODEL_XF, deviceCode, "pfStatus", paramKeys, dbMap, retMap);
|
|
|
- baDevAttrCheckAndUpdate(METER_MODEL_XF, deviceCode, "pfMA", paramKeys, dbMap, retMap);
|
|
|
- baDevAttrCheckAndUpdate(METER_MODEL_XF, deviceCode, "pfFault", paramKeys, dbMap, retMap);
|
|
|
- baDevAttrCheckAndUpdate(METER_MODEL_XF, deviceCode, "xfTempSetVal", paramKeys, dbMap, retMap);
|
|
|
- baDevAttrCheckAndUpdate(METER_MODEL_XF, deviceCode, "LnSu", paramKeys, dbMap, retMap);
|
|
|
- baDevAttrCheckAndUpdate(METER_MODEL_XF, deviceCode, "timeSetTag", paramKeys, dbMap, retMap);
|
|
|
- baDevAttrCheckAndUpdate(METER_MODEL_XF, deviceCode, "manualTag", paramKeys, dbMap, retMap);
|
|
|
- baDevTimeStatueCheckAndUpdate(METER_MODEL_XF, deviceCode, "timeStatus", paramKeys, dbMap, retMap);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- private void auhDeviceCollect(EmsDevice device) {
|
|
|
- String deviceCode = device.getDeviceCode();
|
|
|
- Map<String, String> paramKeys = config.getAhuMapper();
|
|
|
-
|
|
|
- Set<String> pointIds = paramKeys.entrySet().stream().filter(
|
|
|
- entry -> StringUtils.startsWith(entry.getKey(), deviceCode) && !StringUtils.startsWith(entry.getKey(),
|
|
|
- deviceCode + ".setCtl-")).flatMap(entry -> Arrays.stream(StringUtils.split(entry.getValue(), ",")))
|
|
|
- .map(String::trim).collect(Collectors.toSet());
|
|
|
-
|
|
|
- if (CollectionUtils.isNotEmpty(pointIds)) {
|
|
|
- CodesValReq req = new CodesValReq(pointIds);
|
|
|
-
|
|
|
- // 调用能耗数据接口获取实时数据
|
|
|
- CallData<String> callData = new BaCtlEnergyTemplate(config.getUrl()).getCodesVal(req);
|
|
|
- String callRes = callData.getResPayload();
|
|
|
- saveCallLog(device.getDeviceCode(), device.getDeviceModel(), "SyncAuhDevAttr", 0, JSON.toJSONString(req), callRes);
|
|
|
- JSONObject resJson = JSONObject.parseObject(callRes);
|
|
|
- Assert.isTrue(StringUtils.equals(resJson.getString("code"), "200"), resJson.getInteger("code"),
|
|
|
- resJson.getString("error"));
|
|
|
- String dataStr = resJson.getString("ResultPointObjArr");
|
|
|
- List<CodesVal> retList = JSON.parseArray(dataStr, CodesVal.class);
|
|
|
- Map<String, CodesVal> retMap = retList.stream()
|
|
|
- .collect(Collectors.toMap(CodesVal::getPointId, Function.identity()));
|
|
|
-
|
|
|
- List<EmsObjAttrValue> dbAttrList = objAttrValueService.selectByObjCode(METER_MODEL_AHU, deviceCode);
|
|
|
- Map<String, EmsObjAttrValue> dbMap = dbAttrList.stream()
|
|
|
- .collect(Collectors.toMap(EmsObjAttrValue::getAttrKey, Function.identity()));
|
|
|
-
|
|
|
- baDevAttrCheckAndUpdate(METER_MODEL_AHU, deviceCode, "xfTemp", paramKeys, dbMap, retMap);
|
|
|
- baDevAttrCheckAndUpdate(METER_MODEL_AHU, deviceCode, "sfTemp", paramKeys, dbMap, retMap);
|
|
|
- baDevAttrCheckAndUpdate(METER_MODEL_AHU, deviceCode, "hfTemp", paramKeys, dbMap, retMap);
|
|
|
- baDevAttrCheckAndUpdate(METER_MODEL_AHU, deviceCode, "wCv", paramKeys, dbMap, retMap);
|
|
|
- baDevAttrCheckAndUpdate(METER_MODEL_AHU, deviceCode, "xfCv", paramKeys, dbMap, retMap);
|
|
|
- baDevAttrCheckAndUpdate(METER_MODEL_AHU, deviceCode, "lwDpAlarm", paramKeys, dbMap, retMap);
|
|
|
- baDevAttrCheckAndUpdate(METER_MODEL_AHU, deviceCode, "fjUvAlarm", paramKeys, dbMap, retMap);
|
|
|
- baDevAttrCheckAndUpdate(METER_MODEL_AHU, deviceCode, "afAlarm", paramKeys, dbMap, retMap);
|
|
|
- baDevAttrCheckAndUpdate(METER_MODEL_AHU, deviceCode, "xfStatus", paramKeys, dbMap, retMap);
|
|
|
- baDevAttrCheckAndUpdate(METER_MODEL_AHU, deviceCode, "xfMA", paramKeys, dbMap, retMap);
|
|
|
- baDevAttrCheckAndUpdate(METER_MODEL_AHU, deviceCode, "xfFault", paramKeys, dbMap, retMap);
|
|
|
- baDevAttrCheckAndUpdate(METER_MODEL_AHU, deviceCode, "xfTempSetVal", paramKeys, dbMap, retMap);
|
|
|
- baDevAttrCheckAndUpdate(METER_MODEL_AHU, deviceCode, "LnSu", paramKeys, dbMap, retMap);
|
|
|
- baDevAttrCheckAndUpdate(METER_MODEL_AHU, deviceCode, "timeSetTag", paramKeys, dbMap, retMap);
|
|
|
- baDevAttrCheckAndUpdate(METER_MODEL_AHU, deviceCode, "manualTag", paramKeys, dbMap, retMap);
|
|
|
- baDevTimeStatueCheckAndUpdate(METER_MODEL_AHU, deviceCode, "timeStatus", paramKeys, dbMap, retMap);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- private void wtDeviceCollect(EmsDevice device) {
|
|
|
- String deviceCode = device.getDeviceCode();
|
|
|
- Map<String, String> paramKeys = config.getWtMapper();
|
|
|
-
|
|
|
- Set<String> pointIds = paramKeys.entrySet().stream()
|
|
|
- .filter(entry -> StringUtils.startsWith(entry.getKey(), deviceCode))
|
|
|
- .flatMap(entry -> Arrays.stream(StringUtils.split(entry.getValue(), ","))).map(String::trim)
|
|
|
- .collect(Collectors.toSet());
|
|
|
-
|
|
|
- if (CollectionUtils.isNotEmpty(pointIds)) {
|
|
|
- CodesValReq req = new CodesValReq(pointIds);
|
|
|
-
|
|
|
- // 调用能耗数据接口获取实时数据
|
|
|
- CallData<String> callData = new BaCtlEnergyTemplate(config.getUrl()).getCodesVal(req);
|
|
|
- String callRes = callData.getResPayload();
|
|
|
- saveCallLog(device.getDeviceCode(), device.getDeviceModel(), "SyncWtDevAttr", 0, JSON.toJSONString(req), callRes);
|
|
|
- JSONObject resJson = JSONObject.parseObject(callRes);
|
|
|
- Assert.isTrue(StringUtils.equals(resJson.getString("code"), "200"), resJson.getInteger("code"),
|
|
|
- resJson.getString("error"));
|
|
|
- String dataStr = resJson.getString("ResultPointObjArr");
|
|
|
- List<CodesVal> retList = JSON.parseArray(dataStr, CodesVal.class);
|
|
|
- Map<String, CodesVal> retMap = retList.stream()
|
|
|
- .collect(Collectors.toMap(CodesVal::getPointId, Function.identity()));
|
|
|
-
|
|
|
- List<EmsObjAttrValue> dbAttrList = objAttrValueService.selectByObjCode(METER_MODEL_WT, deviceCode);
|
|
|
- Map<String, EmsObjAttrValue> dbMap = dbAttrList.stream()
|
|
|
- .collect(Collectors.toMap(EmsObjAttrValue::getAttrKey, Function.identity()));
|
|
|
-
|
|
|
- baDevAttrCheckAndUpdate(METER_MODEL_WT, deviceCode, "highLevelAlarm", paramKeys, dbMap, retMap);
|
|
|
- baDevAttrCheckAndUpdate(METER_MODEL_WT, deviceCode, "lowLevelAlarm", paramKeys, dbMap, retMap);
|
|
|
- baDevAttrCheckAndUpdate(METER_MODEL_WT, deviceCode, "tankLevel", paramKeys, dbMap, retMap);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- private void wpDeviceCollect(EmsDevice device) {
|
|
|
- String deviceCode = device.getDeviceCode();
|
|
|
- Map<String, String> paramKeys = config.getWpMapper();
|
|
|
-
|
|
|
- Set<String> pointIds = paramKeys.entrySet().stream()
|
|
|
- .filter(entry -> StringUtils.startsWith(entry.getKey(), deviceCode))
|
|
|
- .flatMap(entry -> Arrays.stream(StringUtils.split(entry.getValue(), ","))).map(String::trim)
|
|
|
- .collect(Collectors.toSet());
|
|
|
-
|
|
|
- if (CollectionUtils.isNotEmpty(pointIds)) {
|
|
|
- CodesValReq req = new CodesValReq(pointIds);
|
|
|
-
|
|
|
- // 调用能耗数据接口获取实时数据
|
|
|
- CallData<String> callData = new BaCtlEnergyTemplate(config.getUrl()).getCodesVal(req);
|
|
|
- String callRes = callData.getResPayload();
|
|
|
- saveCallLog(device.getDeviceCode(), device.getDeviceModel(), "SyncWpDevAttr", 0, JSON.toJSONString(req), callRes);
|
|
|
- JSONObject resJson = JSONObject.parseObject(callRes);
|
|
|
- Assert.isTrue(StringUtils.equals(resJson.getString("code"), "200"), resJson.getInteger("code"),
|
|
|
- resJson.getString("error"));
|
|
|
- String dataStr = resJson.getString("ResultPointObjArr");
|
|
|
- List<CodesVal> retList = JSON.parseArray(dataStr, CodesVal.class);
|
|
|
- Map<String, CodesVal> retMap = retList.stream()
|
|
|
- .collect(Collectors.toMap(CodesVal::getPointId, Function.identity()));
|
|
|
-
|
|
|
- List<EmsObjAttrValue> dbAttrList = objAttrValueService.selectByObjCode(METER_MODEL_WP, deviceCode);
|
|
|
- Map<String, EmsObjAttrValue> dbMap = dbAttrList.stream()
|
|
|
- .collect(Collectors.toMap(EmsObjAttrValue::getAttrKey, Function.identity()));
|
|
|
-
|
|
|
- baDevAttrCheckAndUpdate(METER_MODEL_WP, deviceCode, "autoState", paramKeys, dbMap, retMap);
|
|
|
- baDevAttrCheckAndUpdate(METER_MODEL_WP, deviceCode, "runningState", paramKeys, dbMap, retMap);
|
|
|
- baDevAttrCheckAndUpdate(METER_MODEL_WP, deviceCode, "faultState", paramKeys, dbMap, retMap);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- private void lightDeviceCollect(EmsDevice device) {
|
|
|
- String deviceCode = device.getDeviceCode();
|
|
|
- Map<String, String> paramKeys = config.getLightMapper();
|
|
|
-
|
|
|
- Set<String> pointIds = paramKeys.entrySet().stream().filter(
|
|
|
- entry -> StringUtils.startsWith(entry.getKey(), deviceCode) && !StringUtils.startsWith(entry.getKey(),
|
|
|
- deviceCode + ".setCtl-")).flatMap(entry -> Arrays.stream(StringUtils.split(entry.getValue(), ",")))
|
|
|
- .map(String::trim).collect(Collectors.toSet());
|
|
|
-
|
|
|
- if (CollectionUtils.isNotEmpty(pointIds)) {
|
|
|
- CodesValReq req = new CodesValReq(pointIds);
|
|
|
-
|
|
|
- // 调用能耗数据接口获取实时数据
|
|
|
- CallData<String> callData = new BaCtlEnergyTemplate(config.getUrl()).getCodesVal(req);
|
|
|
- String callRes = callData.getResPayload();
|
|
|
- saveCallLog(device.getDeviceCode(), device.getDeviceModel(), "SyncLightDevAttr", 0, JSON.toJSONString(req), callRes);
|
|
|
- JSONObject resJson = JSONObject.parseObject(callRes);
|
|
|
- Assert.isTrue(StringUtils.equals(resJson.getString("code"), "200"), resJson.getInteger("code"),
|
|
|
- resJson.getString("error"));
|
|
|
- String dataStr = resJson.getString("ResultPointObjArr");
|
|
|
- List<CodesVal> retList = JSON.parseArray(dataStr, CodesVal.class);
|
|
|
- Map<String, CodesVal> retMap = retList.stream()
|
|
|
- .collect(Collectors.toMap(CodesVal::getPointId, Function.identity()));
|
|
|
-
|
|
|
- List<EmsObjAttrValue> dbAttrList = objAttrValueService.selectByObjCode(METER_MODEL_LIGHT, deviceCode);
|
|
|
- Map<String, EmsObjAttrValue> dbMap = dbAttrList.stream()
|
|
|
- .collect(Collectors.toMap(EmsObjAttrValue::getAttrKey, Function.identity()));
|
|
|
-
|
|
|
- baDevAttrCheckAndUpdate(METER_MODEL_LIGHT, deviceCode, "Switch", paramKeys, dbMap, retMap);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- private void baDevAttrCheckAndUpdate(String devModel, String deviceCode, String attrKey,
|
|
|
- Map<String, String> kvMap, Map<String, EmsObjAttrValue> dbAttrMap, Map<String, CodesVal> retMap) {
|
|
|
- EmsObjAttrValue dbAttr = dbAttrMap.get(attrKey);
|
|
|
- String pointId = kvMap.get(String.format("%s.%s", deviceCode, attrKey));
|
|
|
-
|
|
|
- if (null != dbAttr && retMap.containsKey(pointId)) {
|
|
|
- CodesVal codesVal = retMap.get(pointId);
|
|
|
-
|
|
|
- if (!StringUtils.equals(dbAttr.getAttrValue(), codesVal.getValue())) {
|
|
|
- objAttrValueService.updateObjAttrValue(devModel, deviceCode, attrKey, codesVal.getValue());
|
|
|
- }
|
|
|
- }
|
|
|
- else {
|
|
|
- if (null != pointId && retMap.containsKey(pointId)) {
|
|
|
- CodesVal codesVal = retMap.get(pointId);
|
|
|
- EmsObjAttrValue attr = new EmsObjAttrValue(deviceCode, devModel, attrKey, codesVal.getValue());
|
|
|
- objAttrValueService.mergeObjAttrValue(attr);
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- private void baDevTimeStatueCheckAndUpdate(String devModel, String deviceCode, String attrKey,
|
|
|
- Map<String, String> kvMap, Map<String, EmsObjAttrValue> dbAttrMap, Map<String, CodesVal> retMap) {
|
|
|
- EmsObjAttrValue dbAttr = dbAttrMap.get(attrKey);
|
|
|
- String pointIdStr = kvMap.get(String.format("%s.%s", deviceCode, attrKey));
|
|
|
-
|
|
|
- if (StringUtils.isNotEmpty(pointIdStr)) {
|
|
|
- String[] array = StringUtils.split(pointIdStr, ",");
|
|
|
- String value = "0";
|
|
|
-
|
|
|
- // 定时开-小时
|
|
|
- CodesVal codesVal = retMap.get(array[0]);
|
|
|
-
|
|
|
- if (null != codesVal && StringUtils.equals(codesVal.getValue(), "1")) {
|
|
|
- value = "160";
|
|
|
- }
|
|
|
-
|
|
|
- codesVal = retMap.get(array[1]);
|
|
|
-
|
|
|
- if (null != codesVal && StringUtils.equals(codesVal.getValue(), "1")) {
|
|
|
- value = "101";
|
|
|
- }
|
|
|
-
|
|
|
- codesVal = retMap.get(array[2]);
|
|
|
-
|
|
|
- if (null != codesVal && StringUtils.equals(codesVal.getValue(), "1")) {
|
|
|
- value = "260";
|
|
|
- }
|
|
|
-
|
|
|
- codesVal = retMap.get(array[3]);
|
|
|
-
|
|
|
- if (null != codesVal && StringUtils.equals(codesVal.getValue(), "1")) {
|
|
|
- value = "201";
|
|
|
- }
|
|
|
-
|
|
|
- if (null != dbAttr && !StringUtils.equals(dbAttr.getAttrValue(), value)) {
|
|
|
- objAttrValueService.updateObjAttrValue(devModel, deviceCode, attrKey, value);
|
|
|
- }
|
|
|
- else if (null == dbAttr) {
|
|
|
- EmsObjAttrValue attr = new EmsObjAttrValue(deviceCode, devModel, attrKey, value);
|
|
|
- objAttrValueService.mergeObjAttrValue(attr);
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- private void updateMeterDeviceAttrList(String gwDevieCode, JSONArray subDevs, List<CodesVal> retList) {
|
|
|
- try {
|
|
|
- // 将新采集数据转换为Map
|
|
|
- Map<String, CodesVal> codesValMap = retList.stream()
|
|
|
- .collect(Collectors.toMap(CodesVal::getPointId, Function.identity()));
|
|
|
-
|
|
|
- for (Object subDev : subDevs) {
|
|
|
- JSONObject subDevObj = (JSONObject) subDev;
|
|
|
- String pointId = subDevObj.getString("deviceCode");
|
|
|
- String modelCode = subDevObj.getString("modelCode");
|
|
|
-
|
|
|
- CodesVal syncCodesVal = codesValMap.get(pointId);
|
|
|
-
|
|
|
- if (null != syncCodesVal) {
|
|
|
- EmsObjAttrValue dbAttr = objAttrValueService.selectObjAttrValue(modelCode, pointId, "value");
|
|
|
-
|
|
|
- // 数据验证和处理
|
|
|
- DataValidationResult validationResult = validateMeterData(gwDevieCode, pointId,
|
|
|
- dbAttr.getAttrValue(), syncCodesVal.getValue());
|
|
|
-
|
|
|
- if (validationResult.isValid()) {
|
|
|
- // 更新缓存中的数据
|
|
|
- String hKey = NEW_HOUR_READING + "-" + pointId;
|
|
|
- redisService.setCacheMapValue(gwDevieCode, hKey, validationResult.getValidValue());
|
|
|
-
|
|
|
- if (!StringUtils.equals(validationResult.getValidValue(), dbAttr.getAttrValue())) {
|
|
|
- objAttrValueService.updateObjAttrValue(modelCode, pointId, "value",
|
|
|
- validationResult.getValidValue());
|
|
|
- }
|
|
|
- }
|
|
|
- else {
|
|
|
- // 记录异常数据但不更新
|
|
|
- log.warn("检测到异常抄表数据 - 设备:{}, 测点:{}, 旧值:{}, 新值:{}, 原因:{}",
|
|
|
- dbAttr.getObjCode(), pointId, dbAttr.getAttrValue(), syncCodesVal.getValue(),
|
|
|
- validationResult.getReason());
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- catch (Exception e) {
|
|
|
- log.error("更新设备属性异常", e);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 能耗数据抄报(扩展支持市电计量)
|
|
|
- */
|
|
|
- @Override
|
|
|
- public int meterHourProd() {
|
|
|
- int cnt = 0;
|
|
|
-
|
|
|
- try {
|
|
|
- // 计量设备-网关设备映射集合
|
|
|
- Map<String, EmsDevice> refParentMap = getRefParentMap();
|
|
|
-
|
|
|
- // 电表
|
|
|
- List<MeterDevice> meterDeviceList = getMeterDeviceList(METER_MODEL_E);
|
|
|
-
|
|
|
- // 计算电表小时数据
|
|
|
- if (CollectionUtils.isNotEmpty(meterDeviceList)) {
|
|
|
- Map<String, Price> priceMap = new ConcurrentHashMap<>();
|
|
|
- Date date = DateUtils.adjustHour(new Date(), -1);
|
|
|
- List<ElecMeterH> elecMeterHList = new ArrayList<>();
|
|
|
-
|
|
|
- for (MeterDevice meterDevice : meterDeviceList) {
|
|
|
- EmsDevice gwDevice = refParentMap.get(meterDevice.getDeviceCode());
|
|
|
- ElecMeterH elecMeterH = workElecMeterReading(gwDevice, meterDevice);
|
|
|
-
|
|
|
- if (null != elecMeterH) {
|
|
|
- Price price = priceMap.computeIfAbsent(gwDevice.getAreaCode(),
|
|
|
- k -> priceService.getElecHourPrice(gwDevice.getAreaCode(), date));
|
|
|
- completeElecPrice(elecMeterH, price);
|
|
|
- elecMeterHList.add(elecMeterH);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if (CollectionUtils.isNotEmpty(elecMeterHList)) {
|
|
|
- elecMeterHService.insertBatch(elecMeterHList);
|
|
|
- cnt += elecMeterHList.size();
|
|
|
- generatePgSupplyData(elecMeterHList);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // 水表
|
|
|
- meterDeviceList = getMeterDeviceList(METER_MODEL_W);
|
|
|
-
|
|
|
- // 计算水表小时数据
|
|
|
- if (CollectionUtils.isNotEmpty(meterDeviceList)) {
|
|
|
- Map<String, FdEnergyPriceConfig> priceMap = new ConcurrentHashMap<>();
|
|
|
- List<WaterMeterH> waterMeterHList = new ArrayList<>();
|
|
|
-
|
|
|
- for (MeterDevice meterDevice : meterDeviceList) {
|
|
|
- EmsDevice gwDevice = refParentMap.get(meterDevice.getDeviceCode());
|
|
|
- WaterMeterH waterMeterH = workWaterMeterReading(gwDevice, meterDevice);
|
|
|
-
|
|
|
- if (null != waterMeterH) {
|
|
|
- FdEnergyPriceConfig price = priceMap.computeIfAbsent(gwDevice.getAreaCode(),
|
|
|
- k -> fdEnergyPriceConfigService.selectByAreaCode(gwDevice.getAreaCode(), 70));
|
|
|
- completeWaterPrice(waterMeterH, price);
|
|
|
- waterMeterHList.add(waterMeterH);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if (CollectionUtils.isNotEmpty(waterMeterHList)) {
|
|
|
- waterMeterHService.insertBatch(waterMeterHList);
|
|
|
- cnt += waterMeterHList.size();
|
|
|
-
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- catch (Exception e) {
|
|
|
- log.error("能耗数据抄报异常", e);
|
|
|
- }
|
|
|
-
|
|
|
- return cnt;
|
|
|
- }
|
|
|
-
|
|
|
- private Map<String, EmsDevice> getRefParentMap() {
|
|
|
- Map<String, EmsDevice> refParentMap = new HashMap<>();
|
|
|
-
|
|
|
- List<EmsObjAttrValue> attrValues = objAttrValueService.selectByAttrKey(GATEWAY_MODEL, "subDev");
|
|
|
- Map<String, String> attrValueMap = attrValues.stream()
|
|
|
- .collect(Collectors.toMap(EmsObjAttrValue::getObjCode, EmsObjAttrValue::getAttrValue));
|
|
|
-
|
|
|
- // 网关设备列表
|
|
|
- List<EmsDevice> gwDevices = getDeviceList(GATEWAY_MODEL);
|
|
|
-
|
|
|
- if (CollectionUtils.isNotEmpty(gwDevices)) {
|
|
|
- for (EmsDevice gwDevice : gwDevices) {
|
|
|
- String subDevStr = attrValueMap.get(gwDevice.getDeviceCode());
|
|
|
- if (StringUtils.isNotBlank(subDevStr)) {
|
|
|
- JSONArray jsonArray = JSON.parseArray(subDevStr);
|
|
|
- jsonArray.forEach(obj -> {
|
|
|
- JSONObject jsonObject = (JSONObject) obj;
|
|
|
- refParentMap.put(jsonObject.getString("deviceCode"), gwDevice);
|
|
|
- });
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- return refParentMap;
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 修改后的单设备计量产出方法,返回详细结果
|
|
|
- */
|
|
|
-
|
|
|
- private ElecMeterH workElecMeterReading(EmsDevice gwDevice, MeterDevice meterDevice) {
|
|
|
- ElecMeterH elecMeterH = null;
|
|
|
-
|
|
|
- // 读取最新抄表值
|
|
|
- String newMeterReading = redisService.getCacheMapValue(gwDevice.getDeviceCode(),
|
|
|
- NEW_HOUR_READING + "-" + meterDevice.getDeviceCode());
|
|
|
-
|
|
|
- if (null != newMeterReading) {
|
|
|
- String lastCacheKey = LAST_HOUR_READING + "-" + meterDevice.getDeviceCode();
|
|
|
-
|
|
|
- // 读取历史抄表
|
|
|
- String lastMeterReading = redisService.getCacheMapValue(gwDevice.getDeviceCode(), lastCacheKey);
|
|
|
-
|
|
|
- elecMeterH = getElecMeterH(gwDevice.getDeviceCode(), meterDevice, lastMeterReading, newMeterReading);
|
|
|
- }
|
|
|
-
|
|
|
- return elecMeterH;
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public ElecMeterH getElecMeterH(String deviceCode, MeterDevice mDevice, String lastMeterReading,
|
|
|
- String newMeterReading) {
|
|
|
- ElecMeterH elecMeterH = null;
|
|
|
- String cacheKey = LAST_HOUR_READING + "-" + mDevice.getDeviceCode();
|
|
|
- String timestampKey = LAST_HOUR_TIMESTAMP + "-" + mDevice.getDeviceCode();
|
|
|
-
|
|
|
- // 获取缓存时间戳
|
|
|
- String cachedTimestamp = redisService.getCacheMapValue(deviceCode, timestampKey);
|
|
|
- boolean shouldUseCache = false;
|
|
|
-
|
|
|
- if (StringUtils.isNotEmpty(lastMeterReading) && StringUtils.isNotEmpty(cachedTimestamp)) {
|
|
|
- try {
|
|
|
- long lastUpdateTime = Long.parseLong(cachedTimestamp);
|
|
|
- long currentTime = System.currentTimeMillis();
|
|
|
- // 只有当缓存数据在2小时内才使用
|
|
|
- shouldUseCache = (currentTime - lastUpdateTime) <= MAX_CACHE_AGE_MILLIS;
|
|
|
- }
|
|
|
- catch (NumberFormatException e) {
|
|
|
- log.warn("无效的时间戳缓存: {}", cachedTimestamp);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if (shouldUseCache) {
|
|
|
- // 缓存有效,使用缓存计算
|
|
|
- elecMeterH = execElecHourMeter(mDevice, lastMeterReading, newMeterReading);
|
|
|
- // 更新缓存和时间戳
|
|
|
- updateCacheAfterSuccess(deviceCode, cacheKey, newMeterReading);
|
|
|
- redisService.setCacheMapValue(deviceCode, timestampKey, String.valueOf(System.currentTimeMillis()));
|
|
|
- }
|
|
|
- else {
|
|
|
- // 缓存过期或无效,查询数据库
|
|
|
- ElecMeterH dbElecMeterH = elecMeterHService.selectLatelyItem(mDevice.getDeviceCode());
|
|
|
-
|
|
|
- if (null != dbElecMeterH && null != dbElecMeterH.getMeterReading()) {
|
|
|
- // 验证数据库记录是否为上一小时
|
|
|
- Date currentHour = DateUtils.adjustHour(new Date(), -1);
|
|
|
- long timeDiff = currentHour.getTime() - dbElecMeterH.getRecordTime().getTime();
|
|
|
-
|
|
|
- // 只有时间差在1小时左右(容差30分钟)才计算
|
|
|
- if (Math.abs(timeDiff) <= 30 * 60 * 1000) {
|
|
|
- elecMeterH = execElecHourMeter(mDevice, String.valueOf(dbElecMeterH.getMeterReading()),
|
|
|
- newMeterReading);
|
|
|
- }
|
|
|
- else {
|
|
|
- log.warn("数据时间差过大,跳过计算 - 设备:{}, 时间差:{}小时", mDevice.getDeviceCode(),
|
|
|
- timeDiff / (60 * 60 * 1000));
|
|
|
- }
|
|
|
-
|
|
|
- // 无论是否计算,都更新缓存为当前值,作为下次计算基准
|
|
|
- updateCacheAfterSuccess(deviceCode, cacheKey, newMeterReading);
|
|
|
- redisService.setCacheMapValue(deviceCode, timestampKey, String.valueOf(System.currentTimeMillis()));
|
|
|
- }
|
|
|
- else {
|
|
|
- // 首次上报,仅更新缓存
|
|
|
- if (StringUtils.isNotEmpty(newMeterReading)) {
|
|
|
- updateCacheAfterSuccess(deviceCode, cacheKey, newMeterReading);
|
|
|
- redisService.setCacheMapValue(deviceCode, timestampKey, String.valueOf(System.currentTimeMillis()));
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- return elecMeterH;
|
|
|
- }
|
|
|
-
|
|
|
- private WaterMeterH workWaterMeterReading(EmsDevice gwDevice, MeterDevice meterDevice) {
|
|
|
- WaterMeterH waterMeterH = null;
|
|
|
-
|
|
|
- // 读取最新抄表值
|
|
|
- String newMeterReading = redisService.getCacheMapValue(gwDevice.getDeviceCode(),
|
|
|
- NEW_HOUR_READING + "-" + meterDevice.getDeviceCode());
|
|
|
-
|
|
|
- if (null != newMeterReading) {
|
|
|
- String lastCacheKey = LAST_HOUR_READING + "-" + meterDevice.getDeviceCode();
|
|
|
-
|
|
|
- // 读取历史抄表
|
|
|
- String lastMeterReading = redisService.getCacheMapValue(gwDevice.getDeviceCode(), lastCacheKey);
|
|
|
-
|
|
|
- // 组装水表抄报数据
|
|
|
- waterMeterH = getWaterMeterH(gwDevice.getDeviceCode(), meterDevice, lastMeterReading, newMeterReading);
|
|
|
- }
|
|
|
-
|
|
|
- return waterMeterH;
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public WaterMeterH getWaterMeterH(String deviceCode, MeterDevice mDevice, String lastMeterReading,
|
|
|
- String newMeterReading) {
|
|
|
- WaterMeterH waterMeterH = null;
|
|
|
- String cacheKey = LAST_HOUR_READING + "-" + mDevice.getDeviceCode();
|
|
|
- String timestampKey = LAST_HOUR_TIMESTAMP + "-" + mDevice.getDeviceCode();
|
|
|
-
|
|
|
- // 获取缓存时间戳
|
|
|
- String cachedTimestamp = redisService.getCacheMapValue(deviceCode, timestampKey);
|
|
|
- boolean shouldUseCache = false;
|
|
|
-
|
|
|
- if (StringUtils.isNotEmpty(lastMeterReading) && StringUtils.isNotEmpty(cachedTimestamp)) {
|
|
|
- try {
|
|
|
- long lastUpdateTime = Long.parseLong(cachedTimestamp);
|
|
|
- long currentTime = System.currentTimeMillis();
|
|
|
- // 只有当缓存数据在2小时内才使用
|
|
|
- shouldUseCache = (currentTime - lastUpdateTime) <= MAX_CACHE_AGE_MILLIS;
|
|
|
-
|
|
|
- if (!shouldUseCache) {
|
|
|
- log.warn("水表缓存数据过期 - 设备:{}, 缓存时长:{}小时", mDevice.getDeviceCode(),
|
|
|
- (currentTime - lastUpdateTime) / (60 * 60 * 1000));
|
|
|
- }
|
|
|
- }
|
|
|
- catch (NumberFormatException e) {
|
|
|
- log.warn("无效的时间戳缓存: {}", cachedTimestamp);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if (shouldUseCache) {
|
|
|
- // 缓存有效,使用缓存计算
|
|
|
- waterMeterH = execWaterHourMeter(mDevice, lastMeterReading, newMeterReading);
|
|
|
- if (waterMeterH != null) {
|
|
|
- // 只有成功计算后才更新缓存
|
|
|
- updateCacheAfterSuccess(deviceCode, cacheKey, newMeterReading);
|
|
|
- redisService.setCacheMapValue(deviceCode, timestampKey, String.valueOf(System.currentTimeMillis()));
|
|
|
- }
|
|
|
- }
|
|
|
- else {
|
|
|
- // 缓存过期或无效,查询数据库
|
|
|
- WaterMeterH dbWaterMeterH = waterMeterHService.selectLatelyItem(mDevice.getDeviceCode());
|
|
|
-
|
|
|
- if (null != dbWaterMeterH && null != dbWaterMeterH.getMeterReading()) {
|
|
|
- // 验证数据库记录是否为上一小时
|
|
|
- Date currentHour = DateUtils.adjustHour(new Date(), -1);
|
|
|
- long timeDiff = currentHour.getTime() - dbWaterMeterH.getRecordTime().getTime();
|
|
|
-
|
|
|
- // 只有时间差在1小时左右(容差30分钟)才计算
|
|
|
- if (Math.abs(timeDiff) <= 30 * 60 * 1000) {
|
|
|
- waterMeterH = execWaterHourMeter(mDevice, String.valueOf(dbWaterMeterH.getMeterReading()),
|
|
|
- newMeterReading);
|
|
|
- }
|
|
|
- else {
|
|
|
- log.warn("水表数据时间差过大,跳过计算 - 设备:{}, 时间差:{}小时", mDevice.getDeviceCode(),
|
|
|
- timeDiff / (60 * 60 * 1000));
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // 无论是否计算成功,都更新缓存为当前值,作为下次计算基准
|
|
|
- if (StringUtils.isNotEmpty(newMeterReading)) {
|
|
|
- updateCacheAfterSuccess(deviceCode, cacheKey, newMeterReading);
|
|
|
- redisService.setCacheMapValue(deviceCode, timestampKey, String.valueOf(System.currentTimeMillis()));
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- return waterMeterH;
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 产出市电供应计量数据(优化版)
|
|
|
- */
|
|
|
- private void generatePgSupplyData(List<ElecMeterH> allElecMeterHList) {
|
|
|
- try {
|
|
|
- // 生成市电供应数据
|
|
|
- List<ElecPgSupplyH> pgSupplyHList = new ArrayList<>();
|
|
|
-
|
|
|
- // 获取所有区域的市电设施及其绑定的计量设备
|
|
|
- Set<String> areaCodeSet = allElecMeterHList.stream().map(ElecMeterH::getAreaCode)
|
|
|
- .collect(Collectors.toSet());
|
|
|
-
|
|
|
- Map<String, Price> priceMap = new ConcurrentHashMap<>();
|
|
|
- Date recordTime = DateUtils.adjustHour(new Date(), -1);
|
|
|
-
|
|
|
- // 按区域查询市电设施
|
|
|
- for (String areaCode : areaCodeSet) {
|
|
|
- // 查询区域下市电的供应设施(同时获取了设施绑定的表计)
|
|
|
- List<BoundaryObj> facsMeterBinds = facsService.getFacsWithMeterDev(areaCode, "W", "W2", 45);
|
|
|
-
|
|
|
- if (CollectionUtils.isNotEmpty(facsMeterBinds)) {
|
|
|
- for (BoundaryObj facsMeterBind : facsMeterBinds) {
|
|
|
- // 过滤出当前设施绑定表计对应的小时计量数据
|
|
|
- List<ElecMeterH> subElecMeterHs = filterBindElecMeterDevs(facsMeterBind, allElecMeterHList);
|
|
|
-
|
|
|
- if (CollectionUtils.isNotEmpty(subElecMeterHs)) {
|
|
|
- // 直接累加同一设施下的所有电表数据(同一小时电价类型相同)
|
|
|
- double totalQuantity = subElecMeterHs.stream().mapToDouble(ElecMeterH::getElecQuantity)
|
|
|
- .sum();
|
|
|
-
|
|
|
- double totalCost = subElecMeterHs.stream().mapToDouble(ElecMeterH::getUseElecCost).sum();
|
|
|
-
|
|
|
- // 精度控制:用量保留1位小数,金额保留2位小数
|
|
|
- totalQuantity = formatToDecimalPlaces(totalQuantity, 1);
|
|
|
- totalCost = formatToDecimalPlaces(totalCost, 2);
|
|
|
-
|
|
|
- // 获取电价信息(同一小时所有表计的电价类型和单价都相同,取第一个即可)
|
|
|
- ElecMeterH firstMeter = subElecMeterHs.get(0);
|
|
|
- Integer meterType = firstMeter.getMeterType();
|
|
|
- Double unitPrice = firstMeter.getMeterUnitPrice();
|
|
|
-
|
|
|
- // 创建市电供应记录
|
|
|
- ElecPgSupplyH pgSupplyH = new ElecPgSupplyH();
|
|
|
- pgSupplyH.setAreaCode(areaCode);
|
|
|
- pgSupplyH.setFacsCode(facsMeterBind.getObjCode());
|
|
|
- pgSupplyH.setRecordTime(recordTime);
|
|
|
- pgSupplyH.setDate(recordTime);
|
|
|
- pgSupplyH.setTime(recordTime);
|
|
|
- pgSupplyH.setTimeIndex(getHourIndex(recordTime));
|
|
|
- pgSupplyH.setMeterType(meterType);
|
|
|
- pgSupplyH.setMeterUnitPrice(unitPrice);
|
|
|
- pgSupplyH.setUseElecQuantity(totalQuantity);
|
|
|
- pgSupplyH.setUseElecCost(totalCost);
|
|
|
- pgSupplyHList.add(pgSupplyH);
|
|
|
-
|
|
|
- }
|
|
|
- else {
|
|
|
- Price price = priceMap.computeIfAbsent(areaCode,
|
|
|
- k -> priceService.getElecHourPrice(areaCode, recordTime));
|
|
|
-
|
|
|
- ElecPgSupplyH pgSupplyH = new ElecPgSupplyH();
|
|
|
- pgSupplyH.setAreaCode(areaCode);
|
|
|
- pgSupplyH.setFacsCode(facsMeterBind.getObjCode());
|
|
|
- pgSupplyH.setRecordTime(recordTime);
|
|
|
- pgSupplyH.setDate(recordTime);
|
|
|
- pgSupplyH.setTime(recordTime);
|
|
|
- pgSupplyH.setTimeIndex(getHourIndex(recordTime));
|
|
|
- pgSupplyH.setMeterType(price.getMeterType());
|
|
|
- pgSupplyH.setMeterUnitPrice(price.getPriceValue());
|
|
|
- pgSupplyH.setUseElecQuantity(0.0);
|
|
|
- pgSupplyH.setUseElecCost(0.0);
|
|
|
- pgSupplyHList.add(pgSupplyH);
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- else {
|
|
|
- log.warn("未找到市电设施配置,无法产出市电供应数据");
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if (CollectionUtils.isNotEmpty(pgSupplyHList)) {
|
|
|
- pgSupplyHService.insertBatch(pgSupplyHList);
|
|
|
- }
|
|
|
- }
|
|
|
- catch (Exception e) {
|
|
|
- log.error("产出市电供应计量数据异常", e);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- private List<ElecMeterH> filterBindElecMeterDevs(BoundaryObj facsMeterBind, List<ElecMeterH> allElecMeterHList) {
|
|
|
- Set<String> bindElecMeterDevs = facsMeterBind.getBindMeterDevs();
|
|
|
- if (CollectionUtils.isEmpty(bindElecMeterDevs)) {
|
|
|
- return new ArrayList<>();
|
|
|
- }
|
|
|
- return allElecMeterHList.stream().filter(elecMeterH -> bindElecMeterDevs.contains(elecMeterH.getDeviceCode()))
|
|
|
- .collect(Collectors.toList());
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 验证抄表数据的合理性
|
|
|
- */
|
|
|
- private DataValidationResult validateMeterData(String deviceCode, String pointId, String oldValue,
|
|
|
- String newValue) {
|
|
|
- try {
|
|
|
- // 新数据为空或无效
|
|
|
- if (StringUtils.isBlank(newValue)) {
|
|
|
- return DataValidationResult.invalid("新值为空");
|
|
|
- }
|
|
|
-
|
|
|
- double newVal = Double.parseDouble(newValue);
|
|
|
-
|
|
|
- // 首次数据,直接接受
|
|
|
- if (StringUtils.isBlank(oldValue)) {
|
|
|
- return DataValidationResult.valid(newValue);
|
|
|
- }
|
|
|
-
|
|
|
- double oldVal = Double.parseDouble(oldValue);
|
|
|
- double difference = newVal - oldVal;
|
|
|
-
|
|
|
- // 1. 检查是否为明显的向后跳变(新值比旧值小很多)
|
|
|
- if (difference < MIN_REASONABLE_DECREASE_RATE) {
|
|
|
- // 检查是否可能是表计重置(新值很小,旧值很大)
|
|
|
- if (newVal < 100 && oldVal > 10000) {
|
|
|
- log.info("检测到可能的表计重置 - 设备:{}, 测点:{}, 旧值:{}, 新值:{}", deviceCode, pointId, oldVal,
|
|
|
- newVal);
|
|
|
- // 表计重置的情况,需要人工确认,暂时不更新
|
|
|
- return DataValidationResult.invalid("疑似表计重置,需人工确认");
|
|
|
- }
|
|
|
- else {
|
|
|
- return DataValidationResult.invalid(String.format("数据向后跳变,差值:%.2f", difference));
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // 2. 检查是否增长过快(可能是数据错误)
|
|
|
- if (difference > MAX_HOUR_INCREASE_RATE) {
|
|
|
- return DataValidationResult.invalid(String.format("增长过快,差值:%.2f", difference));
|
|
|
- }
|
|
|
-
|
|
|
- // 3. 连续异常数据确认机制
|
|
|
- if (Math.abs(difference) > MAX_HOUR_INCREASE_RATE * 0.1) { // 超过正常增长的10%认为需要关注
|
|
|
- String abnormalKey = "ABNORMAL_COUNT_" + pointId;
|
|
|
- String countStr = redisService.getCacheMapValue(deviceCode, abnormalKey);
|
|
|
- int abnormalCount = StringUtils.isNotBlank(countStr) ? Integer.parseInt(countStr) : 0;
|
|
|
-
|
|
|
- abnormalCount++;
|
|
|
- redisService.setCacheMapValue(deviceCode, abnormalKey, String.valueOf(abnormalCount));
|
|
|
-
|
|
|
- // 如果连续异常次数太多,需要告警但仍然更新数据
|
|
|
- if (abnormalCount >= ABNORMAL_DATA_CONFIRM_COUNT) {
|
|
|
- log.warn("连续异常数据 - 设备:{}, 测点:{}, 连续{}次异常, 当前差值:{}", deviceCode, pointId,
|
|
|
- abnormalCount, difference);
|
|
|
- // 重置计数
|
|
|
- redisService.setCacheMapValue(deviceCode, abnormalKey, "0");
|
|
|
- }
|
|
|
- }
|
|
|
- else {
|
|
|
- // 数据正常,清除异常计数
|
|
|
- String abnormalKey = "ABNORMAL_COUNT_" + pointId;
|
|
|
- redisService.setCacheMapValue(deviceCode, abnormalKey, "0");
|
|
|
- }
|
|
|
-
|
|
|
- return DataValidationResult.valid(newValue);
|
|
|
-
|
|
|
- }
|
|
|
- catch (NumberFormatException e) {
|
|
|
- return DataValidationResult.invalid("数据格式错误: " + e.getMessage());
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 数据验证结果内部类
|
|
|
- */
|
|
|
- private static class DataValidationResult {
|
|
|
- private final boolean valid;
|
|
|
-
|
|
|
- private final String validValue;
|
|
|
-
|
|
|
- private final String reason;
|
|
|
-
|
|
|
- private DataValidationResult(boolean valid, String validValue, String reason) {
|
|
|
- this.valid = valid;
|
|
|
- this.validValue = validValue;
|
|
|
- this.reason = reason;
|
|
|
- }
|
|
|
-
|
|
|
- public static DataValidationResult valid(String value) {
|
|
|
- return new DataValidationResult(true, value, null);
|
|
|
- }
|
|
|
-
|
|
|
- public static DataValidationResult invalid(String reason) {
|
|
|
- return new DataValidationResult(false, null, reason);
|
|
|
- }
|
|
|
-
|
|
|
- public boolean isValid() {
|
|
|
- return valid;
|
|
|
- }
|
|
|
-
|
|
|
- public String getValidValue() {
|
|
|
- return validValue;
|
|
|
- }
|
|
|
-
|
|
|
- public String getReason() {
|
|
|
- return reason;
|
|
|
- }
|
|
|
- }
|
|
|
-}
|