How-to guide
Alarms and conditions
Event nodes with conditions: dialog and acknowledgeable conditions, alarm conditions up to limit alarms.
How-to guide
Alarms and conditions
Event nodes with conditions report events that are tied to the state of a condition. This page shows how a client processes the event data of each kind of condition, from simple conditions to limit alarms, and how it receives the conditions of an OPC AE server (Alarms & Events).
Conditions
Types usedOpcClientOpcEventReceivedEventArgsOpcEventOpcConditionOpcEventSeverity
The OpcCondition class is a specialization of the OpcEvent class, which the page Events introduces. It provides event data that is tied to specific conditions. The server triggers such an event only if the condition assigned to the event node applies. The event data contains information about the state of the condition and information tied to the evaluation of the condition. Depending on the use case, this information can vary in complexity. For this reason, OpcCondition is the base class of all event data tied to a condition.
Besides the general properties of an event from the OpcEvent base class, an instance of OpcCondition provides further information that can be important for processing in the client. The IsRetained property shows whether the server generally considers the event relevant for clients. The IsEnabled property shows whether the condition is enabled or disabled. Whether an alarm is active, in contrast, is shown by the IsActive property of the alarm conditions (section Alarm conditions).
private static void HandleLocalEvents(
object sender,
OpcEventReceivedEventArgs e)
{
var condition = e.Event as OpcCondition;
if (condition != null && condition.IsRetained) {
Console.Write((condition.ClientUserId ?? "Comment") + ":");
Console.WriteLine(condition.Comment);
}
}Private Shared Sub HandleLocalEvents( _
ByVal sender As Object, _
ByVal e As OpcEventReceivedEventArgs)
Dim condition = TryCast(e.Event, OpcCondition)
If condition IsNot Nothing AndAlso condition.IsRetained Then
Console.Write(If(condition.ClientUserId, "Comment") & ":")
Console.WriteLine(condition.Comment)
End If
End SubIf the client should no longer evaluate the condition, it disables it:
private static void HandleLocalEvents(object sender, OpcEventReceivedEventArgs e)
{
var condition = e.Event as OpcCondition;
if (condition.IsEnabled && condition.Severity < OpcEventSeverity.Medium)
condition.Disable(client);
}Private Shared Sub HandleLocalEvents( _
ByVal sender As Object, _
ByVal e As OpcEventReceivedEventArgs)
Dim condition = TryCast(e.Event, OpcCondition)
If condition.IsEnabled AndAlso condition.Severity < OpcEventSeverity.Medium Then
condition.Disable(client)
End If
End SubThe client can also add a comment on the current state of the condition:
private static void HandleLocalEvents(object sender, OpcEventReceivedEventArgs e)
{
var condition = e.Event as OpcCondition;
if (condition != null)
condition.AddComment(client, "Evaluated by me!");
}Private Shared Sub HandleLocalEvents( _
ByVal sender As Object, _
ByVal e As OpcEventReceivedEventArgs)
Dim condition = TryCast(e.Event, OpcCondition)
If condition IsNot Nothing Then
condition.AddComment(client, "Evaluated by me!")
End If
End SubDialog conditions
Types usedOpcClientOpcEventReceivedEventArgsOpcConditionOpcDialogConditionOpcEventSeverityOpcDialogRequestedEventArgs
The OpcDialogCondition class is a specialization of OpcCondition. The condition of this event is a dialog with the subscribers. Such a condition consists of a prompt and response options. Three more details complete it: the DefaultResponse property names the option that should be selected by default. The OkResponse property names the option that confirms the dialog, and the CancelResponse property the option that cancels it. When the server triggers such an event, it waits until one of the subscribers responds with one of the given response options. The operations tied to the dialog therefore require a response: to a task, a question, a piece of information, or a warning. This is how the client processes the information of the event and reports the response back to the server:
private void HandleLocalEvents(
object sender,
OpcEventReceivedEventArgs e)
{
var condition = e.Event as OpcDialogCondition;
if (condition != null && condition.IsActive) {
Console.WriteLine(condition.Prompt);
Console.WriteLine(" Options:");
var responseOptions = condition.ResponseOptions;
for (int index = 0; index < responseOptions.Length; index++) {
Console.Write(" [{0}] = {1}", index, responseOptions[index].Value);
if (index == condition.DefaultResponse)
Console.Write(" (default)");
Console.WriteLine();
}
var respond = string.Empty;
var respondOption = condition.DefaultResponse;
do {
Console.Write("Enter the number of the option and press Enter to respond: ");
respond = Console.ReadLine();
if (string.IsNullOrEmpty(respond))
break;
} while (!int.TryParse(respond, out respondOption));
condition.Respond(client, respondOption);
// The dialog has been answered, the DialogRequested event is not raised.
e.Handled = true;
}
}Private Sub HandleLocalEvents( _
ByVal sender As Object, _
ByVal e As OpcEventReceivedEventArgs)
Dim condition = TryCast(e.Event, OpcDialogCondition)
If condition IsNot Nothing AndAlso condition.IsActive Then
Console.WriteLine(condition.Prompt)
Console.WriteLine(" Options:")
Dim responseOptions = condition.ResponseOptions
For index As Integer = 0 To responseOptions.Length - 1
Console.Write(" [{0}] = {1}", index, responseOptions(index).Value)
If index = condition.DefaultResponse Then
Console.Write(" (default)")
End If
Console.WriteLine()
Next
Dim respond = String.Empty
Dim respondOption = condition.DefaultResponse
Do
Console.Write("Enter the number of the option and press Enter to respond: ")
respond = Console.ReadLine()
If String.IsNullOrEmpty(respond) Then
Exit Do
End If
Loop While Not Integer.TryParse(respond, respondOption)
condition.Respond(client, respondOption)
'The dialog has been answered, the DialogRequested event is not raised.
e.Handled = True
End If
End SubBesides the standard way of handling events, the OpcClient class offers the DialogRequested event. If the client receives event data of the type OpcDialogCondition and no handler has set the Handled property of the event arguments to true, the client raises the DialogRequested event. You process the dialog through this event. For this reason, if a handler already answers the dialog itself, set the Handled property as in the previous example. Otherwise, the client answers the dialog a second time. With DialogRequested, handling the event data is somewhat easier because the event handler receives it typed:
client.DialogRequested += HandleDialogRequested;
...
private static void HandleDialogRequested(
object sender,
OpcDialogRequestedEventArgs e)
{
// Just use the default response, here.
e.SelectedResponse = e.Dialog.DefaultResponse;
}AddHandler client.DialogRequested, AddressOf HandleDialogRequested
...
Private Shared Sub HandleDialogRequested( _
ByVal sender As Object, _
ByVal e As OpcDialogRequestedEventArgs)
'Just use the default response, here.
e.SelectedResponse = e.Dialog.DefaultResponse
End SubOnly set the SelectedResponse property of the event arguments. OpcClient calls the Respond method of the OpcDialogCondition class itself after the event handler. If SelectedResponse remains at the default value -1 or lies outside the response options, the client sends no response.
Acknowledgeable conditions
Types usedOpcClientOpcEventReceivedEventArgsOpcEventOpcConditionOpcAcknowledgeableConditionOpcEventSeverity
The OpcAcknowledgeableCondition class is a specialization of OpcCondition. It is the base class for conditions that request feedback. Such an event works like a message with a return receipt: when its condition is met, the server sends the message and requests feedback. The return receipt, that is the feedback, can control further processes or simply acknowledge notes and warnings. The OPC UA specification (Part 9) provides two kinds of feedback for this. Acknowledge confirms that someone has taken note of the message. Confirm then confirms that the cause of the message has been resolved. This second stage is optional, and not every server uses it. For both kinds, the events provide the Acknowledge and Confirm methods. The two states are independent of each other: acknowledging does not also confirm, and vice versa. Optionally, you pass a comment from the person handling the event when you acknowledge or confirm. This is how you implement acknowledgment as feedback:
private static void HandleLocalEvents(object sender, OpcEventReceivedEventArgs e)
{
var condition = e.Event as OpcAcknowledgeableCondition;
if (condition != null && !condition.IsAcked) {
Console.WriteLine($"Acknowledgment is required for condtion: {condition.ConditionName}");
Console.WriteLine($" -> {condition.Message}");
Console.Write("Enter your acknowlegment comment and press Enter to acknowledge: ");
var comment = Console.ReadLine();
condition.Acknowledge(client, comment);
}
}Private Shared Sub HandleLocalEvents( _
ByVal sender As Object, _
ByVal e As OpcEventReceivedEventArgs)
Dim condition = TryCast(e.Event, OpcAcknowledgeableCondition)
If condition IsNot Nothing AndAlso Not condition.IsAcked Then
Console.WriteLine("Acknowledgment is required for condtion: {0}", condition.ConditionName)
Console.WriteLine(" -> {0}", condition.Message)
Console.Write("Enter your acknowlegment comment and press Enter to acknowledge: ")
Dim comment = Console.ReadLine()
condition.Acknowledge(client, comment)
End If
End SubWhen it processes such events, the client also checks whether the event has already been confirmed (IsConfirmed property) or acknowledged (IsAcked property). The server always defines the interpretation of the feedback and the logic that follows. Whether a server uses both kinds of feedback or only one is therefore up to the team that develops it. Ideally, a server supports at least the Acknowledge method, since the specification provides confirmation as an optional second stage after acknowledgment.
Alarm conditions
Types usedOpcClientOpcEventReceivedEventArgsOpcAlarmConditionOpcAcknowledgeableConditionOpcEventSeverity
Probably the most important implementation of OpcAcknowledgeableCondition in OPC UA is the OpcAlarmCondition class. Events of this class behave like a bedside alarm clock. Such an event becomes active (IsActive property) when the linked condition is met. For the alarm clock, this is reaching the wake-up time, for example. An alarm that has a wake-up time but should not become active when that time is reached is called a suppressed alarm (IsSuppressed and IsSuppressedOrShelved properties). When an alarm becomes active, the server can shelve it: once ("One Shot Shelving") or for a period of time ("Timed Shelving"). The IsSuppressedOrShelved property shows whether an alarm is suppressed or shelved. The MaxTimeShelved property shows the maximum time an alarm may stay shelved.
private static void HandleLocalEvents(
object sender,
OpcEventReceivedEventArgs e)
{
var alarm = e.Event as OpcAlarmCondition;
if (alarm != null) {
Console.Write($"Alarm {alarm.ConditionName} is");
Console.WriteLine($"{(alarm.IsActive ? "active" : "inactive")}!");
}
}Private Shared Sub HandleLocalEvents( _
ByVal sender As Object, _
ByVal e As OpcEventReceivedEventArgs)
Dim alarm = TryCast(e.Event, OpcAlarmCondition)
If alarm IsNot Nothing Then
Console.Write("Alarm {0} is", alarm.ConditionName)
Console.WriteLine("{0}!", If(alarm.IsActive, "active", "inactive"))
End If
End SubDiscrete alarms
Types usedOpcClientOpcEventReceivedEventArgsOpcDiscreteAlarmOpcOffNormalAlarmOpcTripAlarm
For the event data of OpcAlarmCondition, there are several specializations for specific kinds of alarms. For them, the kind of alarm itself describes its form, its cause, or its content in more detail. One subclass of such self-describing alarms are the discrete alarms. Their base is the OpcDiscreteAlarm class. It represents alarms whose input can take only a certain number of possible values, for example true and false, or running, stopped, and finished. If an alarm represents a discrete state that is considered not normal, the OpcOffNormalAlarm class or one of its subclasses describes it. The NormalStateId property refers to the state that is considered normal. The OPC UA .NET SDK provides a further specialization of this alarm class with the OpcTripAlarm class. This alarm becomes active when an abnormal fault occurs on a monitored device, for example when the motor shuts down because of overload.
private static void HandleLocalEvents(object sender, OpcEventReceivedEventArgs e)
{
var alarm = e.Event as OpcDiscreteAlarm;
if (alarm != null) {
if (alarm is OpcTripAlarm)
Console.WriteLine("Trip Alarm!");
else if (alarm is OpcOffNormalAlarm)
Console.WriteLine("Off Normal Alarm!");
}
}Private Shared Sub HandleLocalEvents( _
ByVal sender As Object, _
ByVal e As OpcEventReceivedEventArgs)
Dim alarm = TryCast(e.Event, OpcDiscreteAlarm)
If alarm IsNot Nothing Then
If TypeOf alarm Is OpcTripAlarm Then
Console.WriteLine("Trip Alarm!")
ElseIf TypeOf alarm Is OpcOffNormalAlarm Then
Console.WriteLine("Off Normal Alarm!")
End If
End If
End SubLimit alarms
Types usedOpcClientOpcEventReceivedEventArgsOpcLimitAlarm
If the server checks process-specific limits and publishes the result when a value exceeds or falls below them, the OpcLimitAlarm class is the central entry point to the limit alarm classes. This class divides limits into up to four levels. In the order of their metric ranking, they are called LowLow, Low, High, and HighHigh. By definition, the server does not have to define all limits.
private static void HandleLocalEvents(
object sender,
OpcEventReceivedEventArgs e)
{
var alarm = e.Event as OpcLimitAlarm;
if (alarm != null) {
Console.Write(alarm.LowLowLimit);
Console.Write(" ≤ ");
Console.Write(alarm.LowLimit);
Console.Write(" ≤ ");
Console.Write(alarm.HighLimit);
Console.Write(" ≤ ");
Console.Write(alarm.HighHighLimit);
}
}Private Shared Sub HandleLocalEvents( _
ByVal sender As Object, _
ByVal e As OpcEventReceivedEventArgs)
Dim alarm = TryCast(e.Event, OpcLimitAlarm)
If alarm IsNot Nothing Then
Console.Write(alarm.LowLowLimit)
Console.Write(" ≤ ")
Console.Write(alarm.LowLimit)
Console.Write(" ≤ ")
Console.Write(alarm.HighLimit)
Console.Write(" ≤ ")
Console.Write(alarm.HighHighLimit)
End If
End SubExclusive limit alarms
Types usedOpcClientOpcEventReceivedEventArgsOpcLimitAlarmOpcExclusiveLimitAlarmOpcExclusiveDeviationAlarmOpcExclusiveLevelAlarmOpcExclusiveRateOfChangeAlarm
The OpcExclusiveLimitAlarm class is a subclass of OpcLimitAlarm. As its name says, it defines limit alarms for exclusive limits. The limits of such an alarm are mutually exclusive. If one limit is exceeded or undershot, no other limit can be exceeded or undershot at the same time.
OPC UA has three further specializations of the OpcExclusiveLimitAlarm class.
OpcExclusiveDeviationAlarm
This alarm reports that the value deviates from a setpoint by more than the limits. The SetpointNodeId property refers to the node of the setpoint.
OpcExclusiveLevelAlarm
This alarm reports a limit violation, typically on an instrument such as a temperature sensor. It becomes active when the observed value is above an upper limit or below a lower limit.
OpcExclusiveRateOfChangeAlarm
This alarm reports an unusual or missing change of a measured value, relative to the speed of the change. It becomes active when the rate of change of the value exceeds or falls below a defined limit.
Non-exclusive limit alarms
Types usedOpcClientOpcEventReceivedEventArgsOpcLimitAlarmOpcNonExclusiveLimitAlarmOpcNonExclusiveDeviationAlarmOpcNonExclusiveLevelAlarmOpcNonExclusiveRateOfChangeAlarm
The OpcNonExclusiveLimitAlarm class is a subclass of OpcLimitAlarm. As its name says, it defines limit alarms for non-exclusive limits. The limits of such an alarm are not mutually exclusive. If one limit is exceeded or undershot, another limit can be exceeded or undershot at the same time. You check the violated limits with the IsLowLow, IsLow, IsHigh, and IsHighHigh properties of the event data.
OPC UA has three further specializations of the OpcNonExclusiveLimitAlarm class.
OpcNonExclusiveDeviationAlarm
This alarm reports that the value deviates from a setpoint by more than the limits. The SetpointNodeId property refers to the node of the setpoint.
OpcNonExclusiveLevelAlarm
This alarm reports a limit violation, typically on an instrument such as a temperature sensor. It becomes active when the observed value is above an upper limit or below a lower limit.
OpcNonExclusiveRateOfChangeAlarm
This alarm reports an unusual or missing change of a measured value, relative to the speed of the change. It becomes active when the rate of change of the value exceeds or falls below a defined limit.
Conditions of an OPC AE server
The client receives and acknowledges the events and conditions of an OPC AE server with the same methods. The section Alarms and events (AE) on the OPC Classic page describes the procedure.

