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

如何用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 12:37:33