feat:opcda协议读写
This commit is contained in:
@@ -8,8 +8,11 @@ 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.bo.AttributeBO;
|
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.MetadataEventDTO;
|
||||||
|
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.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;
|
||||||
@@ -23,6 +26,7 @@ import org.nl.iot.modular.iot.entity.IotConnect;
|
|||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import java.net.UnknownHostException;
|
import java.net.UnknownHostException;
|
||||||
|
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.ConcurrentHashMap;
|
||||||
@@ -66,32 +70,37 @@ public class OpcDaProtocolDriverImpl implements DriverCustomService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public RValue read(IotConnect connect, IotConfig config) {
|
public RValue read(DeviceBO device, SiteBO point) {
|
||||||
return new RValue(config, connect, readValue(getConnector(connect), connect, config));
|
return new RValue(device, point, readValue(getConnector(device), device, point), null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Boolean write(IotConnect connect, IotConfig config, WValue wValue) {
|
public Boolean write(DeviceBO device, WValue wValue) {
|
||||||
Server server = getConnector(connect);
|
Server server = getConnector(device);
|
||||||
return writeValue(server, connect, config, wValue);
|
return writeValue(server, device, wValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<RValue> batchRead(DeviceBO device, List<SiteBO> point) {
|
||||||
|
// todo
|
||||||
|
return List.of();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<WResponse> batchWrite(DeviceBO device, List<WValue> wValue) {
|
||||||
|
// todo
|
||||||
|
return List.of();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取 OPC DA 服务器连接
|
* 获取 OPC DA 服务器连接
|
||||||
* <p>
|
|
||||||
* 根据设备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) {
|
private Server getConnector(DeviceBO deviceBO) {
|
||||||
log.debug("Opc Da Server Connection Info {}", connect);
|
log.debug("Opc Da Server Connection Info {}", deviceBO);
|
||||||
JSONObject config = JSONObject.parseObject(connect.getProtocol());
|
JSONObject config = JSONObject.parseObject(deviceBO.getProperties());
|
||||||
Server server = connectMap.get(connect.getId().toString());
|
Server server = connectMap.get(deviceBO.getId());
|
||||||
if (Objects.isNull(server)) {
|
if (Objects.isNull(server)) {
|
||||||
String host = connect.getHost();
|
String host = deviceBO.getHost();
|
||||||
String clsId = config.getString("clsId");
|
String clsId = config.getString("clsId");
|
||||||
String user = config.getString("username");
|
String user = config.getString("username");
|
||||||
String password = ObjectUtil.isEmpty(config.get("password")) ? "" : config.getString("password");
|
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());
|
server = new Server(connectionInformation, Executors.newSingleThreadScheduledExecutor());
|
||||||
try {
|
try {
|
||||||
server.connect();
|
server.connect();
|
||||||
connectMap.put(connect.getId().toString(), server);
|
connectMap.put(deviceBO.getId(), server);
|
||||||
} catch (AlreadyConnectedException | UnknownHostException | JIException e) {
|
} 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);
|
log.error("Connect opc da server error: {}", e.getMessage(), e);
|
||||||
throw new CommonException(e.getMessage());
|
throw new CommonException(e.getMessage());
|
||||||
}
|
}
|
||||||
@@ -114,15 +123,10 @@ public class OpcDaProtocolDriverImpl implements DriverCustomService {
|
|||||||
* <p>
|
* <p>
|
||||||
* 该方法通过给定的 OPC DA 服务器和位号配置, 获取对应的 Item 对象, 并读取其值。
|
* 该方法通过给定的 OPC DA 服务器和位号配置, 获取对应的 Item 对象, 并读取其值。
|
||||||
* 如果在读取过程中发生异常, 将断开服务器连接并抛出 {@link ReadPointException}。
|
* 如果在读取过程中发生异常, 将断开服务器连接并抛出 {@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 {
|
try {
|
||||||
Item item = getItem(server, connect, config);
|
Item item = getItem(server, deviceBO, siteBO);
|
||||||
return readItem(item);
|
return readItem(item);
|
||||||
} catch (NotConnectedException | JIException | AddFailedException | DuplicateGroupException |
|
} catch (NotConnectedException | JIException | AddFailedException | DuplicateGroupException |
|
||||||
UnknownHostException e) {
|
UnknownHostException e) {
|
||||||
@@ -138,24 +142,16 @@ public class OpcDaProtocolDriverImpl implements DriverCustomService {
|
|||||||
* 根据位号配置中的组名和标签名, 从指定的 OPC DA 服务器中获取对应的 Item 对象。
|
* 根据位号配置中的组名和标签名, 从指定的 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;
|
Group group;
|
||||||
String groupName = connect.getCode();
|
String groupName = deviceBO.getCode();
|
||||||
try {
|
try {
|
||||||
group = server.findGroup(groupName);
|
group = server.findGroup(groupName);
|
||||||
} catch (UnknownGroupException e) {
|
} catch (UnknownGroupException e) {
|
||||||
group = server.addGroup(groupName);
|
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 返回写入操作是否成功
|
* @return boolean 返回写入操作是否成功
|
||||||
* @throws WritePointException 如果写入位号值时发生异常, 则抛出此异常
|
* @throws WritePointException 如果写入位号值时发生异常, 则抛出此异常
|
||||||
*/
|
*/
|
||||||
private boolean writeValue(Server server, IotConnect connect, IotConfig config, WValue wValue) {
|
private boolean writeValue(Server server, DeviceBO deviceBO, WValue wValue) {
|
||||||
try {
|
try {
|
||||||
Item item = getItem(server, connect, config);
|
Item item = getItem(server, deviceBO, wValue.getPoint());
|
||||||
return writeItem(item, wValue);
|
return writeItem(item, wValue);
|
||||||
} catch (NotConnectedException | AddFailedException | DuplicateGroupException | UnknownHostException |
|
} catch (NotConnectedException | AddFailedException | DuplicateGroupException | UnknownHostException |
|
||||||
JIException e) {
|
JIException e) {
|
||||||
|
|||||||
@@ -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.WResponse;
|
||||||
import org.nl.iot.core.driver.entity.WValue;
|
import org.nl.iot.core.driver.entity.WValue;
|
||||||
import org.nl.iot.core.driver.protocol.modbustcp.ModBusProtocolDriverImpl;
|
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.opcua.OpcUaProtocolDriverImpl;
|
||||||
import org.nl.iot.core.driver.protocol.plcs7.PlcS7ProtocolDriverImpl;
|
import org.nl.iot.core.driver.protocol.plcs7.PlcS7ProtocolDriverImpl;
|
||||||
import org.nl.iot.modular.iot.entity.IotConfig;
|
import org.nl.iot.modular.iot.entity.IotConfig;
|
||||||
@@ -38,6 +39,9 @@ public class ApiTest {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private OpcUaProtocolDriverImpl opcUaProtocolDriver;
|
private OpcUaProtocolDriverImpl opcUaProtocolDriver;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private OpcDaProtocolDriverImpl opcDaProtocolDriver;
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void modbusTest() {
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user