【OPC UA】C# 通过OpcUaHelper建立OPC客户端访问KEPServerEx6 OPC服务器数据

这篇具有很好参考价值的文章主要介绍了【OPC UA】C# 通过OpcUaHelper建立OPC客户端访问KEPServerEx6 OPC服务器数据。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

OpcUaHelper

一个通用的opc ua客户端类库,基于.net 4.6.1创建,基于官方opc ua基金会跨平台库创建,封装了节点读写,批量节点读写,引用读取,特性读取,历史数据读取,方法调用,节点订阅,批量订阅等操作。还提供了一个节点浏览器工具。

KEPServerEX

第三方的OPC服务器,各不同厂家多种设备下位PLC与上位机之间通讯。KEPServerEX是行业领先的通信平台,用于向您的所有应用程序提供单一来源的工业自动化数据。该平台的设计使用户能够通过一个直观的用户界面来连接、管理、监视和控制不同的自动化设备和软件应用程序。KEPServerEX 利用 OPC(自动化行业的互操作性标准)和以 IT 为中心的通信协议(如 SNMP、ODBC 和 Web 服务)为用户提供单一来源的工业数据。要开始使用,只需下载 KEPServerEX,然后从Kepware 的包含 150 多个设备驱动程序、客户端驱动程序和高级选项的库中进行选择,以满足您独特的工业控制系统需求。

以下基于开源的OpcUaHelper自带的demo,修改了界面,测试了部分功能。

【OPC UA】C# 通过OpcUaHelper建立OPC客户端访问KEPServerEx6 OPC服务器数据

【OPC UA】C# 通过OpcUaHelper建立OPC客户端访问KEPServerEx6 OPC服务器数据主界面

C# 通过OPC UA 访问KEPServerEx6 演示视频

部分代码:

//同步读取
        private void button1_Click( object sender, EventArgs e )
        {
           
            if (cbo函数Nodeid.Text=="")
            {
                return;
            }
            DataValue dataValue = m_OpcUaClient.ReadNode( new NodeId(cbo函数Nodeid.Text ) );
            if (dataValue.WrappedValue.Value != null)
            {
                txtvalue.Text = dataValue.WrappedValue.Value.ToString();
            }
            //test();
        }
//单节点订阅
        private void button2_Click( object sender, EventArgs e )
        {
            // sub
            m_OpcUaClient.AddSubscription( "A", textBox4.Text, SubCallback );
        }
        //取消订阅 关键字A
        private void button3_Click( object sender, EventArgs e )
        {
            // remove sub
            m_OpcUaClient.RemoveSubscription( "A" );
        }
        //订阅回调
        private void SubCallback(string key, MonitoredItem monitoredItem, MonitoredItemNotificationEventArgs args )
        {
            if (InvokeRequired)
            {
                Invoke( new Action<string, MonitoredItem, MonitoredItemNotificationEventArgs>( SubCallback ), key, monitoredItem, args );
                return;
            }


            if (key == "A")
            {
                // 如果有多个的订阅值都关联了当前的方法,可以通过key和monitoredItem来区分
                MonitoredItemNotification notification = args.NotificationValue as MonitoredItemNotification;
                if (notification != null)
                {
                    textBox3.Text = notification.Value.WrappedValue.Value.ToString( );
                }
            }
            else if(key == "B")
            {
                // 需要区分出来每个不同的节点信息
                MonitoredItemNotification notification = args.NotificationValue as MonitoredItemNotification;
                if (monitoredItem.StartNodeId.ToString( ) == MonitorNodeTags[0])
                {
                    textBox5.Text = notification.Value.WrappedValue.Value.ToString( );
                }
                else if (monitoredItem.StartNodeId.ToString( ) == MonitorNodeTags[1])
                {
                    textBox9.Text = notification.Value.WrappedValue.Value.ToString( );
                }
                else if (monitoredItem.StartNodeId.ToString( ) == MonitorNodeTags[2])
                {
                    textBox10.Text = notification.Value.WrappedValue.Value.ToString( );
                }
            }
        }
// 缓存的批量订阅的节点
        private string[] MonitorNodeTags = null;
        //多节点订阅
        private void button5_Click( object sender, EventArgs e )
        {
            // 多个节点的订阅
            MonitorNodeTags = new string[]
            {
                textBox6.Text,
                textBox7.Text,
                textBox8.Text,
            };
            m_OpcUaClient.AddSubscription( "B", MonitorNodeTags, SubCallback );
        }
        //取消订阅    
        private void button4_Click( object sender, EventArgs e )
        {
            // 取消多个节点的订阅
            m_OpcUaClient.RemoveSubscription( "B" );//关键字 B
        }
//异步读取节点
        private async void buttonReadNodeAsync_Click(object sender, EventArgs e)
        {
            Opc.Ua.DataValue value = m_OpcUaClient.ReadNode(cboNodeid.Text);//SelectedItem.ToString()
            if (value.Value == null)
            {
                return;
            }
            // 一个数据的类型是不是数组由 value.WrappedValue.TypeInfo.ValueRank 来决定的
            // -1 说明是一个数值
            // 1  说明是一维数组,如果类型BuiltInType是Int32,那么实际是int[]
            // 2  说明是二维数组,如果类型BuiltInType是Int32,那么实际是int[,]
            if (value.WrappedValue.TypeInfo.BuiltInType == Opc.Ua.BuiltInType.Int32)
            {
                if (value.WrappedValue.TypeInfo.ValueRank == -1)
                {
                    int temp = (int)value.WrappedValue.Value;               // 最终值
                    txtvalue.Text = temp.ToString();
                }
                else if (value.WrappedValue.TypeInfo.ValueRank == 1)
                {
                    int[] temp = (int[])value.WrappedValue.Value;           // 最终值
                    txtvalue.Text = temp.ToString();
                }
                else if (value.WrappedValue.TypeInfo.ValueRank == 2)
                {
                    int[,] temp = (int[,])value.WrappedValue.Value;         // 最终值
                    txtvalue.Text = temp.ToString();
                }
            }
            else if (value.WrappedValue.TypeInfo.BuiltInType == Opc.Ua.BuiltInType.UInt32)
            {
                uint temp = (uint)value.WrappedValue.Value;                 // 数组的情况参照上面的例子
                txtvalue.Text = temp.ToString();
            }
            else if (value.WrappedValue.TypeInfo.BuiltInType == Opc.Ua.BuiltInType.Float)
            {
                float temp = (float)value.WrappedValue.Value;               // 数组的情况参照上面的例子
                txtvalue.Text = temp.ToString();
            }
            else if (value.WrappedValue.TypeInfo.BuiltInType == Opc.Ua.BuiltInType.String)
            {
                string temp = (string)value.WrappedValue.Value;             // 数组的情况参照上面的例子
                txtvalue.Text = temp.ToString();
            }
            else if (value.WrappedValue.TypeInfo.BuiltInType == Opc.Ua.BuiltInType.DateTime)
            {
                DateTime temp = (DateTime)value.WrappedValue.Value;         // 数组的情况参照上面的例子
                txtvalue.Text = temp.ToString();
            }
            else if (value.WrappedValue.TypeInfo.BuiltInType == Opc.Ua.BuiltInType.Int16)
            {
                short temp = (short)value.WrappedValue.Value;         // 数组的情况参照上面的例子
                txtvalue.Text = temp.ToString();
            }
            else if (value.WrappedValue.TypeInfo.BuiltInType == Opc.Ua.BuiltInType.Double)
            {
                double temp = (double)value.WrappedValue.Value;         // 数组的情况参照上面的例子
                txtvalue.Text = temp.ToString();
            }
        }
//浏览节点引用
        private void buttonBrowseNodeReference_Click(object sender, EventArgs e)
        {
            richTextBox1.Clear();
            try
            {
                //ReferenceDescription[] references = m_OpcUaClient.BrowseNodeReference("ns=2;s=Devices.分厂一.车间二.ModbusTcp客户端");
                ReferenceDescription[] references = m_OpcUaClient.BrowseNodeReference(comboBox1.SelectedItem.ToString());
                richTextBox1.AppendText(string.Format("{0,-30}", "NodeClass")+ string.Format("{0,-30}","BrowseName")+ string.Format("{0,-40}","DisplayName")+ string.Format("{0,-40}","NodeId")+"\r\n");
                foreach (var item in references)
                {
                    Console.Write(string.Format("{0,-30}", item.NodeClass));
                    Console.Write(string.Format("{0,-30}", item.BrowseName));
                    Console.Write(string.Format("{0,-20}", item.DisplayName));
                    Console.WriteLine(string.Format("{0,-20}", item.NodeId.ToString()));
                    /*  string s1 = "中文";
                    string s2 = "语言学English";
                    Console.WriteLine("{0}{1}", padRightEx(s1, 20), "hello");
                    Console.WriteLine("{0}{1}", padRightEx(s2, 20), "hello");*/
                    //richTextBox1.AppendText(string.Format("{0,-30}", item.NodeClass));
                    //richTextBox1.AppendText(string.Format("{0,-30}", item.BrowseName));
                    //richTextBox1.AppendText(string.Format("{0,-20}", item.DisplayName));
                    //richTextBox1.AppendText(string.Format("{0,-20}", item.NodeId.ToString()) + "\r\n");
                    richTextBox1.AppendText(string.Format("{0}{1}{2}{3}\r\n", padRightEx(item.NodeClass.ToString().Trim(), 30), padRightEx(item.BrowseName.ToString().TrimStart(), 40), padRightEx(item.DisplayName.ToString().TrimStart(), 40), padRightEx(item.NodeId.ToString().TrimStart(), 100)));
                }


                ;
                // 输出如下
                //  NodeClass                     BrowseName                      DisplayName           NodeId


                //  Variable                      2:温度                          温度                  ns=2;s=Devices/分厂一/车间二/ModbusTcp客户端/温度
                //  Variable                      2:风俗                          风俗                  ns=2;s=Devices/分厂一/车间二/ModbusTcp客户端/风俗
                //  Variable                      2:转速                          转速                  ns=2;s=Devices/分厂一/车间二/ModbusTcp客户端/转速
                //  Variable                      2:机器人关节                    机器人关节            ns=2;s=Devices/分厂一/车间二/ModbusTcp客户端/机器人关节
                //  Variable                      2:cvsdf                         cvsdf                 ns=2;s=Devices/分厂一/车间二/ModbusTcp客户端/cvsdf
                //  Variable                      2:条码                          条码                  ns=2;s=Devices/分厂一/车间二/ModbusTcp客户端/条码
                //  Variable                      2:开关量                        开关量                ns=2;s=Devices/分厂一/车间二/ModbusTcp客户端/开关量
            }
            catch (Exception ex)
            {
                ClientUtils.HandleException(this.Text, ex);
            }
        }
//启用设备属性-操作模式-模拟  可读取节点属性
        private void buttonReadNoteAttributes_Click(object sender, EventArgs e)
        {
            richTextBox1.Clear();
            try
            {
                //OpcNodeAttribute[] nodeAttributes = m_OpcUaClient.ReadNoteAttributes("ns=2;s=Devices.分厂一.车间二.ModbusTcp客户端.温度");
                OpcNodeAttribute[] nodeAttributes = m_OpcUaClient.ReadNoteAttributes(cboNodeid.Text);
                richTextBox1.AppendText(string.Format("{0,-30}", "Name") + string.Format("{0,-40}", "Type") + string.Format("{0,-40}", "StatusCode") + string.Format("{0,-40}", "Value") + "\r\n");
                foreach (var item in nodeAttributes)
                {
                    //Console.Write(string.Format("{0,-30}", item.Name));
                    //Console.Write(string.Format("{0,-20}", item.Type));
                    //Console.Write(string.Format("{0,-20}", item.StatusCode));
                    //Console.WriteLine(string.Format("{0,20}", item.Value));
                    richTextBox1.AppendText(string.Format("{0}{1}{2}{3}\r\n", padRightEx(item.Name.ToString().Trim(), 30), padRightEx(item.Type.ToString().Trim(), 40), padRightEx(item.StatusCode.ToString().Trim(), 40), padRightEx(item.Value.ToString().Trim(), 100)));


                }
//写入操作
        private void buttonWrite_Click(object sender, EventArgs e)
        {
            try
            {
                // 此处演示写入一个short,2个float类型的数据批量写入操作。启用设备模拟后写入成功。但是很快就被模拟的0覆盖
                bool success = m_OpcUaClient.WriteNodes(new string[] {
                    "ns=2;s=Devices.分厂一.车间二.ModbusTcp客户端.温度",
                    "ns=2;s=Devices.分厂一.车间二.ModbusTcp客户端.风俗",
                    "ns=2;s=Devices.分厂一.车间二.ModbusTcp客户端.转速"},
                    new object[] {
                        (short)1234,
                        123.456f,
                        123f
                    });
                //bool success = m_OpcUaClient.WriteNode("ns=2;s=Devices.分厂一.车间二.ModbusTcp客户端.风俗", 123.456f);
                if (success)
                {
                    MessageBox.Show("写入成功!");
                }
                else
                {
                    // 写入失败,一个失败即为失败
                    MessageBox.Show("写入失败!");
                }
            }
            catch (Exception ex)
            {
                ClientUtils.HandleException(this.Text, ex);
            }
        }

参考: 

https://github.com/dathlin/OpcUaHelper

https://opcfoundation.cn/about/opc-technologies/opc-ua/

https://blog.csdn.net/xiaochenXIHUA/article/details/117070003

https://www.cnblogs.com/bgh408/p/10887580.html

https://blog.csdn.net/Vampire_1122/article/details/119025477

https://cloud.tencent.com/developer/article/1899065

https://blog.csdn.net/han_better/article/details/83034023

https://www.douban.com/note/837168906/?_i=61791832R3OOz3

The End文章来源地址https://www.toymoban.com/news/detail-410483.html

到了这里,关于【OPC UA】C# 通过OpcUaHelper建立OPC客户端访问KEPServerEx6 OPC服务器数据的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • SpringBoot集成Milo库实现OPC UA客户端:连接、遍历节点、读取、写入、订阅与批量订阅

    前面我们搭建了一个本地的 PLC 仿真环境,并通过 KEPServerEX6 读取 PLC 上的数据,最后还使用 UAExpert 作为OPC客户端完成从 KEPServerEX6 这个OPC服务器的数据读取与订阅功能。在这篇文章中,我们将通过 SpringBoot 集成 Milo 库实现一个 OPC UA 客户端,包括连接、遍历节点、读取、写入

    2024年02月09日
    浏览(59)
  • 【C#项目实战】OPC_DA客户端开发

    大家好,我是雷工。 之前练习过一个OPC客户端的样例,并总结了博文,记录了C#开发OPC客户端的一些知识: C#学习记录——【实例】C#实现OPC Client 最近看到一个不同的思路开发的OPC DA客户端,开发并测试了下,下面将开发过程记录如下。 开发OPC客户端程序,其访问接口方式

    2024年02月03日
    浏览(37)
  • OPC通信从入门到精通_2_OPC通信详解和C#客户端编程(OPC基础概念;OPC通信仿真(KepServer作为OPC服务器;使用Modbus Slave和另外软件仿真2个PLC设备);C#程序)

    OPC诞生缘由:OPC诞生之前,软件工程师是不了解硬件和协议的 OPC解决的是软件和硬件之间的问题,让软件工程师无需了解协议及底层硬件,例如串口协议等 OPC起到了桥梁的作用:软件工程师对接OPC,OPC对接硬件 OPC是一种通讯方式,落到实处就是一个软件,就需要开发相应的

    2024年02月05日
    浏览(69)
  • C# 中,使用OpcUaHelper读写OPC服务器

    nuget包 帮助类: Winform: KepServer 设置: 结果:

    2024年02月10日
    浏览(36)
  • QT-使用QTcpSocket建立TCP客户端连接

    使用QT的QTcpSocket建立TCP客户端方式,十分的简单,上手也快,代码量不多,并且还自动支持重连接机制,也就是说如果你的服务端突然死机了,然后服务端又重启,那么我们的客户端这个时候是会自动去再连接的,不需要你的程序再做重连接的机制,所以我们应用起来是十分

    2024年02月14日
    浏览(43)
  • TCP/IP客户端和服务器端建立通信过程

    使用Qt提供的类进行基于 TCP 的套接字通信需要用到两个类: QTcpServer 类用于监听客户端连接以及和客户端建立连接,在使用之前先介绍一下这个类提供的一些常用API函数: 构造函数 给监听的套接字设置监听 listen() 函数 在代码中 通过启动监听按钮 设置监听 参数: address :

    2024年02月07日
    浏览(60)
  • 【OPC UA】使用C#读取OPC UA电液控数据

    OPC UA与OPC DA协议常见于工业生产中使用,例如煤矿的综采支架电液控系统。OPC UA 是OPC 的后继标准,只是后面增加了UA ,意指”统一架构”(Unified Architecture).它的主要目的是摆脱windows! 实现与平台无关的OPC.从OPC 演进到OPC UA,它的目的并没有改变,依然是为了实现分布式控制系统中

    2024年02月15日
    浏览(39)
  • AI对话交互场景使用WebSocket建立H5客户端和服务端的信息实时双向通信

    WebSocket使得客户端和服务器之间的数据交换变得更加简单,允许 服务端主动向客户端推送数据 。在WebSocket API中,浏览器和服务器只需要完成一次握手,两者之间就可以创建持久性的连接,并进行双向数据传输。 初次接触 WebSocket 的人,都会问同样的问题:我们已经有了 HT

    2024年02月03日
    浏览(47)
  • (学习笔记-TCP连接断开)建立了连接,但是客户端或服务端出现问题,会怎么样?

    客户端出现故障指的是客户端的主机发生了宕机或者断电的场景。发生这种情况的时候,如果服务端一直不会发送数据给客户端,那么服务端是永远无法感知到客户端宕机这件事的,也就是服务端的TCP连接将一直处于 ESTABLISH 状态,占用着资源。 为了避免这种情况,TCP有一个

    2024年02月16日
    浏览(43)
  • C# Socket编程(服务端、客户端)

    1.最直白的Socket代码 服务端 客户端 2.封装过有点绕的Socket代码 服务端 客户端 3.GitHub代码 https://github.com/harrylsp/AndroidADBDriver

    2024年02月16日
    浏览(43)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包