找回密码
 立即注册

QQ登录

只需一步,快速开始

工控课堂 首页 工控文库 上位机编程 查看内容

基于OPCUA客户端上位机编写

2022-2-20 14:58| 发布者: gk-auto| 查看: 826| 评论: 11|原作者: gk-auto

摘要: 一、简介前面写过使用自动化接口进行OPCDA的客户端编写,但是OPCDA是基于COM/DCOM的技术,如果服务器与客户端不在同一台电脑上配置较为复杂;基于COM/DCOM的技术有着不可根除的缺点,因此随着技术的进步,以及数据交 ...
一、简介
前面写过使用自动化接口进行OPCDA的客户端编写,但是OPCDA是基于COM/DCOM的技术,如果服务器与客户端不在同一台电脑上配置较为复杂;基于COM/DCOM的技术有着不可根除的缺点,因此随着技术的进步,以及数据交换各方面需求的提高,OPC基金会在2008年发布了新的规范:OPC UA。OPC UA规范不再是基于COM/DCOM技术,因此OPC UA不仅能在Windows平台上实现,更可以在Linux,以及其他的嵌入式平台中实现。
与传统OPC规范相同,OPC UA同样有着相同的设计目标:1.功能等价:所有的基于COM的OPC规范中的功能,都映射到了OPC UA中。2. 多平台支持:支持从嵌入式的微控制器到基于云的分散式控制架构。3.安全:信息加密,互访认证以及安全监听功能。4.扩展性:不影响现有应用程序的情况下,就可以添加新的功能。5.丰富的信息建模:可定义复杂的信息,而不再是单一的数据。
二、OPCUA服务器配置
本次OPCUA服务器依然使用KEPServerEX 6,配置如下:
1、在托盘找到KEPServerEX 6图标,右键弹出菜单,点击OPCUA配置






2、在弹出的配置界面进行如下图的配置:






3、打开KEPServerEX 6主界面,右键点击项目,选择属性,进行配置如下,即完成OPCUA服务器配置;






三、软件编写:
1、软件实现节点浏览,添加订阅,移除订阅,清空订阅的功能,演示界面如下:




2、本次代码实现主要基于OPC UA的最新官方库二次封装的一个类库:OpcUaHelper.dll,开源地址:
https://github.com/dathlin/OpcUaHelper;准备好开发的IDE,新建项目。注意:项目的.NET Framework版本最低为4.6。打开NuGet管理器,引用OpcUaHelper;






3、代码编写:
<1> 建立连接
private void button1_Click(object sender, EventArgs e)
{
opcUaClient.UserIdentity = new UserIdentity(new AnonymousIdentityToken());
opcUaClient.ConnectServer(textBox1.Text);
PopulateBranch(ObjectIds.ObjectsFolder, treeView1.Nodes);
}
<2>节点浏览
private async void PopulateBranch(NodeId sourceId, TreeNodeCollection nodes)
{
odes.Clear();
nodes.Add(new TreeNode("Browsering..."));
// fetch references from the server.
TreeNode[] listNode = await Task.Run(() =>
{
ReferenceDescriptionCollection references = GetReferenceDescriptionCollection(sourceId);
List<TreeNode> list = new List<TreeNode>();
if (references != null)
{
// process results.
for (int ii = 0; ii < references.Count; ii++)
{
ReferenceDescription target = references[ii];
TreeNode child = new TreeNode(Utils.Format("{0}", target));
child.Tag = target;
child.Nodes.Add(new TreeNode());
list.Add(child);
}
}
return list.ToArray();
});
//更新显示的属性
// DisplayAttributes(sourceId);
nodes.Clear();
nodes.AddRange(listNode.ToArray());
}
private ReferenceDescriptionCollection GetReferenceDescriptionCollection(NodeId sourceId)
{
//TaskCompletionSource<ReferenceDescriptionCollection> task = new TaskCompletionSource<ReferenceDescriptionCollection>();
// 找到所有组件的节点
BrowseDescription nodeToBrowse1 = new BrowseDescription();
nodeToBrowse1.NodeId = sourceId;
nodeToBrowse1.BrowseDirection = BrowseDirection.Forward;
nodeToBrowse1.ReferenceTypeId = ReferenceTypeIds.Aggregates;
nodeToBrowse1.IncludeSubtypes = true;
nodeToBrowse1.NodeClassMask = (uint)(NodeClass.Object | NodeClass.Variable | NodeClass.Method | NodeClass.ReferenceType | NodeClass.ObjectType | NodeClass.View | NodeClass.VariableType | NodeClass.DataType);
nodeToBrowse1.ResultMask = (uint)BrowseResultMask.All;
// 找到所有节点组织的节点.
BrowseDescription nodeToBrowse2 = new BrowseDescription();
nodeToBrowse2.NodeId = sourceId;
nodeToBrowse2.BrowseDirection = BrowseDirection.Forward;
nodeToBrowse2.ReferenceTypeId = ReferenceTypeIds.Organizes;
nodeToBrowse2.IncludeSubtypes = true;
nodeToBrowse2.NodeClassMask = (uint)(NodeClass.Object | NodeClass.Variable | NodeClass.Method | NodeClass.View | NodeClass.ReferenceType | NodeClass.ObjectType | NodeClass.VariableType | NodeClass.DataType);
nodeToBrowse2.ResultMask = (uint)BrowseResultMask.All;
BrowseDescriptionCollection nodesToBrowse = new BrowseDescriptionCollection();
nodesToBrowse.Add(nodeToBrowse1);
nodesToBrowse.Add(nodeToBrowse2);
// 从服务器获取引用
ReferenceDescriptionCollection references = FormUtils.Browse(opcUaClient.Session, nodesToBrowse, false);
return references;
}
private void treeView1_BeforeExpand(object sender, TreeViewCancelEventArgs e)
{
try
{
// check if node has already been expanded once.
if (e.Node.Nodes.Count != 1)
{
return;
}
if (e.Node.Nodes.Count > 0)
{
if (e.Node.Nodes[0].Text != String.Empty)
{
return;
}
}
// get the source for the node.得到的源节点
ReferenceDescription reference = e.Node.Tag as ReferenceDescription;
if (reference == null || reference.NodeId.IsAbsolute)
{
e.Cancel = true;
return;
}
// populate children.
PopulateBranch((NodeId)reference.NodeId, e.Node.Nodes);
}
catch (Exception exception)
{
ClientUtils.HandleException(this.Text, exception);
}
}
<3>、完整代码较长,如需要完整代码可先关注并留言,然后私信我发送“OPCUA”即可自动回复,如果能帮助到你,感谢你的关注订阅,可以第一时间接收后续更新。





[groupid=83]工控上位机学习[/groupid]
关注公众号,加入500人微信群,下载100G免费资料!
发表评论

最新评论

引用 LZY11 2025-2-7 09:49
求客户端源码
引用 lzffzl 2025-11-13 07:03
来凑个热闹,增加点人气~
引用 王海涛 2025-11-13 09:40
同款经历!简直是世另我
引用 大浪淘沙 2025-11-13 19:01
救命!这波发言太秀了,直接原地封神~
疯狂认同!楼主说出了我不敢说的话
引用 陈记顺和 2025-11-20 15:26
谁懂啊!真的被戳中笑点 / 泪点了
引用 gfdhd 2025-11-21 07:32
水个经验,楼主加油,支持你~
引用 artcontrol 2025-11-21 07:50
这评论区卧虎藏龙,个个都是人才!
引用 mzf971011 2025-11-21 07:54
浅蹲一个后续,楼主更新踢我一下
引用 xmj825936 2025-11-21 07:55
我先占个楼,等下再慢慢看~
引用 zhaiboxin8 2025-11-21 07:58
笑不活了,评论区比正文还精彩
已转发给朋友,一起快乐一下
引用 杨鹏飞 2025-11-21 08:00
这波反向操作,我属实没想到!

查看全部评论(11)

热门文章
关闭

站长推荐上一条 /1 下一条

QQ|手机版|免责声明|本站介绍|工控课堂 ( 沪ICP备20008691号-1 )

GMT+8, 2025-12-23 07:25 , Processed in 0.306323 second(s), 29 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

返回顶部