基于C#.NETFramework从Kepware OPC UA服务器获取树结构及读取标签求助
简洁实现OPC UA节点树导入TreeView与标签定时读取(.NET Framework + Kepware)
依赖准备
- 安装NuGet包:
OPCFoundation.NetStandard.Opc.Ua(兼容.NET Framework 4.6.1及以上版本)
1. 连接OPC UA服务器并填充TreeView
核心通过递归遍历OPC UA节点树,将节点同步到WinForms的TreeView控件中,同时处理UI线程同步避免跨线程异常。
代码实现
using Opc.Ua; using Opc.Ua.Client; using System.Windows.Forms; public class OpcUaTreeHelper { private Session _session; private TreeView _treeView; public OpcUaTreeHelper(TreeView treeView) { _treeView = treeView; } // 连接Kepware OPC UA服务器 public async Task ConnectAsync(string endpointUrl) { var endpoint = new ConfiguredEndpoint(null, new EndpointDescription(endpointUrl)); // Kepware默认安全模式为None,可根据实际配置调整 endpoint.SecurityMode = MessageSecurityMode.None; endpoint.SecurityPolicyUri = SecurityPolicies.None; _session = await Session.Create( new ApplicationConfiguration(), endpoint, false, "", 60000, new UserIdentity(new AnonymousIdentityToken()), null); // 从根节点开始遍历填充TreeView await PopulateTreeViewAsync(_session.NodeCache.RootNode, _treeView.Nodes); } // 递归遍历节点并添加到TreeView private async Task PopulateTreeViewAsync(Node node, TreeNodeCollection parentNodes) { var treeNode = new TreeNode(node.DisplayName.Text) { Tag = node.NodeId }; // 跨线程更新UI控件 _treeView.Invoke((Action)(() => parentNodes.Add(treeNode))); // 遍历子节点(筛选变量和对象类型节点,跳过系统冗余节点) var browseResult = await _session.BrowseAsync( null, null, node.NodeId, 0u, BrowseDirection.Forward, ReferenceTypeIds.HierarchicalReferences, true, (uint)NodeClass.Variable | (uint)NodeClass.Object); foreach (var reference in browseResult.References) { var childNode = await _session.ReadNodeAsync(reference.NodeId); if (childNode != null) { await PopulateTreeViewAsync(childNode, treeNode.Nodes); } } } }
窗体中调用示例
private async void Form_Load(object sender, EventArgs e) { var helper = new OpcUaTreeHelper(treeView1); // 替换为你的Kepware OPC UA服务器地址,默认端口49320 await helper.ConnectAsync("opc.tcp://localhost:49320"); }
2. 定时读取指定标签并记录日志
使用WinForms Timer实现每分钟读取逻辑,通过OPC UA的ReadAsync方法获取标签值,追加到日志文件中。
代码实现
private Session _opcSession; private Timer _readTimer; // 初始化定时任务 private void InitReadTimer() { _readTimer = new Timer { Interval = 60000 }; // 60秒间隔 _readTimer.Tick += ReadTagsAndLog; _readTimer.Start(); } // 读取标签并写入日志 private async void ReadTagsAndLog(object sender, EventArgs e) { if (_opcSession == null || !_opcSession.Connected) return; // 替换为需要读取的标签NodeId,可从TreeView节点的Tag属性获取 var targetTagIds = new NodeId[] { new NodeId("ns=2;s=Channel1.Device1.Pressure"), new NodeId("ns=2;s=Channel1.Device1.Temperature") }; try { var readResults = await _opcSession.ReadAsync( null, 0, TimestampsToReturn.Both, targetTagIds.Select(id => new ReadValueId { NodeId = id }).ToArray()); // 构造日志内容 var logLine = $"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] "; foreach (var result in readResults) { logLine += result.StatusCode.IsGood ? $"{result.NodeId}: {result.Value} " : $"{result.NodeId}: 读取失败({result.StatusCode}) "; } // 追加到日志文件 File.AppendAllText("opc_tag_log.txt", logLine + Environment.NewLine); } catch (Exception ex) { File.AppendAllText("opc_tag_log.txt", $"[{DateTime.Now}] 读取异常: {ex.Message}" + Environment.NewLine); } }
关键注意事项
- Kepware的OPC UA节点Id格式:通常为
ns=2;s=ChannelName.DeviceName.TagName,ns=2为用户命名空间,可在Kepware配置中确认。 - 权限配置:确保Kepware OPC UA服务器允许匿名访问,或配置对应用户身份信息。
- 资源释放:程序退出时需断开OPC会话,避免资源泄漏:
await _session.CloseAsync();
内容的提问来源于stack exchange,提问作者Mert Atmaca
相关产品推荐
相关产品推荐

