优化逻辑

This commit is contained in:
weitang 2025-04-27 14:05:10 +08:00
parent 667a637d92
commit 7597ddfe2e
7 changed files with 424 additions and 1 deletions

View File

@ -0,0 +1,178 @@
package com.yfd.platform.component.iec104.client;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.yfd.platform.component.iec104.enums.QualifiersEnum;
import com.yfd.platform.component.iec104.enums.TypeIdentifierEnum;
import com.yfd.platform.component.iec104.message.MessageDetail;
import com.yfd.platform.component.iec104.message.MessageInfo;
import com.yfd.platform.component.iec104.server.master.BootNettyClientChannel;
import com.yfd.platform.component.iec104.server.master.BootNettyClientChannelCache;
import com.yfd.platform.modules.auxcontrol.domain.DeviceSignal;
import com.yfd.platform.modules.auxcontrol.domain.GatewayDevice;
import com.yfd.platform.modules.auxcontrol.domain.MeterDevice;
import com.yfd.platform.modules.auxcontrol.service.IDeviceSignalService;
import com.yfd.platform.modules.auxcontrol.service.IGatewayDeviceService;
import com.yfd.platform.modules.auxcontrol.service.IMeterDeviceService;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@Service
public class IIEC104Service {
@Resource
private IMeterDeviceService meterDeviceService;
@Resource
private IGatewayDeviceService gatewayDeviceService;
@Resource
private IDeviceSignalService deviceSignalService;
public boolean sendCommand(String systemcode, String signalid, String type, String value) {
DeviceSignal deviceSignal = deviceSignalService.getById(signalid);
//辅控系统下属网关机状态监控
if (StrUtil.isNotEmpty(systemcode) && "10".equals(systemcode)) {
if (ObjUtil.isNotEmpty(deviceSignal)) {
LambdaQueryWrapper<GatewayDevice> queryWrapper = new LambdaQueryWrapper<>();
//类型
queryWrapper.eq(GatewayDevice::getDeviceType, "30");
//通讯网关机的iec地址
queryWrapper.eq(GatewayDevice::getIecAddr, deviceSignal.getYxAddr());
//查找网关机
GatewayDevice gatewayDevice = gatewayDeviceService.getOne(queryWrapper);
//连接到主机
if ("1".equals(value)) {
//连接到子系统的通讯网关
gatewayDeviceService.connectToSlave(gatewayDevice.getIpAddr());
} else {
//断开与子系统通讯网关的连接
gatewayDeviceService.disconnectToSlave(gatewayDevice.getIpAddr());
}
}
} else {
if (ObjUtil.isNotEmpty(deviceSignal)) {
//查找设备
MeterDevice meterDevice = meterDeviceService.getById(deviceSignal.getMeterDeviceId());
LambdaQueryWrapper<GatewayDevice> queryWrapper = new LambdaQueryWrapper<>();
//通讯网关机的IP地址
queryWrapper.eq(GatewayDevice::getIpAddr, meterDevice.getNetdeviceIp());
//查找网关机
GatewayDevice gatewayDevice = gatewayDeviceService.getOne(queryWrapper);
if (ObjUtil.isNotEmpty(gatewayDevice)) {
int iecaddr = gatewayDevice.getIecAddr();
String address = "";
if ("yk".equals(type)) {
address = deviceSignal.getYkAddr();
} else if ("yt".equals(type)) {
address = deviceSignal.getYtAddr();
}
MessageDetail comand = getYk_YtCommand(iecaddr, deviceSignal.getYkytType(), address, value);
//以上都是自加的
if (BootNettyClientChannelCache.channelMapCache.size() > 0) {
for (Map.Entry<String, BootNettyClientChannel> entry :
BootNettyClientChannelCache.channelMapCache.entrySet()) {
BootNettyClientChannel bootNettyChannel = entry.getValue();
if (bootNettyChannel != null && bootNettyChannel.getChannel().isOpen()) {
if (bootNettyChannel.getCode().equals(meterDevice.getNetdeviceIp())) {//对应的终端
bootNettyChannel.getChannel().writeAndFlush(comand);
}
}
}
}
}
}
}
return false;
}
private MessageDetail getYk_YtCommand(int terminalAddress, String type, String address, String value) {
// 接收序号
short accept = 0;
// 发送序号
short send = 0;
//控制欲
byte[] control = com.ydl.iec.util.Iec104Util.getIcontrol(accept, send);
//类型标识 2D
TypeIdentifierEnum typeIdentifierEnum = null;
// 消息地址 总召唤地址为0
//偏差 6000H
int messageAddress = Integer.parseInt(address) + 24576;
List<MessageInfo> messages = new ArrayList<>();
MessageInfo message = new MessageInfo();
//单点
if ("01".equals(type)) {
typeIdentifierEnum = TypeIdentifierEnum.onePointTelecontrol;
if ("0".equals(value)) {
message.setMessageInfos(new byte[]{0x00});
}
if ("1".equals(value)) {
message.setMessageInfos(new byte[]{0x01});
}
} else if ("02".equals(type)) {
//双点
typeIdentifierEnum = TypeIdentifierEnum.twoPointTelecontrol;
if ("0".equals(value)) {
message.setMessageInfos(new byte[]{0x01});
}
if ("1".equals(value)) {
message.setMessageInfos(new byte[]{0x02});
}
} else if ("03".equals(type)) {
//遥调 -归一化值
typeIdentifierEnum = TypeIdentifierEnum.normalizedTeleadjustment;
short value1 = Short.parseShort(value);
byte[] byteArray = new byte[2];
byteArray[0] = (byte) (value1 & 0xFF); // 低位字节
byteArray[1] = (byte) ((value1 >> 8) & 0xFF); // 高位字节
message.setMessageInfos(byteArray);
} else if ("04".equals(type)) {
//遥调 -标度化值
typeIdentifierEnum = TypeIdentifierEnum.scaledTeleadjustment;
short value1 = Short.parseShort(value);
byte[] byteArray = new byte[2];
byteArray[0] = (byte) (value1 & 0xFF); // 低位字节
byteArray[1] = (byte) ((value1 >> 8) & 0xFF); // 高位字节
message.setMessageInfos(byteArray);
} else if ("05".equals(type)) {
//遥调 -浮点数值
typeIdentifierEnum = TypeIdentifierEnum.shortFloatingPointTeleadjustment;
byte[] byteArray = new byte[4];
float value1 = Float.parseFloat(value);
int intBits = Float.floatToIntBits(value1);
byteArray[0] = (byte) (intBits & 0xFF); // 第一个字节最低位
byteArray[1] = (byte) ((intBits >> 8) & 0xFF); // 第二个字节
byteArray[2] = (byte) ((intBits >> 16) & 0xFF);// 第三个字节
byteArray[3] = (byte) ((intBits >> 24) & 0xFF);// 第四个字节最高位
message.setMessageInfos(byteArray);
}
message.setMessageAddress(messageAddress);
messages.add(message);
short terminalAddress1 = (short) terminalAddress;
//SQ=0 length =1
int sq = 0;
//可变结构限定词 01
boolean isContinuous = sq == 0 ? false : true;
// 传输原因
short transferReason = 6;
//公共地址
// true1 ; false 0
boolean isTest = false;
// true:0 false;1 isPn 肯定确认 和否定确认
boolean isPN = true;
MessageDetail ruleDetail104 = new MessageDetail(control, typeIdentifierEnum, isContinuous, isTest, isPN,
transferReason,
terminalAddress1, messageAddress, messages, null, null);
if (type.equals("03") || type.equals("04") || type.equals("05")) {
QualifiersEnum qualifiers = QualifiersEnum.qualityQualifiers;
ruleDetail104 = new MessageDetail(control, typeIdentifierEnum, isContinuous, isTest, isPN, transferReason,
terminalAddress1, messageAddress, messages, null, qualifiers);
}
return ruleDetail104;
}
}

View File

@ -57,6 +57,21 @@ public class DeviceSignalController {
return ResponseResult.successData(deviceSignalPage);
}
/**********************************
* 用途说明: 查询遥信遥测数据
* 参数说明
* areaid 区域ID
* 返回值说明: 变电站辅控设备信号集合
***********************************/
@GetMapping("/queryYxYcData")
@ApiOperation("查询遥信遥测数据")
public ResponseResult queryYxYcData(String mainDeviceId, String componentId) {
LambdaQueryWrapper<DeviceSignal> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(StrUtil.isNotBlank(mainDeviceId), DeviceSignal::getMainDeviceId, mainDeviceId).eq(StrUtil.isNotBlank(componentId), DeviceSignal::getMainCompnentId, componentId);
List<DeviceSignal> list = deviceSignalService.list(queryWrapper);
return ResponseResult.successData(list);
}
/***********************************
* 用途说明新增变电站辅控设备信号

View File

@ -0,0 +1,112 @@
package com.yfd.platform.modules.auxcontrol.controller;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.yfd.platform.component.iec104.client.IIEC104Service;
import com.yfd.platform.component.iec61850.client.IEC61850Service;
import com.yfd.platform.config.ResponseResult;
import com.yfd.platform.modules.auxcontrol.domain.DeviceAlarmRecord;
import com.yfd.platform.modules.auxcontrol.domain.DeviceSignal;
import com.yfd.platform.modules.auxcontrol.domain.GatewayDevice;
import com.yfd.platform.modules.auxcontrol.domain.MeterDevice;
import com.yfd.platform.modules.auxcontrol.service.IDeviceAlarmRecordService;
import com.yfd.platform.modules.auxcontrol.service.IDeviceSignalService;
import com.yfd.platform.modules.auxcontrol.service.IGatewayDeviceService;
import com.yfd.platform.modules.auxcontrol.service.IMeterDeviceService;
import com.yfd.platform.modules.basedata.service.ISubstationAreaService;
import com.yfd.platform.modules.basedata.service.ISubstationComponentService;
import com.yfd.platform.modules.basedata.service.ISubstationMaindeviceService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.util.List;
/**
* <p>
* 变电站-系统运行日志 前端控制器
* </p>
*
* @author zhengsl
* @since 2024-04-05
*/
@RestController
@RequestMapping("/iecclient")
@Api(value = "IEC104Controller", tags = "IEC104服务")
public class IECController {
//变电站-辅控设备-信号 服务类
@Resource
private IDeviceSignalService deviceSignalService;
//变电站辅控设备 服务类
@Resource
private IGatewayDeviceService gatewayDeviceService;
@Resource
private IMeterDeviceService meterDeviceService;
//变电站报警记录
@Resource
private IDeviceAlarmRecordService deviceAlarmRecordService;
@Resource
private IIEC104Service iec104Service;
@Resource
private IEC61850Service iec61850Service;
@GetMapping("/confirmclosealarm")
@ApiOperation("确认告警信息,关闭告警弹窗")
public ResponseResult confirmCloseAlarmRecord(String record_id) {
DeviceAlarmRecord alarmRecord = new DeviceAlarmRecord();
alarmRecord.setRecordId(record_id);
alarmRecord.setStatus("03");
alarmRecord.setFixTime(DateUtil.toLocalDateTime(DateUtil.date()));
deviceAlarmRecordService.updateById(alarmRecord);
return ResponseResult.success();
}
/**********************************
* 用途说明: 发送遥控遥调命令
* 参数说明
* systemcode 系统编号
***********************************/
@GetMapping("/sendCommand")
@ApiOperation("发送遥控遥调命令")
public ResponseResult sendCommand(String systemcode, String signalid, String type, String value) throws Exception {
if (StrUtil.isBlank(signalid)) {
return ResponseResult.error("信号ID不能为空");
}
DeviceSignal deviceSignal = deviceSignalService.getById(signalid);
if (ObjUtil.isNotEmpty(deviceSignal)) {
LambdaQueryWrapper<MeterDevice> queryWrapper = new LambdaQueryWrapper<>();
//型号对应的监控设备id
queryWrapper.eq(MeterDevice::getDeviceId, deviceSignal.getMeterDeviceId());
//查找信号对应监控设备
MeterDevice meterDevice = meterDeviceService.getOne(queryWrapper);
LambdaQueryWrapper<GatewayDevice> queryWrapper2 = new LambdaQueryWrapper<>();
//IP地址
queryWrapper2.eq(GatewayDevice::getIpAddr, meterDevice.getNetdeviceIp());
//查找信号对应网关机设备
GatewayDevice netDevice = gatewayDeviceService.getOne(queryWrapper2);
if (netDevice == null) {
return ResponseResult.error("组件未关联信号!");
}
if ("IEC104".equals(netDevice.getProtocol())) {
iec104Service.sendCommand(systemcode, signalid, type, value);
} else if ("IEC61850".equals(netDevice.getProtocol())) {
iec61850Service.sendCommand(systemcode, signalid, type, value);
}
return ResponseResult.success();
} else {
return ResponseResult.error("组件未关联信号!");
}
}
}

View File

@ -20,6 +20,8 @@ public interface DeviceSignalMapper extends BaseMapper<DeviceSignal> {
DeviceSignal selectOneDeviceSignal(String slaveIp, String type, String address);
Map<String,Object> selectDeviceSignalMap(String slaveIp, String type, String address);
List<Map<String, Object>> getDeviceSignalMaps(String mainDeviceId, String signalName);
List<DeviceSignal> selectDeviceSignalByIp(String ip);
@Update("UPDATE fk_device_signal SET yc_value = #{value}, lastmodifydate = #{datetime} WHERE yc_addr = #{node_addr}")
boolean updateDeviceSignalValue_yc(String node_addr,String value,String datetime);
@Update("UPDATE fk_device_signal SET yx_value = #{value}, lastmodifydate = #{datetime} WHERE yx_addr = #{node_addr}")

View File

@ -46,4 +46,8 @@ public interface IGatewayDeviceService extends IService<GatewayDevice> {
* 返回值说明: boolean
***********************************/
boolean updateGatewayDevice(GatewayDevice gatewayDevice);
boolean connectToSlave(String ip);
boolean disconnectToSlave(String ip);
}

View File

@ -1,19 +1,34 @@
package com.yfd.platform.modules.auxcontrol.service.impl;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yfd.platform.component.WebSocketServer;
import com.yfd.platform.component.iec104.client.MasterSysDataHandler;
import com.yfd.platform.component.iec104.config.Iec104Config;
import com.yfd.platform.component.iec104.server.Iec104Master;
import com.yfd.platform.component.iec104.server.Iec104MasterFactory;
import com.yfd.platform.component.iec104.server.master.BootNettyClientChannel;
import com.yfd.platform.component.iec104.server.master.BootNettyClientChannelCache;
import com.yfd.platform.component.iec104.server.master.EventLoopGroupManager;
import com.yfd.platform.component.utils.OptimizedThreadPool;
import com.yfd.platform.modules.auxcontrol.domain.DeviceSignal;
import com.yfd.platform.modules.auxcontrol.domain.GatewayDevice;
import com.yfd.platform.modules.auxcontrol.mapper.DeviceSignalMapper;
import com.yfd.platform.modules.auxcontrol.mapper.GatewayDeviceMapper;
import com.yfd.platform.modules.auxcontrol.service.IGatewayDeviceService;
import com.yfd.platform.utils.StringUtils;
import io.netty.channel.EventLoopGroup;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.io.IOException;
import java.sql.Timestamp;
import java.util.List;
import java.util.Map;
/**
* <p>
@ -29,6 +44,9 @@ public class GatewayDeviceServiceImpl extends ServiceImpl<GatewayDeviceMapper, G
@Resource
private GatewayDeviceMapper gatewayDeviceMapper;
@Resource
private DeviceSignalMapper deviceSignalMapper;
/**********************************
* 用途说明: 根据IP,更新心跳保持时间
* 参数说明
@ -87,4 +105,78 @@ public class GatewayDeviceServiceImpl extends ServiceImpl<GatewayDeviceMapper, G
public boolean updateGatewayDevice(GatewayDevice gatewayDevice) {
return this.saveOrUpdate(gatewayDevice);
}
@Override
public boolean connectToSlave(String ip) {
LambdaQueryWrapper<GatewayDevice> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(GatewayDevice::getIpAddr, ip);
GatewayDevice systemDevice = gatewayDeviceMapper.selectOne(queryWrapper);
if (ObjUtil.isNotEmpty(systemDevice)) {
Iec104Config iec104Config = new Iec104Config();
iec104Config.setFrameAmountMax((short) 10);
short terminnalAddress = systemDevice.getIecAddr().shortValue();
//通讯网关机地址
iec104Config.setTerminnalAddress(terminnalAddress);
iec104Config.setSlaveCode(systemDevice.getDeviceCode());
iec104Config.setSlaveIP(systemDevice.getIpAddr());
EventLoopGroup group = EventLoopGroupManager.getEventLoopGroup(ip);
if (ObjUtil.isNotEmpty(group)) {
try {
disconnectToSlave(ip);
Thread.sleep(1000);
} catch (InterruptedException e) {
log.error("Exception caught", e);
}
}
Runnable runnable = () -> {
Iec104Master iec104server = Iec104MasterFactory.createTcpClientMaster(iec104Config.getSlaveIP(), 2404);
try {
iec104server.setDataHandler(new MasterSysDataHandler()).setConfig(iec104Config).run();
} catch (Exception e) {
EventLoopGroupManager.shutdownEventLoopGroup(ip);
log.error(String.format("%s-对应的终端连接失败!", iec104Config.getSlaveIP()));
}
};
OptimizedThreadPool threadPool = OptimizedThreadPool.getInstance();
threadPool.execute(runnable);
}
return true;
}
@Override
//断开与网关机的通讯连接
public boolean disconnectToSlave(String ip) {
LambdaQueryWrapper<GatewayDevice> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(GatewayDevice::getIpAddr, ip);
GatewayDevice gatewayDevice = gatewayDeviceMapper.selectOne(queryWrapper);
if (ObjUtil.isEmpty(gatewayDevice)) {
return true;
}
if (BootNettyClientChannelCache.channelMapCache.size() <= 0) {
return true;
}
for (Map.Entry<String, BootNettyClientChannel> entry :
BootNettyClientChannelCache.channelMapCache.entrySet()) {
BootNettyClientChannel bootNettyChannel = entry.getValue();
if (bootNettyChannel != null && bootNettyChannel.getChannel().isOpen() && bootNettyChannel.getCode().equals(ip)) {
bootNettyChannel.getChannel().pipeline().close();
bootNettyChannel.getChannel().close();
bootNettyChannel.getScheduledTaskPool().stopSendCommandTask();
BootNettyClientChannelCache.remove(entry.getKey());
EventLoopGroupManager.shutdownEventLoopGroup(ip);
gatewayDevice.setStatus("02");
gatewayDeviceMapper.updateById(gatewayDevice);
List<DeviceSignal> list = deviceSignalMapper.selectDeviceSignalByIp(ip);
String message = JSONUtil.toJsonStr(list);
try {
WebSocketServer.sendInfo(message);
} catch (IOException e) {
log.error("Exception caught", e);
}
}
}
return true;
}
}

View File

@ -68,5 +68,25 @@
fds.signal_name LIKE CONCAT('',#{signalName},'')
</if>
</select>
<select id="selectDeviceSignalByIp" resultType="com.yfd.platform.modules.auxcontrol.domain.DeviceSignal">
SELECT
a.signal_id,
a.meter_device_id,
a.signal_name,
'' signal_unit,
a.yx_addr,
a.yc_addr,
CASE
WHEN b.STATUS = '01' THEN
'1' ELSE '0'
END yx_value
FROM
fk_device_signal a
JOIN fk_gateway_device b ON ( a.yx_addr = b.iec_addr )
WHERE
b.device_type = '30'
AND b.ip_addr = #{ip}
</select>
</mapper>