namespace Common.UI.ViewModels { using Common.Hardware.SIRT; using Common.Hardware.SIRT.Parameters; using Common.Hardware.SIRT.Tasks; using Common.Hardware.WaterMeter.eRegister; using Common.Hardware.WaterMeter.eRegister.Features; using Common.Hardware.WaterMeter.eRegister.Telegrams; using Common.UI.Infrastructure; using LaaPackages.SqlClient; using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Threading; using System.Threading.Tasks; using System.Windows.Input; using System.Windows.Media; public class SetMetrologyParametersVM : VM { private readonly Dictionary telegrams; private readonly Dictionary meterSizes; private CancellationTokenSource cancellationTokenSource; private CancellationToken cancellationToken; private Task cancellationTask; private SIRTBroadcaster sirt; private string portName; private string sirtId; private int frequency; public SetMetrologyParametersVM() { AppHost.SIRTHub.Connected += this.SIRTHub_Connected; AppHost.SIRTHub.Disconnected += this.SIRTHub_Disconnected; var hours = this.TestModeHours; if (hours == 0) { this.modeInfo = $"Test mode is off"; } else { this.modeInfo = $"Test mode is on for {hours} h"; } var min = this.LEDOnTime; if (min == 0) { this.ledInfo = $"LED is off"; } else { this.ledInfo = $"LED is on for {this.ledOnTime} min"; } this.ActivateSIRTCommand = new Command(this.ActivateSIRTCommandHandler); this.SetMetrologyParametersCommand = new Command(this.SetMetrologyParametersCommandHandler); this.SwitchSettingsVisibilityCommand = new Command(this.SwitchSettingsVisibilityCommandHandler); this.meterSizes = SqlConnection .CreateSqlConnection(Appsettings.GetSetting("ConnectionString")) .CreateCommand($@" SELECT TRIM(CONCAT( mt.Title , IIF(mt.Additive IS NULL, NULL, ' ') , mt.Additive , IIF(SUBSTRING(nw.Title, 1, 1) BETWEEN '0' AND '9', ' DN', ' ') , nw.Title)) , mtnw.Value , ms.Ruecklaufsperre , ms.Volume_per_Pulse , ms.Volume_per_LED_Pulse FROM CSD.MeterType AS mt JOIN CSD.MeterTypeNominalWidth AS mtnw ON mt.ID = mtnw.MeterType_ID JOIN CSD.NominalWidth AS nw ON mtnw.NominalWidth_ID = nw.ID JOIN eRegister_Metersize AS ms ON mtnw.Value = ms.Metersize WHERE ms.Volume_per_Pulse IS NOT NULL ORDER BY mt.Value, mtnw.Value") .ExecuteReader(x => new MeterSizeVM { Title = x.GetValue(0), Size = x.GetValue(1), UseCandIRules = x.GetValue(2), Vpp = x.GetValue(3), VppLED = x.GetValue(4), }) .ToDictionary(x => x.Title, x => x); this.meterSizes[string.Empty] = null; this.MeterSizes = this.meterSizes.Keys.ToArray(); this.DecimalPlacesSource = Enum.GetNames(typeof(DecimalPointLocations)); this.telegrams = new Dictionary(); foreach (var property in typeof(SEMI).GetProperties(BindingFlags.Public | BindingFlags.Instance)) { var name = property.Name; this.telegrams[name] = new PropertyVM { Source = nameof(SEMI), Name = name }; } foreach (var property in typeof(DEBUG).GetProperties(BindingFlags.Public | BindingFlags.Instance)) { var name = property.Name; this.telegrams[name] = new PropertyVM { Source = nameof(DEBUG), Name = name }; } foreach (var property in typeof(BUP).GetProperties(BindingFlags.Public | BindingFlags.Instance)) { var name = property.Name; this.telegrams[name] = new PropertyVM { Source = nameof(BUP), Name = name }; } foreach (var property in typeof(LAT).GetProperties(BindingFlags.Public | BindingFlags.Instance)) { var name = property.Name; this.telegrams[name] = new PropertyVM { Source = nameof(LAT), Name = name }; } this.Properties = this.telegrams.Values.ToArray(); this.MessurementUnitsSource = Enum .GetValues(typeof(MessurementUnits)) .Cast() .Where(x => (int)x < 10) .Select(x => x.ToString()) .ToArray(); } private string sirtInfo = "No SIRT is connected"; public string SIRTInfo { get => this.sirtInfo; set => this.SetValue(x => x.sirtInfo = value); } private string modeInfo; public string ModeInfo { get => this.modeInfo; set => this.SetValue(x => x.modeInfo = value); } private uint address = 4291268719; public uint Address { get => this.address; set => this.SetValue(x => x.address = value); } private string meterSize; public string MeterSize { get => this.meterSize; set => this.SetValue(x => { x.meterSize = value; if (!string.IsNullOrWhiteSpace(x.meterSize) && this.meterSizes.TryGetValue(x.meterSize, out var ms)) { this.VPP = ms.Vpp; this.VPPLED = ms.VppLED; this.UseCandIRules = ms.UseCandIRules; this.Units = $"{MessurementUnits.Cubic_Meters}"; this.DecimalPlaces = $"{(ms.Vpp < 700 ? DecimalPointLocations.Three : DecimalPointLocations.Two)}"; } else { this.VPP = default(int); this.VPPLED = default(int); this.UseCandIRules = default(bool); this.Units = default(string); this.DecimalPlaces = default(string); } }); } private float vpp; public float VPP { get => this.vpp; set => this.SetValue(x => x.vpp = value); } private float vppLED; public float VPPLED { get => this.vppLED; set => this.SetValue(x => x.vppLED = value); } private int offsetFactor; public int OffsetFactor { get => this.offsetFactor; set => this.SetValue(x => x.offsetFactor = value); } private byte offsetTime; public byte OffsetTime { get => this.offsetTime; set => this.SetValue(x => x.offsetTime = value); } private byte factoryCalibration; public byte FactoryCalibration { get => this.factoryCalibration; set => this.SetValue(x => x.factoryCalibration = value); } private string units; public string Units { get => this.units; set => this.SetValue(x => x.units = value); } private string decimalPlaces; public string DecimalPlaces { get => this.decimalPlaces; set => this.SetValue(x => x.decimalPlaces = value); } private bool useCandIRules; public bool UseCandIRules { get => this.useCandIRules; set => this.SetValue(x => x.useCandIRules = value); } private string status; public string Status { get => this.status; set => this.SetValue(x => x.status = value); } private bool areSettingsVisible; public bool AreSettingsVisible { get => this.areSettingsVisible; set => this.SetValue(x => x.areSettingsVisible = value); } private bool stayAwake; public bool StayAwake { get => this.stayAwake; set => this.SetValue(x => x.stayAwake = value); } private bool changeMode; public bool ChangeMode { get => this.changeMode; set => this.SetValue(x => x.changeMode = value); } private byte testModeHours; public byte TestModeHours { get { var testModeHoursString = Appsettings.GetSetting(nameof(this.TestModeHours)); _ = byte.TryParse($"{testModeHoursString}", out this.testModeHours); return this.testModeHours; } set => this.SetValue(x => { this.testModeHours = Math.Max(Math.Min(value, (byte)72), byte.MinValue); if (this.testModeHours == 0) { this.ModeInfo = $"Test mode is off"; } else { this.ModeInfo = $"Test mode is on for {this.testModeHours} h"; } Appsettings.SetSetting(nameof(this.TestModeHours), $"{this.testModeHours}"); }); } public string SIRT_433 { get => Appsettings.GetSetting(nameof(this.SIRT_433)); set => Appsettings.SetSetting(nameof(this.SIRT_433), value); } public string SIRT_868 { get => Appsettings.GetSetting(nameof(this.SIRT_868)); set => Appsettings.SetSetting(nameof(this.SIRT_868), value); } private string ledInfo; public string LEDInfo { get => this.ledInfo; set => this.SetValue(x => x.ledInfo = value); } private byte ledOnTime; public byte LEDOnTime { get { var ledOnTimeString = Appsettings.GetSetting(nameof(this.LEDOnTime)); _ = byte.TryParse($"{ledOnTimeString}", out this.ledOnTime); return this.ledOnTime; } set => this.SetValue(x => { this.ledOnTime = Math.Max(Math.Min(value, byte.MaxValue), byte.MinValue); if (this.ledOnTime == 0) { this.LEDInfo = $"LED is off"; } else { this.LEDInfo = $"LED is on for {this.ledOnTime} min"; } Appsettings.SetSetting(nameof(this.LEDOnTime), $"{this.ledOnTime}"); }); } public ICommand ActivateSIRTCommand { get; } public ICommand SetMetrologyParametersCommand { get; } public ICommand SwitchSettingsVisibilityCommand { get; } public string[] MeterSizes { get; } public string[] DecimalPlacesSource { get; } public PropertyVM[] Properties { get; } public string[] MessurementUnitsSource { get; } private void ActivateSIRTCommandHandler(string portName) { Task.Run(() => { this.InvokeAsync(() => { this.SIRTInfo = $"Disconnecting {this.portName} ..."; AppHost.SIRTHub.Close(this.portName); }); }) .ContinueWith(_ => { this.InvokeAsync(() => { this.SIRTInfo = $"Connecting {portName} ..."; AppHost.SIRTHub.TryOpen(portName, out this.sirtId, out this.frequency); }); }); } private void SIRTHub_Connected(SIRTBroadcaster sirt) { this.sirt = sirt; this.portName = this.sirt.PortName; this.SIRTInfo = $"{this.sirt.Id}|{this.sirt.Frequency}Mhz"; } private void Ertask_MessageReceived(byte[] bytes) { if (bytes is null) { return; } var message = new SIRTMessage(bytes); if (message.Command == SIRTConstants.FROM_AIR) { var p11 = new P11(message.P1); var rssi = new RSSI(message.P2, (ushort)this.sirt.Frequency); var data = message.Payload; var length = data.Length; if (length > 0) { var type = data[0]; var telegram = default(object); var background = Brushes.White; if (type == SIRTConstants.BUP) { telegram = new BUP(data, p11); } else if (type == SIRTConstants.LAT) { telegram = new LAT(data, p11); } else if (type == SIRTConstants.DEBUG) { telegram = new DEBUG(data, p11); } else if (type == SIRTConstants.SEMI) { telegram = new SEMI(data, this.sirt.Frequency, p11); } if (telegram != null) { var sourceType = telegram.GetType(); var sourceName = sourceType.Name; foreach (var property in sourceType.GetProperties(BindingFlags.Public | BindingFlags.Instance)) { var name = property.Name; if (this.telegrams.TryGetValue(name, out var propertyVM)) { propertyVM.Source = sourceName; propertyVM.Value = $"{property.GetValue(telegram)}"; } } } } } } private void SIRTHub_Disconnected(SIRTBroadcaster sirt) { this.sirt = null; this.SIRTInfo = $"{sirt.PortName} disconnected"; } private void SetMetrologyParametersCommandHandler() { this.Status = null; foreach (var property in this.telegrams.Values) { property.Value = null; } if (this.sirt is null) { this.Status = "No SIRT is activated"; return; } var task = new EregisterTask(this.sirt.Frequency) { DelPamSemi = true, WakeUpCmd = true, RequestAddress = this.Address, }; try { task.SetCancelled(); this.cancellationTokenSource.Cancel(); } catch (Exception e) { this.Status = e.Message; } finally { this.cancellationTokenSource = null; this.cancellationToken = default(CancellationToken); this.cancellationTask = null; } this.cancellationTokenSource = new CancellationTokenSource(); this.cancellationToken = this.cancellationTokenSource.Token; this.cancellationTask = Task.Run(() => { void StateChanged(SIRTTask x) { this.Status = x.State.ToString(); } task.MessageReceived += this.Ertask_MessageReceived; task.StateChanged += StateChanged; if (this.StayAwake) { task.WakeUpModul = this.StayAwake; task.Data = new ChangeWakeUp { WakeUpMode = WakeUpMode.StayAwake } .Append(new ProvidePin { AuthLevel = AuthLevel.II }); this.Status = "Changing wake status"; task.SetPending(); while (task.State != SIRTTaskState.Completed && task.State != SIRTTaskState.Cancelled) { AppHost.SIRTHub.Start(task); task.Wait(); if (task.State == SIRTTaskState.Completed && task.State == SIRTTaskState.Cancelled) { break; } } task.WakeUpModul = false; } if (!string.IsNullOrWhiteSpace(this.MeterSize)) { task.Data = new SetMetrologyParameters { DecimalPoint = this.VPP < 700 ? DecimalPointLocations.Three : DecimalPointLocations.Two, MeterSize = this.meterSizes.TryGetValue(this.MeterSize, out var ms) ? ms.Size : (byte)23, FactoryCalibration = this.FactoryCalibration, OffsetFactor = this.OffsetFactor, OffsetTime = this.OffsetTime, Units = Enum.TryParse($"{this.Units}", out var units) ? units : MessurementUnits.Cubic_Meters, UseCandIRules = this.UseCandIRules, VppLED = (uint)(this.vppLED * 65536), Vpp = (int)((uint)(this.vpp * 65536) | 0x80_00_00_00), } .Append(new ProvidePin { AuthLevel = AuthLevel.III }); this.Status = "Changing metrology values"; task.SetPending(); while (task.State != SIRTTaskState.Completed && task.State != SIRTTaskState.Cancelled) { AppHost.SIRTHub.Start(task); task.Wait(); if (task.State == SIRTTaskState.Completed && task.State == SIRTTaskState.Cancelled) { break; } } } task.Data = new OpticalTelegram { Minutes = this.ChangeMode ? byte.MinValue : this.LEDOnTime } .Append(new ProvidePin { AuthLevel = AuthLevel.III }); this.Status = "Changing LED status"; task.SetPending(); while (task.State != SIRTTaskState.Completed && task.State != SIRTTaskState.Cancelled) { AppHost.SIRTHub.Start(task); task.Wait(); if (task.State == SIRTTaskState.Completed && task.State == SIRTTaskState.Cancelled) { break; } } if (this.ChangeMode) { task.Data = new ActivateMetrologyTestMode() { Hours = this.TestModeHours } .Append(new ProvidePin { AuthLevel = AuthLevel.I }); task.SetPending(); while (task.State != SIRTTaskState.Completed && task.State != SIRTTaskState.Cancelled) { AppHost.SIRTHub.Start(task); task.Wait(); if (task.State == SIRTTaskState.Completed && task.State == SIRTTaskState.Cancelled) { break; } } } task.StateChanged -= StateChanged; task.MessageReceived -= this.Ertask_MessageReceived; }, this.cancellationToken); } private void SwitchSettingsVisibilityCommandHandler() => this.AreSettingsVisible = !this.AreSettingsVisible; } }