UA Bundle SDK .NET  2.2.0.255
 All Classes Namespaces Functions Variables Enumerations Enumerator Properties Events Groups Pages
Lesson 6: Adding support for Alarms & Conditions

Update UaModeler project to add condition object StateCondition to controller

Figure 6.1:

Condition Object OffNormalAlarm is added to ControllerType

Create code update and XML export

  • BAIdentifiers.cs
  • buildingautomation.xml

Figure 6.2:

Add initialization of Alarm object

After controller object creation

  • Create alarm data model object
  • Link to alarm nodes
SetComponentUserData(
new NodeId(block.Name, InstanceNamespaceIndex),
new QualifiedName(yourorganisation.BA.BrowseNames.StartWithSetPoint, TypeNamespaceIndex),
new SystemFunction() { Address = block.Address, Function = 3 });
// New Code Begin
// 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);
// New Code End
foreach (BlockProperty property in block.Properties)

Set Alarm Active State

Change alarm state when controller state changes

Set in BlockStateChanged event

private void UnderlyingSystem_BlockStateChanged(int blockAddress, string blockName, int state)
{
...
// report the event.
ReportEvent(e.SourceNode, e);
// New Code Begin
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);
}
else
{
// 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);
}
// report alarm status as event.
ReportEvent(alarm.SourceNode, e);
// New Code End
}

Add Acknowledge handling

Override Acknowledge

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;
}
// Check if the alarm is already inactive
OffNormalAlarmModel alarm = (OffNormalAlarmModel)model;
if (alarm.ActiveState.Id == false)
{
alarm.Retain = false;
}
e = model.CreateEvent(Server.FilterManager);
}
ReportEvent(model.SourceNode, e);
return StatusCodes.Good;
}

Alarm View in UaExpert

Figure 6.3:

Alarms view is part of the Event view Alarm condition changes can be triggered with methods Acknowledge can be called from Alarm view