common/Ui/Common.UI/ViewModels/SetMetrologyParametersVM.cs
2026-04-23 17:50:07 +02:00

643 lines
21 KiB
C#

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<SetMetrologyParametersVM>
{
private readonly Dictionary<string, PropertyVM> telegrams;
private readonly Dictionary<string, MeterSizeVM> 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<string>(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<string>(0),
Size = x.GetValue<byte>(1),
UseCandIRules = x.GetValue<bool>(2),
Vpp = x.GetValue<int>(3),
VppLED = x.GetValue<uint>(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<string, PropertyVM>();
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<MessurementUnits>()
.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<MessurementUnits>($"{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;
}
}