# Ereignisse

> Anleitung: Globale Ereignisse veröffentlichen und lokale Ereignisse über Ereignis-Nodes bereitstellen.

**Beispielanwendungen:**

- Server.EventTypes ([C#](https://github.com/Traeger-GmbH/opcuanet-samples/tree/master/cs/Basic/Server.EventTypes), [VB.NET](https://github.com/Traeger-GmbH/opcuanet-samples/tree/master/vb/Basic/Server.EventTypes)): Stellt einen eigenen Ereignistyp aus einem NodeSet bereit; ein Methodenaufruf durch den Client löst Ereignisse mit strukturierten Daten aus.
- Server.LightweightEvents ([C#](https://github.com/Traeger-GmbH/opcuanet-samples/tree/master/cs/Scenarios/Server.LightweightEvents), [VB.NET](https://github.com/Traeger-GmbH/opcuanet-samples/tree/master/vb/Scenarios/Server.LightweightEvents)): Verwendet einen einzigen Ereignis-Node für Ereignisse verschiedener Quellen, statt je Quelle einen eigenen Ereignis-Node anzulegen.
- Client.EventTypes ([C#](https://github.com/Traeger-GmbH/opcuanet-samples/tree/master/cs/Basic/Client.EventTypes), [VB.NET](https://github.com/Traeger-GmbH/opcuanet-samples/tree/master/vb/Basic/Client.EventTypes)): Abonniert Ereignisse eines eigenen Ereignistyps und liest ihre strukturierten Ereignisdaten über eine eigene Ereignisklasse.

Diese Seite zeigt, wie ein Server mit dem OPC UA .NET SDK Ereignisse (Alarm & Events) sendet. Ereignisse mit Bedingungen und Alarme beschreibt die Seite [Alarme und Bedingungen](https://www.traeger.de/docs/development/opcua/server/alarms-conditions).

## Globale Ereignisse senden

Beteiligte Typen: `OpcServer`, `OpcNodeManager`, `OpcEventSeverity`, `OpcText`

Ereignisse informieren einen Abonnenten über Abläufe, Zustände und systemspezifische Begebenheiten. Der Server kann solche Informationen über **globale Ereignisse** direkt an Interessenten zustellen. Ein globales Ereignis lösen Sie entweder über eine Instanz von `OpcNodeManager` oder über eine Instanz von `OpcServer` aus. Dafür bietet das SDK mehrere Überladungen der Methode `ReportEvent`. Die Überladungen von `OpcServer` setzen einen gestarteten Server voraus.

Ein globales Ereignis lösen Sie über eine Instanz von `OpcServer` auf die folgenden Arten aus:

```csharp
var server = new OpcServer(...);
// ...

server.ReportEvent(
        OpcEventSeverity.Medium,
        "Recognized a medium urgent situation.");

// Same usage as before + arguments support.
server.ReportEvent(
        OpcEventSeverity.Medium,
        "Recognized a medium urgent situation at machine {0}.",
        machineId);

// Sames usage as before + source node.
server.ReportEvent(
        sourceNode,
        OpcEventSeverity.Medium,
        "Recognized a medium urgent situation.");

// Same usage as before + arguments support.
server.ReportEvent(
        sourceNode,
        OpcEventSeverity.Medium,
        "Recognized a medium urgent situation at machine {0}.",
        machineId);

// Same usage as before + explicit source information.
server.ReportEvent(
        sourceNodeId,
        sourceNodeName,
        OpcEventSeverity.Medium,
        "Recognized a medium urgent situation.");

// Same usage as before + arguments support.
server.ReportEvent(
        sourceNodeId,
        sourceNodeName,
        OpcEventSeverity.Medium,
        "Recognized a medium urgent situation at machine {0}.",
        machineId);
		
```

```vbnet
Dim server As New OpcServer(...)
' ...

server.ReportEvent( _
        OpcEventSeverity.Medium, _
        "Recognized a medium urgent situation.")

' Same usage as before + arguments support.
server.ReportEvent( _
        OpcEventSeverity.Medium, _
        "Recognized a medium urgent situation at machine {0}.", _
        machineId)

' Same usage as before + source node.
server.ReportEvent( _
        sourceNode, _
        OpcEventSeverity.Medium, _
        "Recognized a medium urgent situation.")

' Same usage as before + arguments support.
server.ReportEvent( _
        sourceNode, _
        OpcEventSeverity.Medium, _
        "Recognized a medium urgent situation at machine {0}.", _
        machineId)

' Same usage as before + explicit source information.
server.ReportEvent( _
        sourceNodeId, _
        sourceNodeName, 
        OpcEventSeverity.Medium, _
        "Recognized a medium urgent situation.")

' Same usage as before + arguments support.
server.ReportEvent( _
        sourceNodeId, _
        sourceNodeName, _
        OpcEventSeverity.Medium, _
        "Recognized a medium urgent situation at machine {0}.", _
        machineId)

```

Dieselben Überladungen bietet auch `OpcNodeManager` als Instanzmethoden. Zusätzlich nimmt die Methode `ReportEvent` dort einen Ereignis-Node entgegen (siehe [Ereignisse an einem Node bereitstellen](https://www.traeger.de/docs/development/opcua/server/events#ereignisse-an-einem-node-bereitstellen)). Sie übernimmt dessen Änderungen und versendet ihn als Ereignis:

```csharp
// Applies the changes of the event node and sends the event to all subscribers.
server.ReportEvent(activatedEvent);
```

```vbnet
'Applies the changes of the event node and sends the event to all subscribers.
server.ReportEvent(activatedEvent)
```

## Ereignisse an einem Node bereitstellen

Beteiligte Typen: `OpcServer`, `OpcNodeManager`, `OpcEventNode`

Nicht immer ist es zweckmäßig, Ereignisse global über den Server an alle Abonnenten zu senden. Oft entscheidet der Kontext, ob ein Ereignis für einen Abonnenten von Interesse ist. Für solche lokalen Ereignisse dienen Ereignis-Nodes.
Die Basisklasse aller Ereignis-Nodes ist die Klasse `OpcEventNode`. Mit ihr stellen Sie einfache Ereignisse, wie sie der Abschnitt [Globale Ereignisse senden](https://www.traeger.de/docs/development/opcua/server/events#globale-ereignisse-senden) zeigt, als lokale Ereignisse bereit.

Da der Ereignis-Node (`OpcEventNode`) ein Node ist, legen Sie ihn zuerst wie jeden anderen Node im `OpcNodeManager` an:

```csharp
var activatedEvent = new OpcEventNode(machineOne, "Activated");

```

```vbnet
Dim activatedEvent As New OpcEventNode(machineOne, "Activated")

```

Damit der Ereignis-Node ein Ereignis senden kann, definieren Sie ihn als „Benachrichtiger“ (engl. Notifier). Tragen Sie den Ereignis-Node dazu bei jedem Node als „Benachrichtiger“ ein, über den eine Subscription das lokale Ereignis empfangen soll:

```csharp
machineOne.AddNotifier(this.SystemContext, activatedEvent);

```

```vbnet
machineOne.AddNotifier(Me.SystemContext, activatedEvent)

```

Bevor Sie ein Ereignis auslösen, tragen Sie alle für das Ereignis relevanten Informationen auf dem Ereignis-Node ein. Welche Informationen Sie ändern und wie Sie sie festlegen, hängt vom Anwendungsfall ab. Im Allgemeinen sieht das so aus:

```csharp
activatedEvent.SourceNodeId = sourceNodeId;
activatedEvent.SourceName = sourceNodeName;
activatedEvent.Severity = OpcEventSeverity.Medium;
activatedEvent.Message = "Recognized a medium urgent situation.";

```

```vbnet
activatedEvent.SourceNodeId = sourceNodeId
activatedEvent.SourceName = sourceNodeName
activatedEvent.Severity = OpcEventSeverity.Medium
activatedEvent.Message = "Recognized a medium urgent situation."

```

Der Ereignis-Node `OpcEventNode` bietet außerdem weitere Eigenschaften:

```csharp
// Server generated value to identify a specific Event
activatedEvent.EventId = ...;

// The time the event occured
activatedEvent.Time = ...;

// The time the event has been received by the underlaying system / device
activatedEvent.ReceiveTime = ...;

```

```vbnet
' Server generated value to identify a specific Event
activatedEvent.EventId = ...

' The time the event occured
activatedEvent.Time = ...

' The time the event has been received by the underlaying system / device
activatedEvent.ReceiveTime = ...

```

Wenn das Ereignis konfiguriert ist, rufen Sie die Methode `ReportEvent` des Ereignis-Nodes auf:

```csharp
activatedEvent.ReportEvent(this.SystemContext);

```

```vbnet
activatedEvent.ReportEvent(Me.SystemContext)

```

Die Methode ruft automatisch `ApplyChanges` auf dem Node auf, erzeugt eine Momentaufnahme (engl. Snapshot) des Nodes und sendet diese an alle Abonnenten. Wenn das Ereignis über einen anderen Node als Quelle gemeldet werden soll, verwenden Sie die Methode `ReportEventFrom`. Nach dem Aufruf von `ReportEvent` können Sie die Eigenschaften des Ereignis-Nodes beliebig weiter ändern.

Ein Abonnent erfährt nur von Ereignissen, solange er mit dem Server verbunden ist und eine Subscription angelegt hat. Er weiß deshalb nicht, welche Ereignisse schon vor dem Verbindungsaufbau aufgetreten sind. Wenn ein Abonnent den aktuellen Stand anfordert (zum Beispiel über einen ConditionRefresh), kann der Server ihm die betreffenden Ereignisse so bereitstellen:

```csharp
machineOne.QueryEventsCallback = (context, events) => {
    // Ensure that an re-entrance upon notifier cross-references will not add
    // events to the collection which are already stored in.
    if (events.Count != 0)
        return;
 
    events.Add(activatedEvent.CreateEvent(context));
};

```

```vbnet
machineOne.QueryEventsCallback = Sub(context, events)
    'Ensure that an re-entrance upon notifier cross-references will not add
    'events to the collection which are already stored in.
    If events.Count <> 0 Then
        Return
    End If

    events.Add(activatedEvent.CreateEvent(context))
End Sub
```

Jeder Node, unter dem ein Ereignis-Node als „Benachrichtiger“ eingetragen ist, muss einen solchen Callback separat festlegen. Der Server ist allerdings **nicht verpflichtet**, vergangene Ereignisse bereitzustellen. Außerdem können Sie jederzeit mit der Methode `CreateEvent` des Ereignis-Nodes eine Momentaufnahme des Nodes anlegen und zwischenspeichern. Die zwischengespeicherten Momentaufnahmen stellen Sie dann beim Aufruf des `QueryEventsCallback` bereit. Bedingungen, deren Eigenschaft `IsRetained` gesetzt ist, meldet das SDK bei einem ConditionRefresh auch ohne `QueryEventsCallback` automatisch.

Damit Clients vergangene Ereignisse über einen Zeitraum abfragen können (HistoryRead für Ereignisse), stellt der Server eine Ereignis-Historie bereit. Wie das geht, beschreibt der Abschnitt [Ereignis-Historie bereitstellen](https://www.traeger.de/docs/development/opcua/server/historical-data#ereignis-historie-bereitstellen).
