日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

OPC UA简介

發(fā)布時間:2023/12/18 编程问答 44 豆豆
生活随笔 收集整理的這篇文章主要介紹了 OPC UA简介 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

OPC是應(yīng)用于工業(yè)通信的,在windows環(huán)境的下一種通訊技術(shù),原有的通信技術(shù)難以滿足日益復(fù)雜的環(huán)境,在可擴(kuò)展性,安全性,跨平臺性方面的不足日益明顯,所以O(shè)PC基金會在幾年前提出了面向未來的架構(gòu)設(shè)計的OPC 統(tǒng)一架構(gòu),簡稱OPC UA,截止目前為止,越來越多公司將OPC UA作為開放的數(shù)據(jù)標(biāo)準(zhǔn),在未來工業(yè)4.0行業(yè)上也將大放異彩。

?

在OPC UA的服務(wù)器端。會公開一些數(shù)據(jù)節(jié)點,或是方法等信息,允許第三方使用標(biāo)準(zhǔn)的OPC協(xié)議來進(jìn)行訪問,在傳輸層已經(jīng)安全的處理所有的消息,對于客戶端的訪問來說,應(yīng)該是非常清楚簡單的。

?

本篇文章是講述如何開發(fā)C#的OPC UA客戶端的方式,關(guān)于如何開發(fā)OPC UA可配置的服務(wù)器,請參照另一篇博客:http://www.cnblogs.com/dathlin/p/8976955.html?這篇博客講述了如何創(chuàng)建基于三菱,西門子,歐姆龍,ModbusTcp客戶端,異形ModbusTcp客戶端的OPC UA服務(wù)器引擎。

聯(lián)系作者及加群方式(激活碼在群里發(fā)放):http://www.hslcommunication.cn/Cooperation

2.0版本說明


2018年8月18日 20:09:24 ?基于OPC UA的最新官方庫,重新調(diào)整了訂閱的代碼實現(xiàn),開源地址:https://github.com/dathlin/OpcUaHelper?除了組件的源代碼之外,還包含了一個服務(wù)器的示例,就是下面的的示例操作。

更加詳細(xì)的代碼說明可以參照GitHub上的readme文件

前期準(zhǔn)備


準(zhǔn)備好開發(fā)的IDE,首選Visual Studio2017版本,新建項目,或是在你原有的項目上進(jìn)行擴(kuò)展。注意:項目的.NET Framework版本最低為4.6

打開NuGet管理器,輸入指令(如果不明白,參考http://www.cnblogs.com/dathlin/p/7705014.html):

1

Install-Package OpcUaHelper

或者:

然后在窗體的界面新增引用:

1

using?OpcUaHelper;

接下就可以愉快碼代碼了。

?

?

OPC UA服務(wù)器準(zhǔn)備


此處有一個供網(wǎng)友測試的服務(wù)器:opc.tcp://118.24.36.220:62547/DataAccessServer

當(dāng)然,一般的網(wǎng)友都會使用Kepware軟件,在此處介紹一個我自己開發(fā)的OPC UA網(wǎng)關(guān)服務(wù)器,支持三菱,西門子,歐姆龍,modbustcp客戶端轉(zhuǎn)化成OPC UA服務(wù)器,支持創(chuàng)建modbus服務(wù)器,異形服務(wù)器,地址是

https://github.com/dathlin/SharpNodeSettings

?

節(jié)點瀏覽器


我們在得到一個OPC UA的服務(wù)器之后,第一件事就是使用節(jié)點瀏覽器對所有的節(jié)點進(jìn)行訪問,不然你根本就不知道服務(wù)器公開了什么東西,此處我使用了一個測試服務(wù)器,該地址為云端地址,不保證以后會不會繼續(xù)支持訪問,目前來說還是可以訪問的。

比如這個地址:opc.tcp://118.24.36.220:62547/DataAccessServer

OK,然后我們可以使用代碼來顯示這個服務(wù)器到底有什么數(shù)據(jù)了!在窗體上新增一個按鈕,雙擊它進(jìn)入點擊事件,寫上

1

2

3

4

5

6

7

private?void?button1_Click(object?sender, EventArgs e)

{

????using?(FormBrowseServer form =?new?FormBrowseServer())

????{

????????form.ShowDialog();

????}

}

然后就會顯示如下的界面:在地址欄輸入上述地址,點擊連接(此處能連接上的條件是服務(wù)器配置為允許匿名登錄):

?

左邊區(qū)域可以隨便點擊看看,可以看到所有公開的數(shù)據(jù),比如點擊一個數(shù)據(jù)節(jié)點,下面圖片中的Name節(jié)點,右邊編輯框會顯示該節(jié)點的ID標(biāo)識,這個標(biāo)識很重要,關(guān)系到等會的讀寫操作。

客戶端實例化


?

1

2

3

4

5

6

7

8

9

10

11

private?OpcUaClient opcUaClient =?new?OpcUaClient();

?

private?async?void?Form1_Load(object?sender, EventArgs e)

{

????await opcUaClient.ConnectServer("opc.tcp://118.24.36.220:62547/DataAccessServer");

}

?

private?void?Form1_FormClosing(object?sender, FormClosingEventArgs e)

{

????opcUaClient.Disconnect();

}

如上所示,在窗體載入的時候?qū)嵗?#xff0c;在窗體關(guān)閉的時候斷開連接。下面的節(jié)點操作和其他操作使用的實例都是這個opcUaClient,如果你連接的服務(wù)器是需要用戶名和密碼的,那么修改Load中的代碼如下:

1

2

3

private?async?void?Form1_Load(object?sender, EventArgs e)

????????{

????????????opcUaClient.UserIdentity =?new?Opc.Ua.UserIdentity("admin",?"123456");

1

await opcUaClient.ConnectServer("opc.tcp://118.24.36.220:62547/DataAccessServer");

1

}

  

節(jié)點讀取操作


我們要讀取一個節(jié)點數(shù)據(jù),有兩個信息是必須知道的

  • 節(jié)點的ID標(biāo)識,就是在上述節(jié)點瀏覽器中的編輯框的信息("ns=2;s=Machines/Machine A/Name")
  • 節(jié)點的數(shù)據(jù)類型,這個是必須知道的,不然也不好讀取數(shù)據(jù)。(“string”)

上面的兩個信息都可以通過節(jié)點瀏覽器來獲取到信息,現(xiàn)在,我們已經(jīng)獲取到了這兩個信息,就上面的括號里的數(shù)據(jù),然后我們在新增一個按鈕,來讀取數(shù)據(jù):

1

2

3

4

5

6

7

8

9

10

11

12

13

private?void?button2_Click(object?sender, EventArgs e)

{

????try

????{

????????string?value = opcUaClient.ReadNode<string>("ns=2;s=Machines/Machine A/Name");

????????MessageBox.Show(value);?// 顯示測試數(shù)據(jù)

????}

????catch(Exception ex)

????{

????????// 使用了opc ua的錯誤處理機(jī)制來處理錯誤,網(wǎng)絡(luò)不通或是讀取拒絕

????????ClientUtils.HandleException(Text, ex);

????}

}

可以看到,真正的讀取數(shù)據(jù)的操作只有一行代碼,但是此處展示了一個良好的編程習(xí)慣,使用try..catch..,關(guān)于錯誤捕獲的使用以后會專門開篇文章講解。在展示一個讀取float數(shù)據(jù)類型的示例

1

2

3

4

5

6

7

8

9

10

11

12

13

private?void?button2_Click(object?sender, EventArgs e)

{

????try

????{

????????float?value = opcUaClient.ReadNode<float>("ns=2;s=Machines/Machine B/TestValueFloat");

????????MessageBox.Show(value.ToString());?// 顯示100.5

????}

????catch(Exception ex)

????{

????????// 使用了opc ua的錯誤處理機(jī)制來處理錯誤,網(wǎng)絡(luò)不通或是讀取拒絕

????????ClientUtils.HandleException(Text, ex);

????}

}

其他的類型參照這種寫法就行,哪怕是數(shù)組類型也是沒有關(guān)系的。

類型未知節(jié)點讀取操作


我們要讀取一個節(jié)點數(shù)據(jù),假設(shè)我們只知道一個節(jié)點的ID,或者說這個節(jié)點的類型是可能變化的,那么我們需要讀取到值的同時讀取到這個數(shù)據(jù)的類型,那么代碼參照下面

  • 節(jié)點的ID標(biāo)識,就是在上述節(jié)點瀏覽器中的編輯

節(jié)點的數(shù)據(jù)類型最終由 value.WrappedValue.TypeInfo 來決定,有兩個屬性,是否是數(shù)組和基礎(chǔ)類型,下面的代碼只有int類型進(jìn)行了嚴(yán)格的數(shù)組判斷,其他類型參照即可。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

????private?void?button3_Click(object?sender, EventArgs e)

????{

????????Opc.Ua.DataValue value = opcUaClient.ReadNode("ns=2;s=Robots/RobotA/RobotMode");

????????// 一個數(shù)據(jù)的類型是不是數(shù)組由 value.WrappedValue.TypeInfo.ValueRank 來決定的

????????// -1 說明是一個數(shù)值

????????// 1? 說明是一維數(shù)組,如果類型BuiltInType是Int32,那么實際是int[]

????????// 2? 說明是二維數(shù)組,如果類型BuiltInType是Int32,那么實際是int[,]

????????if?(value.WrappedValue.TypeInfo.BuiltInType == Opc.Ua.BuiltInType.Int32)

????????{

????????????if?(value.WrappedValue.TypeInfo.ValueRank == -1)

????????????{

????????????????int?temp = (int)value.WrappedValue.Value;???????????????// 最終值

????????????}

????????????else?if?(value.WrappedValue.TypeInfo.ValueRank == 1)

????????????{

????????????????int[] temp = (int[])value.WrappedValue.Value;???????????// 最終值

????????????}

????????????else?if?(value.WrappedValue.TypeInfo.ValueRank == 2)

????????????{

????????????????int[,] temp = (int[,])value.WrappedValue.Value;?????????// 最終值

????????????}

????????}

????????else?if(value.WrappedValue.TypeInfo.BuiltInType == Opc.Ua.BuiltInType.UInt32)

????????{

????????????uint?temp = (uint)value.WrappedValue.Value;?????????????????// 數(shù)組的情況參照上面的例子

????????}

????????else?if?(value.WrappedValue.TypeInfo.BuiltInType == Opc.Ua.BuiltInType.Float)

????????{

????????????float?temp = (float)value.WrappedValue.Value;???????????????// 數(shù)組的情況參照上面的例子

????????}

????????else?if?(value.WrappedValue.TypeInfo.BuiltInType == Opc.Ua.BuiltInType.String)

????????{

????????????string?temp = (string)value.WrappedValue.Value;?????????????// 數(shù)組的情況參照上面的例子

????????}

????????else?if?(value.WrappedValue.TypeInfo.BuiltInType == Opc.Ua.BuiltInType.DateTime)

????????{

????????????DateTime temp = (DateTime)value.WrappedValue.Value;?????????// 數(shù)組的情況參照上面的例子

????????}

????}

}

?

批量節(jié)點讀取操作


批量讀取節(jié)點時,有個麻煩之處在于類型不一定都是一致的,所以為了支持更加廣泛的讀取操作,只提供Opc.Ua.DataValue的讀取,讀取到數(shù)據(jù)后需要自己做一些轉(zhuǎn)換,根據(jù)類型來自己轉(zhuǎn),參照上面類型未知的節(jié)點操作代碼。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

try

{

????// 添加所有的讀取的節(jié)點,此處的示例是類型不一致的情況

????List<NodeId> nodeIds =?new?List<NodeId>( );

????nodeIds.Add(?new?NodeId(?"ns=2;s=Devices/分廠一/車間二/ModbusTcp客戶端/溫度"?) );

????nodeIds.Add(?new?NodeId(?"ns=2;s=Devices/分廠一/車間二/ModbusTcp客戶端/風(fēng)俗"?) );

????nodeIds.Add(?new?NodeId(?"ns=2;s=Devices/分廠一/車間二/ModbusTcp客戶端/轉(zhuǎn)速"?) );

????nodeIds.Add(?new?NodeId(?"ns=2;s=Devices/分廠一/車間二/ModbusTcp客戶端/機(jī)器人關(guān)節(jié)"?) );

????nodeIds.Add(?new?NodeId(?"ns=2;s=Devices/分廠一/車間二/ModbusTcp客戶端/cvsdf"?) );

????nodeIds.Add(?new?NodeId(?"ns=2;s=Devices/分廠一/車間二/ModbusTcp客戶端/條碼"?) );

????nodeIds.Add(?new?NodeId(?"ns=2;s=Devices/分廠一/車間二/ModbusTcp客戶端/開關(guān)量"?) );

?

????// dataValues按順序定義的值,每個值里面需要重新判斷類型

????List<DataValue> dataValues = opcUaClient.ReadNodes( nodeIds.ToArray() );

????// 然后遍歷你的數(shù)據(jù)信息

????foreach?(var?dataValue?in?dataValues)

????{

????????// 獲取你的實際的數(shù)據(jù)

????????object?value = dataValue.WrappedValue.Value;

????}

?

?

?

?

????// 如果你批量讀取的值的類型都是一樣的,比如float,那么有簡便的方式

????List<string> tags =?new?List<string>( );

????tags.Add(?"ns=2;s=Devices/分廠一/車間二/ModbusTcp客戶端/風(fēng)俗"?);

????tags.Add(?"ns=2;s=Devices/分廠一/車間二/ModbusTcp客戶端/轉(zhuǎn)速"?);

?

????// 按照順序定義的值

????List<float> values = opcUaClient.ReadNodes<float>( tags.ToArray() );

?

}

catch?(Exception ex)

{

????ClientUtils.HandleException(?this.Text, ex );

}

  

?

?

節(jié)點寫入操作


?

節(jié)點的寫入操作和讀取類似,我們還是必須要先知道節(jié)點的ID和數(shù)據(jù)類型,和讀取最大的區(qū)別是,寫入的操作很有可能會失敗,因為服務(wù)器對于數(shù)據(jù)的輸入都是很敏感的,這部分權(quán)限肯定會控制的,也就是很有可能會發(fā)生寫入拒絕,此處的測試服務(wù)器允許寫入,下面舉例在Name節(jié)點寫入“abcd測試寫入啊”信息:

1

2

3

4

5

6

7

8

9

10

11

12

13

private?void?button3_Click(object?sender, EventArgs e)

{

????try

????{

????????bool?IsSuccess = opcUaClient.WriteNode("ns=2;s=Machines/Machine B/Name","abcd測試寫入啊");

????????MessageBox.Show(IsSuccess.ToString());?// 顯示True,如果成功的話

????}

????catch(Exception ex)

????{

????????// 使用了opc ua的錯誤處理機(jī)制來處理錯誤,網(wǎng)絡(luò)不通或是讀取拒絕

????????ClientUtils.HandleException(Text, ex);

????}

}

再寫個例子,寫入Float數(shù)據(jù)

1

2

3

4

5

6

7

8

9

10

11

12

13

private?void?button3_Click(object?sender, EventArgs e)

{

????try

????{

????????bool?IsSuccess = opcUaClient.WriteNode("ns=2;s=Machines/Machine B/TestValueFloat",123.456f);

????????MessageBox.Show(IsSuccess.ToString());?// 顯示True,如果成功的話

????}

????catch(Exception ex)

????{

????????// 使用了opc ua的錯誤處理機(jī)制來處理錯誤,網(wǎng)絡(luò)不通或是讀取拒絕

????????ClientUtils.HandleException(Text, ex);

????}

}

要想查看是否真的寫入,可以使用節(jié)點數(shù)據(jù)瀏覽器來查看是否真的寫入。

批量節(jié)點寫入操作


?寫入節(jié)點操作時,類型并不一定是統(tǒng)一的,所以此處提供統(tǒng)一的object數(shù)組寫入,需要注意,對應(yīng)的節(jié)點名稱和值的類型必須一致!

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

private?void?button5_Click(object?sender, EventArgs e)

{

????// 批量寫入的代碼

????string[] nodes =?new?string[]

????{

????????"ns=2;s=Robots/RobotA/RobotMode",

????????"ns=2;s=Robots/RobotA/UserFloat"

????};

????object[] data =?new?object[]

????{

????????4,

????????new?float[]{5,3,1,5,7,8}

????};

?

????// 都成功返回True,否則返回False

????bool?result = opcUaClient.WriteNodes(nodes, data);

}

?

數(shù)據(jù)訂閱


下面舉例說明訂閱ns=2;s=Machines/Machine B/TestValueFloat的數(shù)據(jù),我們假設(shè)這個在服務(wù)器上是不斷變化的,按照如下的方式進(jìn)行數(shù)據(jù)訂閱:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

private?void?button2_Click(?object?sender, EventArgs e )

{

????// sub

????OpcUaClient.AddSubscription(?"A",?"ns=2;s=Machines/Machine B/TestValueFloat", SubCallback );

}

?

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")

????{

????????// 如果有多個的訂閱值都關(guān)聯(lián)了當(dāng)前的方法,可以通過key和monitoredItem來區(qū)分

????????MonitoredItemNotification notification = args.NotificationValue?as?MonitoredItemNotification;

????????if?(notification !=?null)

????????{

????????????textBox3.Text = notification.Value.WrappedValue.Value.ToString( );

????????}

????}

}

移除訂閱

1

OpcUaClient.RemoveSubscription(?"A"?);

  

批量訂閱的方式,參照源代碼或是 github的說明文件。

?

?

  

方法調(diào)用


?

有些OPC 服務(wù)器會提供方法調(diào)用,測試服務(wù)器提供了一個方法,它支持兩個int參數(shù)輸入,string參數(shù)輸出,方法節(jié)點為:ns=2;s=Machines/Machine B/Calculate

我們接下來看看調(diào)用服務(wù)器的方法到底返回了什么?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

private?void?button6_Click(object?sender, EventArgs e)

{

????try

????{

????????string?value = opcUaClient.CallMethodByNodeId("ns=2;s=Machines/Machine B",

????????????"ns=2;s=Machines/Machine B/Calculate", 123, 456)[0].ToString();

????????MessageBox.Show(value);// 顯示:我也不知道剛剛發(fā)生了什么,調(diào)用設(shè)備為:Machine B

????}

????catch(Exception ex)

????{

????????// 使用了opc ua的錯誤處理機(jī)制來處理錯誤,網(wǎng)絡(luò)不通或是讀取拒絕

????????ClientUtils.HandleException(Text, ex);

????}

}

我們在調(diào)用方法的時候需要傳入方法的父節(jié)點 ID,以及方法的ID,必須先清楚方法的傳入?yún)?shù)和傳出參數(shù)才能對應(yīng)的代碼。

日志輸出


OPC UA客戶端在運行時會輸出一大堆的日志,容量會增加的比較快,是否需要配置,請謹(jǐn)慎處理,如果真的有需要,按照下面的配置方式來完成

1

2

3

4

5

private?void?button5_Click(object?sender, EventArgs e)

{

????// False 代表每次啟動清空日志,True代碼不清空,注意,該日志大小增加非???/p>

????opcUaClient.SetLogPathName(Application.StartupPath +?"\\Logs\\opc.ua.client.txt",?false);

}

上述的都是一些最常用的方法了,已經(jīng)可以應(yīng)付大多數(shù)的需求,該客戶端類還提供了一些連接啟動事件,斷開事件等等,可以滿足額外的需求。

?

引用讀取


這種情況比較少,比如服務(wù)器端有個MachineB節(jié)點,下面放了一些數(shù)據(jù),如果客戶端把讀取的節(jié)點寫死一般問題也不大,應(yīng)該服務(wù)器很少會改變,但是服務(wù)器真的改變了呢。。。。比如在MachineB下追加了一個數(shù)據(jù),這種情況確實很少,但是對于我們寫成相對動態(tài)的情況來說,就很有必要,但是中間問題很多,因為新增的節(jié)點類型你是不知道的,ID也是不知道的,所以還先要讀取引用,然后在讀取數(shù)據(jù),然后在判斷類型,進(jìn)行相應(yīng)的轉(zhuǎn)化。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

private?void?button6_Click(object?sender, EventArgs e)

{

????try

????{

????????Opc.Ua.ReferenceDescription[] reference = opcUaClient.BrowseNodeReference("ns=2;s=Machines/Machine B");

?

????????foreach?(var?refer?in?reference)

????????{

????????????// 如果不是值節(jié)點,就不要了,否則下面讀取了也是沒有意義的

????????????if?(refer.NodeClass != NodeClass.Variable)

????????????{

????????????????continue;

????????????}

?????????????

?

????????????// 分別讀取數(shù)據(jù)

????????????Opc.Ua.DataValue dataValue = opcUaClient.ReadNode((Opc.Ua.NodeId)refer.NodeId);

????????????if?(dataValue.WrappedValue.TypeInfo.BuiltInType == Opc.Ua.BuiltInType.Boolean)

????????????{

????????????????// 讀取到的是bool數(shù)據(jù),在這里做處理

????????????????bool?value = (bool)dataValue.WrappedValue.Value;

????????????}

????????????else?if?(dataValue.WrappedValue.TypeInfo.BuiltInType == Opc.Ua.BuiltInType.String)

????????????{

????????????????// 讀取到的是string字符串,在這里做處理

????????????????string?value = dataValue.WrappedValue.Value.ToString();

????????????}

????????}

????}

????catch?(Exception ex)

????{

????????// 使用了opc ua的錯誤處理機(jī)制來處理錯誤,網(wǎng)絡(luò)不通或是讀取拒絕

????????ClientUtils.HandleException(Text, ex);

????}

}

?

異步操作


?

在讀取寫入單個節(jié)點的功能中,提供了一個異步版本,用來方便的進(jìn)行異步操作

1

2

3

4

5

6

7

8

9

10

11

12

13

private?async?void?button2_Click(object?sender, EventArgs e)

{

????try

????{

????????float?value = await opcUaClient.ReadNodeAsync<float>("ns=2;s=Machines/Machine B/TestValueFloat");

????????MessageBox.Show(value.ToString());?// 顯示100.5

????}

????catch(Exception ex)

????{

????????// 使用了opc ua的錯誤處理機(jī)制來處理錯誤,網(wǎng)絡(luò)不通或是讀取拒絕

????????ClientUtils.HandleException(Text, ex);

????}

}

1

2

3

4

5

6

7

8

9

10

11

12

13

private?async?void?button3_Click(object?sender, EventArgs e)

{

????try

????{

????????bool?IsSuccess = await opcUaClient.WriteNodeAsync("ns=2;s=Machines/Machine B/TestValueFloat",123.456f);

????????MessageBox.Show(IsSuccess.ToString());?// 顯示True,如果成功的話

????}

????catch(Exception ex)

????{

????????// 使用了opc ua的錯誤處理機(jī)制來處理錯誤,網(wǎng)絡(luò)不通或是讀取拒絕

????????ClientUtils.HandleException(Text, ex);

????}

}

  

?

查看本地以注冊的服務(wù)器


利用官方的控件庫來實現(xiàn)的一個操作,允許查看本地的已經(jīng)注冊的服務(wù)器。

1

2

3

4

5

6

7

8

9

10

11

12

private?void?button6_Click(?object?sender, EventArgs e )

{

????// 獲取本機(jī)已經(jīng)注冊的服務(wù)器地址

????string?endpointUrl =?new?Opc.Ua.Client.Controls.DiscoverServerDlg( ).ShowDialog( opcUaClient.AppConfig,?null?);

????// 獲取其他服務(wù)器注冊的地址,注意,需要該IP的安全策略配置正確

????// string endpointUrl = new Opc.Ua.Client.Controls.DiscoverServerDlg( ).ShowDialog( opcUaClient.AppConfig, "192.168.0.100" );

?

????if?(!string.IsNullOrEmpty( endpointUrl ))

????{

????????// 獲取到的需要操作的服務(wù)器地址

????}

}

?

?

觸發(fā)事件


本opc ua客戶端類,包含了幾個常用的事件,現(xiàn)在進(jìn)行說明:

  • ConnectComplete 事件:在第一次連接到服務(wù)器完成的時候觸發(fā)
  • ReconnectStarting 事件:開始重新連接到服務(wù)器的時候觸發(fā)
  • ReconnectComplete 事件:重新連接到服務(wù)器的時候觸發(fā)
  • KeepAliveComplete 事件:因為opc ua客戶端每隔5秒會與服務(wù)器進(jìn)行通訊驗證,每次驗證都會觸發(fā)該方法
  • OpcStatusChange 事件:本OPC UA客戶端的終極事件,當(dāng)客戶端的狀態(tài)變更都會觸發(fā),包括了連接,重連,斷開,狀態(tài)激活,opc ua的狀態(tài)等等

事件類的完整代碼如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

/// <summary>

/// 狀態(tài)通知的消息類

/// </summary>

public?class?OpcUaStatusEventArgs : EventArgs

{

????/// <summary>

????/// 是否異常

????/// </summary>

????public?bool?Error {?get;?set; }

????/// <summary>

????/// 時間

????/// </summary>

????public?DateTime Time {?get;?set; }

????/// <summary>

????/// 文本

????/// </summary>

????public?string?Text {?get;?set; }

?

????/// <summary>

????/// 轉(zhuǎn)化為字符串

????/// </summary>

????/// <returns></returns>

????public?override?string?ToString()

????{

????????return?Error ??"[異常]"?:?"[正常]"?+ Time.ToString("? yyyy-MM-dd HH:mm:ss? ") + Text;

????}

}

?

獲取客戶端網(wǎng)絡(luò)是否正常有個屬性

1

2

3

4

5

6

7

/// <summary>

/// Indicate the connect status

/// </summary>

public?bool?Connected

{

????get?{?return?m_IsConnected; }

}

?

?

特別說明


雖然提供了刪除一個節(jié)點和新增一個節(jié)點的方法,但是在客戶端是不允許操作的,調(diào)用無效。

創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎勵來咯,堅持創(chuàng)作打卡瓜分現(xiàn)金大獎

總結(jié)

以上是生活随笔為你收集整理的OPC UA简介的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。