diff --git a/riis-system/src/main/java/com/yfd/platform/component/iec104/client/IEC104ClientRunner.java b/riis-system/src/main/java/com/yfd/platform/component/iec104/client/IEC104ClientRunner.java index b98224d..9f84790 100644 --- a/riis-system/src/main/java/com/yfd/platform/component/iec104/client/IEC104ClientRunner.java +++ b/riis-system/src/main/java/com/yfd/platform/component/iec104/client/IEC104ClientRunner.java @@ -17,7 +17,7 @@ package com.yfd.platform.component.iec104.client; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.yfd.platform.component.iec104.config.Iec104Config; -import com.yfd.platform.component.iec104.core.OptimizedThreadPool; +import com.yfd.platform.component.utils.OptimizedThreadPool; import com.yfd.platform.component.iec104.server.Iec104Master; import com.yfd.platform.component.iec104.server.Iec104MasterFactory; import com.yfd.platform.modules.auxcontrol.domain.GatewayDevice; diff --git a/riis-system/src/main/java/com/yfd/platform/component/iec104/core/ControlManageUtil.java b/riis-system/src/main/java/com/yfd/platform/component/iec104/core/ControlManageUtil.java index f5c9a5a..8bc0c1b 100644 --- a/riis-system/src/main/java/com/yfd/platform/component/iec104/core/ControlManageUtil.java +++ b/riis-system/src/main/java/com/yfd/platform/component/iec104/core/ControlManageUtil.java @@ -1,11 +1,9 @@ package com.yfd.platform.component.iec104.core; -import com.yfd.platform.component.iec104.client.MasterSysDataHandler; import com.yfd.platform.component.iec104.common.Iec104Constant; import com.yfd.platform.component.iec104.message.MessageDetail; import com.ydl.iec.util.Iec104Util; -import com.yfd.platform.component.iec104.server.Iec104Master; -import com.yfd.platform.component.iec104.server.Iec104MasterFactory; +import com.yfd.platform.component.utils.OptimizedThreadPool; import io.netty.channel.ChannelHandlerContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/riis-system/src/main/java/com/yfd/platform/component/iec104/core/ScheduledTaskPool.java b/riis-system/src/main/java/com/yfd/platform/component/iec104/core/ScheduledTaskPool.java index 592f540..89e1954 100644 --- a/riis-system/src/main/java/com/yfd/platform/component/iec104/core/ScheduledTaskPool.java +++ b/riis-system/src/main/java/com/yfd/platform/component/iec104/core/ScheduledTaskPool.java @@ -1,13 +1,11 @@ package com.yfd.platform.component.iec104.core; import cn.hutool.core.util.ObjUtil; -import com.yfd.platform.component.iec104.client.MasterSysDataHandler; import com.yfd.platform.component.iec104.common.BasicInstruction104; import com.yfd.platform.component.iec104.message.MessageDetail; -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.utils.OptimizedThreadPool; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInboundHandlerAdapter; import lombok.extern.slf4j.Slf4j; diff --git a/riis-system/src/main/java/com/yfd/platform/component/iec104/server/master/handler/Iec104ClientHandler.java b/riis-system/src/main/java/com/yfd/platform/component/iec104/server/master/handler/Iec104ClientHandler.java index 4b715b1..8cf516d 100644 --- a/riis-system/src/main/java/com/yfd/platform/component/iec104/server/master/handler/Iec104ClientHandler.java +++ b/riis-system/src/main/java/com/yfd/platform/component/iec104/server/master/handler/Iec104ClientHandler.java @@ -1,7 +1,6 @@ package com.yfd.platform.component.iec104.server.master.handler; import cn.hutool.core.util.ObjUtil; -import com.yfd.platform.component.iec104.common.BasicInstruction104; import com.yfd.platform.component.iec104.core.*; import com.yfd.platform.component.iec104.message.MessageDetail; import com.yfd.platform.component.iec104.server.handler.ChannelHandlerImpl; @@ -9,6 +8,7 @@ import com.yfd.platform.component.iec104.server.handler.DataHandler; 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 io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInboundHandlerAdapter; import io.netty.channel.SimpleChannelInboundHandler; diff --git a/riis-system/src/main/java/com/yfd/platform/component/iec104/server/slave/handler/Iec104TcpSlaveHandler.java b/riis-system/src/main/java/com/yfd/platform/component/iec104/server/slave/handler/Iec104TcpSlaveHandler.java index da99589..324cec3 100644 --- a/riis-system/src/main/java/com/yfd/platform/component/iec104/server/slave/handler/Iec104TcpSlaveHandler.java +++ b/riis-system/src/main/java/com/yfd/platform/component/iec104/server/slave/handler/Iec104TcpSlaveHandler.java @@ -2,7 +2,7 @@ package com.yfd.platform.component.iec104.server.slave.handler; import com.yfd.platform.component.iec104.core.ControlManageUtil; import com.yfd.platform.component.iec104.core.Iec104ThreadLocal; -import com.yfd.platform.component.iec104.core.OptimizedThreadPool; +import com.yfd.platform.component.utils.OptimizedThreadPool; import com.yfd.platform.component.iec104.message.MessageDetail; import com.yfd.platform.component.iec104.server.handler.ChannelHandlerImpl; import com.yfd.platform.component.iec104.server.handler.DataHandler; diff --git a/riis-system/src/main/java/com/yfd/platform/component/iec61850/client/ClientConnetContext.java b/riis-system/src/main/java/com/yfd/platform/component/iec61850/client/ClientConnetContext.java new file mode 100644 index 0000000..a90419c --- /dev/null +++ b/riis-system/src/main/java/com/yfd/platform/component/iec61850/client/ClientConnetContext.java @@ -0,0 +1,21 @@ +package com.yfd.platform.component.iec61850.client; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +public class ClientConnetContext { + + private static Map contextMap = new ConcurrentHashMap<>(); + + public static void put(String key, Object value) { + contextMap.put(key, value); + } + + public static Object get(String key) { + return contextMap.get(key); + } + + public static void remove(String key) { + contextMap.remove(key); + } +} diff --git a/riis-system/src/main/java/com/yfd/platform/component/iec61850/client/IEC61850ClientListener.java b/riis-system/src/main/java/com/yfd/platform/component/iec61850/client/IEC61850ClientListener.java new file mode 100644 index 0000000..d887c8e --- /dev/null +++ b/riis-system/src/main/java/com/yfd/platform/component/iec61850/client/IEC61850ClientListener.java @@ -0,0 +1,77 @@ +package com.yfd.platform.component.iec61850.client; + +import com.beanit.iec61850bean.*; +import com.yfd.platform.modules.auxcontrol.mapper.DeviceSignalMapper; +import com.yfd.platform.modules.auxcontrol.service.IDeviceAlarmRecordService; +import com.yfd.platform.modules.auxcontrol.service.IDeviceWorkDataService; +import com.yfd.platform.utils.StringUtils; +import lombok.RequiredArgsConstructor; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +import java.io.IOException; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; + +@Component +@RequiredArgsConstructor +public class IEC61850ClientListener extends Thread implements ClientEventListener { + + private static final Logger log = LoggerFactory.getLogger(StringUtils.class); + + private final DeviceSignalMapper deviceSignalMapper; + private final IDeviceAlarmRecordService deviceAlarmRecordService; + private final IDeviceWorkDataService deviceWorkDataService; + + @Override + public void newReport(Report report) { + //遥测 测量值(浮点数) + for (FcModelNode value : report.getValues()) { + if ("MX".equals(value.getFc().name())) { + String node_name = value.getChild("mag").getChild("f").toString().split(":")[0].replace(".mag.f", ""); + BdaFloat32 f = (BdaFloat32) value.getChild("mag").getChild("f"); + String node_value = f.getValueString(); + BdaTimestamp t = (BdaTimestamp) value.getChild("t"); + String datestr = changeUTCtoLocalTime(t.getValueString()); + log.info(node_name + ":" + node_value + ":" + datestr); + //更新信号数据值 + deviceSignalMapper.updateDeviceSignalValue_yc(node_name, node_value, datestr); + //插入历史数据 + deviceWorkDataService.insertData("IEC61850", null, node_name, node_value, datestr); + //执行报警处理 + deviceAlarmRecordService.doAlaramRecord("IEC61850", "yc", null, node_name, node_value); + + } else if ("ST".equals(value.getFc().name())) { + //遥信 状态值 + String node_name = value.getChild("stVal").toString().split(":")[0].replace(".stVal", ""); + BdaBoolean state = (BdaBoolean) value.getChild("stVal"); + String node_value = state.getValue() ? "1" : "0"; + BdaTimestamp t = (BdaTimestamp) value.getChild("t"); + String datestr = changeUTCtoLocalTime(t.getValueString()); + log.info(node_name + ":" + node_value + ":" + datestr); + //更新信号状态 + deviceSignalMapper.updateDeviceSignalValue_yx(node_name, node_value, datestr); + //执行报警处理:生成设备自身报警记录(status=1) + deviceAlarmRecordService.doAlaramRecord("IEC61850", "yx", null, node_name, node_value); + } + } + } + + private String changeUTCtoLocalTime(String utctime) { + // 解析UTC时间字符串为ZonedDateTime对象 + ZonedDateTime utcDateTime = ZonedDateTime.parse(utctime); + // 将UTC时间转换为本地时间(假设本地时区为Asia/Shanghai) + ZonedDateTime localDateTime = utcDateTime.withZoneSameInstant(ZoneId.of("Asia/Shanghai")); + DateTimeFormatter LocalFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS"); + return localDateTime.format(LocalFormatter); + + } + + @Override + public void associationClosed(IOException e) { + log.info("客户端已连接到服务器!"); + } + +} diff --git a/riis-system/src/main/java/com/yfd/platform/component/iec61850/client/IEC61850ClientRunner.java b/riis-system/src/main/java/com/yfd/platform/component/iec61850/client/IEC61850ClientRunner.java new file mode 100644 index 0000000..349c4c2 --- /dev/null +++ b/riis-system/src/main/java/com/yfd/platform/component/iec61850/client/IEC61850ClientRunner.java @@ -0,0 +1,55 @@ + +package com.yfd.platform.component.iec61850.client; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.yfd.platform.component.utils.OptimizedThreadPool; +import com.yfd.platform.modules.auxcontrol.domain.GatewayDevice; +import com.yfd.platform.modules.auxcontrol.mapper.GatewayDeviceMapper; +import lombok.RequiredArgsConstructor; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.boot.ApplicationArguments; +import org.springframework.boot.ApplicationRunner; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Component; + +import java.util.List; + +/** + * @author + * @date 2019-01-07 + */ +@Component +@RequiredArgsConstructor +public class IEC61850ClientRunner implements ApplicationRunner { + + private static final Logger log = LoggerFactory.getLogger(IEC61850ClientRunner.class); + private final GatewayDeviceMapper gatewayDeviceMapper; + private final IEC61850Service iec61850Service; + + /** + * 项目启动时激活启用的IEC104 与各子站的连接任务 + * + * @param applicationArguments / + */ + @Override + @Async + public void run(ApplicationArguments applicationArguments) throws Exception { + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + // 没有停用 + queryWrapper.ne(GatewayDevice::getStatus, "00"); + queryWrapper.eq(GatewayDevice::getDeviceType, "30"); + queryWrapper.eq(GatewayDevice::getProtocol, "IEC61850"); + queryWrapper.select(GatewayDevice::getId, GatewayDevice::getDeviceCode, GatewayDevice::getDeviceName, + GatewayDevice::getIpAddr, GatewayDevice::getIecAddr, GatewayDevice::getUrcb, GatewayDevice::getBrcb); + queryWrapper.orderByAsc(GatewayDevice::getDeviceCode); + List list = gatewayDeviceMapper.selectList(queryWrapper); + if (!list.isEmpty()) { + for (GatewayDevice systemDevice : list) { + OptimizedThreadPool threadPool = OptimizedThreadPool.getInstance(); + threadPool.execute(() -> iec61850Service.connect(systemDevice)); + } + } + } + +} diff --git a/riis-system/src/main/java/com/yfd/platform/component/iec61850/client/IEC61850Service.java b/riis-system/src/main/java/com/yfd/platform/component/iec61850/client/IEC61850Service.java new file mode 100644 index 0000000..02c1bfb --- /dev/null +++ b/riis-system/src/main/java/com/yfd/platform/component/iec61850/client/IEC61850Service.java @@ -0,0 +1,186 @@ +package com.yfd.platform.component.iec61850.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.beanit.iec61850bean.*; +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 com.yfd.platform.utils.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.io.IOException; +import java.net.InetAddress; + +@Service +public class IEC61850Service { + + private static final Logger log = LoggerFactory.getLogger(StringUtils.class); + + @Resource + private IMeterDeviceService meterDeviceService; + @Resource + private IGatewayDeviceService gatewayDeviceService; + @Resource + private IDeviceSignalService deviceSignalService; + @Resource + private IEC61850ClientListener clientListener; + + /** + * 连接到设备并检索服务器模型 + * + * @param gatewayDevice 设备信息 + */ + public boolean connect(GatewayDevice gatewayDevice) { + ClientSap clientSap = new ClientSap(); + clientSap.setTSelRemote(new byte[]{0, 1}); + clientSap.setTSelLocal(new byte[]{0, 0}); + clientSap.setApTitleCalled(new int[]{1, 1, 999, 1}); + + ClientAssociation clientAssociation = null; + try { + clientAssociation = clientSap.associate(InetAddress.getByName(gatewayDevice.getIpAddr()), 102, null, + clientListener); + //保存到系统上下文中 + ClientConnetContext.put(gatewayDevice.getIpAddr(), clientAssociation); + + ServerModel serverModel = clientAssociation.retrieveModel(); + //"TEMPLATELD_Device0/LLN0.urcbAin1p01" + String urcbs = gatewayDevice.getUrcb(); + if (StrUtil.isNotEmpty(urcbs)) { + String[] urcbArray = urcbs.split(","); + for (String s : urcbArray) { + Urcb urcb = serverModel.getUrcb(s); + clientAssociation.getRcbValues(urcb); + clientAssociation.reserveUrcb(urcb); + clientAssociation.enableReporting(urcb); + } + } + //"TEMPLATELD_Device8/LLN0.brcbDin1p01" + String brcbs = gatewayDevice.getBrcb(); + if (StrUtil.isNotEmpty(brcbs)) { + String[] brcbArray = brcbs.split(","); + for (String s : brcbArray) { + Brcb brcb = serverModel.getBrcb(s); + clientAssociation.getRcbValues(brcb); + clientAssociation.enableReporting(brcb); + } + } + //sendCommand("", "a397bf1d4042ae948d248b1f1856937e", "yk", "true"); + //sendCommand("", "a397bf1d4042ae948d248b1f1856937e", "yt", "25.6"); + } catch (ServiceError | IOException e) { + log.info("未能关联或检索设备的模型 %s: %s", gatewayDevice.getDeviceCode(), + e.getMessage()); + } + return true; + } + + /** + * 从服务器断开连接 + * + * @param gatewayDevice 设备信息 + */ + public boolean disconnect(GatewayDevice gatewayDevice) { + ClientAssociation association = (ClientAssociation) ClientConnetContext.get(gatewayDevice.getIpAddr()); + association.disconnect(); + return true; + } + + /** + * 给设备发送遥控、遥调命令 + *

+ * systemcode 系统编号 + * signalid 信号id + * type 类型(yk、yt) + * value + */ + public boolean sendCommand(String systemcode, String signalid, String type, String value) throws IOException, + ServiceError { + + 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)) { + //连接到子系统的通讯网关 + connect(gatewayDevice); + } else { + //断开与子系统通讯网关的连接 + disconnect(gatewayDevice); + } + } + } else { + if (ObjUtil.isNotEmpty(deviceSignal)) { + //查找设备 + MeterDevice meterDevice = meterDeviceService.getById(deviceSignal.getMeterDeviceId()); + QueryWrapper queryWrapper = new QueryWrapper<>(); + //通讯网关机的IP地址 + queryWrapper.eq("ip_addr", meterDevice.getNetdeviceIp()); + //查找网关机 + GatewayDevice gatewayDevice = gatewayDeviceService.getOne(queryWrapper); + String convalue = value; + if (ObjUtil.isNotEmpty(gatewayDevice)) { + String address = ""; + if ("yk".equals(type)) { + convalue = "1".equals(value) ? "true" : "false"; + address = deviceSignal.getYkAddr(); + } else if ("yt".equals(type)) { + address = deviceSignal.getYtAddr(); + } + //获取连接 + ClientAssociation association = + (ClientAssociation) ClientConnetContext.get(meterDevice.getNetdeviceIp()); + if (ObjUtil.isNotEmpty(association)) { + //检索模型 + ServerModel serverModel = association.retrieveModel(); + if ("true".equals(convalue) || "false".equals(convalue)) { + FcModelNode fcModelNode = (FcModelNode) serverModel.findModelNode(address, Fc.CO); + ModelNode oper = fcModelNode.getChild("Oper"); + BdaBoolean ctlVal = (BdaBoolean) oper.getChild("ctlVal"); + boolean b_value = Boolean.parseBoolean(convalue); + ctlVal.setValue(b_value); + association.operate(fcModelNode); + } else { + FcModelNode fcModelNode = (FcModelNode) serverModel.findModelNode(address, Fc.SP); + if (fcModelNode == null) { + throw new IllegalArgumentException("Model node not found for address: " + address); + } + // 获取 "SetVal" 子节点 + ModelNode setValNode = fcModelNode.getChild("SetVal"); + if (!(setValNode instanceof BdaFloat32)) { + throw new IllegalArgumentException("'SetVal' child node not found or not of type " + + "BdaFloat32 for model node: " + address); + } + // 将 "SetVal" 子节点强制转换为 BdaFloat32 并设置值 + BdaFloat32 setVal = (BdaFloat32) setValNode; + float temperature = Float.parseFloat(convalue); // 目标温度值,例如 22.5 摄氏度 + setVal.setFloat(temperature); + // 执行操作命令 + association.setDataValues(fcModelNode); + } + + } + } + } + } + return false; + } + +} + diff --git a/riis-system/src/main/java/com/yfd/platform/component/iec104/core/OptimizedThreadPool.java b/riis-system/src/main/java/com/yfd/platform/component/utils/OptimizedThreadPool.java similarity index 98% rename from riis-system/src/main/java/com/yfd/platform/component/iec104/core/OptimizedThreadPool.java rename to riis-system/src/main/java/com/yfd/platform/component/utils/OptimizedThreadPool.java index 2a4e30c..1a1b715 100644 --- a/riis-system/src/main/java/com/yfd/platform/component/iec104/core/OptimizedThreadPool.java +++ b/riis-system/src/main/java/com/yfd/platform/component/utils/OptimizedThreadPool.java @@ -1,4 +1,4 @@ -package com.yfd.platform.component.iec104.core; +package com.yfd.platform.component.utils; import org.jetbrains.annotations.NotNull; 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 a6d1908..dc11e8a 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 @@ -2,6 +2,7 @@ package com.yfd.platform.modules.auxcontrol.mapper; import com.yfd.platform.modules.auxcontrol.domain.DeviceSignal; import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.Update; import java.util.List; import java.util.Map; @@ -18,6 +19,9 @@ 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); + @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}") + boolean updateDeviceSignalValue_yx(String node_addr,String value,String datetime); }