目录
-
- 摘要
- 一、OPC-UA协议概述
-
- [1.1 什么是OPC-UA](#1.1 什么是OPC-UA)
- [1.2 OPC-UA特点](#1.2 OPC-UA特点)
- [1.3 OPC-UA vs OPC-DA](#1.3 OPC-UA vs OPC-DA)
- [二、DolphinDB OPC-UA插件](#二、DolphinDB OPC-UA插件)
-
- [2.1 插件安装](#2.1 插件安装)
- [2.2 连接配置](#2.2 连接配置)
- 三、OPC-UA连接
-
- [3.1 创建连接](#3.1 创建连接)
- [3.2 浏览节点](#3.2 浏览节点)
- [3.3 节点标识](#3.3 节点标识)
- 四、数据读取
-
- [4.1 读取单个节点](#4.1 读取单个节点)
- [4.2 批量读取](#4.2 批量读取)
- [4.3 读取历史数据](#4.3 读取历史数据)
- 五、数据订阅
-
- [5.1 创建订阅](#5.1 创建订阅)
- [5.2 订阅配置](#5.2 订阅配置)
- [5.3 取消订阅](#5.3 取消订阅)
- 六、数据写入
-
- [6.1 写入单个节点](#6.1 写入单个节点)
- [6.2 批量写入](#6.2 批量写入)
- 七、实战案例
-
- [7.1 PLC数据采集系统](#7.1 PLC数据采集系统)
- 八、总结
- 参考资料
摘要
本文深入讲解DolphinDB OPC-UA协议接入技术。从OPC-UA协议原理到插件配置,从节点浏览到数据订阅,从实时采集到历史数据读取,全面介绍OPC-UA数据采集的核心方法。通过丰富的代码示例,帮助读者掌握工业标准通信的核心技能。
一、OPC-UA协议概述
1.1 什么是OPC-UA
OPC-UA(Open Platform Communications Unified Architecture)是工业自动化标准通信协议:
#mermaid-svg-ADHkGOE1wf32uOip{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-ADHkGOE1wf32uOip .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-ADHkGOE1wf32uOip .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-ADHkGOE1wf32uOip .error-icon{fill:#552222;}#mermaid-svg-ADHkGOE1wf32uOip .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-ADHkGOE1wf32uOip .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-ADHkGOE1wf32uOip .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-ADHkGOE1wf32uOip .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-ADHkGOE1wf32uOip .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-ADHkGOE1wf32uOip .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-ADHkGOE1wf32uOip .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-ADHkGOE1wf32uOip .marker{fill:#333333;stroke:#333333;}#mermaid-svg-ADHkGOE1wf32uOip .marker.cross{stroke:#333333;}#mermaid-svg-ADHkGOE1wf32uOip svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-ADHkGOE1wf32uOip p{margin:0;}#mermaid-svg-ADHkGOE1wf32uOip .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-ADHkGOE1wf32uOip .cluster-label text{fill:#333;}#mermaid-svg-ADHkGOE1wf32uOip .cluster-label span{color:#333;}#mermaid-svg-ADHkGOE1wf32uOip .cluster-label span p{background-color:transparent;}#mermaid-svg-ADHkGOE1wf32uOip .label text,#mermaid-svg-ADHkGOE1wf32uOip span{fill:#333;color:#333;}#mermaid-svg-ADHkGOE1wf32uOip .node rect,#mermaid-svg-ADHkGOE1wf32uOip .node circle,#mermaid-svg-ADHkGOE1wf32uOip .node ellipse,#mermaid-svg-ADHkGOE1wf32uOip .node polygon,#mermaid-svg-ADHkGOE1wf32uOip .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-ADHkGOE1wf32uOip .rough-node .label text,#mermaid-svg-ADHkGOE1wf32uOip .node .label text,#mermaid-svg-ADHkGOE1wf32uOip .image-shape .label,#mermaid-svg-ADHkGOE1wf32uOip .icon-shape .label{text-anchor:middle;}#mermaid-svg-ADHkGOE1wf32uOip .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-ADHkGOE1wf32uOip .rough-node .label,#mermaid-svg-ADHkGOE1wf32uOip .node .label,#mermaid-svg-ADHkGOE1wf32uOip .image-shape .label,#mermaid-svg-ADHkGOE1wf32uOip .icon-shape .label{text-align:center;}#mermaid-svg-ADHkGOE1wf32uOip .node.clickable{cursor:pointer;}#mermaid-svg-ADHkGOE1wf32uOip .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-ADHkGOE1wf32uOip .arrowheadPath{fill:#333333;}#mermaid-svg-ADHkGOE1wf32uOip .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-ADHkGOE1wf32uOip .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-ADHkGOE1wf32uOip .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-ADHkGOE1wf32uOip .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-ADHkGOE1wf32uOip .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-ADHkGOE1wf32uOip .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-ADHkGOE1wf32uOip .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-ADHkGOE1wf32uOip .cluster text{fill:#333;}#mermaid-svg-ADHkGOE1wf32uOip .cluster span{color:#333;}#mermaid-svg-ADHkGOE1wf32uOip div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-ADHkGOE1wf32uOip .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-ADHkGOE1wf32uOip rect.text{fill:none;stroke-width:0;}#mermaid-svg-ADHkGOE1wf32uOip .icon-shape,#mermaid-svg-ADHkGOE1wf32uOip .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-ADHkGOE1wf32uOip .icon-shape p,#mermaid-svg-ADHkGOE1wf32uOip .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-ADHkGOE1wf32uOip .icon-shape .label rect,#mermaid-svg-ADHkGOE1wf32uOip .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-ADHkGOE1wf32uOip .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-ADHkGOE1wf32uOip .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-ADHkGOE1wf32uOip :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} OPC-UA架构
PLC/DCS
OPC-UA Server
传感器
设备
OPC-UA Client
DolphinDB
SCADA
MES
1.2 OPC-UA特点
| 特点 | 说明 |
|---|---|
| 平台无关 | 跨平台支持 |
| 安全通信 | 加密认证 |
| 信息模型 | 标准化数据模型 |
| 订阅机制 | 变化通知 |
1.3 OPC-UA vs OPC-DA
| 特性 | OPC-DA | OPC-UA |
|---|---|---|
| 平台 | Windows only | 跨平台 |
| 协议 | DCOM | TCP/HTTP |
| 安全 | 弱 | 强 |
| 推荐 | ❌ | ✅ |
二、DolphinDB OPC-UA插件
2.1 插件安装
python
// 检查插件
getLoadedPlugins()
// 加载OPC-UA插件
loadPlugin("opcua")
// 查看插件函数
opcua::getPluginFunctions()
2.2 连接配置
python
// OPC-UA连接配置
config = dict(STRING, ANY, [
["endpointUrl", "opc.tcp://localhost:4840"],
["securityMode", "None"], // None/Sign/SignAndEncrypt
["securityPolicy", "None"], // None/Basic128Rsa15/Basic256/Aes256
["username", "admin"],
["password", "password"]
])
三、OPC-UA连接
3.1 创建连接
python
// 连接OPC-UA服务器
conn = opcua::connect("opc.tcp://localhost:4840")
// 带认证连接
conn = opcua::connect(
"opc.tcp://localhost:4840",
"admin",
"password"
)
// 查看连接状态
opcua::getStatus(conn)
// 断开连接
opcua::disconnect(conn)
3.2 浏览节点
python
// 浏览根节点
nodes = opcua::browse(conn, "i=84") // Root节点
// 浏览Objects节点
objects = opcua::browse(conn, "i=85") // Objects节点
// 浏览设备节点
deviceNodes = opcua::browse(conn, "ns=2;s=Device1")
3.3 节点标识
python
// 节点标识格式
// i=数字 -> 整数标识符
// s=字符串 -> 字符串标识符
// g=GUID -> GUID标识符
// b=字节串 -> 字节串标识符
// 示例
nodeId = "ns=2;s=Temperature" // 命名空间2,字符串标识符
nodeId = "i=2258" // 整数标识符
四、数据读取
4.1 读取单个节点
python
// 读取节点值
value = opcua::read(conn, "ns=2;s=Temperature")
// 读取带时间戳
result = opcua::readWithTimestamp(conn, "ns=2;s=Temperature")
print("值: " + string(result.value))
print("时间: " + string(result.timestamp))
print("质量: " + string(result.quality))
4.2 批量读取
python
// 批量读取多个节点
nodeIds = [
"ns=2;s=Temperature",
"ns=2;s=Humidity",
"ns=2;s=Pressure"
]
values = opcua::readBatch(conn, nodeIds)
// 结果
for (i in 0..nodeIds.size()) {
print(nodeIds[i] + " = " + string(values[i]))
}
4.3 读取历史数据
python
// 读取历史数据
startTime = now() - 3600000 // 1小时前
endTime = now()
history = opcua::readHistory(
conn,
"ns=2;s=Temperature",
startTime,
endTime
)
// 历史数据格式
select top 10 * from history
五、数据订阅
5.1 创建订阅
python
// 创建流表
share streamTable(1:0,
`node_id`timestamp`value`quality,
[STRING, TIMESTAMP, DOUBLE, INT]) as opcua_stream
// 创建订阅
subscription = opcua::createSubscription(conn, 1000) // 采样间隔1秒
// 添加监控项
opcua::addMonitoredItem(subscription, "ns=2;s=Temperature", opcua_stream)
opcua::addMonitoredItem(subscription, "ns=2;s=Humidity", opcua_stream)
opcua::addMonitoredItem(subscription, "ns=2;s=Pressure", opcua_stream)
// 查看订阅
opcua::getSubscriptionStat(subscription)
5.2 订阅配置
python
// 订阅参数配置
subscription = opcua::createSubscription(
conn,
1000, // 采样间隔(毫秒)
100, // 队列大小
true, // 数据变化触发
10 // 环形缓冲区大小
)
// 监控项配置
opcua::addMonitoredItem(
subscription,
"ns=2;s=Temperature",
opcua_stream,
0.5 // 死区(变化超过0.5才触发)
)
5.3 取消订阅
python
// 删除监控项
opcua::removeMonitoredItem(subscription, "ns=2;s=Temperature")
// 删除订阅
opcua::deleteSubscription(subscription)
六、数据写入
6.1 写入单个节点
python
// 写入节点值
opcua::write(conn, "ns=2;s=Setpoint", 25.0)
// 写入带时间戳
opcua::writeWithTimestamp(
conn,
"ns=2;s=Setpoint",
25.0,
now()
)
6.2 批量写入
python
// 批量写入
nodeIds = ["ns=2;s=Setpoint1", "ns=2;s=Setpoint2", "ns=2;s=Setpoint3"]
values = [25.0, 30.0, 35.0]
opcua::writeBatch(conn, nodeIds, values)
七、实战案例
7.1 PLC数据采集系统
python
// ========== PLC数据采集系统 ==========
// 1. 创建分布式表
db = database("dfs://plc_db", VALUE, 1..100)
schema = table(1:0,
`device_id`timestamp`temperature`pressure`flow_rate,
[SYMBOL, TIMESTAMP, DOUBLE, DOUBLE, DOUBLE])
db.createPartitionedTable(schema, `plc_data, `device_id)
// 2. 创建流表
share streamTable(100000:0,
`device_id`timestamp`temperature`pressure`flow_rate,
[SYMBOL, TIMESTAMP, DOUBLE, DOUBLE, DOUBLE]) as plc_stream
// 3. 启用持久化
enableTablePersistence(plc_stream, true, true, 1000000)
// 4. 订阅流表写入分布式表
subscribeTable(, "plc_stream", "persist", -1,
def(msg) {
loadTable("dfs://plc_db", "plc_data").append!(msg)
}, 10000, 5000)
// 5. 连接OPC-UA服务器
conn = opcua::connect("opc.tcp://plc-server:4840")
// 6. 创建订阅
subscription = opcua::createSubscription(conn, 1000)
// 7. 添加监控项
opcua::addMonitoredItem(subscription, "ns=2;s=Temperature", plc_stream)
opcua::addMonitoredItem(subscription, "ns=2;s=Pressure", plc_stream)
opcua::addMonitoredItem(subscription, "ns=2;s=FlowRate", plc_stream)
// 8. 监控函数
def monitorPlc() {
print("=== PLC数据采集监控 ===")
print("OPC-UA状态: " + opcua::getStatus(conn))
print("流表行数: " + string(exec count(*) from plc_stream))
t = loadTable("dfs://plc_db", "plc_data")
print("分布式表行数: " + string(exec count(*) from t))
}
monitorPlc()
print("PLC数据采集系统启动完成")
八、总结
本文详细介绍了DolphinDB OPC-UA协议接入:
- OPC-UA协议:工业标准、安全通信、信息模型
- 插件配置:安装、加载、连接
- 节点浏览:浏览节点、节点标识
- 数据读取:单点读取、批量读取、历史数据
- 数据订阅:创建订阅、监控项配置
- 数据写入:单点写入、批量写入
思考题:
- OPC-UA相比OPC-DA有什么优势?
- 如何设计高可用的OPC-UA数据采集系统?
- 如何处理OPC-UA连接断开问题?