遍歷OPCUA節(jié)點
1.使用OPCUA,獲取PLC數(shù)據(jù)
問題:如果是結(jié)構(gòu)體,數(shù)組發(fā)現(xiàn)不能夠使用符號訪問,只能用數(shù)字訪問

為了解決這個問題,通過代碼獲取所有的節(jié)點數(shù)據(jù),然后構(gòu)建到map里面
簡介訪問數(shù)據(jù)

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 = "服務(wù)器";
public static void main(String[] args) {
String endpointUrl = "opc.tcp://192.168.10.10:4840"; // OPC UA服務(wù)器地址
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服務(wù)器: " + endpointUrl);
Map<String, NodeId> nodeMap = new LinkedHashMap<>();
browseAndPrint(client, Identifiers.RootFolder, "", nodeMap);
client.disconnect().get();
System.out.println("已斷開與服務(wù)器的連接");
} 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. 區(qū)分大小寫
boolean hasServer = StrUtil.contains(currentPath, "服務(wù)器");
nodeMap.put(currentPath, childId);
String nodeType = (nodeClass == NodeClass.Variable) ? "變量節(jié)點" : "對象節(jié)點";
System.out.println("映射: " + currentPath + " → " + childId + "(" + nodeType + ")");
// 如果是變量節(jié)點,輸出基礎(chǔ)類型和數(shù)據(jù)類型
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(" 基礎(chǔ)類型: " + currentPath + ", 數(shù)據(jù)類型: " + dataTypeName);
}
// 遞歸瀏覽子節(jié)點
browseAndPrint(client, childId, currentPath, nodeMap);
}
}
}

優(yōu)化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 = "服務(wù)器";
public static void main(String[] args) {
String endpointUrl = "opc.tcp://192.168.10.10:4840"; // OPC UA服務(wù)器地址
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服務(wù)器: " + endpointUrl);
Map<String, NodeId> nodeMap = new LinkedHashMap<>();
browseAndPrint(client, Identifiers.RootFolder, "", nodeMap);
client.disconnect().get();
System.out.println("已斷開與服務(wù)器的連接");
} 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. 區(qū)分大小寫
boolean hasServer = StrUtil.contains(currentPath, "服務(wù)器");
nodeMap.put(currentPath, childId);
String nodeType = (nodeClass == NodeClass.Variable) ? "變量節(jié)點" : "對象節(jié)點";
System.out.println("映射: " + currentPath + " → " + childId + "(" + nodeType + ")");
// 如果是變量節(jié)點,輸出基礎(chǔ)類型和數(shù)據(jù)類型
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(" 基礎(chǔ)類型: " + currentPath + ", 數(shù)據(jù)類型: " + dataTypeName);
}
// 遞歸瀏覽子節(jié)點
browseAndPrint(client, childId, currentPath, nodeMap);
}
}
}

浙公網(wǎng)安備 33010602011771號