OpcUaHelper的基本使用
-
FromBrowseServer
使用此窗口服务可以查看服务器的节点状态。
1 OpcUaHelper.Forms.FormBrowseServer formBrowseServer = new Forms.FormBrowseServer( );
2 formBrowseServer.ShowDialog( );
当然你可以固定住这个地址,传入地址即可,此处为示例:
1 OpcUaHelper.Forms.FormBrowseServer formBrowseServer = new Forms.FormBrowseServer( "opc.tcp://127.0.0.1:62541/SharpNodeSettings/OpcUaServer" );
2 formBrowseServer.ShowDialog( );
-
OPC UA Client
-
实例化操作
1 OpcUaClient m_OpcUaClient = new OpcUaClient();
-
设置匿名连接
1 m_OpcUaClient.UserIdentity = new UserIdentity( new AnonymousIdentityToken( ) );
-
设置用户名连接
1 m_OpcUaClient.UserIdentity = new UserIdentity( "user", "password" );
-
使用证书连接
1 X509Certificate2 certificate = new X509Certificate2( "[证书的路径]", "[密钥]", X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.Exportable ); 2 m_OpcUaClient.UserIdentity = new UserIdentity( certificate );
-
正式开始连接服务器,连接操作必须放在Try中,异步执行。
1 private async void button1_Click( object sender, EventArgs e ) 2 { 3 // connect to server, this is a sample 4 try 5 { 6 await m_OpcUaClient.ConnectServer( "opc.tcp://127.0.0.1:62541/SharpNodeSettings/OpcUaServer" ); 7 } 8 catch (Exception ex) 9 { 10 ClientUtils.HandleException( "Connected Failed", ex ); 11 } 12 }
-
Read/Write Node
-
节点字符设为
1 ns=2;s=Devices/分厂一/车间二/ModbusTcp客户端/温度
-
类型为int16,使用下面方法读取
1 try 2 { 3 short value = m_OpcUaClient.ReadNode<short>( "ns=2;s=Devices/分厂一/车间二/ModbusTcp客户端/温度" ); 4 } 5 catch(Exception ex) 6 { 7 ClientUtils.HandleException( this.Text, ex ); 8 }
-
异步读取
1 try 2 { 3 short value = await m_OpcUaClient.ReadNodeAsync<short>( "ns=2;s=Devices/分厂一/车间二/ModbusTcp客户端/温度" ); 4 } 5 catch (Exception ex) 6 { 7 ClientUtils.HandleException( this.Text, ex ); 8 }
-
写入节点
1 try 2 { 3 m_OpcUaClient.WriteNode( "ns=2;s=Devices/分厂一/车间二/ModbusTcp客户端/温度", (short)123 ); 4 } 5 catch (Exception ex) 6 { 7 ClientUtils.HandleException( this.Text, ex ); 8 }
-
批量读取(类型一致)
1 try 2 { 3 // 如果你批量读取的值的类型都是一样的,比如float,那么有简便的方式 4 List<string> tags = new List<string>( ); 5 tags.Add( "ns=2;s=Devices/分厂一/车间二/ModbusTcp客户端/风俗" ); 6 tags.Add( "ns=2;s=Devices/分厂一/车间二/ModbusTcp客户端/转速" ); 7 8 // 按照顺序定义的值 9 List<float> values = m_OpcUaClient.ReadNodes<float>( tags.ToArray() ); 10 11 } 12 catch (Exception ex) 13 { 14 ClientUtils.HandleException( this.Text, ex ); 15 }
-
批量读取(类型不一致)
1 try 2 { 3 // 添加所有的读取的节点,此处的示例是类型不一致的情况 4 List<NodeId> nodeIds = new List<NodeId>( ); 5 nodeIds.Add( new NodeId( "ns=2;s=Devices/分厂一/车间二/ModbusTcp客户端/温度" ) ); 6 nodeIds.Add( new NodeId( "ns=2;s=Devices/分厂一/车间二/ModbusTcp客户端/风俗" ) ); 7 nodeIds.Add( new NodeId( "ns=2;s=Devices/分厂一/车间二/ModbusTcp客户端/转速" ) ); 8 nodeIds.Add( new NodeId( "ns=2;s=Devices/分厂一/车间二/ModbusTcp客户端/机器人关节" ) ); 9 nodeIds.Add( new NodeId( "ns=2;s=Devices/分厂一/车间二/ModbusTcp客户端/cvsdf" ) ); 10 nodeIds.Add( new NodeId( "ns=2;s=Devices/分厂一/车间二/ModbusTcp客户端/条码" ) ); 11 nodeIds.Add( new NodeId( "ns=2;s=Devices/分厂一/车间二/ModbusTcp客户端/开关量" ) ); 12 13 // dataValues按顺序定义的值,每个值里面需要重新判断类型 14 List<DataValue> dataValues = m_OpcUaClient.ReadNodes( nodeIds.ToArray() ); 15 16 17 } 18 catch (Exception ex) 19 { 20 ClientUtils.HandleException( this.Text, ex ); 21 }
-
批量写入
1 try 2 { 3 // 此处演示写入一个short,2个float类型的数据批量写入操作 4 bool success = m_OpcUaClient.WriteNodes( new string[] { 5 "ns=2;s=Devices/分厂一/车间二/ModbusTcp客户端/温度", 6 "ns=2;s=Devices/分厂一/车间二/ModbusTcp客户端/风俗", 7 "ns=2;s=Devices/分厂一/车间二/ModbusTcp客户端/转速"}, 8 new object[] { 9 (short)1234, 10 123.456f, 11 123f 12 } ); 13 if (success) 14 { 15 // 写入成功 16 } 17 else 18 { 19 // 写入失败,一个失败即为失败 20 } 21 } 22 catch (Exception ex) 23 { 24 ClientUtils.HandleException( this.Text, ex ); 25 }
-
读取Attrubute
1 try 2 { 3 OpcNodeAttribute[] nodeAttributes = m_OpcUaClient.ReadNoteAttributes( "ns=2;s=Devices/分厂一/车间二/ModbusTcp客户端/温度" ); 4 foreach (var item in nodeAttributes) 5 { 6 Console.Write( string.Format( "{0,-30}", item.Name ) ); 7 Console.Write( string.Format( "{0,-20}", item.Type ) ); 8 Console.Write( string.Format( "{0,-20}", item.StatusCode ) ); 9 Console.WriteLine( string.Format( "{0,20}", item.Value ) ); 10 } 11 12 // 输出如下 13 // Name Type StatusCode Vlaue 14 15 // NodeClass Int32 Good 2 16 // BrowseName QualifiedName Good 2:温度 17 // DisplayName LocalizedText Good 温度 18 // Description LocalizedText Good 19 // WriteMask UInt32 Good 96 20 // UserWriteMask UInt32 Good 96 21 // Value Int16 Good -11980 22 // DataType NodeId Good i=4 23 // ValueRank Int32 Good -1 24 // ArrayDimensions Null Good 25 // AccessLevel Byte Good 3 26 // UserAccessLevel Byte Good 3 27 // MinimumSamplingInterval Double Good 0 28 // Historizing Boolean Good False 29 } 30 catch (Exception ex) 31 { 32 ClientUtils.HandleException( this.Text, ex ); 33 }
-
读取Reference
1 try 2 { 3 ReferenceDescription[] references = m_OpcUaClient.BrowseNodeReference( "ns=2;s=Devices/分厂一/车间二/ModbusTcp客户端" ); 4 foreach (var item in references) 5 { 6 Console.Write( string.Format( "{0,-30}", item.NodeClass ) ); 7 Console.Write( string.Format( "{0,-30}", item.BrowseName ) ); 8 Console.Write( string.Format( "{0,-20}", item.DisplayName ) ); 9 Console.WriteLine( string.Format( "{0,-20}", item.NodeId.ToString( ) ) ); 10 } 11 12 ; 13 // 输出如下 14 // NodeClass BrowseName DisplayName NodeId 15 16 // Variable 2:温度 温度 ns=2;s=Devices/分厂一/车间二/ModbusTcp客户端/温度 17 // Variable 2:风俗 风俗 ns=2;s=Devices/分厂一/车间二/ModbusTcp客户端/风俗 18 // Variable 2:转速 转速 ns=2;s=Devices/分厂一/车间二/ModbusTcp客户端/转速 19 // Variable 2:机器人关节 机器人关节 ns=2;s=Devices/分厂一/车间二/ModbusTcp客户端/机器人关节 20 // Variable 2:cvsdf cvsdf ns=2;s=Devices/分厂一/车间二/ModbusTcp客户端/cvsdf 21 // Variable 2:条码 条码 ns=2;s=Devices/分厂一/车间二/ModbusTcp客户端/条码 22 // Variable 2:开关量 开关量 ns=2;s=Devices/分厂一/车间二/ModbusTcp客户端/开关量 23 } 24 catch (Exception ex) 25 { 26 ClientUtils.HandleException( this.Text, ex ); 27 }
-
订阅(单节点订阅)
1 m_OpcUaClient.AddSubscription( "A", "ns=2;s=Devices/分厂一/车间二/ModbusTcp客户端/温度", SubCallback );
关键字A是自定义的,方便回调判断或是取消订阅用的,方法SubCallback是一个回调方法:
1 private void SubCallback(string key, MonitoredItem monitoredItem, MonitoredItemNotificationEventArgs args ) 2 { 3 if (InvokeRequired) 4 { 5 Invoke( new Action<string, MonitoredItem, MonitoredItemNotificationEventArgs>( SubCallback ), key, monitoredItem, args ); 6 return; 7 } 8 9 if (key == "A") 10 { 11 // 如果有多个的订阅值都关联了当前的方法,可以通过key和monitoredItem来区分 12 MonitoredItemNotification notification = args.NotificationValue as MonitoredItemNotification; 13 if (notification != null) 14 { 15 textBox3.Text = notification.Value.WrappedValue.Value.ToString( ); 16 } 17 } 18 }
取消订阅代码如下:
1 m_OpcUaClient.RemoveSubscription( "A" );
-
订阅(批量订阅)
此处举例批量订阅3个点节点,按顺序在 textBox5 , textBox9 , textBox10 文本框按照顺序进行显示,此处比上面的操作需要麻烦一点, 需要缓存下批量订阅的节点信息
1 // 缓存的批量订阅的节点 2 private string[] MonitorNodeTags = null; 3 4 private void button5_Click( object sender, EventArgs e ) 5 { 6 // 多个节点的订阅 7 MonitorNodeTags = new string[] 8 { 9 textBox6.Text, 10 textBox7.Text, 11 textBox8.Text, 12 }; 13 m_OpcUaClient.AddSubscription( "B", MonitorNodeTags, SubCallback ); 14 }
修改上述的回调方法如下:
1 private void SubCallback(string key, MonitoredItem monitoredItem, MonitoredItemNotificationEventArgs args ) 2 { 3 if (InvokeRequired) 4 { 5 Invoke( new Action<string, MonitoredItem, MonitoredItemNotificationEventArgs>( SubCallback ), key, monitoredItem, args ); 6 return; 7 } 8 9 if (key == "A") 10 { 11 // 如果有多个的订阅值都关联了当前的方法,可以通过key和monitoredItem来区分 12 MonitoredItemNotification notification = args.NotificationValue as MonitoredItemNotification; 13 if (notification != null) 14 { 15 textBox3.Text = notification.Value.WrappedValue.Value.ToString( ); 16 } 17 } 18 else if(key == "B") 19 { 20 // 需要区分出来每个不同的节点信息 21 MonitoredItemNotification notification = args.NotificationValue as MonitoredItemNotification; 22 if (monitoredItem.StartNodeId.ToString( ) == MonitorNodeTags[0]) 23 { 24 textBox5.Text = notification.Value.WrappedValue.Value.ToString( ); 25 } 26 else if (monitoredItem.StartNodeId.ToString( ) == MonitorNodeTags[1]) 27 { 28 textBox9.Text = notification.Value.WrappedValue.Value.ToString( ); 29 } 30 else if (monitoredItem.StartNodeId.ToString( ) == MonitorNodeTags[2]) 31 { 32 textBox10.Text = notification.Value.WrappedValue.Value.ToString( ); 33 } 34 } 35 }