OPC UA学习心得 — 2 标准节点类

标准的节点类

  1. 节点类用于定义OPC UA地址空间中的节点
  2. 地址空间中模型的元素被称为节点,为节点分配节点类来代表对象模型的元素。
  3. 节点类源于通用的基本节点类。
  4. 首先定义节本节点类,然后定义用于组织地址空间的节点类,之后再定义用于代表对象的节点类。
  5. 代表对象的节点类分为三种:用于定义实例,定义实例的类型,以及定义数据类型。

标准的节点类有如下几种:

  • 基本节点类:能够派生所有其他节点类。
  • 对象节点类
  • 对象类型节点类
  • 变量节点类:定义数据变量
  • 变量类型节点类:定义特性
  • 方法节点类:定义方法,方法没有类型定义,可以绑定到对象上。
  • 引用类型节点类:定义引用。
  • 视图节点类:定义地址空间中节点子集。

1. 基本节点类

基本节点类的属性:

名称使用数据类型
NodeIdMNodeId
NodeClassMNodeClass
BrowseNameMQualifiedName
DisplayNameMLocalizedText
DescriptionOLocalizedText
WriteMaskOUInt32
UserWriteMaskOUInt32

注:M代表必备项,O代表可选项

  • NodeId:节点ID,在服务器中唯一标识一个节点。是定位和在服务器间交换信息的最重要概念。浏览地址空间时,服务器返回NodeId,客户端在服务调用时使用NodeId来定位节点。
  • BrowseName:浏览名称,仅用于浏览目的,不宜用来显示节点的名称,用作浏览地址空间浏览路径的一个非本地化人员可读的名称。
  • DisplayName:显示名称,包含了节点的本地化名称。如果客户端响应显示节点名称给用户,宜使用该属性。
  • Description:描述,本地化的文本中解释节点的含义。
  • WriteMask:写入掩码,公开了客户端写入节点属性的可能性。该属性不考虑任何用户访问权。
  • UserWriteMask:考虑用户访问权时,公开的客户端写入节点属性的可能性。指定哪个节点属性可被当前连接到服务器上的用户修改。

2. 对象节点类

对象节点类用于定义对象。而对象被用于代表系统、系统组件、现实世界的对象和软件对象。对象节点类继承了基本节点类的基本属性

对象节点类
注:0…* 表示没有限制,不使用或者可以无限次用;0…1 表示最多用一次;1 表示必须提供一次

  • 必备的EventNotifier属性表示对象是否可以被用于订阅事件或者读和写事件的历史。
  • HasTypeDefinition引用指向被用作对象的类型定义的对象类型。
  • 使用HasComponent引用来定义数据变量、对象和对象的方法。
  • 使用HasProperty引用来定义对象的特性。
  • HasModellingRule规定了建模规则,对象最多只能指定一个该引用。
  • HasModelParent引用规定了对象的父模型。

3. 对象类型节点类

为对象提供定义,用来定义对象类型。从基本节点类继承基本属性,附加IsAbstract属性表示对象类型是否是抽象的。

对象类型节点类

4. 变量节点类

变量代表简单或复杂的值,总是被定义为地址空间里其他节点的特性或数据变量,变量由变量类型定义。

变量节点类

5. 变量类型节点类

变量总是基于变量类型,指向其变量类型的HasTypeDefinition引用。

变量类型节点类

6. 方法节点类

用来定义方法,从基本节点类继承基本属性,不定义附加属性。使用HasProperty引用可以为方法定义特性,InputArgument和OutputArgument特性。

方法节点类

7. 引用类型节点类

引用被定义为引用类型节点的实例。

引用类型节点类继承了基本节点类的基本属性,其BrowseName属性在服务器中必须唯一。IsAbstract属性指示引用类型是否抽象,抽象的引用类型不能被实例化,只能用于组织。

引用类型节点类

8. 视图节点类

视图定义地址空间里的节点的子集(即地址空间的一个摘要),全部地址空间是缺省视图。针对庞大的下层系统(的地址空间),使用视图可以只关注感兴趣的数据。

视图也是地址空间中的节点。浏览视图上下文时,开始于视图节点。视图中所有节点应该是可访问的,浏览可以进行跳转。

视图节点可以作为进入地址空间的附加输入项,还可以作为组织地址空间的一种结构。

视图的另一个重要作用是,跟踪地址空间的不同版本,其ViewVersion特性,只要视图内容(如属于视图的引用和节点)发生改变,特性就会被更新。

视图节点类定义视图。

视图节点类

总结:

OPC UA地址空间中的节点是用节点类来定义的。OPC UA定义了基本的节点类,能够派生其他所有的节点类。而节点类在地址空间中也是使用节点来表示。为节点分配所属的节点类,则使用引用。

作为OPC中最重要的节点类别,对象、变量和方法(这三个概念基本可以表述一切具象事务),分别涉及到节点类中的对象/对象类型节点类、变量/变量类型节点类和方法节点类。

对象的类型定义是对象节点类,如一个基本对象其TypeDefinition可以是BaseObjectType,将对象和基本对象类型联系的纽带则是HasTypeDefinition引用。

如果是一个自定义的对象类型,则该对象的类型定义是对象类型节点类,即在基本对象类型的基础上进行重写,扩充其属性。通过实例化一个对象类型节点类,则得到属性重写的对象节点。

无论是何种类型的节点,在定义时首先需要关注该节点的引用,常用的引用如:

  • HasTypeDefinition,指向了节点的类型定义,绑定对象或变量到其对象类型或变量类型。
  • HasProperty,指定变量为特性,其源节点可以使任何节点类,目标节点应为变量。
  • HasModellingRule,绑定建模规则到一个对象、变量或方法,如果没有建模规则,则不能正确实例化节点。
  • HasModelParent,公开对象、变量或方法的父模型。
  • HasComponent,关联对象或对象类型与其包含的对象、数据变量和方法。通过该引用,将对象的属性节点指定到对应的对象中。
  • Organizes,用于组织地址空间中的节点,在地址空间中构造层次结构。它的源节点是对象或视图,如果它是对象,一般定义为FolderType或其子类型之一。

使用引用指定了节点间的关系,也就建立了地址空间的整体结构。将关注点定位到特定的节点,则需要关注节点的属性。任何类型的节点,都继承自基本节点类,拥有基本节点类所具有的属性,包括:NodeId,NodeClass,BrowseName,DisplayName,WriteMask,UserWriteMask

基本节点类向外派生,产生了对象节点、变量节点、方法节点、视图节点以及事件节点。这些节点是对应节点类(类型节点)的实例。所以节点的重点在于节点类(定义节点类型的节点)

节点类有多种,但终究还是产生于元数据(UA规范定义的节点类)。更确切的说,节点类的基本就是BaseObjectType和BaseVariableType,以及描述数据(一般作为节点的Value属性)类型的BaseDataType。想要搞定节点,重点就是这三个。

如有错误,欢迎指正 hbin6358@163.com
您好,如果您要在Java中使用OPC UA实现节点以及子节点的读取,可以使用Eclipse Milo这个Java实现的OPC UA库。以下是一个读取节点及其子节点的示例代码: ```java import org.eclipse.milo.opcua.sdk.client.OpcUaClient; import org.eclipse.milo.opcua.sdk.client.api.UaBrowseResult; import org.eclipse.milo.opcua.sdk.client.api.nodes.Node; import org.eclipse.milo.opcua.sdk.client.nodes.UaNode; import org.eclipse.milo.opcua.stack.core.Identifiers; import org.eclipse.milo.opcua.stack.core.types.builtin.NodeId; import org.eclipse.milo.opcua.stack.core.types.builtin.QualifiedName; import org.eclipse.milo.opcua.stack.core.types.builtin.Variant; import org.eclipse.milo.opcua.stack.core.types.enumerated.BrowseDirection; import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; public class ReadNodesExample { public static void main(String[] args) throws Exception { // 创建OPC UA客户端 OpcUaClient client = createClient(); // 连接到OPC UA服务器 client.connect().get(); try { // 获取根节点 NodeId rootNodeId = Identifiers.RootFolder; UaNode rootNode = client.getAddressSpace().getNode(rootNodeId).get(); // 读取根节点的DisplayName属性 String rootDisplayName = rootNode.getDisplayName().getText(); System.out.println("Root Node DisplayName: " + rootDisplayName); // 浏览根节点的子节点,并输出子节点的DisplayName属性 List<Node> childNodes = browseNode(client, rootNodeId); for (Node childNode : childNodes) { String childDisplayName = childNode.getDisplayName().getText(); System.out.println("Child Node DisplayName: " + childDisplayName); } } finally { // 断开连接 client.disconnect().get(); } } private static OpcUaClient createClient() throws Exception { // TODO: 替换成实际的OPC UA服务器地址 String serverUrl = "opc.tcp://localhost:4840"; // 创建OPC UA客户端 OpcUaClient client = new OpcUaClient(serverUrl); return client; } private static List<Node> browseNode(OpcUaClient client, NodeId nodeId) throws ExecutionException, InterruptedException { // 浏览节点的子节点 UaBrowseResult browseResult = client.browse(nodeId, BrowseDirection.Forward, Identifiers.References, true).get(); // 获取子节点NodeIds List<NodeId> childNodeIds = browseResult.getReferences().stream() .map(reference -> reference.getReferenceTypeId().equals(Identifiers.HasComponent) ? reference.getTargetNodeId() : null) .filter(nodeId -> nodeId != null) .collect(Collectors.toList()); // 获取子节点的详细信息 CompletableFuture<List<Node>> future = client.getAddressSpace().getNodes(childNodeIds); return future.get(); } } ``` 在这个示例代码中,我们首先创建了一个OPC UA客户端,连接到了OPC UA服务器。然后,我们获取了根节点并读取了根节点的DisplayName属性。接下来,我们使用browseNode()方法浏览了根节点的子节点,并输出了子节点的DisplayName属性。 需要注意的是,在实际应用中,我们应该将OPC UA客户端的创建、连接、断开连接等操作放在try-catch-finally块中,以确保在发生异常时能够正确地关闭连接。同时,我们也应该根据实际需求修改代码中的节点Id、属性名称等参数。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值