1.背景
前面我们搭建了一个本地的 PLC 仿真环境,并通过 KEPServerEX6 读取 PLC 上的数据,最后还使用 UAExpert 作为OPC客户端完成从 KEPServerEX6 这个OPC服务器的数据读取与订阅功能。在这篇文章中,我们将通过 SpringBoot 集成 Milo 库实现一个 OPC UA 客户端,包括连接、遍历节点、读取、写入、订阅与批量订阅等功能。
引入依赖
SpringBoot 后端项目中引入 Milo 库依赖(客户端 SDK )
org.eclipse.milo
sdk-client
0.6.3
org.eclipse.milo
sdk-server
0.6.3
org.bouncycastle
bcpkix-jdk15on
1.57
连接
public OpcUaClient opcUaClientConnect() throws Exception {
OpcUaClient opcUaClient = null;
//安全权限
Path securityTempDir = Paths.get(System.getProperty("java.io.tmpdir"), "security");
Files.createDirectories(securityTempDir);
if (!Files.exists(securityTempDir)) {
throw new Exception("unable to create security dir: " + securityTempDir);
}
opcUaClient = OpcUaClient.create(endPointUrl,
endpoints -> {
final Optional endpoint = endpoints
.stream()
.filter(e -> e.getSecurityPolicyUri().equals(SecurityPolicy.None.getUri()))
.findFirst();
EndpointDescription newEndpoint = new EndpointDescription(this.endPointUrl, endpoint.get().getServer(), endpoint.get().getServerCertificate(),
endpoint.get().getSecurityMode(), endpoint.get().getSecurityPolicyUri(), endpoint.get().getUserIdentityTokens(),
endpoint.get().getTransportProfileUri(), endpoint.get().getSecurityLevel());
return Optional.of(newEndpoint);
},
configBuilder ->
configBuilder
.setApplicationName(LocalizedText.english("eclipse milo opc-ua client"))
.setApplicationUri("urn:eclipse:milo:examples:client")
.setIdentityProvider(new AnonymousProvider())
.setRequestTimeout(UInteger.valueOf(500))
.build()
);
try {
CompletableFuture connect = opcUaClient.connect();
connect.get();
//Thread.sleep(2000);
} catch (ExecutionException e) {
logger.error("连接失败opc opcUaClientConnect方法");
//e.printStackTrace();
}
return opcUaClient;
}
获取节点值
//获取节点的数据信息
public DataValue getOpcUaNodeValue(OpcUaClient connectionFromPool, String machineName) {
NodeId nodeId = new NodeId(2, machineName);//"OPC_Test.设备 1.TAG1"
//读取节点数据
DataValue value = null;
try {
value = connectionFromPool.readValue(0.0, TimestampsToReturn.Neither, nodeId).get();
// 状态==false 连接上 true没有连接上
//System.out.println("Status: " + value.getStatusCode().isBad());
//标识符
// String id = String.valueOf(nodeId.getIdentifier());
// System.out.println(id + ": " + value.getValue().getValue());
} catch (Exception e) {
e.printStackTrace();
}
return value;
}
批量订阅指定节点
@Configuration
public class OpcUaConfig {
private Logger logger = LoggerFactory.getLogger(RedisTimer.class);
@Autowired
TableConsumeMapperService tableConsumeMapperService;
@Autowired
private DataNode dataNode;
@Bean
public DataNode transferService() {
return dataNode;
}
OpcUaMiloTemplate opcUaMiloTemplate = new OpcUaMiloTemplate();
OpcUaClient connectionFromPool = opcUaMiloTemplate.getConnectionFromPool();
@Bean
public void handlerMultipleNodeListen() throws Exception {
//final CountDownLatch eventLatch = new CountDownLatch(1);
List tableConsumeList = tableConsumeMapperService.getTableConsumeList();
List batchIdentifiers = new ArrayList();
//batchIdentifiers.add("OPC_Test.Q.TAG1");
for (TableConsume tableConsume : tableConsumeList) {
//batchIdentifiers.add(getConsumePosition);
batchIdentifiers.add(tableConsume.getConsumePosition());
}
try {
//OpcUaClient connectionFromPool = opcUaClientConnect();
//创建订阅
ManagedSubscription subscription = ManagedSubscription.create(connectionFromPool);
List nodeIdList = new ArrayList();
for (String id : batchIdentifiers) {
nodeIdList.add(new NodeId(2, id));
}
//监听
List dataItemList = subscription.createDataItems(nodeIdList);
for (ManagedDataItem managedDataItem : dataItemList) {
managedDataItem.addDataValueListener((t) -> {
//DataNode node = new DataNode();
//System.out.println(managedDataItem.getNodeId().getIdentifier().toString() + ":" + t.getValue().getValue().toString());
dataNode.setNodeAdress(managedDataItem.getNodeId().getIdentifier().toString());
dataNode.setDateValue(t.getValue().getValue().toString());
DataNode dataNode = transferService();
ToolUtils.nodeList.add(dataNode);
});
}
Thread.sleep(2000);//是指订阅的时间长度
//eventLatch.await();
logger.error("订阅获取的值::::" + ToolUtils.nodeList.toString());
} catch (Exception e) {
e.printStackTrace();
}
}
}