.NET Based OPC UA Client/Server SDK
Lesson 6: Adding Support for Alarms & Conditions

In this example we extend the ControllerType defined in Lesson 2 by adding an instance of an alarm: We add a new Object called StateCondition having the TypeDefinition OffNodemalAlarmType (see Figure 6.1).

Figure 6.1: New StateCondition Object

Open the UaModeler project created in Lesson 2. Add a new Object called “StateCondition” as a child of ControllerType and choose “OffNormalAlarmType” as TypeDefinition (see Figure 6.2).

Figure 6.2: Add Alarm Object

Then regenerate the source files, export the model as xml file and replace the files BAIdentifiers.cs and buildingautomation.xml in your project.

After adding the controller object, we create an instance of the OffNormalAlarmModel. This class is used to store all data related to the OffNormalAlarmType. With LinkModelToNode the SDK maps the data defined in the instance to the nodes in the address space.

new NodeId(block.Name, InstanceNamespaceIndex),
new QualifiedName(yourorganisation.BA.BrowseNames.StartWithSetPoint, TypeNamespaceIndex),
new SystemFunction() { Address = block.Address, Function = 3 });
// Set alarm condition nodeId
NodeId alarmId = new NodeId(block.Name + "." + yourorganisation.BA.BrowseNames.StateCondition, InstanceNamespaceIndex);
// Create off normal alarm data object
OffNormalAlarmModel alarm = new OffNormalAlarmModel();
alarm.NodeId = alarmId;
alarm.EventType = ObjectTypeIds.OffNormalAlarmType;
alarm.SourceNode = new NodeId(block.Name, InstanceNamespaceIndex);
alarm.SourceName = block.Name;
alarm.Severity = (ushort)EventSeverity.Low;
alarm.ConditionName = "StateCondition";
alarm.ConditionClassId = ObjectTypeIds.ProcessConditionClassType;
alarm.ConditionClassName = BrowseNames.ProcessConditionClassType;
alarm.Retain = false;
alarm.EnabledState.Value = ConditionStateNames.Enabled;
alarm.EnabledState.Id = true;
alarm.AckedState.Value = ConditionStateNames.Acknowledged;
alarm.AckedState.Id = true;
alarm.ActiveState.Value = ConditionStateNames.Inactive;
alarm.ActiveState.Id = false;
alarm.SuppressedOrShelved = false;
// Link alarm data object to nodes in address space
LinkModelToNode(alarmId, alarm, null, null, 500);
foreach (BlockProperty property in block.Properties)

We change the state of the alarm in the BlockStateChanged EventHandler.

NodeId alarmId = new NodeId(blockName + "." + yourorganisation.BA.BrowseNames.StateCondition, InstanceNamespaceIndex);
OffNormalAlarmModel alarm = (OffNormalAlarmModel)GetNodeUserData(alarmId);
// Change state of StateCondition
lock (alarm)
alarm.LastSeverity.Value = alarm.Severity;
alarm.LastSeverity.SourceTimestamp = alarm.Time;
if (state == 0)
// Change state to active and unacknowledged
alarm.Retain = true;
alarm.Severity = (ushort)EventSeverity.High;
alarm.AckedState.Value = ConditionStateNames.Unacknowledged;
alarm.AckedState.Id = false;
alarm.Activate(Server.DefaultRequestContext, true);
// Change state to inactive
alarm.Severity = (ushort)EventSeverity.Low;
alarm.Activate(Server.DefaultRequestContext, false);
if (alarm.AckedState.Id == true)
alarm.Retain = false;
e = alarm.CreateEvent(Server.FilterManager, true);
// report alarm status as event.
ReportEvent(alarm.SourceNode, e);

Finally, we have to add handling for Acknowledge calls by clients. Therefore, we need to override the Acknowledge method defined at the BaseNodeManager.

public override StatusCode Acknowledge(
RequestContext context,
AcknowledgeableConditionModel model,
byte[] eventId,
LocalizedText comment)
GenericEvent e = null;
lock (model)
StatusCode error = model.Acknowledge(context, eventId, comment);
if (error.IsBad())
return error;
e = model.CreateEvent(Server.FilterManager, true);
ReportEvent(model.SourceNode, e);
return StatusCodes.Good;

To test the alarm, open a new Event View in UaExpert and change to the “Alarms” tab (see Figure 6.3). The alarm can be triggered by calling the methods “Start” and “Stop”. Right click on an Alarm to acknowledge, confirm, or add a comment.

Figure 6.3: Alarms in UaExpert