OMNI testen on 2020

This commit is contained in:
Stoyan Zlatev
2024-01-05 16:02:53 +01:00
parent 10a366ad9c
commit a05e490ef3
16 changed files with 1191 additions and 212 deletions
+2 -2
View File
@@ -4,8 +4,8 @@
<add key="PSNR" value="2015"/>
<add key="Type" value="T2" />
<add key="COMPorts" value="COM4" />
<!--<add key="ExchangeHubURL" value="http://sla12iis01.emea.sensus.net/LaaProductionWeb" />-->
<add key="ExchangeHubURL" value="http://localhost:52822/LaaProductionWeb"/>
<add key="ExchangeHubURL" value="http://sla12iis01.emea.sensus.net/LaaProductionWeb" />
<!--<add key="ExchangeHubURL" value="http://localhost:52822/LaaProductionWeb"/>-->
<add key="OmniDB" value="Server=SLASQL01.emea.sensus.net; Database=AuftragKopie; User ID=sa; Password=sqlserver;" />
</appSettings>
</configuration>
@@ -2,7 +2,6 @@
{
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
@@ -10,6 +9,7 @@
using OmniPlus;
using OmniPlus.Features;
using OmniPlus.Features.Enums;
using OmniPlus.Inspection;
using OMNIPruefung.ViewModels.Base;
@@ -127,12 +127,12 @@
}
}
public int AvailableIn { get; set; }
public OMNIPlusVM Meter { get; }
internal void CancelExecution()
{
this.Dispose();
this.State = "Prüfung abgebrochen.";
this.Connected = false;
this.Running = false;
@@ -140,7 +140,7 @@
internal Task InitializeAsync(CancellationToken cancellationToken)
{
cancellationToken.Register(this.Dispose);
cancellationToken.Register(this.CancelExecution);
void Initialize()
{
@@ -163,7 +163,7 @@
if (this.IsRunning())
{
this.State = "Mit IRDA verbunden";
this.State = "Verbunden";
}
else
{
@@ -181,12 +181,12 @@
}
}
return Task.Factory.StartNew(Initialize, cancellationToken);
return this.StartNew(Initialize, cancellationToken);
}
internal Task ReadSystemParametersAsync(CancellationToken cancelationToken)
{
cancelationToken.Register(this.Dispose);
cancelationToken.Register(this.CancelExecution);
void ReadSystemParameters()
{
@@ -216,12 +216,12 @@
}
}
return Task.Factory.StartNew(ReadSystemParameters, cancelationToken);
return this.StartNew(ReadSystemParameters, cancelationToken);
}
internal Task SetInputVolumeAsync(OmniPlusType defaults, CancellationToken cancelationToken)
{
cancelationToken.Register(this.Dispose);
cancelationToken.Register(this.CancelExecution);
void SetInputVolume()
{
@@ -232,6 +232,8 @@
if (this.Running)
{
this.Meter.Add(defaults.InputVolume);
this.State = "Flow-Eigenschaften konfiguriert";
}
else
@@ -247,87 +249,12 @@
}
}
return Task.Factory.StartNew(SetInputVolume, cancelationToken);
}
internal Task SetReferenceVolumeAsync(OmniPlusTestPoint pp, double referenceV, CancellationToken cancellationToken)
{
cancellationToken.Register(this.Dispose);
void SetReferenceVolume()
{
if (this.results.ContainsKey(pp))
{
this.results[pp].VolumeMessured = referenceV;
}
}
return Task.Factory.StartNew(SetReferenceVolume, cancellationToken);
}
internal Task SaveInspectionAsync(CancellationToken cancellationToken)
{
cancellationToken.Register(this.Dispose);
void SaveInspection()
{
if (!this.IsRunning())
{
return;
}
var resultsBuilder = new StringBuilder();
resultsBuilder.AppendLine($"GPM\t"
+ $"m³/h\t"
+ $"ml/R\t"
+ $"R(soll)\t"
+ $"R(ist)\t"
+ $"T(soll)\t"
+ $"T(ist)\t"
+ $"m³(ist)\t"
+ $"Diff %\t"
+ $"Factor %\t"
+ $"Min\t"
+ $"Max\t");
foreach (var kvp in this.results)
{
var pruefpunkt = kvp.Key;
var ergebnis = kvp.Value;
resultsBuilder.AppendLine($"{pruefpunkt.GalPerMin:0.00}\t"
+ $"{pruefpunkt.VolumeM3H:0.00}\t"
+ $"{pruefpunkt.MlPerRotation:0.00}\t"
+ $"{pruefpunkt.Rotations}\t"
+ $"{ergebnis.Rotations}\t"
+ $"{pruefpunkt.Duration}\t"
+ $"{ergebnis.Duration}\t"
+ $"{ergebnis.VolumeMessured}\t"
+ $"{ergebnis.DifferencePercentage:0.00}%\t"
+ $"{this.GetCorrectionFactor():0.00}%\t"
+ $"{pruefpunkt.MinDiff:0.00}\t"
+ $"{pruefpunkt.MaxDiff:0.00}\t");
}
this.TestResults = resultsBuilder.ToString();
try
{
File.WriteAllText($"{this.Header}_{DateTime.Now:yyyyMMddHHmmss}.csv", this.TestResults);
}
catch (Exception e)
{
this.State = e.ToString();
}
}
return Task.Factory.StartNew(SaveInspection, cancellationToken);
return this.StartNew(SetInputVolume, cancelationToken);
}
internal Task StartPPCalibrationAsync(OmniPlusTestPoint pp, CancellationToken cancellationToken)
{
cancellationToken.Register(this.Dispose);
cancellationToken.Register(this.CancelExecution);
void StartPPCalibration()
{
@@ -340,6 +267,8 @@
var activationResponse = connection.StartChamberCalibration(pp.Rotations, pp.Duration);
this.Running = activationResponse.Succeeded && activationResponse.Control == ChamberCalibrationResponse.TEST_ACTIVATED;
this.Meter.Add(pp);
if (this.Running)
{
this.State = $"PP {rotations}/{duration} (rotations/seconds) wurde gestarted.";
@@ -353,12 +282,12 @@
this.Progress += 10;
}
return Task.Factory.StartNew(StartPPCalibration, cancellationToken);
return this.StartNew(StartPPCalibration, cancellationToken);
}
internal Task StopPPCalibrationAsync(OmniPlusTestPoint pp, CancellationToken cancellationToken)
internal Task StopPPCalibrationAsync(OmniPlusTestPoint pp, double referenceV, CancellationToken cancellationToken)
{
cancellationToken.Register(this.Dispose);
cancellationToken.Register(this.CancelExecution);
void StopPPCalibration()
{
@@ -366,11 +295,14 @@
{
var calibrationResult = connection.ViewChamberCalibration();
this.results[pp].Rotations = calibrationResult.Rotations;
this.results[pp].Duration = calibrationResult.Duration;
this.results[pp].Duration = calibrationResult.DurationSec;
this.results[pp].MeterVolume = pp.VolumeM3(this.results[pp]);
this.results[pp].VolumeMessured = referenceV;
this.Running = calibrationResult.Succeeded && calibrationResult.Control == ChamberCalibrationResponse.TEST_COMPLETED;
this.Meter.Add(this.results[pp]);
if (this.Running)
{
this.State = $"PP {pp.Rotations}/{pp.Duration} (rotations/seconds) wurde durchgeführt.";
@@ -384,7 +316,201 @@
this.Progress += 10;
}
return Task.Factory.StartNew(StopPPCalibration, cancellationToken);
return this.StartNew(StopPPCalibration, cancellationToken);
}
internal Task FinishInspectionAsync(CancellationToken cancellationToken)
{
cancellationToken.Register(this.CancelExecution);
void FinishInspection()
{
if (!this.IsRunning())
{
return;
}
var configurationParameters = this.connection.ViewConfigurationParameters();
var canContinue = configurationParameters.Succeeded;
// if (canContinue)
{
this.Meter.Add(configurationParameters);
// TODO: Uncomment in production
// var systemTimeReset = connection.SetSystemTime();
//canContinue = systemTimeReset.Succeeded;
}
// if (canContinue)
{
var registerSettings = new RegisterSettings();
registerSettings.IntPart = this.Meter.IntPart;
registerSettings.Fraction = this.Meter.Fraction;
registerSettings.Size = this.Meter.Size;
registerSettings.Range = this.Meter.Range;
registerSettings.VolumePerPulseUnit = 0x00;
registerSettings.MeterUnits = (byte)MessurementUnits.USGallons;
registerSettings.FlowUnits = (byte)MessurementUnits.USGallons;
registerSettings.FlowRate = (byte)TimeUnits.Minutes;
registerSettings.FactoryCorrection = this.Meter.FactoryCorrection;
registerSettings.FieldCorrection = 0x00;
registerSettings.PulseWeight = 0x01;
registerSettings.PulseWidth = 0x02;
registerSettings.PulseUpdate = 0x00;
var response = this.connection.Set(registerSettings);
canContinue = response.Succeeded;
}
// if (canContinue)
{
var configurationParametersSet = new ConfigurationParametersSet();
configurationParametersSet.ProgrammableID = this.Meter.BuildInfo;
configurationParametersSet.FactoryID = this.Meter.BuildInfo;
configurationParametersSet.NumberOfReadingDigits = 8;
configurationParametersSet.ReadingPreset = "000000000";
configurationParametersSet.OptionalUniDirFields = 1;
configurationParametersSet.AlarmPercistancePeriodDays = 31;
configurationParametersSet.DataLogIntervalMinutes = 60;
configurationParametersSet.ManifacturingTime = Epoch20000101.UTCNow - 30000;
configurationParametersSet.SystemTime = Epoch20000101.UTCNow;
configurationParametersSet.RebootCount = 0;
configurationParametersSet.BuildInfo = this.Meter.BuildInfo;
var response = this.connection.Set(configurationParametersSet);
canContinue = response.Succeeded;
}
// if (canContinue)
{
var response = this.connection.ClearDisplay();
canContinue = response.Succeeded;
}
// if (canContinue)
{
var response = this.connection.Set(new LeakAlarm
{
FlowRateGal = 0.25F, // 0.25 gpm
TimeLimit = 24 * 60 * 60 // 24 hours => 86400sec
});
canContinue = response.Succeeded;
}
// if (canContinue)
{
var response = this.connection.Set(new HighFlowAlarm
{
FlowRateGal = 25F, // 25 gpm
TimeLimit = 1 * 60 * 60 // 1 hours => 86400sec
});
canContinue = response.Succeeded;
}
// if (canContinue)
{
var response = this.connection.Set(new ReverseFlowAlarm
{
FlowRateGal = -1F, // -1 gpm
TimeLimit = 60 // 1 hours => 86400sec
});
canContinue = response.Succeeded;
}
// if (canContinue)
{
var response = this.connection.ClearAlarms();
canContinue = response.Succeeded;
}
// if (canContinue)
{
var alarmsState = this.connection.ViewAlarmsState();
canContinue = alarmsState.Succeeded;
//&& alarmsState.UsrEnabled
//&& alarmsState.PreEnabledInactive;
//TODO: Check alarms
}
// if (canContinue)
{
var response = this.connection.EnableNFC();
canContinue = response.Succeeded;
}
// if (canContinue)
{
var registerSettingsAfter = this.connection.ViewRegisterSettings();
//canContinue = registerSettingsAfter.Succeeded
// && meter.Compare(registerSettingsAfter);
}
// if (canContinue)
{
var systemParametersAfter = this.connection.ViewSystemParameters();
canContinue = systemParametersAfter.Succeeded;
//&& meter.Compare(systemParametersAfter);
}
// if (canContinue)
{
var configurationParametersAfter = this.connection.ViewConfigurationParameters();
canContinue = configurationParametersAfter.Succeeded;
//&& meter.Compare(configurationParametersAfter);
}
// if (canContinue)
{
var alarmsState = this.connection.ViewAlarmsState();
canContinue = alarmsState.Succeeded;
//&& alarmsState.UsrEnabled
//&& alarmsState.PreEnabledInactive;
}
// if (canContinue)
{
var response = this.connection.ViewAlarmSettings(0x01);
canContinue = response.Succeeded;
}
// if (canContinue)
{
var response = this.connection.ViewAlarmSettings(0x02);
canContinue = response.Succeeded;
}
// if (canContinue)
{
var response = this.connection.ViewAlarmSettings(0x04);
canContinue = response.Succeeded;
}
if (canContinue)
{
//connection.Set(new FactorySeal
//{
// Sealed = true,
//});
//var factorySeal = connection.ViewFactorySeal();
//canContinue = factorySeal.Succeeded && factorySeal.Sealed;
}
this.Progress = 100;
}
return this.StartNew(FinishInspection, cancellationToken);
}
internal void SaveInspection(StringBuilder results)
{
if (results.Length <= 1)
{
results.AppendLine(string.Join(";", this.Meter.Results.Select(x => x.Key)));
}
results.AppendLine(string.Join(";", this.Meter.Results.Select(x => x.Value)));
}
internal double GetCorrectionFactor()
@@ -404,23 +530,12 @@
{
try
{
this.SaveInspectionAsync(CancellationToken.None).Wait();
this.connection?.Disconnect();
}
catch (Exception e)
{
this.State = e.Message;
}
try
{
this.results.Clear();
}
catch (Exception e)
{
this.State = e.Message;
}
}
private bool IsRunning()
@@ -434,5 +549,19 @@
return this.Connected;
}
private Task StartNew(Action action, CancellationToken cancellationToken, int counter = 3)
{
return Task
.Factory
.StartNew(action, cancellationToken);
//.ContinueWith(task =>
//{
// if (task.Status == TaskStatus.Faulted && counter > 0)
// {
// StartNew(action, cancellationToken, counter - 1).Wait();
// }
//});
}
}
}
@@ -10,7 +10,9 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Input;
@@ -37,6 +39,7 @@
{
this.Header = "EOL";
this.CanStart = true;
this.CanCheck = true;
this.Option = new EOLOptionVM(this);
this.OmniDefaults = new OmniPlusType();
@@ -49,6 +52,7 @@
this.LoadComPorts = new Command(this.PrepareConnections);
this.CancelInspection = new Command(this.CancelInspectionHandler);
this.StartInspection = new Command(this.StartInspectionHandler);
this.CheckInspection = new Command(this.CheckInspectionHandler);
this.Option.OptionSelected += this.NotifyOptionSelected;
@@ -127,6 +131,18 @@
}
}
private bool canCheck;
public bool CanCheck
{
get => this.canCheck;
set
{
this.canCheck = value;
this.NotifyPropertyChanged(nameof(this.CanCheck));
}
}
private bool canStop;
public bool CanStop
{
@@ -171,8 +187,23 @@
public ICommand StartInspection { get; }
public ICommand CheckInspection { get; }
private string errorLog;
private void PrepareConnections()
{
try
{
var directory = Directory.CreateDirectory(".\\Results");
this.errorLog = Path.Combine(directory.FullName, $"errors.txt");
File.AppendAllText(this.errorLog, string.Empty);
}
catch (Exception e)
{
this.State = e.ToString();
}
this.exchangeConnection.Disconnect();
this.exchangeConnection.Connect(this.hubsettings.ExchangeHubURL);
@@ -271,14 +302,13 @@
this.State = default(string);
}
this.InvokeAsync(() =>
Task.Factory.StartNew(() =>
{
this.WaitUntil(this.AvailableIn, show: true, error: true);
this.CanStart = true;
this.Error = default(string);
this.State = default(string);
}, wait: false);
});
}
private void StartInspectionHandler()
@@ -289,8 +319,11 @@
this.cancellationTokenSource = new CancellationTokenSource();
this.cancellationToken = this.cancellationTokenSource.Token;
var metersVM = this.Nodes.Cast<COMContentVM>();
this.cancellationToken.Register(() => this.canceled = true);
this.InvokeAsync(() =>
{
this.InvokeAsync((tasks, cancellationToken) =>
@@ -303,7 +336,7 @@
foreach (var pp in this.OmniDefaults.TestPoints)
{
if (this.cancellationTokenSource?.IsCancellationRequested == true)
if (this.canceled)
{
break;
}
@@ -313,6 +346,11 @@
this.StartFlow(pp.VolumeM3H);
if (this.canceled)
{
break;
}
this.InvokeAsync((tasks, cancellationToken) =>
{
foreach (var meterVM in metersVM)
@@ -322,48 +360,165 @@
});
this.StartReferenceMessurement(duration);
if (this.canceled)
{
break;
}
this.WaitUntil((int)(duration * 1.2), true, false);
if (this.canceled)
{
break;
}
var referenceV = this.GetReferenceVolume();
if (this.cancellationTokenSource?.IsCancellationRequested == true)
{
break;
}
this.InvokeAsync((tasks, cancellationToken) =>
{
foreach (var meterVM in metersVM)
{
tasks.Add(meterVM.StopPPCalibrationAsync(pp, cancellationToken));
tasks.Add(meterVM.StopPPCalibrationAsync(pp, referenceV, cancellationToken));
}
});
if (this.cancellationTokenSource?.IsCancellationRequested == true)
if (this.canceled)
{
break;
}
}
this.exchangeConnection.SendStopFlow();
foreach (var meterVM in metersVM)
{
meterVM.GetCorrectionFactor();
}
var results = new StringBuilder();
foreach (var meterVM in metersVM)
{
meterVM.SaveInspection(results);
}
try
{
var directory = Directory.CreateDirectory(".\\Results");
var file = Path.Combine(directory.FullName, $"Results_{DateTime.Now:yyyyMMddHHmmss}.csv");
File.WriteAllText(file, results.ToString());
}
catch (Exception e)
{
this.State = e.ToString();
}
if (!this.canceled)
{
this.InvokeAsync((tasks, cancellationToken) =>
{
foreach (var meterVM in metersVM)
{
tasks.Add(meterVM.SetReferenceVolumeAsync(pp, referenceV, cancellationToken));
tasks.Add(meterVM.FinishInspectionAsync(cancellationToken));
}
});
}
this.exchangeConnection.SendStopReferenceMessurement(default(double));
this.exchangeConnection.SendStopFlow();
foreach (var meterVM in metersVM)
{
meterVM.Dispose();
}
this.WaitUntil(this.AvailableIn, show: true);
this.CanStart = true;
this.Error = default(string);
this.State = default(string);
}, this.cancellationToken);
}
private void CheckInspectionHandler()
{
this.canceled = false;
this.CanStart = false;
this.CanStop = true;
this.cancellationTokenSource = new CancellationTokenSource();
this.cancellationToken = this.cancellationTokenSource.Token;
var metersVM = this.Nodes.Cast<COMContentVM>();
this.cancellationToken.Register(() => this.canceled = true);
this.InvokeAsync(() =>
{
this.InvokeAsync((tasks, cancellationToken) =>
{
foreach (var meterVM in metersVM)
{
tasks.Add(meterVM.SaveInspectionAsync(cancellationToken));
tasks.Add(meterVM.SetInputVolumeAsync(this.OmniDefaults, cancellationToken));
}
});
foreach (var pp in this.OmniDefaults.TestPoints)
{
if (this.canceled)
{
break;
}
var rotations = pp.Rotations;
var duration = pp.Duration;
this.StartFlow(pp.VolumeM3H);
if (this.canceled)
{
break;
}
this.InvokeAsync((tasks, cancellationToken) =>
{
foreach (var meterVM in metersVM)
{
tasks.Add(meterVM.StartPPCalibrationAsync(pp, cancellationToken));
}
});
this.StartReferenceMessurement(duration);
if (this.canceled)
{
break;
}
this.WaitUntil((int)(duration * 1.2), true, false);
if (this.canceled)
{
break;
}
var referenceV = this.GetReferenceVolume();
this.InvokeAsync((tasks, cancellationToken) =>
{
foreach (var meterVM in metersVM)
{
tasks.Add(meterVM.StopPPCalibrationAsync(pp, referenceV, cancellationToken));
}
});
if (this.canceled)
{
break;
}
}
this.exchangeConnection.SendStopFlow();
foreach (var meterVM in metersVM)
{
meterVM.GetCorrectionFactor();
@@ -374,15 +529,13 @@
meterVM.Dispose();
}
this.InvokeAsync(() =>
{
this.WaitUntil(this.AvailableIn, show: true);
this.WaitUntil(this.AvailableIn, show: true);
this.CanStart = true;
this.Error = default(string);
this.State = default(string);
});
}, wait: false);
this.CanStart = true;
this.Error = default(string);
this.State = default(string);
}, this.cancellationToken);
}
private void WaitUntil(int duration, bool show = false, bool error = true)
@@ -395,6 +548,7 @@
}
this.CanStart = false;
this.AvailableIn = duration;
this.awaiter = new ManualResetEventSlim();
this.timer = new TimersTimer(1000)
{
@@ -563,12 +717,6 @@
private void InvokeAsync(Action<ICollection<Task>, CancellationToken> action, bool wait = true)
{
if (this.cancellationTokenSource?.IsCancellationRequested == true)
{
this.cancellationTokenSource = new CancellationTokenSource();
this.cancellationToken = this.cancellationTokenSource.Token;
}
this.tasks = new List<Task>();
action?.Invoke(this.tasks, this.cancellationToken);
@@ -576,24 +724,47 @@
if (tasks.Any())
{
var handle = Task.Factory
.ContinueWhenAll(this.tasks.ToArray(), _ => { })
.ContinueWith(_ => this.tasks.Clear());
.ContinueWhenAll(this.tasks.ToArray(), _tasks =>
{
foreach (var t in _tasks)
{
this.LogError($"[{t.Id}]:{nameof(t.Status)} = {t.Status}{Environment.NewLine}");
if (t.Exception != null)
{
this.LogError($"[{t.Id}]:{t.Exception}{Environment.NewLine}");
}
}
});
if (wait)
{
handle.Wait();
}
this.tasks.Clear();
}
}
private void InvokeAsync(Action action, bool wait = true)
private Task InvokeAsync(Action action, CancellationToken cancellationToken)
{
var handle = Task.Factory.StartNew(action);
return Task
.Factory
.StartNew(action, cancellationToken)
.ContinueWith(t =>
{
this.LogError($"[{t.Id}]:{nameof(t.Status)} = {t.Status}{Environment.NewLine}");
if (wait)
{
handle.Wait();
}
if (t.Exception != null)
{
this.LogError($"[{t.Id}]:{t.Exception}{Environment.NewLine}");
}
});
}
private void LogError(string error)
{
File.AppendAllText(this.errorLog, error);
}
}
}
@@ -1,39 +1,114 @@
namespace OMNIPruefung.ViewModels.Features
{
using OmniPlus.Features;
using OmniPlus.Inspection;
using OMNIPruefung.ViewModels.Base;
using System.Collections.ObjectModel;
public class OMNIPlusVM : VM<OMNIPlusVM>
{
public ObservableCollection<Property> Values { get; }
= new ObservableCollection<Property>();
public ObservableCollection<Result> Results { get; }
= new ObservableCollection<Result>();
public ushort IntPart { get; internal set; }
public ushort Fraction { get; internal set; }
public byte Size { get; internal set; }
public byte Range { get; internal set; }
public sbyte FactoryCorrection { get; internal set; }
public string BuildInfo { get; internal set; }
internal void AddResult(string key, string value)
{
this.Results.Add(new Result
{
Key = key,
Value = value
});
}
internal void Add(SystemParameters response)
{
this.AddResult("Reading System Parameters", $"{response.Status}");
if (response.Succeeded)
{
this.BuildInfo = response.BuildInfo.Value;
this.AddResult(nameof(response.VersionAndType), response.VersionAndType.Value);
this.AddResult(nameof(response.BuildInfo), response.BuildInfo.Value);
this.AddResult(nameof(response.BatteryVoltage), $"{(response.BatteryVoltage.Volts + 0.0001) / 1000:0.0000 V}");
this.AddResult(nameof(response.ManifacturingTime), $"{response.ManifacturingTime.DateTime:dd.MM.yyyy}");
this.AddResult(nameof(response.SystemTime), $"{response.SystemTime.DateTime:dd.MM.yyyy}");
this.AddResult(nameof(response.RebootsCount), $"{response.RebootsCount}");
this.AddResult(nameof(response.FactorySealed), $"{response.FactorySealed}");
}
}
internal void Add(InputVolume response)
{
this.IntPart = response.IntPart;
this.Fraction = response.Fraction;
this.Size = response.Size;
this.Range = response.Range;
this.AddResult("Setting ml/r", $"{response.MlPerRotation:0.0000 ml/r}");
}
internal void Add(OmniPlusTestPoint pp)
{
this.AddResult("Test point:", $"{pp.Rotations}/{pp.Duration:0}");
this.AddResult("Volume", $"{pp.VolumeM3H:0.0000 m³/h}");
this.AddResult("Duration", $"{pp.Duration:0 sec.}");
this.AddResult("ml/rotation", $"{pp.MlPerRotation:0.0000 ml/r}");
this.AddResult("Validation frame", $"{pp.MinDiff:0.00}% - {pp.MaxDiff:0.00}%");
}
internal void Add(OmniPlusTest test)
{
this.AddResult("Result", $"{test.DifferencePercentage:0.00}%");
this.AddResult("Meter volume", $"{test.MeterVolume:0.0000 m³}");
this.AddResult("Reference volume", $"{test.VolumeMessured:0.0000 m³}");
this.AddResult("Test result", $"{test.Rotations}/{test.Duration:0}");
}
internal void Add(ConfigurationParameters response)
{
this.AddResult(nameof(response.ProgrammableID), response.ProgrammableID.Value);
this.AddResult(nameof(response.FactoryID), response.FactoryID.Value);
this.AddResult(nameof(response.ReadingDigits), $"{response.ReadingDigits.Count}");
this.AddResult(nameof(response.Readings), response.Readings.Value);
this.AddResult("Optional Uni-Dir-Fields", response.OptionalUniDirFields.Value);
this.AddResult("Alarm persistence", $"{response.AlarmPersistenceDays:0 days}");
this.AddResult("Data log interval", $"{response.DataLogIntervalMins:0 min.}");
this.AddResult(nameof(response.DeviceID), response.DeviceID.Value);
}
internal void AddFactoryCorrection(double value)
{
this.FactoryCorrection = (sbyte)(value * 10);
this.AddResult("Factory correction %", $"{value:0.00}%");
this.AddResult("Factory correction", $"{this.FactoryCorrection:0}");
}
}
public class Result
{
public string Key { get; set; }
public string Value { get; set; }
}
public class Property
{
public string DbName { get; set; }
public string Key { get; set; }
public string DisplayName { get; set; }
public string BinValue { get; set; }
public string StrValue { get; set; }
public string Value { get; set; }
}
}
@@ -13,27 +13,9 @@
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<ItemsControl Grid.Row="0" ItemsSource="{Binding Meter.Properties}" FontFamily="Consolas">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical">
<Label Content="{Binding Path=Key}" Padding="21, 3" FontWeight="Bold"/>
<ItemsControl ItemsSource="{Binding Path=Value}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Label Content="{Binding Path=Key}" Padding="42, 3, 2, 3" Width="200" FontWeight="Bold"/>
<Label Content="{Binding Path=Value}" Padding="3"/>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<DataGrid Grid.Row="0" ItemsSource="{Binding Meter.Results}" FontFamily="Consolas" FontSize="13" HeadersVisibility="Column" />
<TextBlock Grid.Row="1"
Margin="13"
FontFamily="Consolas"
@@ -44,7 +26,5 @@
FontFamily="Consolas"
TextAlignment="Left"
Text="{Binding Error}" />
<DataGrid Grid.Row="3" ItemsSource="{Binding Meter.Results}" />
</Grid>
</ScrollViewer>
@@ -79,6 +79,8 @@
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<ComboBox Grid.Column="0" Text="{Binding Size}" HorizontalAlignment="Stretch" Margin="0, 2, 2, 2">
<ComboBoxItem IsSelected="True">5</ComboBoxItem>
@@ -95,6 +97,11 @@
<ComboBoxItem >R2</ComboBoxItem>
<ComboBoxItem >T2</ComboBoxItem>
</ComboBox>
<Button Grid.Column="3"
Content="Überprüfung starten"
Style="{DynamicResource SystemBtn}"
Visibility="{Binding CanCheck, Converter={StaticResource BooleanVisibility}}"
Command="{Binding CheckInspection}"/>
</Grid>
<!--<Label Grid.Column="0" Grid.Row="9" Content="Type eingeben: " VerticalContentAlignment="Center" VerticalAlignment="Stretch"/>
@@ -24,13 +24,18 @@
}
}
protected override void BeginRead(byte[] buffer)
protected override void BeginRead(byte[] bytes)
{
var start = Array.IndexOf(buffer, this.encoder.Device2PC);
if (bytes is null)
{
return;
}
var start = Array.IndexOf(bytes, this.encoder.Device2PC);
if (start >= 0)
{
if (this.encoder.TryDecode(buffer, out byte[] message))
if (this.encoder.TryDecode(bytes, out byte[] message))
{
this.EnqueueMessage(message);
this.RemoveRange(message.Length);
@@ -38,7 +43,7 @@
}
else
{
this.RemoveRange(buffer.Length);
this.RemoveRange(bytes.Length);
}
}
}
@@ -6,9 +6,11 @@
internal abstract class SerialDataReader : SerialDataStream
{
protected bool read;
private Thread thread;
private List<byte> stream;
private Queue<byte[]> messages;
protected ManualResetEventSlim awaiter;
protected SerialDataReader(SerialPortSettings settings) : base(settings)
{
@@ -29,7 +31,18 @@
public override void Dispose()
{
this.StopListening();
try
{
this.messages = null;
this.stream = null;
this.thread?.Abort();
this.thread = null;
}
catch (Exception e)
{
this.NotifyStateChanged(e.ToString());
}
base.Dispose();
}
@@ -77,13 +90,26 @@
{
try
{
if (this.IsOpen)
if (!this.IsOpen)
{
base.Open();
}
if (!this.IsAlive)
{
this.stream = new List<byte>();
this.messages = new Queue<byte[]>();
this.thread = new Thread(this.BeginRead);
this.thread.Start();
}
if (this.awaiter?.IsSet == true)
{
this.awaiter.Set();
}
this.awaiter = new ManualResetEventSlim();
this.read = true;
}
catch (Exception e)
{
@@ -95,22 +121,24 @@
{
try
{
if (this.IsAlive)
{
this.thread.Abort();
}
this.stream.Clear();
}
catch (Exception e)
{
this.NotifyStateChanged(e);
}
this.stream?.Clear();
this.messages?.Clear();
this.messages = null;
this.stream = null;
this.thread = null;
try
{
this.messages.Clear();
}
catch (Exception e)
{
this.NotifyStateChanged(e);
}
this.read = false;
this.awaiter.Set();
}
private void BeginRead()
@@ -119,9 +147,9 @@
while (this.IsAlive)
{
if (this.stream is null)
if (!this.read)
{
continue;
this.awaiter.Wait();
}
var bytes = this.ReadBytes();
@@ -131,7 +159,7 @@
this.stream.AddRange(bytes);
}
this.BeginRead(this.stream.ToArray());
this.BeginRead(this.stream?.ToArray());
}
this.NotifyStateChanged($"{nameof(IrdaStream)} - reading thread stoped.");
@@ -1,19 +1,32 @@
namespace OmniPlus.Connections
{
using System;
using System.IO;
using System.Threading;
internal class UI1236Stream : IrdaStream
{
private readonly string fileName;
private readonly UI1236Encoder encoder;
public UI1236Stream(SerialPortSettings settings) : base(settings)
{
var directiry = Directory.CreateDirectory(".\\UI1236");
this.fileName = Path.Combine(directiry.FullName, $"[{settings.PortName}].txt");
this.encoder = new UI1236Encoder();
File.AppendAllText(Path.Combine(directiry.FullName, $"[{settings.PortName}].txt"), string.Empty);
this.StateChanged += this.UI1236Stream_StateChanged;
}
public byte[] Write(params byte[] bytes)
{
this.LogToFile($">>> {BitConverter.ToString(bytes)}");
this.StartListening();
Thread.Sleep(500);
this.WriteBytes(bytes);
var response = new byte[0];
@@ -34,12 +47,12 @@
}
else
{
Thread.Sleep(200);
Thread.Sleep(500);
}
}
else
{
Thread.Sleep(200);
Thread.Sleep(500);
}
}
@@ -48,11 +61,16 @@
break;
}
Thread.Sleep(200);
this.LogToFile($"<<< {BitConverter.ToString(response)}");
Thread.Sleep(500);
}
this.StopListening();
this.LogToFile($"<<< {BitConverter.ToString(response)}");
this.LogToFile(string.Empty);
return response;
}
@@ -63,5 +81,22 @@
base.WriteBytes(message);
}
}
private void LogToFile(string value)
{
try
{
File.AppendAllText(this.fileName, $"{value}{Environment.NewLine}");
}
catch (Exception e)
{
}
}
private void UI1236Stream_StateChanged(object state)
{
this.LogToFile($"{state}");
}
}
}
@@ -67,7 +67,7 @@
public class ConfigurationParametersSet : FeatureRequest
{
const int LENGTH = 80;
const int LENGTH = 90;
public ConfigurationParametersSet() : base(LENGTH)
{
@@ -88,9 +88,9 @@
get => this.programmableID;
set
{
this.SetASCIIBytes(value, 0, 21);
this.SetASCIIBytes(value, 0, 20);
this.programmableID = this.bytes.ToASCIIString(0, 21);
this.programmableID = this.bytes.ToASCIIString(0, 20);
}
}
@@ -139,9 +139,9 @@
get => this.readingPreset;
set
{
this.SetASCIIBytes(value, 38, 10);
this.SetASCIIBytes(value, 38, 9);
this.readingPreset = this.bytes.ToASCIIString(38, 10);
this.readingPreset = this.bytes.ToASCIIString(38, 9);
}
}
@@ -240,9 +240,9 @@
get => this.buildInfo;
set
{
this.SetASCIIBytes(value, 64, 16);
this.SetASCIIBytes(value, 64, 14);
this.buildInfo = this.bytes.ToASCIIString(64, 16);
this.buildInfo = this.bytes.ToASCIIString(64, 14);
}
}
@@ -251,10 +251,17 @@
/// Set Device ID String, string is padded and terminated with '\0'
/// +1
/// </summary>
//public string DeviceID
//{
// set => this.SetASCIIBytes(value, 80, 10);
//}
private string deviceID;
public string DeviceID
{
get => this.deviceID;
set
{
this.SetASCIIBytes(value, 80, 9);
this.deviceID = this.bytes.ToASCIIString(80, 9);
}
}
private void SetASCIIBytes(string value, int start, int length)
{
@@ -43,7 +43,16 @@
public short CorrectionFactor { get; set; }
public double MlPerRotation
=> OmniPlusExtensions.MlPerRotation(this.IntPart, this.Fraction, this.CorrectionFactor);
{
get
{
var mlPerRotation = OmniPlusExtensions.MlPerRotation(this.IntPart, this.Fraction, this.CorrectionFactor);
this.InputVolume.MlPerRotation = mlPerRotation;
return OmniPlusExtensions.MlPerRotation(this.IntPart, this.Fraction, this.CorrectionFactor);
}
}
public InputVolume InputVolume { get; }
= new InputVolume();
+1
View File
@@ -99,6 +99,7 @@
<Compile Include="Features\VersionAndType.cs" />
<Compile Include="Inspection\OmniPlusFormulas.cs" />
<Compile Include="OmniPlusConnection.cs" />
<Compile Include="OmniPlusConnectionsPool.cs" />
<Compile Include="OmniPlusDatabase.cs" />
<Compile Include="Inspection\OmniPlusExtensions.cs" />
<Compile Include="Inspection\OmniPlusTest.cs" />
@@ -0,0 +1,498 @@
using OmniPlus.Features;
using OmniPlus.Inspection;
using System;
using System.Collections.Concurrent;
using System.ComponentModel;
using System.Threading;
using System.Threading.Tasks;
namespace OmniPlus
{
public class OmniPlusConnectionsPool : IDisposable
{
public event Action Done;
private readonly ConcurrentDictionary<int, OmniPlusConnection> connections;
private readonly ConcurrentDictionary<int, OmniPlusMeter> meters;
private readonly CancellationTokenSource cancellationTokenSource;
private readonly CancellationToken cancellationToken;
private readonly OmniPlusExchangeSlave exchangeSlave;
private readonly OmniPlusDatabase database;
private readonly OmniPlusType omniType;
private byte size;
private string variant;
private BackgroundWorker background;
public OmniPlusConnectionsPool(string dbConnectionString, string signalRURL)
{
this.connections = new ConcurrentDictionary<int, OmniPlusConnection>();
this.meters = new ConcurrentDictionary<int, OmniPlusMeter>();
this.cancellationTokenSource = new CancellationTokenSource();
this.exchangeSlave = new OmniPlusExchangeSlave(signalRURL);
this.database = new OmniPlusDatabase(dbConnectionString);
this.omniType = new OmniPlusType();
this.size = 5;
this.variant = "C2";
this.cancellationToken = this.cancellationTokenSource.Token;
this.cancellationToken.Register(this.CancellationCallback);
}
public void Dispose()
{
this.exchangeSlave.Dispose();
// Disposes all OmniPlus connections.
foreach (var connectionKVP in this.connections)
{
connectionKVP.Value?.Disconnect();
}
// Clears collected connections and their meters.
this.connections.Clear();
this.meters.Clear();
}
public void InitializeInspection(params string[] portNames)
{
OmniPlusConnection connection;
OmniPlusMeter meter;
int position = 1;
bool connected;
foreach (var portName in portNames)
{
connection = new OmniPlusConnection(portName);
connected = connection.ConnectIrda();
if (connected)
{
}
else
{
connection.Disconnect();
connection = default(OmniPlusConnection);
meter = default(OmniPlusMeter);
}
this.connections.TryAdd(position, connection);
position++;
}
this.database.LoadOmniDefaults(this.size, this.variant, this.omniType);
}
public void CancelExecution()
=> this.cancellationTokenSource.Cancel(false);
//public void StartInspection()
//{
// foreach (var position in this.connections.Keys)
// {
// this.StartOmniInitialization(position);
// //foreach (var point in this.omniType.TestPoints)
// //{
// // this.StartOmniInspection(position, point);
// //}
// //this.CalculateCorrectionFactor(position);
// this.FinishOmniInspection(position);
// }
//}
public void StartInspection()
{
this.background = new BackgroundWorker();
this.background.DoWork += this.StartInspection;
this.background.RunWorkerAsync();
}
private void StartInspection(object sender, EventArgs args)
{
var connectionsCount = this.connections.Count;
var tasks = new Task[connectionsCount];
foreach (var position in this.connections.Keys)
{
tasks[position - 1] = Task.Factory.StartNew(() => this.StartOmniInitialization(position), this.cancellationToken);
}
foreach (var point in this.omniType.TestPoints)
{
// TODO: 600 = 10min * 60sec - change for production.
//if (!this.exchangeSlave.SetQAndWaitUntilReached(point.VolumeM3H))
//{
// this.CancelExecution();
// break;
//}
tasks = new Task[connectionsCount];
foreach (var position in this.connections.Keys)
{
tasks[position - 1] = Task.Factory.StartNew(() => this.StartOmniInspection(position, point), this.cancellationToken);
}
//var volume = this.exchangeSlave.RequestRefV();
//foreach (var position in this.connections.Keys)
//{
// this.SetPointDifference(position, point, volume);
//}
}
foreach (var position in this.connections.Keys)
{
this.CalculateCorrectionFactor(position);
}
tasks = new Task[connectionsCount];
foreach (var position in this.connections.Keys)
{
tasks[position - 1] = Task.Factory.StartNew(() => this.FinishOmniInspection(position), this.cancellationToken);
}
this.Done?.Invoke();
}
private void StartOmniInitialization(int position)
{
if (this.TryGetOmni(position, out var connection, out var meter))
{
var systemParameters = connection.ViewSystemParameters();
// connection.Set(this.omniType.InputVolume).Succeeded;
}
else
{
}
}
private void StartOmniInspection(int position, OmniPlusTestPoint point)
{
var header = $"{point.VolumeM3H:0.0000}m³/h";
if (this.TryGetOmni(position, out var connection, out var meter) /*&& meter.Initialized && meter.CanCalibrate*/)
{
var activationResponse = connection.StartChamberCalibration(point.Rotations, point.Duration);
if (activationResponse.Succeeded)
{
var calibrationResult = new ChamberCalibrationResponse();
var duration = point.Duration + 3;
this.NotifyWhileThreadSleep(position, header, point.Duration + 3);
for (int i = 0; i < 3; i++)
{
calibrationResult = connection.ViewChamberCalibration();
if (calibrationResult.Succeeded)
{
break;
}
Thread.Sleep(1000);
}
}
else // activation failed
{
}
}
else // not connected
{
}
}
private void SetPointDifference(int position, OmniPlusTestPoint point, double volume)
{
//var header = $"{point.VolumeM3H:0.0000}m³/h";
//if (this.TryGetOmni(position, out var _, out var meter) && meter.Initialized && meter.CanCalibrate)
//{
// var difference = meter.AddCalibrationVolume(point, volume);
// this.StateChanged?.Invoke(position, 0, header, $"{difference:0.00}%");
//}
//else // not connected
//{
// this.StateChanged?.Invoke(position, 0, header, null);
//}
}
private void CalculateCorrectionFactor(int position)
{
//if (this.TryGetOmni(position, out var _, out var meter) && meter.Initialized && meter.CanCalibrate)
//{
// var correctionFactor = meter.GetCorrectionFactor();
// this.StateChanged?.Invoke(position, meter.CanCalibrate ? 1 : -1, CORRECTION, $"{correctionFactor:0.00}%");
//}
//else // not connected
//{
// this.StateChanged?.Invoke(position, 0, CORRECTION, null);
//}
}
private void FinishOmniInspection(int position)
{
//if (this.TryGetOmni(position, out var connection, out var meter)/* && meter.Calibrated*/)
//{
// var configurationParameters = connection.ViewConfigurationParameters();
// var canContinue = configurationParameters.Succeeded;
// if (canContinue)
// {
// meter.AddConfigurationParameters(configurationParameters);
// this.database.AddOrUpdate(position, configurationParameters);
// }
// if (canContinue)
// {
// // TODO: Uncomment in production
// //var systemTimeReset = connection.SetSystemTime();
// //canContinue = systemTimeReset.Succeeded;
// }
// if (canContinue)
// {
// var registerSettings = new RegisterSettings();
// registerSettings.IntPart = this.omniType.IntPart;
// registerSettings.Fraction = this.omniType.Fraction;
// registerSettings.Size = this.omniType.Size;
// registerSettings.Range = this.omniType.Range;
// registerSettings.VolumePerPulseUnit = 0x00;
// registerSettings.MeterUnits = (byte)MessurementUnits.USGallons;
// registerSettings.FlowUnits = (byte)MessurementUnits.USGallons;
// registerSettings.FlowRate = (byte)TimeUnits.Minutes;
// registerSettings.FactoryCorrection = meter.FactoryCorrection;
// registerSettings.FieldCorrection = 0x00;
// registerSettings.PulseWeight = 0x01;
// registerSettings.PulseWidth = 0x02;
// registerSettings.PulseUpdate = 0x00;
// var response = connection.Set(registerSettings);
// canContinue = response.Succeeded;
// if (canContinue)
// {
// meter.AddRegisterSettings(registerSettings);
// }
// }
// if (canContinue)
// {
// var configurationParametersSet = new ConfigurationParametersSet();
// configurationParametersSet.ProgrammableID = "816232411983";
// configurationParametersSet.FactoryID = "816232411983";
// configurationParametersSet.NumberOfReadingDigits = 8; // meter.ReadingDigits;
// configurationParametersSet.ReadingPreset = "000000000";
// configurationParametersSet.OptionalUniDirFields = 1; // meter.OptionalUniDirFields;
// configurationParametersSet.AlarmPercistancePeriodDays = 31;
// configurationParametersSet.DataLogIntervalMinutes = 60;
// configurationParametersSet.ManifacturingTime = Epoch20000101.UTCNow - 30000; // meter.ManifacturingTime;
// configurationParametersSet.SystemTime = Epoch20000101.UTCNow;
// configurationParametersSet.RebootCount = 0;
// configurationParametersSet.BuildInfo = "816232411983"; // meter.BuildInfo;
// // configurationParametersSet.DeviceID = "OMNI-01";
// var response = connection.Set(configurationParametersSet);
// canContinue = response.Succeeded;
// }
// if (canContinue)
// {
// var response = connection.ClearDisplay();
// canContinue = response.Succeeded;
// }
// if (canContinue)
// {
// var response = connection.Set(new LeakAlarm
// {
// FlowRateGal = 0.25F, // 0.25 gpm
// TimeLimit = 24 * 60 * 60 // 24 hours => 86400sec
// });
// canContinue = response.Succeeded;
// }
// if (canContinue)
// {
// var response = connection.Set(new HighFlowAlarm
// {
// FlowRateGal = 25F, // 25 gpm
// TimeLimit = 1 * 60 * 60 // 1 hours => 86400sec
// });
// canContinue = response.Succeeded;
// }
// if (canContinue)
// {
// var response = connection.Set(new ReverseFlowAlarm
// {
// FlowRateGal = -1F, // -1 gpm
// TimeLimit = 60 // 1 hours => 86400sec
// });
// canContinue = response.Succeeded;
// }
// if (canContinue)
// {
// var response = connection.ClearAlarms();
// canContinue = response.Succeeded;
// }
// if (canContinue)
// {
// var alarmsState = connection.ViewAlarmsState();
// canContinue = alarmsState.Succeeded;
// //&& alarmsState.UsrEnabled
// //&& alarmsState.PreEnabledInactive;
// //TODO: Check alarms
// }
// if (canContinue)
// {
// var response = connection.EnableNFC();
// canContinue = response.Succeeded;
// }
// if (canContinue)
// {
// var registerSettingsAfter = connection.ViewRegisterSettings();
// canContinue = registerSettingsAfter.Succeeded
// && meter.Compare(registerSettingsAfter);
// }
// if (canContinue)
// {
// var systemParametersAfter = connection.ViewSystemParameters();
// canContinue = systemParametersAfter.Succeeded;
// //&& meter.Compare(systemParametersAfter);
// }
// if (canContinue)
// {
// var configurationParametersAfter = connection.ViewConfigurationParameters();
// canContinue = configurationParametersAfter.Succeeded;
// //&& meter.Compare(configurationParametersAfter);
// }
// if (canContinue)
// {
// var alarmsState = connection.ViewAlarmsState();
// canContinue = alarmsState.Succeeded;
// //&& alarmsState.UsrEnabled
// //&& alarmsState.PreEnabledInactive;
// }
// if (canContinue)
// {
// var response = connection.ViewAlarmSettings(0x01);
// canContinue = response.Succeeded;
// }
// if (canContinue)
// {
// var response = connection.ViewAlarmSettings(0x02);
// canContinue = response.Succeeded;
// }
// if (canContinue)
// {
// var response = connection.ViewAlarmSettings(0x04);
// canContinue = response.Succeeded;
// }
// if (canContinue)
// {
// //connection.Set(new FactorySeal
// //{
// // Sealed = true,
// //});
// //var factorySeal = connection.ViewFactorySeal();
// //canContinue = factorySeal.Succeeded && factorySeal.Sealed;
// }
//}
//else // meter or connection not in use
//{
//}
}
/// <summary>
/// Returns only connected connections and meters.
/// </summary>
/// <param name="position">The position of connection and meter.</param>
/// <param name="connection"><see cref="OmniPlusConnection"/></param>
/// <param name="meter"><see cref="OmniPlusMeter"/></param>
/// <returns>Returns true if connection and meter are found and are not null and the meter is connected, otherwise false.</returns>
private bool TryGetOmni(int position, out OmniPlusConnection connection, out OmniPlusMeter meter)
{
var connectionFound = this.connections.TryGetValue(position, out connection);
var meterFound = this.meters.TryGetValue(position, out meter);
return connectionFound
&& connection != null
&& meterFound
&& meter != null;
}
private void NotifyWhileThreadSleep(int position, string header, int duration)
{
//var seconds = 0;
//var timer = new System.Timers.Timer(1000)
//{
// Enabled = true,
// AutoReset = true,
//};
//timer.Elapsed += (_, _1) =>
//{
// this.StateChanged?.Invoke(position, 0, header, $"{seconds++}/{duration}");
//};
//timer.Start();
//Thread.Sleep(duration * 1000);
//timer.Stop();
}
private void CancellationCallback()
{
// TODO: Update database.
this.Dispose();
}
}
internal class OmniPlusExchangeSlave
{
private String signalRURL;
public OmniPlusExchangeSlave(String signalRURL)
{
this.signalRURL = signalRURL;
}
internal void Dispose()
{
throw new NotImplementedException();
}
}
internal class OmniPlusMeter
{
}
}