# Events

> How-to guide: Publish global events from the server and provide local events through event nodes.

> This content was machine translated and may contain errors. [Read in German](https://www.traeger.de/docs/development/opcua/server/events)

**Sample applications:**

- 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)): This sample demonstrates how to setup an OPC UA server to provide a custom event type defined in a nodeset. Its events carry structured data and are raised when a client calls the StartJob method.
- 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)): This use case demonstrates in which way a server can "re-use" a single event node to represent events from different event sources without to define for each source another event node.
- 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)): This sample demonstrates how to subscribe to events of a custom event type and how to access their structured event data through an own event class.

This page shows how a server sends events (Alarms & Events) with the OPC UA .NET SDK. The [Alarms and conditions](https://www.traeger.de/en/docs/development/opcua/server/alarms-conditions) page describes events with conditions and alarms.

## Send global events

Types used: `OpcServer`, `OpcNodeManager`, `OpcEventSeverity`, `OpcText`

Events inform a subscriber about processes, states, and system-specific occurrences. The server can deliver such information directly to interested parties through **global events**. You raise a global event either through an instance of `OpcNodeManager` or through an instance of `OpcServer`. For this, the SDK provides several overloads of the `ReportEvent` method. The overloads of `OpcServer` require a started server.

You raise a global event through an instance of `OpcServer` in the following ways:

```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)

```

`OpcNodeManager` provides the same overloads as instance methods. In addition, its `ReportEvent` method accepts an event node (see [Provide events on a node](https://www.traeger.de/en/docs/development/opcua/server/events#provide-events-on-a-node)). It applies the changes of the node and sends it as an event:

```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)
```

## Provide events on a node

Types used: `OpcServer`, `OpcNodeManager`, `OpcEventNode`

It does not always make sense to send events globally through the server to all subscribers. Often the context decides whether an event is of interest to a subscriber. Event nodes serve these local events.
The base class of all event nodes is the `OpcEventNode` class. With it, you provide simple events like those in [Send global events](https://www.traeger.de/en/docs/development/opcua/server/events#send-global-events) as local events.

Because the event node (`OpcEventNode`) is a node, first create it in the `OpcNodeManager` like any other node:

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

```

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

```

To let the event node send an event, define it as a notifier. To do so, add the event node as a notifier to each node through which a subscription should receive the local event:

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

```

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

```

Before you raise an event, set all information relevant to the event on the event node. Which information you change and how you set it depends on the use case. In general, it looks like this:

```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."

```

The event node `OpcEventNode` also provides further properties:

```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 = ...

```

Once the event is configured, call the `ReportEvent` method of the event node:

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

```

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

```

The method automatically calls `ApplyChanges` on the node, creates a snapshot of the node, and sends it to all subscribers. If the event should be reported with another node as its source, use the `ReportEventFrom` method. After calling `ReportEvent`, you can continue to change the properties of the event node as needed.

A subscriber only learns about events while it is connected to the server and has created a subscription. It therefore does not know which events occurred before it connected. If a subscriber requests the current state (for example through a ConditionRefresh), the server can provide the relevant events to it as follows:

```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
```

Each node that has an event node registered as a notifier must set such a callback separately. However, the server is **not required** to provide past events. In addition, you can create and cache a snapshot of the node at any time with the `CreateEvent` method of the event node. You then provide the cached snapshots when the `QueryEventsCallback` is called. The SDK automatically reports conditions whose `IsRetained` property is set on a ConditionRefresh, even without a `QueryEventsCallback`.

To let clients query past events over a period of time (HistoryRead for events), the server provides an event history. The [Provide the event history](https://www.traeger.de/en/docs/development/opcua/server/historical-data#provide-the-event-history) section describes how.
