2020-05-05 13:42:15 +00:00
|
|
|
|
///
|
|
|
|
|
|
/// Copyright (c) 2020 Sensus Slovensko a.s.
|
|
|
|
|
|
///
|
|
|
|
|
|
using System;
|
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
|
using log4net;
|
|
|
|
|
|
using NHibernate;
|
|
|
|
|
|
using Events.Entities;
|
|
|
|
|
|
using Results.Entities;
|
|
|
|
|
|
|
|
|
|
|
|
namespace TBF.BenchControl.Various.StatisticsMonitoring
|
|
|
|
|
|
{
|
|
|
|
|
|
public class ProcessStatistics : ComponentBase, IOperation, GenericDevices.IStatisticsMonitoring
|
|
|
|
|
|
{
|
|
|
|
|
|
private static readonly ILog log = LogManager.GetLogger(typeof(ProcessStatistics));
|
2021-04-07 07:57:42 +00:00
|
|
|
|
public override string ToString() { return string.Format("{0}({1})", ClassName, Cfg.ToString(-1)); }
|
2020-05-05 13:42:15 +00:00
|
|
|
|
|
|
|
|
|
|
readonly StatisticsCfg statisticsCfg;
|
|
|
|
|
|
|
|
|
|
|
|
int lastBatchNr;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public ProcessStatistics() {}
|
|
|
|
|
|
|
|
|
|
|
|
public ProcessStatistics(Generic.IComponentCfg cfg)
|
|
|
|
|
|
: base(cfg)
|
|
|
|
|
|
{
|
|
|
|
|
|
statisticsCfg = cfg as StatisticsCfg;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2021-04-07 07:57:42 +00:00
|
|
|
|
public override void Initialize()
|
|
|
|
|
|
{
|
|
|
|
|
|
ApplyConfig();
|
|
|
|
|
|
log.FatalFormat("{0} initialized: {1}", Name, this);
|
|
|
|
|
|
}
|
2020-05-05 13:42:15 +00:00
|
|
|
|
|
|
|
|
|
|
void ApplyConfig()
|
|
|
|
|
|
{
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#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[Config.Data.WMsCount];
|
|
|
|
|
|
int[] failures = new int[Config.Data.WMsCount];
|
|
|
|
|
|
for (int i = 0; i < Config.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.
|
|
|
|
|
|
///
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
ISession session = Results.DB.CreateSession();
|
|
|
|
|
|
|
|
|
|
|
|
int usagesMin;
|
|
|
|
|
|
do
|
|
|
|
|
|
{
|
|
|
|
|
|
usagesMin = 0;
|
|
|
|
|
|
IList<Batch> batches = session.QueryOver<Batch>()
|
|
|
|
|
|
.Where(x => x.Id == 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 < Config.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 < Config.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);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
/// Find out whether at lest one event needs to be triggered
|
|
|
|
|
|
///
|
|
|
|
|
|
bool doTriggerEvents = false;
|
|
|
|
|
|
for (int i = 0; i < Config.Data.WMsCount; i++)
|
|
|
|
|
|
{
|
|
|
|
|
|
if ((usages[i] > 0) && (iperlHeadFailureRateThreshold > 0) && (float)failures[i] / (float)usages[i] >= iperlHeadFailureRateThreshold)
|
|
|
|
|
|
{
|
|
|
|
|
|
doTriggerEvents = true;
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2020-11-18 09:44:30 +00:00
|
|
|
|
if (doTriggerEvents && !string.IsNullOrEmpty(Events.DB.ConnectionString))
|
2020-05-05 13:42:15 +00:00
|
|
|
|
{
|
|
|
|
|
|
///
|
|
|
|
|
|
/// Trigger events
|
|
|
|
|
|
///
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
ISession session = Events.DB.CreateSession();
|
|
|
|
|
|
Events.DB.LoadSubscribers(session);
|
|
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < Config.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);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|