遍历OPCUA节点

1.使用OPCUA,获取PLC数据
问题:如果是结构体,数组发现不能够使用符号访问,只能用数字访问
image

为了解决这个问题,通过代码获取所有的节点数据,然后构建到map里面
简介访问数据
image

package plc.gy;

import cn.hutool.core.util.StrUtil;
import org.eclipse.milo.opcua.sdk.client.OpcUaClient;
import org.eclipse.milo.opcua.sdk.client.nodes.UaVariableNode;
import org.eclipse.milo.opcua.stack.core.Identifiers;
import org.eclipse.milo.opcua.stack.core.UaException;
import org.eclipse.milo.opcua.stack.core.types.builtin.*;
import org.eclipse.milo.opcua.stack.core.types.enumerated.BrowseDirection;
import org.eclipse.milo.opcua.stack.core.types.enumerated.NodeClass;
import org.eclipse.milo.opcua.stack.core.types.structured.BrowseDescription;
import org.eclipse.milo.opcua.stack.core.types.structured.BrowseResult;
import org.eclipse.milo.opcua.stack.core.types.structured.ReferenceDescription;

import java.util.*;
import java.util.concurrent.ExecutionException;

import static org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.Unsigned.uint;

public class OpcUaNodeMapper {
    private static final String REQUIRED_KEYWORD = "服务器";


    public static void main(String[] args) {
        String endpointUrl = "opc.tcp://192.168.10.10:4840"; // OPC UA服务器地址

        try {
            OpcUaClient client = OpcUaClient.create(
                    endpointUrl,
                    endpoints -> endpoints.stream()
                            .filter(e -> e.getSecurityPolicyUri().equals("http://opcfoundation.org/UA/SecurityPolicy#None"))
                            .findFirst(),
                    configBuilder -> configBuilder
                            .setApplicationName(LocalizedText.english("OPC UA Mapper"))
                            .setApplicationUri("urn:eclipse:milo:examples:client")
                            .setRequestTimeout(uint(5000))
                            .build()
            );

            client.connect().get();
            System.out.println("已连接到OPC UA服务器: " + endpointUrl);

            Map<String, NodeId> nodeMap = new LinkedHashMap<>();
            browseAndPrint(client, Identifiers.RootFolder, "", nodeMap);

            client.disconnect().get();
            System.out.println("已断开与服务器的连接");

        } catch (Exception e) {
            System.err.println("通信失败: " + e.getMessage());
            e.printStackTrace();
        }
    }

    private static void browseAndPrint(OpcUaClient client, NodeId nodeId, String path, Map<String, NodeId> nodeMap)
            throws ExecutionException, InterruptedException, UaException {

        BrowseDescription browse = new BrowseDescription(
                nodeId,
                BrowseDirection.Forward,
                Identifiers.References,
                true,
                uint(NodeClass.Object.getValue() | NodeClass.Variable.getValue()),
                uint(0x3f)
        );

        BrowseResult result = client.browse(browse).get();
        ReferenceDescription[] refs = result.getReferences();

        if (refs == null) return;

        for (ReferenceDescription ref : refs) {
            NodeId childId = ref.getNodeId().toNodeId(client.getNamespaceTable()).orElse(null);
            if (childId == null) continue;

            String browseName = ref.getBrowseName().getName();
            String currentPath = path.isEmpty() ? browseName : path + "." + browseName;
            NodeClass nodeClass = ref.getNodeClass();

            // 1. 区分大小写
            boolean hasServer = StrUtil.contains(currentPath, "服务器");

            nodeMap.put(currentPath, childId);

            String nodeType = (nodeClass == NodeClass.Variable) ? "变量节点" : "对象节点";
            System.out.println("映射: " + currentPath + " → " + childId + "(" + nodeType + ")");

            // 如果是变量节点,输出基础类型和数据类型
            if (nodeClass == NodeClass.Variable) {
                UaVariableNode varNode = client.getAddressSpace().getVariableNode(childId);
                NodeId dataTypeId = varNode.getDataType();
                String dataTypeStr = dataTypeId != null ? dataTypeId.toParseableString() : "未知";

                String dataTypeName = client.getAddressSpace()
                        .getNode(dataTypeId)
                        .getBrowseName()
                        .getName();

                System.out.println("  基础类型: " + currentPath + ", 数据类型: " + dataTypeName);
            }

            // 递归浏览子节点
            browseAndPrint(client, childId, currentPath, nodeMap);
        }
    }
}

image

优化1

package plc.gy;

import cn.hutool.core.util.StrUtil;
import org.eclipse.milo.opcua.sdk.client.OpcUaClient;
import org.eclipse.milo.opcua.sdk.client.nodes.UaVariableNode;
import org.eclipse.milo.opcua.stack.core.Identifiers;
import org.eclipse.milo.opcua.stack.core.UaException;
import org.eclipse.milo.opcua.stack.core.types.builtin.*;
import org.eclipse.milo.opcua.stack.core.types.enumerated.BrowseDirection;
import org.eclipse.milo.opcua.stack.core.types.enumerated.NodeClass;
import org.eclipse.milo.opcua.stack.core.types.structured.BrowseDescription;
import org.eclipse.milo.opcua.stack.core.types.structured.BrowseResult;
import org.eclipse.milo.opcua.stack.core.types.structured.ReferenceDescription;

import java.util.*;
import java.util.concurrent.ExecutionException;

import static org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.Unsigned.uint;

public class OpcUaNodeMapper {
    private static final String REQUIRED_KEYWORD = "服务器";


    public static void main(String[] args) {
        String endpointUrl = "opc.tcp://192.168.10.10:4840"; // OPC UA服务器地址

        try {
            OpcUaClient client = OpcUaClient.create(
                    endpointUrl,
                    endpoints -> endpoints.stream()
                            .filter(e -> e.getSecurityPolicyUri().equals("http://opcfoundation.org/UA/SecurityPolicy#None"))
                            .findFirst(),
                    configBuilder -> configBuilder
                            .setApplicationName(LocalizedText.english("OPC UA Mapper"))
                            .setApplicationUri("urn:eclipse:milo:examples:client")
                            .setRequestTimeout(uint(5000))
                            .build()
            );

            client.connect().get();
            System.out.println("已连接到OPC UA服务器: " + endpointUrl);

            Map<String, NodeId> nodeMap = new LinkedHashMap<>();
            browseAndPrint(client, Identifiers.RootFolder, "", nodeMap);

            client.disconnect().get();
            System.out.println("已断开与服务器的连接");

        } catch (Exception e) {
            System.err.println("通信失败: " + e.getMessage());
            e.printStackTrace();
        }
    }

    private static void browseAndPrint(OpcUaClient client, NodeId nodeId, String path, Map<String, NodeId> nodeMap)
            throws ExecutionException, InterruptedException, UaException {

        BrowseDescription browse = new BrowseDescription(
                nodeId,
                BrowseDirection.Forward,
                Identifiers.References,
                true,
                uint(NodeClass.Object.getValue() | NodeClass.Variable.getValue()),
                uint(0x3f)
        );

        BrowseResult result = client.browse(browse).get();
        ReferenceDescription[] refs = result.getReferences();

        if (refs == null) return;

        for (ReferenceDescription ref : refs) {
            NodeId childId = ref.getNodeId().toNodeId(client.getNamespaceTable()).orElse(null);
            if (childId == null) continue;

            String browseName = ref.getBrowseName().getName();
            String currentPath = path.isEmpty() ? browseName : path + "." + browseName;
            NodeClass nodeClass = ref.getNodeClass();

            // 1. 区分大小写
            boolean hasServer = StrUtil.contains(currentPath, "服务器");

            nodeMap.put(currentPath, childId);

            String nodeType = (nodeClass == NodeClass.Variable) ? "变量节点" : "对象节点";
            System.out.println("映射: " + currentPath + " → " + childId + "(" + nodeType + ")");

            // 如果是变量节点,输出基础类型和数据类型
            if (nodeClass == NodeClass.Variable) {
                UaVariableNode varNode = client.getAddressSpace().getVariableNode(childId);
                NodeId dataTypeId = varNode.getDataType();
                String dataTypeStr = dataTypeId != null ? dataTypeId.toParseableString() : "未知";

                String dataTypeName = client.getAddressSpace()
                        .getNode(dataTypeId)
                        .getBrowseName()
                        .getName();

                System.out.println("  基础类型: " + currentPath + ", 数据类型: " + dataTypeName);
            }

            // 递归浏览子节点
            browseAndPrint(client, childId, currentPath, nodeMap);
        }
    }
}

posted @ 2025-07-15 16:44  拿受用  阅读(153)  评论(0)    收藏  举报