跳到主要内容

OpcUaNodeId — 强类型 NodeId

概述

OPC UA 节点 ID 默认用字符串编码 ("ns=2;s=Foo" / "i=84")。OpcUaNodeId 是不可变 dataclass, 显式带 namespace / id_type / identifier 三件套, 与字符串 100% 互转。

对应规范段: Part 6 §5.2.2。

API

成员类别读写说明
OpcUaNodeId.NULL静态空哨兵
OpcUaNodeId.from_numeric(ns, id)工厂数字型
OpcUaNodeId.from_string(ns, id)工厂字符串型
OpcUaNodeId.from_guid(ns, uuid)工厂GUID 型
OpcUaNodeId.from_opaque(ns, bytes)工厂不透明型
OpcUaNodeId.parse(s)静态解析, 失败抛 ValueError
OpcUaNodeId.try_parse(s)静态安全解析, 返回 (bool, nid)
nid.to_string() / str(nid)序列化
nid.namespace_index / id_type / identifier / is_null属性字段

相关结构:

class NodeIdType(IntEnum):
NUMERIC = 0 # i= uint32
STRING = 1 # s= UTF-8
GUID = 2 # g= {xxxx-...}
OPAQUE = 3 # b= base64

代码示例

import uuid
from opcua import OpcUaNodeId, NodeIdType

# 1) 工厂构造
n1 = OpcUaNodeId.from_numeric(0, 84) # i=84
n2 = OpcUaNodeId.from_string(2, "Boiler1.Temp") # ns=2;s=Boiler1.Temp
n3 = OpcUaNodeId.from_guid(3, uuid.uuid4()) # ns=3;g={...}
n4 = OpcUaNodeId.from_opaque(4, bytes([1, 2, 3]))

# 2) 解析
n5 = OpcUaNodeId.parse("ns=2;s=Demo.Tag")
print(f"ns={n5.namespace_index}, type={n5.id_type}, id={n5.identifier}")

ok, n6 = OpcUaNodeId.try_parse("ns=99;i=foo") # False
if not ok:
print("invalid")

# 3) 序列化
s = str(n2) # "ns=2;s=Boiler1.Temp"

# 4) 与 SDK 互转 - SDK 接口接受字符串
with ua.read(str(n2)) as dv:
pass

# 5) 字典 key (frozen dataclass 自动 __hash__)
d = {n2: "锅炉一温度"}

# 6) Null
print(OpcUaNodeId.NULL.is_null) # True

字符串编码规则

编码说明
i=NNN数字, ns=0 时省略
ns=N;i=NNN数字
ns=N;s=XXX字符串
ns=N;g={GUID}GUID
ns=N;b=base64==字节

最佳实践

  • 配置文件存字符串, 加载用 parse
  • 代码内部用强类型
  • Numeric 优先 (uint 比较快)
  • 用户输入永远先 try_parse

跨语言对照

C#PythonJavaC++RustC
OpcUaNodeIdOpcUaNodeIdOpcUaNodeIdOpcUaNodeIdOpcUaNodeIdDarraUa_NodeId
ParseparseparseParseparseDarraUa_NodeId_Parse
FromNumericfrom_numericfromNumericFromNumericfrom_numericDarraUa_NodeId_FromNumeric

下一步