/// /// Copyright (c) 2017-2020 Sensus Slovensko a.s. /// using System; using System.Collections.Generic; using log4net; using Config.Entities; using Results.Entities; using TBF.BenchControl.Sequences; namespace TBF.BenchControl.Various.ErrorFlags { public class Errors : ComponentBase, GenericDevices.IErrorFlags { private static readonly ILog log = LogManager.GetLogger(typeof(Errors)); public override string ToString() { return string.Format("{0}({1})", this.GetType().Namespace.Substring(17), Cfg.ToString(1)); } /// /// Cfg /// readonly ErrorsCfg errorsCfg; /// /// Ger error flags for a test /// /// A valid test result /// true = diverter was used (times apply) /// true = start/stop valve was used (times apply) /// Diverter or valve switch time in s on test start /// Diverter or valve switch time in s on test end /// Error flags public long GetErrorFlags(TestRslt testRslt, bool diverter, bool startStopValve, float switchTimeStart, float switchTimeEnd, out long infoFlags) { /// Any E# is 'true' on error, 'false' when OK /// Average flow bool E1 = (testRslt.FlowVolume < testRslt.Qfrom()) || (testRslt.FlowVolume > testRslt.Qto()); /// Max. and min. up and down water temperature bool E2 = ProcessData.TempUpStat.Min < testRslt.TempLimLo() || ProcessData.TempUpStat.Max > testRslt.TempLimHi() || ProcessData.TempDownStat.Min < testRslt.TempLimLo() || ProcessData.TempDownStat.Max > testRslt.TempLimHi(); /// Max. flow deviation bool E3 = ProcessData.RefFlowStat.Min < ProcessData.RefFlowStat.Average * (1.0f - errorsCfg.TestParams.Delta_Q_pct / 100.0f) || ProcessData.RefFlowStat.Max > ProcessData.RefFlowStat.Average * (1.0f + errorsCfg.TestParams.Delta_Q_pct / 100.0f); /// Max. up and down water temperature deviation bool E4 = ProcessData.TempUpStat.Min < ProcessData.TempUpStat.Average - errorsCfg.TestParams.Delta_T || ProcessData.TempUpStat.Max > ProcessData.TempUpStat.Average + errorsCfg.TestParams.Delta_T || ProcessData.TempDownStat.Min < ProcessData.TempDownStat.Average - errorsCfg.TestParams.Delta_T || ProcessData.TempDownStat.Max > ProcessData.TempDownStat.Average + errorsCfg.TestParams.Delta_T; /// Max. absolute value of up and down water temperature difference bool E5 = Math.Abs(ProcessData.TempUpStat.Average - ProcessData.TempDownStat.Average) > errorsCfg.TestParams.Delta_Tup_Tdn; bool E6 = false; /// Test time (min) bool E7 = testRslt.TestTime < errorsCfg.TestParams.TestTime_min; /// Test time (max) bool E8 = testRslt.TestTime > errorsCfg.TestParams.TestTime_max; bool E9 = false; bool E10 = false; if (diverter) { E9 = (Math.Abs(switchTimeStart - switchTimeEnd) > errorsCfg.TestParams.Coef_E9 * (switchTimeStart + switchTimeEnd) + errorsCfg.TestParams.Offset_E9); E10 = ((switchTimeStart + switchTimeEnd) > errorsCfg.TestParams.Coef_E10 * testRslt.TestTime); } bool E11 = false; bool E12 = false; if (startStopValve) { E11 = ((switchTimeStart + switchTimeEnd) > errorsCfg.TestParams.Coef_E11 * testRslt.TestTime); E12 = (Math.Abs(switchTimeStart - switchTimeEnd) > errorsCfg.TestParams.Coef_E12 * (switchTimeStart + switchTimeEnd) + errorsCfg.TestParams.Offset_E12); } /// Ambient temperature bool E13 = ProcessData.AmbTempStat.Min < errorsCfg.TestParams.AmbTemp_min || ProcessData.AmbTempStat.Max > errorsCfg.TestParams.AmbTemp_max; /// Water pressure bool E14 = ProcessData.PressUpStat.Min < errorsCfg.TestParams.Pressure_min || ProcessData.PressUpStat.Max > errorsCfg.TestParams.Pressure_max || ProcessData.PressDownStat.Min < errorsCfg.TestParams.Pressure_min || ProcessData.PressDownStat.Max > errorsCfg.TestParams.Pressure_max; /// Max. and min. flow double rectifiedFlowMin = (testRslt.FlowMean == 0) ? testRslt.FlowMin : testRslt.FlowMin * testRslt.FlowVolume / testRslt.FlowMean; double rectifiedFlowMax = (testRslt.FlowMean == 0) ? testRslt.FlowMax : testRslt.FlowMax * testRslt.FlowVolume / testRslt.FlowMean; bool E21 = rectifiedFlowMin < testRslt.Qfrom() || rectifiedFlowMax > testRslt.Qto(); /// Electrical conductivity of water bool E36 = ProcessData.ConductStat.Min < errorsCfg.TestParams.Conductivity_min || ProcessData.ConductStat.Max > errorsCfg.TestParams.Conductivity_max; long errorFlags = 0; sbyte on = (sbyte)ErrorFlagsMode.On; if (E1 && (errorsCfg.TestParams.E1 == on)) errorFlags |= (long)ErrorFlagMask.E1; if (E2 && (errorsCfg.TestParams.E2 == on)) errorFlags |= (long)ErrorFlagMask.E2; if (E3 && (errorsCfg.TestParams.E3 == on)) errorFlags |= (long)ErrorFlagMask.E3; if (E4 && (errorsCfg.TestParams.E4 == on)) errorFlags |= (long)ErrorFlagMask.E4; if (E5 && (errorsCfg.TestParams.E5 == on)) errorFlags |= (long)ErrorFlagMask.E5; if (E6 && (errorsCfg.TestParams.E6 == on)) errorFlags |= (long)ErrorFlagMask.E6; if (E7 && (errorsCfg.TestParams.E7 == on)) errorFlags |= (long)ErrorFlagMask.E7; if (E8 && (errorsCfg.TestParams.E8 == on)) errorFlags |= (long)ErrorFlagMask.E8; if (E9 && (errorsCfg.TestParams.E9 == on)) errorFlags |= (long)ErrorFlagMask.E9; if (E10 && (errorsCfg.TestParams.E10 == on)) errorFlags |= (long)ErrorFlagMask.E10; if (E11 && (errorsCfg.TestParams.E11 == on)) errorFlags |= (long)ErrorFlagMask.E11; if (E12 && (errorsCfg.TestParams.E12 == on)) errorFlags |= (long)ErrorFlagMask.E12; if (E13 && (errorsCfg.TestParams.E13 == on)) errorFlags |= (long)ErrorFlagMask.E13; if (E14 && (errorsCfg.TestParams.E14 == on)) errorFlags |= (long)ErrorFlagMask.E14; /// E15, E16, E17, E18, E19, E20 skipped if (E21 && (errorsCfg.TestParams.E21 == on)) errorFlags |= (long)ErrorFlagMask.E21; if (E36 && (errorsCfg.TestParams.E36 == on)) errorFlags |= (long)ErrorFlagMask.E36; long _infoFlags = 0; sbyte info = (sbyte)ErrorFlagsMode.Info; if (E1 && (errorsCfg.TestParams.E1 == info)) _infoFlags |= (long)ErrorFlagMask.E1; if (E2 && (errorsCfg.TestParams.E2 == info)) _infoFlags |= (long)ErrorFlagMask.E2; if (E3 && (errorsCfg.TestParams.E3 == info)) _infoFlags |= (long)ErrorFlagMask.E3; if (E4 && (errorsCfg.TestParams.E4 == info)) _infoFlags |= (long)ErrorFlagMask.E4; if (E5 && (errorsCfg.TestParams.E5 == info)) _infoFlags |= (long)ErrorFlagMask.E5; if (E6 && (errorsCfg.TestParams.E6 == info)) _infoFlags |= (long)ErrorFlagMask.E6; if (E7 && (errorsCfg.TestParams.E7 == info)) _infoFlags |= (long)ErrorFlagMask.E7; if (E8 && (errorsCfg.TestParams.E8 == info)) _infoFlags |= (long)ErrorFlagMask.E8; if (E9 && (errorsCfg.TestParams.E9 == info)) _infoFlags |= (long)ErrorFlagMask.E9; if (E10 && (errorsCfg.TestParams.E10 == info)) _infoFlags |= (long)ErrorFlagMask.E10; if (E11 && (errorsCfg.TestParams.E11 == info)) _infoFlags |= (long)ErrorFlagMask.E11; if (E12 && (errorsCfg.TestParams.E12 == info)) _infoFlags |= (long)ErrorFlagMask.E12; if (E13 && (errorsCfg.TestParams.E13 == info)) _infoFlags |= (long)ErrorFlagMask.E13; if (E14 && (errorsCfg.TestParams.E14 == info)) _infoFlags |= (long)ErrorFlagMask.E14; /// E15, E16, E17, E18, E19, E20 skipped if (E21 && (errorsCfg.TestParams.E21 == info)) _infoFlags |= (long)ErrorFlagMask.E21; if (E36 && (errorsCfg.TestParams.E36 == info)) _infoFlags |= (long)ErrorFlagMask.E36; infoFlags = _infoFlags; return errorFlags; } MeterTestRslt GetMtrTstRsltFromNames(IList meterTestRslts, string testNames) { if (string.IsNullOrEmpty(testNames)) return null; string[] names = testNames.Split(new char[] { ';' }); foreach (var nm in names) { foreach (var mtr in meterTestRslts) if (mtr.Name() == nm) return mtr; } return null; /// No matching MeterTestRslt found } /// /// Get water meter error flags E15 and E16 (evaluated from three meter test results) /// /// Meter test results /// Error flags public long GetWMtrErrorFlags(IList meterTestRslts, out long infoIndicators) { long _infoIndicators = 0; long errorIndicators = 0; MeterTestRslt mtrQ3 = GetMtrTstRsltFromNames(meterTestRslts, errorsCfg.Q3Names); MeterTestRslt mtrQ2 = GetMtrTstRsltFromNames(meterTestRslts, errorsCfg.Q2Names); MeterTestRslt mtrQ1 = GetMtrTstRsltFromNames(meterTestRslts, errorsCfg.Q1Names); if (mtrQ3 == null || !mtrQ3.TestDone || mtrQ2 == null || !mtrQ2.TestDone || mtrQ1 == null || !mtrQ1.TestDone) { /// No error indicator; } else if (((mtrQ3.Error > mtrQ3.ErrLimHi() / 2) && (mtrQ2.Error > mtrQ2.ErrLimHi() / 2) && (mtrQ1.Error > mtrQ1.ErrLimHi() / 2)) || ((mtrQ3.Error < mtrQ3.ErrLimLo() / 2) && (mtrQ2.Error < mtrQ2.ErrLimLo() / 2) && (mtrQ1.Error < mtrQ1.ErrLimLo() / 2))) { if (errorsCfg.TestParams.E15 == (sbyte)ErrorFlagsMode.Info) _infoIndicators |= (long)ErrorFlagMask.E15; /// Set E15 if (errorsCfg.TestParams.E15 == (sbyte)ErrorFlagsMode.On) errorIndicators |= (long)ErrorFlagMask.E15; /// Set E15 } foreach (var mtr in meterTestRslts) { errorIndicators |= mtr.ErrorIndicators; /// Set any error flag from mtr.ErrorIndicators (iPerl) } infoIndicators = _infoIndicators; return errorIndicators; } public Errors() { } public Errors(Generic.IComponentCfg cfg, IList components) : base(cfg) { errorsCfg = cfg as ErrorsCfg; StartChangeHandler(); log.Warn(this.ToString()); } #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 CfgChangeHandler; public override void StartChangeHandler() { CfgChangeHandler += delegate(object sender, CfgChangeArgs args) { ErrorsCfg tmpcfg = args.Cfg as ErrorsCfg; if (tmpcfg != null && tmpcfg.Name.Equals(Name)) { if (args.Command == CfgChangeCmd.CfgChange) { errorsCfg.Q3Names = tmpcfg.Q3Names; errorsCfg.Q2Names = tmpcfg.Q2Names; errorsCfg.Q1Names = tmpcfg.Q1Names; } } }; } #endregion Configuration Change Handling } }