如何用C# Opc.Ua.Client通过标签名访问OPC UA节点并订阅
问题分析与解决方案
问题根源
你用ns=2;s=MyObject:Tag1这种字符串NodeId访问失败,核心原因是Python freeopcua创建变量时,默认的字符串NodeId标识符仅为变量名"Tag1",而非对象+冒号+变量名的组合。服务器端并未注册"MyObject:Tag1"作为节点的字符串ID,自然无法通过该标识定位节点。
解决方案
提供两种可行方案,可根据需求选择:
方案一:修改Python服务器,显式设置变量的字符串NodeId
在创建变量时,手动指定NodeId的字符串标识符为"MyObject:Tag1"格式,让客户端能直接通过该字符串NodeId访问。修改后的Python代码如下:
from opcua import Server from opcua import ua # 创建OPC UA服务器实例 server = Server() server.set_endpoint("opc.tcp://127.0.0.1:4840/freeopcua/server/") # 配置服务器命名空间 uri = "http://example.org" idx = server.register_namespace(uri) print(f"ns= {idx} value={uri}.") # 在地址空间中创建新对象 root = server.nodes.objects.add_object(idx, "MyObject") # 创建带自定义字符串NodeId的变量节点 variables = { "Tag1": root.add_variable(ua.NodeId(f"MyObject:Tag1", idx), "Tag1", 0.0), "Tag2": root.add_variable(ua.NodeId(f"MyObject:Tag2", idx), "Tag2", 0.0), "Tag3": root.add_variable(ua.NodeId(f"MyObject:Tag3", idx), "Tag3", 0.0), } for var in variables.values(): var.set_writable() # 允许写入权限 var.set_modelling_rule(True) print(f"Variable '{var}' fully qualified name: {var.nodeid.to_string()}") # 启动服务器 server.start()
修改后,服务器输出的NodeId会变为ns=2;s=MyObject:Tag1这类格式,客户端即可直接通过该字符串NodeId访问节点。
方案二:在C#客户端通过BrowsePath访问层级节点
若不想修改服务器代码,可利用OPC UA的BrowsePath功能,通过对象与变量的层级路径查找节点,而非依赖自定义字符串NodeId。以下是C#客户端示例代码:
using Opc.Ua; using Opc.Ua.Client; // 假设已完成客户端连接,session为已建立的Session实例 int namespaceIndex = 2; // 需与Python服务器输出的idx值一致,若索引动态变化可通过session.GetNamespaceUris()获取 NodeId rootNodeId = Objects.ObjectsNodeId; // 构建层级路径的BrowsePath BrowsePath browsePath = new BrowsePath( rootNodeId, new RelativePathElement[] { new RelativePathElement( NodeClass.Object, new QualifiedName("MyObject", namespaceIndex), false ), new RelativePathElement( NodeClass.Variable, new QualifiedName("Tag1", namespaceIndex), false ) } ); // 执行路径查找 BrowsePathResult result = session.BrowsePath(browsePath); if (result.StatusCode == StatusCodes.Good && result.Targets.Length > 0) { NodeId tagNodeId = result.Targets[0].TargetId as NodeId; // 读取节点值 DataValue value = session.ReadValue(tagNodeId); Console.WriteLine($"Tag1当前值:{value.Value}"); // 创建订阅并监听值变化 Subscription subscription = new Subscription(session.DefaultSubscription) { PublishingInterval = 1000, Enabled = true }; MonitoredItem monitoredItem = new MonitoredItem(subscription.DefaultItem) { StartNodeId = tagNodeId, AttributeId = Attributes.Value }; monitoredItem.Notification += (sender, e) => { MonitoredItemNotification notification = e.NotificationValue as MonitoredItemNotification; Console.WriteLine($"Tag1更新值:{notification.Value.Value}"); }; subscription.AddItem(monitoredItem); session.AddSubscription(subscription); subscription.Create(); } else { Console.WriteLine($"节点查找失败:{result.StatusCode}"); }
内容的提问来源于stack exchange,提问作者Kiran
相关产品推荐
相关产品推荐

