第二章:信息建模:对象和变量的类型1

REDISANT 提供互联网与物联网开发测试套件 #


对象和变量的类型 #

OPC UA 的主要功能是不仅在数据类型级别(知道值是 Int32 还是字符串)提供类型信息,而且在对象级别也提供类型信息。例如,这允许公开特定类型的设备提供测量温度的信息。在传统 OPC 中,除了使用产品或域特定的命名约定之外,没有其他可能性。在 OPC UA 中,您可以通过定义温度传感器的类型并创建该类型的对象来表达此信息。可以定义标准类型,并且可以通过继承从中派生特定于供应商的类型。特定于供应商的类型可以用来增强标准类型。这允许客户端利用特定类型的知识进行编程,例如,通过定义针对特定类型定制的图形元素(如面板)并将其用于该类型的多个实例。

OPC UA 提供了丰富的类型模型,但它并不强制服务器真正使用它。例如,OPC 基金会的包装器通常将经典 OPC DA 数据映射到 OPC UA,并且没有任何可用的实际类型信息,因此无法提供实际类型系统。在这种情况下,只使用一些基类型。因此,下面介绍的类型模型是一个强大的概念,但如果没有可用的类型信息,它也不会成为使用 OPC UA 的障碍。

OPC UA 地址空间为对象的类型定义定义了ObjectType节点类,为变量的类型定义定义了 VariableType节点类。方法没有可用的类型定义。方法可以绑定到 ObjectType,因此可以在对象上使用,但它们由其 BrowseName 及其参数定义,因此不需要类型。

如果我们要概括 ObjectTypes 和 VariableTypes 来解释共同的特征,我们将它们称为 TypeDefinition。

简单对象类型 #

ObjectType 可以是简单的,也可以是复杂的。复杂类型会公开其下存在于该类型的每个实例上的一些节点结构,而简单类型只会为对象定义一些语义。简单类型的一个示例是 OPC UA [UA 第 3 部分] 定义的 FolderType。此处的语义定义为文件夹的目的是在地址空间中组织其他节点。FolderType 下没有定义其他结构。

1.8 总结了 ObjectType 的属性。唯一的新增属性指定类型是否为抽象类型。抽象类型不能被对象引用为类型定义,只能用于组织类型层次结构中的类型。

ObjectType 的属性
属性 数据类型 描述
包含表1.1中定义的所有公共属性
IsAbstract Boolean 此属性指示 ObjectType 是具体的还是抽象的,因此不能直接用作类型定义

让我们来看看对象的类型系统是如何工作的。在图 1.10 中,您可以看到由 OPC UA 定义的简单 ObjectType FolderType 和一些使用该类型的对象。对象使用 HasTypeDefinition ReferenceType 引用其类型。每个对象都是类型化的,并且只有一个类型,因此每个对象都是一个 HasTypeDefinition Reference 的源。在图 1.10 中,对象“Root”和“Objects”使用 HasTypeDefinition Reference 引用 FolderType,因此属于 FolderType 类型。这两个节点实际上都是进入地址空间的标准入口点,并在 [UA 第 5 部分] 中定义。

当使用 NodeManagement Services(参见第 5 章)创建新对象时,必须提供类型定义。新对象的某些属性不必指定,但可以用 ObjectType 的默认值填充。对于“Objects”,只有[2] Description 和 DisplayName 属性默认使用 ObjectType 的默认值填充。这在使用 FolderType 的 Description 的“Root”对象上得到了体现。

简单 ObjectType 的示例

除了提供语义之外,FolderType 并不限制其实例的使用。理论上,节点的所有属性都可以更改(对于某些属性,如 NodeClass,这通常没有意义)。可以将新的引用添加到节点(例如图 1.10 中的 Root 现在引用Objects),稍后可以从对象中删除它们。但是,这可能不适用于所有类型的引用。即使 FolderType 不限制引用的使用,也可能存在将其使用限制为某些 ObjectType 或 NodeClass 的 ReferenceType。此外,其他 ObjectType 可能会限制其实例的引用方式,我们将在讨论复杂 ObjectType 时看到这一点。

ObjectType 支持继承,因此存在 ObjectType 的类型层次结构。在图 1.11 中,您可以看到类型层次结构的摘录,其中简单类型 BranchType 派生自 FolderType。 OPC DA 服务器的包装器可以使用此类型来表示 OPC DA 分支。它们与 FolderType Objects具有相同的用途,即它们只是组织地址空间。但是,创建子类型是有意义的,这样客户端就知道他们正在访问包装的 Classic OPC DA 数据。客户端可以忽略子类型,并基于它是 FolderType 子类型的知识,将每个 BranchType 类型的对象视为 FolderType 类型的对象。

简单 ObjectType 的继承

简单变量类型 #

与 ObjectType 一样,VariableType 也可以是简单的或复杂的。复杂类型公开了其下的节点结构,该结构在实例中可用,而简单 VariableType 仅定义变量的语义或限制实例上 Value 属性的数据类型的使用。例如,OPC UA 规范为变量定义了一个名为 BaseDataVariableType 的基本类型,不限制数据类型的使用 [UA 第 5 部分]。子类型可以定义具有典型计数器语义的计数器变量,并将数据类型的使用限制为标量整数值。

在详细介绍示例之前,让我们先检查表 1.9 中的 VariableType 节点类的属性。

VariableTypes 的属性
属性 数据类型 描述
包含表1.1中定义的所有公共属性
Value Is not fix; specified by other Attributes 此可选属性定义此变量类型的实例的默认值。值的数据类型由 DataType、ValueRank 和 ArrayDimensions 属性指定
DataType NodeId 定义此类型实例的Value属性的数据类型以及VariableType的Value属性的数据类型(如果提供)
ValueRank Int32 标识此类型实例的值是标量值、数组还是多维数组
ArrayDimensions UInt32[] 此可选属性允许指定数组或矩阵的大小,并且只能在值为数组时使用。对于数组的每个维度,此数组中的相应条目定义维度的大小
IsAbstract Boolean 此属性指示变量类型是抽象的,因此不能直接用作类型定义或具体

VariableType 节点类的属性与 Variable 节点类非常相似。它包含 Value 属性和 Value 属性的数据类型定义。它不包含那些提供有关值的运行时行为的信息的属性(它当前是否已历史记录化、是否可读、最小采样率是多少等),但它包含 IsAbstract 属性,用于标识VariableType是否可直接由实例使用或仅用于组织VariableType的层次结构。与变量不同,Value属性只是可选的,因为它对VariableType没有实际用途,因为预计Value在变量类型上没有实际意义。提供Value的唯一原因是为变量类型的实例定义默认值。因此,为变量类型的值提供数据类型信息主要用于定义变量类型实例的数据类型。

在第 2.8 节中,您将了解到DataType也有一个层次结构。VariableType可能只使用该层次结构的一些基类型,而VariableType的实例可能提供更具体的类型。让我们看一个具体的例子。在图 1.12 中,您可以看到 BaseDataVariableType。它使用 BaseDataType(DataType 层次结构的根)并且不限制数组的使用。因此,此 VariableType 的实例可以根据需要限制其数据类型(例如 Variable1 使用标量 Int32)。

但是,数据类型的限制不必在实例上进行。变量仅使用抽象基本数据类型也是有效的。在这种情况下,客户端必须期望返回该数据类型的任何子类型。例如,Variable2 仅将数据类型限制为标量,因此有效的返回值是字符串“Test1”、Int32 “123”等。每次值更改时,数据类型都会更改,客户端必须能够处理此行为。在第 2.8 节中,您将看到有更多抽象DataType。例如,这允许公开提供的数字作为值,而无需指定数字的具体类型。

对于简单变量类型的子类型化,适用与实例化变量类型的相同规则。数据类型可以更具体,但当然不能扩展。在图 1.13 中,您可以看到 BaseDataVariableType 子类型的示例。 BaseDataVariableType 的子类型 CounterType 限制了数据类型的使用(仅允许标量整数),还定义了该 VariableType 实例的语义。它使用名称(Counter)和Description属性来定义语义。

简单变量类型的示例
简单变量类型的继承

以下规则不仅适用于简单类型,也适用于复杂类型。

没有规则要求 ObjectTypes 或 VariableTypes 的名称保持唯一。服务器可以提供具有相同名称的多个类型。只有 NodeId 才能使类型唯一。但是,不建议两次使用相同的 BrowseName。

并不禁止 ObjectTypes 或 VariableTypes 可以有多个超类型,但不建议这样做。每个 ObjectType 和每个 VariableType 必须至少有一个超类型,BaseObjectType 和 BaseVariableType 除外。因此,每个 ObjectType 必须是 BaseObjectType 的子类型,每个 VariableType 必须是 BaseVariableType 的子类型。

VariableTypes 的实例和子类型可以进一步限制数据类型,但不能利用它。这意味着它们可以使用 DataType 的子类型,但不能使用超类型或任何不是同一 DataType 或子类型的其他 DataType。如果 ValueRank 没有指定具体特征,则可以在实例或子类型中指定。如果 VariableType 在 ValueRank 中指定了“Any”,则子类型或实例可以选择“Scalar”或任何其他选项。如果 VariableType 指定 OneOrMoreDimensions,则实例或子类型可以指定具体维度(例如,OneDimension);但是,它不能指定“Any”或“Scalar”。

超类型定义的任何语义仍然必须适用于子类型。示例中使用的 VariableType CounterType 可以再定义它的子类型,但为 CounterType 定义的语义仍然必须对子类型有效。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 原文链接:https://blog.redisant.cn