|
@@ -1,67 +1,101 @@
|
|
|
package com.judong.chuanyiserver.util;
|
|
|
|
|
|
+import com.alibaba.fastjson.JSONObject;
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
import org.eclipse.milo.opcua.sdk.client.OpcUaClient;
|
|
|
+import org.eclipse.milo.opcua.sdk.client.api.config.OpcUaClientConfig;
|
|
|
import org.eclipse.milo.opcua.sdk.client.api.identity.AnonymousProvider;
|
|
|
import org.eclipse.milo.opcua.sdk.client.nodes.UaNode;
|
|
|
-import org.eclipse.milo.opcua.sdk.client.subscriptions.ManagedDataItem;
|
|
|
-import org.eclipse.milo.opcua.sdk.client.subscriptions.ManagedSubscription;
|
|
|
-import org.eclipse.milo.opcua.stack.core.AttributeId;
|
|
|
+import org.eclipse.milo.opcua.stack.client.DiscoveryClient;
|
|
|
import org.eclipse.milo.opcua.stack.core.Identifiers;
|
|
|
+import org.eclipse.milo.opcua.stack.core.UaException;
|
|
|
import org.eclipse.milo.opcua.stack.core.security.SecurityPolicy;
|
|
|
-import org.eclipse.milo.opcua.stack.core.types.builtin.*;
|
|
|
-import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UInteger;
|
|
|
-import org.eclipse.milo.opcua.stack.core.types.enumerated.MonitoringMode;
|
|
|
+import org.eclipse.milo.opcua.stack.core.types.builtin.LocalizedText;
|
|
|
+import org.eclipse.milo.opcua.stack.core.types.builtin.NodeId;
|
|
|
+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.structured.MonitoredItemCreateRequest;
|
|
|
-import org.eclipse.milo.opcua.stack.core.types.structured.MonitoringParameters;
|
|
|
-import org.eclipse.milo.opcua.stack.core.types.structured.ReadValueId;
|
|
|
-
|
|
|
+import org.eclipse.milo.opcua.stack.core.types.structured.EndpointDescription;
|
|
|
+import org.jinterop.dcom.common.JIException;
|
|
|
+import org.openscada.opc.lib.da.Server;
|
|
|
+import org.openscada.opc.lib.da.browser.Branch;
|
|
|
+import org.openscada.opc.lib.da.browser.TreeBrowser;
|
|
|
+import org.springframework.beans.factory.annotation.Autowired;
|
|
|
+import org.springframework.util.ObjectUtils;
|
|
|
+
|
|
|
+import java.net.UnknownHostException;
|
|
|
import java.nio.file.Files;
|
|
|
import java.nio.file.Path;
|
|
|
import java.nio.file.Paths;
|
|
|
import java.util.ArrayList;
|
|
|
+import java.util.Collection;
|
|
|
import java.util.List;
|
|
|
import java.util.Objects;
|
|
|
-import java.util.concurrent.CountDownLatch;
|
|
|
+import java.util.concurrent.CompletableFuture;
|
|
|
+import java.util.concurrent.ExecutionException;
|
|
|
+import java.util.function.Predicate;
|
|
|
|
|
|
+@Slf4j
|
|
|
public class OpcServerUaUtil {
|
|
|
+
|
|
|
+ private static final String certPath = "C:/Users/Administrator/Desktop/";
|
|
|
+ private static final String endpointUrl = "opc.tcp://192.168.0.252:49322";
|
|
|
+// private static final String endpointUrl = "opc.tcp://192.168.0.252:37800";
|
|
|
+
|
|
|
/**
|
|
|
* 创建OPC UA客户端
|
|
|
*
|
|
|
* @return
|
|
|
*/
|
|
|
- public OpcUaClient createClient() throws Exception {
|
|
|
- //opc ua服务端地址
|
|
|
- String endPointUrl = "opc.tcp://192.168.0.138:37800";
|
|
|
- Path securityTempDir = Paths.get(System.getProperty("java.io.tmpdir"), "security");
|
|
|
+ public static OpcUaClient createClient() throws Exception {
|
|
|
+ Path securityTempDir = Paths.get(certPath, "security");
|
|
|
+
|
|
|
Files.createDirectories(securityTempDir);
|
|
|
if (!Files.exists(securityTempDir)) {
|
|
|
- throw new Exception("unable to create security dir: " + securityTempDir);
|
|
|
+ log.info("无法创建安全目录: " + securityTempDir);
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ KeyStoreLoader keyStoreLoader = new KeyStoreLoader();
|
|
|
+ KeyStoreLoader loader = keyStoreLoader.load(securityTempDir);
|
|
|
+ // 搜索OPC节点
|
|
|
+ List<EndpointDescription> endpoints = null;
|
|
|
+ try {
|
|
|
+ endpoints = DiscoveryClient.getEndpoints(endpointUrl).get();
|
|
|
+ } catch (Throwable e) {
|
|
|
+ String discoveryUrl = endpointUrl;
|
|
|
+ if (!discoveryUrl.endsWith("/")) {
|
|
|
+ discoveryUrl += "/";
|
|
|
+ }
|
|
|
+ discoveryUrl += "discovery";
|
|
|
+ endpoints = DiscoveryClient.getEndpoints(discoveryUrl).get();
|
|
|
}
|
|
|
- return OpcUaClient.create(endPointUrl,
|
|
|
- endpoints ->
|
|
|
- endpoints.stream()
|
|
|
- .filter(e -> e.getSecurityPolicyUri().equals(SecurityPolicy.None.getUri()))
|
|
|
- .findFirst(),
|
|
|
- configBuilder ->
|
|
|
- configBuilder
|
|
|
- .setApplicationName(LocalizedText.english("eclipse milo opc-ua client"))
|
|
|
- .setApplicationUri("urn:eclipse:milo:examples:client")
|
|
|
- //访问方式(new AnonymousProvider()表示使用匿名方式访问,也可以通过new UsernameProvider(userName, password)方式访问。)
|
|
|
- .setIdentityProvider(new AnonymousProvider())
|
|
|
- .setRequestTimeout(UInteger.valueOf(5000))
|
|
|
- .build()
|
|
|
- );
|
|
|
+ EndpointDescription endpoint = endpoints.stream()
|
|
|
+ .filter(e -> e.getSecurityPolicyUri().equals(SecurityPolicy.None.getUri())).filter(endpointFilter())
|
|
|
+ .findFirst().orElseThrow(() -> new Exception("no desired endpoints returned"));
|
|
|
+ OpcUaClientConfig config = OpcUaClientConfig.builder()
|
|
|
+ .setApplicationName(LocalizedText.english("my"))
|
|
|
+ .setApplicationUri("urn:Jellyleo:UnifiedAutomation:UaExpert@Jellyleo")
|
|
|
+ .setCertificate(loader.getClientCertificate()).setKeyPair(loader.getClientKeyPair())
|
|
|
+ .setEndpoint(endpoint)
|
|
|
+// .setIdentityProvider(new UsernameProvider("jellyleo", "123456"))
|
|
|
+ .setIdentityProvider(new AnonymousProvider()) // 匿名验证
|
|
|
+ .setRequestTimeout(Unsigned.uint(5000)).build();
|
|
|
+
|
|
|
+ return OpcUaClient.create(config);
|
|
|
}
|
|
|
|
|
|
- /**
|
|
|
- * 遍历树形节点
|
|
|
- *
|
|
|
- * @param client OPC UA客户端
|
|
|
- * @param uaNode 节点
|
|
|
- * @throws Exception
|
|
|
- */
|
|
|
- private static void browseNode(OpcUaClient client, UaNode uaNode) throws Exception {
|
|
|
+ private static Predicate<EndpointDescription> endpointFilter() {
|
|
|
+ return e -> true;
|
|
|
+ }
|
|
|
+
|
|
|
+ public static CompletableFuture<OpcUaClient> getFuture() {
|
|
|
+ return new CompletableFuture<>();
|
|
|
+ }
|
|
|
+
|
|
|
+ public static List<JSONObject> generOpcUaTree(OpcUaClient client, UaNode uaNode) throws UaException, ExecutionException, InterruptedException {
|
|
|
+ if(Blank.isEmpty(client)){
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ List<JSONObject> jsonList = new ArrayList<>();
|
|
|
List<? extends UaNode> nodes;
|
|
|
if (uaNode == null) {
|
|
|
nodes = client.getAddressSpace().browseNodes(Identifiers.ObjectsFolder);
|
|
@@ -69,134 +103,49 @@ public class OpcServerUaUtil {
|
|
|
nodes = client.getAddressSpace().browseNodes(uaNode);
|
|
|
}
|
|
|
for (UaNode nd : nodes) {
|
|
|
+ if(Blank.isEmpty(nd)){
|
|
|
+ continue;
|
|
|
+ }
|
|
|
//排除系统行性节点,这些系统性节点名称一般都是以"_"开头
|
|
|
if (Objects.requireNonNull(nd.getBrowseName().getName()).contains("_")) {
|
|
|
- continue;
|
|
|
+// continue;
|
|
|
}
|
|
|
- System.out.println("Node= " + nd.getBrowseName().getName());
|
|
|
- browseNode(client, nd);
|
|
|
+ JSONObject jsonObject = new JSONObject();
|
|
|
+ jsonObject.put("label", nd.getBrowseName().getName());
|
|
|
+// jsonObject.put("value",client.readValue(0.0, TimestampsToReturn.Neither, nd.getNodeId()).get());
|
|
|
+ jsonObject.put("children", generOpcUaTree(client, nd));
|
|
|
+ jsonList.add(jsonObject);
|
|
|
}
|
|
|
+ return jsonList;
|
|
|
}
|
|
|
|
|
|
- /**
|
|
|
- * 读取节点数据
|
|
|
- *
|
|
|
- * @param client OPC UA客户端
|
|
|
- * @throws Exception
|
|
|
- */
|
|
|
- private static void readNode(OpcUaClient client) throws Exception {
|
|
|
- int namespaceIndex = 2;
|
|
|
- String identifier = "TD-01.SB-01.AG-01";
|
|
|
- //节点
|
|
|
- NodeId nodeId = new NodeId(namespaceIndex, identifier);
|
|
|
- //读取节点数据
|
|
|
- DataValue value = client.readValue(0.0, TimestampsToReturn.Neither, nodeId).get();
|
|
|
- //标识符
|
|
|
- identifier = String.valueOf(nodeId.getIdentifier());
|
|
|
- System.out.println(identifier + ": " + String.valueOf(value.getValue().getValue()));
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 写入节点数据
|
|
|
- *
|
|
|
- * @param client
|
|
|
- * @throws Exception
|
|
|
- */
|
|
|
- private static void writeNodeValue(OpcUaClient client) throws Exception {
|
|
|
- //节点
|
|
|
- NodeId nodeId = new NodeId(2, "TD-01.SB-01.AG-01");
|
|
|
- short i = 3;
|
|
|
- //创建数据对象,此处的数据对象一定要定义类型,不然会出现类型错误,导致无法写入
|
|
|
- DataValue nowValue = new DataValue(new Variant(i), null, null);
|
|
|
- //写入节点数据
|
|
|
- StatusCode statusCode = client.writeValue(nodeId, nowValue).join();
|
|
|
- System.out.println("结果:" + statusCode.isGood());
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 订阅(单个)
|
|
|
- *
|
|
|
- * @param client
|
|
|
- * @throws Exception
|
|
|
- */
|
|
|
- private static void subscribe(OpcUaClient client) throws Exception {
|
|
|
- //创建发布间隔1000ms的订阅对象
|
|
|
- client
|
|
|
- .getSubscriptionManager()
|
|
|
- .createSubscription(1000.0)
|
|
|
- .thenAccept(t -> {
|
|
|
- //节点
|
|
|
- NodeId nodeId = new NodeId(2, "TD-01.SB-01.AG-01");
|
|
|
- ReadValueId readValueId = new ReadValueId(nodeId, AttributeId.Value.uid(), null, null);
|
|
|
- //创建监控的参数
|
|
|
- MonitoringParameters parameters = new MonitoringParameters(UInteger.valueOf(1), 1000.0, null, UInteger.valueOf(10), true);
|
|
|
-// MonitoringParameters parameters = new MonitoringParameters(UInteger.valueOf(atomic.getAndIncrement()), 1000.0, null, UInteger.valueOf(10), true);
|
|
|
- //创建监控项请求
|
|
|
- //该请求最后用于创建订阅。
|
|
|
- MonitoredItemCreateRequest request = new MonitoredItemCreateRequest(readValueId, MonitoringMode.Reporting, parameters);
|
|
|
- List<MonitoredItemCreateRequest> requests = new ArrayList<>();
|
|
|
- requests.add(request);
|
|
|
- //创建监控项,并且注册变量值改变时候的回调函数。
|
|
|
- t.createMonitoredItems(
|
|
|
- TimestampsToReturn.Both,
|
|
|
- requests,
|
|
|
- (item, id) -> item.setValueConsumer((it, val) -> {
|
|
|
- System.out.println("nodeid :" + it.getReadValueId().getNodeId());
|
|
|
- System.out.println("value :" + val.getValue().getValue());
|
|
|
- })
|
|
|
- );
|
|
|
- }).get();
|
|
|
-
|
|
|
- //持续订阅
|
|
|
- Thread.sleep(Long.MAX_VALUE);
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 批量订阅
|
|
|
- *
|
|
|
- * @param client
|
|
|
- * @throws Exception
|
|
|
- */
|
|
|
- private static void managedSubscriptionEvent(OpcUaClient client) throws Exception {
|
|
|
- final CountDownLatch eventLatch = new CountDownLatch(1);
|
|
|
-
|
|
|
- //处理订阅业务
|
|
|
- handlerNode(client);
|
|
|
-
|
|
|
- //持续监听
|
|
|
- eventLatch.await();
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 处理订阅业务
|
|
|
- *
|
|
|
- * @param client OPC UA客户端
|
|
|
- */
|
|
|
- private static void handlerNode(OpcUaClient client) {
|
|
|
- try {
|
|
|
- //创建订阅
|
|
|
- ManagedSubscription subscription = ManagedSubscription.create(client);
|
|
|
-
|
|
|
- //你所需要订阅的key
|
|
|
- List<String> key = new ArrayList<>();
|
|
|
- key.add("TD-01.SB-01.AG-01");
|
|
|
- key.add("TD-01.SB-01.AG-02");
|
|
|
-
|
|
|
- List<NodeId> nodeIdList = new ArrayList<>();
|
|
|
- for (String s : key) {
|
|
|
- nodeIdList.add(new NodeId(2, s));
|
|
|
- }
|
|
|
-
|
|
|
- //监听
|
|
|
- List<ManagedDataItem> dataItemList = subscription.createDataItems(nodeIdList);
|
|
|
- for (ManagedDataItem managedDataItem : dataItemList) {
|
|
|
- managedDataItem.addDataValueListener((t) -> {
|
|
|
- System.out.println(managedDataItem.getNodeId().getIdentifier().toString() + ":" + t.getValue().getValue().toString());
|
|
|
- });
|
|
|
- }
|
|
|
- } catch (Exception e) {
|
|
|
- e.printStackTrace();
|
|
|
- }
|
|
|
- }
|
|
|
+// private void browseNode(OpcUaClient client, UaNode uaNode) throws Exception {
|
|
|
+// List<? extends UaNode> nodes;
|
|
|
+// if (uaNode == null) {
|
|
|
+// nodes = client.getAddressSpace().browseNodes(Identifiers.ObjectsFolder);//从根目录
|
|
|
+//// nodes = client.getAddressSpace().browseNodes(new NodeId(2,"my"));//指定目录
|
|
|
+// } else {
|
|
|
+// nodes = client.getAddressSpace().browseNodes(uaNode);
|
|
|
+// }
|
|
|
+// if (ObjectUtils.isEmpty(nodes)) {
|
|
|
+// return;
|
|
|
+// }
|
|
|
+// for (UaNode nd : nodes) {
|
|
|
+// if (nd.getBrowseName().getName().contains("test")) {
|
|
|
+// browseNode(client, nd);
|
|
|
+// }
|
|
|
+// if (nd.getBrowseName().getName().contains("name")) {
|
|
|
+// Object identifier = nd.getNodeId().getIdentifier();
|
|
|
+// String s = identifier.toString();
|
|
|
+//
|
|
|
+// nodeNames.add(s);
|
|
|
+// }
|
|
|
+//// //排除系统行性节点,这些系统性节点名称一般都是以"_"开头
|
|
|
+//// if (Objects.requireNonNull(nd.getBrowseName().getName()).contains("_")) {
|
|
|
+//// continue;
|
|
|
+//// }
|
|
|
+// }
|
|
|
+// System.err.println();
|
|
|
+// }
|
|
|
|
|
|
}
|