fix:协议驱动完善+工厂类
This commit is contained in:
@@ -0,0 +1,70 @@
|
|||||||
|
package org.nl.iot.core.driver;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.nl.common.exception.CommonException;
|
||||||
|
import org.nl.iot.core.driver.service.DriverCustomService;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 抽象驱动类
|
||||||
|
* @Author: liyongde
|
||||||
|
* @Date: 2026/3/19 16:06
|
||||||
|
* @Modified By:
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
public abstract class AbstractProtocolDriver<T> implements DriverCustomService {
|
||||||
|
|
||||||
|
protected Map<String, T> connectMap = new ConcurrentHashMap<>();;
|
||||||
|
|
||||||
|
// 注入映射管理器
|
||||||
|
protected final ConnectionProtocolMappingManager mappingManager;
|
||||||
|
|
||||||
|
// 构造方法注入
|
||||||
|
public AbstractProtocolDriver(ConnectionProtocolMappingManager mappingManager) {
|
||||||
|
this.mappingManager = mappingManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建连接(统一方法,自动注册映射)
|
||||||
|
* @param connectionId 连接ID(原key)
|
||||||
|
* @param protocolCode 协议编码
|
||||||
|
* @param connection 连接对象
|
||||||
|
*/
|
||||||
|
public void addConnection(String connectionId, String protocolCode, T connection) {
|
||||||
|
if (connection == null) {
|
||||||
|
throw new CommonException("连接对象不能为空");
|
||||||
|
}
|
||||||
|
connectMap.put(connectionId, connection);
|
||||||
|
// 注册连接ID与协议的映射
|
||||||
|
mappingManager.registerMapping(connectionId, protocolCode);
|
||||||
|
log.info("新增连接:协议={},连接ID={}", protocolCode, connectionId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 重写删除方法:删除连接后同步清理映射
|
||||||
|
*/
|
||||||
|
public void removeConnection(String connectionId) {
|
||||||
|
if (connectMap.isEmpty() || !connectMap.containsKey(connectionId)) {
|
||||||
|
log.warn("连接ID={}不存在,无需删除", connectionId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 1. 删除连接对象
|
||||||
|
T connection = connectMap.remove(connectionId);
|
||||||
|
closeConnection(connection);
|
||||||
|
// 2. 清理映射关系
|
||||||
|
mappingManager.removeMapping(connectionId);
|
||||||
|
log.info("删除连接成功:连接ID={}", connectionId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 抽象方法:子类实现具体的连接关闭逻辑(类型安全)
|
||||||
|
* @param connection 要关闭的连接对象
|
||||||
|
*/
|
||||||
|
protected abstract void closeConnection(T connection);
|
||||||
|
|
||||||
|
// 保留event方法的抽象(子类必须实现)
|
||||||
|
// @Override
|
||||||
|
// public abstract void event(MetadataEventDTO metadataEvent);
|
||||||
|
}
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
package org.nl.iot.core.driver;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.nl.common.exception.CommonException;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 全局连接ID-协议编码映射管理器
|
||||||
|
* 核心作用:记录每个连接ID所属的协议编码,解决删除时"只知ID不知协议"的问题
|
||||||
|
* @Author: liyongde
|
||||||
|
* @Date: 2026/3/19 16:30
|
||||||
|
* @Modified By:
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
public class ConnectionProtocolMappingManager {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 映射表:连接ID → 协议编码(如 "conn_123" → "MODBUS")
|
||||||
|
*/
|
||||||
|
private final Map<String, String> connectionId2ProtocolCode = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 注册连接ID与协议编码的映射(创建连接时调用)
|
||||||
|
*/
|
||||||
|
public void registerMapping(String connectionId, String protocolCode) {
|
||||||
|
if (connectionId == null || connectionId.trim().isEmpty()) {
|
||||||
|
throw new CommonException("连接ID不能为空");
|
||||||
|
}
|
||||||
|
if (protocolCode == null || protocolCode.trim().isEmpty()) {
|
||||||
|
throw new CommonException("协议编码不能为空");
|
||||||
|
}
|
||||||
|
String upperCode = protocolCode.trim().toUpperCase();
|
||||||
|
connectionId2ProtocolCode.put(connectionId.trim(), upperCode);
|
||||||
|
log.debug("注册连接映射:连接ID={} → 协议编码={}", connectionId, upperCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据连接ID获取协议编码(删除连接时调用)
|
||||||
|
*/
|
||||||
|
public String getProtocolCodeByConnectionId(String connectionId) {
|
||||||
|
if (connectionId == null || connectionId.trim().isEmpty()) {
|
||||||
|
throw new CommonException("连接ID不能为空");
|
||||||
|
}
|
||||||
|
String protocolCode = connectionId2ProtocolCode.get(connectionId.trim());
|
||||||
|
if (protocolCode == null) {
|
||||||
|
throw new CommonException("未找到连接ID[" + connectionId + "]对应的协议编码");
|
||||||
|
}
|
||||||
|
return protocolCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除映射关系(连接删除后同步清理)
|
||||||
|
*/
|
||||||
|
public void removeMapping(String connectionId) {
|
||||||
|
if (connectionId == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
connectionId2ProtocolCode.remove(connectionId.trim());
|
||||||
|
log.debug("移除连接映射:连接ID={}", connectionId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查连接ID是否已注册
|
||||||
|
*/
|
||||||
|
public boolean containsMapping(String connectionId) {
|
||||||
|
return connectionId != null && connectionId2ProtocolCode.containsKey(connectionId.trim());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
package org.nl.iot.core.driver;
|
||||||
|
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.nl.common.exception.CommonException;
|
||||||
|
import org.nl.iot.core.driver.service.DriverCustomService;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @Author: liyongde
|
||||||
|
* @Date: 2026/3/19 16:49
|
||||||
|
* @Modified By:
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
public class DriverConnectionManager {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private DriverCustomFactory driverCustomFactory;
|
||||||
|
@Resource
|
||||||
|
private ConnectionProtocolMappingManager mappingManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 核心方法:仅传入连接ID,自动删除对应协议的连接
|
||||||
|
* (无需知道协议编码,完全适配你的场景)
|
||||||
|
*/
|
||||||
|
public void removeConnectionById(String connectionId) {
|
||||||
|
// 1. 校验参数
|
||||||
|
if (connectionId == null || connectionId.trim().isEmpty()) {
|
||||||
|
throw new CommonException("连接ID不能为空");
|
||||||
|
}
|
||||||
|
// 2. 根据连接ID获取协议编码
|
||||||
|
String protocolCode = mappingManager.getProtocolCodeByConnectionId(connectionId);
|
||||||
|
// 3. 通过工厂类获取对应驱动
|
||||||
|
DriverCustomService driver = driverCustomFactory.getDriver(protocolCode);
|
||||||
|
if (!(driver instanceof AbstractProtocolDriver<?>)) {
|
||||||
|
throw new CommonException("驱动类[" + driver.getClass().getSimpleName() + "]未继承AbstractProtocolDriver");
|
||||||
|
}
|
||||||
|
// 4. 强转并调用删除方法
|
||||||
|
AbstractProtocolDriver<?> abstractDriver = (AbstractProtocolDriver<?>) driver;
|
||||||
|
abstractDriver.removeConnection(connectionId);
|
||||||
|
log.info("删除连接完成:连接ID={},协议编码={}", connectionId, protocolCode);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
package org.nl.iot.core.driver.protocol.modbustcp;
|
package org.nl.iot.core.driver.protocol.modbustcp;
|
||||||
|
|
||||||
import jakarta.annotation.PostConstruct;
|
|
||||||
import lombok.SneakyThrows;
|
import lombok.SneakyThrows;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.plc4x.java.DefaultPlcDriverManager;
|
import org.apache.plc4x.java.DefaultPlcDriverManager;
|
||||||
@@ -11,6 +10,8 @@ import org.apache.plc4x.java.api.messages.PlcWriteRequest;
|
|||||||
import org.apache.plc4x.java.api.messages.PlcWriteResponse;
|
import org.apache.plc4x.java.api.messages.PlcWriteResponse;
|
||||||
import org.apache.plc4x.java.api.types.PlcResponseCode;
|
import org.apache.plc4x.java.api.types.PlcResponseCode;
|
||||||
import org.apache.plc4x.java.api.value.PlcValue;
|
import org.apache.plc4x.java.api.value.PlcValue;
|
||||||
|
import org.nl.iot.core.driver.AbstractProtocolDriver;
|
||||||
|
import org.nl.iot.core.driver.ConnectionProtocolMappingManager;
|
||||||
import org.nl.iot.core.driver.ProtocolDriver;
|
import org.nl.iot.core.driver.ProtocolDriver;
|
||||||
import org.nl.iot.core.driver.ProtocolType;
|
import org.nl.iot.core.driver.ProtocolType;
|
||||||
import org.nl.iot.core.driver.bo.DeviceBO;
|
import org.nl.iot.core.driver.bo.DeviceBO;
|
||||||
@@ -19,16 +20,16 @@ import org.nl.iot.core.driver.bo.SiteBO;
|
|||||||
import org.nl.iot.core.driver.entity.RValue;
|
import org.nl.iot.core.driver.entity.RValue;
|
||||||
import org.nl.iot.core.driver.entity.WResponse;
|
import org.nl.iot.core.driver.entity.WResponse;
|
||||||
import org.nl.iot.core.driver.entity.WValue;
|
import org.nl.iot.core.driver.entity.WValue;
|
||||||
import org.nl.iot.core.driver.enums.MetadataOperateTypeEnum;
|
|
||||||
import org.nl.iot.core.driver.util.JavaToPlcValueConvertUtil;
|
|
||||||
import org.nl.iot.core.driver.protocol.modbustcp.util.ModBusTcpUtils;
|
import org.nl.iot.core.driver.protocol.modbustcp.util.ModBusTcpUtils;
|
||||||
|
import org.nl.iot.core.driver.util.JavaToPlcValueConvertUtil;
|
||||||
import org.nl.iot.core.driver.util.PlcValueConvertUtil;
|
import org.nl.iot.core.driver.util.PlcValueConvertUtil;
|
||||||
import org.nl.iot.core.driver.service.DriverCustomService;
|
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -39,14 +40,14 @@ import java.util.concurrent.TimeUnit;
|
|||||||
@Slf4j
|
@Slf4j
|
||||||
@Service
|
@Service
|
||||||
@ProtocolDriver(ProtocolType.MODBUS)
|
@ProtocolDriver(ProtocolType.MODBUS)
|
||||||
public class ModBusProtocolDriverImpl implements DriverCustomService {
|
public class ModBusProtocolDriverImpl extends AbstractProtocolDriver<PlcConnection> {
|
||||||
|
|
||||||
private Map<String, PlcConnection> connectMap;
|
public ModBusProtocolDriverImpl(ConnectionProtocolMappingManager mappingManager) {
|
||||||
|
super(mappingManager);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@PostConstruct
|
|
||||||
public void initial() {
|
public void initial() {
|
||||||
connectMap = new ConcurrentHashMap<>(16);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -56,13 +57,13 @@ public class ModBusProtocolDriverImpl implements DriverCustomService {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void event(MetadataEventDTO metadataEvent) {
|
public void event(MetadataEventDTO metadataEvent) {
|
||||||
MetadataOperateTypeEnum operateType = metadataEvent.getOperateType();
|
// MetadataOperateTypeEnum operateType = metadataEvent.getOperateType();
|
||||||
log.info("Device metadata event: connectId: {}, operate: {}", metadataEvent.getConnectId(), operateType);
|
// log.info("Device metadata event: connectId: {}, operate: {}", metadataEvent.getConnectId(), operateType);
|
||||||
|
//
|
||||||
// When the device is updated or deleted, remove the corresponding connection handle
|
// // When the device is updated or deleted, remove the corresponding connection handle
|
||||||
if (MetadataOperateTypeEnum.DELETE.equals(operateType) || MetadataOperateTypeEnum.UPDATE.equals(operateType)) {
|
// if (MetadataOperateTypeEnum.DELETE.equals(operateType) || MetadataOperateTypeEnum.UPDATE.equals(operateType)) {
|
||||||
connectMap.remove(metadataEvent.getConnectId());
|
// connectMap.remove(metadataEvent.getConnectId());
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -85,6 +86,14 @@ public class ModBusProtocolDriverImpl implements DriverCustomService {
|
|||||||
return batchWriteValue(getConnector(device), wValue);
|
return batchWriteValue(getConnector(device), wValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void closeConnection(PlcConnection connection) {
|
||||||
|
try {
|
||||||
|
connection.close();
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.warn("关闭失败:{}", e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
public static List<WResponse> batchWriteValue(PlcConnection modbusMaster, List<WValue> wValues) {
|
public static List<WResponse> batchWriteValue(PlcConnection modbusMaster, List<WValue> wValues) {
|
||||||
List<WResponse> res = new ArrayList<>();
|
List<WResponse> res = new ArrayList<>();
|
||||||
@@ -119,6 +128,7 @@ public class ModBusProtocolDriverImpl implements DriverCustomService {
|
|||||||
try {
|
try {
|
||||||
if (Objects.isNull(modbusMaster)) {
|
if (Objects.isNull(modbusMaster)) {
|
||||||
modbusMaster = new DefaultPlcDriverManager().getConnection(ModBusTcpUtils.buildModBusPlcUrl(deviceBO));
|
modbusMaster = new DefaultPlcDriverManager().getConnection(ModBusTcpUtils.buildModBusPlcUrl(deviceBO));
|
||||||
|
createModBusConnection(deviceBO.getId(), modbusMaster);
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
@@ -126,6 +136,12 @@ public class ModBusProtocolDriverImpl implements DriverCustomService {
|
|||||||
return modbusMaster;
|
return modbusMaster;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 业务中创建连接时,调用父类的addConnection方法
|
||||||
|
public void createModBusConnection(String connectionId, PlcConnection connection) {
|
||||||
|
// 传入协议编码(MODBUS)和连接ID、连接对象
|
||||||
|
addConnection(connectionId, ProtocolType.MODBUS.getMainCode(), connection);
|
||||||
|
}
|
||||||
|
|
||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
public String readValue(PlcConnection modbusMaster, SiteBO point) {
|
public String readValue(PlcConnection modbusMaster, SiteBO point) {
|
||||||
// 1. 解析配置
|
// 1. 解析配置
|
||||||
|
|||||||
@@ -2,12 +2,13 @@ package org.nl.iot.core.driver.protocol.opcda;
|
|||||||
|
|
||||||
import cn.hutool.core.util.ObjectUtil;
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
import com.alibaba.fastjson.JSONObject;
|
import com.alibaba.fastjson.JSONObject;
|
||||||
import jakarta.annotation.PostConstruct;
|
|
||||||
import lombok.SneakyThrows;
|
import lombok.SneakyThrows;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.jinterop.dcom.common.JIException;
|
import org.jinterop.dcom.common.JIException;
|
||||||
import org.jinterop.dcom.core.JIVariant;
|
import org.jinterop.dcom.core.JIVariant;
|
||||||
import org.nl.common.exception.CommonException;
|
import org.nl.common.exception.CommonException;
|
||||||
|
import org.nl.iot.core.driver.AbstractProtocolDriver;
|
||||||
|
import org.nl.iot.core.driver.ConnectionProtocolMappingManager;
|
||||||
import org.nl.iot.core.driver.ProtocolDriver;
|
import org.nl.iot.core.driver.ProtocolDriver;
|
||||||
import org.nl.iot.core.driver.ProtocolType;
|
import org.nl.iot.core.driver.ProtocolType;
|
||||||
import org.nl.iot.core.driver.bo.DeviceBO;
|
import org.nl.iot.core.driver.bo.DeviceBO;
|
||||||
@@ -16,14 +17,12 @@ import org.nl.iot.core.driver.bo.SiteBO;
|
|||||||
import org.nl.iot.core.driver.entity.RValue;
|
import org.nl.iot.core.driver.entity.RValue;
|
||||||
import org.nl.iot.core.driver.entity.WResponse;
|
import org.nl.iot.core.driver.entity.WResponse;
|
||||||
import org.nl.iot.core.driver.entity.WValue;
|
import org.nl.iot.core.driver.entity.WValue;
|
||||||
import org.nl.iot.core.driver.enums.MetadataOperateTypeEnum;
|
|
||||||
import org.nl.iot.core.driver.enums.PointTypeFlagEnum;
|
import org.nl.iot.core.driver.enums.PointTypeFlagEnum;
|
||||||
import org.nl.iot.core.driver.protocol.opcda.org.openscada.opc.lib.common.AlreadyConnectedException;
|
import org.nl.iot.core.driver.protocol.opcda.org.openscada.opc.lib.common.AlreadyConnectedException;
|
||||||
import org.nl.iot.core.driver.protocol.opcda.org.openscada.opc.lib.common.ConnectionInformation;
|
import org.nl.iot.core.driver.protocol.opcda.org.openscada.opc.lib.common.ConnectionInformation;
|
||||||
import org.nl.iot.core.driver.protocol.opcda.org.openscada.opc.lib.common.NotConnectedException;
|
import org.nl.iot.core.driver.protocol.opcda.org.openscada.opc.lib.common.NotConnectedException;
|
||||||
import org.nl.iot.core.driver.protocol.opcda.org.openscada.opc.lib.da.*;
|
import org.nl.iot.core.driver.protocol.opcda.org.openscada.opc.lib.da.*;
|
||||||
import org.nl.iot.core.driver.protocol.opcda.util.JIVariantToStringUtil;
|
import org.nl.iot.core.driver.protocol.opcda.util.JIVariantToStringUtil;
|
||||||
import org.nl.iot.core.driver.service.DriverCustomService;
|
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import java.net.UnknownHostException;
|
import java.net.UnknownHostException;
|
||||||
@@ -31,29 +30,19 @@ import java.util.ArrayList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Service
|
@Service
|
||||||
@ProtocolDriver(ProtocolType.OPCDA)
|
@ProtocolDriver(ProtocolType.OPCDA)
|
||||||
public class OpcDaProtocolDriverImpl implements DriverCustomService {
|
public class OpcDaProtocolDriverImpl extends AbstractProtocolDriver<Server> {
|
||||||
/**
|
|
||||||
* Opc Da Server Map
|
public OpcDaProtocolDriverImpl(ConnectionProtocolMappingManager mappingManager) {
|
||||||
*/
|
super(mappingManager);
|
||||||
private Map<String, Server> connectMap;
|
}
|
||||||
|
|
||||||
@PostConstruct
|
|
||||||
@Override
|
@Override
|
||||||
public void initial() {
|
public void initial() {
|
||||||
/*
|
|
||||||
* 驱动初始化逻辑
|
|
||||||
*
|
|
||||||
* 提示: 此处逻辑仅供参考, 请务必结合实际应用场景进行修改。
|
|
||||||
* 驱动启动时会自动执行该方法, 您可以在此处执行特定的初始化操作。
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
connectMap = new ConcurrentHashMap<>(16);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -63,12 +52,21 @@ public class OpcDaProtocolDriverImpl implements DriverCustomService {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void event(MetadataEventDTO metadataEvent) {
|
public void event(MetadataEventDTO metadataEvent) {
|
||||||
MetadataOperateTypeEnum operateType = metadataEvent.getOperateType();
|
// MetadataOperateTypeEnum operateType = metadataEvent.getOperateType();
|
||||||
log.info("Device metadata event: connectId: {}, operate: {}", metadataEvent.getConnectId(), operateType);
|
// log.info("Device metadata event: connectId: {}, operate: {}", metadataEvent.getConnectId(), operateType);
|
||||||
|
//
|
||||||
|
// // When the device is updated or deleted, remove the corresponding connection handle
|
||||||
|
// if (MetadataOperateTypeEnum.DELETE.equals(operateType) || MetadataOperateTypeEnum.UPDATE.equals(operateType)) {
|
||||||
|
// connectMap.remove(metadataEvent.getConnectId());
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
// When the device is updated or deleted, remove the corresponding connection handle
|
@Override
|
||||||
if (MetadataOperateTypeEnum.DELETE.equals(operateType) || MetadataOperateTypeEnum.UPDATE.equals(operateType)) {
|
protected void closeConnection(Server server) {
|
||||||
connectMap.remove(metadataEvent.getConnectId());
|
try {
|
||||||
|
server.disconnect();
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.warn("关闭失败:{}", e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -109,9 +107,9 @@ public class OpcDaProtocolDriverImpl implements DriverCustomService {
|
|||||||
server = new Server(connectionInformation, Executors.newSingleThreadScheduledExecutor());
|
server = new Server(connectionInformation, Executors.newSingleThreadScheduledExecutor());
|
||||||
try {
|
try {
|
||||||
server.connect();
|
server.connect();
|
||||||
connectMap.put(deviceBO.getId(), server);
|
addOpcDaConnection(deviceBO.getId(), server);
|
||||||
} catch (AlreadyConnectedException | UnknownHostException | JIException e) {
|
} catch (AlreadyConnectedException | UnknownHostException | JIException e) {
|
||||||
connectMap.entrySet().removeIf(next -> next.getKey().equals(deviceBO.getId()));
|
removeConnection(deviceBO.getId());
|
||||||
log.error("Connect opc da server error: {}", e.getMessage(), e);
|
log.error("Connect opc da server error: {}", e.getMessage(), e);
|
||||||
throw new CommonException(e.getMessage());
|
throw new CommonException(e.getMessage());
|
||||||
}
|
}
|
||||||
@@ -119,6 +117,12 @@ public class OpcDaProtocolDriverImpl implements DriverCustomService {
|
|||||||
return server;
|
return server;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 业务中创建连接时,调用父类的addConnection方法
|
||||||
|
public void addOpcDaConnection(String connectionId, Server connection) {
|
||||||
|
// 传入协议编码(OpcDa)和连接ID、连接对象
|
||||||
|
addConnection(connectionId, ProtocolType.OPCDA.getMainCode(), connection);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 从 OPC DA 服务器读取位号值
|
* 从 OPC DA 服务器读取位号值
|
||||||
* <p>
|
* <p>
|
||||||
|
|||||||
@@ -1,11 +1,9 @@
|
|||||||
package org.nl.iot.core.driver.protocol.opcua;
|
package org.nl.iot.core.driver.protocol.opcua;
|
||||||
|
|
||||||
import com.alibaba.fastjson.JSONObject;
|
import com.alibaba.fastjson.JSONObject;
|
||||||
import jakarta.annotation.PostConstruct;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.eclipse.milo.opcua.sdk.client.OpcUaClient;
|
import org.eclipse.milo.opcua.sdk.client.OpcUaClient;
|
||||||
import org.eclipse.milo.opcua.sdk.client.api.identity.AnonymousProvider;
|
import org.eclipse.milo.opcua.sdk.client.api.identity.AnonymousProvider;
|
||||||
import org.eclipse.milo.opcua.stack.core.AttributeId;
|
|
||||||
import org.eclipse.milo.opcua.stack.core.UaException;
|
import org.eclipse.milo.opcua.stack.core.UaException;
|
||||||
import org.eclipse.milo.opcua.stack.core.types.builtin.DataValue;
|
import org.eclipse.milo.opcua.stack.core.types.builtin.DataValue;
|
||||||
import org.eclipse.milo.opcua.stack.core.types.builtin.NodeId;
|
import org.eclipse.milo.opcua.stack.core.types.builtin.NodeId;
|
||||||
@@ -13,8 +11,9 @@ import org.eclipse.milo.opcua.stack.core.types.builtin.StatusCode;
|
|||||||
import org.eclipse.milo.opcua.stack.core.types.builtin.Variant;
|
import org.eclipse.milo.opcua.stack.core.types.builtin.Variant;
|
||||||
import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.Unsigned;
|
import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.Unsigned;
|
||||||
import org.eclipse.milo.opcua.stack.core.types.enumerated.TimestampsToReturn;
|
import org.eclipse.milo.opcua.stack.core.types.enumerated.TimestampsToReturn;
|
||||||
import org.eclipse.milo.opcua.stack.core.types.structured.WriteValue;
|
|
||||||
import org.nl.common.exception.CommonException;
|
import org.nl.common.exception.CommonException;
|
||||||
|
import org.nl.iot.core.driver.AbstractProtocolDriver;
|
||||||
|
import org.nl.iot.core.driver.ConnectionProtocolMappingManager;
|
||||||
import org.nl.iot.core.driver.ProtocolDriver;
|
import org.nl.iot.core.driver.ProtocolDriver;
|
||||||
import org.nl.iot.core.driver.ProtocolType;
|
import org.nl.iot.core.driver.ProtocolType;
|
||||||
import org.nl.iot.core.driver.bo.DeviceBO;
|
import org.nl.iot.core.driver.bo.DeviceBO;
|
||||||
@@ -25,49 +24,38 @@ import org.nl.iot.core.driver.entity.WResponse;
|
|||||||
import org.nl.iot.core.driver.entity.WValue;
|
import org.nl.iot.core.driver.entity.WValue;
|
||||||
import org.nl.iot.core.driver.enums.MetadataOperateTypeEnum;
|
import org.nl.iot.core.driver.enums.MetadataOperateTypeEnum;
|
||||||
import org.nl.iot.core.driver.enums.PointTypeFlagEnum;
|
import org.nl.iot.core.driver.enums.PointTypeFlagEnum;
|
||||||
import org.nl.iot.core.driver.service.DriverCustomService;
|
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import jakarta.annotation.PreDestroy;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.concurrent.*;
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
import java.util.concurrent.ExecutionException;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.concurrent.TimeoutException;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Service
|
@Service
|
||||||
@ProtocolDriver(ProtocolType.OPCUA)
|
@ProtocolDriver(ProtocolType.OPCUA)
|
||||||
public class OpcUaProtocolDriverImpl implements DriverCustomService {
|
public class OpcUaProtocolDriverImpl extends AbstractProtocolDriver<OpcUaClient> {
|
||||||
private Map<String, OpcUaClient> connectMap;
|
|
||||||
|
|
||||||
@PostConstruct
|
public OpcUaProtocolDriverImpl(ConnectionProtocolMappingManager mappingManager) {
|
||||||
@Override
|
super(mappingManager);
|
||||||
public void initial() {
|
|
||||||
/*
|
|
||||||
* 驱动初始化逻辑
|
|
||||||
*
|
|
||||||
* 提示: 此处逻辑仅供参考, 请务必结合实际应用场景进行修改。
|
|
||||||
* 驱动启动时会自动执行该方法, 您可以在此处执行特定的初始化操作。
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
connectMap = new ConcurrentHashMap<>(16);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// @PreDestroy
|
@Override
|
||||||
// public void destroy() {
|
public void initial() {
|
||||||
// // 应用关闭时清理所有连接
|
|
||||||
// log.info("Cleaning up OPC UA connections...");
|
}
|
||||||
// connectMap.values().forEach(client -> {
|
|
||||||
// try {
|
@Override
|
||||||
// client.disconnect().get(5, TimeUnit.SECONDS);
|
protected void closeConnection(OpcUaClient client) {
|
||||||
// } catch (Exception e) {
|
try {
|
||||||
// log.warn("Error disconnecting OPC UA client during cleanup: {}", e.getMessage());
|
client.disconnect().get(5, TimeUnit.SECONDS);
|
||||||
// }
|
} catch (Exception e) {
|
||||||
// });
|
log.error("Error disconnecting OPC UA client during cleanup: {}", e.getMessage());
|
||||||
// connectMap.clear();
|
}
|
||||||
// log.info("OPC UA connections cleanup completed");
|
}
|
||||||
// }
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void schedule() {
|
public void schedule() {
|
||||||
@@ -171,10 +159,10 @@ public class OpcUaProtocolDriverImpl implements DriverCustomService {
|
|||||||
.setSessionTimeout(Unsigned.uint(60000)) // 设置会话超时时间为 60 秒
|
.setSessionTimeout(Unsigned.uint(60000)) // 设置会话超时时间为 60 秒
|
||||||
.build()
|
.build()
|
||||||
);
|
);
|
||||||
connectMap.put(device.getId(), opcUaClient);
|
addOPCUAConnection(device.getId(), opcUaClient);
|
||||||
log.info("Created new OPC UA client for device: {}", device.getId());
|
log.info("Created new OPC UA client for device: {}", device.getId());
|
||||||
} catch (UaException e) {
|
} catch (UaException e) {
|
||||||
connectMap.entrySet().removeIf(next -> next.getKey().equals(device.getId()));
|
removeConnection(device.getId());
|
||||||
log.error("Failed to create OPC UA client: {}", e.getMessage(), e);
|
log.error("Failed to create OPC UA client: {}", e.getMessage(), e);
|
||||||
throw new IllegalArgumentException(e.getMessage());
|
throw new IllegalArgumentException(e.getMessage());
|
||||||
}
|
}
|
||||||
@@ -182,6 +170,12 @@ public class OpcUaProtocolDriverImpl implements DriverCustomService {
|
|||||||
return opcUaClient;
|
return opcUaClient;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 业务中创建连接时,调用父类的addConnection方法
|
||||||
|
public void addOPCUAConnection(String connectionId, OpcUaClient connection) {
|
||||||
|
// 传入协议编码(OPCUA)和连接ID、连接对象
|
||||||
|
addConnection(connectionId, ProtocolType.OPCUA.getMainCode(), connection);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 读取 OPC UA 节点的值
|
* 读取 OPC UA 节点的值
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
package org.nl.iot.core.driver.protocol.plcs7;
|
package org.nl.iot.core.driver.protocol.plcs7;
|
||||||
|
|
||||||
import jakarta.annotation.PostConstruct;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.plc4x.java.DefaultPlcDriverManager;
|
import org.apache.plc4x.java.DefaultPlcDriverManager;
|
||||||
import org.apache.plc4x.java.api.PlcConnection;
|
import org.apache.plc4x.java.api.PlcConnection;
|
||||||
@@ -11,6 +10,8 @@ import org.apache.plc4x.java.api.messages.PlcWriteResponse;
|
|||||||
import org.apache.plc4x.java.api.types.PlcResponseCode;
|
import org.apache.plc4x.java.api.types.PlcResponseCode;
|
||||||
import org.apache.plc4x.java.api.value.PlcValue;
|
import org.apache.plc4x.java.api.value.PlcValue;
|
||||||
import org.nl.common.exception.CommonException;
|
import org.nl.common.exception.CommonException;
|
||||||
|
import org.nl.iot.core.driver.AbstractProtocolDriver;
|
||||||
|
import org.nl.iot.core.driver.ConnectionProtocolMappingManager;
|
||||||
import org.nl.iot.core.driver.ProtocolDriver;
|
import org.nl.iot.core.driver.ProtocolDriver;
|
||||||
import org.nl.iot.core.driver.ProtocolType;
|
import org.nl.iot.core.driver.ProtocolType;
|
||||||
import org.nl.iot.core.driver.bo.DeviceBO;
|
import org.nl.iot.core.driver.bo.DeviceBO;
|
||||||
@@ -19,15 +20,17 @@ import org.nl.iot.core.driver.bo.SiteBO;
|
|||||||
import org.nl.iot.core.driver.entity.RValue;
|
import org.nl.iot.core.driver.entity.RValue;
|
||||||
import org.nl.iot.core.driver.entity.WResponse;
|
import org.nl.iot.core.driver.entity.WResponse;
|
||||||
import org.nl.iot.core.driver.entity.WValue;
|
import org.nl.iot.core.driver.entity.WValue;
|
||||||
import org.nl.iot.core.driver.enums.MetadataOperateTypeEnum;
|
import org.nl.iot.core.driver.protocol.plcs7.util.PlcS7Utils;
|
||||||
import org.nl.iot.core.driver.util.JavaToPlcValueConvertUtil;
|
import org.nl.iot.core.driver.util.JavaToPlcValueConvertUtil;
|
||||||
import org.nl.iot.core.driver.util.PlcValueConvertUtil;
|
import org.nl.iot.core.driver.util.PlcValueConvertUtil;
|
||||||
import org.nl.iot.core.driver.protocol.plcs7.util.PlcS7Utils;
|
|
||||||
import org.nl.iot.core.driver.service.DriverCustomService;
|
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.ArrayList;
|
||||||
import java.util.concurrent.*;
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@@ -37,18 +40,14 @@ import java.util.concurrent.*;
|
|||||||
@Slf4j
|
@Slf4j
|
||||||
@Service
|
@Service
|
||||||
@ProtocolDriver(ProtocolType.PLCS7)
|
@ProtocolDriver(ProtocolType.PLCS7)
|
||||||
public class PlcS7ProtocolDriverImpl implements DriverCustomService {
|
public class PlcS7ProtocolDriverImpl extends AbstractProtocolDriver<PlcConnection> {
|
||||||
|
|
||||||
/**
|
public PlcS7ProtocolDriverImpl(ConnectionProtocolMappingManager mappingManager) {
|
||||||
* Plc Connector Map
|
super(mappingManager);
|
||||||
* 仅供参考
|
}
|
||||||
*/
|
|
||||||
private Map<String, PlcConnection> connectMap;
|
|
||||||
|
|
||||||
@PostConstruct
|
|
||||||
@Override
|
@Override
|
||||||
public void initial() {
|
public void initial() {
|
||||||
connectMap = new ConcurrentHashMap<>(16);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -58,12 +57,21 @@ public class PlcS7ProtocolDriverImpl implements DriverCustomService {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void event(MetadataEventDTO metadataEvent) {
|
public void event(MetadataEventDTO metadataEvent) {
|
||||||
MetadataOperateTypeEnum operateType = metadataEvent.getOperateType();
|
// MetadataOperateTypeEnum operateType = metadataEvent.getOperateType();
|
||||||
log.info("Device metadata event: connectId: {}, operate: {}", metadataEvent.getConnectId(), operateType);
|
// log.info("Device metadata event: connectId: {}, operate: {}", metadataEvent.getConnectId(), operateType);
|
||||||
|
//
|
||||||
|
// // When the device is updated or deleted, remove the corresponding connection handle
|
||||||
|
// if (MetadataOperateTypeEnum.DELETE.equals(operateType) || MetadataOperateTypeEnum.UPDATE.equals(operateType)) {
|
||||||
|
// connectMap.remove(metadataEvent.getConnectId());
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
// When the device is updated or deleted, remove the corresponding connection handle
|
@Override
|
||||||
if (MetadataOperateTypeEnum.DELETE.equals(operateType) || MetadataOperateTypeEnum.UPDATE.equals(operateType)) {
|
protected void closeConnection(PlcConnection connection) {
|
||||||
connectMap.remove(metadataEvent.getConnectId());
|
try {
|
||||||
|
connection.close();
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.warn("关闭失败:{}", e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -145,7 +153,7 @@ public class PlcS7ProtocolDriverImpl implements DriverCustomService {
|
|||||||
String connectionUrl = PlcS7Utils.getS7ConnectionUrl(deviceBO);
|
String connectionUrl = PlcS7Utils.getS7ConnectionUrl(deviceBO);
|
||||||
log.info("创建S7连接,deviceId: {}, url: {}", deviceId, connectionUrl);
|
log.info("创建S7连接,deviceId: {}, url: {}", deviceId, connectionUrl);
|
||||||
connection = new DefaultPlcDriverManager().getConnection(connectionUrl);
|
connection = new DefaultPlcDriverManager().getConnection(connectionUrl);
|
||||||
connectMap.put(deviceId, connection);
|
addPlcS7Connection(deviceBO.getId(), connection);
|
||||||
}
|
}
|
||||||
return connection;
|
return connection;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
@@ -154,6 +162,12 @@ public class PlcS7ProtocolDriverImpl implements DriverCustomService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 业务中创建连接时,调用父类的addConnection方法
|
||||||
|
public void addPlcS7Connection(String connectionId, PlcConnection connection) {
|
||||||
|
// 传入协议编码(PLCS7)和连接ID、连接对象
|
||||||
|
addConnection(connectionId, ProtocolType.PLCS7.getMainCode(), connection);
|
||||||
|
}
|
||||||
|
|
||||||
public static PlcReadRequest.Builder doBuildReadRequest(PlcConnection s7Connection, List<SiteBO> points) {
|
public static PlcReadRequest.Builder doBuildReadRequest(PlcConnection s7Connection, List<SiteBO> points) {
|
||||||
try {
|
try {
|
||||||
PlcReadRequest.Builder readBuilder = s7Connection.readRequestBuilder();
|
PlcReadRequest.Builder readBuilder = s7Connection.readRequestBuilder();
|
||||||
|
|||||||
@@ -16,8 +16,10 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|||||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.nl.common.pojo.CommonResult;
|
import org.nl.common.pojo.CommonResult;
|
||||||
|
import org.nl.iot.core.driver.DriverConnectionManager;
|
||||||
import org.nl.iot.modular.iot.entity.IotConnect;
|
import org.nl.iot.modular.iot.entity.IotConnect;
|
||||||
import org.nl.iot.modular.iot.entity.IotConfig;
|
import org.nl.iot.modular.iot.entity.IotConfig;
|
||||||
import org.nl.iot.modular.iot.service.IotConfigService;
|
import org.nl.iot.modular.iot.service.IotConfigService;
|
||||||
@@ -43,6 +45,8 @@ public class IotConnectController {
|
|||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private IotConfigService iotConfigService;
|
private IotConfigService iotConfigService;
|
||||||
|
@Resource
|
||||||
|
private DriverConnectionManager connectionManager;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取连接列表
|
* 获取连接列表
|
||||||
@@ -92,6 +96,7 @@ public class IotConnectController {
|
|||||||
@PostMapping("/edit")
|
@PostMapping("/edit")
|
||||||
public CommonResult edit(@RequestBody IotConnect connect) {
|
public CommonResult edit(@RequestBody IotConnect connect) {
|
||||||
iotConnectService.updateById(connect);
|
iotConnectService.updateById(connect);
|
||||||
|
connectionManager.removeConnectionById(connect.getId().toString());
|
||||||
return CommonResult.ok();
|
return CommonResult.ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -110,7 +115,7 @@ public class IotConnectController {
|
|||||||
if (count > 0) {
|
if (count > 0) {
|
||||||
throw new CommonException("连接已被信号配置使用,无法删除");
|
throw new CommonException("连接已被信号配置使用,无法删除");
|
||||||
}
|
}
|
||||||
iotConnectService.removeById(connect.getId());
|
connectionManager.removeConnectionById(connect.getId().toString());
|
||||||
return CommonResult.ok();
|
return CommonResult.ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -128,6 +133,9 @@ public class IotConnectController {
|
|||||||
throw new CommonException("所选连接存在信号配置,无法删除");
|
throw new CommonException("所选连接存在信号配置,无法删除");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for (Integer id : ids) {
|
||||||
|
connectionManager.removeConnectionById(String.valueOf(id));
|
||||||
|
}
|
||||||
iotConnectService.removeBatchByIds(ids);
|
iotConnectService.removeBatchByIds(ids);
|
||||||
return CommonResult.ok();
|
return CommonResult.ok();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user