Kommunikation
Orientierung
Motivation
Moderne industrielle Kommunikation verwendet Ethernet basierte Protokolle. Aus der Vielzahl der verfügbaren Standards hat sich über die letzten Jahre das Protokoll OPC UA etabliert. Dieses Protokoll entwickelte sich aus dem Vorgänger OPC. Da das Protokoll immer mehr Bedeutung und weitere Verbreitung findet, ist es unabdingbar, sich mit dem Protokoll auseinandersetzen. Die weite Verbreitung hat ebenso den Vorteil, dass für viele Programmiersprachen bereits fertige Bibliotheken existieren.
Lernvoraussetzung
- Kentnisse einer Programmiersprache sind notwendig (C/C++, Python, ...).
- Kentnisse über objektorientiertes Programmieren sind empfohlen, jedoch nicht notwendig.
Lernergebnisse
Nach der Durchführung der Übung sind Sie in der Lage…
- … grundlegend mit dem industriellen Kommunikationsprotokoll OPC UA umzugehen.
- … auszulesen, welche Informationen auf einem Server verfügbar sind.
- … einzelne Informationspunkte gezielt auszulesen.
- … sich bei Änderung von ausgewählten Daten benachrichtigen zu lassen.
- … Funktionen auf dem entfernten Server ausführen zu lassen.
Literaturtipps
- Die Grundlagen im nächsten Abschnitt
- OPC Unified Architecture von Mahnke, Leitner & Damm
Wegweiser durch die Übung
Für die Übung benötigt man zwischen 90 und 120 Minuten.
Die konkrete Dauer hängt hier vom individuellen Lernfortschritt ab.
Folgende Aktivitäten/Tätigkeiten werden von Ihnen erwartet:
- Im Baustein Grundlagen
- erarbeiten der notwendigen Theorie.
- Im Baustein Übung
- lesen Sie sich die Rahmenbedingungen der Übung durch.
- finden Sie bereits fertigen Quellcode in Python als Musterlösung.
- finden Sie wiederkehrende Herausforderungen bei der Kommunikation mit entfernten Rechnern.
- finden Sie verschiedene Fragen um Ihr Wissen abzuprüfen.
- Im Baustein Anwendung
- bekommen Sie verschiedene Aufgaben gestellt.
- Im Baustein Reflexion
- erhalten Sie eine kurze Zusammenfassung der Ergebnisse
Grundlagen
Diese Übung soll die Verwendung eines industriellen Kommunikationsprotokolls näherbringen. Dafür wird das Protokoll OPC UA verwendet. OPC UA bietet viele Möglichkeiten und kann über verschiedene Programmiersprachen angesprochen werden. Folgende Möglichkeiten bietet das Protokoll:
- Datenzugriff auf einem Server
- Ausführen von Prozeduren auf dem Server
- Erstellen von Benachrichtigungen bei Datenänderung
Sie sind nach der Übung in der Lage, mit dem Kommunikationsprotokoll OPC UA einfache Datentransporte zu realisieren. Dadurch können Sie mit einigen der angebotenen Online Live Übungen interagieren.
Nodes und Node-Klassen
OPC UA arbeitet mit Datenpunkten, auch Nodes genannt.
Jeder Node besitzt eine Reihe an Attributen und basierend auf der Nodeklasse noch weitere Informationen:
- Node-ID
- Node-Klasse
- Browse-Name
- Anzeigename
- Beschreibung
Node-IDs
Eine Node-ID besitzt zwei Elemente, einen Namespace und einen Identifier. Der Namespace ist ein numerischer Index, der durch einen URI vorgegeben wird. Der URI bezeichnet eine Institution, die für die Vergabe der Identifier zuständig ist. Der Index ist nichts anderes, als die Position der URI in einer auf dem Server abgelegten Liste. Der Namespace-Index 0 bezeichnet dabei die OPC UA Foundation. Es gibt vier verschiedene Arten von Identifiern:- Numeric
Ein numeric Identifier bezeichnet einfach eine vorzeichenlose Zahl. Bei der Serealisierung dieses Identifiers wird die Bezeichnung i verwendet. - String Bei einem String handelt es sich um eine lesbare Zeichenfolge. Bei der Serealisierung wird der Identifier mit s gekennzeichnet.
- Bytestring (Opaque)
Ein Opaque Identifier ist ein Identifier, der nach einem Namespace-Spezifischen Schema erstellt worden ist. Dieser wird zur Serealisierung in einen Base64-String umgewandelt. Dies ist wichtig, da im Bytestring auch Zeichen vorkommen können, die nicht darstellbar sind. Der verwendete Buchstabe zur Kenzeichnung ist b. - GUID
Eine GUID ist eine 16-Byte hexadezimal Zahl, die im folgenden Format abgebildet ist: uint32-uint16-uint16-uint8[2]-uint8[6] Ein Beispiel für eine GUID ist 9EAA3455-92B1-C9C6-89C8-2CA23723B2EB.
Indentifier | Identifier-Type | Beispiel |
---|---|---|
Numeric | i | ns=0;i=85 |
String | s | ns=1;s=Temperatur |
Bytestring | b | ns=1;b=M/RbKBsRVkePCePcx24oRA== |
GUID | g | ns=1;g=9EAA3455-92B1-C9C6-89C8-2CA23723B2EB |
Node-Klassen
Die Nodeklassen definieren, welche zusätzlichen Informationen verfügbar sind.-
Object
Ein Object, zu Deutsch Objekt, wird verwendet, um Systeme oder Subsysteme zu erzeugen. Dabei ist es egal, ob es sich um physische oder virtuelle Systeme handelt, die abgebildet werden. Folgende Attribute kommen zu den Grundattributen hinzu:-
Event-Notifier
Damit wird signalisiert, welche Events überwacht werden können.
-
Event-Notifier
-
Variable
Eine Variable wird verwendet, um einem Objekt einen Inhalt zu geben. Da eine Variable einen gewissen Wert repräsentiert, besitzt eine Variable sehr viel mehr Attribute:-
DataType
Dies ist die Node-ID des Datentypes. -
ValueRank
Der ValueRank gibt an, ob die Daten ein einzelner Wert, oder eine Liste an Werten ist. Genauer gesagt, können die Werte als Skalar, eindimensionales Array oder mehrdimensionales Array vorliegen. -
ArrayDimensions
Dieses Element gibt an, wie groß die einzelnen Dimensionen sind. Dieses Attribut ist nur relevant, wenn die Daten nicht als Skalar vorliegen. -
Value
Dies ist der Wert, der vom Node verwaltet wird. Wie dieses Element zu interpretieren ist, hängt von den Attributen DataType, ValueRank und ArrayDimensions ab. -
Historizing
Dieses Element gibt an, ob auf dem Server eine Historie der Daten gespeichert wird. -
AccessLevel
Dieses Element gibt an, welche Berechtigungen im Allgemeinen gewährt werden. Mögliche Berechtigungen sind Lesen und Schreiben des aktuellen Wertes und Lesen/Schreiben der Historie. -
UserAccessLevel
Dieses Element gibt an, welche Berechtigungen der aktuelle Benutzer besitzt. -
MinimumSamplingInterval
Dieses Element gibt an, wie schnell der Server Änderungen eines Wertes erfassen kann. Dies ist vor allem dann interessant, wenn der Server die Information erst von einem Subsystem anfordern muss.
-
DataType
-
Methods
Methods, zu Deutsch Methoden, sind Funktionen die auf dem Server ausgeführt werden können.-
Executable
Dieses Attribut gibt an, ob die Funktion aktuell ausführbar ist. -
UserExecutable
Dieses Attribut gibt an, ob die Funktion vom aktuellen Benutzer ausführbar ist.
-
Executable
-
ReferenceType
ReferenceTypes, zu Deutsch Referenztypen, beschreiben die Relation zwischen Elementen auf dem Server. Eine genaue Erklärung zu Referenzen findet sich im nächsten Abschnitt.-
isAbstract
Dieses Attribut gibt an, ob es sich bei dem Typ um ein Organisationselement der Hierarchie handelt, oder ob er tatsächlich verwendet werden kann. Sollte der Typ abstrakt sein, so kann er nicht erzeugt werden, aber sehr wohl verwendet werden um bestehende Elemente eines Subtyps ansprechen zu können. Auf Referenzen wird im späteren Abschnitt noch näher eingegangen. -
symmetric
Dieses Attribut gibt an, ob die Referenz symmetrisch ist. Wenn sie symmetrisch ist, dann besitzt die Referenz in die umgekehrte Richtung die selbe Bedeutung. Ein Beispiel für eine nicht symmetrische Referenz ist die Eltern-Kind Beziehung; so ist zB.: A der Elternteil von B und B ist das Kind von A. Ein Beispiel für eine symmetrische Referenz ist die Geschwister-Beziehung. -
inverseName
Wenn die Referenz nicht symmetrisch ist, gibt dieses Element den Namen der umgekehrten Referenz an. Beim vorhergehenden Beispiel war der Elternteil von der reguläre Name der Referenz und ist das Kind von der Name der umgekehrten Referenz.
-
isAbstract
-
DataType
Ein DataType, zu Deutsch Datentyp, definiert wie die Daten zu interpretieren sind. Die von der OPC UA Foundation vorgegebenen Datentypen sind in Namespace 0 zu finden und stellen grundlegende Datentypen dar. Neben den grundlegenden Datentypen ist es auch möglich eigene Datentypen zu definieren. Es ist jedoch sinnvoller, Variablen-Typen und Objekt-Typen zu definieren.-
isAbstract
Dieses Attribut gibt, genau wie bei den Referenzen, an, ob es sich um ein organisatorisches Element handelt oder nicht.
-
isAbstract
-
VariableType
Ein VariableType, zu Deutsch Typdefinition einer Variable, wird verwendet um den Datenelementen eine Bedeutung zu geben. Dies ist vor allem interessant, wenn man sich ein Beispiel ansieht. Beispiel: Ein Node vom BaseVariableType, einem generischen Variablen-Type, ist auf dem Server verfügbar. Der Node repräsentiert eine Temperatur. Jetzt ist unbekannt, ob es sich bei der Temperatur um Celsius, Kelvin oder Fahrenheit handelt. Wenn jedoch ein Celsius-Typ definiert und verwendet wird, ist sofort klar, wie die Daten zu interpretieren sind. Alternativ kann auch ein Temperatur-Datentyp definiert werden, bei dem in der Beschreibung die Interpretation deklariert wird. Dies hat jedoch den Nachteil, dass nicht sofort aus dem Variablentyp klar ist, wie die Daten zu interpretieren sind.-
DataType
Dies ist die Node-ID des Datentypes. -
ValueRank
Der ValueRank gibt an, ob die Daten ein einzelner Wert, oder eine Liste an Werten ist. Genauer gesagt, können die Werte als Skalar, eindimensionales Array oder mehrdimensionales Array vorliegen. -
ArrayDimensions
Dieses Element gibt an, wie groß die einzelnen Dimensionen sind. Dieses Attribut ist nur relevant, wenn die Daten nicht als Skalar vorliegen. -
Value
Dies ist der Wert, der vom Node verwaltet wird. Wie dieses Element zu interpretieren ist, hängt von den Attributen DataType, ValueRank und ArrayDimensions ab. -
isAbstract
Dieses Attribut gibt, genau wie bei den Referenzen, an, ob es sich um ein organisatorisches Element handelt oder nicht.
-
DataType
-
ObjectType
Ein ObjectType, zu Deutsch Typdefinition eines Objektes, wird verwendet um sicherzustellen, dass ein Objekt bei der Erstellung gewisse Attribute besitzt. In objektorientierten Programmiersprachen würde man dieses Konstrukt auch Klasse nennen.-
isAbstract
Dieses Attribut gibt, genau wie bei den Referenzen, an, ob es sich um ein organisatorisches Element handelt oder nicht.
-
isAbstract
-
View
Eine View, zu Deutsch Ansicht, bezeichnet eine Liste an Nodes, die für eine bestimmte Aufgabe interessant sein können. So kann zum Beispiel eine Ansicht definiert werden, die für die Wartung interessant ist, und eine andere Ansicht, die für den regulären Gebrauch interessant ist. Damit muss nicht der Gesamte Adressraum des Servers abgesucht werden.-
ContainsNoLoop
Dieses Attribut gibt an, ob die dargestellten Nodes eine zirkuläre Hierarchie aufbauen, wenn man den Referenzen folgt. -
EventNotifier
Dieses Attribut gibt an, ob man über diese Ansicht Events generieren lassen kann (zB bei Datenänderung) und ob die Event-Historie lesbar und änderbar ist.
-
ContainsNoLoop
Referenzen und Datentypen
Referenzen
Referenzen werden verwendet, um Nodes miteinander in Beziehung zu setzen.
Eine Referenz besitzt immer drei Bestandteile:
- Quelle
- Ziel
- Referenztyp
Abstrakte Referenzen sind durch spezielle Kennzeichnung hervorgehoben. Das Praktische an abstrakten Referenzen ist, dass sie als organisatorische Elemente dienen und bei der Filterung von Ergebnissen verwendet werden können. Im Folgenden werden ausgewählte Referenztypen behandelt.
-
Organizes
Diese Referenz wird verwendet, wenn Objekte oder Variablen in einem Ordner zusammengefasst werden. Ein Ordner ist ein Objekt, das nur zum Zusammenfassen von Informationspunkten dient. Ordner werden zum Beispiel im Standard-Informations-Modell verwendet, um alle Objekte, alle Typdefinitionen und alle Views zusammenzufassen. -
HasProperty
Diese Referenz wird verwendet, um Eigenschaften von Objekten und Variablen abzubilden. Properties selbst können keine Quellen von weiteren Referenzen sein. Ein Beispiel für eine Eigenschaft wäre bei einer Datei das Änderungsdatum. -
HasComponent
Diese Referenz wird verwendet um Inhalte eines Objektes zu definieren. Elemente die über diese Referenzart erstellt worden sind, können weiterhin die Quelle für neue Referenzen sein. -
HasOrderedComponent
Diese Referenz wird verwendet, um einem Objekt Methoden zu geben.
Datentypen
OPC UA definiert eine Reihe an Datentypen, die verwendet werden können.
Zusätzlich können noch eigene Datentypen definiert werden.
Beispiele dafür sind Aufzählungen; dafür gibt es den Basistyp Enumeration.
Ebenso ist es möglich, eigene Strukturen zu definieren.
Hier muss jedoch im Regelfall auf beiden Seiten, also auf Server und Client, eine Funktion existieren, die die Daten interpretieren kann.
Die gesamte Hierarchie der Datentypen ist in der folgenden Abbildung dargestellt.Im Folgenden werden einige Datentypen behandelt:
- NodeId
- ExpandedNodeId
- NodeIDs werden verwendet um Datenelemente eines Servers zu bezeichnen. Darauf wurde im vorhergehenden Abschnitt bereits eingegangen. NodeIDs werden verwendet um lokale Nodes eines Servers zu identifizieren. ExpandedNodeIDs erlauben es, Nodes eines anderen Servers zu referenzieren. So wäre es zum Beispiel möglich alle Variablen und Objektdefinitionen auf einem zentralen Server zu hinterlegen und diese von anderen Servern referenzieren zu lassen.
- DateTime
- DateTime wird verwendet, um einen Zeitstempel zu erzeugen.
- DataValue
- Dies bezeichnet einen Datenwert mit einem Statuscode und einem Zeitstempel.
- QualifiedName
- Ein QualifiedName bezeichnet einen String, der mit einem Namespace-Index versehen ist. Der Browse-Name eines Nodes ist ein Beispiel für einen QualifiedName. Dieser wird in den Angaben dieser Übung wie folgt gekennzeichnet: qn=<namespaceIndex>;<name>.
- Number
- Dieser Datentyp fasst alle Zahlen zusammen. Die Art der Zahl ist hierbei irrelevant.
- Integer
- UInteger
- Hierbei handelt es sich um vorzeichenbehaftete oder vorzeichenfreie Ganzzahlen. Hier gibt die Zahl an, wie viele Bits zur Verfügung stehen.
- Float
- Double
- Dies sind Gleitkommazahlen mit einfacher und doppelter Genauigkeit.
- DiagnosticInfo
- Dieser Datentyp bietet detaillierte Informationen in einem Fehlerfall.
- Boolean
- Dieser Datentyp repräsentiert einen Wert der Wahr oder Falsch sein kann.
- String
- ByteString
- Strings und ByteStrings sind Zeichenketten. Während Strings Zeichenketten aus druckbaren Zeichen bestehen, bestehen ByteStrings aus allen möglichen Zeichen. Da ein ByteString sehr häufig Zeichen beinhaltet, die nicht dargestellt werden können, werden sie Base64 kodiert dargestellt.
- LocalizedText
- Ein LocalizedText ist eine Struktur, die Informationen in einer gewissen Sprache kommuniziert. Ein LocalizedText besitzt damit zwei Elemente, die Sprache in der die Information vorliegt und die Information selbst.
- GUID
- Ein 16 Byte Wert, der als globale einzigartige Identifikationsnummer verwendet wird. Der Wert setzt sich aus einem 32-Bit Wert, zwei 16-Bit Werten und acht 8-Bit Werten.
- XMLElement
- Ein XML Element ist ein Element der Extensible Markup Language.
Discovery und Browsing
OPC UA definiert ebenso Möglichkeiten Server zu finden und Informationen auszulesen.
Discovery definiert, wie ein Server gefunden werden kann.
Browsing beschreibt das Erhalten von Informationen über die verfügbaren Nodes.
Discovery
OPC bietet die Möglichkeit mit Discovery-Servern zu arbeiten. Ein Discovery-Server ist ein Server, bei dem sich andere Server registrieren können. Dadurch muss man nur eine/n Teilnehmer/in im Netzwerk kennen, um alle verfügbaren Server zu finden.Browsing
Beim Browsen werden folgende Funktionen geboten:
-
Browse
Beim Browsen gibt man einen Node an und erhält alle Nodes, die den angegebenen Node als Quelle einer Referenz haben. Man kann zusätzlich noch nach Referenzen und Node-Klassen filtern. An diesem Punkt sind die zuvor erwähnten abstrakten Referenzen hilfreich, da dadurch eine Vielzahl an konkreten Referenzen abgedeckt werden kann. Folgende Informationen werden immer für jeden Node zurückgegeben:- Referenz
- Node-ID
- Browsename
- Displayname
- Node-Klasse
-
qn=0;Root
-
qn=0;Objects
-
qn=0;Server
- qn=0;NamespaceArray
- qn=0;ServerArray
-
qn=0;Server
-
qn=0;Types
- qn=0;DataTypes
- qn=0;ObjectTypes
- qn=0;ReferennceTypes
- qn=0;VariableTypes
- qn=0;Views
-
qn=0;Objects
-
BrowseNext
Diese Funktion kann verwendet werden, wenn nicht alle Nodes zurückgegeben werden konnten. Dies kann vor allem dann hilfreich sein, wenn mehr Nodes gefunden wurden, als auf einmal gesendet werden können. -
TranslateBrowsePathToNodeID
Mit diesem Service kann ein Browsepath in eine Node-ID umgewandelt werden. Dies ist gerade dann interessant, wenn man zwar weiß wie der Datenpunkt heißt, aber die Node-ID unbekannt ist. Da man aber die Node-ID braucht um Nodes ansprechen zu können, ist dieses Service unumgänglich. Der Browsepath ist eine Liste von Browsenames der einzelnen Nodes. Diese Funktionalität ist vor allem dann wichtig, wenn die Elemente auf dem Server semantisch oder durch eine Ontologie beschrieben werden können. -
Register/Unregister Nodes
Mit dieser Funktionalität kann man einem Server mitteilen, dass die aktuelle Verbindung vermehrt auf die angegebenen Nodes zugreifen wird. Dabei geschehen zwei Sachen. Erstens wird die Menge an Information reduziert, die übertragen werden muss. Dies geschieht dadurch, dass der Client eine numerische Node-ID bekommt. Diese ist am einfachsten zu übertragen. Zweitens optimiert der Server den Zugriff auf den Datenpunkt selbst, damit das Schreiben auf oder Ausführen von dem Node effizienter geschieht. Unregister teilt dem Server mit, dass der Node nicht mehr vermehrt benötigt wird. Diese Funktionalität sollte nicht verwendet werden, wenn der Node nur ausgelesen wird, da es dazu effizientere Mechanismen gibt. Auf diese Mechanismen wird im Punkt Read/Write eingegangen.
Read/Write
Read
Es können im Regelfall alle Attribute eines Nodes gelesen werden. Beim Lesen des Wertes eines Nodes, dem Value-Attribute, werden die Zugriffsrechte in Betracht gezogen.Write
Im Regelfall kann nur das Value-Attribut eines Nodes beschrieben werden. Dabei werden auch die Zugriffsrechte der aktuellen Verbindung in Betracht gezogen.Subscriptions und Monitored Items
Subscriptions und Monitored Items sind ein Mechanismus, um Nodes zu überwachen und bei Bedarf die neue Information an den Client zu schicken. Zuerst legt ein Client eine Subscription an und definiert wie die Informationen transportiert werden. Dabei kann er festlegen welche Priorität die Daten haben, wieviele Informationen auf einmal übertragen werden können und in welchem Intervall die Daten gesendet werden. Danach können, basierend auf der Subscription, Monitored Items angelegt werden. Hier wird angegeben, welche Node-ID überwacht werden soll, in welchem Intervall der Node auf Änderungen überprüft werden soll und wann eine Änderung gesendet werden soll. Dabei kann man sich entscheiden, ob man informiert werden möchte wenn sich der Status ändert, wenn sich Status und Wert ändern, oder wenn sich Status, Wert und Zeitstempel ändern. Sollten bestimmte Werte überwacht werden, so ist es sehr empfehlenswert diesen Mechanismus zu wählen.Methoden
Methoden sind Funktionen, die auf dem Server hinterlegt sind und über das Netzwerk ausgeführt werden können.
Methoden können Eingabeparameter, Ausgabewerte, beide, oder keine von beiden besitzen.
Eingabeparameter werden verwendet, um dem Methodenaufruf zusätzliche Information mitzugeben.
Ausgabewerte werden verwendet, um Information zurück zur/zum Aufrufenden zu übermitteln.
Man kann einfach ermitteln, ob eine Methode Argumente besitzt, indem man den Methoden-Node durchsucht.
Besitzt er eine Referenz auf einen Node mit dem Browsename qn=0;InputArguments, so benötigt die Methode Eingabeparaemter.
Besitzt er eine Referenz auf einen Node mit dem Browsename qn=0;OutputArguments, so liefert die Methode Ausgabewerte.
Sicherheit
OPC UA verwendet zur Kommunikation verschiedene Sicherheitsmechanismen.
Wenn ein Client Kontakt zu einem Server aufnimmt, wird zuerst eine Verbindung initiiert.
Basierend auf der Verbindung wird ein sicherer Kanal erzeugt.
Erst nachdem der sichere Kanal erzeugt worden ist, wird eine Session angelegt.
Die gesamte Kommunikation zwischen Client und Server wird in einer bestehenden Session abgehandelt.
Die Session selbst ist nicht an einen speziellen sicheren Kanal gebunden.
Dadurch bleibt eine Session erhalten, auch wenn der sichere Kanal erneuert wird.
Bei der Anmeldung gibt es verschiedene Authentifizierungsarten:
- Anonym
- Benutzername/Passwort
- X509v3 Zertifikat
- WS-SecurityToken
- None - Die Kommunikation wird nicht verschlüsselt.
- Basic128RSA15
- Basic256
Architektur
OPC UA kann auf verschiedene Arten verwendet werden.
Im Folgenden sind die häufigsten Konfigurationen zu finden.
Server/Client
Dabei stellt ein Rechner, der Server, Informationen und Methoden zur Verfügung. Andere Rechner, die Clients, verbinden sich zum Server, um die Informationen zu erhalten. Dies ist die häufigste Art, auf die das Protokoll verwendet wird.Chained Server
Bei der Chained-Server Architektur erfolgt die Kommunikation über einen Zwischenserver. Der Zwischenserver besitzt einen eingebetteten Client, der mit dem eigentlichen Server kommuniziert. Dieser Server kann zum Beispiel zur Protokollkonvertierung verwendet werden. Ein weiterer Einsatzfall wäre, dass der Zwischenserver von außerhalb des Produktionsnetzwerkes erreichbar ist, der eigentliche Server jedoch nicht. Der Server mit dem in den angebotenen Online-Übungen interagiert wird, ist ein Chained Server. Jeder angeschlossene Server besitzt in diesem Fall einen eigenene Namespace. Der Namespace des Servers beinhaltet lediglich organisatorische Elemente, einen Ordner für jeden angeschlossenen Server und einen Indikator ob der Server online ist.Server to Server
Die Server to Server Kommunikation wird eingesetzt, wenn Daten auf mehreren Servern zur Verfügung stehen müssen. In diesem Szenario besitzt jeder Server einen eingebetteten Client, um dem zweiten Server Änderungen mitteilen zu können. Dies ist vor allem dann ein Vorteil, wenn Server-Redundanzen notwendig sind.Aggregating Server
Ein Aggregating Server bindet mehrere Server an und verarbeitet die gewonnenen Informationen weiter bevor er diese weitergibt. Während der Chained Server lediglich die Daten der angebundenen Server weitergibt, konzentriert der Aggregating Server die Informationen, die aus den Daten gewonnen werden können. Übung
Im Folgenden werden verschiedene Beispielaufgaben mit fertigen Python-Lösungen präsentiert.
Dazu werden die einzelnen Schritte des Python-Codes und die Funktionen der Python OPC-UA Bibliothek erklärt.
Die Installation der Bibliothek wird HIER erklärt, während die Funktionen der Bibliothek HIER nachgeschlagen werden können.
Dieses Beispiel demonstriert lediglich, wie man sich mit einem OPC-UA-Server mithilfe der vorgegebenen Funktionen verbindet.
Es soll eine Verbindung zum Server der FH Technikum Wien hergestellt werden.
Folgende Eckdaten sind zum Verbinden notwendig:
Verbindung ohne Zugangsdaten aufbauen
Als erster Schritt müssen die nötigen Python-Bibliotheken importiert werden.
Die Bibliothek time wird später verwendet, um ein Beenden des Python-Programms zu vermeiden.
Da nur eine Verbindung hergestellt werden soll, wird nur die Klasse Client von opcua importiert.
Danach werden der Servername und der Port in den Variablen HOST bzw. PORT gespeichert.
Nun kann eine Instanz der Klasse Client erstellt werden.
Dazu muss der URL des Servers als String übergeben werden.
#!/usr/bin/env python3
"""
This example shows how to connect to the server without credentials
"""
import time
from opcua import Client
if __name__ == "__main__":
# Create a OPC-UA Client with the following specification:
# Server: engine.ie.technikum-wien.at
# Port: 4840
HOST = "engine.ie.technikum-wien.at"
PORT = 4840
# This syntax does not provide credentials and we are logging in anonymously
# at the specified server. The Server has been configured to allow anonymous
# users to read every datapoint. All other actions are prohibited.
CLIENT = Client("opc.tcp://{}:{}/".format(HOST, PORT))
#!/usr/bin/env python3
"""
This example shows how to connect to the server without credentials
"""
import time
from opcua import Client
if __name__ == "__main__":
# Create a OPC-UA Client with the following specification:
# Server: engine.ie.technikum-wien.at
# Port: 4840
HOST = "engine.ie.technikum-wien.at"
PORT = 4840
# This syntax does not provide credentials and we are logging in anonymously
# at the specified server. The Server has been configured to allow anonymous
# users to read every datapoint. All other actions are prohibited.
CLIENT = Client("opc.tcp://{}:{}/".format(HOST, PORT))
try:
# Connect to the Server
# This function connects to the server. If the connection has already
# been implemented, nothing is done. If the connection terminated the
# function reconnects
CLIENT.connect()
try:
# Loop
while True:
print("connected with server")
# Sleep
time.sleep(1)
except KeyboardInterrupt:
pass
finally:
# Disconnect
CLIENT.disconnect()
Dieses Beispiel unterscheidet sich vom vorherigen nur dadurch, dass eine Verbindung mit Userdaten hergestellt werden soll.
Zusätzlich zu den Daten der vorhergehenden Aufgabe kommen folgende Informationen:
Verbindung mit Zugangsdaten aufbauen
Der Programmcode beinhaltet bereits das gesamte Programm, da nur die Zugangsdaten für die Serververbindung hinzugefügt werden müssen.
Diese Daten werden in den Variablen USER und PASS gespeichert.
Die korrekte URL benötigt die Logininformationen durch ein : getrennt, was in der Variable CREDENTIALS gespeichert wird.
Anschließend kann wiederum die Instanz Client erstellt werden, wobei im Gegensatz zum vorigen Beispiel, die Loginformationen vor dem Servernamen übergeben werden.
Die Userinformationen werden wie bei E-Mailadressen durch das @ Symbol vom Servernamen getrennt.
Der weitere Programm ist ident zu jenem aus dem vorigen Beispiel.
#!/usr/bin/env python3
"""
This example shows how to connect to the server with credentials
"""
import time
from opcua import Client
if __name__ == "__main__":
# Create a OPC-UA Client with the following specification:
# Server: engine.ie.technikum-wien.at
# Port: 4840
HOST = "engine.ie.technikum-wien.at"
PORT = 4840
USER = "student"
PASS = "student"
CREDENTIALS = "{}:{}".format(USER, PASS)
# This syntax does provide credentials.
CLIENT = Client("opc.tcp://{}@{}:{}/".format(CREDENTIALS, HOST, PORT))
try:
# Connect to the Server
CLIENT.connect()
try:
# Loop
while True:
print("connected with server")
# Sleep
time.sleep(1)
except KeyboardInterrupt:
pass
finally:
# Disconnect
CLIENT.disconnect()
In der folgenden Aufgabe geht es darum, die Nodes des Hauptservers und des Beispiel-Servers zu ermitteln.
Dafür werden zwei Namespaces benötigt, der Namespace des Hauptservers selbst und der Namespace des Beispiel-Servers.
Es sollen die verfügbaren Namespaces angezeigt sowie die Elemente des Server-Namespaces und die Elemente des Beispiel-Namespaces ausgegeben werden.
Zusätzlich zu den Daten der vorhergehenden Aufgabe kommen folgende Informationen:
Browsen
Da nun das Programm nach Ausgabe der nötigen Informationen automatisch beendet werden soll, wird die Bibliothek time nicht benötigt.
Die Verbindung mit dem Server erfolgt wieder wie gewohnt, wobei es reicht, sich anonym am Server anzumelden.
Um zu demonstrieren, welche Namespaces am Hauptserver verfügbar sind, werden diese im ersten Schritt ausgegeben.
Die Namespaces des Servers werden durch die Methode get_namespace_array() als Python-Liste in der Variable NAMESPACES gespeichert.
Dies ermöglicht es, die einzelnen Namespaces des Servers in der nachfolgenden for-Schleife auszugeben.
#!/usr/bin/env python3
"""
This example shows how to connect to the server without credentials
"""
from opcua import Client
from opcua import ua
if __name__ == "__main__":
# Create a OPC-UA Client with the following specification:
# Server: engine.ie.technikum-wien.at
# Port: 4840
HOST = "engine.ie.technikum-wien.at"
PORT = 4840
# This syntax does not provide credentials and we are logging in anonymously
# at the specified server. The Server has been configured to allow anonymous
# users to read every datapoint. All other actions are prohibited.
CLIENT = Client("opc.tcp://{}:{}/".format(HOST, PORT))
try:
# Connect to the Server
# This function connects to the server. If the connection has already
# been implemented, nothing is done. If the connection terminated the
# function reconnects
CLIENT.connect()
# There are multiple Namespaces on the Server and we want to query them
NAMESPACES = CLIENT.get_namespace_array()
print(">Namespaces")
for namespace in NAMESPACES:
print(" {}".format(namespace))
#!/usr/bin/env python3
"""
This example shows how to connect to the server without credentials
"""
from opcua import Client
from opcua import ua
if __name__ == "__main__":
# Create a OPC-UA Client with the following specification:
# Server: engine.ie.technikum-wien.at
# Port: 4840
HOST = "engine.ie.technikum-wien.at"
PORT = 4840
# This syntax does not provide credentials and we are logging in anonymously
# at the specified server. The Server has been configured to allow anonymous
# users to read every datapoint. All other actions are prohibited.
CLIENT = Client("opc.tcp://{}:{}/".format(HOST, PORT))
try:
# Connect to the Server
# This function connects to the server. If the connection has already
# been implemented, nothing is done. If the connection terminated the
# function reconnects
CLIENT.connect()
# There are multiple Namespaces on the Server and we want to query them
NAMESPACES = CLIENT.get_namespace_array()
print(">Namespaces")
for namespace in NAMESPACES:
print(" {}".format(namespace))
# In order to browse, we need some node as a starting point.
STARTNODE = CLIENT.get_objects_node()
# The method get_children returns all children of the Node in question
NODES = STARTNODE.get_children()
print(">Browsing")
print(" Children of: {}".format(STARTNODE.nodeid.to_string()))
for node in NODES:
print(" {} -- {} -- {}".format(
node.nodeid.to_string(), # Short form of NodeID
node.get_browse_name().to_string(), # Short form
ua.NodeClass(node.get_node_class()).name))# Name of the nodeclass
#!/usr/bin/env python3
"""
This example shows how to connect to the server without credentials
"""
from opcua import Client
from opcua import ua
if __name__ == "__main__":
# Create a OPC-UA Client with the following specification:
# Server: engine.ie.technikum-wien.at
# Port: 4840
HOST = "engine.ie.technikum-wien.at"
PORT = 4840
# This syntax does not provide credentials and we are logging in anonymously
# at the specified server. The Server has been configured to allow anonymous
# users to read every datapoint. All other actions are prohibited.
CLIENT = Client("opc.tcp://{}:{}/".format(HOST, PORT))
try:
# Connect to the Server
# This function connects to the server. If the connection has already
# been implemented, nothing is done. If the connection terminated the
# function reconnects
CLIENT.connect()
# There are multiple Namespaces on the Server and we want to query them
NAMESPACES = CLIENT.get_namespace_array()
print(">Namespaces")
for namespace in NAMESPACES:
print(" {}".format(namespace))
# In order to browse, we need some node as a starting point.
STARTNODE = CLIENT.get_objects_node()
# The method get_children returns all children of the Node in question
NODES = STARTNODE.get_children()
print(">Browsing")
print(" Children of: {}".format(STARTNODE.nodeid.to_string()))
for node in NODES:
print(" {} -- {} -- {}".format(
node.nodeid.to_string(), # Short form of NodeID
node.get_browse_name().to_string(), # Short form
ua.NodeClass(node.get_node_class()).name))# Name of the nodeclass
# As we know the Node-ID, we can access the node directly
STARTNODE = CLIENT.get_node("ns=1;s=OPC Examples")
NODES = STARTNODE.get_children()
print(" Children of: {}".format(STARTNODE.nodeid.to_string()))
for node in NODES:
print(" {} -- {} -- {}".format(
node.nodeid.to_string(), # Short form of NodeID
node.get_browse_name().to_string(), # Short form
ua.NodeClass(node.get_node_class()).name))# Name of the nodeclass
finally:
# Disconnect
CLIENT.disconnect()
Im Folgenden geht es darum, Informationen von einem Node zu erhalten.
Die Aufgabe sieht vor, dass die angegebene Variable ExampleVariable ausgelesen wird.
Folgende Eckdaten sind zum Verbinden notwendig:
Lesen
Wiederum erfolgt eine anonyme Verbindung zum Server der FH Technikum Wien.
Mithilfe des Namespaces wird der Namespace-Index durch die Methode get_namespace_index() ermittelt und in der Variable IDX gespeichert.
Dazu muss der URL des Namespaces der Methode übergeben werden.
Nun wird eine Node-Instanz (NODE) durch die bereits bekannte Methode get_node(NodeID) erzeugt.
Die NodeID muss der Methode als Parameter übergeben werden, wobei der zuvor ermittelte Namespace-Index benötigt wird.
Im Anschluss kann der Wert des Nodes einfach durch die Methode get_value() in der Variable VALUE gespeichert und ausgegeben werden.
#!/usr/bin/env python3
"""
This example shows how to read a variable from the server
"""
from opcua import Client
if __name__ == "__main__":
# Create a OPC-UA Client with the following specification:
# Server: engine.ie.technikum-wien.at
# Port: 4840
HOST = "engine.ie.technikum-wien.at"
PORT = 4840
# This syntax does not provide credentials and we are logging in anonymously
# at the specified server. The Server has been configured to allow anonymous
# users to read every datapoint. All other actions are prohibited.
CLIENT = Client("opc.tcp://{}:{}/".format(HOST, PORT))
try:
# Connect to the Server
CLIENT.connect()
IDX = CLIENT.get_namespace_index("opc.tcp://engine.ie.technikum-wien.at/OPCExamples")
# Get Node from the client based on the NodeID
NODE = CLIENT.get_node("ns={};s=ExampleVariable".format(IDX))
# Read the current value
VALUE = NODE.get_value()
# Print the Information
print("{}: {}".format(NODE, VALUE))
finally:
# Disconnect
CLIENT.disconnect()
Diese Aufgabe sieht vor, dass eine Subscription mit einem Monitored Item für den entsprechenden Node erzeugt wird.
Dies ist die bevorzugte Variante, um Daten periodisch zu empfangen.
Bei jeder Wertänderung der Variable ExampleVariable soll dies ausgegeben werden.
Subscriben
Im ersten Schritt wird die Klasse SubscriptionHandler erstellt.
Der SubscriptionHandler hat die Aufgabe einen Node zu beobachten.
Die Funktionen der Klasse übernehmen folgende Aufgaben:
Nachdem eine Instanz der Klasse erstellt wird, wird ein Zähler initiiert.
Der Zähler soll die Anzahl der Wertänderungen speichern.
Wenn eine Instanz der Klasse gelöscht wird, wird mitgeteilt wie viele Wertänderungen registriert wurden.
Diese Funktion wird aufgerufen, wenn eine Wertänderung des übergebenen node registriert wird.
Der Parameter value beinhaltet den aktuellen Wert des Nodes.
Der Parameter _ speichert die Rohdaten der Benachrichtigung, der hier aber nicht weiter beachtet werden muss.
In diesem Beispiel soll der aktuelle Wert ausgegeben werden.
Zusätzlich wird noch der Zähler bei jeder Wertänderung um eins erhöht.
Der Funktionsname datachange_notification ist durch die OPC-UA Bibliothek vorgegeben und wird bei Wertänderungen automatisch aufgerufen, wenn dies gewollt ist.
Wie die Benachrichtigung bei Wertänderungen definiert wird, wird im nächsten Abschnitt erklärt.
#!/usr/bin/env python3
"""
This example shows how to create a subscription to a variable
"""
import time
from opcua import Client
class SubscriptionHandler(object): # pylint: disable=too-few-public-methods
"""
Subsrciption handler.
"""
def __init__(self):
self.counter = 0
def __del__(self):
print("Observed {} datachanges".format(self.counter))
def datachange_notification(self, node, value, _):
"""
Function that's called when data is changed
Args:
node: The node id that had a datachange
value: The current value
_: The raw data of the notification
Returns:
None
"""
print("{}: {}".format(node, value))
self.counter = self.counter + 1
#!/usr/bin/env python3
"""
This example shows how to create a subscription to a variable
"""
import time
from opcua import Client
class SubscriptionHandler(object): # pylint: disable=too-few-public-methods
"""
Subsrciption handler.
"""
def __init__(self):
self.counter = 0
def __del__(self):
print("Observed {} datachanges".format(self.counter))
def datachange_notification(self, node, value, _):
"""
Function that's called when data is changed
Args:
node: The node id that had a datachange
value: The current value
_: The raw data of the notification
Returns:
None
"""
print("{}: {}".format(node, value))
self.counter = self.counter + 1
if __name__ == "__main__":
CLIENT = Client("opc.tcp://engine.ie.technikum-wien.at:4840/")
try:
CLIENT.connect()
IDX = CLIENT.get_namespace_index("opc.tcp://engine.ie.technikum-wien.at/OPCExamples")
NODE = CLIENT.get_node("ns={};s=ExampleVariable".format(IDX))
# Create a handler to work with the updated data
HANDLER = SubscriptionHandler()
# Create a subscription
SUB = CLIENT.create_subscription(500, HANDLER)
# Connect NodeIDs to the Subscription
SUB.subscribe_data_change(NODE)
try:
# Loop -- only needed so the program doesn't stop right away
while True:
# Sleep
time.sleep(1)
except KeyboardInterrupt:
pass
SUB.delete()
finally:
CLIENT.disconnect()
Anwendung
Zugangsdaten
Folgende Informationen benötigen Sie, um auf die Übung zugreifen zu können:
- Host: engine.ie.technikum-wien.at
- Port: 4840
- Username: student
- Password: student
- Namespace: opc.tcp://engine.ie.technikum-wien.at/OPCExercises
Browsing
Finden Sie heraus, welche Datenpunkte über den Node ns=1;s=OPC Exercises erreicht werden können. Ermitteln Sie die Node-IDs im angegebenen Namespace, den Anzeigenamen und die Klasse.
Lösung
Es sind folgende Nodes auf dem Server verfügbar:- ns=3;i=119 -- Sensor 1 -- Variable
- ns=3;i=316 -- Sensor 2 -- Variable
- ns=3;i=317 -- Sensor 3 -- Variable
- ns=3;i=318 -- Test-Method -- Method
- ns=3;i=320 -- Convert String -- Method
#!/usr/bin/env python3
"""
This is an example-solution
"""
from opcua import Client
if __name__ == "__main__":
CLIENT = Client("opc.tcp://student:student@engine.ie.technikum-wien.at:4840/")
try:
CLIENT.connect()
IDX = CLIENT.get_namespace_index("opc.tcp://engine.ie.technikum-wien.at/OPCExercises")
print("Namespace Index of Exercises: {}".format(IDX))
print("Nodes in ns={}:".format(IDX))
NODE = CLIENT.get_node("ns=1;s=OPC Exercises")
NODES = NODE.get_children()
for node in NODES:
if node.nodeid.NamespaceIndex != IDX: # Required as we get all children of the node
continue
print("{} -- {} -- {}".format(
node.nodeid.to_string(), # Get a short printable NodeId
node.get_display_name().to_string(), # Get a short printable Display Name
node.get_node_class().name)) # Get a short readbale nodeclass
finally:
CLIENT.disconnect()
Auslesen der Variablen
Geben Sie die Beschreibung der in der vorhergehenden Aufgabe ermittelten Nodes aus. Lesen Sie - bei den Variablen - über 10 Sekunden im 1-Sekunden-Intervall die Werte der einzelnen Nodes und geben Sie die ermittelten Werte aus.
Lösung
Folgende Beschreibungen und Variablenwerte existieren für die einzelnen Nodes. Beachten Sie, dass es sich bei den Werten der Variablen um zufällige Werte handelt und somit variieren.- ns=3;i=119
-
The sensor reading of an analogue sensor with a range of 4 to 20 mA.
Values: [4.251206457216534, 4.289866899644205, 4.895675476539514, 4.9098246865436375, 5.420688888428982, 5.88977037896077, 6.270517873818549, 7.583171043162588, 8.316529417004658, 8.831909074195444] - ns=3;i=316
-
The sensor reading of an analogue sensor with a range of -10 to 10 V.
Values: [-2.9375731073518523, -1.7124065024717305, -0.7790857976530966, 0.14439170175511734, 1.2071837310511713, 2.121364889782571, 3.1357310629583113, 4.92733921542168, 5.738893638260663, 6.580431443068198] - ns=3;i=317
-
The sensor reading of a digital sensor with either true or false
Values: [True, True, True, False, False, True, True, True, False, False] - ns=3;i=318
- Method that returns how many times it has been called so far
- ns=3;i=320
- Method that converts a string. Specifically it flips upper and lowercase
#!/usr/bin/env python3
"""
This is an example-solution
"""
import time
from opcua import Client
from opcua import ua
if __name__ == "__main__":
CLIENT = Client("opc.tcp://student:student@engine.ie.technikum-wien.at:4840/")
try:
CLIENT.connect()
IDX = CLIENT.get_namespace_index("opc.tcp://engine.ie.technikum-wien.at/OPCExercises")
print("Namespace Index of Exercises: {}".format(IDX))
NODE = CLIENT.get_node("ns=1;s=OPC Exercises")
NODES = NODE.get_children()
for node in NODES:
if node.nodeid.NamespaceIndex != IDX:
continue
print("{}: {}".format(node.nodeid.to_string(), node.get_description().to_string()))
if node.get_node_class() == ua.NodeClass.Variable:
values = []
for i in range(10):
values.append(node.get_value())
time.sleep(1)
print("Values: {}".format(values))
finally:
CLIENT.disconnect()
Methoden analysieren
Ermitteln Sie, welche Parameter die von Ihnen ermittelten Methoden benötigen und welche Ergebnisse die Methoden liefern.
Lösung
Die Funktionen besitzen folgende Parameter:- ns=3;i=318
-
- Output
- Calls -- Number of calls to the function
- Message -- The number of calls as a printable string message
- ns=3;i=320
-
- Input
- imput -- Input string
- Output
- output -- Output string with flipped case
#!/usr/bin/env python3
"""
This is an example solution
"""
from opcua import Client
from opcua import ua
if __name__ == "__main__":
CLIENT = Client("opc.tcp://student:student@engine.ie.technikum-wien.at:4840/")
try:
CLIENT.connect()
IDX = CLIENT.get_namespace_index("opc.tcp://engine.ie.technikum-wien.at/OPCExercises")
print("Namespace Index of Exercises: {}".format(IDX))
PARENT = CLIENT.get_node("ns=1;s=OPC Exercises")
for child in PARENT.get_children():
if child.nodeid.NamespaceIndex != IDX:
continue
if child.get_node_class() != ua.NodeClass.Method:
continue
print("{}: {}".format(child.nodeid.to_string(), child.get_display_name().to_string()))
for arg in child.get_children():
print(arg.get_display_name().to_string())
for param in arg.get_value():
print("{}: {}".format(param.Name, param.Description.to_string()))
finally:
CLIENT.disconnect()
Methoden aufrufen
Führen Sie alle Methoden aus, die Sie ermittelt haben.
Lösung
Dies kann man mit folgender Beispiel-Lösung erreichen:#!/usr/bin/env python3
"""
This is an example solution
"""
from opcua import Client
if __name__ == "__main__":
CLIENT = Client("opc.tcp://student:student@engine.ie.technikum-wien.at:4840/")
try:
CLIENT.connect()
IDX = CLIENT.get_namespace_index("opc.tcp://engine.ie.technikum-wien.at/OPCExercises")
print("Namespace Index of Exercises: {}".format(IDX))
METHOD1 = CLIENT.get_node("ns={};i=318".format(IDX))
METHOD2 = CLIENT.get_node("ns={};i=320".format(IDX))
PARENT = CLIENT.get_node("ns=1;s=OPC Exercises")
for idx, res in enumerate(PARENT.call_method(METHOD1)):
print("{}: {}".format(idx, res))
RES = PARENT.call_method(METHOD2, "Test String")
print(RES)
finally:
CLIENT.disconnect()
Subscription
Subscriben Sie zu den Variablen für 10 Sekunden und lassen Sie sich die empfangenen Werte nachher anzeigen.
Lösung
Dies kann man mit folgender Beispiel-Lösung erreichen:#!/usr/bin/env python3
"""
This is an example-solution
"""
import time
from opcua import Client
from opcua import ua
class SubscriptionHandler(object): # pylint: disable=too-few-public-methods
"""
Subsrciption handler.
"""
def __init__(self):
self.counter = 0
self.items = {}
def __del__(self):
print("Observed {} datachanges".format(self.counter))
for key, value in self.items.items():
print("{} ({} values): {}".format(key.nodeid.to_string(), len(value), value))
def datachange_notification(self, node, value, _):
"""
Function that's called when data is changed
Args:
node: The node id that had a datachange
value: The current value
_: The raw data of the notification
Returns:
None
"""
if node not in self.items.keys():
self.items[node] = []
self.items[node].append(value)
self.counter = self.counter + 1
if __name__ == "__main__":
CLIENT = Client("opc.tcp://student:student@engine.ie.technikum-wien.at:4840/")
try:
CLIENT.connect()
IDX = CLIENT.get_namespace_index("opc.tcp://engine.ie.technikum-wien.at/OPCExercises")
print("Namespace Index of Exercises: {}".format(IDX))
NODE = CLIENT.get_node("ns=1;s=OPC Exercises")
NODES = NODE.get_children()
HANDLER = SubscriptionHandler()
SUB = CLIENT.create_subscription(500, HANDLER)
for child in NODES:
if child.nodeid.NamespaceIndex != IDX:
continue
if child.get_node_class() == ua.NodeClass(2):
print("{}: {}".format(
child.nodeid.to_string(),
child.get_description().to_string()))
SUB.subscribe_data_change(child)
print("Setup done; sleep 10 Seconds")
time.sleep(10)
SUB.delete()
finally:
CLIENT.disconnect()
Reflexion
Nach der Durchführung der Onlineübung sind Sie in der Lage mit den Laboren zu interagieren.
Sie haben die Grundlagen des Kommunikationsprotokolles kennen gelernt und einige der wichtigsten Funktionen bereits ausprobiert.
Sie sind damit in der Lage …
- … grundlegend mit dem industriellen Kommunikationsprotokoll OPC UA umzugehen.
- … auszulesen, welche Informationen auf einem Server verfügbar sind.
- … einzelne Informationspunkte gezielt auszulesen.
- … sich bei Änderung von ausgewählten Daten benachrichtigen zu lassen.
- … Funktionen auf dem entfernten Server ausführen zu lassen.
Selbstevaluierung
Welches Attribut ist für jeden Node einzigartig?
Die NodeID ist für jeden Node einzigartig!
Aus welchen Elementen setzt sich die NodeID zusammen?
Die NodeID besitzt zwei Elemente: Namespace und Identifier
Welche Informationen beinhaltet das NodeID-Beispiel ns=2;b=aGVsbG8gd29ybGQ=?
Es kann einerseits der Namespace-Index 2 entnommen werden.
Andererseits ist der Identifier angegeben, welcher im Base64-Format vorliegt.
Das Base64-Format wird durch den Identifier-Typ b angegeben.Anmerkung: Der Inhalt des Identifiers kann in diesem Fall durch Online-Tools in einen für Menschen lesbaren Text umgewandelt werden!
Wofür wird die Node-Klasse VariableType verwendet?
VariableType wird verwendet, um einem Datenelement eine Bedeutung zu geben.
Dadurch kann das Datenelement interpretiert werden.
Welche Bestandteile besitzt eine Referenz?
Eine Referenz besitzt immer folgende drei Bestandteile: Quelle, Ziel und Referenztyp
Wozu werden Subscriptions verwendet?
Subscriptions dienen in Kombination mit Monitored Items zur Überwachung von Nodes.
Dadurch können Daten von ausgewählten Nodes periodisch und unter definierten Umständen Änderungen des Nodes gesendet werden.
Welche Verschlüsselungsarten existieren, um die Kommunikation zwischen Server und Client zu verschlüsseln?
- None - Die Kommunikation wird nicht verschlüsselt.
- Basic128RSA15
- Basic256
Take-Home-Messages
- Jeder Node wird durch seine NodeID eindeutig beschreiben
- Durch Node-Klasse eiens Nodes wird definiert, welche zusätzlichen Informationen verfügbar sind
- Die Node-Klasse Object dient zur Erzeugung weiterer (Sub-)Systeme
- Die Node-Klasse Variable wird verwendet, um einem Node einen Inhalt zu geben
- Die Node-Klasse Methods beschreibt auf dem Server ausführbare Funktionen
- Referenzen werden verwendet, um Nodes miteinander in Beziehung zu setzen
- Subscriptions und Monitored Items dienen zur Überwachung von Nodes
Links und Literaur
- Erklärung OPC-UA
- Erklärung OPC
- OPC-UA-Bibliothek C/C++
- OPC-UA-Bibliothek Python
- OPC-UA-Bibliothek Node.js
- OPC-UA-Bibliothek Matlab
- Base64-Kodierung
- Extensible Markup Language (XML)
- Installationsanleitung OPC-UA-Bibliothek in Python
- Python OPC-UA Dokumentation
Weiterführende Themengebiete
- Client-Side Node Management
- Server-Implementierung
- Datenmodellierung