/// <summary> /// Create an alert if conditions are met. /// </summary> ContosoPerformanceStatus UpdateAlert( ContosoTopologyNode node, double value, DateTime time, ContosoPerformanceSetting setting, ContosoAlertCause causeMin = ContosoAlertCause.AlertCauseValueBelowMinimum, ContosoAlertCause causeMax = ContosoAlertCause.AlertCauseValueAboveMaximum) { if (value != 0 && value < setting.Minimum) { ContosoAlert alert = new ContosoAlert(causeMin, node.Key, time); node.AddAlert(alert); node.Status = ContosoPerformanceStatus.Poor; } else if (value != 0 && value > setting.Maximum) { ContosoAlert alert = new ContosoAlert(causeMax, node.Key, time); node.AddAlert(alert); node.Status = ContosoPerformanceStatus.Poor; } else { node.Status = ContosoPerformanceStatus.Good; } return(node.Status); }
/// <summary> /// Lookup the alert with alertId. /// </summary> public ContosoAlert FindAlert(long alertId) { List <string> allTopologyNodeKeys = GetAllChildren(TopologyRoot.Key); allTopologyNodeKeys.Add(TopologyRoot.Key); foreach (var key in allTopologyNodeKeys) { ContosoTopologyNode topologyNode = TopologyTable[key] as ContosoTopologyNode; if (topologyNode == null) { Trace.TraceError($"Can not find node with key '{key}' in the topology."); return(null); } // Check the node for the alert id. ContosoAlert alert = topologyNode.FindAlert(alertId); // Return when found. if (alert != null) { return(alert); } } Trace.TraceError($"Can not find alert with id '{alertId}'."); return(null); }
/// <summary> /// The alert is added to the alert list of this node. /// </summary> public void AddAlert(ContosoAlert alert) { lock (_alertsLock) { Alerts.Add(alert); } }
/// <summary> /// The all alerts, which have the same cause and are older then the given one are deleted. /// </summary> public bool CloseAlert(long alertId) { lock (_alertsLock) { // Verify existence of the alertId. ContosoAlert alert = Alerts.Find(x => x.AlertId == alertId); if (alert == null) { Trace.TraceError($"alertId '{alertId}' in node '{Key}' can not be found."); return(false); } // Fail if the alert is not yet acknowledged. if (alert.Status != ContosoAlertStatus.AlertStatusAcknowledged) { Trace.TraceError($"alert with alertId '{alertId}' in node '{Key}' can not be closed, since it is not acknowledged ('{alert.Status}')"); return(false); } // Close all older alerts. List <ContosoAlert> oldAlerts = Alerts.FindAll(x => (x.Time <= alert.Time && x.Cause == alert.Cause)); foreach (var alertToRemove in oldAlerts) { Alerts.RemoveAll(x => x == alertToRemove); } } return(true); }
/// <summary> /// Create alert information for the UX from the given alert. /// </summary> private ContosoAlertInfo CreateDashboardAlertInfo(ContosoAlert alert, long sameCauseAlertsCount, string nodeKey) { ContosoAlertInfo alertInfo = new ContosoAlertInfo(); ContosoTopologyNode topologyNode = TopologyTable[alert.Key] as ContosoTopologyNode; alertInfo.AlertId = alert.AlertId; alertInfo.CauseDescription = alert.GetAlertCauseDescription(); alertInfo.Cause = alert.Cause; alertInfo.Occurences = sameCauseAlertsCount; List <string> parentList = GetFullHierarchy(nodeKey); alertInfo.TopologyDetails = new string[ContosoAlertInfo.MaxTopologyDetailsCount]; int index = 0; if (parentList.Count == 1) { alertInfo.TopologyDetails[index] = topologyNode.Name; } else { parentList.Reverse(); parentList.RemoveAt(0); foreach (var parent in parentList) { ContosoTopologyNode parentNode = (ContosoTopologyNode)TopologyTable[parent]; alertInfo.TopologyDetails[index++] = parentNode.Name; } // Check if the alert has been caused by an OPC UA node value. if (alert.SubKey != "null") { OpcUaNode opcUaNode = ((Station)TopologyTable[alert.Key]).GetOpcUaNode(alert.SubKey); alertInfo.TopologyDetails[index] = opcUaNode.SymbolicName; } } alertInfo.Key = alert.Key; alertInfo.SubKey = alert.SubKey; alertInfo.UxTime = string.Format("{0}-{1}", alert.Time.ToString("t"), alert.Time.ToString("d")); alertInfo.Time = alert.Time; alertInfo.Status = alert.Status; alertInfo.AlertActionInfo = topologyNode.CreateAlertActionInfo(alert.Cause, alert.SubKey); return(alertInfo); }
/// <summary> /// Create alert information for the UX from the given alert. /// </summary> private ContosoAlertInfo CreateDashboardAlertInfo(ContosoAlert alert, long sameCauseAlertsCount, string nodeKey) { ContosoAlertInfo alertInfo = new ContosoAlertInfo(); ContosoTopologyNode topologyNode = TopologyTable[alert.Key] as ContosoTopologyNode; alertInfo.AlertId = alert.AlertId; alertInfo.Cause = alert.Cause; alertInfo.Occurences = sameCauseAlertsCount; List <string> parentList = GetFullHierarchy(nodeKey); alertInfo.TopologyDetails = new string[ContosoAlertInfo.MaxTopologyDetailsCount]; int index = 0; if (parentList.Count == 1) { alertInfo.TopologyDetails[index] = topologyNode.Name; } else { parentList.Reverse(); parentList.RemoveAt(0); foreach (var parent in parentList) { ContosoTopologyNode parentNode = (ContosoTopologyNode)TopologyTable[parent]; alertInfo.TopologyDetails[index++] = parentNode.Name; } // Check if the alert has been caused by an OPC UA node value. if (alert.SubKey != "null") { ContosoOpcUaNode contosoOpcUaNode = Startup.Topology.GetOpcUaNode(alert.Key, alert.SubKey); alertInfo.TopologyDetails[index] = contosoOpcUaNode.SymbolicName; alertInfo.Maximum = contosoOpcUaNode.Maximum; alertInfo.Minimum = contosoOpcUaNode.Minimum; } else { switch (alert.Cause) { case ContosoAlertCause.AlertCauseOeeOverallBelowMinimum: case ContosoAlertCause.AlertCauseOeeOverallAboveMaximum: alertInfo.Maximum = topologyNode.OeeOverallPerformanceSetting.Maximum; alertInfo.Minimum = topologyNode.OeeOverallPerformanceSetting.Minimum; break; case ContosoAlertCause.AlertCauseOeeAvailabilityBelowMinimum: case ContosoAlertCause.AlertCauseOeeAvailabilityAboveMaximum: alertInfo.Maximum = topologyNode.OeeAvailabilityPerformanceSetting.Maximum; alertInfo.Minimum = topologyNode.OeeAvailabilityPerformanceSetting.Minimum; break; case ContosoAlertCause.AlertCauseOeePerformanceBelowMinimum: case ContosoAlertCause.AlertCauseOeePerformanceAboveMaximum: alertInfo.Maximum = topologyNode.OeePerformancePerformanceSetting.Maximum; alertInfo.Minimum = topologyNode.OeePerformancePerformanceSetting.Minimum; break; case ContosoAlertCause.AlertCauseOeeQualityBelowMinimum: case ContosoAlertCause.AlertCauseOeeQualityAboveMaximum: alertInfo.Maximum = topologyNode.OeeQualityPerformanceSetting.Maximum; alertInfo.Minimum = topologyNode.OeeQualityPerformanceSetting.Minimum; break; case ContosoAlertCause.AlertCauseKpi1BelowMinimum: case ContosoAlertCause.AlertCauseKpi1AboveMaximum: alertInfo.Maximum = topologyNode.Kpi1PerformanceSetting.Maximum; alertInfo.Minimum = topologyNode.Kpi1PerformanceSetting.Minimum; break; case ContosoAlertCause.AlertCauseKpi2BelowMinimum: case ContosoAlertCause.AlertCauseKpi2AboveMaximum: alertInfo.Maximum = topologyNode.Kpi2PerformanceSetting.Maximum; alertInfo.Minimum = topologyNode.Kpi2PerformanceSetting.Minimum; break; } } } alertInfo.Key = alert.Key; alertInfo.SubKey = alert.SubKey; alertInfo.UxTime = string.Format("{0}-{1}", alert.Time.ToString("t"), alert.Time.ToString("d")); alertInfo.Time = alert.Time; alertInfo.Status = alert.Status; alertInfo.AlertActionInfo = topologyNode.CreateAlertActionInfo(alert.Cause, alert.SubKey); return(alertInfo); }
/// <summary> /// Gets alert information for the given topology node and all nodes below it. /// Multiple alerts with the same cause are consolidated and only the time information for the newest alert is returned. /// This information will be shown in the UX. /// </summary> public List <ContosoAlertInfo> GetAlerts(string key) { List <ContosoAlert> alertList = GetAllAlerts(key); List <ContosoAlertInfo> dashboardAlerts = new List <ContosoAlertInfo>(); ContosoAlertCause dummyAlertCause = new ContosoAlertCause(); ContosoAlertInfo dashboardAlert = new ContosoAlertInfo(); if (alertList.Count == 0) { return(dashboardAlerts); } List <string> allNodeKey = GetAllChildren(key); // Add key itself as well. allNodeKey.Add(key); foreach (var nodeKey in allNodeKey) { ContosoTopologyNode topologyNode = TopologyTable[nodeKey] as ContosoTopologyNode; List <ContosoAlert> childAlerts = topologyNode.Alerts; if (childAlerts.Count > 0) { if (topologyNode.GetType() == typeof(Station)) { Station station = topologyNode as Station; // The OPC UA nodes only generate value alerts. foreach (var opcNode in station.NodeList) { foreach (ContosoAlertCause alertCause in Enum.GetValues(dummyAlertCause.GetType())) { if (alertCause == ContosoAlertCause.AlertCauseValueBelowMinimum || alertCause == ContosoAlertCause.AlertCauseValueAboveMaximum) { // Aggregate similar alerts. List <ContosoAlert> sameCauseAlerts = childAlerts.FindAll(x => (x.Cause == alertCause && x.Key == nodeKey && x.SubKey == opcNode.NodeId && x.Time != DateTime.MinValue)); if (sameCauseAlerts.Count > 0) { // Find the newest alert. long newestTicks = sameCauseAlerts.Max(x => x.Time.Ticks); ContosoAlert alert = sameCauseAlerts.Find(x => x.Time.Ticks == newestTicks); // Create alert dashboard info and add it to the dashboard alert list. dashboardAlert = CreateDashboardAlertInfo(alert, sameCauseAlerts.Count, nodeKey); dashboardAlerts.Add(dashboardAlert); } } } } // For the station node we handle performance alerts. foreach (ContosoAlertCause alertCause in Enum.GetValues(dummyAlertCause.GetType())) { if (alertCause == ContosoAlertCause.AlertCauseValueBelowMinimum || alertCause == ContosoAlertCause.AlertCauseValueAboveMaximum) { continue; } // Aggregate similar alerts. List <ContosoAlert> sameCauseAlerts = childAlerts.FindAll(x => (x.Cause == alertCause && x.Key == nodeKey && x.Time != DateTime.MinValue)); if (sameCauseAlerts.Count > 0) { // Find the newest alert. long newestTicks = sameCauseAlerts.Max(x => x.Time.Ticks); ContosoAlert alert = sameCauseAlerts.Find(x => x.Time.Ticks == newestTicks); // Create alert dashboard info and add it to the dashboard alert list. dashboardAlert = CreateDashboardAlertInfo(alert, sameCauseAlerts.Count, nodeKey); dashboardAlerts.Add(dashboardAlert); } } } else { foreach (ContosoAlertCause alertCause in Enum.GetValues(dummyAlertCause.GetType())) { // Aggregate similar alerts. List <ContosoAlert> sameCauseAlerts = childAlerts.FindAll(x => (x.Cause == alertCause && x.Key == nodeKey && x.Time != DateTime.MinValue)); if (sameCauseAlerts.Count > 0) { // Find the newest alert. long newestTicks = sameCauseAlerts.Max(x => x.Time.Ticks); ContosoAlert alert = sameCauseAlerts.Find(x => x.Time.Ticks == newestTicks); // Create alert dashboard info and add it to the dashboard alert list. dashboardAlert = CreateDashboardAlertInfo(alert, sameCauseAlerts.Count, nodeKey); dashboardAlerts.Add(dashboardAlert); } } } } } dashboardAlerts.Sort(delegate(ContosoAlertInfo x, ContosoAlertInfo y) { if (x.Time < y.Time) { return(1); } if (x.Time == y.Time) { return(0); } return(-1); }); return(dashboardAlerts); }