common/CordonelPreadjustmentUi/Processes/Actions/PressureTestProcess.cs
2026-04-23 17:50:07 +02:00

257 lines
13 KiB
C#

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;
/// <summary>
/// Process for cordonel water meters with pressure sensor.
/// </summary>
/// <remarks date="2023-05-23" author="Stoyan Zlatev">
/// Just started implementing pressure test for water meters with pressure sensor.
/// </remarks>
public class PressureTestProcess : BaseProcess
{
/// <summary>
/// Read / Write is pressure present for the water meter.
/// </summary>
/// <remarks date="2023-05-23" author="Stoyan Zlatev">
/// Just started implementing pressure test for water meters with pressure sensor.
/// </remarks>
private const string PRESSURE_PRESENT = "METROLOGYASST_PressurePresent";
/// <summary>
/// Read / Write pressure measurements for the water meter.
/// </summary>
/// <remarks date="2023-05-23" author="Stoyan Zlatev">
/// Just started implementing pressure test for water meters with pressure sensor.
/// </remarks>
private const string PRESSURE_MEASURE = "METROLOGYASST_PressureMeasure";
/// <summary>
/// Constructor for passing parameters to the base constructor of the derived class.
/// </summary>
/// <param name="processName">The name used to show into the GUI.</param>
/// <param name="panelState">TODO: Get the right description. Probably the state for the box into the GUI. ???</param>
/// <param name="performMessage">TODO: Get the right description. Probably the success message to show into the GUI. ???</param>
/// <param name="failedMessage">TODO: Get the right description. Probably the error message to show into the GUI. ???</param>
/// <param name="expectedTimeS">TODO: Get the right description. Probably the expected time for process the pressure tests. ???</param>
/// <remarks date="2023-05-23" author="Stoyan Zlatev">
/// Just started implementing pressure test for water meters with pressure sensor.
/// </remarks>
public PressureTestProcess(string processName, StatusPanelItems panelState, string performMessage, string failedMessage, int? expectedTimeS)
: base(processName, panelState, performMessage, failedMessage, expectedTimeS)
{
}
/// <summary>
/// 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.
/// <list type="number">
/// <listheader>Measurement as follow.</listheader>
/// <item>Measure starts with <see cref="PRESSURE_MEASURE"/> = 1</item>
/// <item>Then registry is readeded and comaired to the referenz meters acording to the specification.</item>
/// </list>
/// </summary>
/// <returns>Returns a <see cref="List{Task}"/> for processing the pressure tests on the goggedin cordonels.</returns>
/// <remarks date="2023-05-23" author="Stoyan Zlatev">
/// Just started implementing pressure test for water meters with pressure sensor.
/// </remarks>
public override List<Task> StartWork()
{
/// List of the processes to start.
var listOfPresureTestTasks = new List<Task>();
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 <see cref="MeterStateControl"/>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<bool>(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<int>(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<bool>(() =>
{
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<int>(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<PressureTestSpecification>(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; }
}
}