Zum Inhalt springen

Anleitung

Ereignisse

Ereignisse eines Servers empfangen, filtern und auswerten, mit Ereignis-Nodes arbeiten und Audit-Ereignisse empfangen.

Anleitung

Ereignisse ​

Diese Seite zeigt, wie ein Client Ereignisse (Alarm & Events) eines Servers empfängt, filtert und auswertet. Ereignisse mit Bedingungen und Alarme beschreibt die Seite Alarme und Bedingungen.

Beteiligte TypenOpcClientOpcObjectTypesOpcEventTypesOpcEventReceivedEventArgsOpcEventOpcAlarmConditionOpcSimpleAttributeOperandOpcFilterOpcEventFilterOpcEventSeverity

Globale Ereignisse empfangen ​

Ereignisse informieren einen Abonnenten, zum Beispiel einen Client, über Abläufe, Zustände und systemspezifische Begebenheiten. Über globale Ereignisse erhalten Abonnenten solche Informationen direkt. Ein Server veröffentlicht ein globales Ereignis immer über sein Server-Objekt. Deshalb abonniert der Client globale Ereignisse auch über diesen Node:

csharp
client.SubscribeEvent(OpcObjectTypes.Server, HandleGlobalEvents);
vbnet
client.SubscribeEvent(OpcObjectTypes.Server, AddressOf HandleGlobalEvents)

Ein Ereignis behandeln Sie in der Regel mit einer Methode dieser Signatur:

csharp
private static void HandleGlobalEvents(
        object sender,
        OpcEventReceivedEventArgs e)
{
    Console.WriteLine(e.Event.Message);
}
vbnet
Private Shared Sub HandleGlobalEvents( _
        ByVal sender As Object, _
        ByVal e As OpcEventReceivedEventArgs)
    Console.WriteLine(e.Event.Message)
End Sub

Die Eigenschaft Event der Ereignisargumente (Klasse OpcEventReceivedEventArgs) liefert die empfangenen Ereignisdaten. Sie liefert immer eine Instanz der Klasse OpcEvent. Wenn die Ereignisdaten zu einer Spezialisierung der Klasse OpcEvent gehören, casten Sie sie einfach:

csharp
private static void HandleGlobalEvents(
        object sender,
        OpcEventReceivedEventArgs e)
{
    var alarm = e.Event as OpcAlarmCondition;
 
    if (alarm != null)
        Console.WriteLine("Alarm: " + alarm.Message);
}
vbnet
Private Shared Sub HandleGlobalEvents( _
        ByVal sender As Object, _
        ByVal e As OpcEventReceivedEventArgs)
    Dim alarm = TryCast(e.Event, OpcAlarmCondition)

    If alarm IsNot Nothing Then
        Console.WriteLine("Alarm: " & alarm.Message.Value)
    End If
End Sub

Ereignisse filtern ​

Der Aufruf oben abonniert alle Ereignisse, die der Server global veröffentlicht. Mit einem Ereignisfilter (engl. EventFilter) schränken Sie die erhaltenen Informationen ein und auch die Ereignisse, die der Server überhaupt an den Client sendet. Der Client übermittelt den Filter beim Anlegen der Subscription an den Server:

csharp
// Define an attribute operand using the identifier of the type which defines the
// attribute / property including the name of the attribute / property to evaluate
// by the operand.
var severity = new OpcSimpleAttributeOperand(OpcEventTypes.Event, "Severity");
var conditionName = new OpcSimpleAttributeOperand(OpcEventTypes.Condition, "ConditionName");
 
var filter = OpcFilter.Using(client)
        .FromEvents(OpcEventTypes.AlarmCondition)
        .Where(severity > OpcEventSeverity.Medium & conditionName.Like("Temperature"))
        .Select();
 
client.SubscribeEvent(
        OpcObjectTypes.Server,
        filter,
        HandleGlobalEvents);
vbnet
'Define an attribute operand using the identifier of the type which defines the
'attribute / property including the name of the attribute / property to evaluate
'by the operand.
Dim severity = New OpcSimpleAttributeOperand(OpcEventTypes.Event, "Severity")
Dim conditionName = New OpcSimpleAttributeOperand(OpcEventTypes.Condition, "ConditionName")

Dim filter = OpcFilter.Using(client) _
        .FromEvents(OpcEventTypes.AlarmCondition) _
        .Where(severity > OpcEventSeverity.Medium And conditionName.Like("Temperature")) _
        .Select()

client.SubscribeEvent(
        OpcObjectTypes.Server,
        filter,
        AddressOf HandleGlobalEvents)

Um einen Ereignisfilter zu erstellen, benötigen Sie immer eine Instanz von OpcClient, die bereits mit dem Zielserver verbunden ist. Beim Zusammenstellen des Filters ruft der Client nämlich die relevanten Typinformationen vom Server ab. Im Beispiel oben sammelt der Client so alle Eigenschaften des Node-Typs OpcAlarmConditionNode rekursiv bis zum OpcNode. Anhand der Where- und Select-Klauseln erstellt er daraus Regeln für die Auswahl der Ereignisdaten. Die zu analysierenden Node-Typen übergeben Sie durch Komma getrennt an die Methode FromEvents:

csharp
var severity = new OpcSimpleAttributeOperand(OpcEventTypes.Event, "Severity");
var conditionName = new OpcSimpleAttributeOperand(OpcEventTypes.Condition, "ConditionName");
 
var filter = OpcFilter.Using(client)
        .FromEvents(
            OpcEventTypes.AlarmCondition,
            OpcEventTypes.ExclusiveLimitAlarm,
            OpcEventTypes.DialogCondition)
        .Where(severity > OpcEventSeverity.Medium & conditionName.Like("Temperature"))
        .Select();
 
client.SubscribeEvent(
        OpcObjectTypes.Server,
        filter,
        HandleGlobalEvents);
vbnet
Dim severity = New OpcSimpleAttributeOperand(OpcEventTypes.Event, "Severity")
Dim conditionName = New OpcSimpleAttributeOperand(OpcEventTypes.Condition, "ConditionName")

Dim filter = OpcFilter.Using(client) _
        .FromEvents( _
            OpcEventTypes.AlarmCondition, _
            OpcEventTypes.ExclusiveLimitAlarm, _
            OpcEventTypes.DialogCondition) _
        .Where(severity > OpcEventSeverity.Medium And conditionName.Like("Temperature")) _
        .Select()

client.SubscribeEvent(
        OpcObjectTypes.Server,
        filter,
        AddressOf HandleGlobalEvents)

Mit der Methode Where schränken Sie die von FromEvents gesammelten Informationen über die Eigenschaften der Node-Typen ein. Dafür bietet das SDK verschiedene Operatorüberladungen (<=, <, >, >= und ==). Der Operator != löst eine NotSupportedException aus. Verwenden Sie stattdessen (a < b) | (a > b). Um Operanden logisch zu kombinieren, stehen außerdem die Operatoren ODER (|) und UND (&) bereit. Für weitere Einschränkungen gibt es Methoden wie Like, Between, InList, IsNull, Not, OfType, Cast und InView. Für Sprachen ohne diese Operatoren (wie Visual Basic) stehen die gleichwertigen Methoden EqualsTo, GreaterThan, GreaterThanOrEqualsTo, LessThan und LessThanOrEqualsTo bereit.

Ab Version 2.59 erwartet Between die Operanden in der Reihenfolge von OPC UA: a.Between(lower, upper) prüft, ob a zwischen lower und upper liegt. Mehrere Where-Aufrufe hintereinander verknüpfen ihre Bedingungen ab Version 2.59 mit UND, wie ein einzelnes Where mit &. In älteren Versionen gilt nur die Bedingung des letzten Aufrufs.

Danach wählen Sie mit der Methode Select die Eigenschaften aus, die der Server zusätzlich an den Client überträgt. Das geschieht, wenn ein Ereignis eintritt, das den Bedingungen aus Where entspricht.

Das folgende Beispiel abonniert alle Ereignisse, die aktuell aktiv, aber noch nicht bestätigt sind:

csharp
var isActive = new OpcSimpleAttributeOperand(
        OpcEventTypes.AlarmCondition,
        "ActiveState", "Id");
var isAcked = new OpcSimpleAttributeOperand(
        OpcEventTypes.AcknowledgeableCondition,
        "AckedState", "Id");

var filter = OpcFilter.Using(client)
    .FromEvents(OpcEventTypes.AlarmCondition)
    .Where(OpcFilterOperand.OfType(OpcEventTypes.AlarmCondition)
        & isAcked == false
        & isActive == true)
    .Select();

var subscription = client.SubscribeEvent("ns=2;s=Machine", filter, (sender, e) => {
    if (e.Event is OpcAlarmCondition alarm) {
        Console.WriteLine(
                "{0}: {1}, IsActive = {2}, IsAcked = {3} ({4})",
                alarm.GetType().Name,
                alarm.Message,
                alarm.IsActive,
                alarm.IsAcked,
                alarm.Severity);
    }
});
vbnet
Dim isActive = New OpcSimpleAttributeOperand( _
        OpcEventTypes.AlarmCondition, _
        "ActiveState", "Id")
Dim isAcked = New OpcSimpleAttributeOperand( _
        OpcEventTypes.AcknowledgeableCondition, _
        "AckedState", "Id")

Dim filter = OpcFilter.Using(client) _
    .FromEvents(OpcEventTypes.AlarmCondition) _
    .Where(OpcFilterOperand.OfType(OpcEventTypes.AlarmCondition) _
        And isAcked = False _
        And isActive = True) _
    .Select()

Dim subscription = client.SubscribeEvent("ns=2;s=Machine", filter, _
    Sub(sender, e)
        Dim alarm = TryCast(e.Event, OpcAlarmCondition)

        If alarm IsNot Nothing Then
            Console.WriteLine( _
                    "{0}: {1}, IsActive = {2}, IsAcked = {3} ({4})", _
                    alarm.GetType().Name, alarm.Message, alarm.IsActive, alarm.IsAcked, alarm.Severity)
        End If
    End Sub)

Ereignisse eines Nodes empfangen ​

Beteiligte TypenOpcClientOpcEventReceivedEventArgsOpcEventOpcSubscription

Es ist nicht immer sinnvoll, dass ein Server Ereignisse durchweg global über das Server-Objekt an alle Abonnenten sendet. Oft entscheidet der Kontext, ob ein Ereignis für einen Abonnenten von Interesse ist. Für solche lokalen Ereignisse gibt es Ereignis-Nodes. Wenn der Server einen Ereignis-Node verwendet, um Ereignisdaten für einen Node bereitzustellen, ist der Ereignis-Node ein sogenannter Benachrichtiger (engl. Notifier) des Nodes. Ein HasNotifier-Verweis zeigt deshalb, welcher Ereignis-Node Ereignisdaten an einen Node meldet. Ein Ereignis-Node kann Benachrichtiger für mehrere Nodes sein. Deshalb abonniert der Client lokale Ereignisse immer über die benachrichtigten Nodes:

csharp
client.SubscribeEvent(machineNodeId, HandleLocalEvents);
vbnet
client.SubscribeEvent(machineNodeId, AddressOf HandleLocalEvents)

Ein Ereignis behandeln Sie in der Regel mit einer Methode dieser Signatur. Die weitere Verarbeitung der Ereignisdaten entspricht der Verarbeitung globaler Ereignisse (siehe Abschnitt Globale Ereignisse empfangen).

csharp
private static void HandleLocalEvents(
        object sender,
        OpcEventReceivedEventArgs e)
{
    Console.WriteLine(e.Event.Message);
}
vbnet
Private Shared Sub HandleLocalEvents( _
        ByVal sender As Object, _
        ByVal e As OpcEventReceivedEventArgs)
    Console.WriteLine(e.Event.Message)
End Sub

Auch lokale Ereignisse können Sie filtern, wie im Abschnitt Ereignisse filtern gezeigt.

Ein Abonnent (ein Client) erfährt nur von Ereignissen, solange er mit dem Server verbunden ist und eine Subscription angelegt hat. Nach dem Verbindungsaufbau kennt er deshalb den aktuellen Zustand der Bedingungen des Servers nicht (siehe Alarme und Bedingungen). Mit dem folgenden Aufruf fordert er diesen Zustand an. Der Server sendet daraufhin für alle Bedingungen, die sich aktuell in einem relevanten Zustand befinden (IsRetained ist true), erneut ein Ereignis. Vergangene Ereignisse liefert dieser Aufruf nicht. Wenn der Server sie bereitstellt, liest der Client sie über die Ereignis-Historie, siehe Ereignis-Historie lesen.

csharp
var subscription = client.SubscribeEvent(
        machineNodeId,
        HandleLocalEvents);
 
// Query most recent event information.
subscription.RefreshConditions();
vbnet
Dim subscription = client.SubscribeEvent( _
        machineNodeId, _
        AddressOf HandleLocalEvents)
 
'Query most recent event information.
subscription.RefreshConditions()

Audit-Ereignisse empfangen ​

Beteiligte TypenOpcClientOpcFilterOpcEventFilterOpcObjectTypesOpcEvent

Audit-Ereignisse protokollieren sicherheitsrelevante Aktionen eines Servers. Ein mit dem SDK entwickelter Server meldet sie über das Server-Objekt, sofern das Auditing im Server eingeschaltet ist (siehe Audit-Ereignisse). Er meldet sie beim Öffnen und Schließen eines sicheren Kanals (AuditOpenSecureChannelEventType, AuditChannelEventType) sowie beim Erstellen (AuditCreateSessionEventType) und beim Aktivieren (AuditActivateSessionEventType) einer Sitzung. Wie in OPC UA festgelegt, erhält ein Client sie nur über einen Endpunkt mit dem Modus SignAndEncrypt oder über HTTPS und nur, wenn der angemeldete Benutzer der Rolle SecurityAdmin angehört. Ein Client abonniert sie wie andere Ereignisse über einen Filter auf die Ereignistypen, im folgenden Beispiel auf die beiden Ereignistypen der Sitzung:

csharp
OpcEventFilter filter = OpcFilter.Using(client)
        .FromEvents(
                OpcObjectTypes.GetNodeId(OpcObjectType.AuditCreateSessionEventType),
                OpcObjectTypes.GetNodeId(OpcObjectType.AuditActivateSessionEventType))
        .Select();
 
client.SubscribeEvent(OpcObjectTypes.Server, filter, HandleAuditEvent);
...
private static void HandleAuditEvent(
        object sender,
        OpcEventReceivedEventArgs e)
{
    OpcEvent audit = e.Event;
 
    Console.WriteLine(
            "{0:u} {1} {2}: {3}",
            audit.Time,
            audit.EventTypeId,
            audit.SourceName,
            audit.Message);
}
vbnet
Dim filter As OpcEventFilter = OpcFilter.Using(client) _
        .FromEvents( _
                OpcObjectTypes.GetNodeId(OpcObjectType.AuditCreateSessionEventType), _
                OpcObjectTypes.GetNodeId(OpcObjectType.AuditActivateSessionEventType)) _
        .Select()

client.SubscribeEvent(OpcObjectTypes.Server, filter, AddressOf HandleAuditEvent)
...
Private Shared Sub HandleAuditEvent( _
        ByVal sender As Object, _
        ByVal e As OpcEventReceivedEventArgs)
    Dim audit As OpcEvent = e.Event

    Console.WriteLine( _
            "{0:u} {1} {2}: {3}", _
            audit.Time, _
            audit.EventTypeId, _
            audit.SourceName, _
            audit.Message)
End Sub

Der Client kann die allgemeinen Felder eines Ereignisses lesen, zum Beispiel Time, EventTypeId, SourceName und Message. Die besonderen Felder der Audit-Ereignisse, etwa die Identität des Benutzers oder die Kennung der Sitzung, stellt das SDK im Client nicht bereit.