tbf/TBF/Rig/Various/StatisticsMonitoring/ProcessStatistics.cs

222 lines
7.9 KiB
C#

///
/// Copyright (c) 2020 Sensus Slovensko a.s.
///
using System;
using System.Collections.Generic;
using log4net;
using NHibernate;
using Common;
using Events.Entities;
using Results.Entities;
namespace TBF.Rig.Various.StatisticsMonitoring
{
public class ProcessStatistics : ComponentBase, IOperation, GenericDevices.IStatisticsMonitoring
{
private static readonly ILog log = LogManager.GetLogger(typeof(ProcessStatistics));
public override string ToString() { return string.Format("{0}({1})", ClassName, Cfg.ToString(-1)); }
readonly StatisticsCfg statisticsCfg;
int lastBatchNr;
public ProcessStatistics() {}
public ProcessStatistics(Generic.IComponentCfg cfg)
: base(cfg)
{
statisticsCfg = cfg as StatisticsCfg;
}
public override void Initialize()
{
ApplyConfig();
log.FatalFormat("{0} initialized: {1}", Name, this);
}
void ApplyConfig()
{
// TODO
}
#region Configuration Change Handling
public static void OnCfgChange(object sender, CfgChangeArgs args)
{
if (CfgChangeHandler == null) return;
try { CfgChangeHandler(sender, args); }
catch (Exception e) { log.Error("CfgChangeHandler(...) failed", e); }
}
public static event EventHandler<CfgChangeArgs> CfgChangeHandler;
public override void StartChangeHandler()
{
CfgChangeHandler += delegate(object sender, CfgChangeArgs args)
{
StatisticsCfg newCfg = args.Cfg as StatisticsCfg;
if (newCfg != null && newCfg.Name.Equals(Name))
{
if (args.Command == CfgChangeCmd.CfgChange)
{
statisticsCfg.EventSource = newCfg.EventSource;
statisticsCfg.iPerlHeadFailureRateThreshold = newCfg.iPerlHeadFailureRateThreshold;
ApplyConfig();
}
}
};
}
#endregion Configuration Change Handling
/// <summary>
/// Writes the test cycle results into a file
/// Events:
/// Event.StatisticsProcessed
/// Event.Busy
/// </summary>
/// <param name="batch">Results to write into a file</param>
/// <returns>Reference to the operation</returns>
public IOperation ProcessStatisticsOp(int lastBatchNr)
{
this.lastBatchNr = lastBatchNr;
return this;
}
public void Start()
{
Process(lastBatchNr, statisticsCfg);
}
public Event Run()
{
return Event.StatisticsProcessed;
}
public void Stop()
{
}
/// <summary>
/// Process recent batch results and calculate statistics of iPERL head failures
/// </summary>
/// <param name="batchNr">Number of the last saved batch</param>
void Process(int batchNr, StatisticsCfg statisticsCfg)
{
const int RequiredUsages = 10;
const int MaxBatches = 20;
float iperlHeadFailureRateThreshold = (float)statisticsCfg.iPerlHeadFailureRateThreshold / 100.0f;
int completeBatchesProcessed = 0;
int[] usages = new int[TBF.Data.WMsCount];
int[] failures = new int[TBF.Data.WMsCount];
for (int i = 0; i < TBF.Data.WMsCount; i++) usages[i] = failures[i] = 0;
///
/// Read results of recent batches (up to 'MaxBatches')
/// Take into account only batches where the 1st test in named 'RFID' and
/// at least one water meter completed all tests.
///
{
ISession session = null;
try
{
session = TBF.DB.ResultsDBSessionFactory.OpenSession();
int usagesMin;
do
{
usagesMin = 0;
IList<Batch> batches = session.QueryOver<Batch>()
.Where(x => x.BatchNr == batchNr)
.List();
batchNr--;
if (batches.Count != 1 || batches[0].TestRslts.Count < 1 || batches[0].TestRslts[0].MethodClass != "TestMethods.iPerlCommunication")
{
continue;
}
bool isACompleteBatch = false;
foreach (var wm in batches[0].WaterMeters)
{
int i = wm.WMPosition - 1;
if (0 <= i && i < TBF.Data.WMsCount && usages[i] < RequiredUsages && !wm.Disabled && wm.CompletedFromTests())
{
isACompleteBatch = true;
usages[i]++;
if (!wm.MeterTestRslts[0].Passed) failures[i]++;
}
}
usagesMin = int.MaxValue;
for (int i = 0; i < TBF.Data.WMsCount; i++) if (usagesMin > usages[i]) usagesMin = usages[i];
if (isACompleteBatch) completeBatchesProcessed++;
}
while ((usagesMin < RequiredUsages) && (batchNr > 0) && (completeBatchesProcessed < MaxBatches));
}
catch (Exception exc)
{
log.ErrorFormat("Failed to calculate iPERL head usage statistics: {0}", exc.Message);
}
finally
{
if (session != null && session.IsOpen) session.Close();
}
}
///
/// Find out whether at lest one event needs to be triggered
///
bool doTriggerEvents = false;
for (int i = 0; i < TBF.Data.WMsCount; i++)
{
if ((usages[i] > 0) && (iperlHeadFailureRateThreshold > 0) && (float)failures[i] / (float)usages[i] >= iperlHeadFailureRateThreshold)
{
doTriggerEvents = true;
break;
}
}
if (doTriggerEvents && TBF.DB.EventsDBSessionFactory != null)
{
///
/// Trigger events
///
ISession session = null;
try
{
session = TBF.DB.EventsDBSessionFactory.OpenSession();
Events.DB.LoadSubscribers(session);
for (int i = 0; i < TBF.Data.WMsCount; i++)
{
if ((usages[i] > 0) && (iperlHeadFailureRateThreshold > 0) && (float)failures[i] / (float)usages[i] >= iperlHeadFailureRateThreshold)
{
TBF.UiBridge.Bridge.TriggerEvent(session,
statisticsCfg.EventSource,
EventClass.EquipmentHW,
Severity.Error,
string.Format("Príliš veľa chýb hlavice č. {0}", i + 1),
string.Format("Percento chýb je {0}%", (100 * failures[i]) / usages[i]),
SubscriberGroup.Metrology | SubscriberGroup.Maintenance | SubscriberGroup.Production);
}
}
}
catch (Exception exc)
{
log.ErrorFormat("Failed to trigger events: source = {0}, message = {1}", statisticsCfg.EventSource, exc.Message);
}
finally
{
if (session != null && session.IsOpen) session.Close();
}
}
}
}
}