From 97157a5ccf057df9642e148f6e4e90074dea8785 Mon Sep 17 00:00:00 2001 From: caozehui <2427765068@qq.com> Date: Mon, 13 Apr 2026 16:28:25 +0800 Subject: [PATCH] =?UTF-8?q?=E5=8F=98=E9=A2=91=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../SocketFreqConverterDevService.java | 267 ++++++++++++++++++ .../handler/SocketFreqConverterService.java | 246 ++++++++++++++++ .../pojo/dto/FreqConverterRespDTO.java | 41 +++ .../pojo/enums/SourceOperateCodeEnum.java | 14 +- .../util/socket/FormalTestManager.java | 3 + .../detection/util/socket/SocketManager.java | 13 +- .../util/socket/cilent/NettyClient.java | 103 +++++++ .../NettyFreqConverterClientHandler.java | 151 ++++++++++ .../NettyFreqConverterDevClientHandler.java | 67 +++++ .../socket/config/SocketConnectionConfig.java | 52 ++-- .../gather/dip/mapper/PqDipDataMapper.java | 11 + .../njcn/gather/dip/pojo/po/PqDipData.java | 44 +++ .../gather/dip/service/IPqDipDataService.java | 11 + .../service/impl/PqDipDataServiceImpl.java | 15 + .../controller/FreqConverterController.java | 98 +++++++ .../mapper/FreqConverterStatusMapper.java | 11 + .../mapper/PqFreqConverterConfigMapper.java | 11 + .../pojo/param/PqFreqConverterParam.java | 66 +++++ .../pojo/po/FreqConverterStatus.java | 37 +++ .../pojo/po/PqFreqConverterConfig.java | 68 +++++ .../pojo/vo/TolerantPointVO.java | 25 ++ .../service/IFreqConverterService.java | 51 ++++ .../IPqFreqConverterConfigService.java | 21 ++ .../impl/FreqConverterServiceImpl.java | 70 +++++ .../PqFreqConverterConfigServiceImpl.java | 43 +++ 25 files changed, 1512 insertions(+), 27 deletions(-) create mode 100644 detection/src/main/java/com/njcn/gather/detection/handler/SocketFreqConverterDevService.java create mode 100644 detection/src/main/java/com/njcn/gather/detection/handler/SocketFreqConverterService.java create mode 100644 detection/src/main/java/com/njcn/gather/detection/pojo/dto/FreqConverterRespDTO.java create mode 100644 detection/src/main/java/com/njcn/gather/detection/util/socket/cilent/NettyFreqConverterClientHandler.java create mode 100644 detection/src/main/java/com/njcn/gather/detection/util/socket/cilent/NettyFreqConverterDevClientHandler.java create mode 100644 detection/src/main/java/com/njcn/gather/dip/mapper/PqDipDataMapper.java create mode 100644 detection/src/main/java/com/njcn/gather/dip/pojo/po/PqDipData.java create mode 100644 detection/src/main/java/com/njcn/gather/dip/service/IPqDipDataService.java create mode 100644 detection/src/main/java/com/njcn/gather/dip/service/impl/PqDipDataServiceImpl.java create mode 100644 detection/src/main/java/com/njcn/gather/freqConverter/controller/FreqConverterController.java create mode 100644 detection/src/main/java/com/njcn/gather/freqConverter/mapper/FreqConverterStatusMapper.java create mode 100644 detection/src/main/java/com/njcn/gather/freqConverter/mapper/PqFreqConverterConfigMapper.java create mode 100644 detection/src/main/java/com/njcn/gather/freqConverter/pojo/param/PqFreqConverterParam.java create mode 100644 detection/src/main/java/com/njcn/gather/freqConverter/pojo/po/FreqConverterStatus.java create mode 100644 detection/src/main/java/com/njcn/gather/freqConverter/pojo/po/PqFreqConverterConfig.java create mode 100644 detection/src/main/java/com/njcn/gather/freqConverter/pojo/vo/TolerantPointVO.java create mode 100644 detection/src/main/java/com/njcn/gather/freqConverter/service/IFreqConverterService.java create mode 100644 detection/src/main/java/com/njcn/gather/freqConverter/service/IPqFreqConverterConfigService.java create mode 100644 detection/src/main/java/com/njcn/gather/freqConverter/service/impl/FreqConverterServiceImpl.java create mode 100644 detection/src/main/java/com/njcn/gather/freqConverter/service/impl/PqFreqConverterConfigServiceImpl.java diff --git a/detection/src/main/java/com/njcn/gather/detection/handler/SocketFreqConverterDevService.java b/detection/src/main/java/com/njcn/gather/detection/handler/SocketFreqConverterDevService.java new file mode 100644 index 00000000..9765264b --- /dev/null +++ b/detection/src/main/java/com/njcn/gather/detection/handler/SocketFreqConverterDevService.java @@ -0,0 +1,267 @@ +package com.njcn.gather.detection.handler; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.collection.ListUtil; +import cn.hutool.core.util.StrUtil; +import com.alibaba.fastjson.JSON; +import com.njcn.gather.detection.pojo.enums.DetectionCodeEnum; +import com.njcn.gather.detection.pojo.enums.SourceOperateCodeEnum; +import com.njcn.gather.detection.pojo.enums.SourceResponseCodeEnum; +import com.njcn.gather.detection.pojo.param.DevPhaseSequenceParam; +import com.njcn.gather.detection.pojo.po.DevData; +import com.njcn.gather.detection.pojo.vo.SocketDataMsg; +import com.njcn.gather.detection.pojo.vo.SocketMsg; +import com.njcn.gather.detection.util.socket.CnSocketUtil; +import com.njcn.gather.detection.util.socket.FormalTestManager; +import com.njcn.gather.detection.util.socket.MsgUtil; +import com.njcn.gather.detection.util.socket.SocketManager; +import com.njcn.gather.detection.util.socket.cilent.NettyClient; +import com.njcn.gather.detection.util.socket.cilent.NettyFreqConverterDevClientHandler; +import com.njcn.gather.detection.util.socket.config.SocketConnectionConfig; +import com.njcn.gather.device.pojo.vo.PreDetection; +import com.njcn.gather.device.service.IPqDevService; +import com.njcn.gather.dip.pojo.po.PqDipData; +import com.njcn.gather.dip.service.IPqDipDataService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import java.time.LocalDateTime; +import java.util.*; +import java.util.concurrent.CompletableFuture; +import java.util.stream.Collectors; + +@Slf4j +@Service +@RequiredArgsConstructor +public class SocketFreqConverterDevService { + + private final SocketConnectionConfig socketConnectionConfig; + private final IPqDevService pqDevService; + private final IPqDipDataService pqDipDataService; + + /** + * 连接设备Socket + * + * @param devTag 设备Channel唯一标识符 + */ + public void connectSocket(String devTag) { + if (SocketManager.isChannelActive(devTag)) { + return; + } + String ip = socketConnectionConfig.getDevice().getIp(); + Integer port = socketConnectionConfig.getDevice().getPort(); + + NettyFreqConverterDevClientHandler handler = new NettyFreqConverterDevClientHandler(devTag, this); + CompletableFuture.runAsync(() -> { + NettyClient.commonConnect(ip, port, devTag, handler); + }); + } + + private void init(String converterId, String monitorId) { + FormalTestManager.freqConverterDevStep = null; + FormalTestManager.stopFlag = false; + } + + /** + * 连接设备 + */ + public void connectionDev(String devTag, String converterId, String monitorId) { + this.init(converterId, monitorId); + + String payload = buildSingleMonitorPayload(monitorId); + if (StrUtil.isBlank(payload)) { + return; + } + + SocketMsg socketMsg = new SocketMsg<>(); + socketMsg.setRequestId(SourceOperateCodeEnum.YJC_SBTXJY.getValue()); + socketMsg.setOperateCode(SourceOperateCodeEnum.DEV_INIT_GATHER_03.getValue()); + socketMsg.setData(payload); + SocketManager.sendMsg(devTag, JSON.toJSONString(socketMsg)); + FormalTestManager.freqConverterDevStep = SourceOperateCodeEnum.YJC_SBTXJY; + } + + public void handleRead(String devTag, String msg) { + SocketDataMsg socketDataMsg = MsgUtil.socketDataMsg(msg); + + switch (FormalTestManager.freqConverterDevStep) { + case YJC_SBTXJY: + handleYjcSbtxjy(devTag, socketDataMsg); + break; + case FORMAL_REAL: + handleFormalReal(devTag, socketDataMsg); + break; + case QUITE: + handleQuit(devTag, socketDataMsg); + break; + } + } + + private void handleYjcSbtxjy(String devTag, SocketDataMsg socketDataMsg) { + SourceResponseCodeEnum responseCodeEnum = SourceResponseCodeEnum.getDictDataEnumByCode(socketDataMsg.getCode()); + switch (Objects.requireNonNull(responseCodeEnum)) { + case SUCCESS: + this.sendGetDipDataMsg(devTag); + FormalTestManager.freqConverterDevStep = SourceOperateCodeEnum.FORMAL_REAL; + break; + default: + log.info("设备响应异常,devTag={}, operateCode={}, code={}, data={}", devTag, socketDataMsg.getOperateCode(), socketDataMsg.getCode(), socketDataMsg.getData()); + break; + } + } + + private void handleFormalReal(String devTag, SocketDataMsg socketDataMsg) { + SourceResponseCodeEnum responseCodeEnum = SourceResponseCodeEnum.getDictDataEnumByCode(socketDataMsg.getCode()); + + switch (responseCodeEnum) { + case UNPROCESSED_BUSINESS: + break; + case SUCCESS: + case NORMAL_RESPONSE: + DevData devData = JSON.parseObject(socketDataMsg.getData(), DevData.class); + // 如果变频器不是处于 “故障中” 状态,就保存数据,反之,这段时期内的数据不保存 + if (!FormalTestManager.stopFlag) { + saveDipData(devData); + } + break; + case DEV_ERROR: + case DEV_TARGET: + case COMMUNICATION_ERR: + case DATA_RESOLVE: + case NO_INIT_DEV: + default: + log.info("设备响应异常,devTag={}, operateCode={}, code={}, data={}", devTag, socketDataMsg.getOperateCode(), socketDataMsg.getCode(), socketDataMsg.getData()); + break; + } + } + + private void handleQuit(String devTag, SocketDataMsg socketDataMsg) { + SourceResponseCodeEnum responseCodeEnum = SourceResponseCodeEnum.getDictDataEnumByCode(socketDataMsg.getCode()); + + switch (responseCodeEnum) { + case SUCCESS: + cleanup(devTag, true); + break; + default: + log.warn("设备关闭响应失败,devTag={}, operateCode={}, code={}, data={}", devTag, socketDataMsg.getOperateCode(), socketDataMsg.getCode(), socketDataMsg.getData()); + break; + } + } + + public void stopTest(String converterTag, String devTag) { + FormalTestManager.freqConverterDevStep = SourceOperateCodeEnum.QUITE; + sendQuitMsg(devTag, SourceOperateCodeEnum.QUIT_INIT_03); + } + + + private String buildSingleMonitorPayload(String monitorId) { + String[] split = monitorId.split(CnSocketUtil.SPLIT_TAG); + if (split.length < 2 || StrUtil.isBlank(split[0]) || StrUtil.isBlank(split[1])) { + return null; + } + + List preDetections = pqDevService.getDevInfo(Collections.singletonList(split[0])); + if (CollUtil.isEmpty(preDetections)) { + return null; + } + + PreDetection preDetection = preDetections.get(0); + List monitorList = preDetection.getMonitorList(); + if (CollUtil.isEmpty(monitorList)) { + return null; + } + + List matchedMonitorList = monitorList.stream() + .filter(item -> split[1].equals(item.getLineId())) + .collect(Collectors.toList()); + if (CollUtil.isEmpty(matchedMonitorList)) { + return null; + } + + preDetection.setMonitorList(matchedMonitorList); + Map> payload = new HashMap<>(1); + payload.put("deviceList", Collections.singletonList(preDetection)); + return JSON.toJSONString(payload); + } + + private void sendGetDipDataMsg(String monitorId) { + SocketMsg socketMsg = new SocketMsg<>(); + socketMsg.setRequestId(SourceOperateCodeEnum.FORMAL_REAL.getValue()); + socketMsg.setOperateCode(SourceOperateCodeEnum.OPER_GATHER.getValue()); + + DevPhaseSequenceParam phaseSequenceParam = new DevPhaseSequenceParam(); + // 设置监测点ID列表 + phaseSequenceParam.setMoniterIdList(ListUtil.of(monitorId)); + + // 设置数据类型列表 + phaseSequenceParam.setDataType(ListUtil.of("avg$MAG", "avg$DUR")); + // 设置读取次数 + phaseSequenceParam.setReadCount(0); + // 设置忽略次数 + phaseSequenceParam.setIgnoreCount(0); + socketMsg.setData(JSON.toJSONString(phaseSequenceParam)); + socketMsg.setOperateCode(SourceOperateCodeEnum.DEV_DATA_REQUEST_03.getValue()); + SocketManager.sendMsg(monitorId, JSON.toJSONString(socketMsg)); + } + + private void sendQuitMsg(String devTag, SourceOperateCodeEnum operateCodeEnum) { + SocketMsg socketMsg = new SocketMsg<>(); + socketMsg.setRequestId(SourceOperateCodeEnum.QUITE.getValue()); + socketMsg.setOperateCode(operateCodeEnum.getValue()); + SocketManager.sendMsg(devTag, JSON.toJSONString(socketMsg)); + } + + private void saveDipData(DevData devData) { + if (Objects.isNull(devData) || CollUtil.isEmpty(devData.getSqlData())) { + return; + } + + Double residualVoltage = null; + Integer durationMs = null; + for (DevData.SqlDataDTO sqlDataDTO : devData.getSqlData()) { + if (Objects.isNull(sqlDataDTO) || Objects.isNull(sqlDataDTO.getList())) { + continue; + } + + Double value = getSqlDataValue(sqlDataDTO.getList()); + if (Objects.isNull(value)) { + continue; + } + + if (DetectionCodeEnum.MAG.getCode().equalsIgnoreCase(sqlDataDTO.getDesc())) { + residualVoltage = value; + } else if (DetectionCodeEnum.DUR.getCode().equalsIgnoreCase(sqlDataDTO.getDesc())) { + durationMs = (int) Math.round(value * 1000); + } + } + + PqDipData pqDipData = new PqDipData(); + pqDipData.setStartTime(LocalDateTime.parse(devData.getTime())); + pqDipData.setResidualVoltage(residualVoltage); + pqDipData.setDurationMs(durationMs); + pqDipDataService.save(pqDipData); + } + + private Double getSqlDataValue(DevData.SqlDataDTO.ListDTO listDTO) { + if (Objects.nonNull(listDTO.getA())) { + return listDTO.getA(); + } + if (Objects.nonNull(listDTO.getB())) { + return listDTO.getB(); + } + if (Objects.nonNull(listDTO.getC())) { + return listDTO.getC(); + } + return listDTO.getT(); + } + + public void cleanup(String devTag, boolean removeSocket) { + FormalTestManager.freqConverterDevStep = null; + if (removeSocket) { + SocketManager.removeUser(devTag); + } else { + SocketManager.clearUser(devTag); + } + } +} diff --git a/detection/src/main/java/com/njcn/gather/detection/handler/SocketFreqConverterService.java b/detection/src/main/java/com/njcn/gather/detection/handler/SocketFreqConverterService.java new file mode 100644 index 00000000..3a30eb03 --- /dev/null +++ b/detection/src/main/java/com/njcn/gather/detection/handler/SocketFreqConverterService.java @@ -0,0 +1,246 @@ +package com.njcn.gather.detection.handler; + +import cn.hutool.core.util.IdUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.json.JSONObject; +import cn.hutool.json.JSONUtil; +import com.alibaba.fastjson.JSON; +import com.njcn.gather.detection.pojo.dto.FreqConverterRespDTO; +import com.njcn.gather.detection.pojo.enums.SourceOperateCodeEnum; +import com.njcn.gather.detection.pojo.vo.SocketMsg; +import com.njcn.gather.detection.util.socket.FormalTestManager; +import com.njcn.gather.detection.util.socket.SocketManager; +import com.njcn.gather.detection.util.socket.cilent.NettyClient; +import com.njcn.gather.detection.util.socket.cilent.NettyFreqConverterClientHandler; +import com.njcn.gather.detection.util.socket.config.SocketConnectionConfig; +import com.njcn.gather.freqConverter.pojo.po.FreqConverterStatus; +import com.njcn.gather.freqConverter.pojo.po.PqFreqConverterConfig; +import com.njcn.gather.freqConverter.service.IFreqConverterService; +import com.njcn.gather.freqConverter.service.IPqFreqConverterConfigService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + +/** + * @author czh + * @version 1.0 + */ +@Slf4j +@Service +@RequiredArgsConstructor +public class SocketFreqConverterService { + private final IFreqConverterService freqConverterService; + + private final SocketConnectionConfig socketConnectionConfig; + + private final IPqFreqConverterConfigService pqFreqConverterConfigService; + + /** + * 连接变频器Socket + * + * @param converterChannelTag 变频器Channel唯一标识符 + */ + public void connectSocket(String converterChannelTag) { + if (SocketManager.isChannelActive(converterChannelTag)) { + return; + } + String ip = socketConnectionConfig.getFreqConverter().getIp(); + Integer port = socketConnectionConfig.getFreqConverter().getPort(); + + NettyFreqConverterClientHandler handler = new NettyFreqConverterClientHandler(converterChannelTag, this); + + CompletableFuture.runAsync(() -> { + NettyClient.commonConnect(ip, port, converterChannelTag, handler); + }); + } + + /** + * 重连 + * + * @param converterChannelTag + */ + public void reconnect(String converterChannelTag) { + SocketManager.removeUser(converterChannelTag); + + String ip = socketConnectionConfig.getFreqConverter().getIp(); + Integer port = socketConnectionConfig.getFreqConverter().getPort(); + + NettyFreqConverterClientHandler handler = new NettyFreqConverterClientHandler(converterChannelTag, this); + + CompletableFuture.runAsync(() -> { + NettyClient.commonConnect(ip, port, converterChannelTag, handler); + }); + } + + /** + * 重试连接成功,重新开启定时任务,获取变频器状态数据 + * + * @param converterChannelTag + */ + public void onReconnectSuccess(String converterChannelTag) { + log.info("变频器重连成功,恢复数据采集,converterChannelTag={}", converterChannelTag); + + FormalTestManager.stopFlag = false; + + if (FormalTestManager.scheduler == null) { + FormalTestManager.scheduler = Executors.newScheduledThreadPool(1); + FormalTestManager.scheduledFuture = FormalTestManager.scheduler.scheduleAtFixedRate(() -> { + this.sendGetDeviceStatusMsg(converterChannelTag); + }, 0l, 200l, TimeUnit.MILLISECONDS); + } + } + + private void init(String converterId, String monitorId) { + FormalTestManager.freqConverterStep = null; + FormalTestManager.pairsIpMap.put(converterId, monitorId); + clearScheduleTask(); + } + + /** + * 连接变频器 + */ + public void connectionFreqConverter(String freqConverterTag, String converterId, String monitorId) { + this.init(converterId, monitorId); + + SocketMsg> socketMsg = new SocketMsg<>(); + socketMsg.setOperateCode(SourceOperateCodeEnum.CMD_INIT_SERIAL.getValue()); + String requestId = IdUtil.fastSimpleUUID(); + socketMsg.setRequestId(requestId); + + PqFreqConverterConfig freqConverterConfig = pqFreqConverterConfigService.getById(converterId); + + Map map = new HashMap<>(); + map.put("portName", freqConverterConfig.getPortName()); + map.put("slaveAddress", freqConverterConfig.getSlaveAddress()); + map.put("baudRate", freqConverterConfig.getBaudRate()); + map.put("parity", freqConverterConfig.getParity()); + map.put("dataBits", freqConverterConfig.getDataBits()); + map.put("stopBits", freqConverterConfig.getStopBits()); + map.put("timeoutMs", freqConverterConfig.getTimeoutMs()); + socketMsg.setData(map); + + SocketManager.sendMsg(freqConverterTag, JSON.toJSONString(socketMsg)); + FormalTestManager.freqConverterStep = SourceOperateCodeEnum.CMD_INIT_SERIAL; + } + + public void handleRead(String converterChannelTag, String msg) { + FreqConverterRespDTO respDTO = JSON.parseObject(msg, FreqConverterRespDTO.class); + + switch (FormalTestManager.freqConverterStep) { + case CMD_INIT_SERIAL: + handleInitSerial(converterChannelTag, respDTO); + break; + case CMD_GET_DEVICE_STATUS: + handleGetDeviceStatus(converterChannelTag, respDTO); + break; + case CMD_CLOSE_SERIAL: + handleCloseSerial(converterChannelTag, respDTO); + break; + } + } + + public void stopTest(String converterTag, String devTag) { + FormalTestManager.freqConverterStep = SourceOperateCodeEnum.CMD_CLOSE_SERIAL; + this.sendClose(converterTag); + } + + public void cleanup(String converterChannelTag, boolean removeSocket) { + clearScheduleTask(); + FormalTestManager.freqConverterStep = null; + if (!removeSocket) { + FormalTestManager.stopFlag = true; + } else { + FormalTestManager.stopFlag = false; + } + FormalTestManager.pairsIpMap.clear(); + if (removeSocket) { + SocketManager.removeUser(converterChannelTag); + } else { + SocketManager.clearUser(converterChannelTag); + } + } + + private void handleInitSerial(String converterChannelTag, FreqConverterRespDTO respDTO) { + if (respDTO.getCode() == 0 && respDTO.getSuccess()) { + FormalTestManager.freqConverterStep = SourceOperateCodeEnum.CMD_GET_DEVICE_STATUS; + freqConverterService.clearAllData(); + if (Objects.isNull(FormalTestManager.scheduler)) { + FormalTestManager.scheduler = Executors.newScheduledThreadPool(1); + FormalTestManager.scheduledFuture = FormalTestManager.scheduler.scheduleAtFixedRate(() -> { + this.sendGetDeviceStatusMsg(converterChannelTag); + }, 0l, 200l, TimeUnit.MILLISECONDS); + } + } else { + log.error("变频器初始化串口失败,converterChannelTag={}, converterId={}, converterTag={}, msg={}", converterChannelTag, converterChannelTag, converterChannelTag, respDTO.getMessage()); + } + } + + private void handleGetDeviceStatus(String converterChannelTag, FreqConverterRespDTO respDTO) { + JSONObject obj = JSONUtil.parseObj(respDTO.getData().toString()); + String timestamp = (String) obj.get("Timestamp"); + timestamp = timestamp.replace("+08:00", StrUtil.EMPTY); + obj.set("Timestamp", timestamp); + + FreqConverterStatus freqConverterStatus = JSON.parseObject(obj.toString(), FreqConverterStatus.class); + // 变频器故障中,移除这段时期内的设备数据 + if (freqConverterStatus.getStatusWord1() == 4) { + FormalTestManager.stopFlag = true; + } else { + FormalTestManager.stopFlag = false; + } + freqConverterService.saveFreqConverterStatus(freqConverterStatus); + } + + private void handleCloseSerial(String converterChannelTag, FreqConverterRespDTO respDTO) { + if (respDTO.getCode() == 0 && respDTO.getSuccess()) { + cleanup(converterChannelTag, true); + } else { + this.sendClose(converterChannelTag); + } + } + + + private void sendGetDeviceStatusMsg(String converterId) { + SocketMsg> socketMsg = new SocketMsg<>(); + socketMsg.setOperateCode(SourceOperateCodeEnum.CMD_GET_DEVICE_STATUS.getValue()); + String requestId = IdUtil.fastSimpleUUID(); + socketMsg.setRequestId(requestId); + + Map map = new HashMap<>(); + socketMsg.setData(map); + SocketManager.sendMsg(converterId, JSON.toJSONString(socketMsg)); + } + + private void sendClose(String converterTag) { + SocketMsg> socketMsg = new SocketMsg<>(); + socketMsg.setOperateCode(SourceOperateCodeEnum.CMD_CLOSE_SERIAL.getValue()); + String requestId = IdUtil.fastSimpleUUID(); + socketMsg.setRequestId(requestId); + + Map map = new HashMap<>(); + socketMsg.setData(map); + SocketManager.sendMsg(converterTag, JSON.toJSONString(socketMsg)); + } + + + private void clearScheduleTask() { + if (FormalTestManager.scheduledFuture != null) { + FormalTestManager.scheduledFuture.cancel(true); + FormalTestManager.scheduledFuture = null; + } + if (FormalTestManager.scheduler != null) { + FormalTestManager.scheduler.shutdown(); + FormalTestManager.scheduler = null; + } + } + +} + + diff --git a/detection/src/main/java/com/njcn/gather/detection/pojo/dto/FreqConverterRespDTO.java b/detection/src/main/java/com/njcn/gather/detection/pojo/dto/FreqConverterRespDTO.java new file mode 100644 index 00000000..fd06628f --- /dev/null +++ b/detection/src/main/java/com/njcn/gather/detection/pojo/dto/FreqConverterRespDTO.java @@ -0,0 +1,41 @@ +package com.njcn.gather.detection.pojo.dto; + +import com.fasterxml.jackson.annotation.JsonAlias; +import lombok.Data; + +/** + * @author caozehui + * @data 2026-04-08 + */ +@Data +public class FreqConverterRespDTO { + /** + * 请求编号 + */ + @JsonAlias({"RequestId"}) + private String requestId; + + /** + * 是否成功 + */ + @JsonAlias({"Success"}) + private Boolean success; + + /** + * 状态码 + */ + @JsonAlias({"Code"}) + private Integer code; + + /** + * 消息 + */ + @JsonAlias({"Message"}) + private String message; + + /** + * 数据 + */ + @JsonAlias({"Data"}) + private Object data; +} diff --git a/detection/src/main/java/com/njcn/gather/detection/pojo/enums/SourceOperateCodeEnum.java b/detection/src/main/java/com/njcn/gather/detection/pojo/enums/SourceOperateCodeEnum.java index 8a5fd050..a4b5fb30 100644 --- a/detection/src/main/java/com/njcn/gather/detection/pojo/enums/SourceOperateCodeEnum.java +++ b/detection/src/main/java/com/njcn/gather/detection/pojo/enums/SourceOperateCodeEnum.java @@ -52,7 +52,7 @@ public enum SourceOperateCodeEnum { YJC_MXYZXJY("yjc_mxyzxjy", "模型一致性校验"), FORMAL_REAL("formal_real","正式检测"), RECORD_WAVE_STEP1("record_wave_step1","启动录波_step1"), -// RECORD_WAVE_STEP2("record_wave_step2","启动录波_step2"), + // RECORD_WAVE_STEP2("record_wave_step2","启动录波_step2"), // SIMULATE_REAL("simulate_real","模拟检测"), Coefficient_Check("Coefficient_Check","系数校验"), QUITE("quit","关闭设备通讯初始化"), @@ -70,9 +70,6 @@ public enum SourceOperateCodeEnum { FLICKER_DATA_CHECK("flicker_data_check","闪变数据校验"), - - - /** * */ @@ -100,12 +97,17 @@ public enum SourceOperateCodeEnum { small_comp_start("small_comp_start","小电压校准开始"), small_comp_end("small_comp_end","小电压校准结束"), - /** * ftp文件传送指令 */ FTP_SEND_01("FTP_SEND$01", "发送文件"), - RDRE$01("RDRE$01", "启动录波"); + RDRE$01("RDRE$01", "启动录波"), + + CMD_PING("ping", "检查 TCP 服务是否在线"), + CMD_INIT_SERIAL("initSerial", "初始化并打开串口连接"), + CMD_GET_SERIAL_CONFIG("getSerialConfig", "获取当前串口配置"), + CMD_GET_DEVICE_STATUS("getDeviceStatus", "读取变频器运行状态"), + CMD_CLOSE_SERIAL("closeSerial", "关闭串口"),; private final String value; private final String msg; diff --git a/detection/src/main/java/com/njcn/gather/detection/util/socket/FormalTestManager.java b/detection/src/main/java/com/njcn/gather/detection/util/socket/FormalTestManager.java index 9ce8d743..7e310de0 100644 --- a/detection/src/main/java/com/njcn/gather/detection/util/socket/FormalTestManager.java +++ b/detection/src/main/java/com/njcn/gather/detection/util/socket/FormalTestManager.java @@ -31,6 +31,9 @@ public class FormalTestManager { // 当前步骤 public static SourceOperateCodeEnum currentStep; + public static SourceOperateCodeEnum freqConverterStep; + public static SourceOperateCodeEnum freqConverterDevStep; + /** * key:设备ip,value:当前设备下面的监测点ID(ip_通道号) */ diff --git a/detection/src/main/java/com/njcn/gather/detection/util/socket/SocketManager.java b/detection/src/main/java/com/njcn/gather/detection/util/socket/SocketManager.java index f8b813c2..c2ecaf62 100644 --- a/detection/src/main/java/com/njcn/gather/detection/util/socket/SocketManager.java +++ b/detection/src/main/java/com/njcn/gather/detection/util/socket/SocketManager.java @@ -81,6 +81,17 @@ public class SocketManager { socketGroup.remove(userId); } + public static void clearUser(String userId) { + Channel channel = socketSessions.remove(userId); + NioEventLoopGroup eventExecutors = socketGroup.remove(userId); + if (ObjectUtil.isNotNull(eventExecutors)) { + eventExecutors.shutdownGracefully(); + } + if (ObjectUtil.isNotNull(channel)) { + log.info("{}__{}已清理客户端会话", userId, channel.id()); + } + } + public static Channel getChannelByUserId(String userId) { return socketSessions.get(userId); } @@ -315,4 +326,4 @@ public class SocketManager { } - \ No newline at end of file + diff --git a/detection/src/main/java/com/njcn/gather/detection/util/socket/cilent/NettyClient.java b/detection/src/main/java/com/njcn/gather/detection/util/socket/cilent/NettyClient.java index eb74ccb3..b421deb8 100644 --- a/detection/src/main/java/com/njcn/gather/detection/util/socket/cilent/NettyClient.java +++ b/detection/src/main/java/com/njcn/gather/detection/util/socket/cilent/NettyClient.java @@ -56,6 +56,109 @@ public class NettyClient { */ private static NettyClient instance; + /** + * 静态方法:智能连接变频器设备(兼容性包装) + * + * @param ip IP地址 + * @param port 端口号 + * @param ChannelId Channel唯一标识 + * @param handler 变频器处理器 + */ + public static void commonConnect(String ip, Integer port, String ChannelId, + SimpleChannelInboundHandler handler) { + if (instance != null) { + instance.executeCommonConnect(ip, port, ChannelId, handler); + } else { + log.error("NettyClient未初始化,无法创建连接"); + } + } + + /** + * 执行变频器Socket连接建立流程 + * + * @param ip 目标服务器IP地址 + * @param port 目标服务器端口号 + * @param ChannelId Channel唯一标识id + * @param handler 变频器业务处理器 + */ + private static void executeCommonConnect(String ip, Integer port, + String ChannelId, + SimpleChannelInboundHandler handler) { + NioEventLoopGroup group = createEventLoopGroup(); + + try { + Bootstrap bootstrap = configureBootstrap(group); + ChannelInitializer initializer = createCommonChannelInitializer(ChannelId, handler); + bootstrap.handler(initializer); + ChannelFuture channelFuture = bootstrap.connect(ip, port).sync(); + handleCommonConnectionResult(channelFuture, ChannelId, handler, group); + } catch (Exception e) { + handleCommonConnectionException(e, ChannelId, handler, group); + } + } + + /** + * 创建通用通道初始化器 + * + * @param channelId Channel唯一标识id + * @param handler 通用业务处理器 + * @return ChannelInitializer 通道初始化器 + */ + private static ChannelInitializer createCommonChannelInitializer( + String channelId, SimpleChannelInboundHandler handler) { + return new ChannelInitializer() { + @Override + protected void initChannel(NioSocketChannel ch) { + ch.pipeline() + .addLast(new LineBasedFrameDecoder(10240 * 2)) + .addLast(new StringDecoder(CharsetUtil.UTF_8)) + .addLast(new StringEncoder(CharsetUtil.UTF_8)) + .addLast(new IdleStateHandler(60, 0, 0, TimeUnit.SECONDS)) + .addLast(handler); + } + }; + } + + /** + * 处理通用连接结果 + * + * @param channelFuture 连接Future对象 + * @param channelId Channel唯一标识符 + * @param handler 通用业务处理器 + * @param group 事件循环组 + */ + private static void handleCommonConnectionResult(ChannelFuture channelFuture, + String channelId, + SimpleChannelInboundHandler handler, + NioEventLoopGroup group) { + channelFuture.addListener((ChannelFutureListener) ch -> { + if (!ch.isSuccess()) { + log.error("连接Socket失败,channelId={}", channelId); + group.shutdownGracefully(); + } else { + log.info("连接Socket成功,channel={}, channelId={}", + channelId, channelFuture.channel().id()); + SocketManager.addGroup(channelId, group); + SocketManager.addUser(channelId, channelFuture.channel()); + } + }); + } + + /** + * 处理通用连接异常 + * + * @param e 异常对象 + * @param channelId Channel唯一标识id + * @param handler 通用业务处理器 + * @param group 事件循环组 + */ + private static void handleCommonConnectionException(Exception e, String channelId, + SimpleChannelInboundHandler handler, + NioEventLoopGroup group) { + log.error("连接Socket服务端发生异常,channelId={}, error={}", channelId, e.getMessage(), e); + group.shutdownGracefully(); + } + @PostConstruct public void init() { diff --git a/detection/src/main/java/com/njcn/gather/detection/util/socket/cilent/NettyFreqConverterClientHandler.java b/detection/src/main/java/com/njcn/gather/detection/util/socket/cilent/NettyFreqConverterClientHandler.java new file mode 100644 index 00000000..d2a8b727 --- /dev/null +++ b/detection/src/main/java/com/njcn/gather/detection/util/socket/cilent/NettyFreqConverterClientHandler.java @@ -0,0 +1,151 @@ +package com.njcn.gather.detection.util.socket.cilent; + +import cn.hutool.core.util.StrUtil; +import com.njcn.gather.detection.handler.SocketFreqConverterService; +import com.njcn.gather.detection.util.socket.FormalTestManager; +import com.njcn.gather.detection.util.socket.SocketManager; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.SimpleChannelInboundHandler; +import io.netty.handler.timeout.IdleState; +import io.netty.handler.timeout.IdleStateEvent; +import lombok.extern.slf4j.Slf4j; + +/** + * 变频器Netty客户端处理器 + */ +@Slf4j +public class NettyFreqConverterClientHandler extends SimpleChannelInboundHandler { + + /** + * 变频器Channel唯一标识符 + */ + private final String converterChannelTag; + + + /** + * 变频器Socket响应服务 + */ + private final SocketFreqConverterService socketFreqConverterService; + + /** + * 重连次数 + */ + private int reconnectAttempts = 0; + + /** + * 最大重连次数 + */ + private static final int MAX_RECONNECT_ATTEMPTS = 3; + + /** + * 重连间隔(毫秒) + */ + private static final long RECONNECT_INTERVAL_MS = 5000; + + /** + * 是否正在重连 + */ + private volatile boolean isReconnecting = false; + + /** + * 构造方法 + * + * @param converterChannelTag 变频器Chanel唯一标识符 + * @param socketFreqConverterService 变频器Socket响应服务 + */ + public NettyFreqConverterClientHandler(String converterChannelTag, SocketFreqConverterService socketFreqConverterService) { + this.converterChannelTag = converterChannelTag; + this.socketFreqConverterService = socketFreqConverterService; + } + + @Override + public void channelActive(ChannelHandlerContext ctx) throws Exception { + log.info("变频器连接已建立,converterChannelTag={}, channelId={}", converterChannelTag, ctx.channel().id()); + + // 注册Channel到SocketManager + SocketManager.addUser(converterChannelTag, ctx.channel()); + + if (reconnectAttempts > 0) { + log.info("变频器重连成功,converterChannelTag={}, 重连次数={}", converterChannelTag, reconnectAttempts); + reconnectAttempts = 0; + isReconnecting = false; + FormalTestManager.stopFlag = false; + socketFreqConverterService.onReconnectSuccess(converterChannelTag); + } + + super.channelActive(ctx); + } + + @Override + protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception { + if (StrUtil.isBlank(msg)) { + log.debug("收到空消息,忽略,converterChannelTag={}", converterChannelTag); + return; + } + + log.info("收到变频器消息,converterChannelTag={}, msg={}", converterChannelTag, msg); + + // 处理状态数据 + socketFreqConverterService.handleRead(converterChannelTag, msg); + } + + @Override + public void channelInactive(ChannelHandlerContext ctx) throws Exception { + log.warn("变频器连接已断开,converterChannelTag={}", converterChannelTag); + + socketFreqConverterService.cleanup(converterChannelTag, false); + + if (!isReconnecting && reconnectAttempts < MAX_RECONNECT_ATTEMPTS) { + attemptReconnect(ctx); + } else if (reconnectAttempts >= MAX_RECONNECT_ATTEMPTS) { + log.error("变频器重连失败,已达到最大重连次数{}次,converterChannelTag={}", MAX_RECONNECT_ATTEMPTS, converterChannelTag); + FormalTestManager.stopFlag = true; + } + + super.channelInactive(ctx); + } + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { + log.error("变频器连接发生异常,converterChannelTag={}, error={}", converterChannelTag, cause.getMessage(), cause); + FormalTestManager.stopFlag = true; + log.warn("变频器连接异常,设置stopFlag=true,设备数据将不再入库"); + ctx.close(); + } + + @Override + public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { + if (evt instanceof IdleStateEvent) { + IdleStateEvent event = (IdleStateEvent) evt; + if (event.state() == IdleState.READER_IDLE) { + log.warn("变频器连接读空闲,converterChannelTag={}", converterChannelTag); + // 可以选择发送心跳或关闭连接 + } + } + super.userEventTriggered(ctx, evt); + } + + private void attemptReconnect(ChannelHandlerContext ctx) { + isReconnecting = true; + reconnectAttempts++; + + log.info("准备重连变频器,converterChannelTag={}, 第{}/{}次重连,{}秒后开始", + converterChannelTag, reconnectAttempts, MAX_RECONNECT_ATTEMPTS, RECONNECT_INTERVAL_MS / 1000); + + ctx.executor().schedule(() -> { + try { + log.info("开始执行变频器重连,converterChannelTag={}", converterChannelTag); + socketFreqConverterService.reconnect(converterChannelTag); + } catch (Exception e) { + log.error("变频器重连触发失败,converterChannelTag={}, error={}", converterChannelTag, e.getMessage(), e); + isReconnecting = false; + + if (reconnectAttempts < MAX_RECONNECT_ATTEMPTS) { + log.warn("将在{}秒后进行下一次重试", RECONNECT_INTERVAL_MS / 1000); + ctx.executor().schedule(() -> attemptReconnect(ctx), RECONNECT_INTERVAL_MS, java.util.concurrent.TimeUnit.MILLISECONDS); + } + } + }, RECONNECT_INTERVAL_MS, java.util.concurrent.TimeUnit.MILLISECONDS); + } +} + diff --git a/detection/src/main/java/com/njcn/gather/detection/util/socket/cilent/NettyFreqConverterDevClientHandler.java b/detection/src/main/java/com/njcn/gather/detection/util/socket/cilent/NettyFreqConverterDevClientHandler.java new file mode 100644 index 00000000..ab33cb96 --- /dev/null +++ b/detection/src/main/java/com/njcn/gather/detection/util/socket/cilent/NettyFreqConverterDevClientHandler.java @@ -0,0 +1,67 @@ +package com.njcn.gather.detection.util.socket.cilent; + +import com.njcn.gather.detection.handler.SocketFreqConverterDevService; +import com.njcn.gather.detection.util.socket.FormalTestManager; +import com.njcn.gather.detection.util.socket.SocketManager; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.SimpleChannelInboundHandler; +import io.netty.handler.timeout.IdleState; +import io.netty.handler.timeout.IdleStateEvent; +import lombok.extern.slf4j.Slf4j; + +/** + * 设备 Netty 客户端处理器 + */ +@Slf4j +public class NettyFreqConverterDevClientHandler extends SimpleChannelInboundHandler { + + private final String devChannelTag; + private final SocketFreqConverterDevService socketFreqConverterDevService; + + public NettyFreqConverterDevClientHandler(String devChannelTag, SocketFreqConverterDevService socketFreqConverterDevService) { + this.devChannelTag = devChannelTag; + this.socketFreqConverterDevService = socketFreqConverterDevService; + } + + @Override + public void channelActive(ChannelHandlerContext ctx) throws Exception { + log.info("设备连接已建立,devChannelTag={}, channelId={}", devChannelTag, ctx.channel().id()); + SocketManager.addUser(devChannelTag, ctx.channel()); + super.channelActive(ctx); + } + + @Override + protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception { + if (FormalTestManager.stopFlag) { + log.debug("变频器异常或重连中,丢弃设备数据,devChannelTag={}, msg={}", devChannelTag, msg); + return; + } + + log.info("收到设备消息,devChannelTag={}, msg={}", devChannelTag, msg); + socketFreqConverterDevService.handleRead(devChannelTag, msg); + } + + @Override + public void channelInactive(ChannelHandlerContext ctx) throws Exception { + log.warn("设备连接已断开,devChannelTag={}", devChannelTag); + socketFreqConverterDevService.cleanup(devChannelTag, false); + super.channelInactive(ctx); + } + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { + log.error("设备连接发生异常,devChannelTag={}, error={}", devChannelTag, cause.getMessage(), cause); + ctx.close(); + } + + @Override + public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { + if (evt instanceof IdleStateEvent) { + IdleStateEvent event = (IdleStateEvent) evt; + if (event.state() == IdleState.READER_IDLE) { + log.warn("设备连接读空闲,devChannelTag={}", devChannelTag); + } + } + super.userEventTriggered(ctx, evt); + } +} diff --git a/detection/src/main/java/com/njcn/gather/detection/util/socket/config/SocketConnectionConfig.java b/detection/src/main/java/com/njcn/gather/detection/util/socket/config/SocketConnectionConfig.java index f053029e..8c3565d5 100644 --- a/detection/src/main/java/com/njcn/gather/detection/util/socket/config/SocketConnectionConfig.java +++ b/detection/src/main/java/com/njcn/gather/detection/util/socket/config/SocketConnectionConfig.java @@ -18,29 +18,21 @@ import java.util.Set; @Component @ConfigurationProperties(prefix = "socket") public class SocketConnectionConfig { + /** + * 被检设备配置 + */ + private DeviceConfig device = new DeviceConfig(); /** * 程控源设备配置 */ private SourceConfig source = new SourceConfig(); - /** - * 被检设备配置 - */ - private DeviceConfig device = new DeviceConfig(); - @Data - public static class SourceConfig { - /** - * 程控源IP地址 - */ - private String ip; - - /** - * 程控源端口号 - */ - private Integer port; - } + /** + * 变频器配置 + */ + private DeviceConfig freqConverter = new DeviceConfig(); @Data public static class DeviceConfig { @@ -48,13 +40,33 @@ public class SocketConnectionConfig { * 被检设备IP地址 */ private String ip; - + /** * 被检设备端口号 */ private Integer port; } + @Data + public static class SourceConfig { + /** + * 程控源IP地址 + */ + private String ip; + + /** + * 程控源端口号 + */ + private Integer port; + } + + /** + * 获取被检设备配置 + */ + public DeviceConfig getDevice() { + return device; + } + /** * 获取程控源配置 */ @@ -63,10 +75,10 @@ public class SocketConnectionConfig { } /** - * 获取被检设备配置 + * 获取变频器配置 */ - public DeviceConfig getDevice() { - return device; + public DeviceConfig getFreqConverter() { + return freqConverter; } /** diff --git a/detection/src/main/java/com/njcn/gather/dip/mapper/PqDipDataMapper.java b/detection/src/main/java/com/njcn/gather/dip/mapper/PqDipDataMapper.java new file mode 100644 index 00000000..83ac7cf6 --- /dev/null +++ b/detection/src/main/java/com/njcn/gather/dip/mapper/PqDipDataMapper.java @@ -0,0 +1,11 @@ +package com.njcn.gather.dip.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.njcn.gather.dip.pojo.po.PqDipData; + +/** + * @author caozehui + * @date 2026-04-09 + */ +public interface PqDipDataMapper extends BaseMapper { +} diff --git a/detection/src/main/java/com/njcn/gather/dip/pojo/po/PqDipData.java b/detection/src/main/java/com/njcn/gather/dip/pojo/po/PqDipData.java new file mode 100644 index 00000000..9f72dc7f --- /dev/null +++ b/detection/src/main/java/com/njcn/gather/dip/pojo/po/PqDipData.java @@ -0,0 +1,44 @@ +package com.njcn.gather.dip.pojo.po; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.njcn.db.mybatisplus.bo.BaseEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + * 电压暂降数据 + * + * @author caozehui + * @date 2026-04-09 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("pq_dip_data") +public class PqDipData extends BaseEntity implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * 主键ID + */ + private String id; + + /** + * 起始时间戳 + */ + private LocalDateTime startTime; + + /** + * 残余电压,单位:%Ur + */ + private Double residualVoltage; + + /** + * + * 持续时间,单位:ms + */ + private Integer durationMs; +} diff --git a/detection/src/main/java/com/njcn/gather/dip/service/IPqDipDataService.java b/detection/src/main/java/com/njcn/gather/dip/service/IPqDipDataService.java new file mode 100644 index 00000000..d851f0c1 --- /dev/null +++ b/detection/src/main/java/com/njcn/gather/dip/service/IPqDipDataService.java @@ -0,0 +1,11 @@ +package com.njcn.gather.dip.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.njcn.gather.dip.pojo.po.PqDipData; + +/** + * @author caozehui + * @date 2026-04-09 + */ +public interface IPqDipDataService extends IService { +} diff --git a/detection/src/main/java/com/njcn/gather/dip/service/impl/PqDipDataServiceImpl.java b/detection/src/main/java/com/njcn/gather/dip/service/impl/PqDipDataServiceImpl.java new file mode 100644 index 00000000..1111c307 --- /dev/null +++ b/detection/src/main/java/com/njcn/gather/dip/service/impl/PqDipDataServiceImpl.java @@ -0,0 +1,15 @@ +package com.njcn.gather.dip.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.njcn.gather.dip.mapper.PqDipDataMapper; +import com.njcn.gather.dip.pojo.po.PqDipData; +import com.njcn.gather.dip.service.IPqDipDataService; +import org.springframework.stereotype.Service; + +/** + * @author caozehui + * @date 2026-04-09 + */ +@Service +public class PqDipDataServiceImpl extends ServiceImpl implements IPqDipDataService { +} diff --git a/detection/src/main/java/com/njcn/gather/freqConverter/controller/FreqConverterController.java b/detection/src/main/java/com/njcn/gather/freqConverter/controller/FreqConverterController.java new file mode 100644 index 00000000..331fec5a --- /dev/null +++ b/detection/src/main/java/com/njcn/gather/freqConverter/controller/FreqConverterController.java @@ -0,0 +1,98 @@ +package com.njcn.gather.freqConverter.controller; + +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.njcn.common.pojo.annotation.OperateInfo; +import com.njcn.common.pojo.constant.OperateType; +import com.njcn.common.pojo.enums.response.CommonResponseEnum; +import com.njcn.common.pojo.response.HttpResult; +import com.njcn.common.utils.LogUtil; +import com.njcn.gather.device.pojo.param.PqDevParam; +import com.njcn.gather.freqConverter.pojo.param.PqFreqConverterParam; +import com.njcn.gather.freqConverter.pojo.po.PqFreqConverterConfig; +import com.njcn.gather.freqConverter.service.IFreqConverterService; +import com.njcn.gather.freqConverter.service.IPqFreqConverterConfigService; +import com.njcn.web.controller.BaseController; +import com.njcn.web.utils.HttpResultUtil; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiImplicitParam; +import io.swagger.annotations.ApiOperation; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * @author caozehui + * @data 2026-04-13 + */ +@Slf4j +@Api(tags = "变频器") +@RestController +@RequestMapping("/freqConverter") +@RequiredArgsConstructor +public class FreqConverterController extends BaseController { + private final IFreqConverterService freqConverterService; + private final IPqFreqConverterConfigService pqFreqConverterConfigService; + + + @OperateInfo + @PostMapping("/list") + @ApiOperation("分页查询变频器列表") + @ApiImplicitParam(name = "queryParam", value = "查询参数", required = true) + public HttpResult> list(@RequestBody @Validated PqFreqConverterParam.QueryParam queryParam) { + String methodDescribe = getMethodDescribe("list"); + LogUtil.njcnDebug(log, "{},查询数据为:{}", methodDescribe, queryParam); + Page result = pqFreqConverterConfigService.listPqFreqConverterConfigs(queryParam); + return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, result, methodDescribe); + } + + @OperateInfo(operateType = OperateType.ADD) + @PostMapping("/add") + @ApiOperation("新增变频器") + @ApiImplicitParam(name = "pqDevParam", value = "被检设备", required = true) + public HttpResult add(@RequestBody @Validated PqFreqConverterParam param) { + String methodDescribe = getMethodDescribe("add"); + LogUtil.njcnDebug(log, "{},新增数据为:{}", methodDescribe, param); + boolean result = pqFreqConverterConfigService.addPqFreqConverterConfig(param); + if (result) { + return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, true, methodDescribe); + } else { + return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.FAIL, false, methodDescribe); + } + } + + @OperateInfo(operateType = OperateType.UPDATE) + @PostMapping("/update") + @ApiOperation("修改变频器") + @ApiImplicitParam(name = "updateParam", value = "被检设备", required = true) + public HttpResult update(@RequestBody @Validated PqFreqConverterParam.UpdateParam param) { + String methodDescribe = getMethodDescribe("update"); + LogUtil.njcnDebug(log, "{},修改数据为:{}", methodDescribe, param); + boolean result = pqFreqConverterConfigService.updatePqFreqConverterConfig(param); + if (result) { + return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, true, methodDescribe); + } else { + return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.FAIL, false, methodDescribe); + } + } + + @OperateInfo(operateType = OperateType.DELETE) + @PostMapping("/delete") + @ApiOperation("删除变频器") + @ApiImplicitParam(name = "param", value = "删除参数", required = true) + public HttpResult delete(@RequestBody @Validated PqDevParam.DeleteParam param) { + String methodDescribe = getMethodDescribe("delete"); + LogUtil.njcnDebug(log, "{},删除ID数据为:{}", methodDescribe, String.join(StrUtil.COMMA, param.getIds())); + boolean result = pqFreqConverterConfigService.deletePqFreqConverterConfig(param); + if (result) { + return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, true, methodDescribe); + } else { + return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.FAIL, false, methodDescribe); + } + } + +} diff --git a/detection/src/main/java/com/njcn/gather/freqConverter/mapper/FreqConverterStatusMapper.java b/detection/src/main/java/com/njcn/gather/freqConverter/mapper/FreqConverterStatusMapper.java new file mode 100644 index 00000000..5c9a9958 --- /dev/null +++ b/detection/src/main/java/com/njcn/gather/freqConverter/mapper/FreqConverterStatusMapper.java @@ -0,0 +1,11 @@ +package com.njcn.gather.freqConverter.mapper; + +import com.github.yulichang.base.MPJBaseMapper; +import com.njcn.gather.freqConverter.pojo.po.FreqConverterStatus; + +/** + * @author caozehui + * @data 2026-04-07 + */ +public interface FreqConverterStatusMapper extends MPJBaseMapper { +} diff --git a/detection/src/main/java/com/njcn/gather/freqConverter/mapper/PqFreqConverterConfigMapper.java b/detection/src/main/java/com/njcn/gather/freqConverter/mapper/PqFreqConverterConfigMapper.java new file mode 100644 index 00000000..4528bd62 --- /dev/null +++ b/detection/src/main/java/com/njcn/gather/freqConverter/mapper/PqFreqConverterConfigMapper.java @@ -0,0 +1,11 @@ +package com.njcn.gather.freqConverter.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.njcn.gather.freqConverter.pojo.po.PqFreqConverterConfig; + +/** + * @author caozehui + * @data 2026-04-08 + */ +public interface PqFreqConverterConfigMapper extends BaseMapper { +} diff --git a/detection/src/main/java/com/njcn/gather/freqConverter/pojo/param/PqFreqConverterParam.java b/detection/src/main/java/com/njcn/gather/freqConverter/pojo/param/PqFreqConverterParam.java new file mode 100644 index 00000000..90dd0551 --- /dev/null +++ b/detection/src/main/java/com/njcn/gather/freqConverter/pojo/param/PqFreqConverterParam.java @@ -0,0 +1,66 @@ +package com.njcn.gather.freqConverter.pojo.param; + +import com.njcn.common.pojo.constant.PatternRegex; +import com.njcn.gather.device.pojo.param.PqDevParam; +import com.njcn.gather.pojo.constant.DetectionValidMessage; +import com.njcn.web.pojo.param.BaseParam; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.Pattern; + +/** + * @author caozehui + * @data 2026-04-13 + */ +@Data +public class PqFreqConverterParam { + @ApiModelProperty(value = "名称", required = true) + private String name; + + @ApiModelProperty(value = "电脑串口名", required = true) + private String portName; + + @ApiModelProperty(value = "变频器设置从机地址", required = true) + private Integer slaveAddress; + + @ApiModelProperty(value = "变频器设置波特率", required = true) + private Integer baudRate; + + @ApiModelProperty(value = "奇偶校验类型: None, Even, Odd", required = true) + private String parity; + + @ApiModelProperty(value = "变频器数据位", required = true) + private Integer dataBits; + + @ApiModelProperty(value = "变频器停止位,当前只支持 1 或 2", required = true) + private Integer stopBits; + + @ApiModelProperty(value = "串口读写超时,单位毫秒", required = true) + private Integer timeoutMs; + + /** + * 分页查询实体 + */ + @Data + @EqualsAndHashCode(callSuper = true) + public static class QueryParam extends BaseParam { + @ApiModelProperty(value = "名称", required = true) + private String name; + } + + /** + * 更新操作实体 + */ + @Data + @EqualsAndHashCode(callSuper = true) + public static class UpdateParam extends PqDevParam { + + @ApiModelProperty(value = "id", required = true) + @NotBlank(message = DetectionValidMessage.ID_NOT_BLANK) + @Pattern(regexp = PatternRegex.SYSTEM_ID, message = DetectionValidMessage.ID_FORMAT_ERROR) + private String id; + } +} diff --git a/detection/src/main/java/com/njcn/gather/freqConverter/pojo/po/FreqConverterStatus.java b/detection/src/main/java/com/njcn/gather/freqConverter/pojo/po/FreqConverterStatus.java new file mode 100644 index 00000000..eb4e73f0 --- /dev/null +++ b/detection/src/main/java/com/njcn/gather/freqConverter/pojo/po/FreqConverterStatus.java @@ -0,0 +1,37 @@ +package com.njcn.gather.freqConverter.pojo.po; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.njcn.db.mybatisplus.bo.BaseEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + * @author caozehui + * @data 2026-04-07 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("pq_freq_converter_status") +public class FreqConverterStatus extends BaseEntity implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * 主键ID + */ + private String id; + + private Integer slaveAddress; + + private Integer statusWord1; + + private String statusWord1Hex; + + /** + * 状态记录时刻(时间戳) + */ + private LocalDateTime timestamp; +} \ No newline at end of file diff --git a/detection/src/main/java/com/njcn/gather/freqConverter/pojo/po/PqFreqConverterConfig.java b/detection/src/main/java/com/njcn/gather/freqConverter/pojo/po/PqFreqConverterConfig.java new file mode 100644 index 00000000..edce073b --- /dev/null +++ b/detection/src/main/java/com/njcn/gather/freqConverter/pojo/po/PqFreqConverterConfig.java @@ -0,0 +1,68 @@ +package com.njcn.gather.freqConverter.pojo.po; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.njcn.db.mybatisplus.bo.BaseEntity; +import lombok.Data; + +/** + * 变频器配置实体类 + */ +@Data +@TableName("pq_freq_converter_config") +public class PqFreqConverterConfig extends BaseEntity { + + /** + * 主键ID + */ + private String id; + + /** + * 变频器名称 + */ + private String name; + + /** + * 电脑串口名,如COM1 + */ + private String portName; + + /** + * 变频器设置从机地址,范围1~127 + */ + private Integer slaveAddress; + + /** + * 变频器设置波特率,如19200 + */ + private Integer baudRate; + + /** + * 奇偶校验类型: None, Even, Odd + */ + private String parity; + + /** + * 变频器数据位 + */ + private Integer dataBits; + + /** + * 变频器停止位,当前只支持 1 或 2 + */ + private Integer stopBits; + + /** + * 串口读写超时,单位毫秒 + */ + private Integer timeoutMs; + + /** + * 数据表后缀 + */ + private Integer suffix; + + /** + * 状态:0-删除 1-正常 + */ + private Integer state; +} \ No newline at end of file diff --git a/detection/src/main/java/com/njcn/gather/freqConverter/pojo/vo/TolerantPointVO.java b/detection/src/main/java/com/njcn/gather/freqConverter/pojo/vo/TolerantPointVO.java new file mode 100644 index 00000000..2b8efa50 --- /dev/null +++ b/detection/src/main/java/com/njcn/gather/freqConverter/pojo/vo/TolerantPointVO.java @@ -0,0 +1,25 @@ +package com.njcn.gather.freqConverter.pojo.vo; + +import lombok.Data; + +/** + * @author caozehui + * @data 2026-04-13 + */ +@Data +public class TolerantPointVO { + /** + * 持续时间,单位ms + */ + private Integer durationMs; + + /** + * 残余电压,单位:%Ur + */ + private Double residualVoltage; + + /** + * 是否耐受 + */ + private boolean tolerant; +} diff --git a/detection/src/main/java/com/njcn/gather/freqConverter/service/IFreqConverterService.java b/detection/src/main/java/com/njcn/gather/freqConverter/service/IFreqConverterService.java new file mode 100644 index 00000000..68c26eaa --- /dev/null +++ b/detection/src/main/java/com/njcn/gather/freqConverter/service/IFreqConverterService.java @@ -0,0 +1,51 @@ +package com.njcn.gather.freqConverter.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.njcn.gather.dip.pojo.po.PqDipData; +import com.njcn.gather.freqConverter.pojo.po.FreqConverterStatus; +import com.njcn.gather.freqConverter.pojo.vo.TolerantPointVO; + +import java.util.List; + +/** + * @author caozehui + * @data 2026-04-07 + */ +public interface IFreqConverterService extends IService { + + + /** + * 保存变频器状态数据 + * + * @param status 变频器状态数据 + * @return 是否保存成功 + */ + boolean saveFreqConverterStatus(FreqConverterStatus status); + + + /** + * 查询指定变频器的状态历史 + * + * @param converterId 变频器ID + * @return 状态数据列表 + */ + List listStatusHistory(String converterId); + + /** + * 清空所有数据 + * + * @return + */ + boolean clearAllData(); + + /** + * 根据设备暂降数据判断变频器是否耐受 + * + * @param freqConverterDataList 变频器数据集合 + * @param dipDataList 设备暂降数据集合 + * @return 是否耐受 + */ + List getTolerantPoints(List freqConverterDataList, List dipDataList); + + +} diff --git a/detection/src/main/java/com/njcn/gather/freqConverter/service/IPqFreqConverterConfigService.java b/detection/src/main/java/com/njcn/gather/freqConverter/service/IPqFreqConverterConfigService.java new file mode 100644 index 00000000..8ddd0be9 --- /dev/null +++ b/detection/src/main/java/com/njcn/gather/freqConverter/service/IPqFreqConverterConfigService.java @@ -0,0 +1,21 @@ +package com.njcn.gather.freqConverter.service; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.IService; +import com.njcn.gather.device.pojo.param.PqDevParam; +import com.njcn.gather.freqConverter.pojo.param.PqFreqConverterParam; +import com.njcn.gather.freqConverter.pojo.po.PqFreqConverterConfig; + +/** + * @author caozehui + * @data 2026-04-08 + */ +public interface IPqFreqConverterConfigService extends IService { + Page listPqFreqConverterConfigs(PqFreqConverterParam.QueryParam queryParam); + + boolean addPqFreqConverterConfig(PqFreqConverterParam param); + + boolean updatePqFreqConverterConfig(PqFreqConverterParam.UpdateParam param); + + boolean deletePqFreqConverterConfig(PqDevParam.DeleteParam param); +} diff --git a/detection/src/main/java/com/njcn/gather/freqConverter/service/impl/FreqConverterServiceImpl.java b/detection/src/main/java/com/njcn/gather/freqConverter/service/impl/FreqConverterServiceImpl.java new file mode 100644 index 00000000..a24e44f8 --- /dev/null +++ b/detection/src/main/java/com/njcn/gather/freqConverter/service/impl/FreqConverterServiceImpl.java @@ -0,0 +1,70 @@ +package com.njcn.gather.freqConverter.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.njcn.gather.dip.pojo.po.PqDipData; +import com.njcn.gather.freqConverter.mapper.FreqConverterStatusMapper; +import com.njcn.gather.freqConverter.pojo.po.FreqConverterStatus; +import com.njcn.gather.freqConverter.pojo.vo.TolerantPointVO; +import com.njcn.gather.freqConverter.service.IFreqConverterService; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; + +/** + * 变频器状态数据Service实现类 + *

+ * 实现变频器状态数据的存储、查询和清理功能。 + * 当数据量超过阈值时,自动清理无效或过期数据,避免内存和数据库资源浪费。 + *

+ * + * @author CN_Gather Detection Team + * @version 1.0 + * @since 2026 + */ +@Service +public class FreqConverterServiceImpl extends ServiceImpl implements IFreqConverterService { + + @Override + @Transactional(rollbackFor = Exception.class) + public boolean saveFreqConverterStatus(FreqConverterStatus status) { + return this.save(status); + } + + @Override + public List listStatusHistory(String converterId) { + return this.lambdaQuery().list(); + } + + @Override + public boolean clearAllData() { + return this.remove(null); + } + + @Override + public List getTolerantPoints(List freqConverterDataList, List dipDataList) { + dipDataList.sort(Comparator.comparing(PqDipData::getDurationMs)); + + List res = new ArrayList<>(); + for (PqDipData dipData : dipDataList) { + TolerantPointVO tolerantPointVO = new TolerantPointVO(); + tolerantPointVO.setDurationMs(dipData.getDurationMs()); + tolerantPointVO.setResidualVoltage(dipData.getResidualVoltage()); + LocalDateTime dipEndTime = dipData.getStartTime().plusNanos(dipData.getDurationMs() * 1_000_000L); + FreqConverterStatus nextStatus = freqConverterDataList.stream() + .filter(item -> item.getTimestamp() != null && !item.getTimestamp().isBefore(dipEndTime)) + .min(Comparator.comparing(FreqConverterStatus::getTimestamp)) + .orElse(null); + if (nextStatus == null || nextStatus.getStatusWord1() == null || nextStatus.getStatusWord1() != 4) { + tolerantPointVO.setTolerant(true); + } else { + tolerantPointVO.setTolerant(false); + } + res.add(tolerantPointVO); + } + return res; + } +} diff --git a/detection/src/main/java/com/njcn/gather/freqConverter/service/impl/PqFreqConverterConfigServiceImpl.java b/detection/src/main/java/com/njcn/gather/freqConverter/service/impl/PqFreqConverterConfigServiceImpl.java new file mode 100644 index 00000000..056ca49f --- /dev/null +++ b/detection/src/main/java/com/njcn/gather/freqConverter/service/impl/PqFreqConverterConfigServiceImpl.java @@ -0,0 +1,43 @@ +package com.njcn.gather.freqConverter.service.impl; + +import cn.hutool.core.bean.BeanUtil; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.njcn.gather.device.pojo.param.PqDevParam; +import com.njcn.gather.freqConverter.mapper.PqFreqConverterConfigMapper; +import com.njcn.gather.freqConverter.pojo.param.PqFreqConverterParam; +import com.njcn.gather.freqConverter.pojo.po.PqFreqConverterConfig; +import com.njcn.gather.freqConverter.service.IPqFreqConverterConfigService; +import org.springframework.stereotype.Service; + +/** + * @author caozehui + * @data 2026-04-08 + */ +@Service +public class PqFreqConverterConfigServiceImpl extends ServiceImpl implements IPqFreqConverterConfigService { + @Override + public Page listPqFreqConverterConfigs(PqFreqConverterParam.QueryParam queryParam) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.like("name", queryParam.getName()); + return this.page(new Page<>(queryParam.getPageNum(), queryParam.getPageSize()), queryWrapper); + } + + @Override + public boolean addPqFreqConverterConfig(PqFreqConverterParam param) { + PqFreqConverterConfig pqFreqConverterConfig = BeanUtil.copyProperties(param, PqFreqConverterConfig.class); + return this.save(pqFreqConverterConfig); + } + + @Override + public boolean updatePqFreqConverterConfig(PqFreqConverterParam.UpdateParam param) { + PqFreqConverterConfig pqFreqConverterConfig = BeanUtil.copyProperties(param, PqFreqConverterConfig.class); + return this.updateById(pqFreqConverterConfig); + } + + @Override + public boolean deletePqFreqConverterConfig(PqDevParam.DeleteParam param) { + return this.lambdaUpdate().set(PqFreqConverterConfig::getState, 0).update(); + } +}