From ec9268b43eec80e8e5cb15a89db1995e93cf264d Mon Sep 17 00:00:00 2001 From: amadeo-alex <68441479+amadeo-alex@users.noreply.github.com> Date: Sat, 24 Jan 2026 12:34:04 +0100 Subject: [PATCH 01/13] Fix: launch parameters ignored for LaunchUrlCommand (#417) --- src/HASS.Agent/HASS.Agent/Functions/HelperFunctions.cs | 4 ++-- .../Commands/InternalCommands/LaunchUrlCommand.cs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/HASS.Agent/HASS.Agent/Functions/HelperFunctions.cs b/src/HASS.Agent/HASS.Agent/Functions/HelperFunctions.cs index 5f604d43..72fbb27f 100644 --- a/src/HASS.Agent/HASS.Agent/Functions/HelperFunctions.cs +++ b/src/HASS.Agent/HASS.Agent/Functions/HelperFunctions.cs @@ -371,9 +371,9 @@ internal static void OpenLocalFolder(string path) /// /// /// - internal static void LaunchUrl(string url, bool incognito = false) + internal static void LaunchUrl(string url, bool incognito = false, bool explicitUrl = false) { - var targetUrl = StorageManager.GetElementUrl(url); + var targetUrl = explicitUrl ? url : StorageManager.GetElementUrl(url); // did the user provide a browser? if (string.IsNullOrEmpty(Variables.AppSettings.BrowserBinary)) diff --git a/src/HASS.Agent/HASS.Agent/HomeAssistant/Commands/InternalCommands/LaunchUrlCommand.cs b/src/HASS.Agent/HASS.Agent/HomeAssistant/Commands/InternalCommands/LaunchUrlCommand.cs index b20b53d2..b8884225 100644 --- a/src/HASS.Agent/HASS.Agent/HomeAssistant/Commands/InternalCommands/LaunchUrlCommand.cs +++ b/src/HASS.Agent/HASS.Agent/HomeAssistant/Commands/InternalCommands/LaunchUrlCommand.cs @@ -39,7 +39,7 @@ public override void TurnOn() return; } - HelperFunctions.LaunchUrl(_url, _incognito); + HelperFunctions.LaunchUrl(_url, _incognito, true); State = "OFF"; } @@ -59,7 +59,7 @@ public override void TurnOnWithAction(string action) // prepare command var command = string.IsNullOrWhiteSpace(_url) ? action : $"{_url} {action}"; - HelperFunctions.LaunchUrl(command, _incognito); + HelperFunctions.LaunchUrl(command, _incognito, true); State = "OFF"; } From efcb0e224e4f3dafd638d84092e9fca51b0260b4 Mon Sep 17 00:00:00 2001 From: amadeo-alex <68441479+amadeo-alex@users.noreply.github.com> Date: Sat, 24 Jan 2026 12:40:54 +0100 Subject: [PATCH 02/13] Release: 2.2.1 (#418) --- src/HASS.Agent.Installer/InstallerScript-Service-x86.iss | 2 +- src/HASS.Agent.Installer/InstallerScript-Service.iss | 2 +- src/HASS.Agent.Installer/InstallerScript-x86.iss | 2 +- src/HASS.Agent.Installer/InstallerScript.iss | 2 +- .../HASS.Agent.Satellite.Service.csproj | 6 +++--- src/HASS.Agent/HASS.Agent.Shared/HASS.Agent.Shared.csproj | 6 +++--- src/HASS.Agent/HASS.Agent/HASS.Agent.csproj | 6 +++--- 7 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/HASS.Agent.Installer/InstallerScript-Service-x86.iss b/src/HASS.Agent.Installer/InstallerScript-Service-x86.iss index 9b632fc5..d34a5ec6 100644 --- a/src/HASS.Agent.Installer/InstallerScript-Service-x86.iss +++ b/src/HASS.Agent.Installer/InstallerScript-Service-x86.iss @@ -9,7 +9,7 @@ ; Standard installation constants #define MyAppName "HASS.Agent Satellite Service" -#define MyAppVersion "2.2.0" +#define MyAppVersion "2.2.1" #define MyAppPublisher "HASS.Agent Team" #define MyAppURL "https://hass-agent.io" #define MyAppExeName "HASS.Agent.Satellite.Service.exe" diff --git a/src/HASS.Agent.Installer/InstallerScript-Service.iss b/src/HASS.Agent.Installer/InstallerScript-Service.iss index f2825143..f9c44adb 100644 --- a/src/HASS.Agent.Installer/InstallerScript-Service.iss +++ b/src/HASS.Agent.Installer/InstallerScript-Service.iss @@ -9,7 +9,7 @@ ; Standard installation constants #define MyAppName "HASS.Agent Satellite Service" -#define MyAppVersion "2.2.0" +#define MyAppVersion "2.2.1" #define MyAppPublisher "HASS.Agent Team" #define MyAppURL "https://hass-agent.io" #define MyAppExeName "HASS.Agent.Satellite.Service.exe" diff --git a/src/HASS.Agent.Installer/InstallerScript-x86.iss b/src/HASS.Agent.Installer/InstallerScript-x86.iss index 62f11d9e..75927faa 100644 --- a/src/HASS.Agent.Installer/InstallerScript-x86.iss +++ b/src/HASS.Agent.Installer/InstallerScript-x86.iss @@ -9,7 +9,7 @@ ; Standard installation constants #define MyAppName "HASS.Agent" -#define MyAppVersion "2.2.0" +#define MyAppVersion "2.2.1" #define MyAppPublisher "HASS.Agent Team" #define MyAppURL "https://hass-agent.io" #define MyAppExeName "HASS.Agent.exe" diff --git a/src/HASS.Agent.Installer/InstallerScript.iss b/src/HASS.Agent.Installer/InstallerScript.iss index 4519dba4..335f0338 100644 --- a/src/HASS.Agent.Installer/InstallerScript.iss +++ b/src/HASS.Agent.Installer/InstallerScript.iss @@ -9,7 +9,7 @@ ; Standard installation constants #define MyAppName "HASS.Agent" -#define MyAppVersion "2.2.0" +#define MyAppVersion "2.2.1" #define MyAppPublisher "HASS.Agent Team" #define MyAppURL "https://hass-agent.io" #define MyAppExeName "HASS.Agent.exe" diff --git a/src/HASS.Agent/HASS.Agent.Satellite.Service/HASS.Agent.Satellite.Service.csproj b/src/HASS.Agent/HASS.Agent.Satellite.Service/HASS.Agent.Satellite.Service.csproj index 1e3dfd54..4464d5b6 100644 --- a/src/HASS.Agent/HASS.Agent.Satellite.Service/HASS.Agent.Satellite.Service.csproj +++ b/src/HASS.Agent/HASS.Agent.Satellite.Service/HASS.Agent.Satellite.Service.csproj @@ -8,7 +8,7 @@ dotnet-HASSAgentSatelliteService-6E4FA50A-3AC9-4E66-8671-9FAB92372154 anycpu x64;x86;AnyCPU - 2.2.0 + 2.2.1 HASS.Agent Team HASS.Agent Satellite Service HASS.Agent.Satellite.Service @@ -17,9 +17,9 @@ https://github.com/hass-agent/HASS.Agent https://github.com/hass-agent/HASS.Agent hass.png - 2.2.0 + 2.2.1 hass.ico - 2.2.0 + 2.2.1 10.0.17763.0 false diff --git a/src/HASS.Agent/HASS.Agent.Shared/HASS.Agent.Shared.csproj b/src/HASS.Agent/HASS.Agent.Shared/HASS.Agent.Shared.csproj index 0fae9b41..31336c84 100644 --- a/src/HASS.Agent/HASS.Agent.Shared/HASS.Agent.Shared.csproj +++ b/src/HASS.Agent/HASS.Agent.Shared/HASS.Agent.Shared.csproj @@ -10,9 +10,9 @@ Shared functions and models for the HASS.Agent platform. https://github.com/hass-agent/HASS.Agent https://github.com/hass-agent/HASS.Agent - 2.2.0 - 2.2.0 - 2.2.0 + 2.2.1 + 2.2.1 + 2.2.1 logo_128.png True hassagent.ico diff --git a/src/HASS.Agent/HASS.Agent/HASS.Agent.csproj b/src/HASS.Agent/HASS.Agent/HASS.Agent.csproj index 0ce5be7e..42f43703 100644 --- a/src/HASS.Agent/HASS.Agent/HASS.Agent.csproj +++ b/src/HASS.Agent/HASS.Agent/HASS.Agent.csproj @@ -17,7 +17,7 @@ anycpu x64;x86;AnyCPU full - 2.2.0 + 2.2.1 HASS.Agent Team HASS.Agent Team Windows-based client for Home Assistant. Provides notifications, quick actions, commands, sensors and more. @@ -27,8 +27,8 @@ https://github.com/hass-agent/HASS.Agent MIT app.manifest - 2.2.0 - 2.2.0 + 2.2.1 + 2.2.1 HASS.Agent None true From c5540318a68b79a3b13c5ebd813c62cff0dc8985 Mon Sep 17 00:00:00 2001 From: amadeo-alex <68441479+amadeo-alex@users.noreply.github.com> Date: Sat, 7 Feb 2026 19:51:39 +0100 Subject: [PATCH 03/13] Fix: launch parameters for LaunchURLCommand not treated explicitly (#428) From 7a55068c40eec5728ffd636a2eb6cd42852319bd Mon Sep 17 00:00:00 2001 From: amadeo-alex <68441479+amadeo-alex@users.noreply.github.com> Date: Sat, 7 Feb 2026 20:09:38 +0100 Subject: [PATCH 04/13] Fix: MQTT connection test using proper username & password (#429) This PR fixes issue reported via #396 by @jwidess where MQTT connection test during initial onboarding would check "configured" username rather than the provided one. --- src/HASS.Agent/HASS.Agent/MQTT/MqttManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/HASS.Agent/HASS.Agent/MQTT/MqttManager.cs b/src/HASS.Agent/HASS.Agent/MQTT/MqttManager.cs index 67cfb13b..43eae3a5 100644 --- a/src/HASS.Agent/HASS.Agent/MQTT/MqttManager.cs +++ b/src/HASS.Agent/HASS.Agent/MQTT/MqttManager.cs @@ -917,7 +917,7 @@ internal static async Task TestConnection(string address, int port, bool u clientOptionsBuilder.WithTcpServer(address, port); } - if (!string.IsNullOrEmpty(Variables.AppSettings.MqttUsername)) + if (!string.IsNullOrEmpty(username)) { clientOptionsBuilder.WithCredentials(username, password); } From dcab412d8133f14693971a2e269f670f40c26d9c Mon Sep 17 00:00:00 2001 From: amadeo-alex <68441479+amadeo-alex@users.noreply.github.com> Date: Sat, 7 Feb 2026 20:41:25 +0100 Subject: [PATCH 05/13] Fix: "ESCAPE" key as KeyCommand parameter (#431) This PR fixes issue reported via #423 by @arklev where "ESCAPE" key couldn't be provided as a parameter to KeyCommand - configuration window would close. Now closing the window requires pressing "ESCAPE" key twice. --- .../HASS.Agent/Forms/Commands/CommandsMod.cs | 22 ++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/src/HASS.Agent/HASS.Agent/Forms/Commands/CommandsMod.cs b/src/HASS.Agent/HASS.Agent/Forms/Commands/CommandsMod.cs index a14d80bc..de248bda 100644 --- a/src/HASS.Agent/HASS.Agent/Forms/Commands/CommandsMod.cs +++ b/src/HASS.Agent/HASS.Agent/Forms/Commands/CommandsMod.cs @@ -28,7 +28,9 @@ public partial class CommandsMod : MetroForm private bool _interfaceLockedWrongType; private bool _loading = true; - private readonly Dictionary _commandEntityTypes = new(); + private bool _escapeLock = true; + + private readonly Dictionary _commandEntityTypes = new(); private readonly Dictionary _radioDevices = new(); public CommandsMod(ConfiguredCommand command, bool serviceMode = false, string serviceDeviceName = "") @@ -977,11 +979,21 @@ private void LblIntegrityInfo_Click(object sender, EventArgs e) private void CommandsMod_KeyUp(object sender, KeyEventArgs e) { - if (e.KeyCode != Keys.Escape) - return; + if (e.KeyCode != Keys.Escape) + { + _escapeLock = true; + return; + } - Close(); - } + if (_escapeLock) + { + _escapeLock = false; + } + else + { + Close(); + } + } private void CommandsMod_Layout(object sender, LayoutEventArgs e) { From 30c21ffa8ef044b4abd6e41a35e6b5dd8546525d Mon Sep 17 00:00:00 2001 From: amadeo-alex <68441479+amadeo-alex@users.noreply.github.com> Date: Sat, 7 Feb 2026 21:52:42 +0100 Subject: [PATCH 06/13] Fix: WebViewCommand position not working properly with negative values (#432) This PR fixes an issue reported via #427 by @DyadicOne where moving WebViewCommand configuration window to screen with negative location values, would cause HASS.Agent to crash/save last positive value. --- .../CommandConfig/WebViewCommandConfig.Designer.cs | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/src/HASS.Agent/HASS.Agent/Forms/Commands/CommandConfig/WebViewCommandConfig.Designer.cs b/src/HASS.Agent/HASS.Agent/Forms/Commands/CommandConfig/WebViewCommandConfig.Designer.cs index 718b80ee..cba67b64 100644 --- a/src/HASS.Agent/HASS.Agent/Forms/Commands/CommandConfig/WebViewCommandConfig.Designer.cs +++ b/src/HASS.Agent/HASS.Agent/Forms/Commands/CommandConfig/WebViewCommandConfig.Designer.cs @@ -243,11 +243,8 @@ private void InitializeComponent() this.NumLocationX.Font = new System.Drawing.Font("Segoe UI", 10F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point); this.NumLocationX.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(241)))), ((int)(((byte)(241)))), ((int)(((byte)(241))))); this.NumLocationX.Location = new System.Drawing.Point(34, 160); - this.NumLocationX.Maximum = new decimal(new int[] { - 65535, - 0, - 0, - 0}); + this.NumLocationX.Maximum = new decimal(Int32.MaxValue); + this.NumLocationX.Minimum = new decimal(Int32.MinValue); this.NumLocationX.MaxLength = 10; this.NumLocationX.MetroColor = System.Drawing.SystemColors.WindowFrame; this.NumLocationX.Name = "NumLocationX"; @@ -269,11 +266,8 @@ private void InitializeComponent() this.NumLocationY.Font = new System.Drawing.Font("Segoe UI", 10F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point); this.NumLocationY.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(241)))), ((int)(((byte)(241)))), ((int)(((byte)(241))))); this.NumLocationY.Location = new System.Drawing.Point(149, 160); - this.NumLocationY.Maximum = new decimal(new int[] { - 65535, - 0, - 0, - 0}); + this.NumLocationY.Maximum = new decimal(Int32.MaxValue); + this.NumLocationY.Minimum = new decimal(Int32.MinValue); this.NumLocationY.MaxLength = 10; this.NumLocationY.MetroColor = System.Drawing.SystemColors.WindowFrame; this.NumLocationY.Name = "NumLocationY"; From 493f22f73cf9ebd4ea94dce096b0ce372e9fd549 Mon Sep 17 00:00:00 2001 From: Serge Baranov Date: Sun, 22 Mar 2026 03:18:45 -0700 Subject: [PATCH 07/13] Fix LastActiveSensor reporting wrong time after ~25 days (#440) Thanks to @CrazyCoder! ``` Replace Environment.TickCount with Environment.TickCount64 (Int64). This returns the same millisecond count but won't overflow for about 292 million years. Also changed Convert.ToDouble(lastInputInfo.dwTime) to (long)lastInputInfo.dwTime so the arithmetic stays in integer types instead of going through floating point for no reason. ``` --- .../Sensors/GeneralSensors/SingleValue/LastActiveSensor.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/HASS.Agent/HASS.Agent.Shared/HomeAssistant/Sensors/GeneralSensors/SingleValue/LastActiveSensor.cs b/src/HASS.Agent/HASS.Agent.Shared/HomeAssistant/Sensors/GeneralSensors/SingleValue/LastActiveSensor.cs index 7796990c..5d7de85e 100644 --- a/src/HASS.Agent/HASS.Agent.Shared/HomeAssistant/Sensors/GeneralSensors/SingleValue/LastActiveSensor.cs +++ b/src/HASS.Agent/HASS.Agent.Shared/HomeAssistant/Sensors/GeneralSensors/SingleValue/LastActiveSensor.cs @@ -86,12 +86,12 @@ private static DateTime GetLastInputTime() lastInputInfo.cbSize = Marshal.SizeOf(lastInputInfo); lastInputInfo.dwTime = 0; - var envTicks = Environment.TickCount; + var envTicks = Environment.TickCount64; if (!GetLastInputInfo(ref lastInputInfo)) return DateTime.Now; - var lastInputTick = Convert.ToDouble(lastInputInfo.dwTime); + var lastInputTick = (long)lastInputInfo.dwTime; var idleTime = envTicks - lastInputTick; return idleTime > 0 ? DateTime.Now - TimeSpan.FromMilliseconds(idleTime) : DateTime.Now; From 3ab46fb972a16ce5b0d0d3df84dcf4878d1e43aa Mon Sep 17 00:00:00 2001 From: Bluscream Date: Sun, 22 Mar 2026 11:57:07 +0100 Subject: [PATCH 08/13] Fix: NullReferenceException in Satellite Service on unknown types Thanks to @Bluscream for the PR! --- .../Settings/StoredCommands.cs | 7 +++++-- .../Settings/StoredSensors.cs | 14 +++++++++++--- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/src/HASS.Agent/HASS.Agent.Satellite.Service/Settings/StoredCommands.cs b/src/HASS.Agent/HASS.Agent.Satellite.Service/Settings/StoredCommands.cs index 0673e775..de838048 100644 --- a/src/HASS.Agent/HASS.Agent.Satellite.Service/Settings/StoredCommands.cs +++ b/src/HASS.Agent/HASS.Agent.Satellite.Service/Settings/StoredCommands.cs @@ -1,4 +1,4 @@ -using HASS.Agent.Shared.Enums; +using HASS.Agent.Shared.Enums; using HASS.Agent.Shared.Models.Config; using HASS.Agent.Shared.HomeAssistant.Commands; using HASS.Agent.Shared.HomeAssistant.Commands.CustomCommands; @@ -56,7 +56,10 @@ internal static async Task LoadAsync() // convert to abstract commands await Task.Run(delegate { - foreach (var abstractCommand in configuredCommands.Select(ConvertConfiguredToAbstract)) Variables.Commands.Add(abstractCommand!); + foreach (var abstractCommand in configuredCommands.Select(ConvertConfiguredToAbstract)) + { + if (abstractCommand != null) Variables.Commands.Add(abstractCommand); + } }); // all good diff --git a/src/HASS.Agent/HASS.Agent.Satellite.Service/Settings/StoredSensors.cs b/src/HASS.Agent/HASS.Agent.Satellite.Service/Settings/StoredSensors.cs index ea81e57a..556c8086 100644 --- a/src/HASS.Agent/HASS.Agent.Satellite.Service/Settings/StoredSensors.cs +++ b/src/HASS.Agent/HASS.Agent.Satellite.Service/Settings/StoredSensors.cs @@ -1,4 +1,4 @@ -using HASS.Agent.Shared.Enums; +using HASS.Agent.Shared.Enums; using HASS.Agent.Shared.Models.Config; using HASS.Agent.Satellite.Service.Extensions; using HASS.Agent.Shared.HomeAssistant.Sensors; @@ -61,8 +61,16 @@ await Task.Run(delegate { foreach (var sensor in configuredSensors) { - if (sensor.IsSingleValue()) Variables.SingleValueSensors.Add(ConvertConfiguredToAbstractSingleValue(sensor)!); - else Variables.MultiValueSensors.Add(ConvertConfiguredToAbstractMultiValue(sensor)!); + if (sensor.IsSingleValue()) + { + var abstractSensor = ConvertConfiguredToAbstractSingleValue(sensor); + if (abstractSensor != null) Variables.SingleValueSensors.Add(abstractSensor); + } + else + { + var abstractSensor = ConvertConfiguredToAbstractMultiValue(sensor); + if (abstractSensor != null) Variables.MultiValueSensors.Add(abstractSensor); + } } }); From fdbeae63907a869fc12b680dead49ad57c6cc263 Mon Sep 17 00:00:00 2001 From: amadeo-alex <68441479+amadeo-alex@users.noreply.github.com> Date: Thu, 28 May 2026 12:16:48 +0200 Subject: [PATCH 09/13] Fix: Hotkey Library Change (#449) --- .../Onboarding/Onboarding-6-HotKey.cs | 68 ++++- .../HASS.Agent/Forms/Configuration.cs | 259 +++++++++++++----- src/HASS.Agent/HASS.Agent/Forms/Main.cs | 25 +- .../Forms/QuickActions/QuickActionsConfig.cs | 2 +- .../Forms/QuickActions/QuickActionsMod.cs | 77 ++++-- .../HASS.Agent/Functions/HelperFunctions.cs | 4 +- src/HASS.Agent/HASS.Agent/HASS.Agent.csproj | 4 +- .../HASS.Agent/Libraries/HotkeyListener.dll | Bin 448000 -> 0 bytes ...KeyManager.cs => InternalHotKeyManager.cs} | 103 +++++-- .../HASS.Agent/Settings/SettingsManager.cs | 3 +- src/HASS.Agent/HASS.Agent/Variables.cs | 8 +- 11 files changed, 412 insertions(+), 141 deletions(-) delete mode 100644 src/HASS.Agent/HASS.Agent/Libraries/HotkeyListener.dll rename src/HASS.Agent/HASS.Agent/Managers/{HotKeyManager.cs => InternalHotKeyManager.cs} (51%) diff --git a/src/HASS.Agent/HASS.Agent/Controls/Onboarding/Onboarding-6-HotKey.cs b/src/HASS.Agent/HASS.Agent/Controls/Onboarding/Onboarding-6-HotKey.cs index d0313c97..a8c556f7 100644 --- a/src/HASS.Agent/HASS.Agent/Controls/Onboarding/Onboarding-6-HotKey.cs +++ b/src/HASS.Agent/HASS.Agent/Controls/Onboarding/Onboarding-6-HotKey.cs @@ -1,12 +1,13 @@ using HASS.Agent.Functions; -using WK.Libraries.HotkeyListenerNS; +using System.Windows.Forms; namespace HASS.Agent.Controls.Onboarding { public partial class OnboardingHotKey : UserControl { - private readonly HotkeySelector _hotkeySelector = new(); - + private Keys _key = Keys.None; + private Keys _modifiers = Keys.None; + public OnboardingHotKey() { InitializeComponent(); @@ -14,19 +15,18 @@ public OnboardingHotKey() private void OnboardingHotKey_Load(object sender, EventArgs e) { - // config quick actions hotkey selector - _hotkeySelector.Enable(TbQuickActionsHotkey); - + TbQuickActionsHotkey.ReadOnly = true; + TbQuickActionsHotkey.KeyDown += TbQuickActionsHotkey_KeyDown; if (string.IsNullOrEmpty(Variables.AppSettings.QuickActionsHotKey)) { // if nothing set, load default LoadDefault(); } - else if (Variables.AppSettings.QuickActionsHotKey == _hotkeySelector.EmptyHotkeyText) + else if (Variables.AppSettings.QuickActionsHotKey == string.Empty) { // if set to empty, show empty - TbQuickActionsHotkey.Text = _hotkeySelector.EmptyHotkeyText; + TbQuickActionsHotkey.Text = string.Empty; } else { @@ -81,13 +81,61 @@ private void LoadSetValue() internal bool Store() { Variables.AppSettings.QuickActionsHotKey = TbQuickActionsHotkey.Text; - _hotkeySelector.Dispose(); + TbQuickActionsHotkey.KeyDown -= TbQuickActionsHotkey_KeyDown; return true; } private void BtnClear_Click(object sender, EventArgs e) { - TbQuickActionsHotkey.Text = _hotkeySelector.EmptyHotkeyText; + TbQuickActionsHotkey.Text = string.Empty; + } + + private void TbQuickActionsHotkey_KeyDown(object sender, KeyEventArgs e) + { + e.SuppressKeyPress = true; + + var key = e.KeyCode; + + if (key is Keys.LControlKey or Keys.RControlKey + or Keys.LShiftKey or Keys.RShiftKey + or Keys.LWin or Keys.RWin + or Keys.Alt) + { + key = Keys.None; + } + + if (key == Keys.Escape) + { + _key = Keys.None; + _modifiers = Keys.None; + TbQuickActionsHotkey.Text = string.Empty; + + return; + } + + _key = key; + TbQuickActionsHotkey.Text = FormatHotkey(_key, e.Modifiers); + } + + private string FormatHotkey(Keys key, Keys modifiers) + { + var parts = new List(); + if ((modifiers & Keys.Shift) != 0) + { + parts.Add(nameof(Keys.Shift)); + } + + if ((modifiers & Keys.Control) != 0) + { + parts.Add(nameof(Keys.Control)); + } + + if ((modifiers & Keys.Alt) != 0) + { + parts.Add(nameof(Keys.Alt)); + } + + return parts.Count > 0 ? string.Join(", ", parts) + " + " + key : key.ToString(); } } } diff --git a/src/HASS.Agent/HASS.Agent/Forms/Configuration.cs b/src/HASS.Agent/HASS.Agent/Forms/Configuration.cs index 8c081535..cf1f6baa 100644 --- a/src/HASS.Agent/HASS.Agent/Forms/Configuration.cs +++ b/src/HASS.Agent/HASS.Agent/Forms/Configuration.cs @@ -8,7 +8,6 @@ using HASS.Agent.Settings; using HASS.Agent.Shared; using HASS.Agent.Shared.Functions; -using WK.Libraries.HotkeyListenerNS; using Task = System.Threading.Tasks.Task; using ConfigSatelliteService = HASS.Agent.Controls.Configuration.ConfigService; using HASS.Agent.MQTT; @@ -17,8 +16,7 @@ namespace HASS.Agent.Forms { public partial class Configuration : MetroForm { - private readonly HotkeySelector _hotkeySelector = new(); - private readonly Hotkey _previousHotkey = Variables.QuickActionsHotKey; + private readonly string _previousHotkey = Variables.QuickActionsHotKey; private readonly string _previousDeviceName = Variables.AppSettings.DeviceName; private readonly int _previousLocalApiPort = Variables.AppSettings.LocalApiPort; @@ -41,6 +39,9 @@ public partial class Configuration : MetroForm private bool _initializing = true; + private Keys _key = Keys.None; + private Keys _modifiers = Keys.None; + public Configuration() { InitializeComponent(); @@ -52,7 +53,7 @@ private void Configuration_Load(object sender, EventArgs e) KeyPreview = true; // suspend global hotkeys - Variables.HotKeyListener.Suspend(); + Variables.HotKeyListener.IsEnabled = false; // load controls TabGeneral.Controls.Add(_general); @@ -79,18 +80,21 @@ private void Configuration_Load(object sender, EventArgs e) LoadSettings(); // config quick actions hotkey selector - if (Variables.QuickActionsHotKey != null) _hotkeySelector.Enable(_hotKey.TbQuickActionsHotkey, Variables.QuickActionsHotKey); - else _hotkeySelector.Enable(_hotKey.TbQuickActionsHotkey); + _hotKey.TbQuickActionsHotkey.ReadOnly = true; + _hotKey.TbQuickActionsHotkey.KeyDown += TbQuickActionsHotkey_KeyDown; + if (Variables.QuickActionsHotKey != null) + { + _hotKey.TbQuickActionsHotkey.Text = Variables.QuickActionsHotKey; + } } private void Configuration_FormClosing(object sender, FormClosingEventArgs e) { // resume global hotkeys - Variables.HotKeyListener.Resume(); + Variables.HotKeyListener.IsEnabled = true; - // remove hotkey selector - _hotkeySelector?.Disable(_hotKey.TbQuickActionsHotkey); - _hotkeySelector?.Dispose(); + // clean hotkey selector + _hotKey.TbQuickActionsHotkey.KeyDown -= TbQuickActionsHotkey_KeyDown; // dispose controls _general.Dispose(); @@ -110,14 +114,62 @@ private void Configuration_FormClosing(object sender, FormClosingEventArgs e) _nfc.Dispose(); } + private void TbQuickActionsHotkey_KeyDown(object sender, KeyEventArgs e) + { + e.SuppressKeyPress = true; + + var key = e.KeyCode; + + if (key is Keys.LControlKey or Keys.RControlKey + or Keys.LShiftKey or Keys.RShiftKey + or Keys.LWin or Keys.RWin + or Keys.Alt) + { + key = Keys.None; + } + + if (key == Keys.Escape) + { + _key = Keys.None; + _modifiers = Keys.None; + _hotKey.TbQuickActionsHotkey.Text = string.Empty; + + return; + } + + _key = key; + _hotKey.TbQuickActionsHotkey.Text = FormatHotkey(_key, e.Modifiers); + } + + private string FormatHotkey(Keys key, Keys modifiers) + { + var parts = new List(); + if ((modifiers & Keys.Shift) != 0) + { + parts.Add(nameof(Keys.Shift)); + } + + if ((modifiers & Keys.Control) != 0) + { + parts.Add(nameof(Keys.Control)); + } + + if ((modifiers & Keys.Alt) != 0) + { + parts.Add(nameof(Keys.Alt)); + } + + return parts.Count > 0 ? string.Join(", ", parts) + " + " + key : key.ToString(); + } + private void BindEvents() { // hass _homeAssistantApi.CbHassAutoClientCertificate.CheckedChanged += CbHassAutoClientCertificate_CheckedChanged; - + // mqtt _mqtt.CbMqttTls.CheckedChanged += CbMqttTls_CheckedChanged; - + // hotkey _hotKey.BtnClearHotKey.Click += BtnClearHotKey_Click; } @@ -148,7 +200,8 @@ private async void ProcessChanges() BtnStore.Text = Languages.Configuration_BtnStore_Busy; // optionally sanitize device name - if (_general.CbEnableDeviceNameSanitation.Checked) _general.TbDeviceName.Text = SharedHelperFunctions.GetSafeValue(_general.TbDeviceName.Text); + if (_general.CbEnableDeviceNameSanitation.Checked) + _general.TbDeviceName.Text = SharedHelperFunctions.GetSafeValue(_general.TbDeviceName.Text); // store settings await StoreSettingsAsync(); @@ -198,28 +251,32 @@ private async void ProcessChanges() // disconnect mqtt so we don't get announced again await Task.Run(Variables.MqttManager.Disconnect); - + forceRestart = true; } // reserve the new local api's port if it's changed if (Variables.AppSettings.LocalApiPort != _previousLocalApiPort) { - MessageBoxAdv.Show(this, Languages.Configuration_ProcessChanges_MessageBox2, Variables.MessageBoxTitle, MessageBoxButtons.OK, MessageBoxIcon.Information); + MessageBoxAdv.Show(this, Languages.Configuration_ProcessChanges_MessageBox2, Variables.MessageBoxTitle, + MessageBoxButtons.OK, MessageBoxIcon.Information); // try to reserve elevated if (!ApiManager.ExecuteElevatedPortReservation()) { // failed, copy the command onto the clipboard - Clipboard.SetText($"netsh http add urlacl url=http://+:{Variables.AppSettings.LocalApiPort}/ user=\"{SharedHelperFunctions.EveryoneLocalizedAccountName()}\""); + Clipboard.SetText( + $"netsh http add urlacl url=http://+:{Variables.AppSettings.LocalApiPort}/ user=\"{SharedHelperFunctions.EveryoneLocalizedAccountName()}\""); // notify the user - MessageBoxAdv.Show(this, Languages.Configuration_ProcessChanges_MessageBox3, Variables.MessageBoxTitle, MessageBoxButtons.OK, MessageBoxIcon.Error); + MessageBoxAdv.Show(this, Languages.Configuration_ProcessChanges_MessageBox3, + Variables.MessageBoxTitle, MessageBoxButtons.OK, MessageBoxIcon.Error); } else { // notify the user - MessageBoxAdv.Show(this, Languages.Configuration_ProcessChanges_MessageBox4, Variables.MessageBoxTitle, MessageBoxButtons.OK, MessageBoxIcon.Information); + MessageBoxAdv.Show(this, Languages.Configuration_ProcessChanges_MessageBox4, + Variables.MessageBoxTitle, MessageBoxButtons.OK, MessageBoxIcon.Information); // we need to restart, so go ahead, otherwise it's starting to look like popup-spam .. forceRestart = true; @@ -230,17 +287,22 @@ private async void ProcessChanges() { // prepare the restart without asking var restartPrepared = HelperFunctions.Restart(); - if (!restartPrepared) MessageBoxAdv.Show(this, Languages.Configuration_MessageBox_RestartManually, Variables.MessageBoxTitle, MessageBoxButtons.OK, MessageBoxIcon.Error); + if (!restartPrepared) + MessageBoxAdv.Show(this, Languages.Configuration_MessageBox_RestartManually, + Variables.MessageBoxTitle, MessageBoxButtons.OK, MessageBoxIcon.Error); } else { // ask the user if they want to restart - var question = MessageBoxAdv.Show(this, Languages.Configuration_ProcessChanges_MessageBox5, Variables.MessageBoxTitle, MessageBoxButtons.YesNo, MessageBoxIcon.Question); + var question = MessageBoxAdv.Show(this, Languages.Configuration_ProcessChanges_MessageBox5, + Variables.MessageBoxTitle, MessageBoxButtons.YesNo, MessageBoxIcon.Question); if (question == DialogResult.Yes) { // prepare the restart var restartPrepared = HelperFunctions.Restart(); - if (!restartPrepared) MessageBoxAdv.Show(this, Languages.Configuration_MessageBox_RestartManually, Variables.MessageBoxTitle, MessageBoxButtons.OK, MessageBoxIcon.Error); + if (!restartPrepared) + MessageBoxAdv.Show(this, Languages.Configuration_MessageBox_RestartManually, + Variables.MessageBoxTitle, MessageBoxButtons.OK, MessageBoxIcon.Error); } } @@ -260,7 +322,8 @@ private bool CheckValues() { if (!SharedHelperFunctions.CheckHomeAssistantApiToken(hassApi)) { - var q = MessageBoxAdv.Show(this, Languages.Configuration_CheckValues_MessageBox1, Variables.MessageBoxTitle, MessageBoxButtons.YesNo, MessageBoxIcon.Exclamation); + var q = MessageBoxAdv.Show(this, Languages.Configuration_CheckValues_MessageBox1, + Variables.MessageBoxTitle, MessageBoxButtons.YesNo, MessageBoxIcon.Exclamation); if (q != DialogResult.Yes) return false; } } @@ -271,7 +334,8 @@ private bool CheckValues() { if (!SharedHelperFunctions.CheckHomeAssistantUri(hassUri)) { - var q = MessageBoxAdv.Show(this, Languages.Configuration_CheckValues_MessageBox2, Variables.MessageBoxTitle, MessageBoxButtons.YesNo, MessageBoxIcon.Exclamation); + var q = MessageBoxAdv.Show(this, Languages.Configuration_CheckValues_MessageBox2, + Variables.MessageBoxTitle, MessageBoxButtons.YesNo, MessageBoxIcon.Exclamation); if (q != DialogResult.Yes) return false; } } @@ -282,7 +346,8 @@ private bool CheckValues() { if (!SharedHelperFunctions.CheckMqttBrokerUri(mqttUri)) { - var q = MessageBoxAdv.Show(this, Languages.Configuration_CheckValues_MessageBox3, Variables.MessageBoxTitle, MessageBoxButtons.YesNo, MessageBoxIcon.Exclamation); + var q = MessageBoxAdv.Show(this, Languages.Configuration_CheckValues_MessageBox3, + Variables.MessageBoxTitle, MessageBoxButtons.YesNo, MessageBoxIcon.Exclamation); if (q != DialogResult.Yes) return false; } } @@ -298,28 +363,42 @@ private void LoadSettings() { // general _general.TbDeviceName.Text = Variables.AppSettings.DeviceName; - _general.CbEnableDeviceNameSanitation.CheckState = Variables.AppSettings.SanitizeName ? CheckState.Checked : CheckState.Unchecked; + _general.CbEnableDeviceNameSanitation.CheckState = + Variables.AppSettings.SanitizeName ? CheckState.Checked : CheckState.Unchecked; _general.NumDisconnectGrace.Value = Variables.AppSettings.DisconnectedGracePeriodSeconds; - _general.CbEnableStateNotifications.CheckState = Variables.AppSettings.EnableStateNotifications ? CheckState.Checked : CheckState.Unchecked; + _general.CbEnableStateNotifications.CheckState = Variables.AppSettings.EnableStateNotifications + ? CheckState.Checked + : CheckState.Unchecked; // startup settings Task.Run(_startup.DetermineStartOnLoginStatus); // local api _localApi.NumLocalApiPort.Value = Variables.AppSettings.LocalApiPort; - _localApi.CbLocalApiActive.CheckState = Variables.AppSettings.LocalApiEnabled ? CheckState.Checked : CheckState.Unchecked; + _localApi.CbLocalApiActive.CheckState = + Variables.AppSettings.LocalApiEnabled ? CheckState.Checked : CheckState.Unchecked; // notifications - _notifications.CbAcceptNotifications.CheckState = Variables.AppSettings.NotificationsEnabled ? CheckState.Checked : CheckState.Unchecked; - _notifications.CbNotificationsIgnoreImageCertErrors.CheckState = Variables.AppSettings.NotificationsIgnoreImageCertificateErrors ? CheckState.Checked : CheckState.Unchecked; - _notifications.CbNotificationsOpenActionUri.CheckState = Variables.AppSettings.NotificationsOpenActionUri ? CheckState.Checked : CheckState.Unchecked; + _notifications.CbAcceptNotifications.CheckState = Variables.AppSettings.NotificationsEnabled + ? CheckState.Checked + : CheckState.Unchecked; + _notifications.CbNotificationsIgnoreImageCertErrors.CheckState = + Variables.AppSettings.NotificationsIgnoreImageCertificateErrors + ? CheckState.Checked + : CheckState.Unchecked; + _notifications.CbNotificationsOpenActionUri.CheckState = Variables.AppSettings.NotificationsOpenActionUri + ? CheckState.Checked + : CheckState.Unchecked; // hass settings _homeAssistantApi.TbHassIp.Text = Variables.AppSettings.HassUri; _homeAssistantApi.TbHassApiToken.Text = Variables.AppSettings.HassToken; _homeAssistantApi.TbHassClientCertificate.Text = Variables.AppSettings.HassClientCertificate; - _homeAssistantApi.CbHassAutoClientCertificate.CheckState = Variables.AppSettings.HassAutoClientCertificate ? CheckState.Checked : CheckState.Unchecked; - _homeAssistantApi.CbHassAllowUntrustedCertificates.CheckState = Variables.AppSettings.HassAllowUntrustedCertificates ? CheckState.Checked : CheckState.Unchecked; + _homeAssistantApi.CbHassAutoClientCertificate.CheckState = Variables.AppSettings.HassAutoClientCertificate + ? CheckState.Checked + : CheckState.Unchecked; + _homeAssistantApi.CbHassAllowUntrustedCertificates.CheckState = + Variables.AppSettings.HassAllowUntrustedCertificates ? CheckState.Checked : CheckState.Unchecked; if (Variables.AppSettings.HassAutoClientCertificate) { _homeAssistantApi.TbHassClientCertificate.Text = string.Empty; @@ -327,10 +406,13 @@ private void LoadSettings() } // hotkey - _hotKey.CbEnableQuickActionsHotkey.CheckState = Variables.AppSettings.QuickActionsHotKeyEnabled ? CheckState.Checked : CheckState.Unchecked; + _hotKey.CbEnableQuickActionsHotkey.CheckState = Variables.AppSettings.QuickActionsHotKeyEnabled + ? CheckState.Checked + : CheckState.Unchecked; // mqtt - _mqtt.CbEnableMqtt.CheckState = Variables.AppSettings.MqttEnabled ? CheckState.Checked : CheckState.Unchecked; + _mqtt.CbEnableMqtt.CheckState = + Variables.AppSettings.MqttEnabled ? CheckState.Checked : CheckState.Unchecked; _mqtt.TbMqttAddress.Text = Variables.AppSettings.MqttAddress; _mqtt.NumMqttPort.Value = Variables.AppSettings.MqttPort; _mqtt.CbMqttTls.CheckState = Variables.AppSettings.MqttUseTls ? CheckState.Checked : CheckState.Unchecked; @@ -340,15 +422,25 @@ private void LoadSettings() _mqtt.TbMqttClientId.Text = Variables.AppSettings.MqttClientId; _mqtt.TbMqttRootCertificate.Text = Variables.AppSettings.MqttRootCertificate; _mqtt.TbMqttClientCertificate.Text = Variables.AppSettings.MqttClientCertificate; - _mqtt.CbAllowUntrustedCertificates.CheckState = Variables.AppSettings.MqttAllowUntrustedCertificates ? CheckState.Checked : CheckState.Unchecked; - _mqtt.CbUseRetainFlag.CheckState = Variables.AppSettings.MqttUseRetainFlag ? CheckState.Checked : CheckState.Unchecked; - _mqtt.CbUseWebSocket.CheckState = Variables.AppSettings.MqttUseWebSocket ? CheckState.Checked : CheckState.Unchecked; - _mqtt.CbIgnoreGracePeriod.CheckState = Variables.AppSettings.MqttIgnoreGracePeriod ? CheckState.Checked : CheckState.Unchecked; + _mqtt.CbAllowUntrustedCertificates.CheckState = Variables.AppSettings.MqttAllowUntrustedCertificates + ? CheckState.Checked + : CheckState.Unchecked; + _mqtt.CbUseRetainFlag.CheckState = + Variables.AppSettings.MqttUseRetainFlag ? CheckState.Checked : CheckState.Unchecked; + _mqtt.CbUseWebSocket.CheckState = + Variables.AppSettings.MqttUseWebSocket ? CheckState.Checked : CheckState.Unchecked; + _mqtt.CbIgnoreGracePeriod.CheckState = Variables.AppSettings.MqttIgnoreGracePeriod + ? CheckState.Checked + : CheckState.Unchecked; // updates - _updates.CbUpdates.CheckState = Variables.AppSettings.CheckForUpdates ? CheckState.Checked : CheckState.Unchecked; - _updates.CbBetaUpdates.CheckState = Variables.AppSettings.ShowBetaUpdates ? CheckState.Checked : CheckState.Unchecked; - _updates.CbExecuteUpdater.CheckState = Variables.AppSettings.EnableExecuteUpdateInstaller ? CheckState.Checked : CheckState.Unchecked; + _updates.CbUpdates.CheckState = + Variables.AppSettings.CheckForUpdates ? CheckState.Checked : CheckState.Unchecked; + _updates.CbBetaUpdates.CheckState = + Variables.AppSettings.ShowBetaUpdates ? CheckState.Checked : CheckState.Unchecked; + _updates.CbExecuteUpdater.CheckState = Variables.AppSettings.EnableExecuteUpdateInstaller + ? CheckState.Checked + : CheckState.Unchecked; // cache _localStorage.TbImageCacheLocation.Text = Variables.ImageCachePath; @@ -359,7 +451,9 @@ private void LoadSettings() _localStorage.NumWebViewRetention.Value = Variables.AppSettings.WebViewCacheRetentionDays; // logging - _logging.CbExtendedLogging.CheckState = SettingsManager.GetExtendedLoggingSetting() ? CheckState.Checked : CheckState.Unchecked; + _logging.CbExtendedLogging.CheckState = SettingsManager.GetExtendedLoggingSetting() + ? CheckState.Checked + : CheckState.Unchecked; // external tools _externalTools.TbExternalBrowserName.Text = Variables.AppSettings.BrowserName; @@ -369,20 +463,31 @@ private void LoadSettings() _externalTools.TbExternalExecutorBinary.Text = Variables.AppSettings.CustomExecutorBinary; // mediaplayer - _mediaPlayer.CbEnableMediaPlayer.CheckState = Variables.AppSettings.MediaPlayerEnabled ? CheckState.Checked : CheckState.Unchecked; + _mediaPlayer.CbEnableMediaPlayer.CheckState = Variables.AppSettings.MediaPlayerEnabled + ? CheckState.Checked + : CheckState.Unchecked; // tray icon - _trayIcon.CbUseModernIcon.CheckState = Variables.AppSettings.TrayIconUseModern ? CheckState.Checked : CheckState.Unchecked; - _trayIcon.CbDefaultMenu.CheckState = Variables.AppSettings.TrayIconShowDefaultMenu ? CheckState.Checked : CheckState.Unchecked; - _trayIcon.CbShowWebView.CheckState = Variables.AppSettings.TrayIconShowWebView ? CheckState.Checked : CheckState.Unchecked; + _trayIcon.CbUseModernIcon.CheckState = + Variables.AppSettings.TrayIconUseModern ? CheckState.Checked : CheckState.Unchecked; + _trayIcon.CbDefaultMenu.CheckState = Variables.AppSettings.TrayIconShowDefaultMenu + ? CheckState.Checked + : CheckState.Unchecked; + _trayIcon.CbShowWebView.CheckState = + Variables.AppSettings.TrayIconShowWebView ? CheckState.Checked : CheckState.Unchecked; _trayIcon.NumWebViewWidth.Value = Variables.AppSettings.TrayIconWebViewWidth; _trayIcon.NumWebViewHeight.Value = Variables.AppSettings.TrayIconWebViewHeight; - _trayIcon.SelectedScreen = Variables.AppSettings.TrayIconWebViewScreen; + _trayIcon.SelectedScreen = Variables.AppSettings.TrayIconWebViewScreen; _trayIcon.TbWebViewUrl.Text = Variables.AppSettings.TrayIconWebViewUrl; - _trayIcon.CbWebViewKeepLoaded.CheckState = Variables.AppSettings.TrayIconWebViewBackgroundLoading ? CheckState.Checked : CheckState.Unchecked; - _trayIcon.CbWebViewShowMenuOnLeftClick.CheckState = Variables.AppSettings.TrayIconWebViewShowMenuOnLeftClick ? CheckState.Checked : CheckState.Unchecked; + _trayIcon.CbWebViewKeepLoaded.CheckState = Variables.AppSettings.TrayIconWebViewBackgroundLoading + ? CheckState.Checked + : CheckState.Unchecked; + _trayIcon.CbWebViewShowMenuOnLeftClick.CheckState = Variables.AppSettings.TrayIconWebViewShowMenuOnLeftClick + ? CheckState.Checked + : CheckState.Unchecked; - _nfc.CbEnableNfc.CheckState = Variables.AppSettings.NfcScanningEnabled ? CheckState.Checked : CheckState.Unchecked; + _nfc.CbEnableNfc.CheckState = + Variables.AppSettings.NfcScanningEnabled ? CheckState.Checked : CheckState.Unchecked; // done _initializing = false; @@ -394,10 +499,13 @@ private void LoadSettings() private async Task StoreSettingsAsync() { // general - var deviceName = string.IsNullOrEmpty(_general.TbDeviceName.Text) ? SharedHelperFunctions.GetSafeDeviceName() : _general.TbDeviceName.Text; + var deviceName = string.IsNullOrEmpty(_general.TbDeviceName.Text) + ? SharedHelperFunctions.GetSafeDeviceName() + : _general.TbDeviceName.Text; Variables.AppSettings.DeviceName = deviceName; Variables.AppSettings.SanitizeName = _general.CbEnableDeviceNameSanitation.CheckState == CheckState.Checked; - Variables.AppSettings.EnableStateNotifications = _general.CbEnableStateNotifications.CheckState == CheckState.Checked; + Variables.AppSettings.EnableStateNotifications = + _general.CbEnableStateNotifications.CheckState == CheckState.Checked; var uiLanguage = Variables.SupportedUILanguages.Find(x => x.DisplayName == _general.CbLanguage.Text); Variables.AppSettings.InterfaceLanguage = uiLanguage?.Name ?? "en"; @@ -409,32 +517,38 @@ private async Task StoreSettingsAsync() Variables.AppSettings.LocalApiEnabled = _localApi.CbLocalApiActive.CheckState == CheckState.Checked; // notifications - Variables.AppSettings.NotificationsEnabled = _notifications.CbAcceptNotifications.CheckState == CheckState.Checked; - Variables.AppSettings.NotificationsIgnoreImageCertificateErrors = _notifications.CbNotificationsIgnoreImageCertErrors.CheckState == CheckState.Checked; - Variables.AppSettings.NotificationsOpenActionUri = _notifications.CbNotificationsOpenActionUri.CheckState == CheckState.Checked; + Variables.AppSettings.NotificationsEnabled = + _notifications.CbAcceptNotifications.CheckState == CheckState.Checked; + Variables.AppSettings.NotificationsIgnoreImageCertificateErrors = + _notifications.CbNotificationsIgnoreImageCertErrors.CheckState == CheckState.Checked; + Variables.AppSettings.NotificationsOpenActionUri = + _notifications.CbNotificationsOpenActionUri.CheckState == CheckState.Checked; // hass settings Variables.AppSettings.HassUri = _homeAssistantApi.TbHassIp.Text; Variables.AppSettings.HassToken = _homeAssistantApi.TbHassApiToken.Text; Variables.AppSettings.HassClientCertificate = _homeAssistantApi.TbHassClientCertificate.Text; - Variables.AppSettings.HassAutoClientCertificate = _homeAssistantApi.CbHassAutoClientCertificate.CheckState == CheckState.Checked; - Variables.AppSettings.HassAllowUntrustedCertificates = _homeAssistantApi.CbHassAllowUntrustedCertificates.CheckState == CheckState.Checked; + Variables.AppSettings.HassAutoClientCertificate = + _homeAssistantApi.CbHassAutoClientCertificate.CheckState == CheckState.Checked; + Variables.AppSettings.HassAllowUntrustedCertificates = + _homeAssistantApi.CbHassAllowUntrustedCertificates.CheckState == CheckState.Checked; // hotkey config - Variables.AppSettings.QuickActionsHotKeyEnabled = _hotKey.CbEnableQuickActionsHotkey.CheckState == CheckState.Checked; + Variables.AppSettings.QuickActionsHotKeyEnabled = + _hotKey.CbEnableQuickActionsHotkey.CheckState == CheckState.Checked; if (Variables.AppSettings.QuickActionsHotKeyEnabled) { // hotkey enabled, store and activate - Variables.QuickActionsHotKey = new Hotkey(_hotKey.TbQuickActionsHotkey.Text); + Variables.QuickActionsHotKey = _hotKey.TbQuickActionsHotkey.Text; Variables.AppSettings.QuickActionsHotKey = Variables.QuickActionsHotKey.ToString(); - Variables.HotKeyManager.QuickActionsHotKeyChanged(_previousHotkey); + Variables.InternalHotKeyManager.QuickActionsHotKeyChanged(_previousHotkey); } else { // hotkey disabled, remove and deactivate Variables.QuickActionsHotKey = null; Variables.AppSettings.QuickActionsHotKey = string.Empty; - Variables.HotKeyManager.QuickActionsHotKeyChanged(_previousHotkey, false); + Variables.InternalHotKeyManager.QuickActionsHotKeyChanged(_previousHotkey, false); } // mqtt @@ -448,7 +562,8 @@ private async Task StoreSettingsAsync() Variables.AppSettings.MqttClientId = _mqtt.TbMqttClientId.Text; Variables.AppSettings.MqttRootCertificate = _mqtt.TbMqttRootCertificate.Text; Variables.AppSettings.MqttClientCertificate = _mqtt.TbMqttClientCertificate.Text; - Variables.AppSettings.MqttAllowUntrustedCertificates = _mqtt.CbAllowUntrustedCertificates.CheckState == CheckState.Checked; + Variables.AppSettings.MqttAllowUntrustedCertificates = + _mqtt.CbAllowUntrustedCertificates.CheckState == CheckState.Checked; Variables.AppSettings.MqttUseRetainFlag = _mqtt.CbUseRetainFlag.CheckState == CheckState.Checked; Variables.AppSettings.MqttUseWebSocket = _mqtt.CbUseWebSocket.CheckState == CheckState.Checked; Variables.AppSettings.MqttIgnoreGracePeriod = _mqtt.CbIgnoreGracePeriod.CheckState == CheckState.Checked; @@ -459,7 +574,8 @@ private async Task StoreSettingsAsync() // updates Variables.AppSettings.CheckForUpdates = _updates.CbUpdates.CheckState == CheckState.Checked; Variables.AppSettings.ShowBetaUpdates = _updates.CbBetaUpdates.CheckState == CheckState.Checked; - Variables.AppSettings.EnableExecuteUpdateInstaller = _updates.CbExecuteUpdater.CheckState == CheckState.Checked; + Variables.AppSettings.EnableExecuteUpdateInstaller = + _updates.CbExecuteUpdater.CheckState == CheckState.Checked; // cache Variables.AppSettings.ImageCacheRetentionDays = (int)_localStorage.NumImageRetention.Value; @@ -480,7 +596,8 @@ private async Task StoreSettingsAsync() AgentSharedBase.SetCustomExecutorBinary(Variables.AppSettings.CustomExecutorBinary); // mediaplayer - Variables.AppSettings.MediaPlayerEnabled = _mediaPlayer.CbEnableMediaPlayer.CheckState == CheckState.Checked; + Variables.AppSettings.MediaPlayerEnabled = + _mediaPlayer.CbEnableMediaPlayer.CheckState == CheckState.Checked; // tray icon Variables.AppSettings.TrayIconUseModern = _trayIcon.CbUseModernIcon.CheckState == CheckState.Checked; @@ -490,12 +607,16 @@ private async Task StoreSettingsAsync() Variables.AppSettings.TrayIconWebViewHeight = (int)_trayIcon.NumWebViewHeight.Value; Variables.AppSettings.TrayIconWebViewScreen = _trayIcon.NumWebViewScreen.SelectedIndex; Variables.AppSettings.TrayIconWebViewUrl = _trayIcon.TbWebViewUrl.Text; - Variables.AppSettings.TrayIconWebViewBackgroundLoading = _trayIcon.CbWebViewKeepLoaded.CheckState == CheckState.Checked; - Variables.AppSettings.TrayIconWebViewShowMenuOnLeftClick = _trayIcon.CbWebViewShowMenuOnLeftClick.CheckState == CheckState.Checked; + Variables.AppSettings.TrayIconWebViewBackgroundLoading = + _trayIcon.CbWebViewKeepLoaded.CheckState == CheckState.Checked; + Variables.AppSettings.TrayIconWebViewShowMenuOnLeftClick = + _trayIcon.CbWebViewShowMenuOnLeftClick.CheckState == CheckState.Checked; // nfc Variables.AppSettings.NfcScanningEnabled = _nfc.CbEnableNfc.CheckState == CheckState.Checked; - Variables.AppSettings.NfcSelectedScanner = _nfc.CbNfcScanner.SelectedItem == null ? string.Empty : _nfc.CbNfcScanner.SelectedItem.ToString(); + Variables.AppSettings.NfcSelectedScanner = _nfc.CbNfcScanner.SelectedItem == null + ? string.Empty + : _nfc.CbNfcScanner.SelectedItem.ToString(); // save to file SettingsManager.StoreAppSettings(); @@ -532,7 +653,7 @@ private void Configuration_KeyUp(object sender, KeyEventArgs e) private void BtnClearHotKey_Click(object sender, EventArgs e) { - _hotKey.TbQuickActionsHotkey.Text = _hotkeySelector.EmptyHotkeyText; + _hotKey.TbQuickActionsHotkey.Text = string.Empty; } private void Configuration_ResizeEnd(object sender, EventArgs e) @@ -571,4 +692,4 @@ private void CbHassAutoClientCertificate_CheckedChanged(object sender, EventArgs private void BtnClose_Click(object sender, EventArgs e) => Close(); } -} +} \ No newline at end of file diff --git a/src/HASS.Agent/HASS.Agent/Forms/Main.cs b/src/HASS.Agent/HASS.Agent/Forms/Main.cs index e79059ec..5bde6719 100644 --- a/src/HASS.Agent/HASS.Agent/Forms/Main.cs +++ b/src/HASS.Agent/HASS.Agent/Forms/Main.cs @@ -24,11 +24,12 @@ using Serilog; using Syncfusion.Windows.Forms; using WindowsDesktop; -using WK.Libraries.HotkeyListenerNS; using NativeMethods = HASS.Agent.Functions.NativeMethods; using QuickActionsConfig = HASS.Agent.Forms.QuickActions.QuickActionsConfig; using Task = System.Threading.Tasks.Task; using Microsoft.Win32; +using NHotkey; +using NHotkey.WindowsForms; namespace HASS.Agent.Forms { @@ -64,11 +65,11 @@ private async void Main_Load(object sender, EventArgs e) // exception handlers Application.ThreadException += Application_ThreadException; AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; - } - - if (SharedHelperFunctions.RunningElevated()) - { - Log.Warning("[MAIN] Running with elevated privileges, this might cause issues for example with notifications!"); + } + + if (SharedHelperFunctions.RunningElevated()) + { + Log.Warning("[MAIN] Running with elevated privileges, this might cause issues for example with notifications!"); } // catch all key presses @@ -88,7 +89,7 @@ private async void Main_Load(object sender, EventArgs e) SetMqttStatus(ComponentStatus.Loading); // create a hotkey listener - Variables.HotKeyListener = new HotkeyListener(); + Variables.HotKeyListener = HotkeyManager.Current; // check for dpi scaling CheckDpiScalingFactor(); @@ -124,7 +125,7 @@ private async void Main_Load(object sender, EventArgs e) // prepare the tray icon config SystemEvents.DisplaySettingsChanged += (s, a) => RefreshTrayIcon(); - ProcessTrayIcon(); + ProcessTrayIcon(); InitializeHotkeys(); @@ -304,10 +305,10 @@ private static void CurrentDomain_UnhandledException(object sender, UnhandledExc private void InitializeHotkeys() { // prepare listener - Variables.HotKeyListener.HotkeyPressed += HotkeyListener_HotkeyPressed; + Variables.InternalHotKeyManager.HotkeyActivated += HotkeyListener_HotkeyPressed; // bind quick actions hotkey (if configured) - Variables.HotKeyManager.InitializeQuickActionsHotKeys(); + Variables.InternalHotKeyManager.InitializeQuickActionsHotKeys(); } /// @@ -317,10 +318,10 @@ private void InitializeHotkeys() /// private void HotkeyListener_HotkeyPressed(object sender, HotkeyEventArgs e) { - if (e.Hotkey == Variables.QuickActionsHotKey) + if (e.Name == Variables.QuickActionsHotKey) ShowQuickActions(); else - HotKeyManager.ProcessQuickActionHotKey(e.Hotkey.ToString()); + InternalHotKeyManager.ProcessQuickActionHotKey(e.Name); } /// diff --git a/src/HASS.Agent/HASS.Agent/Forms/QuickActions/QuickActionsConfig.cs b/src/HASS.Agent/HASS.Agent/Forms/QuickActions/QuickActionsConfig.cs index 9a8285c4..7c86317c 100644 --- a/src/HASS.Agent/HASS.Agent/Forms/QuickActions/QuickActionsConfig.cs +++ b/src/HASS.Agent/HASS.Agent/Forms/QuickActions/QuickActionsConfig.cs @@ -163,7 +163,7 @@ private void BtnStore_Click(object sender, EventArgs e) StoredQuickActions.Store(); // reload hotkey bindings - Variables.HotKeyManager.ReloadQuickActionsHotKeys(); + Variables.InternalHotKeyManager.ReloadQuickActionsHotKeys(); // done Close(); diff --git a/src/HASS.Agent/HASS.Agent/Forms/QuickActions/QuickActionsMod.cs b/src/HASS.Agent/HASS.Agent/Forms/QuickActions/QuickActionsMod.cs index e6dcff81..3b4008e0 100644 --- a/src/HASS.Agent/HASS.Agent/Forms/QuickActions/QuickActionsMod.cs +++ b/src/HASS.Agent/HASS.Agent/Forms/QuickActions/QuickActionsMod.cs @@ -6,17 +6,18 @@ using HASS.Agent.Shared.Enums; using HASS.Agent.Shared.Functions; using Syncfusion.Windows.Forms; -using WK.Libraries.HotkeyListenerNS; namespace HASS.Agent.Forms.QuickActions { public partial class QuickActionsMod : MetroForm { - private readonly HotkeySelector _hotkeySelector = new(); internal readonly QuickAction QuickAction; private readonly Dictionary _hassDomainEntityTypes = new(); private readonly Dictionary _hassActionEntityTypes = new(); + + private Keys _key = Keys.None; + private Keys _modifiers = Keys.None; public QuickActionsMod(QuickAction quickAction) { @@ -90,15 +91,17 @@ private async void QuickActionsMod_Load(object sender, EventArgs e) } LvDomain.EndUpdate(); + TbHotkey.ReadOnly = true; + TbHotkey.KeyDown += TbQuickActionsHotkey_KeyDown; + // load or new quickaction? if (QuickAction.Id == Guid.Empty) { // new quickaction Text = Languages.QuickActionsMod_Title_New; QuickAction.Id = Guid.NewGuid(); - - _hotkeySelector.Enable(TbHotkey); - TbHotkey.Text = _hotkeySelector.EmptyHotkeyText; + + TbHotkey.Text = string.Empty; LvDomain.Items[0].Selected = true; if (CbEntity.Items.Count > 0) CbEntity.SelectedIndex = 0; @@ -211,12 +214,7 @@ private void LoadQuickAction() if (!string.IsNullOrWhiteSpace(TbDescription.Text)) TbDescription.SelectionStart = TbDescription.Text.Length; // load the hotkey - if (!string.IsNullOrEmpty(QuickAction.HotKey)) _hotkeySelector.Enable(TbHotkey, new Hotkey(QuickAction.HotKey)); - else - { - _hotkeySelector.Enable(TbHotkey); - TbHotkey.Text = _hotkeySelector.EmptyHotkeyText; - } + TbHotkey.Text = !string.IsNullOrEmpty(QuickAction.HotKey) ? QuickAction.HotKey : string.Empty; } /// @@ -426,16 +424,13 @@ private void CbEntity_SelectedIndexChanged(object sender, EventArgs e) private void QuickActionsMod_FormClosing(object sender, FormClosingEventArgs e) { - // stop and dispose selector - _hotkeySelector?.Disable(TbHotkey); - _hotkeySelector?.Dispose(); + // clean selector + TbHotkey.KeyDown -= TbQuickActionsHotkey_KeyDown; } private void TbHotkey_TextChanged(object sender, EventArgs e) { - if (string.IsNullOrWhiteSpace(TbHotkey.Text) - || TbHotkey.Text == _hotkeySelector?.EmptyHotkeyText - || TbHotkey.Text == _hotkeySelector?.InvalidHotkeyText) + if (string.IsNullOrWhiteSpace(TbHotkey.Text)) { CbEnableHotkey.CheckState = CheckState.Unchecked; return; @@ -481,5 +476,53 @@ private void QuickActionsMod_Layout(object sender, LayoutEventArgs e) // hide the pesky horizontal scrollbar ListViewTheme.ShowScrollBar(LvDomain.Handle, ListViewTheme.SB_HORZ, false); } + + private void TbQuickActionsHotkey_KeyDown(object sender, KeyEventArgs e) + { + e.SuppressKeyPress = true; + + var key = e.KeyCode; + + if (key is Keys.LControlKey or Keys.RControlKey + or Keys.LShiftKey or Keys.RShiftKey + or Keys.LWin or Keys.RWin + or Keys.Alt) + { + key = Keys.None; + } + + if (key == Keys.Escape) + { + _key = Keys.None; + _modifiers = Keys.None; + TbHotkey.Text = string.Empty; + + return; + } + + _key = key; + TbHotkey.Text = FormatHotkey(_key, e.Modifiers); + } + + private string FormatHotkey(Keys key, Keys modifiers) + { + var parts = new List(); + if ((modifiers & Keys.Shift) != 0) + { + parts.Add(nameof(Keys.Shift)); + } + + if ((modifiers & Keys.Control) != 0) + { + parts.Add(nameof(Keys.Control)); + } + + if ((modifiers & Keys.Alt) != 0) + { + parts.Add(nameof(Keys.Alt)); + } + + return parts.Count > 0 ? string.Join(", ", parts) + " + " + key : key.ToString(); + } } } diff --git a/src/HASS.Agent/HASS.Agent/Functions/HelperFunctions.cs b/src/HASS.Agent/HASS.Agent/Functions/HelperFunctions.cs index 72fbb27f..30796038 100644 --- a/src/HASS.Agent/HASS.Agent/Functions/HelperFunctions.cs +++ b/src/HASS.Agent/HASS.Agent/Functions/HelperFunctions.cs @@ -172,8 +172,8 @@ internal static async Task ShutdownAsync(TimeSpan waitBeforeClosing) // stop hotkey Variables.MainForm?.Invoke(new MethodInvoker(delegate { - Variables.HotKeyListener?.RemoveAll(); - Variables.HotKeyListener?.Dispose(); + Variables.InternalHotKeyManager?.ReloadQuickActionsHotKeys(); + //Variables.HotKeyListener?.Dispose(); })); // stop bt listener diff --git a/src/HASS.Agent/HASS.Agent/HASS.Agent.csproj b/src/HASS.Agent/HASS.Agent/HASS.Agent.csproj index 42f43703..8d65e1eb 100644 --- a/src/HASS.Agent/HASS.Agent/HASS.Agent.csproj +++ b/src/HASS.Agent/HASS.Agent/HASS.Agent.csproj @@ -72,6 +72,7 @@ + @@ -93,9 +94,6 @@ Libraries\HADotNet.Core.dll - - Libraries\HotkeyListener.dll - diff --git a/src/HASS.Agent/HASS.Agent/Libraries/HotkeyListener.dll b/src/HASS.Agent/HASS.Agent/Libraries/HotkeyListener.dll deleted file mode 100644 index 6907c33c43bd262abd0ebfee0519de5fa9b04486..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 448000 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 UatJM`(o^{_>WRhwzxKfY0`mqRJOBUy diff --git a/src/HASS.Agent/HASS.Agent/Managers/HotKeyManager.cs b/src/HASS.Agent/HASS.Agent/Managers/InternalHotKeyManager.cs similarity index 51% rename from src/HASS.Agent/HASS.Agent/Managers/HotKeyManager.cs rename to src/HASS.Agent/HASS.Agent/Managers/InternalHotKeyManager.cs index b2d9b2cb..9db0495c 100644 --- a/src/HASS.Agent/HASS.Agent/Managers/HotKeyManager.cs +++ b/src/HASS.Agent/HASS.Agent/Managers/InternalHotKeyManager.cs @@ -1,13 +1,15 @@ using HASS.Agent.Commands; using HASS.Agent.HomeAssistant; using HASS.Agent.Shared.Enums; +using NHotkey; using Serilog; -using WK.Libraries.HotkeyListenerNS; namespace HASS.Agent.Managers { - internal class HotKeyManager + internal class InternalHotKeyManager { + internal event EventHandler HotkeyActivated; + /// /// Initializes the quickaction hotkeys /// @@ -31,7 +33,7 @@ internal void ReloadQuickActionsHotKeys() Variables.MainForm?.BeginInvoke(new MethodInvoker(delegate { // remove all bindings - Variables.HotKeyListener?.RemoveAll(); + RemoveAllRegisteredHotkeys(); // reload InitializeQuickActionsHotKeys(); @@ -80,38 +82,56 @@ internal static void ProcessQuickActionHotKey(string hotkey) } } - private static void InitializeGlobalQuickActionsHotKey() + internal void RemoveAllRegisteredHotkeys() + { + foreach (var quickAction in Variables.QuickActions) + { + Variables.HotKeyListener?.Remove(quickAction.HotKey); + } + } + + private void InitializeGlobalQuickActionsHotKey() { Variables.MainForm?.BeginInvoke(new MethodInvoker(delegate { - // check if the quick action hotkey's active - if (!Variables.AppSettings.QuickActionsHotKeyEnabled) return; - - // check if it's configured - if (Variables.QuickActionsHotKey == null || Variables.QuickActionsHotKey.ToString() == "None") return; + // check if it's enabled and configured + if (!Variables.AppSettings.QuickActionsHotKeyEnabled || string.IsNullOrWhiteSpace(Variables.QuickActionsHotKey) || Variables.QuickActionsHotKey == "None") + { + return; + } // all good, bind - Variables.HotKeyListener?.Add(Variables.QuickActionsHotKey); - - Log.Information("[HOTKEY] Completed bind for global quickaction hotkey"); + var globalHotkey = HotkeyFromString(Variables.QuickActionsHotKey); + if (globalHotkey.Item1 != Keys.None) + { + Variables.HotKeyListener?.AddOrReplace(Variables.QuickActionsHotKey, globalHotkey.Item1 | globalHotkey.Item2, OnHotkeyActivated); + Log.Information("[HOTKEY] Completed bind for global quickaction hotkey"); + } + else + { + Log.Warning("[HOTKEY] Could not bind for global quickaction hotkey"); + } })); } - private static void InitializeIndividualQuickActionsHotKeys() + private void InitializeIndividualQuickActionsHotKeys() { Variables.MainForm?.BeginInvoke(new MethodInvoker(delegate { var count = 0; - foreach (var quickAcion in Variables.QuickActions.Where(x => x.HotKeyEnabled && !string.IsNullOrWhiteSpace(x.HotKey))) + foreach (var quickAcion in Variables.QuickActions.Where(x => + x.HotKeyEnabled && !string.IsNullOrWhiteSpace(x.HotKey))) { try { - Variables.HotKeyListener?.Add(new Hotkey(quickAcion.HotKey)); + var hotkey = HotkeyFromString(quickAcion.HotKey); + Variables.HotKeyListener?.AddOrReplace(quickAcion.HotKey, hotkey.Item1 | hotkey.Item2, OnHotkeyActivated); count++; } catch (Exception ex) { - Log.Fatal(ex, "[HOTKEYS] Unable to bind individual quickaction hotkey '{hotkey}': {msg}", quickAcion.HotKey, ex.Message); + Log.Fatal(ex, "[HOTKEYS] Unable to bind individual quickaction hotkey '{hotkey}': {msg}", + quickAcion.HotKey, ex.Message); } } @@ -123,15 +143,56 @@ private static void InitializeIndividualQuickActionsHotKeys() /// /// Process a changed quickactions hotkey /// - /// + /// /// - internal void QuickActionsHotKeyChanged(Hotkey previousKey, bool register = true) + internal void QuickActionsHotKeyChanged(string previousHotkey, bool register = true) { Variables.MainForm?.BeginInvoke(new MethodInvoker(delegate { - Variables.HotKeyListener?.Remove(previousKey); - if (register && Variables.QuickActionsHotKey != null && Variables.QuickActionsHotKey.KeyCode != Keys.None) Variables.HotKeyListener?.Add(Variables.QuickActionsHotKey); + Variables.HotKeyListener?.Remove(previousHotkey); + if (!register || Variables.QuickActionsHotKey == null + || !string.IsNullOrWhiteSpace(Variables.QuickActionsHotKey)) + { + return; + } + + var parsedHotkey = HotkeyFromString(previousHotkey); + if (parsedHotkey.Item1 != Keys.None) + { + Variables.HotKeyListener?.AddOrReplace(Variables.QuickActionsHotKey, + parsedHotkey.Item1 | parsedHotkey.Item2, OnHotkeyActivated); + } })); } + + private void OnHotkeyActivated(object sender, HotkeyEventArgs e) + { + HotkeyActivated?.Invoke(sender, e); + } + + private static (Keys, Keys) HotkeyFromString(string stringHotkey) + { + if (string.IsNullOrWhiteSpace(stringHotkey)) + { + return (Keys.None, Keys.None); + } + + var parts = stringHotkey.Split("+", 2, StringSplitOptions.TrimEntries); + var modifiersString = parts.Length == 2 ? parts[0] : string.Empty; + var keyString = parts.Length == 2 ? parts[1] : parts[0]; + + var modifiers = Keys.None; + foreach (var modKey in modifiersString.Split(',', StringSplitOptions.RemoveEmptyEntries)) + { + if (!Enum.TryParse(modKey, out var parsedModifiers)) + { + continue; + } + + modifiers |= parsedModifiers; + } + + return Enum.TryParse(keyString, out var parsedKey) ? (parsedKey, modifiers) : (Keys.None, Keys.None); + } } -} +} \ No newline at end of file diff --git a/src/HASS.Agent/HASS.Agent/Settings/SettingsManager.cs b/src/HASS.Agent/HASS.Agent/Settings/SettingsManager.cs index 01c525ac..546f2c31 100644 --- a/src/HASS.Agent/HASS.Agent/Settings/SettingsManager.cs +++ b/src/HASS.Agent/HASS.Agent/Settings/SettingsManager.cs @@ -14,7 +14,6 @@ using Newtonsoft.Json; using Serilog; using Syncfusion.Windows.Forms; -using WK.Libraries.HotkeyListenerNS; namespace HASS.Agent.Settings { @@ -139,7 +138,7 @@ private static bool LoadAppSettings() AgentSharedBase.SetCustomExecutorBinary(Variables.AppSettings.CustomExecutorBinary); // load the hotkey - Variables.QuickActionsHotKey = string.IsNullOrEmpty(Variables.AppSettings.QuickActionsHotKey) ? null : HotkeyListener.Convert(Variables.AppSettings.QuickActionsHotKey); + Variables.QuickActionsHotKey = string.IsNullOrWhiteSpace(Variables.AppSettings.QuickActionsHotKey) ? string.Empty : Variables.AppSettings.QuickActionsHotKey; // done Log.Information("[SETTINGS] Configuration loaded"); diff --git a/src/HASS.Agent/HASS.Agent/Variables.cs b/src/HASS.Agent/HASS.Agent/Variables.cs index f2d9e850..e38a904d 100644 --- a/src/HASS.Agent/HASS.Agent/Variables.cs +++ b/src/HASS.Agent/HASS.Agent/Variables.cs @@ -18,7 +18,7 @@ using MQTTnet; using Serilog.Core; using Microsoft.Web.WebView2.Core; -using WK.Libraries.HotkeyListenerNS; +using NHotkey.WindowsForms; namespace HASS.Agent { @@ -51,9 +51,9 @@ public static class Variables /// internal static Main MainForm { get; set; } internal static HttpClient HttpClient { get; set; } = new(); - internal static Hotkey QuickActionsHotKey { get; set; } = new(Keys.Control | Keys.Alt, Keys.Q); - internal static HotKeyManager HotKeyManager { get; } = new(); - internal static HotkeyListener HotKeyListener { get; set; } + internal static string QuickActionsHotKey { get; set; } = "Control, Alt + Q"; + internal static InternalHotKeyManager InternalHotKeyManager { get; } = new(); + internal static HotkeyManager HotKeyListener { get; set; } internal static Random Rnd { get; } = new(); internal static Font DefaultFont { get; } = new("Segoe UI", 10F, FontStyle.Regular, GraphicsUnit.Point); internal static WebView TrayIconWebView { get; set; } = null; From b2bd836cecd429e069888b324ffb40566b35ee38 Mon Sep 17 00:00:00 2001 From: amadeo-alex <68441479+amadeo-alex@users.noreply.github.com> Date: Thu, 28 May 2026 12:46:44 +0200 Subject: [PATCH 10/13] Fix: version downgrade for development-2.2.1 (#450) --- src/HASS.Agent.Installer/InstallerScript-Service-x86.iss | 2 +- src/HASS.Agent.Installer/InstallerScript-Service.iss | 2 +- src/HASS.Agent.Installer/InstallerScript-x86.iss | 2 +- src/HASS.Agent.Installer/InstallerScript.iss | 2 +- .../HASS.Agent.Satellite.Service.csproj | 6 +++--- src/HASS.Agent/HASS.Agent.Shared/HASS.Agent.Shared.csproj | 6 +++--- src/HASS.Agent/HASS.Agent/HASS.Agent.csproj | 6 +++--- 7 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/HASS.Agent.Installer/InstallerScript-Service-x86.iss b/src/HASS.Agent.Installer/InstallerScript-Service-x86.iss index d34a5ec6..9b632fc5 100644 --- a/src/HASS.Agent.Installer/InstallerScript-Service-x86.iss +++ b/src/HASS.Agent.Installer/InstallerScript-Service-x86.iss @@ -9,7 +9,7 @@ ; Standard installation constants #define MyAppName "HASS.Agent Satellite Service" -#define MyAppVersion "2.2.1" +#define MyAppVersion "2.2.0" #define MyAppPublisher "HASS.Agent Team" #define MyAppURL "https://hass-agent.io" #define MyAppExeName "HASS.Agent.Satellite.Service.exe" diff --git a/src/HASS.Agent.Installer/InstallerScript-Service.iss b/src/HASS.Agent.Installer/InstallerScript-Service.iss index f9c44adb..f2825143 100644 --- a/src/HASS.Agent.Installer/InstallerScript-Service.iss +++ b/src/HASS.Agent.Installer/InstallerScript-Service.iss @@ -9,7 +9,7 @@ ; Standard installation constants #define MyAppName "HASS.Agent Satellite Service" -#define MyAppVersion "2.2.1" +#define MyAppVersion "2.2.0" #define MyAppPublisher "HASS.Agent Team" #define MyAppURL "https://hass-agent.io" #define MyAppExeName "HASS.Agent.Satellite.Service.exe" diff --git a/src/HASS.Agent.Installer/InstallerScript-x86.iss b/src/HASS.Agent.Installer/InstallerScript-x86.iss index 75927faa..62f11d9e 100644 --- a/src/HASS.Agent.Installer/InstallerScript-x86.iss +++ b/src/HASS.Agent.Installer/InstallerScript-x86.iss @@ -9,7 +9,7 @@ ; Standard installation constants #define MyAppName "HASS.Agent" -#define MyAppVersion "2.2.1" +#define MyAppVersion "2.2.0" #define MyAppPublisher "HASS.Agent Team" #define MyAppURL "https://hass-agent.io" #define MyAppExeName "HASS.Agent.exe" diff --git a/src/HASS.Agent.Installer/InstallerScript.iss b/src/HASS.Agent.Installer/InstallerScript.iss index 335f0338..4519dba4 100644 --- a/src/HASS.Agent.Installer/InstallerScript.iss +++ b/src/HASS.Agent.Installer/InstallerScript.iss @@ -9,7 +9,7 @@ ; Standard installation constants #define MyAppName "HASS.Agent" -#define MyAppVersion "2.2.1" +#define MyAppVersion "2.2.0" #define MyAppPublisher "HASS.Agent Team" #define MyAppURL "https://hass-agent.io" #define MyAppExeName "HASS.Agent.exe" diff --git a/src/HASS.Agent/HASS.Agent.Satellite.Service/HASS.Agent.Satellite.Service.csproj b/src/HASS.Agent/HASS.Agent.Satellite.Service/HASS.Agent.Satellite.Service.csproj index 4464d5b6..1e3dfd54 100644 --- a/src/HASS.Agent/HASS.Agent.Satellite.Service/HASS.Agent.Satellite.Service.csproj +++ b/src/HASS.Agent/HASS.Agent.Satellite.Service/HASS.Agent.Satellite.Service.csproj @@ -8,7 +8,7 @@ dotnet-HASSAgentSatelliteService-6E4FA50A-3AC9-4E66-8671-9FAB92372154 anycpu x64;x86;AnyCPU - 2.2.1 + 2.2.0 HASS.Agent Team HASS.Agent Satellite Service HASS.Agent.Satellite.Service @@ -17,9 +17,9 @@ https://github.com/hass-agent/HASS.Agent https://github.com/hass-agent/HASS.Agent hass.png - 2.2.1 + 2.2.0 hass.ico - 2.2.1 + 2.2.0 10.0.17763.0 false diff --git a/src/HASS.Agent/HASS.Agent.Shared/HASS.Agent.Shared.csproj b/src/HASS.Agent/HASS.Agent.Shared/HASS.Agent.Shared.csproj index 31336c84..0fae9b41 100644 --- a/src/HASS.Agent/HASS.Agent.Shared/HASS.Agent.Shared.csproj +++ b/src/HASS.Agent/HASS.Agent.Shared/HASS.Agent.Shared.csproj @@ -10,9 +10,9 @@ Shared functions and models for the HASS.Agent platform. https://github.com/hass-agent/HASS.Agent https://github.com/hass-agent/HASS.Agent - 2.2.1 - 2.2.1 - 2.2.1 + 2.2.0 + 2.2.0 + 2.2.0 logo_128.png True hassagent.ico diff --git a/src/HASS.Agent/HASS.Agent/HASS.Agent.csproj b/src/HASS.Agent/HASS.Agent/HASS.Agent.csproj index 8d65e1eb..c5516e0c 100644 --- a/src/HASS.Agent/HASS.Agent/HASS.Agent.csproj +++ b/src/HASS.Agent/HASS.Agent/HASS.Agent.csproj @@ -17,7 +17,7 @@ anycpu x64;x86;AnyCPU full - 2.2.1 + 2.2.0 HASS.Agent Team HASS.Agent Team Windows-based client for Home Assistant. Provides notifications, quick actions, commands, sensors and more. @@ -27,8 +27,8 @@ https://github.com/hass-agent/HASS.Agent MIT app.manifest - 2.2.1 - 2.2.1 + 2.2.0 + 2.2.0 HASS.Agent None true From dbfc92b74c7ce1767a75fb659b1ff1ab9a38aa66 Mon Sep 17 00:00:00 2001 From: amadeo-alex <68441479+amadeo-alex@users.noreply.github.com> Date: Thu, 28 May 2026 13:33:07 +0200 Subject: [PATCH 11/13] Fix: Baked in HADot.Net library (#451) --- src/HASS.Agent/HASS.Agent/HASS.Agent.csproj | 7 +- .../HASS.Agent/Libraries/HADotNet.Core.dll | Bin 78336 -> 0 bytes .../HASS.Agent/Libraries/HADotNet.Core.xml | 1729 ----------------- 3 files changed, 1 insertion(+), 1735 deletions(-) delete mode 100644 src/HASS.Agent/HASS.Agent/Libraries/HADotNet.Core.dll delete mode 100644 src/HASS.Agent/HASS.Agent/Libraries/HADotNet.Core.xml diff --git a/src/HASS.Agent/HASS.Agent/HASS.Agent.csproj b/src/HASS.Agent/HASS.Agent/HASS.Agent.csproj index c5516e0c..ae1c60a7 100644 --- a/src/HASS.Agent/HASS.Agent/HASS.Agent.csproj +++ b/src/HASS.Agent/HASS.Agent/HASS.Agent.csproj @@ -55,6 +55,7 @@ + all @@ -90,12 +91,6 @@ - - - Libraries\HADotNet.Core.dll - - - UserControl diff --git a/src/HASS.Agent/HASS.Agent/Libraries/HADotNet.Core.dll b/src/HASS.Agent/HASS.Agent/Libraries/HADotNet.Core.dll deleted file mode 100644 index 2e8259605f254d0812b35263c40cd3bfe9c259a5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 78336 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 - - - HADotNet.Core - - - - - Represents the base client from which all other API clients derive. - - - - - Gets the static HttpClient instance. - - - - - Initializes a new instance. - - The preconfigured to communicate with a Home Assistant instance. - - - - Performs a GET request on the specified path. - - The type of data to deserialize and return. - The relative API endpoint path. - The deserialized data of type . - - - - Performs a POST request on the specified path. - - The type of object expected back. - The path to post to. - The body contents to serialize and include. - if the body should be interpereted as a pre-built JSON string, or if it should be serialized. - - - - - Performs a DELETE request on the specified path. - - The type of data to deserialize and return. - The relative API endpoint path. - The deserialized data of type . - - - - Performs a DELETE request on the specified path. - - The relative API endpoint path. - - - - Provides a factory which can instantiate API clients (useful in DI scenarios, for example). - - - - - Gets whether or not the Client Factory has been initialized. - - - - - Gets the instance configured for this ClientFactory. To reconfigure the HttpClient, call again. - - - - - Initializes the client factory with the specified and which are forwarded to clients instantiated from this factory. - - The Home Assistant base instance address (do not include /api/). - The Home Assistant long-lived access token. - - - - Initializes the client factory with the specified and which are forwarded to clients instantiated from this factory. - Allows specifying the to allow further configuring. - - - - - - - - Initializes the client factory with the specified and which are forwarded to clients instantiated from this factory. - - The Home Assistant base instance address (do not include /api/). - The Home Assistant long-lived access token. - - - - Initializes the client factory with the specified and which are forwarded to clients instantiated from this factory. - Allows specifying the to allow further configuring. - - - - - - - - Resets the Client Factory to its initial state (not initialized). - - - - - Retrieves a new instance of a client by type, preconfigured with the same as this (from the last time was called). - - The type of client to get. - Thrown if this is not initialized (call first). - A new instance of the specified type. - - - - Provides access to the automations API for working with automations. - - - - - Initializes a new instance of the . - - The preconfigured to communicate with a Home Assistant instance. - - - - Create the . - - The . - The . - - - - Read the . - - The automation id. - The . - - - - Update the . - - The . - The . - - - - Delete the . - - The automation id. - The . - - - - Provides access to the calendar API for retrieving information about calendar entries. - - - - - Initializes a new instance of the . - - The preconfigured to communicate with a Home Assistant instance. - - - - Retrieves a list of current and future calendar items, from now until the specified . The maximum number of results is driven by the "max_results" configuration option in the calendar config. - - The full name of the calendar entity. If this paramter does not start with "calendar.", it will be prepended automatically. - Optional, defaults to 30. The number of days from the current point in time to retrieve calendar items for. - A representing the calendar items found. - - - - Retrieves a list of current and future calendar items, between the and parameters. The maximum number of results is driven by the "max_results" configuration option in the calendar config. - - The full name of the calendar entity. If this paramter does not start with "calendar.", it will be prepended automatically. - The start date/time to search. - The end date/time to search. - A representing the calendar items found. - - - - Provides access to the camera proxy API which allows fetching of the current image from a camera entity. - - - - - Initializes a new instance of the . - - The preconfigured to communicate with a Home Assistant instance. - - - - Retrieves the most recently available (still) image data from the specified . - - The camera entity ID to reteive the image for. - A byte array containing the still image, typically in JPEG format. - - - - Retrieves the most recently available (still) image data from the specified . - - The camera entity ID to reteive the image for. - true to include the prefix "data:image/jpg;base64,", false to omit. Defaults to true. - A web-friendly Base64-encoded still image, in JPEG format. - - - - Provides access to the configuration API for retrieving the current Home Assistant configuration. - - - - - Initializes a new instance of the . - - The preconfigured to communicate with a Home Assistant instance. - - - - Retrieves the current Home Assistant configuration object. - - A representing the current Home Assistant configuration. - - - - Performs a configuration check and returns the result. - - A containing the results of the check, and any errors that occurred. - - - - Provides access to the discovery API for retrieving the current Home Assistant instance information. - - - - - Initializes a new instance of the . - - The preconfigured to communicate with a Home Assistant instance. - - - - Retrieves the current Home Assistant discovery object. - - A representing the current Home Assistant instance information. - - - - Provides a wrapper around the States endpoint for retrieving entity info. - - - - - Initializes a new instance of the . - - The preconfigured to communicate with a Home Assistant instance. - - - - Retrieves a list of all current entity names (that have state) in the format "domain.name". - - An of strings of all known entities (with state) at the time. - - - - Retrieves a list of entity names for a particular domain (that have state) in the format "domain.name". - - A domain name to filter the entity list to (e.g. "light"). - An of strings of all known entities (with state) at the time. - - - - Provides access to the error log API for retrieving the current error log messages. - - - - - Initializes a new instance of the . - - The preconfigured to communicate with a Home Assistant instance. - - - - Retrieves a list of error log entries. - - An containing error log entries. - - - - Provides access to the event API for retrieving information about events and firing events. - - - - - Initializes a new instance of the . - - The preconfigured to communicate with a Home Assistant instance. - - - - Retrieves a list of event types from the current Home Assistant instance. - - A list of representing the available event types. - - - - Fires an event of type on the event bus. - - An with a message on if the event fired successfully or not. - - - - Provides access to the history API for retrieving and querying for historical state information. - - - - - Initializes a new instance of the . - - The preconfigured to communicate with a Home Assistant instance. - - - - Retrieves a list of ALL historical states for all entities for the past 1 day. WARNING: On larger HA installs, this can return 300+ entities, over 4 MB of data, and take 20+ seconds. - - A representing a 24-hour history snapshot for all entities. - - - - Retrieves a list of ALL historical states for all entities for the specified day ( + 24 hours). WARNING: On larger HA installs, this can return 300+ entities, over 4 MB of data, and take 20+ seconds. - - A representing a 24-hour history snapshot starting from for all entities. - - - - Retrieves a list of ALL historical states for all entities for the specified time range, from to . WARNING: On larger HA installs, for multiple days, this can return A LOT of data and potentially take a LONG time to return. Use with caution! - - A representing a 24-hour history snapshot, from to , for all entities. - - - - Retrieves a list of ALL historical states for all entities for the specified time range, from , for the specified . WARNING: On larger HA installs, for multiple days, this can return A LOT of data and potentially take a LONG time to return. Use with caution! - - A representing a 24-hour history snapshot, from , for the specified , for all entities. - - - - Retrieves a list of historical states for the specified for the specified time range, from to . - - The entity ID to filter on. - The earliest history entry to retrieve. - The most recent history entry to retrieve. - A of history snapshots for the specified , from to . - - - - Retrieves a list of historical states for the specified for the past 1 day. - - The entity ID to retrieve state history for. - A representing a 24-hour history snapshot for the specified . - - - - Provides access to the info API for retrieving information about Supervisor, Core and Host. - - - - - Initializes a new instance of the . - - The preconfigured to communicate with a Home Assistant instance. - - - - Retrieves Supervisor information. - - A representing Supervisor informatio. - - - - Retrieves Host information. - - A representing Host informatio. - - - - Retrieves Core information. - - A representing Host informatio. - - - - Provides access to the Logbook API for retrieving and querying for change events. - - - - - Initializes a new instance of the . - - The preconfigured to communicate with a Home Assistant instance. - - - - Retrieves a list of ALL logbook states for all entities for the past 1 day. - - A representing a 24-hour history snapshot for all entities. - - - - Retrieves a list of ALL historical states for all entities for the specified day ( + 24 hours). WARNING: On larger HA installs, this can return 300+ entities, over 4 MB of data, and take 20+ seconds. - - A representing a 24-hour history snapshot starting from for all entities. - - - - Retrieves a list of ALL historical states for all entities for the specified time range, from to . WARNING: On larger HA installs, for multiple days, this can return A LOT of data and potentially take a LONG time to return. Use with caution! - - A representing a 24-hour history snapshot, from to , for all entities. - - - - Retrieves a list of ALL historical states for all entities for the specified time range, from , for the specified . WARNING: On larger HA installs, for multiple days, this can return A LOT of data and potentially take a LONG time to return. Use with caution! - - A representing a 24-hour history snapshot, from , for the specified , for all entities. - - - - Retrieves a list of historical states for the specified for the specified time range, from to . - - The entity ID to filter on. - The earliest history entry to retrieve. - The most recent history entry to retrieve. - A of history snapshots for the specified , from to . - - - - Retrieves a list of historical states for the specified for the past 1 day. - - The entity ID to retrieve state history for. - A representing a 24-hour history snapshot for the specified . - - - - Provides access to the root API call (located at /api/) to ensure the API is working normally. - - - - - Initializes a new instance of the . - - The preconfigured to communicate with a Home Assistant instance. - - - - Retrieves the API status message for the Home Assistant instance, to ensure it is running. - - A indicating the status of the connected instance. - - - - Provides access to the service API for retrieving information about services and calling services. - - - - - Initializes a new instance of the . - - The preconfigured to communicate with a Home Assistant instance. - - - - Retrieves a list of current services, separated into service domains. - - A representing available services grouped by domain. - - - - Calls a service using the given , , and optionally, . - - The domain of the service (e.g. "light"). - The name of the service (e.g. "turn_on"). - Optional. An object representing the fields/parameters to pass to the service. Can be an anonymous type, or a Dictionary<string, object>. - - - - - Calls a service using the given fully-qualified , and optionally, . - - The fully-qualified service name (e.g. "light.turn_on"). - Optional. An object representing the fields/parameters to pass to the service. Can be an anonymous type, or a Dictionary<string, object>. - - - - - Calls a service using the given , , and optionally, . - - The domain of the service (e.g. "light"). - The name of the service (e.g. "turn_on"). - Optional. A JSON string representing the fields/parameters to pass to the service. Ensure the JSON is a well-formatted object. - - - - - Calls a service using the given fully-qualified , and optionally, . - - The fully-qualified service name (e.g. "light.turn_on"). - Optional. A JSON string representing the fields/parameters to pass to the service. Ensure the JSON is a well-formatted object. - - - - - Calls a service using the given fully-qualified and one or more . - - The fully-qualified service name (e.g. "light.turn_on"). - The entity IDs to pass to the service (using the entity_ids parameter). - - - - - Provides access to the states API for retrieving information about the current state of entities. - - - - - Initializes a new instance of the . - - The preconfigured to communicate with a Home Assistant instance. - - - - Retrieves a list of current entities and their states. - - A representing the current state. - - - - Retrieves the state of an entity by its ID. - - A representing the current state of the requested . - - - - Sets the state of an entity. If the entity does not exist, it will be created. - - The entity ID of the state to change. - The new state value. - Optional. The attributes to set. - A representing the updated state of the updated . - - - - Provides access to the info API for retrieving statistics about Supervisor and Core. - - - - - Initializes a new instance of the . - - The preconfigured to communicate with a Home Assistant instance. - - - - Retrieves Supervisor information. - - A representing Supervisor stats. - - - - Retrieves Core stats. - - A representing Core stats. - - - - Provides access to the template API for rendering Home Assistant templates. - - - - - Initializes a new instance of the . - - The preconfigured to communicate with a Home Assistant instance. - - - - Renders a template and returns the resulting output as a string. - - A string of the rendered template output. - - - - Represents a failed HTTP call to a Home Assistant endpoint. - - - - - Gets the status code for the HTTP response. - - - - - Gets the network description, if the error was at the network level. - - - - - Gets the original request path. - - - - - Gets the error response body. - - - - - Initializes a new HttpResponseException. - - - - - Initializes a new HttpResponseException. - - - - - Initializes a new HttpResponseException. - - - - - The exception that occurs when a Supervisor-only API call is made to a non-Supervisor environment. - - - - - Initializes a new instance of the SupervisorNotFoundException. - - - - - Initializes a new instance of the SupervisorNotFoundException. - - - - - Initializes a new instance of the SupervisorNotFoundException. - - - - - Represents Add-on object. - - - - - Gets or sets the description. - - - - - True if icon is available, otherwise False. - - - - - True if logo is available, otherwise False. - - - - - Gets or sets the name. - - - - - Gets or sets the repository. - - - - - Gets or sets the slug. - - - - - Gets or sets the state. - - - - - True if update is available, otherwise False. - - - - - Gets or sets the version. - - - - - Gets or sets the latest version. - - - - - Represents automation object. - - - - - Gets or sets the ID. - - - - - Gets or sets the alias. - - - - - Gets or sets the description. - - - - - Gets or sets the actions. - - - - - Gets or sets the conditions. - - - - - Gets or sets the triggers. - - - - - Represents the automation result. - - - - - Gets or sets the automation result. - - - - - Represents a calendar item from the Calendar API. - - - - - Gets or sets the Attendee list, if applicable. - - - - - Gets or sets the Created time of the event. - - - - - Gets or sets the creator of the event. - - - - - Gets or sets the end time of the event. - - - - - Gets or sets the eTag for this object. - - - - - Gets or sets the HTML link for this calendar item. - - - - - Gets or sets the iCal UID for this calendar item. - - - - - Gets or sets the unique ID of this calendar item. - - - - - Gets or sets the kind of item (e.g. "calendar#event"). - - - - - Gets or sets the location of the event. - - - - - Gets or sets the organizer of the event. - - - - - Gets or sets the original start time of the event. - - - - - Gets or sets the recurring ID, if this is a recurring item. - - - - - Gets or sets if there are any reminders for this event. - - - - - Gets or sets the sequence number of this event, if applicable. - - - - - Gets or sets the start time of the event. - - - - - Gets or sets the status of this event (e.g. "confirmed"). - - - - - Gets or sets the summary, or title, of this event. - - - - - Gets or sets the transparency of this event (e.g. "transparent"). - - - - - Gets or sets the timestamp when this item was last updated. - - - - - Represents a person (an organizer, an attendee, etc) for an event. - - - - - Gets or sets the display name for this person. - - - - - Gets or sets the person's e-mail address. - - - - - Gets or sets the response if this is an attendee person (e.g. "accepted"). - - - - - Gets or sets if this is the same person as the owner of this calendar (yourself). - - - - - Gets or sets if this is the organizer of the event, for attendees. - - - - - Represents a date/time with a timezone. - - - - - The date of the event, if the event is all-day. - - - - - The date/time of the event, in local time (with an offset). - - - - - The timezone of this date/time. Not always present. - - - - - Represents a reminder override notification. - - - - - The method of notification. - - - - - The number of minutes before the event starts. - - - - - Represents a set of reminders for an event. - - - - - Whether or not to use the account's default reminder period for this event. - - - - - A list of specific notifications or reminders for this event only. - - - - - Represents the Home Assistant configuration object. - - - - - Gets the errors that occurred. This value is if is valid. - - - - - Gets the result of the configuration check. Valid values are valid and invalid. - - - - - Gets a string representation of this object. - - - - - Represents the Home Assistant configuration object. - - - - - Gets or sets the list of components loaded, in the [domain] or [domain].[component] format. - - - - - Gets or sets the relative path to the config directory (usually "/config"). - - - - - Gets or sets the config source, or type of configuration file (usually "yaml"). - - - - - Gets or sets the elevation (in meters) of the current location. - - - - - Gets or sets the latitude of the current location. - - - - - Gets or sets the longitude of the current location. - - - - - Gets or sets the location's friendly name. - - - - - Gets or sets the time zone name (in "tz database" name format, see https://en.wikipedia.org/wiki/List_of_tz_database_time_zones). - - - - - Gets or sets information about the various measurement unit preferences. - - - - - Gets or sets the version of Home Assistant that is currently running (e.g. 0.96.1). - - - - - Gets or sets a list of relative paths that are approved to be exposed externally (e.g. /config/www). - - - - - Gets a string representation of this object. - - - - - Represents an entity state's context. - - - - - Gets or sets the ID of this context. - - - - - Gets or sets the Parent Context ID if this element is a child of another context, otherwise . - - - - - Gets or sets the User ID of this element, or for the default user or no user. - - - - - Gets a string representation of this object. - - - - - Represents Core info object. - - - - - Gets or sets the processor architecture. - - - - - Gets or sets the audio input. - - - - - Gets or sets the audio output. - - - - - True if booted, otherwise False. - - - - - Gets or sets the image. - - - - - Gets or sets the IP address. - - - - - Gets or sets the last_version. - - - - - Gets or sets the machine. - - - - - Gets or sets the port. - - - - - True if SSL is enabled, otherwise False. - - - - - True if update is available, otherwise False. - - - - - Gets or sets the version. - - - - - Gets or sets the latest version. - - - - - Gets or sets the wait boot timeout. - - - - - True if watchdog is enabled, otherwise False. - - - - - Represents a discovery info object, used to convey basic information about the HA instance. - - - - - Gets or sets the Base URL for the instance (e.g. http://192.168.0.2:8123). - - - - - Gets or sets the location name for this instance (e.g. "Home"). - - - - - Gets or sets whether or not a password is required to use the API. (should most always be "true"). - - - - - Gets or sets the current version of Home Assistant (e.g. 0.96.1). - - - - - Gets a string representation of this object. - - - - - Represents an error log entry. - - - - - Gets a Regex object representing a new log line. - - - - - Gets a Regex object representing an error line. - - - - - Gets a Regex object representing a warning line. - - - - - Gets the full, raw log text. - - - - - Gets the list of log entries. - - - - - Gets only log lines with a type of "ERROR". - - - - - Gets only log lines with a type of "WARNING". - - - - - Gets the most recent of entries, sorted newest first. - - The number of entries to retrieve. - A list of log entries of the specified , newest first. - - - - Initializes a new instance of the error log object with the specified data. - - The raw log data to parse. - - - - Parses the raw log text and splits each entry out based on whether or not the line starts with a date. - - The log text to parse. - A parsed list of log entries. - - - - Represents the result of an event firing. - - - - - Gets the resulting message from the event fire command. - - - - - Represents an event definition in Home Assistant. - - - - - Gets the global event string (*). - - - - - Gets the event's name. - - - - - Gets the listener count for this event. - - - - - Gets a string representation of this object. - - - - - Represents a list of one or more historical states for an entity. - - - - - Gets the EntityId for the state objects in this list. - - - - - Gets the earliest point in time represented by this history list. - - - - - Gets the most recent point in time represented by this history list. - - - - - Gets a string representation of this object. - - - - - Represents Host info object. - - - - - Gets or sets the chassis type. - - - - - Gets or sets the CPE string. - - - - - Gets or sets the deployment type (e.g. production). - - - - - Gets or sets the disk free, expressed in GB. - - - - - Gets or sets the disk total, expressed in GB. - - - - - Gets or sets the disk used, expressed in GB. - - - - - Gets or sets the feature list. - - - - - Gets or sets the hostname. - - - - - Gets or sets the kernel version. - - - - - Gets or sets the operating system. - - - - - Represents a logbook entry object. The only consistently available properties are , , and . - - - - - Gets or sets the entity ID for this entry. - - - - - Gets or sets the domain. - - - - - Gets or sets the context user ID associated with this entry. - - - - - Gets or sets the context entity ID associated with this entry. (For example, which automation triggered this change?) - - - - - Gets or sets the friendly name for the . This is sometimes the same as . - - - - - Gets or sets the type of associated change, for example, if an automation triggered this event, the value is 'automation_triggered'. - - - - - Gets or sets the domain associated with the context entity. For example, if an automation triggered this change, the value is 'automation'. - - - - - Gets or sets the name associated with the context entity (e.g. the name of the automation). This is sometimes the same as . - - - - - Gets or sets the new state that the entity transitioned to. - - - - - Gets or sets the source for this logbook entry (i.e. what triggered this change). - - - - - Gets or sets the message, a brief description of what happened. - - - - - Gets or sets the category name for this entry. - - - - - Gets or sets the timestmap when this entry occurred.. - - - - - Represents a basic message object returned from the server (e.g. an object with a "message" property). - - - - - Gets or sets the message for this message object. - - - - - Represents Home Assistant response. - - - - - - Gets or sets the result. - - - - - Gets or sets the data. - - - - - Represents a service domain definition in Home Assistant. - - - - - Gets the service domain's name. - - - - - Gets the list of services in this domain. - - - - - Gets a flat, fully-qualified list of services in this service domain. - - - - - Retrieves a service object from this domain by its name, or returns if the service does not exist. - - The service name to retrieve. - The , if the name exists in this domain, otherwise . - - - - If the specified exists, populates the with the - fully qualified service name (domain.service), and returns . Otherwise, if the service does not exist, - returns . - - The relative name of the service to look up in this service domain. - Upon successful match, will be set to the fullly qualified service name (domain.service). Otherwise, . - if a match was found, otherwise . - - - - Gets a string representation of this object. - - - - - Represents a signle field in a service call. - - - - - Gets or sets the description of this field. - - - - - Gets or sets the example text for this field (may be ). - - - - - Represents a signle service definition. - - - - - The description of the service object. - - - - - The fields/parameters that the service supports. - - - - - Represents a single entity's state. - - - - - Gets or sets the Entity ID that this state represents. - - - - - Gets or sets the string representation of the state that this entity is currently in. - - - - - Gets or sets the entity's current attributes and values. - - - - - Gets or sets the context for this entity's state. - - - - - Gets or sets the UTC date and time that this state was last changed. - - - - - Gets or sets the UTC date and time that this state was last updated. - - - - - Attempts to get the value of the specified attribute by , and cast the value to type . - - Thrown when the specified type cannot be cast to the attribute's current value. - The desired type to cast the attribute value to. - The name of the attribute to retrieve the value for. - The attribute's current value, cast to type . - - - - Gets a string representation of this entity's state. - - - - - Represents the stats object. - - - - - Gets or sets the number of bulk reads. - - - - - Gets or sets the number of bulk writes. - - - - - Gets or sets the CPU usage percent. - - - - - Gets or sets the memory limit. - - - - - Gets or sets the memory usage percent. - - - - - Gets or sets the memory usage. - - - - - Gets or sets the network rx. - - - - - Gets or sets the network tx. - - - - - Represents Supervisor info object. - - - - - Gets or sets the addons. - - - - - Gets or sets the addons repositories. - - - - - Gets or sets the processor architecture. - - - - - Gets or sets the processor channel. - - - - - True if debug, otherwise False. - - - - - True if debug block, otherwise False. - - - - - True if diagnostics is available, otherwise False. - - - - - True if healthy, otherwise False. - - - - - Gets or sets the IP address. - - - - - Gets or sets the logging. - - - - - True if supported, otherwise False. - - - - - Gets or sets the timezone. - - - - - True if update is available, otherwise False. - - - - - Gets or sets the version. - - - - - Gets or sets the latest version. - - - - - Gets or sets the wait boot timeout. - - - - - Represents the Unit System, part of the . - - - - - The length unit (e.g. mi, km). - - - - - The mass unit (e.g. lb, kg). - - - - - The pressure unit (e.g. psi, bar). - - - - - The temperature unit including degree symbol (e.g. °F, °C). - - - - - The volume unit (e.g. gal, L). - - - - - Deserializes the "Example" field into a string regardless of its type. - - - - - Always attempt to deserialize examples. - - - - - Read the JSON into a string. - - - - - Read-only, no writing. - - - - From 6c907e3b40d9d9ea707fa3966b37a9387c584544 Mon Sep 17 00:00:00 2001 From: amadeo-alex <68441479+amadeo-alex@users.noreply.github.com> Date: Thu, 28 May 2026 14:29:13 +0200 Subject: [PATCH 12/13] Fix: Virtual Desktop issues with missing dependency (#452) --- src/HASS.Agent/HASS.Agent/HASS.Agent.csproj | 1 + 1 file changed, 1 insertion(+) diff --git a/src/HASS.Agent/HASS.Agent/HASS.Agent.csproj b/src/HASS.Agent/HASS.Agent/HASS.Agent.csproj index ae1c60a7..7583da5e 100644 --- a/src/HASS.Agent/HASS.Agent/HASS.Agent.csproj +++ b/src/HASS.Agent/HASS.Agent/HASS.Agent.csproj @@ -68,6 +68,7 @@ + From 179f312737f79db53c7e99c08f27779253fc460b Mon Sep 17 00:00:00 2001 From: amadeo-alex <68441479+amadeo-alex@users.noreply.github.com> Date: Sat, 6 Jun 2026 20:48:12 +0200 Subject: [PATCH 13/13] Task: version change to 2.2.1 (#454) --- src/HASS.Agent.Installer/InstallerScript-Service-x86.iss | 2 +- src/HASS.Agent.Installer/InstallerScript-Service.iss | 2 +- src/HASS.Agent.Installer/InstallerScript-x86.iss | 2 +- src/HASS.Agent.Installer/InstallerScript.iss | 2 +- .../HASS.Agent.Satellite.Service.csproj | 6 +++--- src/HASS.Agent/HASS.Agent.Shared/HASS.Agent.Shared.csproj | 6 +++--- src/HASS.Agent/HASS.Agent/HASS.Agent.csproj | 6 +++--- 7 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/HASS.Agent.Installer/InstallerScript-Service-x86.iss b/src/HASS.Agent.Installer/InstallerScript-Service-x86.iss index 9b632fc5..d34a5ec6 100644 --- a/src/HASS.Agent.Installer/InstallerScript-Service-x86.iss +++ b/src/HASS.Agent.Installer/InstallerScript-Service-x86.iss @@ -9,7 +9,7 @@ ; Standard installation constants #define MyAppName "HASS.Agent Satellite Service" -#define MyAppVersion "2.2.0" +#define MyAppVersion "2.2.1" #define MyAppPublisher "HASS.Agent Team" #define MyAppURL "https://hass-agent.io" #define MyAppExeName "HASS.Agent.Satellite.Service.exe" diff --git a/src/HASS.Agent.Installer/InstallerScript-Service.iss b/src/HASS.Agent.Installer/InstallerScript-Service.iss index f2825143..f9c44adb 100644 --- a/src/HASS.Agent.Installer/InstallerScript-Service.iss +++ b/src/HASS.Agent.Installer/InstallerScript-Service.iss @@ -9,7 +9,7 @@ ; Standard installation constants #define MyAppName "HASS.Agent Satellite Service" -#define MyAppVersion "2.2.0" +#define MyAppVersion "2.2.1" #define MyAppPublisher "HASS.Agent Team" #define MyAppURL "https://hass-agent.io" #define MyAppExeName "HASS.Agent.Satellite.Service.exe" diff --git a/src/HASS.Agent.Installer/InstallerScript-x86.iss b/src/HASS.Agent.Installer/InstallerScript-x86.iss index 62f11d9e..75927faa 100644 --- a/src/HASS.Agent.Installer/InstallerScript-x86.iss +++ b/src/HASS.Agent.Installer/InstallerScript-x86.iss @@ -9,7 +9,7 @@ ; Standard installation constants #define MyAppName "HASS.Agent" -#define MyAppVersion "2.2.0" +#define MyAppVersion "2.2.1" #define MyAppPublisher "HASS.Agent Team" #define MyAppURL "https://hass-agent.io" #define MyAppExeName "HASS.Agent.exe" diff --git a/src/HASS.Agent.Installer/InstallerScript.iss b/src/HASS.Agent.Installer/InstallerScript.iss index 4519dba4..335f0338 100644 --- a/src/HASS.Agent.Installer/InstallerScript.iss +++ b/src/HASS.Agent.Installer/InstallerScript.iss @@ -9,7 +9,7 @@ ; Standard installation constants #define MyAppName "HASS.Agent" -#define MyAppVersion "2.2.0" +#define MyAppVersion "2.2.1" #define MyAppPublisher "HASS.Agent Team" #define MyAppURL "https://hass-agent.io" #define MyAppExeName "HASS.Agent.exe" diff --git a/src/HASS.Agent/HASS.Agent.Satellite.Service/HASS.Agent.Satellite.Service.csproj b/src/HASS.Agent/HASS.Agent.Satellite.Service/HASS.Agent.Satellite.Service.csproj index 1e3dfd54..4464d5b6 100644 --- a/src/HASS.Agent/HASS.Agent.Satellite.Service/HASS.Agent.Satellite.Service.csproj +++ b/src/HASS.Agent/HASS.Agent.Satellite.Service/HASS.Agent.Satellite.Service.csproj @@ -8,7 +8,7 @@ dotnet-HASSAgentSatelliteService-6E4FA50A-3AC9-4E66-8671-9FAB92372154 anycpu x64;x86;AnyCPU - 2.2.0 + 2.2.1 HASS.Agent Team HASS.Agent Satellite Service HASS.Agent.Satellite.Service @@ -17,9 +17,9 @@ https://github.com/hass-agent/HASS.Agent https://github.com/hass-agent/HASS.Agent hass.png - 2.2.0 + 2.2.1 hass.ico - 2.2.0 + 2.2.1 10.0.17763.0 false diff --git a/src/HASS.Agent/HASS.Agent.Shared/HASS.Agent.Shared.csproj b/src/HASS.Agent/HASS.Agent.Shared/HASS.Agent.Shared.csproj index 0fae9b41..31336c84 100644 --- a/src/HASS.Agent/HASS.Agent.Shared/HASS.Agent.Shared.csproj +++ b/src/HASS.Agent/HASS.Agent.Shared/HASS.Agent.Shared.csproj @@ -10,9 +10,9 @@ Shared functions and models for the HASS.Agent platform. https://github.com/hass-agent/HASS.Agent https://github.com/hass-agent/HASS.Agent - 2.2.0 - 2.2.0 - 2.2.0 + 2.2.1 + 2.2.1 + 2.2.1 logo_128.png True hassagent.ico diff --git a/src/HASS.Agent/HASS.Agent/HASS.Agent.csproj b/src/HASS.Agent/HASS.Agent/HASS.Agent.csproj index 7583da5e..f3fc5f33 100644 --- a/src/HASS.Agent/HASS.Agent/HASS.Agent.csproj +++ b/src/HASS.Agent/HASS.Agent/HASS.Agent.csproj @@ -17,7 +17,7 @@ anycpu x64;x86;AnyCPU full - 2.2.0 + 2.2.1 HASS.Agent Team HASS.Agent Team Windows-based client for Home Assistant. Provides notifications, quick actions, commands, sensors and more. @@ -27,8 +27,8 @@ https://github.com/hass-agent/HASS.Agent MIT app.manifest - 2.2.0 - 2.2.0 + 2.2.1 + 2.2.1 HASS.Agent None true