Verbesserte Event-API in open62541 v1.5
Bessere Ergonomie für den leistungsfähigen OPC-UA-Eventmechanismus

Einführung
Events sind eine leistungsfähige OPC-UA-Funktion und bieten gegenüber der Überwachung von Datenänderungen mehrere Vorteile:
- Kein Abtastintervall erforderlich
- Umfangreiche, strukturierte Nutzdaten anstelle einzelner Werte
- Starke Semantik durch EventTypes
- Weiterleitung und Aggregation innerhalb der Hierarchie des Informationsmodells
- Integrierte serverseitige Filterung zur Reduzierung des Netzwerkverkehrs
Trotz dieser Vorteile werden Events aufgrund ihrer vermeintlichen Komplexität häufig zu wenig genutzt. In Version 1.5 des open62541-SDKs haben wir uns deshalb darauf konzentriert, die Benutzerfreundlichkeit und Ergonomie der Event-API deutlich zu verbessern. Dieser Artikel stellt die wichtigsten Neuerungen auf Client- und Serverseite vor.
Menschenlesbare Syntax für Event-Felder
Die aus den Event-Feldern bestehende Event-Nutzlast wird durch EventTypes definiert. Dabei handelt es sich um spezialisierte ObjectTypes innerhalb des OPC-UA-Informationsmodells. Viele Companion Specifications definieren eigene EventTypes für ihren Anwendungsbereich. So definiert beispielsweise die AutoID Companion Specification EventTypes für die Erkennung von Barcodes und RFID-Tags.
Die folgende Abbildung gibt einen Überblick über die standardmäßigen Event-Felder des BaseEventType. Diese Felder sind immer verfügbar und bilden die Grundlage für alle Events.
/EventId: ByteString to uniquely identify the event instance
/EventType: NodeId of the EventType
/SourceNode: NodeId of the emitting node
/SourceName: LocalizedText with the DisplayName of the source node
/Time: DateTime with the timestamp when the event occurred
/ReceiveTime: DateTime when the server received the information about the event
/Message: LocalizedText with a human-readable description of the event
/Severity: UInt16 for the urgency of the event between 1 (lowest) and 1000 (catastrophic)Auf der Clientseite werden die relevanten Event-Felder über die Select-Klausel eines EventFilters ausgewählt. Diese Klausel besteht aus SimpleAttributeOperand-Einträgen, also BrowsePaths, die um Metadaten zu Attributen und Indexbereichen ergänzt sind.
Mit v1.5 haben wir eine kompakte und menschenlesbare Syntax zur Definition dieser Operanden eingeführt. Statt umfangreicher Strukturen lassen sich Event-Felder nun als einfache Pfadzeichenfolgen ausdrücken.
Zum Beispiel:
- /1:Robot/2:Axis1/2:Angle
- /2:Line/2:VisualInspection/3:Camera/3:CapturedImage#Value[0:100,0:100]
Die Knoten des EventType werden über ihren BrowseName adressiert, optional mit einem durch einen Doppelpunkt getrennten Präfix für den Namespace-Index. Schrägstriche trennen die Hierarchieebenen. Ausführliche Informationen finden Sie in der open62541-Dokumentation und in unserem ETFA-2024-Paper über Event-Filter.
Diese Darstellung wird nun einheitlich in den Client- und Server-APIs verwendet. Dadurch entsteht ein gemeinsames Modell für Definition, Übertragung und Verarbeitung von Event-Daten.
Clientseite: Event-Überwachung registrieren
Die Registrierung der Event-Überwachung auf der Clientseite wurde erheblich vereinfacht. Zuvor waren zum Aufbau der Select-Klausel mehrere Zeilen Boilerplate-Code erforderlich. Mit v1.5 kann die gesamte Klausel direkt aus einer einzigen menschenlesbaren Zeichenfolge erzeugt werden.
/* EventFilter */
typedef struct {
size_t selectClausesSize;
UA_SimpleAttributeOperand *selectClauses;
UA_ContentFilter whereClause;
} UA_EventFilter;
/* Parse Event-Field Description for the Select-Clause */
UA_StatusCode
UA_SimpleAttributeOperand_parse(UA_SimpleAttributeOperand *sao,
const UA_String input);
/* Callback for Event Notifications */
typedef void (*UA_Client_EventNotificationCallback)
(UA_Client *client, UA_UInt32 subId, void *subContext,
UA_UInt32 monId, void *monContext,
const UA_KeyValueMap eventFields);
/* Register for Event Monitoring */
UA_MonitoredItemCreateResult
UA_Client_MonitoredItems_createEvent(UA_Client *client,
UA_UInt32 subscriptionId,
const UA_MonitoredItemCreateRequest item,
void *context, UA_Client_EventNotificationCallback callback,
UA_Client_DeleteMonitoredItemCallback deleteCallback);Sobald die Überwachung aktiv ist, sendet der Server Event-Benachrichtigungen an den Client. Diese werden an einen benutzerdefinierten Callback übergeben. Wie im obigen Codeausschnitt zu sehen ist, kommen die Event-Felder im Callback als Key-Value-Map an. Die Schlüssel entsprechen der menschenlesbaren Syntax des jeweiligen Event-Feldes. Gleichzeitig bleibt die Reihenfolge der Event-Felder aus der ursprünglichen Select-Klausel erhalten, sodass weiterhin ein ressourceneffizienter indizierter Zugriff möglich ist. Dieses doppelte Zugriffsmuster – über Schlüssel oder Index – verbindet Lesbarkeit und Performance.
Serverseitige Event-Erzeugung in open62541
Auf der Serverseite wurde die Event-Erzeugung in der Funktion UA_Server_createEvent zu einer einzigen ausdrucksstarken API zusammengeführt. Auch diese Funktion nutzt die menschenlesbare Syntax für Event-Felder.
/* Create an event in the server. It gets filtered and sent to the
* monitoring clients, as well as locally registered callbacks. */
UA_StatusCode
UA_Server_createEvent(UA_Server *server, const UA_NodeId sourceNode,
const UA_NodeId eventType, UA_UInt16 severity,
const UA_LocalizedText message,
const UA_KeyValueMap *eventFields,
const UA_NodeId *eventInstance,
UA_ByteString *outEventId);Beim Erzeugen eines Events können Feldwerte aus vier Quellen stammen:
- Inline (verpflichtend): Die wichtigsten Event-Felder werden direkt im Aufruf von UA_Server_createEvent übergeben.
- Feld-Map (optional): Die Key-Value-Map im Argument eventFields ordnet menschenlesbare Definitionen der Event-Felder ihren jeweiligen Variant-Werten zu.
- Event-Instanz (optional): Kann ein Event-Feld über die vorherigen Quellen nicht aufgelöst werden, verweist das Argument eventInstance auf einen ObjectNode im Informationsmodell. In der Regel instanziiert dieses Objekt den EventType des Events. Der Server verwendet dann die Member dieses Objekts, um den Inhalt der Event-Felder aufzulösen.
- Standardwerte (intern): Bleiben verpflichtende Felder des BaseEventType nach den vorherigen Quellen undefiniert, werden intern Standardwerte erzeugt. Beispielsweise wird das Feld /Time auf die aktuelle Uhrzeit gesetzt und für das eindeutige Feld /EventId wird ein zufälliger ByteString verwendet.
Dieses mehrstufige Auflösungsmodell schafft Flexibilität und bleibt zugleich übersichtlich.
Zusammenfassung
OPC-UA-Events sind ein ausdrucksstarker und effizienter Mechanismus zur Übermittlung strukturierter Informationen. Mit Version 1.5 senkt die open62541-API die Einstiegshürde deutlich durch:
- Einführung einer menschenlesbaren Feldsyntax
- Vereinfachung der clientseitigen Filterkonstruktion
- Strukturierte und intuitive Callback-Daten
- Vereinheitlichung und Vereinfachung der serverseitigen Event-Erzeugung
Diese Verbesserungen machen Event-basierte Architekturen für reale Anwendungen leichter zugänglich und praxistauglicher.