namespace CordonelPreadjustmentUi.Processes.Actions { using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; using Xylem.Common.CommonCore.Configuration; using Xylem.Common.Hardware.WaterMeter.Genesis.Registers; using Xylem.Common.Logic.SoftwareAccessHelper; using static CordonelPreadjustmentUi.PreAdjustmentControl; /// /// Process for cordonel water meters with pressure sensor. /// /// /// Just started implementing pressure test for water meters with pressure sensor. /// public class PressureTestProcess : BaseProcess { /// /// Read / Write is pressure present for the water meter. /// /// /// Just started implementing pressure test for water meters with pressure sensor. /// private const string PRESSURE_PRESENT = "METROLOGYASST_PressurePresent"; /// /// Read / Write pressure measurements for the water meter. /// /// /// Just started implementing pressure test for water meters with pressure sensor. /// private const string PRESSURE_MEASURE = "METROLOGYASST_PressureMeasure"; /// /// Constructor for passing parameters to the base constructor of the derived class. /// /// The name used to show into the GUI. /// TODO: Get the right description. Probably the state for the box into the GUI. ??? /// TODO: Get the right description. Probably the success message to show into the GUI. ??? /// TODO: Get the right description. Probably the error message to show into the GUI. ??? /// TODO: Get the right description. Probably the expected time for process the pressure tests. ??? /// /// Just started implementing pressure test for water meters with pressure sensor. /// public PressureTestProcess(string processName, StatusPanelItems panelState, string performMessage, string failedMessage, int? expectedTimeS) : base(processName, panelState, performMessage, failedMessage, expectedTimeS) { } /// /// Determinates and initializes a list of pressure measure tests processes on the logedin cordonels with pressure sensor. /// Programm workflow for Cordonels with pressure sensor. /// When any of the water meters has presure sensor - load the test specification. /// Acording to the test specification process all meters, also the referenz on workplaces 11 and 12. /// /// Measurement as follow. /// Measure starts with = 1 /// Then registry is readeded and comaired to the referenz meters acording to the specification. /// /// /// Returns a for processing the pressure tests on the goggedin cordonels. /// /// Just started implementing pressure test for water meters with pressure sensor. /// public override List StartWork() { /// List of the processes to start. var listOfPresureTestTasks = new List(); var pressureTestSpecification = default(PressureTestSpecification); var pressureTestSpecificationLoaded = false; /// Just to not lose from focus the process progrss object. var processProgress = base.CurrentProcessProgress; var minPressureReferenzValue = default(int?); var maxPressureReferenzValue = default(int?); /// Looping trough all s to determinate whitch are with pressure sensor. foreach (var meterStateControl in base.MeterStateCtls) { /// If the meter is enabled and pressure sensor is present a new pressure mesure task should be initialized and added to the processes list. if (meterStateControl.IsEnabled) { /// Getting the meter object from the state control. var meter = meterStateControl.Meter; /// Reads the buffer for determinating if the pressure sensor is present. var isPressurePresentBuffer = meter.ReadRegister(PRESSURE_PRESENT); /// Converted value for determinating if the pressure sensor is present. var isPressurePresent = RegisterConverter.ByteArrayToValue(isPressurePresentBuffer); if (!isPressurePresent) { processProgress.DebugMessage($"Watermeter has no pressure sensor!", meterStateControl.Slot, "DC", meter.PcbId); continue; } /// Loads the pressure test specification from the defined web service if not yet loaded. if (pressureTestSpecification is null && !pressureTestSpecificationLoaded) { pressureTestSpecificationLoaded = true; pressureTestSpecification = this.LoadPressureTestSpecification(); /// if loading fails if (pressureTestSpecification is null) { processProgress.DebugMessage($"Test specification could not be loaded properly!", meterStateControl.Slot, "DC", meter.PcbId); // TODO: Handle possible exceptions by making http request. continue; } } /// Initialize min and max referenz values ones for all meters if (minPressureReferenzValue is null) { /// setting the min and max values on their oposit values. /// checking the equality later will set up a value by 1 or more referenz meters. minPressureReferenzValue = int.MaxValue; maxPressureReferenzValue = int.MinValue; if (processProgress.Setting.GetTempUseTempFlansh() || TempMeterStateCtls.Any(a => a.IsEnabled)) { /// Determinates the min and max values aus temperatur meters list. foreach (var referenzMeterState in base.TempMeterStateCtls) { if (referenzMeterState.IsEnabled) { var referenzMeter = referenzMeterState.Meter; /// Reset meter pressure referenzMeter.WriteRegister(PRESSURE_MEASURE, 1); if (!referenzMeter.IsLoggedOn) { referenzMeter.Login(); } var referenzPressureBuffer = referenzMeter.ReadRegister(PRESSURE_MEASURE); var referenzPressure = RegisterConverter.ByteArrayToValue(referenzPressureBuffer); if (referenzPressure < minPressureReferenzValue) { minPressureReferenzValue = referenzPressure; } if (referenzPressure > maxPressureReferenzValue) { maxPressureReferenzValue = referenzPressure; } } } } /// Continue if min pressure value is still its oposit for the type. There was no referenz zehler found. if (minPressureReferenzValue == int.MaxValue) { processProgress.DebugMessage($"No referenz watermeter found!", meterStateControl.Slot, "DC", meter.PcbId); continue; } listOfPresureTestTasks.Add(new Task(() => { var measuredTestValues = new int[pressureTestSpecification.NumberOfMeasurements]; var measurementDelyInS = pressureTestSpecification.TimeMeasurementsInS * 1000; var numberOfMeasurements = pressureTestSpecification.NumberOfMeasurements; var testDate = DateTime.Now; for (int measurement = 0; measurement < numberOfMeasurements; measurement++) { /// Reset meter pressure meter.WriteRegister(PRESSURE_MEASURE, 1); /// Read the new meter pressure var pressureMeasureBuffer = meter.ReadRegister(PRESSURE_MEASURE); var pressureInPascals = RegisterConverter.ByteArrayToValue(pressureMeasureBuffer); measuredTestValues[measurement] = pressureInPascals; processProgress.DebugMessage($"Measure {measurement + 1}: {pressureInPascals}Pa", meterStateControl.Slot, "DC", meter.PcbId); /// Dely only for first n - 1 measurements if (measurement < numberOfMeasurements - 1) { Thread.Sleep(measurementDelyInS); } } var avgPressure = (int)measuredTestValues.Average(); var testPassed = minPressureReferenzValue <= avgPressure && avgPressure <= maxPressureReferenzValue; var avgPressureInBars = avgPressure / 100_000F; processProgress.DebugMessage($"Average pressure: {avgPressure}Pa", meterStateControl.Slot, "DC", meter.PcbId); processProgress.DebugMessage($"Average pressure: {avgPressureInBars}Bar", meterStateControl.Slot, "DC", meter.PcbId); if (!this.PostPressureTestResult(meter.PcbId, avgPressureInBars, testPassed, testDate)) { processProgress.DebugMessage($"Test result was not posted!", meterStateControl.Slot, "DC", meter.PcbId); return false; } return testPassed; })); } } } return listOfPresureTestTasks; } private PressureTestSpecification LoadPressureTestSpecification() { try { var responseContent = LocalWebRequest.GetRequest(ServiceUrls.GetPressureSensorSpecificationURL); return JsonConvert.DeserializeObject(responseContent); } catch (Exception e) { return null; } } private bool PostPressureTestResult(string pcbIdText, float avgPressure, bool passed, DateTime testDate) { try { return LocalWebRequest.PostRequestAsync(ServiceUrls.PostPressureSensorResultURL, json: new { PcbId = int.TryParse(pcbIdText, out int pcbId) ? pcbId : default(int?), AvgPressureInBar = avgPressure, TestPassed = passed, TestDate = testDate, }); } catch (Exception e) { return false; } } } internal class PressureTestSpecification { public int NumberOfMeasurements { get; set; } public int TimeMeasurementsInS { get; set; } public float MaxDeviationInBar { get; set; } } }