You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

OPC UA节点恢复在线后如何获取数据变更通知并避免数据丢失?

解决OPC UA订阅节点恢复后的状态感知与数据不丢失问题

核心思路:利用asyncua订阅的状态回调机制

asyncua的Subscription原生支持监控项的状态变更通知,无需自行轮询。通过自定义Handler监听监控项状态变化,既能实时知晓节点恢复情况,又能配合历史数据读取避免数据丢失。

具体实现方案

1. 自定义Subscription Handler,重写状态变更方法

在Handler中实现monitored_item_status_changed方法,该方法会在监控项状态(节点不可用/恢复可用)变化时自动触发:

class SubscriptionHandler:
    def __init__(self, client, subscription):
        self.client = client
        self.subscription = subscription
        self.unavailable_nodes = set()

    def datachange_notification(self, node, val, data):
        # 正常接收数据变更的逻辑
        print(f"节点 {node} 值更新:{val}")

    def monitored_item_status_changed(self, item_id, status, diagnostic):
        # 监控项状态变更回调
        node = self.subscription._monitored_items[item_id]
        if status.is_good():
            # 节点恢复可用
            print(f"节点 {node} 已恢复,状态:{status}")
            if node in self.unavailable_nodes:
                self.unavailable_nodes.remove(node)
                # 启动数据恢复任务
                asyncio.create_task(self.recover_missing_data(node))
        else:
            # 节点变为不可用
            print(f"节点 {node} 不可用,状态:{status}")
            self.unavailable_nodes.add(node)

    async def recover_missing_data(self, node):
        # 恢复后读取当前值或历史数据,填补缺失
        try:
            current_val = await node.read_value()
            print(f"恢复节点 {node} 当前值:{current_val}")
            # 若服务器开启历史存储,可读取不可用期间的历史数据
            # history_details = ua.ReadRawModifiedDetails()
            # history_vals = await node.read_history_values(history_details)
            # print(f"节点 {node} 历史数据:{history_vals}")
        except Exception as e:
            print(f"恢复节点 {node} 数据失败:{e}")

2. 初始化订阅时绑定自定义Handler

修改订阅代码,传入自定义Handler实例:

import asyncio
import asyncua
from asyncua import ua

async def main():
    url = "opc.tcp://your-server-address:port"
    async with asyncua.Client(url=url) as client:
        handler = SubscriptionHandler(client, None)
        subscription = await client.create_subscription(50, handler)
        handler.subscription = subscription  # 将订阅实例关联到Handler
        nodes = [
            client.get_node('ns=3;i=1025'),
            client.get_node('ns=3;i=1026'),
            client.get_node('ns=3;i=1027')
        ]
        await subscription.subscribe_data_change(nodes)
        print("已订阅节点:", subscription._monitored_items)
        
        # 保持客户端运行
        await asyncio.Future()

if __name__ == "__main__":
    asyncio.run(main())

3. 可选:历史数据补全

如果服务器配置了历史数据存储,在节点恢复时调用read_history_values方法,即可获取节点不可用期间的所有数据,完全避免丢失。

方案优势

  • 实时感知:节点状态变化瞬间触发回调,无需等待轮询周期,不会错过恢复时机
  • 无数据遗漏:恢复后可读取当前值或历史数据,覆盖不可用期间的缺失
  • 资源高效:无需周期性发起读取请求,降低客户端与服务器的通信开销

内容的提问来源于stack exchange,提问作者Meet Bedmutha

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 09:47:47