4. OPC UA 信息模型:类型系统、引用类型、对象类型、变量类型、数据编码
OPC UA 信息模型是工业物联网数据语义化的核心。它不仅仅是一个数据通道,更是一套完整的、面向对象的类型系统,用于描述现实世界中的设备、传感器、工艺参数及其相互关系。理解信息模型,是构建可互操作、可扩展的数据采集方案的前提。
4.1 类型系统概述
OPC UA 的类型系统采用严格的层次化结构,所有类型都继承自一个基类。这种设计确保了地址空间中所有节点的行为一致性,并允许客户端通过类型信息自动理解数据的含义。
| 类型类别 | 基类 | 核心作用 | 实例 |
|---|---|---|---|
| 对象类型 | BaseObjectType | 定义对象的属性、变量和方法的结构 | MotorType、PumpType |
| 变量类型 | BaseVariableType | 定义变量的数据类型、语义和属性 | AnalogItemType、PropertyType |
| 引用类型 | BaseReferenceType | 定义节点之间的语义关系 | HasComponent、Organizes |
| 数据类型 | —— | 定义数据值的结构和编码方式 | Int32、String、Structure |
关键概念: 类型系统是“模板”,节点是“实例”。例如,
MotorType 定义了电机应有的所有属性(转速、温度、状态),而地址空间中具体的 Motor_001 节点则是该类型的一个实例,拥有具体的数值。
4.2 引用类型:语义关系的基石
引用类型定义了节点之间如何连接。没有引用,地址空间只是一堆孤立的节点。OPC UA 预定义了几种核心引用类型,并允许用户自定义扩展。
- Hierarchical References(层次引用): 用于构建地址空间的树形结构。
Organizes:用于将子节点组织到父节点下,常用于对象与文件夹之间。HasComponent:表示父对象包含子组件,是强包含关系。HasProperty:表示节点拥有某个属性。
- Non-Hierarchical References(非层次引用): 用于在树形结构之外建立跨分支的语义关联。
HasTypeDefinition:指向节点的类型定义,是实例化关系的核心。HasSubtype:用于定义类型之间的继承关系。HasEventSource:表示节点是事件的来源。
实战要点: 在采集数据时,客户端通常通过
HasComponent 和 Organizes 引用遍历地址空间树,找到目标变量节点。而 HasTypeDefinition 引用则用于获取变量的元数据(如量程、单位),这是实现智能仪表盘的关键。
4.3 对象类型:设备的抽象模板
对象类型是信息模型中最常用的类型,用于定义现实世界中的物理或逻辑实体。一个对象类型可以包含变量、方法、事件和其他对象。
- 预定义对象类型: OPC UA 规范定义了
BaseObjectType,所有自定义对象类型都继承自它。 - 自定义对象类型: 通过
HasSubtype引用从BaseObjectType派生。例如,定义一个TemperatureSensorType,包含CurrentTemperature(变量)、AlarmLimit(属性)和Reset()(方法)。
常见误区: 初学者容易混淆“对象类型”和“对象节点”。对象类型是定义在类型字典中的模板,而对象节点是地址空间中实际存在的实例。修改对象类型会影响所有未覆盖该属性的实例。
4.4 变量类型:数据的语义标签
变量类型为数据值赋予了丰富的语义信息,使得客户端无需预先知道设备细节就能正确解析数据。
| 变量类型 | 用途 | 关键属性 |
|---|---|---|
| PropertyType | 描述节点的静态属性 | Value、DataType、AccessLevel |
| AnalogItemType | 表示模拟量(连续值) | EURange(量程)、EngineeringUnits(工程单位) |
| DiscreteItemType | 表示离散量(枚举或整数值) | EnumValues、ValuePrecision |
| ArrayItemType | 表示数组数据 | ArrayDimensions、AxisInformation |
仪表盘集成价值: 当仪表盘读取一个
AnalogItemType 变量时,可以直接从节点的 EURange 属性获取量程(如 0-100°C),从 EngineeringUnits 获取单位,自动配置 Y 轴范围和标签,无需人工干预。
4.5 数据编码:二进制与 JSON
OPC UA 支持多种数据编码方式,以适应不同的网络环境和应用场景。编码方式决定了数据在网络上传输时的字节格式。
- UA Binary(二进制编码): 默认编码,高效紧凑,适用于高实时性、低带宽的工业现场。所有 OPC UA 服务器和客户端都必须支持。
- UA JSON(JSON 编码): 基于文本,可读性强,易于与 Web 应用、云平台集成。常用于物联网网关和 REST API 场景。
- UA XML(XML 编码): 主要用于配置和交换信息模型文件(NodeSet),不常用于运行时数据采集。
4.6 实战:使用 Python 读取类型信息
在 Python 中,使用 opcua-asyncio 或 opcua 库可以轻松获取节点的类型信息。以下代码展示了如何读取一个变量的类型定义及其属性。
import asyncio
from opcua import Client
async def read_type_info():
client = Client("opc.tcp://localhost:4840")
await client.connect()
try:
# 获取一个变量节点
var_node = client.get_node("ns=2;s=Temperature_001")
# 读取变量的数据类型
data_type = await var_node.read_data_type()
print(f"数据类型: {data_type}")
# 读取变量的类型定义节点 (HasTypeDefinition)
type_def_node = await var_node.read_type_definition()
print(f"类型定义节点: {type_def_node}")
# 读取类型定义节点的 BrowseName
type_name = await type_def_node.read_browse_name()
print(f"变量类型名称: {type_name}")
# 如果是 AnalogItemType,读取量程和单位
if "AnalogItemType" in str(type_name):
# 读取 EURange 属性
eu_range_node = var_node.get_child("0:EURange")
eu_range = await eu_range_node.read_value()
print(f"量程: {eu_range}")
# 读取 EngineeringUnits 属性
unit_node = var_node.get_child("0:EngineeringUnits")
unit = await unit_node.read_value()
print(f"工程单位: {unit}")
finally:
await client.disconnect()
asyncio.run(read_type_info())
代码解读: 上述代码通过
read_type_definition() 获取变量的类型节点,然后通过 get_child() 方法读取类型定义中预定义的属性(如 EURange)。这是实现“自描述仪表盘”的基础——仪表盘无需硬编码任何设备参数,完全通过信息模型动态获取。
4.7 本章小结
OPC UA 信息模型通过严谨的类型系统,将工业数据从“裸数值”提升为“语义对象”。引用类型定义了节点间的关系,对象类型和变量类型提供了结构和语义模板,而数据编码则确保了数据在不同场景下的高效传输。掌握这些概念,是构建可互操作、可维护的工业物联网系统的关键一步。