/// <summary>
        /// Acknowledges an alarm.
        /// </summary>
        /// <param name="alarmName">Name of the alarm.</param>
        /// <param name="recordNumber">The record number.</param>
        /// <param name="comment">The comment.</param>
        /// <param name="userName">Name of the user.</param>
        public void AcknowledgeAlarm(string alarmName, uint recordNumber, LocalizedText comment, string userName)
        {
            UnderlyingSystemAlarm snapshot = null;

            lock (_alarms) {
                var alarm = FindAlarm(alarmName, recordNumber);

                if (alarm != null)
                {
                    if (alarm.SetStateBits(UnderlyingSystemAlarmStates.Acknowledged, true))
                    {
                        alarm.Time     = DateTime.UtcNow;
                        alarm.Reason   = "The alarm was acknoweledged.";
                        alarm.Comment  = Utils.Format("{0}", comment);
                        alarm.UserName = userName;

                        alarm.SetStateBits(UnderlyingSystemAlarmStates.Confirmed, false);
                    }

                    snapshot = alarm.CreateSnapshot();
                }
            }

            if (snapshot != null)
            {
                ReportAlarmChange(snapshot);
            }
        }
        /// <summary>
        /// Adds a comment to an alarm.
        /// </summary>
        /// <param name="alarmName">Name of the alarm.</param>
        /// <param name="recordNumber">The record number.</param>
        /// <param name="comment">The comment.</param>
        /// <param name="userName">Name of the user.</param>
        public void CommentAlarm(string alarmName, uint recordNumber, LocalizedText comment, string userName)
        {
            UnderlyingSystemAlarm snapshot = null;

            lock (_alarms) {
                var alarm = FindAlarm(alarmName, recordNumber);

                if (alarm != null)
                {
                    alarm.Time     = DateTime.UtcNow;
                    alarm.Reason   = "A comment was added.";
                    alarm.UserName = userName;

                    // only change the comment if a non-null comment was provided.
                    if (comment != null && (!string.IsNullOrEmpty(comment.Text) || !string.IsNullOrEmpty(comment.Locale)))
                    {
                        alarm.Comment = Utils.Format("{0}", comment);
                    }

                    snapshot = alarm.CreateSnapshot();
                }
            }

            if (snapshot != null)
            {
                ReportAlarmChange(snapshot);
            }
        }
 /// <summary>
 /// Reports a change to an alarm record.
 /// </summary>
 /// <param name="alarm">The alarm.</param>
 private void ReportAlarmChange(UnderlyingSystemAlarm alarm)
 {
     if (OnAlarmChanged != null)
     {
         try {
             OnAlarmChanged(alarm);
         }
         catch (Exception e) {
             Utils.Trace(e, "Unexpected error reporting change to an Alarm for Source {0}.", SourcePath);
         }
     }
 }
Example #4
0
        /// <summary>
        /// Called when the state of an alarm for the source has changed.
        /// </summary>
        private void OnAlarmChanged(UnderlyingSystemAlarm alarm)
        {
            lock (_nodeManager.Lock) {
                // ignore archived alarms for now.
                if (alarm.RecordNumber != 0)
                {
                    var branchId = new NodeId(alarm.RecordNumber, NodeId.NamespaceIndex);

                    // find the alarm branch.

                    if (!_branches.TryGetValue(alarm.Name, out var branch))
                    {
                        _branches[branchId] = branch = CreateAlarm(alarm, branchId);
                    }

                    // map the system information to the UA defined alarm.
                    UpdateAlarm(branch, alarm);
                    ReportChanges(branch);

                    // delete the branch.
                    if ((alarm.State & UnderlyingSystemAlarmStates.Deleted) != 0)
                    {
                        _branches.Remove(branchId);
                    }

                    return;
                }

                // find the alarm node.

                if (!_alarms.TryGetValue(alarm.Name, out var node))
                {
                    _alarms[alarm.Name] = node = CreateAlarm(alarm, null);
                }

                // map the system information to the UA defined alarm.
                UpdateAlarm(node, alarm);
                ReportChanges(node);
            }
        }
        /// <summary>
        /// Confirms an alarm.
        /// </summary>
        /// <param name="alarmName">Name of the alarm.</param>
        /// <param name="recordNumber">The record number.</param>
        /// <param name="comment">The comment.</param>
        /// <param name="userName">Name of the user.</param>
        public void ConfirmAlarm(string alarmName, uint recordNumber, LocalizedText comment, string userName)
        {
            UnderlyingSystemAlarm snapshot = null;

            lock (_alarms) {
                var alarm = FindAlarm(alarmName, recordNumber);

                if (alarm != null)
                {
                    if (alarm.SetStateBits(UnderlyingSystemAlarmStates.Confirmed, true))
                    {
                        alarm.Time     = DateTime.UtcNow;
                        alarm.Reason   = "The alarm was confirmed.";
                        alarm.Comment  = Utils.Format("{0}", comment);
                        alarm.UserName = userName;

                        // remove branch.
                        if (recordNumber != 0)
                        {
                            _archive.Remove(recordNumber);
                            alarm.SetStateBits(UnderlyingSystemAlarmStates.Deleted, true);
                        }

                        // de-activate alarm.
                        else
                        {
                            alarm.SetStateBits(UnderlyingSystemAlarmStates.Active, false);
                        }
                    }

                    snapshot = alarm.CreateSnapshot();
                }
            }

            if (snapshot != null)
            {
                ReportAlarmChange(snapshot);
            }
        }
        /// <summary>
        /// Creates a new active alarm for the source.
        /// </summary>
        /// <param name="alarmName">Name of the alarm.</param>
        /// <param name="alarmType">Type of the alarm.</param>
        public void CreateAlarm(string alarmName, string alarmType)
        {
            var alarm = new UnderlyingSystemAlarm {
                Source       = this,
                Name         = alarmName,
                AlarmType    = alarmType,
                RecordNumber = 0,
                Reason       = "Alarm created.",
                Time         = DateTime.UtcNow,
                Severity     = EventSeverity.Low,
                Comment      = null,
                UserName     = null,
                State        = UnderlyingSystemAlarmStates.Active | UnderlyingSystemAlarmStates.Enabled,
                EnableTime   = DateTime.UtcNow,
                ActiveTime   = DateTime.UtcNow
            };

            switch (alarmType)
            {
            case "HighAlarm": {
                alarm.Limits = new double[] { 80 };
                alarm.State |= UnderlyingSystemAlarmStates.High;
                break;
            }

            case "HighLowAlarm": {
                alarm.Limits = new double[] { 90, 70, 30, 10 };
                alarm.State |= UnderlyingSystemAlarmStates.High;
                break;
            }
            }

            lock (_alarms) {
                _alarms.Add(alarm);
            }
        }
Example #7
0
        /// <summary>
        /// Updates the alarm with a new state.
        /// </summary>
        /// <param name="node">The node.</param>
        /// <param name="alarm">The alarm.</param>
        private void UpdateAlarm(AlarmConditionState node, UnderlyingSystemAlarm alarm)
        {
            ISystemContext context = _nodeManager.SystemContext;

            // remove old event.
            if (node.EventId.Value != null)
            {
                _events.Remove(Utils.ToHexString(node.EventId.Value));
            }

            // update the basic event information (include generating a unique id for the event).
            node.EventId.Value     = Guid.NewGuid().ToByteArray();
            node.Time.Value        = DateTime.UtcNow;
            node.ReceiveTime.Value = node.Time.Value;

            // save the event for later lookup.
            _events[Utils.ToHexString(node.EventId.Value)] = node;

            // determine the retain state.
            node.Retain.Value = true;

            if (alarm != null)
            {
                node.Time.Value    = alarm.Time;
                node.Message.Value = new LocalizedText(alarm.Reason);

                // update the states.
                node.SetEnableState(context, (alarm.State & UnderlyingSystemAlarmStates.Enabled) != 0);
                node.SetAcknowledgedState(context, (alarm.State & UnderlyingSystemAlarmStates.Acknowledged) != 0);
                node.SetConfirmedState(context, (alarm.State & UnderlyingSystemAlarmStates.Confirmed) != 0);
                node.SetActiveState(context, (alarm.State & UnderlyingSystemAlarmStates.Active) != 0);
                node.SetSuppressedState(context, (alarm.State & UnderlyingSystemAlarmStates.Suppressed) != 0);

                // update other information.
                node.SetComment(context, alarm.Comment, alarm.UserName);
                node.SetSeverity(context, alarm.Severity);

                node.EnabledState.TransitionTime.Value = alarm.EnableTime;
                node.ActiveState.TransitionTime.Value  = alarm.ActiveTime;

                // check for deleted items.
                if ((alarm.State & UnderlyingSystemAlarmStates.Deleted) != 0)
                {
                    node.Retain.Value = false;
                }

                // handle high alarms.

                if (node is ExclusiveLimitAlarmState highAlarm)
                {
                    highAlarm.HighLimit.Value = alarm.Limits[0];

                    if ((alarm.State & UnderlyingSystemAlarmStates.High) != 0)
                    {
                        highAlarm.SetLimitState(context, LimitAlarmStates.High);
                    }
                }

                // handle high-low alarms.

                if (node is NonExclusiveLimitAlarmState highLowAlarm)
                {
                    highLowAlarm.HighHighLimit.Value = alarm.Limits[0];
                    highLowAlarm.HighLimit.Value     = alarm.Limits[1];
                    highLowAlarm.LowLimit.Value      = alarm.Limits[2];
                    highLowAlarm.LowLowLimit.Value   = alarm.Limits[3];

                    var limit = LimitAlarmStates.Inactive;

                    if ((alarm.State & UnderlyingSystemAlarmStates.HighHigh) != 0)
                    {
                        limit |= LimitAlarmStates.HighHigh;
                    }

                    if ((alarm.State & UnderlyingSystemAlarmStates.High) != 0)
                    {
                        limit |= LimitAlarmStates.High;
                    }

                    if ((alarm.State & UnderlyingSystemAlarmStates.Low) != 0)
                    {
                        limit |= LimitAlarmStates.Low;
                    }

                    if ((alarm.State & UnderlyingSystemAlarmStates.LowLow) != 0)
                    {
                        limit |= LimitAlarmStates.LowLow;
                    }

                    highLowAlarm.SetLimitState(context, limit);
                }
            }

            // not interested in disabled or inactive alarms.
            if (!node.EnabledState.Id.Value || !node.ActiveState.Id.Value)
            {
                node.Retain.Value = false;
            }
        }
Example #8
0
        /// <summary>
        /// Creates a new alarm for the source.
        /// </summary>
        /// <param name="alarm">The alarm.</param>
        /// <param name="branchId">The branch id.</param>
        /// <returns>The new alarm.</returns>
        private AlarmConditionState CreateAlarm(UnderlyingSystemAlarm alarm, NodeId branchId)
        {
            ISystemContext context = _nodeManager.SystemContext;

            AlarmConditionState node = null;

            // need to map the alarm type to a UA defined alarm type.
            switch (alarm.AlarmType)
            {
            case "HighAlarm": {
                var node2 = new ExclusiveDeviationAlarmState(this);
                node            = node2;
                node2.HighLimit = new PropertyState <double>(node2);
                break;
            }

            case "HighLowAlarm": {
                var node2 = new NonExclusiveLevelAlarmState(this);
                node = node2;

                node2.HighHighLimit = new PropertyState <double>(node2);
                node2.HighLimit     = new PropertyState <double>(node2);
                node2.LowLimit      = new PropertyState <double>(node2);
                node2.LowLowLimit   = new PropertyState <double>(node2);

                node2.HighHighState = new TwoStateVariableState(node2);
                node2.HighState     = new TwoStateVariableState(node2);
                node2.LowState      = new TwoStateVariableState(node2);
                node2.LowLowState   = new TwoStateVariableState(node2);

                break;
            }

            case "TripAlarm": {
                node = new TripAlarmState(this);
                break;
            }

            default: {
                node = new AlarmConditionState(this);
                break;
            }
            }

            node.SymbolicName = alarm.Name;

            // add optional components.
            node.Comment        = new ConditionVariableState <LocalizedText>(node);
            node.ClientUserId   = new PropertyState <string>(node);
            node.AddComment     = new AddCommentMethodState(node);
            node.ConfirmedState = new TwoStateVariableState(node);
            node.Confirm        = new AddCommentMethodState(node);

            if (NodeId.IsNull(branchId))
            {
                node.SuppressedState = new TwoStateVariableState(node);
                node.ShelvingState   = new ShelvedStateMachineState(node);
            }

            // adding optional components to children is a little more complicated since the
            // necessary initilization strings defined by the class that represents the child.
            // in this case we pre-create the child, add the optional components
            // and call create without assigning NodeIds. The NodeIds will be assigned when the
            // parent object is created.
            node.EnabledState = new TwoStateVariableState(node);
            node.EnabledState.TransitionTime       = new PropertyState <DateTime>(node.EnabledState);
            node.EnabledState.EffectiveDisplayName = new PropertyState <LocalizedText>(node.EnabledState);
            node.EnabledState.Create(context, null, BrowseNames.EnabledState, null, false);

            // same procedure add optional components to the ActiveState component.
            node.ActiveState = new TwoStateVariableState(node);
            node.ActiveState.TransitionTime       = new PropertyState <DateTime>(node.ActiveState);
            node.ActiveState.EffectiveDisplayName = new PropertyState <LocalizedText>(node.ActiveState);
            node.ActiveState.Create(context, null, BrowseNames.ActiveState, null, false);

            // specify reference type between the source and the alarm.
            node.ReferenceTypeId = ReferenceTypeIds.HasComponent;

            // This call initializes the condition from the type model (i.e. creates all of the objects
            // and variables requried to store its state). The information about the type model was
            // incorporated into the class when the class was created.
            //
            // This method also assigns new NodeIds to all of the components by calling the INodeIdFactory.New
            // method on the INodeIdFactory object which is part of the system context. The NodeManager provides
            // the INodeIdFactory implementation used here.
            node.Create(
                context,
                null,
                new QualifiedName(alarm.Name, BrowseName.NamespaceIndex),
                null,
                true);

            // don't add branches to the address space.
            if (NodeId.IsNull(branchId))
            {
                AddChild(node);
            }

            // initialize event information.node
            node.EventType.Value     = node.TypeDefinitionId;
            node.SourceNode.Value    = NodeId;
            node.SourceName.Value    = SymbolicName;
            node.ConditionName.Value = node.SymbolicName;
            node.Time.Value          = DateTime.UtcNow;
            node.ReceiveTime.Value   = node.Time.Value;
            if (node.LocalTime != null)
            {
                node.LocalTime.Value = Utils.GetTimeZoneInfo();
            }
            node.BranchId.Value = branchId;

            // set up method handlers.
            node.OnEnableDisable = OnEnableDisableAlarm;
            node.OnAcknowledge   = OnAcknowledge;
            node.OnAddComment    = OnAddComment;
            node.OnConfirm       = OnConfirm;
            node.OnShelve        = OnShelve;
            node.OnTimedUnshelve = OnTimedUnshelve;

            // return the new node.
            return(node);
        }
        /// <summary>
        /// Updates the state of an alarm.
        /// </summary>
        private void UpdateAlarm(UnderlyingSystemAlarm alarm, long counter, int index, List <UnderlyingSystemAlarm> snapshots)
        {
            string reason = null;

            // ignore disabled alarms.
            if ((alarm.State & UnderlyingSystemAlarmStates.Enabled) == 0)
            {
                return;
            }

            // check if the alarm needs to be updated this cycle.
            if (counter % (8 + (index % 4)) == 0)
            {
                // check if it is time to activate.
                if ((alarm.State & UnderlyingSystemAlarmStates.Active) == 0)
                {
                    reason = "The alarm is active.";

                    alarm.SetStateBits(UnderlyingSystemAlarmStates.Active, true);
                    alarm.SetStateBits(UnderlyingSystemAlarmStates.Acknowledged | UnderlyingSystemAlarmStates.Confirmed, false);
                    alarm.Severity   = EventSeverity.Low;
                    alarm.ActiveTime = DateTime.UtcNow;

                    switch (alarm.AlarmType)
                    {
                    case "HighAlarm": {
                        alarm.SetStateBits(UnderlyingSystemAlarmStates.Limits, false);
                        alarm.SetStateBits(UnderlyingSystemAlarmStates.High, true);
                        break;
                    }

                    case "HighLowAlarm": {
                        alarm.SetStateBits(UnderlyingSystemAlarmStates.Limits, false);
                        alarm.SetStateBits(UnderlyingSystemAlarmStates.Low, true);
                        break;
                    }
                    }
                }

                // bump the severity.
                else if ((alarm.State & UnderlyingSystemAlarmStates.Acknowledged) == 0)
                {
                    if (alarm.Severity < EventSeverity.High)
                    {
                        reason = "The alarm severity has increased.";

                        var values = Enum.GetValues(typeof(EventSeverity));

                        for (var ii = 0; ii < values.Length; ii++)
                        {
                            var severity = (EventSeverity)values.GetValue(ii);

                            if (severity > alarm.Severity)
                            {
                                alarm.Severity = severity;
                                break;
                            }
                        }

                        if (alarm.Severity > EventSeverity.Medium)
                        {
                            switch (alarm.AlarmType)
                            {
                            case "HighLowAlarm": {
                                alarm.SetStateBits(UnderlyingSystemAlarmStates.Limits, false);
                                alarm.SetStateBits(UnderlyingSystemAlarmStates.LowLow, true);
                                break;
                            }
                            }
                        }
                    }

                    // give up on the alarm.
                    else
                    {
                        // create an archived state that needs to be acknowledged.
                        if (alarm.AlarmType == "TripAlarm")
                        {
                            // check the number of archived states.
                            var count = 0;

                            foreach (var record in _archive.Values)
                            {
                                if (record.Name == alarm.Name)
                                {
                                    count++;
                                }
                            }
                            // limit the number of archived states to avoid filling up the display.
                            if (count < 2)
                            {
                                // archive the current state.
                                var snapshot = alarm.CreateSnapshot();
                                snapshot.RecordNumber = ++_nextRecordNumber;
                                snapshot.Severity     = EventSeverity.Low;
                                _archive.Add(snapshot.RecordNumber, snapshot);
                                snapshots.Add(snapshot);
                            }
                        }

                        reason = "The alarm was deactivated by the system.";
                        alarm.SetStateBits(UnderlyingSystemAlarmStates.Active, false);
                        //alarm.SetStateBits(UnderlyingSystemAlarmStates.Acknowledged | UnderlyingSystemAlarmStates.Confirmed, true);
                        alarm.Severity = EventSeverity.Low;
                    }
                }
            }

            // update the reason.
            if (reason != null)
            {
                alarm.Time   = DateTime.UtcNow;
                alarm.Reason = reason;

                // return a snapshot used to report the state change.
                snapshots.Add(alarm.CreateSnapshot());
            }

            // no change so nothing to report.
        }