diff --git a/pqs-device/pq-device/pq-device-boot/src/main/java/com/njcn/device/pq/service/impl/NewStationServiceImpl.java b/pqs-device/pq-device/pq-device-boot/src/main/java/com/njcn/device/pq/service/impl/NewStationServiceImpl.java index 5ffb6f67b..7f24eadf7 100644 --- a/pqs-device/pq-device/pq-device-boot/src/main/java/com/njcn/device/pq/service/impl/NewStationServiceImpl.java +++ b/pqs-device/pq-device/pq-device-boot/src/main/java/com/njcn/device/pq/service/impl/NewStationServiceImpl.java @@ -16,6 +16,7 @@ import com.njcn.device.pq.service.INewStationService; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import java.util.Arrays; import java.util.List; import java.util.Map; @@ -24,7 +25,6 @@ import java.util.Map; *

* 新能源场站高低电压穿越表 服务实现类 *

- * * @author guofeihu * @since 2024-08-14 */ @@ -66,6 +66,7 @@ public class NewStationServiceImpl extends ServiceImpl listIds = Arrays.asList(ids.split(",")); //判断该新能源场站信息是否绑定了测点ID diff --git a/pqs-event/event-api/pom.xml b/pqs-event/event-api/pom.xml index 85b06eec7..7a9b3b1d7 100644 --- a/pqs-event/event-api/pom.xml +++ b/pqs-event/event-api/pom.xml @@ -56,6 +56,12 @@ jna 3.0.9 + + com.njcn + pms-device-api + 1.0.0 + compile + diff --git a/pqs-event/event-api/src/main/java/com/njcn/event/api/TransientFeignClient.java b/pqs-event/event-api/src/main/java/com/njcn/event/api/TransientFeignClient.java new file mode 100644 index 000000000..313ae8c2e --- /dev/null +++ b/pqs-event/event-api/src/main/java/com/njcn/event/api/TransientFeignClient.java @@ -0,0 +1,22 @@ +package com.njcn.event.api; + +import com.njcn.common.pojo.constant.ServerInfo; +import com.njcn.common.pojo.response.HttpResult; +import com.njcn.device.pms.pojo.param.MonitorTerminalParam; +import com.njcn.event.api.fallback.TransientFeignClientFallbackFactory; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; + +/** + * 暂态事件Feign客户端 + * @author guofeihu + * @date 2024-08-22 + */ +@FeignClient(value = ServerInfo.EVENT,path = "/transient",fallbackFactory = TransientFeignClientFallbackFactory.class) +public interface TransientFeignClient { + + @PostMapping("/getTransientAnalyseWaveToByteArray") + HttpResult getTransientAnalyseWaveToByteArray(@RequestBody MonitorTerminalParam param); + +} diff --git a/pqs-event/event-api/src/main/java/com/njcn/event/api/fallback/TransientFeignClientFallbackFactory.java b/pqs-event/event-api/src/main/java/com/njcn/event/api/fallback/TransientFeignClientFallbackFactory.java new file mode 100644 index 000000000..41e93454b --- /dev/null +++ b/pqs-event/event-api/src/main/java/com/njcn/event/api/fallback/TransientFeignClientFallbackFactory.java @@ -0,0 +1,40 @@ +package com.njcn.event.api.fallback; + +import com.njcn.common.pojo.enums.response.CommonResponseEnum; +import com.njcn.common.pojo.exception.BusinessException; +import com.njcn.common.pojo.response.HttpResult; +import com.njcn.device.pms.pojo.param.MonitorTerminalParam; +import com.njcn.event.api.TransientFeignClient; +import com.njcn.event.utils.EventlEnumUtil; +import feign.hystrix.FallbackFactory; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; +import org.springframework.web.bind.annotation.RequestBody; + +/** + * 暂态事件熔断降级 + * @author guofeihu + * @date 2024-08-22 + */ +@Slf4j +@Component +public class TransientFeignClientFallbackFactory implements FallbackFactory { + + @Override + public TransientFeignClient create(Throwable throwable) { + //判断抛出异常是否为解码器抛出的业务异常 + Enum exceptionEnum = CommonResponseEnum.SERVICE_FALLBACK; + if (throwable.getCause() instanceof BusinessException) { + BusinessException businessException = (BusinessException) throwable.getCause(); + exceptionEnum = EventlEnumUtil.getExceptionEnum(businessException.getResult()); + } + Enum finalExceptionEnum = exceptionEnum; + return new TransientFeignClient() { + @Override + public HttpResult getTransientAnalyseWaveToByteArray(@RequestBody MonitorTerminalParam param) { + log.error("{}异常,降级处理,异常为:{}", "暂态事件波形分析:", throwable.toString()); + throw new BusinessException(finalExceptionEnum); + } + }; + } +} diff --git a/pqs-event/event-boot/src/main/java/com/njcn/event/controller/majornetwork/TransientController.java b/pqs-event/event-boot/src/main/java/com/njcn/event/controller/majornetwork/TransientController.java index 2b75a1946..238162eb3 100644 --- a/pqs-event/event-boot/src/main/java/com/njcn/event/controller/majornetwork/TransientController.java +++ b/pqs-event/event-boot/src/main/java/com/njcn/event/controller/majornetwork/TransientController.java @@ -23,6 +23,9 @@ import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; import javax.servlet.http.HttpServletResponse; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectOutputStream; import java.util.List; /** @@ -60,6 +63,24 @@ public class TransientController extends BaseController { return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, wave, methodDescribe); } + @OperateInfo(info = LogEnum.BUSINESS_COMMON) + @PostMapping("/getTransientAnalyseWaveToByteArray") + @ApiOperation("暂态事件波形分析(转byte数组)") + public HttpResult getTransientAnalyseWaveToByteArray(@RequestBody MonitorTerminalParam param){ + byte[] bytes = null; + String methodDescribe = getMethodDescribe("getTransientAnalyseWaveToByteArray"); + WaveDataDTO wave = transientService.getTransientAnalyseWave(param); + try { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(baos); + oos.writeObject(wave); + bytes = baos.toByteArray(); + } catch (IOException e) { + e.printStackTrace(); + } + return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, bytes, methodDescribe); + } + @OperateInfo(info = LogEnum.BUSINESS_COMMON, operateType = OperateType.DOWNLOAD) @PostMapping("/downloadWaveFile") @ApiOperation("暂态波形下载") diff --git a/pqs-prepare/prepare-api/src/main/java/com/njcn/prepare/harmonic/api/event/fallback/RActivePowerRangeFeignClientFallbackFactory.java b/pqs-prepare/prepare-api/src/main/java/com/njcn/prepare/harmonic/api/event/fallback/RActivePowerRangeFeignClientFallbackFactory.java index 8b15f4270..1f0fee36c 100644 --- a/pqs-prepare/prepare-api/src/main/java/com/njcn/prepare/harmonic/api/event/fallback/RActivePowerRangeFeignClientFallbackFactory.java +++ b/pqs-prepare/prepare-api/src/main/java/com/njcn/prepare/harmonic/api/event/fallback/RActivePowerRangeFeignClientFallbackFactory.java @@ -34,13 +34,13 @@ public class RActivePowerRangeFeignClientFallbackFactory implements FallbackFact return new RActivePowerRangeFeignClient() { @Override public HttpResult> record(RActivePowerRangeParam rActivePowerRangeParam) { - log.error("{}异常,降级处理,异常为:{}", "有功功率趋势记录: ", throwable.toString()); + log.error("{}异常,降级处理,异常为:{}", "有功功率趋势记录:", throwable.toString()); throw new BusinessException(finalExceptionEnum); } @Override public HttpResult getDataByLineId(String lineId,String startTime,String endTime) { - log.error("{}异常,降级处理,异常为:{}", "根据监测点ID获取有功功率趋势信息: ", throwable.toString()); + log.error("{}异常,降级处理,异常为:{}", "根据监测点ID获取有功功率趋势信息:", throwable.toString()); throw new BusinessException(finalExceptionEnum); } }; diff --git a/pqs-prepare/prepare-api/src/main/java/com/njcn/prepare/harmonic/api/event/fallback/SpThroughFeignClientFallbackFactory.java b/pqs-prepare/prepare-api/src/main/java/com/njcn/prepare/harmonic/api/event/fallback/SpThroughFeignClientFallbackFactory.java index c4b5bec83..beb13a3fa 100644 --- a/pqs-prepare/prepare-api/src/main/java/com/njcn/prepare/harmonic/api/event/fallback/SpThroughFeignClientFallbackFactory.java +++ b/pqs-prepare/prepare-api/src/main/java/com/njcn/prepare/harmonic/api/event/fallback/SpThroughFeignClientFallbackFactory.java @@ -33,19 +33,19 @@ public class SpThroughFeignClientFallbackFactory implements FallbackFactory record() { - log.error("{}异常,降级处理,异常为:{}", "高低电压穿越记录: ", throwable.toString()); + log.error("{}异常,降级处理,异常为:{}", "高低电压穿越记录:", throwable.toString()); throw new BusinessException(finalExceptionEnum); } @Override public HttpResult getDataByEventIds(SpThroughParam spThroughParam) { - log.error("{}异常,降级处理,异常为:{}", "根据事件ID集合及能源站类型获取高低电压穿越次数: ", throwable.toString()); + log.error("{}异常,降级处理,异常为:{}", "根据事件ID集合及能源站类型获取高低电压穿越次数:", throwable.toString()); throw new BusinessException(finalExceptionEnum); } @Override public HttpResult> formatEventIds(SpThroughParam spThroughParam) { - log.error("{}异常,降级处理,异常为:{}", "根据原有的事件集合进行过滤: ", throwable.toString()); + log.error("{}异常,降级处理,异常为:{}", "根据原有的事件集合进行过滤:", throwable.toString()); throw new BusinessException(finalExceptionEnum); } }; diff --git a/pqs-prepare/prepare-api/src/main/java/com/njcn/prepare/harmonic/pojo/po/SpThroughPO.java b/pqs-prepare/prepare-api/src/main/java/com/njcn/prepare/harmonic/pojo/po/SpThroughPO.java index fc2a85ad8..a1ff5cb3a 100644 --- a/pqs-prepare/prepare-api/src/main/java/com/njcn/prepare/harmonic/pojo/po/SpThroughPO.java +++ b/pqs-prepare/prepare-api/src/main/java/com/njcn/prepare/harmonic/pojo/po/SpThroughPO.java @@ -3,6 +3,7 @@ package com.njcn.prepare.harmonic.pojo.po; import com.baomidou.mybatisplus.annotation.TableName; import com.njcn.db.bo.BaseEntity; import lombok.Data; +import java.time.LocalDateTime; /** * 高低电压穿越 实体类 @@ -45,4 +46,9 @@ public class SpThroughPO extends BaseEntity { */ private Boolean state; + /** + * 创建时间(自定义) + */ + private LocalDateTime createTime; + } diff --git a/pqs-prepare/prepare-boot/src/main/java/com/njcn/prepare/harmonic/service/mysql/Impl/event/RActivePowerRangeServiceImpl.java b/pqs-prepare/prepare-boot/src/main/java/com/njcn/prepare/harmonic/service/mysql/Impl/event/RActivePowerRangeServiceImpl.java index bb965441b..1f17a07b3 100644 --- a/pqs-prepare/prepare-boot/src/main/java/com/njcn/prepare/harmonic/service/mysql/Impl/event/RActivePowerRangeServiceImpl.java +++ b/pqs-prepare/prepare-boot/src/main/java/com/njcn/prepare/harmonic/service/mysql/Impl/event/RActivePowerRangeServiceImpl.java @@ -23,6 +23,7 @@ import com.njcn.prepare.harmonic.service.mysql.event.RActivePowerRangeService; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import java.lang.reflect.Field; import java.text.SimpleDateFormat; import java.time.LocalDate; @@ -74,6 +75,7 @@ public class RActivePowerRangeServiceImpl extends MppServiceImpl record(RActivePowerRangeParam rActivePowerRangeParam) { if(rActivePowerRangeParam == null){ rActivePowerRangeParam = new RActivePowerRangeParam(); @@ -404,13 +406,13 @@ public class RActivePowerRangeServiceImpl extends MppServiceImpl commonQuery(String tableName,String columnName,StatisticalDataDTO statisticalDataDTO,Integer start,Integer end){ List commonQueryParams = new ArrayList<>(); //不管哪种时间是固定的 String time = statisticalDataDTO.getTime().atZone(ZoneId.systemDefault()).format(formatter); CommonQueryParam commonQueryParam = new CommonQueryParam(); - //无谐波次数查询 + //无谐波次数指标查询 if(start == null){ commonQueryParam.setStartTime(time); commonQueryParam.setEndTime(time); @@ -421,7 +423,7 @@ public class RActivePowerRangeServiceImpl extends MppServiceImpl evenStDetailPOS = eventDetailFeignClient.getNewEventDetailByTime(getLastTime(),currentTime).getData(); + MonitorTerminalParam monitorTerminalParam = new MonitorTerminalParam(); + monitorTerminalParam.setSystemType(0); + monitorTerminalParam.setType(0); for(RmpEventDetailPO rmpEventDetailPO : evenStDetailPOS){ //获取监测点 LineDTO lineDTO = commLineClient.getLineDetail(rmpEventDetailPO.getMeasurementPointId()).getData(); if(lineDTO != null && lineDTO.getNewStationId() != null){ + //监测点必须绑定新能源场站 NewStation newStation = newStationClient.selectById(lineDTO.getNewStationId()).getData(); if(newStation != null){ - //waveFileComponent.getComtrade(); - //暂升事件 - if(Param.UPPEREVENT.equals(rmpEventDetailPO.getEventType())){ - //风电场 - if(Param.WINDFARM.equals(newStation.getStationType())){ - - } - //光伏电站 - if(Param.PHOTOVOLTAICPOWER.equals(newStation.getStationType())){ - - } - } - //暂降事件 - if(Param.LOWEREVENT.equals(rmpEventDetailPO.getEventType())){ - //风电场 - if(Param.WINDFARM.equals(newStation.getStationType())){ - - } - //光伏电站 - if(Param.PHOTOVOLTAICPOWER.equals(newStation.getStationType())){ - + //事件不能重复统计(除非事件的暂降类型及变电站类型发生变化) + LambdaQueryWrapper lambdaQueryWrapper = new LambdaQueryWrapper(); + lambdaQueryWrapper.eq(SpThroughPO::getEventId,rmpEventDetailPO.getEventId()) + .eq(SpThroughPO::getEventType,rmpEventDetailPO.getEventType()) + .eq(SpThroughPO::getStationType,newStation.getStationType()) + .eq(SpThroughPO::getState,1); + if(this.baseMapper.selectList(lambdaQueryWrapper).isEmpty()){ + //准备高低电压穿越实体bean + SpThroughPO spThroughPO = new SpThroughPO(); + spThroughPO.setId(IdUtil.simpleUUID()); + spThroughPO.setEventId(rmpEventDetailPO.getEventId()); + spThroughPO.setEventType(rmpEventDetailPO.getEventType()); + spThroughPO.setStationType(newStation.getStationType()); + //默认该事件没有穿越 + spThroughPO.setIsOrNot(0); + //设置波形查询的条件:事件ID + monitorTerminalParam.setId(rmpEventDetailPO.getEventId()); + //获取RMS波形数据(由于WaveDataDTO为复杂对象所以转成byte数组在进行反序列化) + byte[] bytes = transientFeignClient.getTransientAnalyseWaveToByteArray(monitorTerminalParam).getData(); + WaveDataDTO waveDataDTO = null; + try { + ByteArrayInputStream bis = new ByteArrayInputStream(bytes); + ObjectInputStream ois = new ObjectInputStream(bis); + //强转成WaveDataDTO + waveDataDTO = (WaveDataDTO)ois.readObject(); + } catch (Exception e) { + e.printStackTrace(); } + //标称电压 + if(lineDTO.getVoltageLevel()!=null){ + Float voltageLevel = Float.parseFloat(lineDTO.getVoltageLevel()); + //格式化数据源 + List> newListRmsData = listRmsDataFormat(waveDataDTO); + //暂升事件 + if(Param.UPPEREVENT.equals(rmpEventDetailPO.getEventType())){ + //风电场 + if(Param.WINDFARM.equals(newStation.getStationType())){ + if(isThrough(waveDataDTO,125,130,500,voltageLevel.floatValue(),newListRmsData) + && isThrough(waveDataDTO,120,125,1000,voltageLevel.floatValue(),newListRmsData) + && isThrough(waveDataDTO,110,120,10000,voltageLevel.floatValue(),newListRmsData)){ + spThroughPO.setIsOrNot(1); + } + } + //光伏电站 + if(Param.PHOTOVOLTAICPOWER.equals(newStation.getStationType())){ + if(isThrough(waveDataDTO,125,130,500,voltageLevel.floatValue(),newListRmsData) + && isThrough(waveDataDTO,120,125,1000,voltageLevel.floatValue(),newListRmsData) + && isThrough(waveDataDTO,110,120,10000,voltageLevel.floatValue(),newListRmsData)){ + spThroughPO.setIsOrNot(1); + } + } + } + //暂降事件 + if(Param.LOWEREVENT.equals(rmpEventDetailPO.getEventType())){ + //风电场 + if(Param.WINDFARM.equals(newStation.getStationType())){ + if(isThrough(waveDataDTO,20,-1,625,voltageLevel.floatValue(),newListRmsData)){ + spThroughPO.setIsOrNot(1); + } + } + //光伏电站 + if(Param.PHOTOVOLTAICPOWER.equals(newStation.getStationType())){ + if(isThrough(waveDataDTO,0,-1,150,voltageLevel.floatValue(),newListRmsData) + && isThrough(waveDataDTO,20,-1,625,voltageLevel.floatValue(),newListRmsData) + && isThrough(waveDataDTO,20,90,-1,voltageLevel.floatValue(),newListRmsData)){ + spThroughPO.setIsOrNot(1); + } + } + } + spThroughPO.setCreateTime(currentTime); + this.baseMapper.insert(spThroughPO); + }; } } } } + } + private boolean isThrough(WaveDataDTO waveDataDTO,int start,int end,int ms,float voltageLevel,List> newListRmsData){ + boolean isThrough = false; + //格式化RMS源数据 + float startVoltageLevel = voltageLevel * (start / 100F); + float endVoltageLevel = -1; + if(end!=-1){ + endVoltageLevel = voltageLevel * (end / 100F); + } + for (int i = 0; i < newListRmsData.size(); i++) { + for (int j = 1; j < newListRmsData.get(i).size(); j++) { + float curValue = newListRmsData.get(i).get(j); + //当电压达到目标值时 + if(endVoltageLevel != -1 && startVoltageLevel < curValue && curValue <= endVoltageLevel){ + isContinuity(newListRmsData,i+1,newListRmsData.get(i).get(0).intValue(),ms,j); + isThrough = true; + }else if(startVoltageLevel == curValue){ + isContinuity(newListRmsData,i+1,newListRmsData.get(i).get(0).intValue(),ms,j); + isThrough = true; + } + } + } + return isThrough; + } + + private boolean isContinuity(List> newListRmsData,int index,int curms,int ms,int p){ + boolean isContinuity = false; + //记录电压有效毫秒数 + Set effectiveMs = new HashSet<>(); + for (int k = curms + 1 ; k <= curms + ms; k++) { + effectiveMs.add(k); + } + int count = 0; + for (int i = index; i < newListRmsData.size(); i++) { + for (int j = 0; j < newListRmsData.get(i).size(); j++) { + int curVallue = newListRmsData.get(i).get(0).intValue(); + //如果当前相别的电压毫秒数在有效期范围内则记录下数字 + if(effectiveMs.contains(curVallue) && checkListIsNull(newListRmsData.get(i),p)!=null){ + count ++; + } + } + } + if(count >= effectiveMs.size()){ + isContinuity = true; + } + return isContinuity; + } + + private Float checkListIsNull(List list ,int index){ + try { + return list.get(index); + } catch (Exception e) { + return null; + } + } + + //格式化RMS数据:将listRmsData中的电压数据取出在根据pt变比组成新的RMS数据 + private List> listRmsDataFormat(WaveDataDTO waveDataDTO){ + List> newListRmsData = new ArrayList<>(); + List indexs = new ArrayList<>(); + //根据channelNames取出电压对应listRmsData数据中的数据索引 + for (int i = 0; i < waveDataDTO.getChannelNames().size(); i++) { + if(waveDataDTO.getChannelNames().get(i).indexOf("电压")!=-1){ + indexs.add(i); + } + } + //前端展示的波形图数据来源就是这个所以这边也跟前端保持一致 + for (int i = 0; i < waveDataDTO.getListRmsData().size(); i++) { + List cur = waveDataDTO.getListRmsData().get(i); + List newCur = new ArrayList<>(); + //数组第一个为时间 + newCur.add(cur.get(0)); + //便利电压数据的索引 + for(Integer index : indexs){ + //根据PT变比算出新的数据(前端取的一次值,也是根据pt变比算出的,所以这边和前端保持一致)新增到新的数组中 + newCur.add(cur.get(index) * Float.parseFloat((waveDataDTO.getPt() / 1000F)+"")); + } + newListRmsData.add(newCur); + } + return newListRmsData; } //拿到最近一次插入高低电压穿越表信息的时间