Laden...

Wie baue ich einen OPC Client in C#

Erstellt von thetrock vor 4 Jahren Letzter Beitrag vor 4 Jahren 6.879 Views
T
thetrock Themenstarter:in
15 Beiträge seit 2019
vor 4 Jahren
Wie baue ich einen OPC Client in C#

Hallo Zusammen,

ich muss einen OPC UA Client in C# programmieren.

Leider komm ich mit den Samples nicht so gut klar.

Kann hier jemand mich unterstützen bzw. eine detailierte Anleitung nennen?

Mti einem fertigen "Client" komme ich schon auf den SErver drauf.

Aber wie ich jetzt starten soll bei der programmierung habe ich keinen Plan, bei dem Thema OPC.

Vorallem in Bezug welche spezielle DLL muss eingebunden werden.

Was benötige ich genau für Aufbau der Verbindung. usw.

Hab bis jetzt nur "kleine" Änderungen oder ganz einfache Programme in C# gelöst. Komme aus der SPS Programmierung.

Danke

thetrock

1.696 Beiträge seit 2006
vor 4 Jahren

Hallo,

auf Github sind einige Lib und Examples, vielleicht hilft dir das.

Ich bin verantwortlich für das, was ich sage, nicht für das, was du verstehst.

**:::

T
thetrock Themenstarter:in
15 Beiträge seit 2019
vor 4 Jahren

Hi vbprogger,

danke für die schnelle Antwort.

Ich komm mit dem Samples/Lib nicht so gut zurecht,

weiß nicht was genau ich da einnbinden muss oder auch nicht.

Bräuchte am besten Info, welche Lib/Sample wie eingesetz wird und dann wie die Befehle implementiert werden müssen.

T
thetrock Themenstarter:in
15 Beiträge seit 2019
vor 4 Jahren

Hi hab jetzt von

https://github.com/convertersystems/...App/Program.cs

den Code benutzt.

wie kann ich jetzt auf Variablen genau zugreifen?

Hab folgende nodeid ns=3;s="DbInfo"."Parameter"."Station1"

16.806 Beiträge seit 2008
vor 4 Jahren

Dein Link geht nicht; und da https://github.com/convertersystems viele Samples hat weiß hier keiner, welches Du meinst.

Aber im Zweifel einfach das Repo Clonen und die Projekte / Solutions in Visual Studio laden.
Ich habe in der Vergangenheit mehrfach genau diesen GitHub User für/in OPC UA Schulungen verwendet / gezeigt.
Daher kann ich Dir aus Erfahrung sagen: das Zeug läuft und lief auch ohne Probleme bei den Schulungsteilnehmern.

T
2.219 Beiträge seit 2008
vor 4 Jahren

@Abt
Kurzer Durchflug durch die Repositories, würde ich folgenden Link vermuten.

Sample

T-Virus

Developer, Developer, Developer, Developer....

99 little bugs in the code, 99 little bugs. Take one down, patch it around, 117 little bugs in the code.

16.806 Beiträge seit 2008
vor 4 Jahren

Bezogen auf das Beispiel verlinkt von T-Virus bekommt man alle Informationen der Anfrage im browseRequest Objekt vom Typ BrowseResponse (ähnlich wie es bei HTTP eben HttpResponse verhält).
Ganz normales Service Behavior-Verhalten.

Was versendet wird sieht man in https://github.com/convertersystems/opc-ua-samples/tree/master/RobotServer

T
thetrock Themenstarter:in
15 Beiträge seit 2019
vor 4 Jahren

Hallo zusammen,

Hier die Anfrage an den Server


                        browseRequest = new BrowseRequest
                        { 
                            NodesToBrowse = new BrowseDescription[] { new BrowseDescription { NodeId = ExpandedNodeId.ToNodeId(rd2.NodeId, channel.NamespaceUris), BrowseDirection = BrowseDirection.Forward, ReferenceTypeId = NodeId.Parse(ReferenceTypeIds.HierarchicalReferences), NodeClassMask = (uint)NodeClass.Variable | (uint)NodeClass.Object | (uint)NodeClass.Method, IncludeSubtypes = true, ResultMask = (uint)BrowseResultMask.All } },
                        };
                       
                        browseResponse = await channel.BrowseAsync(browseRequest);
                        foreach (var rd3 in browseResponse.Results[0].References ?? new ReferenceDescription[0])

wie kann ich rd2.NodeId ersetzten?

Was bewirkt die Zeilte (sieh unten) genau?



                        browseResponse = await channel.BrowseAsync(browseRequest);
                        foreach (var rd3 in browseResponse.Results[0].References ?? new ReferenceDescription[0])
16.806 Beiträge seit 2008
vor 4 Jahren

wie kann ich rd2.NodeId ersetzten?

Die Frage ist unklar. Gib halt was anderes an....? 🤔

Was bewirkt die Zeilte (sieh unten) genau?

  1. Request Call
  2. Iterierung (mit Fallback, falls References null sein sollte).
T
thetrock Themenstarter:in
15 Beiträge seit 2019
vor 4 Jahren

Ich hab rd2.NodeID ausgelesen und hier steht

ns=3;s=PLC

wenn ich das dort als string eingebe übersetzt er es nicht.

Wie kann ich jetzt das rd2.NodeID richtig ersetzten???

Als nächstes, wollte ich eine spezielle Variable auslesen. ID ist bekannt.
wie lautet dan dazu der Befehlt.

Gibt es hierfür auch eine Literatur oder ähnliches?

Danke Gruß thetrock

185 Beiträge seit 2005
vor 4 Jahren

Die Node-ID kommt vom Server, die brauchst du auch zur Zuordnung.

Nach dem Browsen solltest du ja alle Node-ID's haben, du gibst ja beim Browsen an, das du auch die Variablen haben möchtest.

Browsen und setzen von Werten sind aber zwei unterschiedliche Dinge.

Normalerweise must du ein Property des OPC-Items setzen.

T
thetrock Themenstarter:in
15 Beiträge seit 2019
vor 4 Jahren

Danke für die schnelle Antwort.

Kann es sein, dass ich gar nicht Browsen muss???

Der Browse Requeste, lässt alle daten darstellen.
soweit verstanden.

Wie kann ich jetzt genau eine spezielles Objet darstellen

ID

ns=3;s="DbTest"."Test".Data1

bzw. muss ich ein Objetk anlegen mit der ID und kann dann auf die einzelenen Attribute zugrefein (NodeClass, BrowseName,Value, ...)

wie kann ich rd2.NodeId ersetzten?

konnte jetzt ersetz werden

NodeId.Parse("ns=3;s=PLC")
185 Beiträge seit 2005
vor 4 Jahren

Wenn du die Node-ID kennst must du nicht zwangsweise browsen.
Du must die Items, die du benötigst, beim Server abonieren, damit bekommst du die Wertänderungen.
Wenn der Server ein Schreiben des Wertes zulässt, kannst du dann auch den Wert ändern.

T
thetrock Themenstarter:in
15 Beiträge seit 2019
vor 4 Jahren

Hier wird das Abo erstellt

Console.WriteLine("Step 5 - Create a subscription.");
                    var subscriptionRequest = new CreateSubscriptionRequest
                    {
                        RequestedPublishingInterval = 1000,
                        RequestedMaxKeepAliveCount = 10,
                        RequestedLifetimeCount = 30,
                        PublishingEnabled = true
                    };
                    var subscriptionResponse = await channel.CreateSubscriptionAsync(subscriptionRequest);
                    var id = subscriptionResponse.SubscriptionId;

JEtzt muss ich nur noch die Variablen/Items dem Abo hinzufügen.

Console.WriteLine("Step 6 - Add items to the subscription.");
                    var itemsToCreate = new MonitoredItemCreateRequest[]
   {
                                      new MonitoredItemCreateRequest { ItemToMonitor = new ReadValueId { NodeId = NodeId.Parse("ns=3;s=SerialNumber"), AttributeId = AttributeIds.Value }, MonitoringMode = MonitoringMode.Reporting, RequestedParameters = new MonitoringParameters { ClientHandle = 12345, SamplingInterval = -1, QueueSize = 0, DiscardOldest = true } }
                                    

                };
                    var itemsRequest = new CreateMonitoredItemsRequest
                    {
                        SubscriptionId =  id,
                        ItemsToCreate = itemsToCreate,
                    };
                    var itemsResponse = await channel.CreateMonitoredItemsAsync(itemsRequest);

Den Part verstehe ich nur noch nicht.

Wenn ich die NodeID hier eingebe bekomme ich keine Output raus

T
thetrock Themenstarter:in
15 Beiträge seit 2019
vor 4 Jahren
Console.WriteLine("Step 7 - Subscribe to PublishResponse stream."); 
122                 var token = channel.Where(pr => pr.SubscriptionId == id).Subscribe(pr => 
123                 { 
124                     // loop thru all the data change notifications 
125                     var dcns = pr.NotificationMessage.NotificationData.OfType<DataChangeNotification>(); 
126                     foreach (var dcn in dcns) 
127                     { 
128                         foreach (var min in dcn.MonitoredItems) 
129                         { 
130                             Console.WriteLine($"sub: {pr.SubscriptionId}; handle: {min.ClientHandle}; value: {min.Value}"); 
131                         } 
132                     } 
133                 }); 

So, jetzt bekomme ich schon ein Value zurück.

aber wenn meine node ID wiefolgt aussieht

ns=3;s="DbMachineConfiguration"."Parameter"."Bedienung"

bringt er mir ein Fehler, da ja mehrere Strings sind.

Daher meine Frage wie kann ich das lösen und wie kann ich mehrere Items anlegen um das Value und Name auszulesen zu können.

185 Beiträge seit 2005
vor 4 Jahren

die NodeID ist die "Adresse" des OPC Items.
Hier hast du Strings, die NodeID kann aber auch ein INT oder eine GUID sein.

Das Item hat dann verschiedene Properties.
Ein Property ist "Value", wo der Wert drin steht.

T
thetrock Themenstarter:in
15 Beiträge seit 2019
vor 4 Jahren

Das ansprechen via NodeId funktioniert für ns=3;s=DeviceManual

aber wenn ich andere Daten auslesen will, ist hat die NodeId wiefolgt

ns=3;s="DbMachineConfiguration"."Parameter"."Bedienung"

aber das geht ja nicht, da es mehrer Strings sind.

Wie kann ich das lösen?

Kann es sein, das bei dem Sample ich nicht so viele Attribute auslesen kann?

185 Beiträge seit 2005
vor 4 Jahren

ns=3;s="DbMachineConfiguration"."Parameter"."Bedienung"

aber das geht ja nicht, da es mehrer Strings sind.

Warum mehrere Strings?
" ist einfach ein Zeichen mehr nicht.

T
thetrock Themenstarter:in
15 Beiträge seit 2019
vor 4 Jahren

Folgender Code geht

NodeId.Parse("ns=3;s=DeviceManual")

Folgender Code geht nicht

NodeId.Parse("ns=3;s="DbMachineConfiguration"."Parameter"."Laser"")

--> aber die NodeID wird mir so angezeigt

185 Beiträge seit 2005
vor 4 Jahren

Was heist geht nicht?

709 Beiträge seit 2008
vor 4 Jahren

Du übernimmst die Anführungszeichen nicht richtig. Die sind Teil des Strings.

T
thetrock Themenstarter:in
15 Beiträge seit 2019
vor 4 Jahren
185 Beiträge seit 2005
vor 4 Jahren

Du must den String richtig zusammenbauen. Das sind aber Grundlagen.


NodeId.Parse("ns=3;s=\"DbMachineConfiguration\".\"Parameter\".\"Laser\"")

T
thetrock Themenstarter:in
15 Beiträge seit 2019
vor 4 Jahren

@MartinH vielen Dank.

Console.WriteLine("Step 6 - Add items to the subscription.");
                    var itemsToCreate = new MonitoredItemCreateRequest[]
                      {
                                      new MonitoredItemCreateRequest { ItemToMonitor = new ReadValueId { NodeId = NodeId.Parse("ns=3;s=\"DbMachineConfiguration\".\"Parameter\".\"Lasertime\"")  , AttributeId = AttributeIds.Value }, MonitoringMode = MonitoringMode.Reporting, RequestedParameters = new MonitoringParameters { ClientHandle = 12345, SamplingInterval = -1, QueueSize = 0, DiscardOldest = true } }
                                           


                     };
                    var itemsRequest = new CreateMonitoredItemsRequest
                    {
                        SubscriptionId =  id,
                        ItemsToCreate = itemsToCreate,
                    };
                    var itemsResponse = await channel.CreateMonitoredItemsAsync(itemsRequest);

                Console.WriteLine("Step 7 - Subscribe to PublishResponse stream.");
                        var token = channel.Where(pr => pr.SubscriptionId == id).Subscribe(pr =>
                             {
                                    // loop thru all the data change notifications 
                    var dcns = pr.NotificationMessage.NotificationData.OfType<DataChangeNotification>();
                                     foreach (var dcn in dcns)
                                            {
                                                foreach (var min in dcn.MonitoredItems)
                                                  {
                                                       
                                                      Console.WriteLine($" value: {min.Value}");
                                                   }
                                            }
                                  });

Jetzt stellt sich mir die Frage, wo ich mehrer Imtes anlegen kann fürs auslesen?

185 Beiträge seit 2005
vor 4 Jahren

Das kann ich dir auch nicht sagen, ich kenne die LIB nicht.
Ich arbeite da mit den Softing Toolkits.

T
thetrock Themenstarter:in
15 Beiträge seit 2019
vor 4 Jahren

Kann hier noch jemand weiterhelfen ´mit der LIB

bzw. kennt jemand einen guten opensource LIB mit Beschreibung?

16.806 Beiträge seit 2008
vor 4 Jahren

Der Quellcode ist doch offen.
Wenn die Dokumentation nicht ausreicht, dann schau Dir den Quellcode an.

Alternativ den Entwickler fragen und auf Antwort hoffen.

T
thetrock Themenstarter:in
15 Beiträge seit 2019
vor 4 Jahren

Hab leider zu der Lib keine Dokumentation gefunden.

Wenn es so leicht wäre, würde ich hier nicht fragen.

Vielleicht kann trotzdem jemand mir noch weiterhelfen

Jetzt stellt sich mir die Frage, wo ich mehrer Imtes anlegen kann fürs auslesen?

Gruß thetrock

185 Beiträge seit 2005
vor 4 Jahren

Das hast du doch da:


 var itemsToCreate = new MonitoredItemCreateRequest[]
                      {
                                      new MonitoredItemCreateRequest { ItemToMonitor = new ReadValueId { NodeId = NodeId.Parse("ns=3;s=\"DbMachineConfiguration\".\"Parameter\".\"Lasertime\"")  , AttributeId = AttributeIds.Value }, MonitoringMode = MonitoringMode.Reporting, RequestedParameters = new MonitoringParameters { ClientHandle = 12345, SamplingInterval = -1, QueueSize = 0, DiscardOldest = true } }
                                           

da MonitoredItemCreateRequest ein Array ist, kannst du doch da einfach mehrere Items anlegen.

T
thetrock Themenstarter:in
15 Beiträge seit 2019
vor 4 Jahren

Items anlegen hat funktioniert.

Leider kann ich nur den Inhalt der Variable auslesen, wie kann ich auf weiter Eigentschaften zugreifen?

Wie schaut der Vorgang aus, wenn ich den Wert verändern will.

Sollte das mit dem auslesen begrenzt sein, kann jemand eine ander LIB empfehlen.

thetrock