How-to guide
Events
Receive, filter, and evaluate the events of a server, work with event nodes, and receive audit events.
How-to guide
Events
This page shows how a client receives, filters, and evaluates the events (Alarms & Events) of a server. The page Alarms and conditions describes events with conditions and alarms.
Types usedOpcClientOpcObjectTypesOpcEventTypesOpcEventReceivedEventArgsOpcEventOpcAlarmConditionOpcSimpleAttributeOperandOpcFilterOpcEventFilterOpcEventSeverity
Receive global events
Events inform a subscriber, for example a client, about processes, states, and system-specific occurrences. Through global events, subscribers receive such information directly. A server always publishes a global event through its Server object. For this reason, the client also subscribes to global events through this node:
client.SubscribeEvent(OpcObjectTypes.Server, HandleGlobalEvents);client.SubscribeEvent(OpcObjectTypes.Server, AddressOf HandleGlobalEvents)You usually handle an event with a method of this signature:
private static void HandleGlobalEvents(
object sender,
OpcEventReceivedEventArgs e)
{
Console.WriteLine(e.Event.Message);
}Private Shared Sub HandleGlobalEvents( _
ByVal sender As Object, _
ByVal e As OpcEventReceivedEventArgs)
Console.WriteLine(e.Event.Message)
End SubThe Event property of the event arguments (class OpcEventReceivedEventArgs) returns the event data received. It always returns an instance of the OpcEvent class. If the event data belongs to a specialization of the OpcEvent class, simply cast it:
private static void HandleGlobalEvents(
object sender,
OpcEventReceivedEventArgs e)
{
var alarm = e.Event as OpcAlarmCondition;
if (alarm != null)
Console.WriteLine("Alarm: " + alarm.Message);
}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 SubFilter events
The call above subscribes to all events that the server publishes globally. With an event filter, you restrict the information you receive and also the events that the server sends to the client at all. The client transmits the filter to the server when it creates the subscription:
// 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);'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)To create an event filter, you always need an instance of OpcClient that is already connected to the target server. While it builds the filter, the client retrieves the relevant type information from the server. In the example above, the client collects all properties of the node type OpcAlarmConditionNode recursively up to OpcNode. From the Where and Select clauses, it creates rules for selecting the event data. Pass the node types to analyze to the FromEvents method, separated by commas:
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);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)With the Where method, you restrict the information that FromEvents collects through the properties of the node types. For this, the OPC UA .NET SDK offers several operator overloads (<=, <, >, >=, and ==). The operator != throws a NotSupportedException. Use (a < b) | (a > b) instead. To combine operands logically, the operators OR (|) and AND (&) are also available. For further restrictions, there are methods such as Like, Between, InList, IsNull, Not, OfType, Cast, and InView. For languages without these operators (such as Visual Basic), the equivalent methods EqualsTo, GreaterThan, GreaterThanOrEqualsTo, LessThan, and LessThanOrEqualsTo are available.
As of version 2.59, Between takes the operands in OPC UA order: a.Between(lower, upper) checks whether a lies between lower and upper. As of version 2.59, several Where calls in a row combine their conditions with AND, like a single Where with &. In older versions, only the condition of the last call applies.
Then use the Select method to choose the properties that the server additionally transmits to the client. The server does so when an event occurs that matches the conditions from Where.
The following example subscribes to all events that are currently active but not yet acknowledged:
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);
}
});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)Receive events of a node
Types usedOpcClientOpcEventReceivedEventArgsOpcEventOpcSubscription
It does not always make sense for a server to send all events globally through the Server object to all subscribers. Often the context decides whether an event is of interest to a subscriber. For such local events, there are event nodes. If the server uses an event node to provide event data for a node, the event node is a notifier of that node. A HasNotifier reference therefore shows which event node reports event data to a node. An event node can be the notifier of multiple nodes. For this reason, the client always subscribes to local events through the notified nodes:
client.SubscribeEvent(machineNodeId, HandleLocalEvents);client.SubscribeEvent(machineNodeId, AddressOf HandleLocalEvents)You usually handle an event with a method of this signature. The client processes the event data further the same way as for global events (see section Receive global events).
private static void HandleLocalEvents(
object sender,
OpcEventReceivedEventArgs e)
{
Console.WriteLine(e.Event.Message);
}Private Shared Sub HandleLocalEvents( _
ByVal sender As Object, _
ByVal e As OpcEventReceivedEventArgs)
Console.WriteLine(e.Event.Message)
End SubYou can also filter local events, as shown in the section Filter events.
A subscriber (a client) only learns about events while it is connected to the server and has created a subscription. After it connects, it therefore does not know the current state of the conditions of the server (see Alarms and conditions). With the following call, it requests this state. The server then sends an event again for all conditions that are currently in a relevant state (IsRetained is true). This call does not return past events. If the server provides them, the client reads them through the event history, see Read the event history.
var subscription = client.SubscribeEvent(
machineNodeId,
HandleLocalEvents);
// Query most recent event information.
subscription.RefreshConditions();Dim subscription = client.SubscribeEvent( _
machineNodeId, _
AddressOf HandleLocalEvents)
'Query most recent event information.
subscription.RefreshConditions()Receive audit events
Types usedOpcClientOpcFilterOpcEventFilterOpcObjectTypesOpcEvent
Audit events log the security-related actions of a server. A server developed with the SDK reports them through the Server object if auditing is turned on in the server (see Audit events). It reports them when a secure channel is opened and closed (AuditOpenSecureChannelEventType, AuditChannelEventType) and when a session is created (AuditCreateSessionEventType) and activated (AuditActivateSessionEventType). As defined by OPC UA, a client receives them only through an endpoint with the mode SignAndEncrypt or through HTTPS, and only if the logged-on user belongs to the SecurityAdmin role. A client subscribes to them like other events, through a filter on the event types, in the following example on the two event types of the session:
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);
}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 SubThe client can read the general fields of an event, for example Time, EventTypeId, SourceName, and Message. The SDK does not provide the specific fields of audit events in the client, such as the identity of the user or the ID of the session.

