From e6367da2862de5e1f50693ad054f5f1583d8f29b Mon Sep 17 00:00:00 2001 From: Lorenz Stechauner Date: Sun, 9 Nov 2025 23:46:19 +0100 Subject: [PATCH] App: Add SerialPortWatcher --- Elwig/App.xaml.cs | 59 ++++++++++++++++++++--- Elwig/Elwig.csproj | 1 + Elwig/Helpers/SerialPortWatcher.cs | 54 +++++++++++++++++++++ Elwig/Windows/DeliveryAdminWindow.xaml.cs | 13 +++++ 4 files changed, 121 insertions(+), 6 deletions(-) create mode 100644 Elwig/Helpers/SerialPortWatcher.cs diff --git a/Elwig/App.xaml.cs b/Elwig/App.xaml.cs index af793e3..887a555 100644 --- a/Elwig/App.xaml.cs +++ b/Elwig/App.xaml.cs @@ -26,6 +26,7 @@ namespace Elwig { public static bool ForceShutdown { get; private set; } = false; private readonly DispatcherTimer _autoUpdateTimer = new() { Interval = TimeSpan.FromHours(1) }; + public readonly SerialPortWatcher SerialPortWatcher = new(); public static readonly string DataPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), "Elwig"); public static readonly string MailsPath = Path.Combine(DataPath, "mails"); @@ -48,9 +49,10 @@ namespace Elwig { public static string? BranchPhoneNr { get; private set; } public static string? BranchFaxNr { get; private set; } public static string? BranchMobileNr { get; private set; } - public static IList Scales { get; private set; } - public static IList CommandScales => Scales.Where(s => s is ICommandScale).Cast().ToList(); - public static IList EventScales => Scales.Where(s => s is IEventScale).Cast().ToList(); + + public static IList Scales { get; private set; } = []; + public static IList CommandScales => [.. Scales.Where(s => s is ICommandScale).Cast()]; + public static IList EventScales => [.. Scales.Where(s => s is IEventScale).Cast()]; public static ClientParameters Client { get; set; } public static Dispatcher MainDispatcher { get; private set; } @@ -137,6 +139,9 @@ namespace Elwig { _autoUpdateTimer.Start(); } + SerialPortWatcher.SerialPortConnected += OnSerialPortConnected; + SerialPortWatcher.SerialPortDisconnected += OnSerialPortDisconnected; + var list = new List(); foreach (var s in Config.Scales) { try { @@ -144,7 +149,7 @@ namespace Elwig { } catch (Exception e) { list.Add(new InvalidScale(s.Id)); if (s.Required) - MessageBox.Show($"Unable to create scale {s.Id}:\n\n{e.Message}", "Scale Error", + MessageBox.Show($"Verbindung zu Waage {s.Id} konnte nicht hergestellt werden:\n\n{e.Message}", "Waagen-Fehler", MessageBoxButton.OK, MessageBoxImage.Error); } } @@ -152,7 +157,7 @@ namespace Elwig { if (Config.Branch != null) { if (!branches.ContainsKey(Config.Branch.ToLower())) { - MessageBox.Show("Invalid branch name in config!", "Invalid Branch Config", MessageBoxButton.OK, MessageBoxImage.Error); + MessageBox.Show("Ungültige Zweigstelle in Konfigurationsdatei!", "Ungültige Zweigstelle", MessageBoxButton.OK, MessageBoxImage.Error); Shutdown(); } else { SetBranch(branches[Config.Branch.ToLower()]); @@ -160,7 +165,7 @@ namespace Elwig { } else if (branches.Count == 1) { SetBranch(branches.First().Value); } else { - MessageBox.Show("Unable to determine local branch!", "Invalid Branch Config", MessageBoxButton.OK, MessageBoxImage.Error); + MessageBox.Show("Erkennen der lokalen Zweigstelle nicht möglich!", "Ungültige Zweigstelle", MessageBoxButton.OK, MessageBoxImage.Error); Shutdown(); } @@ -181,6 +186,7 @@ namespace Elwig { } private async void Application_Exit(object sender, ExitEventArgs evt) { + SerialPortWatcher.Dispose(); foreach (var s in EventScales) { s.Dispose(); } @@ -240,6 +246,47 @@ namespace Elwig { } } + private void OnSerialPortConnected(object? sender, string name) { + for (var i = 0; i < Config.Scales.Count; i++) { + var s = Config.Scales[i]; + if ((s.Connection?.StartsWith($"serial://{name}:") ?? false) && Scales[i] is InvalidScale) { + try { + Scales[i] = Scale.FromConfig(s); + MessageBox.Show($"Verbindung zu Waage {s.Id} wieder hergestellt!", $"Waage {s.Id}", MessageBoxButton.OK, MessageBoxImage.Information); + } catch (Exception e) { + Scales[i] = new InvalidScale(s.Id); + MessageBox.Show($"Verbindung zu Waage {s.Id} konnte nicht hergestellt werden:\n\n{e.Message}", "Waagen-Fehler", + MessageBoxButton.OK, MessageBoxImage.Error); + } + } + } + UpdateScales(); + } + + private void OnSerialPortDisconnected(object? sender, string name) { + for (var i = 0; i < Config.Scales.Count; i++) { + var s = Config.Scales[i]; + if ((s.Connection?.StartsWith($"serial://{name}:") ?? false) && Scales[i] is not InvalidScale) { + MessageBox.Show($"Verbindung zu Waage {s.Id} unterbrochen!", $"Waagen {s.Id}", MessageBoxButton.OK, MessageBoxImage.Warning); + try { + Scales[i].Dispose(); + } catch { + // ignore + } + Scales[i] = new InvalidScale(s.Id); + } + } + UpdateScales(); + } + + public static void UpdateScales() { + foreach (Window w in CurrentApp.Windows) { + if (w is DeliveryAdminWindow t && t.ViewModel.IsReceipt) { + t.UpdateScales(); + } + } + } + public static async Task CheckForUpdates(bool showAlert = false) { if (Config.UpdateUrl == null) return; var latest = await Utils.GetLatestInstallerUrl(Config.UpdateUrl); diff --git a/Elwig/Elwig.csproj b/Elwig/Elwig.csproj index 3e00528..4adbd20 100644 --- a/Elwig/Elwig.csproj +++ b/Elwig/Elwig.csproj @@ -37,6 +37,7 @@ + diff --git a/Elwig/Helpers/SerialPortWatcher.cs b/Elwig/Helpers/SerialPortWatcher.cs new file mode 100644 index 0000000..d3acaeb --- /dev/null +++ b/Elwig/Helpers/SerialPortWatcher.cs @@ -0,0 +1,54 @@ +using System; +using System.IO.Ports; +using System.Linq; +using System.Management; + +namespace Elwig.Helpers { + public sealed class SerialPortWatcher : IDisposable { + + private readonly ManagementEventWatcher _deviceArrivalWatcher; + private readonly ManagementEventWatcher _deviceRemovalWatcher; + + private string[] _knownPorts; + + public event EventHandler? SerialPortConnected; + public event EventHandler? SerialPortDisconnected; + + public SerialPortWatcher() { + _knownPorts = SerialPort.GetPortNames(); + _deviceArrivalWatcher = new ManagementEventWatcher("SELECT * FROM Win32_DeviceChangeEvent WHERE EventType = 2"); + _deviceArrivalWatcher.EventArrived += (s, e) => OnDeviceArrived(); + _deviceRemovalWatcher = new ManagementEventWatcher("SELECT * FROM Win32_DeviceChangeEvent WHERE EventType = 3"); + _deviceRemovalWatcher.EventArrived += (s, e) => OnDeviceRemoved(); + _deviceArrivalWatcher.Start(); + _deviceRemovalWatcher.Start(); + + } + + private void OnDeviceArrived() { + string[] currentPorts = SerialPort.GetPortNames(); + var newPorts = currentPorts.Except(_knownPorts).ToArray(); + foreach (var port in newPorts) + SerialPortConnected?.Invoke(this, port); + _knownPorts = currentPorts; + } + + private void OnDeviceRemoved() { + string[] currentPorts = SerialPort.GetPortNames(); + var removedPorts = _knownPorts.Except(currentPorts).ToArray(); + foreach (var port in removedPorts) + SerialPortDisconnected?.Invoke(this, port); + _knownPorts = currentPorts; + } + + public void Dispose() { + try { + _deviceArrivalWatcher?.Stop(); + _deviceRemovalWatcher?.Stop(); + } finally { + _deviceArrivalWatcher?.Dispose(); + _deviceRemovalWatcher?.Dispose(); + } + } + } +} diff --git a/Elwig/Windows/DeliveryAdminWindow.xaml.cs b/Elwig/Windows/DeliveryAdminWindow.xaml.cs index 3e8ebc1..be02d94 100644 --- a/Elwig/Windows/DeliveryAdminWindow.xaml.cs +++ b/Elwig/Windows/DeliveryAdminWindow.xaml.cs @@ -1168,6 +1168,19 @@ namespace Elwig.Windows { WeighingDButton.IsEnabled = n > 3 && App.CommandScales[3].IsReady; } + public void UpdateScales() { + if (!ViewModel.IsReceipt) return; + foreach (var s in App.EventScales) { + s.WeighingEvent -= Scale_Weighing; + s.WeighingEvent += Scale_Weighing; + } + if (WeighingManualButton.IsEnabled) { + EnableWeighingButtons(); + } else { + DisableWeighingButtons(); + } + } + private async Task UpdateLsNr() { if (string.IsNullOrEmpty(ViewModel.Date) || ViewModel.Branch == null) { ViewModel.LsNr = "";