From c4918ff60d63486f3405d881da35f1092175650c Mon Sep 17 00:00:00 2001 From: liyongde <1419499670@qq.com> Date: Mon, 16 Mar 2026 20:17:16 +0800 Subject: [PATCH] =?UTF-8?q?feat=EF=BC=9Aopcda=E5=8D=8F=E8=AE=AE=E8=AF=BB?= =?UTF-8?q?=E5=86=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../opcda/OpcDaProtocolDriverImpl.java | 74 ++++---- nl-web-app/src/test/java/org/nl/ApiTest.java | 162 ++++++++++++++++++ 2 files changed, 197 insertions(+), 39 deletions(-) diff --git a/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/opcda/OpcDaProtocolDriverImpl.java b/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/opcda/OpcDaProtocolDriverImpl.java index ddc89e3..944f2bc 100644 --- a/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/opcda/OpcDaProtocolDriverImpl.java +++ b/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/opcda/OpcDaProtocolDriverImpl.java @@ -8,8 +8,11 @@ import org.jinterop.dcom.common.JIException; import org.jinterop.dcom.core.JIVariant; import org.nl.common.exception.CommonException; import org.nl.iot.core.driver.bo.AttributeBO; +import org.nl.iot.core.driver.bo.DeviceBO; import org.nl.iot.core.driver.bo.MetadataEventDTO; +import org.nl.iot.core.driver.bo.SiteBO; import org.nl.iot.core.driver.entity.RValue; +import org.nl.iot.core.driver.entity.WResponse; import org.nl.iot.core.driver.entity.WValue; import org.nl.iot.core.driver.enums.MetadataOperateTypeEnum; import org.nl.iot.core.driver.enums.PointTypeFlagEnum; @@ -23,6 +26,7 @@ import org.nl.iot.modular.iot.entity.IotConnect; import org.springframework.stereotype.Service; import java.net.UnknownHostException; +import java.util.List; import java.util.Map; import java.util.Objects; import java.util.concurrent.ConcurrentHashMap; @@ -66,32 +70,37 @@ public class OpcDaProtocolDriverImpl implements DriverCustomService { } @Override - public RValue read(IotConnect connect, IotConfig config) { - return new RValue(config, connect, readValue(getConnector(connect), connect, config)); + public RValue read(DeviceBO device, SiteBO point) { + return new RValue(device, point, readValue(getConnector(device), device, point), null); } @Override - public Boolean write(IotConnect connect, IotConfig config, WValue wValue) { - Server server = getConnector(connect); - return writeValue(server, connect, config, wValue); + public Boolean write(DeviceBO device, WValue wValue) { + Server server = getConnector(device); + return writeValue(server, device, wValue); + } + + @Override + public List batchRead(DeviceBO device, List point) { + // todo + return List.of(); + } + + @Override + public List batchWrite(DeviceBO device, List wValue) { + // todo + return List.of(); } /** * 获取 OPC DA 服务器连接 - *

- * 根据设备ID和驱动配置获取对应的 OPC DA 服务器连接。如果连接不存在, 则创建新的连接并缓存。 - * - * @param deviceId 设备ID, 用于标识设备对应的 OPC DA 服务器连接 - * @param driverConfig 驱动配置, 包含 OPC DA 服务器的连接信息(如主机地址, CLSID, 用户名, 密码等) - * @return Server 返回与设备ID对应的 OPC DA 服务器连接 - * @throws ConnectorException 如果连接 OPC DA 服务器时发生异常, 则抛出此异常 */ - private Server getConnector(IotConnect connect) { - log.debug("Opc Da Server Connection Info {}", connect); - JSONObject config = JSONObject.parseObject(connect.getProtocol()); - Server server = connectMap.get(connect.getId().toString()); + private Server getConnector(DeviceBO deviceBO) { + log.debug("Opc Da Server Connection Info {}", deviceBO); + JSONObject config = JSONObject.parseObject(deviceBO.getProperties()); + Server server = connectMap.get(deviceBO.getId()); if (Objects.isNull(server)) { - String host = connect.getHost(); + String host = deviceBO.getHost(); String clsId = config.getString("clsId"); String user = config.getString("username"); String password = ObjectUtil.isEmpty(config.get("password")) ? "" : config.getString("password"); @@ -99,9 +108,9 @@ public class OpcDaProtocolDriverImpl implements DriverCustomService { server = new Server(connectionInformation, Executors.newSingleThreadScheduledExecutor()); try { server.connect(); - connectMap.put(connect.getId().toString(), server); + connectMap.put(deviceBO.getId(), server); } catch (AlreadyConnectedException | UnknownHostException | JIException e) { - connectMap.entrySet().removeIf(next -> next.getKey().equals(connect.getId().toString())); + connectMap.entrySet().removeIf(next -> next.getKey().equals(deviceBO.getId())); log.error("Connect opc da server error: {}", e.getMessage(), e); throw new CommonException(e.getMessage()); } @@ -114,15 +123,10 @@ public class OpcDaProtocolDriverImpl implements DriverCustomService { *

* 该方法通过给定的 OPC DA 服务器和位号配置, 获取对应的 Item 对象, 并读取其值。 * 如果在读取过程中发生异常, 将断开服务器连接并抛出 {@link ReadPointException}。 - * - * @param server 已连接的 OPC DA 服务器实例 - * @param pointConfig 位号配置, 包含组名和标签名等信息 - * @return String 返回读取到的位号值 - * @throws ReadPointException 如果读取位号值时发生异常, 则抛出此异常 */ - private String readValue(Server server, IotConnect connect, IotConfig config) { + private String readValue(Server server, DeviceBO deviceBO, SiteBO siteBO) { try { - Item item = getItem(server, connect, config); + Item item = getItem(server, deviceBO, siteBO); return readItem(item); } catch (NotConnectedException | JIException | AddFailedException | DuplicateGroupException | UnknownHostException e) { @@ -138,24 +142,16 @@ public class OpcDaProtocolDriverImpl implements DriverCustomService { * 根据位号配置中的组名和标签名, 从指定的 OPC DA 服务器中获取对应的 Item 对象。 * 如果组不存在, 则创建新的组;如果组已存在, 则直接使用该组。 * - * @param server 已连接的 OPC DA 服务器实例 - * @param pointConfig 位号配置, 包含组名和标签名等信息 - * @return Item 返回与位号配置对应的 Item 对象 - * @throws NotConnectedException 如果 OPC DA 服务器未连接, 则抛出此异常 - * @throws JIException 如果与 OPC DA 服务器通信时发生错误, 则抛出此异常 - * @throws UnknownHostException 如果无法解析 OPC DA 服务器的主机地址, 则抛出此异常 - * @throws DuplicateGroupException 如果尝试添加已存在的组, 则抛出此异常 - * @throws AddFailedException 如果添加组或 Item 失败, 则抛出此异常 */ - public Item getItem(Server server, IotConnect connect, IotConfig config) throws NotConnectedException, JIException, UnknownHostException, DuplicateGroupException, AddFailedException { + public Item getItem(Server server, DeviceBO deviceBO, SiteBO siteBO) throws NotConnectedException, JIException, UnknownHostException, DuplicateGroupException, AddFailedException { Group group; - String groupName = connect.getCode(); + String groupName = deviceBO.getCode(); try { group = server.findGroup(groupName); } catch (UnknownGroupException e) { group = server.addGroup(groupName); } - return group.addItem(groupName + "." + config.getDeviceCode() + "." + config.getAlias()); + return group.addItem(groupName + "." + siteBO.getDeviceCode() + "." + siteBO.getAlias()); } /** @@ -209,9 +205,9 @@ public class OpcDaProtocolDriverImpl implements DriverCustomService { * @return boolean 返回写入操作是否成功 * @throws WritePointException 如果写入位号值时发生异常, 则抛出此异常 */ - private boolean writeValue(Server server, IotConnect connect, IotConfig config, WValue wValue) { + private boolean writeValue(Server server, DeviceBO deviceBO, WValue wValue) { try { - Item item = getItem(server, connect, config); + Item item = getItem(server, deviceBO, wValue.getPoint()); return writeItem(item, wValue); } catch (NotConnectedException | AddFailedException | DuplicateGroupException | UnknownHostException | JIException e) { diff --git a/nl-web-app/src/test/java/org/nl/ApiTest.java b/nl-web-app/src/test/java/org/nl/ApiTest.java index 9981391..eeb1799 100644 --- a/nl-web-app/src/test/java/org/nl/ApiTest.java +++ b/nl-web-app/src/test/java/org/nl/ApiTest.java @@ -9,6 +9,7 @@ import org.nl.iot.core.driver.entity.RValue; import org.nl.iot.core.driver.entity.WResponse; import org.nl.iot.core.driver.entity.WValue; import org.nl.iot.core.driver.protocol.modbustcp.ModBusProtocolDriverImpl; +import org.nl.iot.core.driver.protocol.opcda.OpcDaProtocolDriverImpl; import org.nl.iot.core.driver.protocol.opcua.OpcUaProtocolDriverImpl; import org.nl.iot.core.driver.protocol.plcs7.PlcS7ProtocolDriverImpl; import org.nl.iot.modular.iot.entity.IotConfig; @@ -38,6 +39,9 @@ public class ApiTest { @Autowired private OpcUaProtocolDriverImpl opcUaProtocolDriver; + @Autowired + private OpcDaProtocolDriverImpl opcDaProtocolDriver; + @Test public void modbusTest() { // 构建连接对象 @@ -1473,5 +1477,163 @@ public class ApiTest { } } + @Test + public void opcDaReadTest() { + // 构建OPC DA连接对象 + JSONObject properties = new JSONObject(); + properties.put("clsId", "{F8582CF2-88FB-11D0-B850-00C0F0104305}"); // 示例CLSID,需要根据实际OPC服务器修改 + properties.put("username", "administrator"); + properties.put("password", "P@ssw0rd."); + IotConnect connect = IotConnect.builder() + .id(3) + .code("B_CBJ01") + .host("192.168.81.251") + .port(0) // OPC DA不使用端口 + .properties(JSONObject.toJSONString(properties)) + .protocol("opc-da") + .enabled(true) + .description("测试OPC DA连接") + .build(); + + // 构建配置对象 - 写入操作,设置为可写 + IotConfig config = IotConfig.builder() + .id(2) + .connectId(3) + .alias("action1") + .aliasName("标签2") + .registerAddress("ns=4;s=|var|HCFA-PLC.Application.B_CBJ01.action1") // OPC DA标签地址 + .dataType("WORD") + .readonly(false) // 设置为可写 + .enabled(true) + .description("测试OPC DA写入") + .build(); + + // 执行读取操作 + try { + System.out.println("========== 开始测试OPC DA读取 =========="); + System.out.println("连接信息: " + connect.getHost()); + System.out.println("CLSID: " + properties.getString("clsId")); + System.out.println("标签地址: " + config.getRegisterAddress()); + System.out.println("数据类型: " + config.getDataType()); + + // 转换为DeviceBO + DeviceBO deviceBO = DeviceBO.builder() + .id(String.valueOf(connect.getId())) + .code(connect.getCode()) + .properties(connect.getProperties()) + .host(connect.getHost()) + .port(connect.getPort()) + .protocol(connect.getProtocol()) + .build(); + + // 转换为SiteBO + SiteBO siteBO = SiteBO.builder() + .deviceCode("B_CBJ01") + .alias(config.getAlias()) + .aliasName(config.getAliasName()) + .registerAddress(config.getRegisterAddress()) + .dataType(config.getDataType()) + .readonly(config.getReadonly()) + .build(); + + // 调用驱动读取数据 + RValue result = opcDaProtocolDriver.read(deviceBO, siteBO); + + System.out.println("读取成功!"); + System.out.println("读取结果: " + result.getValue()); + System.out.println("========== OPC DA读取测试完成 =========="); + + } catch (Exception e) { + System.err.println("OPC DA读取测试失败: " + e.getMessage()); + e.printStackTrace(); + } + } + + @Test + public void opcDaWriteTest() { + // 构建OPC DA连接对象 + JSONObject properties = new JSONObject(); + properties.put("clsId", "{F8582CF2-88FB-11D0-B850-00C0F0104305}"); // 示例CLSID,需要根据实际OPC服务器修改 + properties.put("username", "administrator"); + properties.put("password", "P@ssw0rd."); + + IotConnect connect = IotConnect.builder() + .id(3) + .code("OPC_DA_001") + .host("192.168.81.251") + .port(0) // OPC DA不使用端口 + .properties(JSONObject.toJSONString(properties)) + .protocol("opc-da") + .enabled(true) + .description("测试OPC DA连接") + .build(); + + // 构建配置对象 - 写入操作,设置为可写 + IotConfig config = IotConfig.builder() + .id(2) + .connectId(3) + .alias("tag2") + .aliasName("标签2") + .registerAddress("B_CBJ01.B_CBJ01") // OPC DA标签地址 + .dataType("INT") + .readonly(false) // 设置为可写 + .enabled(true) + .description("测试OPC DA写入") + .build(); + + // 执行写入操作 + try { + System.out.println("========== 开始测试OPC DA写入 =========="); + System.out.println("连接信息: " + connect.getHost()); + System.out.println("CLSID: " + properties.getString("clsId")); + System.out.println("标签地址: " + config.getRegisterAddress()); + System.out.println("数据类型: " + config.getDataType()); + + // 转换为DeviceBO + DeviceBO deviceBO = DeviceBO.builder() + .id(String.valueOf(connect.getId())) + .code(connect.getCode()) + .properties(connect.getProperties()) + .host(connect.getHost()) + .port(connect.getPort()) + .protocol(connect.getProtocol()) + .build(); + + // 转换为SiteBO + SiteBO siteBO = SiteBO.builder() + .deviceCode(connect.getCode()) + .alias(config.getAlias()) + .aliasName(config.getAliasName()) + .registerAddress(config.getRegisterAddress()) + .dataType(config.getDataType()) + .readonly(config.getReadonly()) + .build(); + + // 构建写入值对象 + String writeValue = "100"; // 要写入的值 + WValue wValue = WValue.builder() + .point(siteBO) + .value(writeValue) + .type(config.getDataType()) + .build(); + + System.out.println("写入值: " + writeValue); + + // 调用驱动写入数据 + Boolean result = opcDaProtocolDriver.write(deviceBO, wValue); + + if (result != null && result) { + System.out.println("写入成功!"); + System.out.println("写入结果: " + result); + } else { + System.out.println("写入失败!"); + } + System.out.println("========== OPC DA写入测试完成 =========="); + + } catch (Exception e) { + System.err.println("OPC DA写入测试失败: " + e.getMessage()); + e.printStackTrace(); + } + } }