跳到主要内容

OpcUaDataValue

OpcUaDataValue 包装一次 read 返回的全部信息: 值 + 状态 + 时间戳.

实现 AutoCloseable — 持有 native handle, 必须 close.

配套

公共方法

类别属性类型访问说明
variant()OpcUaVariantR实际值 (不持有, 不要 close)
getStatusEnum()Enums.StatusCodeR数据质量 (枚举形式) Good / Bad* / Uncertain*
getStatusCode()intR原始 32-bit StatusCode
isGood()booleanR等价 (code & 0xC0000000) == 0
时间戳sourceTimestamp()longR数据源 FileTime (100ns since 1601 UTC), 0 = null
serverTimestamp()longR服务端 FileTime, 0 = null
内部handle()PointerR内部 native handle (调试用)
释放close()void释放 native 内存 (owns=true 时)

用法

try (OpcUaDataValue dv = ua.read("ns=2;s=Temperature")) {

// 检查质量
if (!dv.isGood()) {
System.err.println("Bad value: " + dv.getStatusEnum());
return;
}

// 取值
OpcUaVariant v = dv.variant();
Double temp = v.asDouble();
if (temp == null) {
System.err.println("Type mismatch");
return;
}

// 取时间戳
long ft = dv.sourceTimestamp();
Instant t = (ft > 0)
? Instant.ofEpochMilli((ft - 116444736000000000L) / 10000L)
: Instant.now();

System.out.printf("%s: %.2f °C%n", t, temp);
}

StatusCode 重点值

含义
Enums.StatusCode.Good (0x00000000)一切正常
Enums.StatusCode.Uncertain (0x40000000)不确定但可用 (例如传感器超量程)
Enums.StatusCode.Bad (0x80000000)数据无效
Enums.StatusCode.BadCommunicationError通讯失败
Enums.StatusCode.BadNodeIdUnknown节点不存在
Enums.StatusCode.BadNotReadable该 Attribute 不可读

业务代码必须检查 getStatusEnum() / isGood(), 不能假设 Good.

Enums.StatusCode 提供 isGood() / isUncertain() / isBad() 按位判断方法.


时间戳含义

  • sourceTimestamp()数据真实产生时间 (传感器采样时刻 / 计算时刻). 历史 / 趋势 / 同步用这个
  • serverTimestamp()服务端收到 / 处理时间. 用于诊断网络延迟. 一般不用于业务

如果服务端没设 SourceTimestamp, 它就是 ServerTimestamp 的副本.

返回 0 表示该时间戳为 null.


FileTime ↔ Instant 转换

import java.time.Instant;

// FileTime → Instant
long ft = dv.sourceTimestamp();
Instant t = (ft > 0)
? Instant.ofEpochMilli((ft - 116444736000000000L) / 10000L)
: Instant.now();

// Instant → FileTime
long ft2 = t.toEpochMilli() * 10000L + 116444736000000000L;

内存所有权

OpcUaDataValue 持有 native handle, 实现 AutoCloseable:

来源owns是否要 close
ua.read(...) 返回true
ua.readMany(...) 返回的每个元素true
ua.readHistoryXxx(...) 返回的每个元素true
node.getValue() 返回true
漏 close 后果

漏 close 会泄漏 native 内存 (定时跑 100k+ 次会涨内存). 永远用 try-with-resources 或 try-finally 包.

最佳实践

// 单个
try (OpcUaDataValue dv = ua.read("ns=2;s=T1")) {
System.out.println(dv.variant());
}

// 批量
List<OpcUaDataValue> dvs = ua.readMany(nodes, Enums.AttributeId.Value);
try {
for (OpcUaDataValue dv : dvs) {
if (dv != null) System.out.println(dv.variant());
}
} finally {
for (OpcUaDataValue dv : dvs) if (dv != null) dv.close();
}

构造 (用于 HistoryUpdate)

通常由 SDK 内部构造. 用户用于 HistoryUpdate 的场景, 当前需要从已有 DataValue 派生 (后续版本会暴露公共构造器).

下一步