diff --git a/riis-system/src/main/java/com/yfd/platform/component/iec104/client/IIEC104Service.java b/riis-system/src/main/java/com/yfd/platform/component/iec104/client/IIEC104Service.java new file mode 100644 index 0000000..3581172 --- /dev/null +++ b/riis-system/src/main/java/com/yfd/platform/component/iec104/client/IIEC104Service.java @@ -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 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 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 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 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; + //公共地址 + // true:1 ; 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; + } +} diff --git a/riis-system/src/main/java/com/yfd/platform/modules/auxcontrol/controller/DeviceSignalController.java b/riis-system/src/main/java/com/yfd/platform/modules/auxcontrol/controller/DeviceSignalController.java index 2ca599b..733df64 100644 --- a/riis-system/src/main/java/com/yfd/platform/modules/auxcontrol/controller/DeviceSignalController.java +++ b/riis-system/src/main/java/com/yfd/platform/modules/auxcontrol/controller/DeviceSignalController.java @@ -57,6 +57,21 @@ public class DeviceSignalController { return ResponseResult.successData(deviceSignalPage); } + /********************************** + * 用途说明: 查询遥信遥测数据 + * 参数说明 + * areaid 区域ID + * 返回值说明: 变电站辅控设备信号集合 + ***********************************/ + @GetMapping("/queryYxYcData") + @ApiOperation("查询遥信遥测数据") + public ResponseResult queryYxYcData(String mainDeviceId, String componentId) { + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(StrUtil.isNotBlank(mainDeviceId), DeviceSignal::getMainDeviceId, mainDeviceId).eq(StrUtil.isNotBlank(componentId), DeviceSignal::getMainCompnentId, componentId); + List list = deviceSignalService.list(queryWrapper); + return ResponseResult.successData(list); + } + /*********************************** * 用途说明:新增变电站辅控设备信号 diff --git a/riis-system/src/main/java/com/yfd/platform/modules/auxcontrol/controller/IECController.java b/riis-system/src/main/java/com/yfd/platform/modules/auxcontrol/controller/IECController.java new file mode 100644 index 0000000..13582bd --- /dev/null +++ b/riis-system/src/main/java/com/yfd/platform/modules/auxcontrol/controller/IECController.java @@ -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; + +/** + *

+ * 变电站-系统运行日志 前端控制器 + *

+ * + * @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 queryWrapper = new LambdaQueryWrapper<>(); + //型号对应的监控设备id + queryWrapper.eq(MeterDevice::getDeviceId, deviceSignal.getMeterDeviceId()); + //查找信号对应监控设备 + MeterDevice meterDevice = meterDeviceService.getOne(queryWrapper); + LambdaQueryWrapper 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("组件未关联信号!"); + } + } +} diff --git a/riis-system/src/main/java/com/yfd/platform/modules/auxcontrol/mapper/DeviceSignalMapper.java b/riis-system/src/main/java/com/yfd/platform/modules/auxcontrol/mapper/DeviceSignalMapper.java index dc11e8a..eefe8a0 100644 --- a/riis-system/src/main/java/com/yfd/platform/modules/auxcontrol/mapper/DeviceSignalMapper.java +++ b/riis-system/src/main/java/com/yfd/platform/modules/auxcontrol/mapper/DeviceSignalMapper.java @@ -20,6 +20,8 @@ public interface DeviceSignalMapper extends BaseMapper { DeviceSignal selectOneDeviceSignal(String slaveIp, String type, String address); Map selectDeviceSignalMap(String slaveIp, String type, String address); List> getDeviceSignalMaps(String mainDeviceId, String signalName); + + List 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}") diff --git a/riis-system/src/main/java/com/yfd/platform/modules/auxcontrol/service/IGatewayDeviceService.java b/riis-system/src/main/java/com/yfd/platform/modules/auxcontrol/service/IGatewayDeviceService.java index f727fbe..3e81883 100644 --- a/riis-system/src/main/java/com/yfd/platform/modules/auxcontrol/service/IGatewayDeviceService.java +++ b/riis-system/src/main/java/com/yfd/platform/modules/auxcontrol/service/IGatewayDeviceService.java @@ -46,4 +46,8 @@ public interface IGatewayDeviceService extends IService { * 返回值说明: boolean ***********************************/ boolean updateGatewayDevice(GatewayDevice gatewayDevice); + + boolean connectToSlave(String ip); + + boolean disconnectToSlave(String ip); } diff --git a/riis-system/src/main/java/com/yfd/platform/modules/auxcontrol/service/impl/GatewayDeviceServiceImpl.java b/riis-system/src/main/java/com/yfd/platform/modules/auxcontrol/service/impl/GatewayDeviceServiceImpl.java index b6ea8e6..5137e3f 100644 --- a/riis-system/src/main/java/com/yfd/platform/modules/auxcontrol/service/impl/GatewayDeviceServiceImpl.java +++ b/riis-system/src/main/java/com/yfd/platform/modules/auxcontrol/service/impl/GatewayDeviceServiceImpl.java @@ -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; /** *

@@ -29,6 +44,9 @@ public class GatewayDeviceServiceImpl extends ServiceImpl 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 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 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 list = deviceSignalMapper.selectDeviceSignalByIp(ip); + String message = JSONUtil.toJsonStr(list); + try { + WebSocketServer.sendInfo(message); + } catch (IOException e) { + log.error("Exception caught", e); + } + } + } + return true; + } } diff --git a/riis-system/src/main/resources/mapper/auxcontrol/DeviceSignalMapper.xml b/riis-system/src/main/resources/mapper/auxcontrol/DeviceSignalMapper.xml index be521bd..3093849 100644 --- a/riis-system/src/main/resources/mapper/auxcontrol/DeviceSignalMapper.xml +++ b/riis-system/src/main/resources/mapper/auxcontrol/DeviceSignalMapper.xml @@ -68,5 +68,25 @@ fds.signal_name LIKE CONCAT('',#{signalName},'') +