变频器

This commit is contained in:
caozehui
2026-04-13 16:28:25 +08:00
parent fd7c6ada6b
commit 97157a5ccf
25 changed files with 1512 additions and 27 deletions

View File

@@ -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);
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -31,6 +31,9 @@ public class FormalTestManager {
// 当前步骤
public static SourceOperateCodeEnum currentStep;
public static SourceOperateCodeEnum freqConverterStep;
public static SourceOperateCodeEnum freqConverterDevStep;
/**
* key:设备ip,value:当前设备下面的监测点ID(ip_通道号)
*/

View File

@@ -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 {
}

View File

@@ -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<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
public void init() {

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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;
}
/**

View File

@@ -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> {
}

View File

@@ -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;
}

View File

@@ -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> {
}

View File

@@ -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 {
}

View File

@@ -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);
}
}
}

View File

@@ -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> {
}

View File

@@ -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> {
}

View File

@@ -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;
}
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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;
}
}

View File

@@ -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();
}
}