变频器
This commit is contained in:
@@ -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<String> 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<PreDetection> preDetections = pqDevService.getDevInfo(Collections.singletonList(split[0]));
|
||||||
|
if (CollUtil.isEmpty(preDetections)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
PreDetection preDetection = preDetections.get(0);
|
||||||
|
List<PreDetection.MonitorListDTO> monitorList = preDetection.getMonitorList();
|
||||||
|
if (CollUtil.isEmpty(monitorList)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<PreDetection.MonitorListDTO> matchedMonitorList = monitorList.stream()
|
||||||
|
.filter(item -> split[1].equals(item.getLineId()))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
if (CollUtil.isEmpty(matchedMonitorList)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
preDetection.setMonitorList(matchedMonitorList);
|
||||||
|
Map<String, List<PreDetection>> payload = new HashMap<>(1);
|
||||||
|
payload.put("deviceList", Collections.singletonList(preDetection));
|
||||||
|
return JSON.toJSONString(payload);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sendGetDipDataMsg(String monitorId) {
|
||||||
|
SocketMsg<String> 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<String> 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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<Map<String, Object>> socketMsg = new SocketMsg<>();
|
||||||
|
socketMsg.setOperateCode(SourceOperateCodeEnum.CMD_INIT_SERIAL.getValue());
|
||||||
|
String requestId = IdUtil.fastSimpleUUID();
|
||||||
|
socketMsg.setRequestId(requestId);
|
||||||
|
|
||||||
|
PqFreqConverterConfig freqConverterConfig = pqFreqConverterConfigService.getById(converterId);
|
||||||
|
|
||||||
|
Map<String, Object> 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<Map<String, Object>> socketMsg = new SocketMsg<>();
|
||||||
|
socketMsg.setOperateCode(SourceOperateCodeEnum.CMD_GET_DEVICE_STATUS.getValue());
|
||||||
|
String requestId = IdUtil.fastSimpleUUID();
|
||||||
|
socketMsg.setRequestId(requestId);
|
||||||
|
|
||||||
|
Map<String, Object> map = new HashMap<>();
|
||||||
|
socketMsg.setData(map);
|
||||||
|
SocketManager.sendMsg(converterId, JSON.toJSONString(socketMsg));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sendClose(String converterTag) {
|
||||||
|
SocketMsg<Map<String, Object>> socketMsg = new SocketMsg<>();
|
||||||
|
socketMsg.setOperateCode(SourceOperateCodeEnum.CMD_CLOSE_SERIAL.getValue());
|
||||||
|
String requestId = IdUtil.fastSimpleUUID();
|
||||||
|
socketMsg.setRequestId(requestId);
|
||||||
|
|
||||||
|
Map<String, Object> 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -52,7 +52,7 @@ public enum SourceOperateCodeEnum {
|
|||||||
YJC_MXYZXJY("yjc_mxyzxjy", "模型一致性校验"),
|
YJC_MXYZXJY("yjc_mxyzxjy", "模型一致性校验"),
|
||||||
FORMAL_REAL("formal_real","正式检测"),
|
FORMAL_REAL("formal_real","正式检测"),
|
||||||
RECORD_WAVE_STEP1("record_wave_step1","启动录波_step1"),
|
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","模拟检测"),
|
// SIMULATE_REAL("simulate_real","模拟检测"),
|
||||||
Coefficient_Check("Coefficient_Check","系数校验"),
|
Coefficient_Check("Coefficient_Check","系数校验"),
|
||||||
QUITE("quit","关闭设备通讯初始化"),
|
QUITE("quit","关闭设备通讯初始化"),
|
||||||
@@ -70,9 +70,6 @@ public enum SourceOperateCodeEnum {
|
|||||||
FLICKER_DATA_CHECK("flicker_data_check","闪变数据校验"),
|
FLICKER_DATA_CHECK("flicker_data_check","闪变数据校验"),
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
@@ -100,12 +97,17 @@ public enum SourceOperateCodeEnum {
|
|||||||
small_comp_start("small_comp_start","小电压校准开始"),
|
small_comp_start("small_comp_start","小电压校准开始"),
|
||||||
small_comp_end("small_comp_end","小电压校准结束"),
|
small_comp_end("small_comp_end","小电压校准结束"),
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ftp文件传送指令
|
* ftp文件传送指令
|
||||||
*/
|
*/
|
||||||
FTP_SEND_01("FTP_SEND$01", "发送文件"),
|
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 value;
|
||||||
private final String msg;
|
private final String msg;
|
||||||
|
|||||||
@@ -31,6 +31,9 @@ public class FormalTestManager {
|
|||||||
// 当前步骤
|
// 当前步骤
|
||||||
public static SourceOperateCodeEnum currentStep;
|
public static SourceOperateCodeEnum currentStep;
|
||||||
|
|
||||||
|
public static SourceOperateCodeEnum freqConverterStep;
|
||||||
|
public static SourceOperateCodeEnum freqConverterDevStep;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* key:设备ip,value:当前设备下面的监测点ID(ip_通道号)
|
* key:设备ip,value:当前设备下面的监测点ID(ip_通道号)
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -81,6 +81,17 @@ public class SocketManager {
|
|||||||
socketGroup.remove(userId);
|
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) {
|
public static Channel getChannelByUserId(String userId) {
|
||||||
return socketSessions.get(userId);
|
return socketSessions.get(userId);
|
||||||
}
|
}
|
||||||
@@ -315,4 +326,4 @@ public class SocketManager {
|
|||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -56,6 +56,109 @@ public class NettyClient {
|
|||||||
*/
|
*/
|
||||||
private static NettyClient instance;
|
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<NioSocketChannel> 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<NioSocketChannel> createCommonChannelInitializer(
|
||||||
|
String channelId, SimpleChannelInboundHandler handler) {
|
||||||
|
return new ChannelInitializer<NioSocketChannel>() {
|
||||||
|
@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
|
@PostConstruct
|
||||||
public void init() {
|
public void init() {
|
||||||
|
|||||||
@@ -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<String> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 变频器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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -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<String> {
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -18,29 +18,21 @@ import java.util.Set;
|
|||||||
@Component
|
@Component
|
||||||
@ConfigurationProperties(prefix = "socket")
|
@ConfigurationProperties(prefix = "socket")
|
||||||
public class SocketConnectionConfig {
|
public class SocketConnectionConfig {
|
||||||
|
/**
|
||||||
|
* 被检设备配置
|
||||||
|
*/
|
||||||
|
private DeviceConfig device = new DeviceConfig();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 程控源设备配置
|
* 程控源设备配置
|
||||||
*/
|
*/
|
||||||
private SourceConfig source = new SourceConfig();
|
private SourceConfig source = new SourceConfig();
|
||||||
|
|
||||||
/**
|
|
||||||
* 被检设备配置
|
|
||||||
*/
|
|
||||||
private DeviceConfig device = new DeviceConfig();
|
|
||||||
|
|
||||||
@Data
|
/**
|
||||||
public static class SourceConfig {
|
* 变频器配置
|
||||||
/**
|
*/
|
||||||
* 程控源IP地址
|
private DeviceConfig freqConverter = new DeviceConfig();
|
||||||
*/
|
|
||||||
private String ip;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 程控源端口号
|
|
||||||
*/
|
|
||||||
private Integer port;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
public static class DeviceConfig {
|
public static class DeviceConfig {
|
||||||
@@ -48,13 +40,33 @@ public class SocketConnectionConfig {
|
|||||||
* 被检设备IP地址
|
* 被检设备IP地址
|
||||||
*/
|
*/
|
||||||
private String ip;
|
private String ip;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 被检设备端口号
|
* 被检设备端口号
|
||||||
*/
|
*/
|
||||||
private Integer port;
|
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() {
|
public DeviceConfig getFreqConverter() {
|
||||||
return device;
|
return freqConverter;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -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<PqDipData> {
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -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<PqDipData> {
|
||||||
|
}
|
||||||
@@ -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<PqDipDataMapper, PqDipData> implements IPqDipDataService {
|
||||||
|
}
|
||||||
@@ -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<Page<PqFreqConverterConfig>> list(@RequestBody @Validated PqFreqConverterParam.QueryParam queryParam) {
|
||||||
|
String methodDescribe = getMethodDescribe("list");
|
||||||
|
LogUtil.njcnDebug(log, "{},查询数据为:{}", methodDescribe, queryParam);
|
||||||
|
Page<PqFreqConverterConfig> 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<Boolean> 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<Boolean> 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<Boolean> 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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<FreqConverterStatus> {
|
||||||
|
}
|
||||||
@@ -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<PqFreqConverterConfig> {
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -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<FreqConverterStatus> {
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存变频器状态数据
|
||||||
|
*
|
||||||
|
* @param status 变频器状态数据
|
||||||
|
* @return 是否保存成功
|
||||||
|
*/
|
||||||
|
boolean saveFreqConverterStatus(FreqConverterStatus status);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询指定变频器的状态历史
|
||||||
|
*
|
||||||
|
* @param converterId 变频器ID
|
||||||
|
* @return 状态数据列表
|
||||||
|
*/
|
||||||
|
List<FreqConverterStatus> listStatusHistory(String converterId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 清空所有数据
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
boolean clearAllData();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据设备暂降数据判断变频器是否耐受
|
||||||
|
*
|
||||||
|
* @param freqConverterDataList 变频器数据集合
|
||||||
|
* @param dipDataList 设备暂降数据集合
|
||||||
|
* @return 是否耐受
|
||||||
|
*/
|
||||||
|
List<TolerantPointVO> getTolerantPoints(List<FreqConverterStatus> freqConverterDataList, List<PqDipData> dipDataList);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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<PqFreqConverterConfig> {
|
||||||
|
Page<PqFreqConverterConfig> listPqFreqConverterConfigs(PqFreqConverterParam.QueryParam queryParam);
|
||||||
|
|
||||||
|
boolean addPqFreqConverterConfig(PqFreqConverterParam param);
|
||||||
|
|
||||||
|
boolean updatePqFreqConverterConfig(PqFreqConverterParam.UpdateParam param);
|
||||||
|
|
||||||
|
boolean deletePqFreqConverterConfig(PqDevParam.DeleteParam param);
|
||||||
|
}
|
||||||
@@ -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实现类
|
||||||
|
* <p>
|
||||||
|
* 实现变频器状态数据的存储、查询和清理功能。
|
||||||
|
* 当数据量超过阈值时,自动清理无效或过期数据,避免内存和数据库资源浪费。
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author CN_Gather Detection Team
|
||||||
|
* @version 1.0
|
||||||
|
* @since 2026
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
public class FreqConverterServiceImpl extends ServiceImpl<FreqConverterStatusMapper, FreqConverterStatus> implements IFreqConverterService {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public boolean saveFreqConverterStatus(FreqConverterStatus status) {
|
||||||
|
return this.save(status);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<FreqConverterStatus> listStatusHistory(String converterId) {
|
||||||
|
return this.lambdaQuery().list();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean clearAllData() {
|
||||||
|
return this.remove(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<TolerantPointVO> getTolerantPoints(List<FreqConverterStatus> freqConverterDataList, List<PqDipData> dipDataList) {
|
||||||
|
dipDataList.sort(Comparator.comparing(PqDipData::getDurationMs));
|
||||||
|
|
||||||
|
List<TolerantPointVO> 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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<PqFreqConverterConfigMapper, PqFreqConverterConfig> implements IPqFreqConverterConfigService {
|
||||||
|
@Override
|
||||||
|
public Page<PqFreqConverterConfig> 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user