From 1bfeb9c45fd9128720ade59005588612bc6e9575 Mon Sep 17 00:00:00 2001 From: Stefan Roelofs Date: Fri, 26 Mar 2021 21:57:46 +0100 Subject: [PATCH 01/13] Refactor some abstract classes. No functional changes, just syntactic sugar. --- .../Domain/AbstractDiscoverable.cs | 12 +--- .../Domain/Commands/AbstractCommand.cs | 72 ++++++++----------- .../Domain/Sensors/AbstractSensor.cs | 71 ++++++++---------- 3 files changed, 60 insertions(+), 95 deletions(-) diff --git a/hass-workstation-service/Domain/AbstractDiscoverable.cs b/hass-workstation-service/Domain/AbstractDiscoverable.cs index aba479e..8f8fd85 100644 --- a/hass-workstation-service/Domain/AbstractDiscoverable.cs +++ b/hass-workstation-service/Domain/AbstractDiscoverable.cs @@ -12,16 +12,8 @@ namespace hass_workstation_service.Domain { public abstract string Domain { get; } public string Name { get; protected set; } - - public string ObjectId - { - get - { - return Regex.Replace(this.Name, "[^a-zA-Z0-9_-]", "_"); - } - } + public string ObjectId => Regex.Replace(Name, "[^a-zA-Z0-9_-]", "_"); public Guid Id { get; protected set; } - public abstract DiscoveryConfigModel GetAutoDiscoveryConfig(); } -} +} \ No newline at end of file diff --git a/hass-workstation-service/Domain/Commands/AbstractCommand.cs b/hass-workstation-service/Domain/Commands/AbstractCommand.cs index 849077e..c711408 100644 --- a/hass-workstation-service/Domain/Commands/AbstractCommand.cs +++ b/hass-workstation-service/Domain/Commands/AbstractCommand.cs @@ -5,72 +5,60 @@ using MQTTnet; namespace hass_workstation_service.Domain.Commands { - public abstract class AbstractCommand : AbstractDiscoverable { /// /// The update interval in seconds. It checks state only if the interval has passed. /// - public int UpdateInterval { get => 1; } + public static int UpdateInterval { get => 1; } public DateTime? LastUpdated { get; protected set; } public string PreviousPublishedState { get; protected set; } public MqttPublisher Publisher { get; protected set; } public override string Domain { get => "switch"; } - public AbstractCommand(MqttPublisher publisher, string name, Guid id = default(Guid)) - { - if (id == Guid.Empty) - { - this.Id = Guid.NewGuid(); - } - else - { - this.Id = id; - } - this.Name = name; - this.Publisher = publisher; - publisher.Subscribe(this); - } - protected CommandDiscoveryConfigModel _autoDiscoveryConfigModel; - protected CommandDiscoveryConfigModel SetAutoDiscoveryConfigModel(CommandDiscoveryConfigModel config) + public AbstractCommand(MqttPublisher publisher, string name, Guid id = default) { - this._autoDiscoveryConfigModel = config; - return config; + Id = id == Guid.Empty ? Guid.NewGuid() : id; + Name = name; + Publisher = publisher; + publisher.Subscribe(this); } public abstract string GetState(); public async Task PublishStateAsync() { - if (LastUpdated.HasValue && LastUpdated.Value.AddSeconds(this.UpdateInterval) > DateTime.UtcNow) - { - // dont't even check the state if the update interval hasn't passed + // dont't even check the state if the update interval hasn't passed + if (LastUpdated.HasValue && LastUpdated.Value.AddSeconds(UpdateInterval) > DateTime.UtcNow) return; - } - string state = this.GetState(); - if (this.PreviousPublishedState == state) - { - // don't publish the state if it hasn't changed + + string state = GetState(); + // don't publish the state if it hasn't changed + if (PreviousPublishedState == state) return; - } + var message = new MqttApplicationMessageBuilder() - .WithTopic(this.GetAutoDiscoveryConfig().State_topic) - .WithPayload(state) - .WithExactlyOnceQoS() - .WithRetainFlag() - .Build(); + .WithTopic(GetAutoDiscoveryConfig().State_topic) + .WithPayload(state) + .WithExactlyOnceQoS() + .WithRetainFlag() + .Build(); await Publisher.Publish(message); - this.PreviousPublishedState = state; - this.LastUpdated = DateTime.UtcNow; + PreviousPublishedState = state; + LastUpdated = DateTime.UtcNow; } - public async void PublishAutoDiscoveryConfigAsync() - { - await this.Publisher.AnnounceAutoDiscoveryConfig(this, this.Domain); - } - public async Task UnPublishAutoDiscoveryConfigAsync() + + public async void PublishAutoDiscoveryConfigAsync() => await Publisher.AnnounceAutoDiscoveryConfig(this, Domain); + + public async Task UnPublishAutoDiscoveryConfigAsync() => await Publisher.AnnounceAutoDiscoveryConfig(this, Domain, true); + + protected CommandDiscoveryConfigModel _autoDiscoveryConfigModel; + protected CommandDiscoveryConfigModel SetAutoDiscoveryConfigModel(CommandDiscoveryConfigModel config) { - await this.Publisher.AnnounceAutoDiscoveryConfig(this, this.Domain, true); + _autoDiscoveryConfigModel = config; + return config; } + public abstract void TurnOn(); public abstract void TurnOff(); } diff --git a/hass-workstation-service/Domain/Sensors/AbstractSensor.cs b/hass-workstation-service/Domain/Sensors/AbstractSensor.cs index 22d9a37..50c52a8 100644 --- a/hass-workstation-service/Domain/Sensors/AbstractSensor.cs +++ b/hass-workstation-service/Domain/Sensors/AbstractSensor.cs @@ -1,12 +1,10 @@ using System; -using System.Text.RegularExpressions; using System.Threading.Tasks; using hass_workstation_service.Communication; using MQTTnet; namespace hass_workstation_service.Domain.Sensors { - public abstract class AbstractSensor : AbstractDiscoverable { /// @@ -17,61 +15,48 @@ namespace hass_workstation_service.Domain.Sensors public string PreviousPublishedState { get; protected set; } public MqttPublisher Publisher { get; protected set; } public override string Domain { get => "sensor"; } - public AbstractSensor(MqttPublisher publisher, string name, int updateInterval = 10, Guid id = default(Guid)) - { - if (id == Guid.Empty) - { - this.Id = Guid.NewGuid(); - } - else - { - this.Id = id; - } - this.Name = name; - this.Publisher = publisher; - this.UpdateInterval = updateInterval; - } - protected SensorDiscoveryConfigModel _autoDiscoveryConfigModel; - protected SensorDiscoveryConfigModel SetAutoDiscoveryConfigModel(SensorDiscoveryConfigModel config) + public AbstractSensor(MqttPublisher publisher, string name, int updateInterval = 10, Guid id = default) { - this._autoDiscoveryConfigModel = config; - return config; + Id = id == Guid.Empty ? Guid.NewGuid() : id; + Name = name; + Publisher = publisher; + UpdateInterval = updateInterval; } public abstract string GetState(); public async Task PublishStateAsync() { - if (LastUpdated.HasValue && LastUpdated.Value.AddSeconds(this.UpdateInterval) > DateTime.UtcNow) - { - // dont't even check the state if the update interval hasn't passed + // dont't even check the state if the update interval hasn't passed + if (LastUpdated.HasValue && LastUpdated.Value.AddSeconds(UpdateInterval) > DateTime.UtcNow) return; - } - string state = this.GetState(); - if (this.PreviousPublishedState == state) - { - // don't publish the state if it hasn't changed + + string state = GetState(); + // don't publish the state if it hasn't changed + if (PreviousPublishedState == state) return; - } + var message = new MqttApplicationMessageBuilder() - .WithTopic(this.GetAutoDiscoveryConfig().State_topic) - .WithPayload(state) - .WithExactlyOnceQoS() - .WithRetainFlag() - .Build(); + .WithTopic(GetAutoDiscoveryConfig().State_topic) + .WithPayload(state) + .WithExactlyOnceQoS() + .WithRetainFlag() + .Build(); await Publisher.Publish(message); - this.PreviousPublishedState = state; - this.LastUpdated = DateTime.UtcNow; + PreviousPublishedState = state; + LastUpdated = DateTime.UtcNow; } - public async void PublishAutoDiscoveryConfigAsync() - { - await this.Publisher.AnnounceAutoDiscoveryConfig(this, this.Domain); - } - public async Task UnPublishAutoDiscoveryConfigAsync() + + public async void PublishAutoDiscoveryConfigAsync() => await Publisher.AnnounceAutoDiscoveryConfig(this, Domain); + + public async Task UnPublishAutoDiscoveryConfigAsync() => await Publisher.AnnounceAutoDiscoveryConfig(this, Domain, true); + + protected SensorDiscoveryConfigModel _autoDiscoveryConfigModel; + protected SensorDiscoveryConfigModel SetAutoDiscoveryConfigModel(SensorDiscoveryConfigModel config) { - await this.Publisher.AnnounceAutoDiscoveryConfig(this, this.Domain, true); + _autoDiscoveryConfigModel = config; + return config; } - } } \ No newline at end of file From a50640d7d76f669d40f012ad2f647b537e58c12b Mon Sep 17 00:00:00 2001 From: Stefan Roelofs Date: Sat, 27 Mar 2021 01:13:49 +0100 Subject: [PATCH 02/13] Changed name of ServiceContractInterfaces to IServiceContractInterfaces Update the interface with new UpdateSensor method calls --- UserInterface/Views/AddCommandDialog.axaml.cs | 8 ++++---- UserInterface/Views/AddSensorDialog.axaml.cs | 8 ++++---- UserInterface/Views/AppInfo.axaml.cs | 8 ++++---- .../Views/BackgroundServiceSettings.axaml.cs | 8 ++++---- UserInterface/Views/BrokerSettings.axaml.cs | 8 ++++---- UserInterface/Views/CommandSettings.axaml.cs | 8 ++++---- UserInterface/Views/SensorSettings.axaml.cs | 8 ++++---- ...ctInterfaces.cs => IServiceContractInterfaces.cs} | 12 +++++++----- hass-workstation-service/Program.cs | 4 ++-- 9 files changed, 37 insertions(+), 35 deletions(-) rename hass-workstation-service/Communication/InterProcesCommunication/{ServiceContractInterfaces.cs => IServiceContractInterfaces.cs} (79%) diff --git a/UserInterface/Views/AddCommandDialog.axaml.cs b/UserInterface/Views/AddCommandDialog.axaml.cs index a1ed877..fbf0974 100644 --- a/UserInterface/Views/AddCommandDialog.axaml.cs +++ b/UserInterface/Views/AddCommandDialog.axaml.cs @@ -17,7 +17,7 @@ namespace UserInterface.Views { public class AddCommandDialog : Window { - private readonly IIpcClient client; + private readonly IIpcClient client; public ComboBox comboBox { get; set; } public ComboBox detectionModecomboBox { get; set; } public AddCommandDialog() @@ -30,12 +30,12 @@ namespace UserInterface.Views // register IPC clients ServiceProvider serviceProvider = new ServiceCollection() - .AddNamedPipeIpcClient("addCommand", pipeName: "pipeinternal") + .AddNamedPipeIpcClient("addCommand", pipeName: "pipeinternal") .BuildServiceProvider(); // resolve IPC client factory - IIpcClientFactory clientFactory = serviceProvider - .GetRequiredService>(); + IIpcClientFactory clientFactory = serviceProvider + .GetRequiredService>(); // create client this.client = clientFactory.CreateClient("addCommand"); diff --git a/UserInterface/Views/AddSensorDialog.axaml.cs b/UserInterface/Views/AddSensorDialog.axaml.cs index 8c12a81..024e78a 100644 --- a/UserInterface/Views/AddSensorDialog.axaml.cs +++ b/UserInterface/Views/AddSensorDialog.axaml.cs @@ -17,7 +17,7 @@ namespace UserInterface.Views { public class AddSensorDialog : Window { - private readonly IIpcClient client; + private readonly IIpcClient client; public ComboBox comboBox { get; set; } public ComboBox detectionModecomboBox { get; set; } public AddSensorDialog() @@ -30,12 +30,12 @@ namespace UserInterface.Views // register IPC clients ServiceProvider serviceProvider = new ServiceCollection() - .AddNamedPipeIpcClient("addsensor", pipeName: "pipeinternal") + .AddNamedPipeIpcClient("addsensor", pipeName: "pipeinternal") .BuildServiceProvider(); // resolve IPC client factory - IIpcClientFactory clientFactory = serviceProvider - .GetRequiredService>(); + IIpcClientFactory clientFactory = serviceProvider + .GetRequiredService>(); // create client this.client = clientFactory.CreateClient("addsensor"); diff --git a/UserInterface/Views/AppInfo.axaml.cs b/UserInterface/Views/AppInfo.axaml.cs index 388d13c..ed0b184 100644 --- a/UserInterface/Views/AppInfo.axaml.cs +++ b/UserInterface/Views/AppInfo.axaml.cs @@ -16,19 +16,19 @@ namespace UserInterface.Views { public class AppInfo : UserControl { - private readonly IIpcClient client; + private readonly IIpcClient client; public AppInfo() { this.InitializeComponent(); // register IPC clients ServiceProvider serviceProvider = new ServiceCollection() - .AddNamedPipeIpcClient("info", pipeName: "pipeinternal") + .AddNamedPipeIpcClient("info", pipeName: "pipeinternal") .BuildServiceProvider(); // resolve IPC client factory - IIpcClientFactory clientFactory = serviceProvider - .GetRequiredService>(); + IIpcClientFactory clientFactory = serviceProvider + .GetRequiredService>(); // create client this.client = clientFactory.CreateClient("info"); diff --git a/UserInterface/Views/BackgroundServiceSettings.axaml.cs b/UserInterface/Views/BackgroundServiceSettings.axaml.cs index 23588c9..f2b518f 100644 --- a/UserInterface/Views/BackgroundServiceSettings.axaml.cs +++ b/UserInterface/Views/BackgroundServiceSettings.axaml.cs @@ -15,19 +15,19 @@ namespace UserInterface.Views { public class BackgroundServiceSettings : UserControl { - private readonly IIpcClient _client; + private readonly IIpcClient _client; public BackgroundServiceSettings() { this.InitializeComponent(); // register IPC clients ServiceProvider serviceProvider = new ServiceCollection() - .AddNamedPipeIpcClient("broker", pipeName: "pipeinternal") + .AddNamedPipeIpcClient("broker", pipeName: "pipeinternal") .BuildServiceProvider(); // resolve IPC client factory - IIpcClientFactory clientFactory = serviceProvider - .GetRequiredService>(); + IIpcClientFactory clientFactory = serviceProvider + .GetRequiredService>(); // create client this._client = clientFactory.CreateClient("broker"); diff --git a/UserInterface/Views/BrokerSettings.axaml.cs b/UserInterface/Views/BrokerSettings.axaml.cs index 3e59837..e870a80 100644 --- a/UserInterface/Views/BrokerSettings.axaml.cs +++ b/UserInterface/Views/BrokerSettings.axaml.cs @@ -17,19 +17,19 @@ namespace UserInterface.Views { public class BrokerSettings : UserControl { - private readonly IIpcClient client; + private readonly IIpcClient client; public BrokerSettings() { this.InitializeComponent(); // register IPC clients ServiceProvider serviceProvider = new ServiceCollection() - .AddNamedPipeIpcClient("broker", pipeName: "pipeinternal") + .AddNamedPipeIpcClient("broker", pipeName: "pipeinternal") .BuildServiceProvider(); // resolve IPC client factory - IIpcClientFactory clientFactory = serviceProvider - .GetRequiredService>(); + IIpcClientFactory clientFactory = serviceProvider + .GetRequiredService>(); // create client this.client = clientFactory.CreateClient("broker"); diff --git a/UserInterface/Views/CommandSettings.axaml.cs b/UserInterface/Views/CommandSettings.axaml.cs index e9753fc..b4379da 100644 --- a/UserInterface/Views/CommandSettings.axaml.cs +++ b/UserInterface/Views/CommandSettings.axaml.cs @@ -18,7 +18,7 @@ namespace UserInterface.Views { public class CommandSettings : UserControl { - private readonly IIpcClient _client; + private readonly IIpcClient _client; private readonly DataGrid _dataGrid; private bool _sensorsNeedToRefresh; @@ -27,12 +27,12 @@ namespace UserInterface.Views this.InitializeComponent(); // register IPC clients ServiceProvider serviceProvider = new ServiceCollection() - .AddNamedPipeIpcClient("commands", pipeName: "pipeinternal") + .AddNamedPipeIpcClient("commands", pipeName: "pipeinternal") .BuildServiceProvider(); // resolve IPC client factory - IIpcClientFactory clientFactory = serviceProvider - .GetRequiredService>(); + IIpcClientFactory clientFactory = serviceProvider + .GetRequiredService>(); // create client this._client = clientFactory.CreateClient("commands"); diff --git a/UserInterface/Views/SensorSettings.axaml.cs b/UserInterface/Views/SensorSettings.axaml.cs index 9eceeb1..dff4900 100644 --- a/UserInterface/Views/SensorSettings.axaml.cs +++ b/UserInterface/Views/SensorSettings.axaml.cs @@ -18,7 +18,7 @@ namespace UserInterface.Views { public class SensorSettings : UserControl { - private readonly IIpcClient _client; + private readonly IIpcClient _client; private readonly DataGrid _dataGrid; private bool _sensorsNeedToRefresh; @@ -27,12 +27,12 @@ namespace UserInterface.Views this.InitializeComponent(); // register IPC clients ServiceProvider serviceProvider = new ServiceCollection() - .AddNamedPipeIpcClient("sensors", pipeName: "pipeinternal") + .AddNamedPipeIpcClient("sensors", pipeName: "pipeinternal") .BuildServiceProvider(); // resolve IPC client factory - IIpcClientFactory clientFactory = serviceProvider - .GetRequiredService>(); + IIpcClientFactory clientFactory = serviceProvider + .GetRequiredService>(); // create client this._client = clientFactory.CreateClient("sensors"); diff --git a/hass-workstation-service/Communication/InterProcesCommunication/ServiceContractInterfaces.cs b/hass-workstation-service/Communication/InterProcesCommunication/IServiceContractInterfaces.cs similarity index 79% rename from hass-workstation-service/Communication/InterProcesCommunication/ServiceContractInterfaces.cs rename to hass-workstation-service/Communication/InterProcesCommunication/IServiceContractInterfaces.cs index 57c29f6..51e2fdd 100644 --- a/hass-workstation-service/Communication/InterProcesCommunication/ServiceContractInterfaces.cs +++ b/hass-workstation-service/Communication/InterProcesCommunication/IServiceContractInterfaces.cs @@ -1,12 +1,11 @@ using hass_workstation_service.Communication.InterProcesCommunication.Models; using System; using System.Collections.Generic; -using System.Text; using System.Threading.Tasks; namespace hass_workstation_service.Communication.NamedPipe { - public interface ServiceContractInterfaces + public interface IServiceContractInterfaces { Task GetMqttBrokerSettings(); public string Ping(string str); @@ -14,12 +13,15 @@ namespace hass_workstation_service.Communication.NamedPipe MqqtClientStatus GetMqqtClientStatus(); void EnableAutostart(bool enable); bool IsAutoStartEnabled(); + Task GetConfiguredSensor(Guid id); Task> GetConfiguredSensors(); - void RemoveSensorById(Guid id); void AddSensor(AvailableSensors sensorType, string json); - void RemoveCommandById(Guid id); + void RemoveSensorById(Guid id); + void UpdateSensorById(Guid id, string json); + ConfiguredCommandModel GetConfiguredCommand(Guid id); List GetConfiguredCommands(); void AddCommand(AvailableCommands commandType, string json); + void RemoveCommandById(Guid id); string GetCurrentVersion(); } -} +} \ No newline at end of file diff --git a/hass-workstation-service/Program.cs b/hass-workstation-service/Program.cs index d720614..ed90371 100644 --- a/hass-workstation-service/Program.cs +++ b/hass-workstation-service/Program.cs @@ -84,14 +84,14 @@ namespace hass_workstation_service Sw_version = GetVersion() }; services.AddSingleton(deviceConfig); - services.AddSingleton(); + services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); services.AddHostedService(); }).ConfigureIpcHost(builder => { // configure IPC endpoints - builder.AddNamedPipeEndpoint(pipeName: "pipeinternal"); + builder.AddNamedPipeEndpoint(pipeName: "pipeinternal"); }); static internal string GetVersion() { From 22de0c41f7ff2594830a70a25165161d5e462f0c Mon Sep 17 00:00:00 2001 From: Stefan Roelofs Date: Sat, 27 Mar 2021 01:15:11 +0100 Subject: [PATCH 03/13] Update ConfigurationServices with methods to update sensors / commands --- .../Data/ConfigurationService.cs | 93 +++++++++++++------ .../Data/IConfigurationService.cs | 11 ++- 2 files changed, 71 insertions(+), 33 deletions(-) diff --git a/hass-workstation-service/Data/ConfigurationService.cs b/hass-workstation-service/Data/ConfigurationService.cs index db11c32..e6802a0 100644 --- a/hass-workstation-service/Data/ConfigurationService.cs +++ b/hass-workstation-service/Data/ConfigurationService.cs @@ -181,7 +181,7 @@ namespace hass_workstation_service.Data command = new LogOffCommand(publisher, configuredCommand.Name, configuredCommand.Id); break; case "CustomCommand": - command = new CustomCommand(publisher, configuredCommand.Command, configuredCommand.Name, configuredCommand.Id); + command = new CustomCommand(publisher, configuredCommand.Command, configuredCommand.Name, configuredCommand.Id); break; case "MediaPlayPauseCommand": command = new MediaPlayPauseCommand(publisher, configuredCommand.Name, configuredCommand.Id); @@ -340,54 +340,89 @@ namespace hass_workstation_service.Data public void AddConfiguredSensor(AbstractSensor sensor) { - this.ConfiguredSensors.Add(sensor); - sensor.PublishAutoDiscoveryConfigAsync(); + AddSensor(sensor); WriteSensorSettingsAsync(); } public void AddConfiguredCommand(AbstractCommand command) { - this.ConfiguredCommands.Add(command); - command.PublishAutoDiscoveryConfigAsync(); + AddCommand(command); WriteCommandSettingsAsync(); } - public async void DeleteConfiguredSensor(Guid id) + public void AddConfiguredSensors(List sensors) { - var sensorToRemove = this.ConfiguredSensors.FirstOrDefault(s => s.Id == id); - if (sensorToRemove != null) - { - await sensorToRemove.UnPublishAutoDiscoveryConfigAsync(); - this.ConfiguredSensors.Remove(sensorToRemove); - WriteSensorSettingsAsync(); - } - else - { - Log.Logger.Warning($"sensor with id {id} not found"); - } + sensors.ForEach(sensor => AddSensor(sensor)); + WriteSensorSettingsAsync(); + } + public void AddConfiguredCommands(List commands) + { + commands.ForEach(command => AddCommand(command)); + WriteCommandSettingsAsync(); + } + + public async void DeleteConfiguredSensor(Guid id) + { + await DeleteSensor(id); + WriteSensorSettingsAsync(); } public async void DeleteConfiguredCommand(Guid id) { - var commandToRemove = this.ConfiguredCommands.FirstOrDefault(s => s.Id == id); - if (commandToRemove != null) - { - await commandToRemove.UnPublishAutoDiscoveryConfigAsync(); - this.ConfiguredCommands.Remove(commandToRemove); - WriteCommandSettingsAsync(); - } - else + await DeleteCommand(id); + WriteCommandSettingsAsync(); + } + + public async void UpdateConfiguredSensor(Guid id, AbstractSensor sensor) + { + await DeleteSensor(id); + AddSensor(sensor); + WriteSensorSettingsAsync(); + } + + public async void UpdateConfiguredCommand(Guid id, AbstractCommand command) + { + await DeleteCommand(id); + AddCommand(command); + WriteCommandSettingsAsync(); + } + + private void AddSensor(AbstractSensor sensor) + { + ConfiguredSensors.Add(sensor); + sensor.PublishAutoDiscoveryConfigAsync(); + } + + private void AddCommand(AbstractCommand command) + { + ConfiguredCommands.Add(command); + command.PublishAutoDiscoveryConfigAsync(); + } + + private async Task DeleteSensor(Guid id) + { + var sensorToRemove = ConfiguredSensors.FirstOrDefault(s => s.Id == id); + if (sensorToRemove == null) { - Log.Logger.Warning($"command with id {id} not found"); + Log.Logger.Warning($"sensor with id {id} not found"); + return; } + await sensorToRemove.UnPublishAutoDiscoveryConfigAsync(); + ConfiguredSensors.Remove(sensorToRemove); } - public void AddConfiguredSensors(List sensors) + private async Task DeleteCommand(Guid id) { - sensors.ForEach((sensor) => this.ConfiguredSensors.Add(sensor)); - WriteSensorSettingsAsync(); + var commandToRemove = ConfiguredCommands.FirstOrDefault(c => c.Id == id); + if (commandToRemove == null) + { + Log.Logger.Warning($"command with id {id} not found"); + return; + } + await commandToRemove.UnPublishAutoDiscoveryConfigAsync(); + ConfiguredCommands.Remove(commandToRemove); } /// diff --git a/hass-workstation-service/Data/IConfigurationService.cs b/hass-workstation-service/Data/IConfigurationService.cs index 43d81dc..b2b63e5 100644 --- a/hass-workstation-service/Data/IConfigurationService.cs +++ b/hass-workstation-service/Data/IConfigurationService.cs @@ -13,13 +13,18 @@ namespace hass_workstation_service.Data { public interface IConfigurationService { - ICollection ConfiguredSensors { get; } Action MqqtConfigChangedHandler { get; set; } + ICollection ConfiguredSensors { get; } ICollection ConfiguredCommands { get; } - void AddConfiguredCommand(AbstractCommand command); void AddConfiguredSensor(AbstractSensor sensor); + void AddConfiguredCommand(AbstractCommand command); void AddConfiguredSensors(List sensors); + void AddConfiguredCommands(List commands); + void DeleteConfiguredSensor(Guid id); + void DeleteConfiguredCommand(Guid id); + void UpdateConfiguredSensor(Guid id, AbstractSensor sensor); + void UpdateConfiguredCommand(Guid id, AbstractCommand command); Task GetMqttClientOptionsAsync(); void ReadSensorSettings(MqttPublisher publisher); void WriteMqttBrokerSettingsAsync(MqttSettings settings); @@ -27,8 +32,6 @@ namespace hass_workstation_service.Data Task GetMqttBrokerSettings(); void EnableAutoStart(bool enable); bool IsAutoStartEnabled(); - void DeleteConfiguredSensor(Guid id); - void DeleteConfiguredCommand(Guid id); void WriteCommandSettingsAsync(); void ReadCommandSettings(MqttPublisher publisher); Task> GetSensorsAfterLoadingAsync(); From 9f65261081151864d5121b2cab905dd626ff72de Mon Sep 17 00:00:00 2001 From: Stefan Roelofs Date: Sat, 27 Mar 2021 01:15:44 +0100 Subject: [PATCH 04/13] Changed type of Type to AvailableSensors. Makes more sense I think. --- .../InterProcesCommunication/ServiceContractModels.cs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/hass-workstation-service/Communication/InterProcesCommunication/ServiceContractModels.cs b/hass-workstation-service/Communication/InterProcesCommunication/ServiceContractModels.cs index 1f87979..f85bdac 100644 --- a/hass-workstation-service/Communication/InterProcesCommunication/ServiceContractModels.cs +++ b/hass-workstation-service/Communication/InterProcesCommunication/ServiceContractModels.cs @@ -1,7 +1,4 @@ -using hass_workstation_service.Domain.Sensors; using System; -using System.Collections.Generic; -using System.Text; namespace hass_workstation_service.Communication.InterProcesCommunication.Models { @@ -23,19 +20,21 @@ namespace hass_workstation_service.Communication.InterProcesCommunication.Models public class ConfiguredSensorModel { public Guid Id { get; set; } - public string Type { get; set; } + public AvailableSensors Type { get; set; } public string Name { get; set; } public string Value { get; set; } public int UpdateInterval { get; set; } public string UnitOfMeasurement { get; set; } } + public class ConfiguredCommandModel { public Guid Id { get; set; } - public string Type { get; set; } + public AvailableCommands Type { get; set; } public string Name { get; set; } public string Command { get; set; } } + public enum AvailableSensors { UserNotificationStateSensor, @@ -70,4 +69,4 @@ namespace hass_workstation_service.Communication.InterProcesCommunication.Models VolumeDownCommand, MuteCommand } -} +} \ No newline at end of file From feb2841cbc4fcf24f4486e8d81c31541e6772c1f Mon Sep 17 00:00:00 2001 From: Stefan Roelofs Date: Sat, 27 Mar 2021 01:16:38 +0100 Subject: [PATCH 05/13] Add methods to Update sensors / commands. --- .../InterProcessApi.cs | 307 +++++++++--------- 1 file changed, 158 insertions(+), 149 deletions(-) diff --git a/hass-workstation-service/Communication/InterProcesCommunication/InterProcessApi.cs b/hass-workstation-service/Communication/InterProcesCommunication/InterProcessApi.cs index 2846115..849631b 100644 --- a/hass-workstation-service/Communication/InterProcesCommunication/InterProcessApi.cs +++ b/hass-workstation-service/Communication/InterProcesCommunication/InterProcessApi.cs @@ -7,15 +7,13 @@ using hass_workstation_service.Domain.Sensors; using Serilog; using System; using System.Collections.Generic; -using System.Dynamic; using System.Linq; -using System.Text; using System.Text.Json; using System.Threading.Tasks; namespace hass_workstation_service.Communication.InterProcesCommunication { - public class InterProcessApi : ServiceContractInterfaces + public class InterProcessApi : IServiceContractInterfaces { private readonly MqttPublisher _publisher; private readonly IConfigurationService _configurationService; @@ -26,73 +24,115 @@ namespace hass_workstation_service.Communication.InterProcesCommunication _configurationService = configurationService; } - public MqqtClientStatus GetMqqtClientStatus() - { - return this._publisher.GetStatus(); - } + public MqqtClientStatus GetMqqtClientStatus() => _publisher.GetStatus(); - public Task GetMqttBrokerSettings() - { - return this._configurationService.GetMqttBrokerSettings(); - } + public Task GetMqttBrokerSettings() => _configurationService.GetMqttBrokerSettings(); /// /// You can use this to check if the application responds. /// /// /// - public string Ping(string str) - { - if (str == "ping") - { - return "pong"; - } - return "what?"; - } + public string Ping(string str) => str == "ping" ? "pong" : "what?"; + + public string GetCurrentVersion() => Program.GetVersion(); /// /// This writes the provided settings to the config file. /// /// - public void WriteMqttBrokerSettingsAsync(MqttSettings settings) - { - this._configurationService.WriteMqttBrokerSettingsAsync(settings); - } + public void WriteMqttBrokerSettingsAsync(MqttSettings settings) => _configurationService.WriteMqttBrokerSettingsAsync(settings); /// /// Enables or disables autostart. /// /// - public void EnableAutostart(bool enable) - { - this._configurationService.EnableAutoStart(enable); - } + public void EnableAutostart(bool enable) => _configurationService.EnableAutoStart(enable); - public bool IsAutoStartEnabled() - { - return this._configurationService.IsAutoStartEnabled(); - } + public bool IsAutoStartEnabled() => _configurationService.IsAutoStartEnabled(); public async Task> GetConfiguredSensors() { - var sensors = await this._configurationService.GetSensorsAfterLoadingAsync(); - return sensors.Select(s => new ConfiguredSensorModel() { Name = s.Name, Type = s.GetType().Name, Value = s.PreviousPublishedState, Id = s.Id, UpdateInterval = s.UpdateInterval, UnitOfMeasurement = ((SensorDiscoveryConfigModel)s.GetAutoDiscoveryConfig()).Unit_of_measurement }).ToList(); + var sensors = await _configurationService.GetSensorsAfterLoadingAsync(); + return sensors.Select(s => + { + if (!Enum.TryParse(s.GetType().Name, out AvailableSensors type)) + Log.Logger.Error("Unknown sensor"); + + return new ConfiguredSensorModel() + { + Name = s.Name, + Type = type, + Value = s.PreviousPublishedState, + Id = s.Id, + UpdateInterval = s.UpdateInterval, + UnitOfMeasurement = ((SensorDiscoveryConfigModel)s.GetAutoDiscoveryConfig()).Unit_of_measurement + }; + }).ToList(); } - public List GetConfiguredCommands() + public async Task GetConfiguredSensor(Guid id) { - return this._configurationService.ConfiguredCommands.Select(s => new ConfiguredCommandModel() { Name = s.Name, Type = s.GetType().Name, Id = s.Id }).ToList(); + var sensors = await _configurationService.GetSensorsAfterLoadingAsync(); + var s = sensors.FirstOrDefault(x => id == x.Id); + if (s == null) + return null; + else + { + if (!Enum.TryParse(s.GetType().Name, out AvailableSensors type)) + Log.Logger.Error("Unknown sensor"); + + return new ConfiguredSensorModel() + { + Name = s.Name, + Type = type, + Value = s.PreviousPublishedState, + Id = s.Id, + UpdateInterval = s.UpdateInterval, + UnitOfMeasurement = ((SensorDiscoveryConfigModel)s.GetAutoDiscoveryConfig()).Unit_of_measurement + }; + } } - public void RemoveCommandById(Guid id) + + public List GetConfiguredCommands() { - this._configurationService.DeleteConfiguredCommand(id); + return _configurationService.ConfiguredCommands.Select(s => + { + if (!Enum.TryParse(s.GetType().Name, out AvailableCommands type)) + Log.Logger.Error("Unknown command"); + + return new ConfiguredCommandModel() + { + Name = s.Name, + Type = type, + Id = s.Id + }; + }).ToList(); } - public void RemoveSensorById(Guid id) + public ConfiguredCommandModel GetConfiguredCommand(Guid id) { - this._configurationService.DeleteConfiguredSensor(id); + var c = _configurationService.ConfiguredCommands.FirstOrDefault(x => id == x.Id); + if (c == null) + return null; + else + { + if (!Enum.TryParse(c.GetType().Name, out AvailableCommands type)) + Log.Logger.Error("Unknown command"); + + return new ConfiguredCommandModel() + { + Name = c.Name, + Type = type, + Id = c.Id + }; + } } + public void RemoveSensorById(Guid id) => _configurationService.DeleteConfiguredSensor(id); + + public void RemoveCommandById(Guid id) => _configurationService.DeleteConfiguredCommand(id); + /// /// Adds a command to the configured commands. This properly initializes the class and writes it to the config file. /// @@ -100,71 +140,12 @@ namespace hass_workstation_service.Communication.InterProcesCommunication /// public void AddSensor(AvailableSensors sensorType, string json) { - var serializerOptions = new JsonSerializerOptions - { - Converters = { new DynamicJsonConverter() } - }; - dynamic model = JsonSerializer.Deserialize(json, serializerOptions); + var sensorToCreate = GetSensorToCreate(sensorType, json); - AbstractSensor sensorToCreate = null; - switch (sensorType) - { - case AvailableSensors.UserNotificationStateSensor: - sensorToCreate = new UserNotificationStateSensor(this._publisher, (int)model.UpdateInterval, model.Name); - break; - case AvailableSensors.DummySensor: - sensorToCreate = new DummySensor(this._publisher, (int)model.UpdateInterval, model.Name); - break; - case AvailableSensors.CurrentClockSpeedSensor: - sensorToCreate = new CurrentClockSpeedSensor(this._publisher, (int)model.UpdateInterval, model.Name); - break; - case AvailableSensors.CPULoadSensor: - sensorToCreate = new CPULoadSensor(this._publisher, (int)model.UpdateInterval, model.Name); - break; - case AvailableSensors.WMIQuerySensor: - sensorToCreate = new WMIQuerySensor(this._publisher, model.Query, (int)model.UpdateInterval, model.Name); - break; - case AvailableSensors.MemoryUsageSensor: - sensorToCreate = new MemoryUsageSensor(this._publisher, (int)model.UpdateInterval, model.Name); - break; - case AvailableSensors.ActiveWindowSensor: - sensorToCreate = new ActiveWindowSensor(this._publisher, (int)model.UpdateInterval, model.Name); - break; - case AvailableSensors.WebcamActiveSensor: - sensorToCreate = new WebcamActiveSensor(this._publisher, (int)model.UpdateInterval, model.Name); - break; - case AvailableSensors.MicrophoneActiveSensor: - sensorToCreate = new MicrophoneActiveSensor(this._publisher, (int)model.UpdateInterval, model.Name); - break; - case AvailableSensors.NamedWindowSensor: - sensorToCreate = new NamedWindowSensor(this._publisher, model.WindowName, model.Name, (int)model.UpdateInterval); - break; - case AvailableSensors.LastActiveSensor: - sensorToCreate = new LastActiveSensor(this._publisher,(int)model.UpdateInterval, model.Name); - break; - case AvailableSensors.LastBootSensor: - sensorToCreate = new LastBootSensor(this._publisher, (int)model.UpdateInterval, model.Name); - break; - case AvailableSensors.SessionStateSensor: - sensorToCreate = new SessionStateSensor(this._publisher, (int)model.UpdateInterval, model.Name); - break; - case AvailableSensors.CurrentVolumeSensor: - sensorToCreate = new CurrentVolumeSensor(this._publisher, (int)model.UpdateInterval, model.Name); - break; - case AvailableSensors.GPUTemperatureSensor: - sensorToCreate = new GpuTemperatureSensor(this._publisher, (int)model.UpdateInterval, model.Name); - break; - case AvailableSensors.GPULoadSensor: - sensorToCreate = new GpuLoadSensor(this._publisher, (int)model.UpdateInterval, model.Name); - break; - default: - Log.Logger.Error("Unknown sensortype"); - break; - } - if (sensorToCreate != null) - { - this._configurationService.AddConfiguredSensor(sensorToCreate); - } + if (sensorToCreate == null) + Log.Logger.Error("Unknown sensortype"); + else + _configurationService.AddConfiguredSensor(sensorToCreate); } /// @@ -173,6 +154,38 @@ namespace hass_workstation_service.Communication.InterProcesCommunication /// /// public void AddCommand(AvailableCommands commandType, string json) + { + var commandToCreate = GetCommandToCreate(commandType, json); + + if (commandToCreate == null) + Log.Logger.Error("Unknown command type"); + else + _configurationService.AddConfiguredCommand(commandToCreate); + } + + public async void UpdateSensorById(Guid id, string json) + { + var existingSensor = await GetConfiguredSensor(id); + var sensorToUpdate = GetSensorToCreate(existingSensor.Type, json); + + if (sensorToUpdate == null) + Log.Logger.Error("Unknown sensortype"); + else + _configurationService.UpdateConfiguredSensor(id, sensorToUpdate); + } + + public void UpdateCommandById(Guid id, string json) + { + var existingCommand = GetConfiguredCommand(id); + var commandToUpdate = GetCommandToCreate(existingCommand.Type, json); + + if (commandToUpdate == null) + Log.Logger.Error("Unknown commandtype"); + else + _configurationService.UpdateConfiguredCommand(id, commandToUpdate); + } + + private AbstractSensor GetSensorToCreate(AvailableSensors sensorType, string json) { var serializerOptions = new JsonSerializerOptions { @@ -180,55 +193,51 @@ namespace hass_workstation_service.Communication.InterProcesCommunication }; dynamic model = JsonSerializer.Deserialize(json, serializerOptions); - AbstractCommand commandToCreate = null; - switch (commandType) - { - case AvailableCommands.ShutdownCommand: - commandToCreate = new ShutdownCommand(this._publisher, model.Name); - break; - case AvailableCommands.RestartCommand: - commandToCreate = new RestartCommand(this._publisher, model.Name); - break; - case AvailableCommands.LogOffCommand: - commandToCreate = new LogOffCommand(this._publisher, model.Name); - break; - case AvailableCommands.CustomCommand: - commandToCreate = new CustomCommand(this._publisher, model.Command, model.Name); - break; - case AvailableCommands.PlayPauseCommand: - commandToCreate = new MediaPlayPauseCommand(this._publisher, model.Name); - break; - case AvailableCommands.NextCommand: - commandToCreate = new MediaNextCommand(this._publisher, model.Name); - break; - case AvailableCommands.PreviousCommand: - commandToCreate = new MediaPreviousCommand(this._publisher, model.Name); - break; - case AvailableCommands.VolumeUpCommand: - commandToCreate = new MediaVolumeUpCommand(this._publisher, model.Name); - break; - case AvailableCommands.VolumeDownCommand: - commandToCreate = new MediaVolumeDownCommand(this._publisher, model.Name); - break; - case AvailableCommands.MuteCommand: - commandToCreate = new MediaMuteCommand(this._publisher, model.Name); - break; - case AvailableCommands.KeyCommand: - commandToCreate = new KeyCommand(this._publisher, Convert.ToByte(model.Key, 16), model.Name); - break; - default: - Log.Logger.Error("Unknown sensortype"); - break; - } - if (commandToCreate != null) + return sensorType switch { - this._configurationService.AddConfiguredCommand(commandToCreate); - } + AvailableSensors.UserNotificationStateSensor => new UserNotificationStateSensor(_publisher, (int)model.UpdateInterval, model.Name), + AvailableSensors.DummySensor => new DummySensor(_publisher, (int)model.UpdateInterval, model.Name), + AvailableSensors.CurrentClockSpeedSensor => new CurrentClockSpeedSensor(_publisher, (int)model.UpdateInterval, model.Name), + AvailableSensors.CPULoadSensor => new CPULoadSensor(_publisher, (int)model.UpdateInterval, model.Name), + AvailableSensors.WMIQuerySensor => new WMIQuerySensor(_publisher, model.Query, (int)model.UpdateInterval, model.Name), + AvailableSensors.MemoryUsageSensor => new MemoryUsageSensor(_publisher, (int)model.UpdateInterval, model.Name), + AvailableSensors.ActiveWindowSensor => new ActiveWindowSensor(_publisher, (int)model.UpdateInterval, model.Name), + AvailableSensors.WebcamActiveSensor => new WebcamActiveSensor(_publisher, (int)model.UpdateInterval, model.Name), + AvailableSensors.MicrophoneActiveSensor => new MicrophoneActiveSensor(_publisher, (int)model.UpdateInterval, model.Name), + AvailableSensors.NamedWindowSensor => new NamedWindowSensor(_publisher, model.WindowName, model.Name, (int)model.UpdateInterval), + AvailableSensors.LastActiveSensor => new LastActiveSensor(_publisher, (int)model.UpdateInterval, model.Name), + AvailableSensors.LastBootSensor => new LastBootSensor(_publisher, (int)model.UpdateInterval, model.Name), + AvailableSensors.SessionStateSensor => new SessionStateSensor(_publisher, (int)model.UpdateInterval, model.Name), + AvailableSensors.CurrentVolumeSensor => new CurrentVolumeSensor(_publisher, (int)model.UpdateInterval, model.Name), + AvailableSensors.GPUTemperatureSensor => new GpuTemperatureSensor(_publisher, (int)model.UpdateInterval, model.Name), + AvailableSensors.GPULoadSensor => new GpuLoadSensor(_publisher, (int)model.UpdateInterval, model.Name), + _ => null + }; } - public string GetCurrentVersion() + private AbstractCommand GetCommandToCreate(AvailableCommands commandType, string json) { - return Program.GetVersion(); + var serializerOptions = new JsonSerializerOptions + { + Converters = { new DynamicJsonConverter() } + }; + dynamic model = JsonSerializer.Deserialize(json, serializerOptions); + + return commandType switch + { + AvailableCommands.ShutdownCommand => new ShutdownCommand(_publisher, model.Name), + AvailableCommands.RestartCommand => new RestartCommand(_publisher, model.Name), + AvailableCommands.LogOffCommand => new LogOffCommand(_publisher, model.Name), + AvailableCommands.CustomCommand => new CustomCommand(_publisher, model.Command, model.Name), + AvailableCommands.PlayPauseCommand => new MediaPlayPauseCommand(_publisher, model.Name), + AvailableCommands.NextCommand => new MediaNextCommand(_publisher, model.Name), + AvailableCommands.PreviousCommand => new MediaPreviousCommand(_publisher, model.Name), + AvailableCommands.VolumeUpCommand => new MediaVolumeUpCommand(_publisher, model.Name), + AvailableCommands.VolumeDownCommand => new MediaVolumeDownCommand(_publisher, model.Name), + AvailableCommands.MuteCommand => new MediaMuteCommand(_publisher, model.Name), + AvailableCommands.KeyCommand => new KeyCommand(_publisher, Convert.ToByte(model.Key, 16), model.Name), + _ => null + }; } } -} +} \ No newline at end of file From ef7fda640b8ccecdfe9b032992444a5d3778943c Mon Sep 17 00:00:00 2001 From: Stefan Roelofs Date: Sat, 27 Mar 2021 10:20:15 +0100 Subject: [PATCH 06/13] changed a line ending --- hass-workstation-service/Data/ConfigurationService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hass-workstation-service/Data/ConfigurationService.cs b/hass-workstation-service/Data/ConfigurationService.cs index e6802a0..40a862a 100644 --- a/hass-workstation-service/Data/ConfigurationService.cs +++ b/hass-workstation-service/Data/ConfigurationService.cs @@ -422,7 +422,7 @@ namespace hass_workstation_service.Data return; } await commandToRemove.UnPublishAutoDiscoveryConfigAsync(); - ConfiguredCommands.Remove(commandToRemove); + ConfiguredCommands.Remove(commandToRemove); } /// From 9b21ad61375d4f0c0150025f8c39b6dfccd56794 Mon Sep 17 00:00:00 2001 From: Stefan Roelofs Date: Sat, 27 Mar 2021 20:17:09 +0100 Subject: [PATCH 07/13] Remove reference to empty directory --- UserInterface/UserInterface.csproj | 1 - 1 file changed, 1 deletion(-) diff --git a/UserInterface/UserInterface.csproj b/UserInterface/UserInterface.csproj index 342d878..633f585 100644 --- a/UserInterface/UserInterface.csproj +++ b/UserInterface/UserInterface.csproj @@ -5,7 +5,6 @@ UserInterface.Program - From f6261d0f4503a5d10e542d1cec34813e806730b3 Mon Sep 17 00:00:00 2001 From: Stefan Roelofs Date: Sat, 27 Mar 2021 23:22:34 +0100 Subject: [PATCH 08/13] Add missing method to interface --- .../InterProcesCommunication/IServiceContractInterfaces.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/hass-workstation-service/Communication/InterProcesCommunication/IServiceContractInterfaces.cs b/hass-workstation-service/Communication/InterProcesCommunication/IServiceContractInterfaces.cs index 51e2fdd..4252e75 100644 --- a/hass-workstation-service/Communication/InterProcesCommunication/IServiceContractInterfaces.cs +++ b/hass-workstation-service/Communication/InterProcesCommunication/IServiceContractInterfaces.cs @@ -22,6 +22,7 @@ namespace hass_workstation_service.Communication.NamedPipe List GetConfiguredCommands(); void AddCommand(AvailableCommands commandType, string json); void RemoveCommandById(Guid id); + void UpdateCommandById(Guid id, string json); string GetCurrentVersion(); } } \ No newline at end of file From 76b7d05fd7afb37bb1021485389317ccf275c213 Mon Sep 17 00:00:00 2001 From: Stefan Roelofs Date: Sat, 27 Mar 2021 23:23:35 +0100 Subject: [PATCH 09/13] Small delay between deleting sensor and adding sensor. I think that the mqtt update works better because of this. --- hass-workstation-service/Data/ConfigurationService.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/hass-workstation-service/Data/ConfigurationService.cs b/hass-workstation-service/Data/ConfigurationService.cs index 40a862a..7965764 100644 --- a/hass-workstation-service/Data/ConfigurationService.cs +++ b/hass-workstation-service/Data/ConfigurationService.cs @@ -377,6 +377,7 @@ namespace hass_workstation_service.Data public async void UpdateConfiguredSensor(Guid id, AbstractSensor sensor) { await DeleteSensor(id); + await Task.Delay(500); AddSensor(sensor); WriteSensorSettingsAsync(); } From bdbce79e386d31a91265b79f998ff58e6276cd4e Mon Sep 17 00:00:00 2001 From: Stefan Roelofs Date: Sat, 27 Mar 2021 23:24:40 +0100 Subject: [PATCH 10/13] ViewModel updates --- .../ViewModels/AddCommandViewModel.cs | 36 +++++--------- .../ViewModels/AddSensorViewModel.cs | 48 +++++++------------ .../ViewModels/CommandSettingsViewModel.cs | 17 ++++--- .../ViewModels/SensorSettingsViewModel.cs | 36 +++++++------- 4 files changed, 58 insertions(+), 79 deletions(-) diff --git a/UserInterface/ViewModels/AddCommandViewModel.cs b/UserInterface/ViewModels/AddCommandViewModel.cs index 133bfca..31d593a 100644 --- a/UserInterface/ViewModels/AddCommandViewModel.cs +++ b/UserInterface/ViewModels/AddCommandViewModel.cs @@ -1,34 +1,24 @@ using hass_workstation_service.Communication.InterProcesCommunication.Models; using ReactiveUI; -using System; -using System.Collections.Generic; -using System.Text; namespace UserInterface.ViewModels { public class AddCommandViewModel : ViewModelBase { - private AvailableCommands selectedType; - private string description; + private AvailableCommands _selectedType; + private string _name; + private string _description; + private bool _showCommandInput; + private bool _showKeyInput; + private string _moreInfoLink; - public string Description { get => description; set => this.RaiseAndSetIfChanged(ref description, value); } - public bool ShowCommandInput { get => showCommandInput; set => this.RaiseAndSetIfChanged(ref showCommandInput, value); } - public bool ShowKeyInput { get => showKeyInput; set => this.RaiseAndSetIfChanged(ref showKeyInput, value); } - - private string moreInfoLink; - private bool showCommandInput; - private bool showKeyInput; - - public string MoreInfoLink - { - get { return moreInfoLink; } - set { this.RaiseAndSetIfChanged(ref moreInfoLink, value); } - } - - public AvailableCommands SelectedType { get => selectedType; set => this.RaiseAndSetIfChanged(ref selectedType, value); } - - public string Name { get; set; } + public AvailableCommands SelectedType { get => _selectedType; set => this.RaiseAndSetIfChanged(ref _selectedType, value); } + public string Name { get => _name; set => this.RaiseAndSetIfChanged(ref _name, value); } + public string Description { get => _description; set => this.RaiseAndSetIfChanged(ref _description, value); } + public bool ShowCommandInput { get => _showCommandInput; set => this.RaiseAndSetIfChanged(ref _showCommandInput, value); } + public bool ShowKeyInput { get => _showKeyInput; set => this.RaiseAndSetIfChanged(ref _showKeyInput, value); } + public string MoreInfoLink { get => _moreInfoLink; set => this.RaiseAndSetIfChanged(ref _moreInfoLink, value); } public string Command { get; set; } public string Key { get; set; } } -} +} \ No newline at end of file diff --git a/UserInterface/ViewModels/AddSensorViewModel.cs b/UserInterface/ViewModels/AddSensorViewModel.cs index e3303f6..6c04b9a 100644 --- a/UserInterface/ViewModels/AddSensorViewModel.cs +++ b/UserInterface/ViewModels/AddSensorViewModel.cs @@ -1,40 +1,28 @@ using hass_workstation_service.Communication.InterProcesCommunication.Models; using ReactiveUI; -using System; -using System.Collections.Generic; -using System.Text; namespace UserInterface.ViewModels { public class AddSensorViewModel : ViewModelBase { - private AvailableSensors selectedType; - private string description; - private bool showQueryInput; - - public string Description { get => description; set => this.RaiseAndSetIfChanged(ref description, value); } - public bool ShowQueryInput { get => showQueryInput; set => this.RaiseAndSetIfChanged(ref showQueryInput, value); } - public bool ShowWindowNameInput { get => showWindowNameInput; set => this.RaiseAndSetIfChanged(ref showWindowNameInput, value); } - - public bool ShowDetectionModeOptions { get => showDetectionModeOptions; set => this.RaiseAndSetIfChanged(ref showDetectionModeOptions, value); } - - private string moreInfoLink; - private int updateInterval; - private bool showWindowNameInput; - private bool showDetectionModeOptions; - - public string MoreInfoLink - { - get { return moreInfoLink; } - set { this.RaiseAndSetIfChanged(ref moreInfoLink, value); } - } - - - public AvailableSensors SelectedType { get => selectedType; set => this.RaiseAndSetIfChanged(ref selectedType, value); } - - public string Name { get; set; } + private AvailableSensors _selectedType; + private string _name; + private int _updateInterval; + private string _description; + private bool _showQueryInput; + private bool _showWindowNameInput; + private bool _showDetectionModeOptions; + private string _moreInfoLink; + + public AvailableSensors SelectedType { get => _selectedType; set => this.RaiseAndSetIfChanged(ref _selectedType, value); } + public string Name { get => _name; set => this.RaiseAndSetIfChanged(ref _name, value); } + public int UpdateInterval { get => _updateInterval; set => this.RaiseAndSetIfChanged(ref _updateInterval, value); } + public string Description { get => _description; set => this.RaiseAndSetIfChanged(ref _description, value); } + public bool ShowQueryInput { get => _showQueryInput; set => this.RaiseAndSetIfChanged(ref _showQueryInput, value); } + public bool ShowWindowNameInput { get => _showWindowNameInput; set => this.RaiseAndSetIfChanged(ref _showWindowNameInput, value); } + public bool ShowDetectionModeOptions { get => _showDetectionModeOptions; set => this.RaiseAndSetIfChanged(ref _showDetectionModeOptions, value); } + public string MoreInfoLink { get => _moreInfoLink; set => this.RaiseAndSetIfChanged(ref _moreInfoLink, value); } public string Query { get; set; } public string WindowName { get; set; } - public int UpdateInterval { get => updateInterval; set => this.RaiseAndSetIfChanged(ref updateInterval, value); } } -} +} \ No newline at end of file diff --git a/UserInterface/ViewModels/CommandSettingsViewModel.cs b/UserInterface/ViewModels/CommandSettingsViewModel.cs index 4477508..ac7eb8a 100644 --- a/UserInterface/ViewModels/CommandSettingsViewModel.cs +++ b/UserInterface/ViewModels/CommandSettingsViewModel.cs @@ -1,15 +1,20 @@ -using ReactiveUI; +using hass_workstation_service.Communication.InterProcesCommunication.Models; +using ReactiveUI; using System; using System.Collections.Generic; -using System.Text; namespace UserInterface.ViewModels { public class CommandSettingsViewModel : ViewModelBase { - private ICollection configuredCommands; + private ICollection _configuredCommands; + + public ICollection ConfiguredCommands + { + get => _configuredCommands; + set => this.RaiseAndSetIfChanged(ref _configuredCommands, value); + } - public ICollection ConfiguredCommands { get => configuredCommands; set => this.RaiseAndSetIfChanged(ref configuredCommands, value); } public void TriggerUpdate() { this.RaisePropertyChanged(); @@ -19,7 +24,7 @@ namespace UserInterface.ViewModels public class CommandViewModel : ViewModelBase { public Guid Id { get; set; } - public string Type { get; set; } + public AvailableCommands Type { get; set; } public string Name { get; set; } } -} +} \ No newline at end of file diff --git a/UserInterface/ViewModels/SensorSettingsViewModel.cs b/UserInterface/ViewModels/SensorSettingsViewModel.cs index 1939bf6..2a52fd0 100644 --- a/UserInterface/ViewModels/SensorSettingsViewModel.cs +++ b/UserInterface/ViewModels/SensorSettingsViewModel.cs @@ -1,15 +1,20 @@ -using ReactiveUI; +using hass_workstation_service.Communication.InterProcesCommunication.Models; +using ReactiveUI; using System; using System.Collections.Generic; -using System.Text; namespace UserInterface.ViewModels { public class SensorSettingsViewModel : ViewModelBase { - private ICollection configuredSensors; + private ICollection _configuredSensors; + + public ICollection ConfiguredSensors + { + get => _configuredSensors; + set => this.RaiseAndSetIfChanged(ref _configuredSensors, value); + } - public ICollection ConfiguredSensors { get => configuredSensors; set => this.RaiseAndSetIfChanged(ref configuredSensors, value); } public void TriggerUpdate() { this.RaisePropertyChanged(); @@ -21,30 +26,21 @@ namespace UserInterface.ViewModels private string _value; public Guid Id { get; set; } - public string Type { get; set; } + public AvailableSensors Type { get; set; } public string Name { get; set; } public int UpdateInterval { get; set; } public string Value { - get => _value; set + get => _value; + set { this.RaiseAndSetIfChanged(ref _value, value); - this.RaisePropertyChanged("ValueString"); + this.RaisePropertyChanged(nameof(ValueString)); } } + public string UnitOfMeasurement { get; set; } - public string ValueString - { - get - { - if (!string.IsNullOrWhiteSpace(_value)) - { - return _value + " " + UnitOfMeasurement; - } - else return ""; - - } - } + public string ValueString => string.IsNullOrWhiteSpace(_value) ? string.Empty : $"{_value} {UnitOfMeasurement}"; } -} +} \ No newline at end of file From dfb671a7ee4912fd0a3dd6fd3a163faa2573ca15 Mon Sep 17 00:00:00 2001 From: Stefan Roelofs Date: Sat, 27 Mar 2021 23:26:33 +0100 Subject: [PATCH 11/13] Update views --- UserInterface/Views/AddCommandDialog.axaml | 34 +++--- UserInterface/Views/AddCommandDialog.axaml.cs | 93 +++++++++++----- UserInterface/Views/AddSensorDialog.axaml | 40 +++---- UserInterface/Views/AddSensorDialog.axaml.cs | 76 +++++++++---- UserInterface/Views/CommandSettings.axaml | 2 +- UserInterface/Views/CommandSettings.axaml.cs | 103 ++++++++++-------- UserInterface/Views/SensorSettings.axaml | 2 +- UserInterface/Views/SensorSettings.axaml.cs | 38 ++++--- 8 files changed, 239 insertions(+), 149 deletions(-) diff --git a/UserInterface/Views/AddCommandDialog.axaml b/UserInterface/Views/AddCommandDialog.axaml index dc2e967..30bdcf7 100644 --- a/UserInterface/Views/AddCommandDialog.axaml +++ b/UserInterface/Views/AddCommandDialog.axaml @@ -5,24 +5,26 @@ mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" x:Class="UserInterface.Views.AddCommandDialog" SizeToContent="WidthAndHeight" - Title="Add command"> - - Command type + Title="Add / edit command"> + + Command type - - - - Name - + + + + Name + - - Command - - Key - - - - + + Command + + Key + + + + + + diff --git a/UserInterface/Views/AddCommandDialog.axaml.cs b/UserInterface/Views/AddCommandDialog.axaml.cs index fbf0974..45005e2 100644 --- a/UserInterface/Views/AddCommandDialog.axaml.cs +++ b/UserInterface/Views/AddCommandDialog.axaml.cs @@ -7,7 +7,6 @@ using hass_workstation_service.Communication.NamedPipe; using JKang.IpcServiceFramework.Client; using Microsoft.Extensions.DependencyInjection; using System; -using System.Dynamic; using System.Linq; using System.Text.Json; using UserInterface.Util; @@ -17,16 +16,25 @@ namespace UserInterface.Views { public class AddCommandDialog : Window { - private readonly IIpcClient client; - public ComboBox comboBox { get; set; } - public ComboBox detectionModecomboBox { get; set; } + private readonly IIpcClient _client; + public ComboBox ComboBox { get; set; } + public ComboBox DetectionModecomboBox { get; set; } + public Guid CommandId { get; } + + public AddCommandDialog(Guid commandId) : this() + { + CommandId = commandId; + GetCommandInfo(CommandId); + Title = "Edit command"; + } + public AddCommandDialog() { - this.InitializeComponent(); + InitializeComponent(); DataContext = new AddCommandViewModel(); - this.comboBox = this.FindControl("ComboBox"); - this.comboBox.Items = Enum.GetValues(typeof(AvailableCommands)).Cast().OrderBy(v => v.ToString()); - this.comboBox.SelectedIndex = 0; + ComboBox = this.FindControl("ComboBox"); + ComboBox.Items = Enum.GetValues(typeof(AvailableCommands)).Cast().OrderBy(v => v.ToString()); + ComboBox.SelectedIndex = 0; // register IPC clients ServiceProvider serviceProvider = new ServiceCollection() @@ -38,22 +46,53 @@ namespace UserInterface.Views .GetRequiredService>(); // create client - this.client = clientFactory.CreateClient("addCommand"); + _client = clientFactory.CreateClient("addCommand"); + Title = "Add sensor"; + + } + + private void InitializeComponent() + { + AvaloniaXamlLoader.Load(this); + } + + private async void GetCommandInfo(Guid commandId) + { + var command = await _client.InvokeAsync(x => x.GetConfiguredCommand(commandId)); + + ComboBox.SelectedItem = command.Type; + FillDefaultValues(); + ComboBox.IsEnabled = false; + var item = (AddCommandViewModel)DataContext; + item.SelectedType = command.Type; + item.Name = command.Name; + //item.UpdateInterval = command.UpdateInterval; + //item.WindowName = + //item.Query = } public async void Save(object sender, RoutedEventArgs args) { - var item = ((AddCommandViewModel)this.DataContext); - dynamic model = new { item.Name, item.Command, item.Key}; + var item = (AddCommandViewModel)DataContext; + dynamic model = new { item.Name, item.Command, item.Key }; string json = JsonSerializer.Serialize(model); - await this.client.InvokeAsync(x => x.AddCommand(item.SelectedType, json)); + if (CommandId == Guid.Empty) + await _client.InvokeAsync(x => x.AddCommand(item.SelectedType, json)); + else + await _client.InvokeAsync(x => x.UpdateCommandById(CommandId, json)); + Close(); } public void ComboBoxClosed(object sender, SelectionChangedEventArgs args) { - var item = ((AddCommandViewModel)this.DataContext); - switch (this.comboBox.SelectedItem) + FillDefaultValues(); + } + + private void FillDefaultValues() + { + var item = (AddCommandViewModel)DataContext; + switch (ComboBox.SelectedItem) { case AvailableCommands.CustomCommand: item.Description = "This command lets you execute any command you want. It will run in a Windows Command Prompt silently. "; @@ -129,28 +168,26 @@ namespace UserInterface.Views break; } } - public void OpenInfo(object sender, RoutedEventArgs args) + + public void OpenInfo(object sender, RoutedEventArgs args) { - var item = ((AddCommandViewModel)this.DataContext); + var item = (AddCommandViewModel)DataContext; BrowserUtil.OpenBrowser(item.MoreInfoLink); } public void Test(object sender, RoutedEventArgs args) { - var item = ((AddCommandViewModel)this.DataContext); + var item = (AddCommandViewModel)DataContext; - System.Diagnostics.Process process = new System.Diagnostics.Process(); - System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo(); - startInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Normal; - startInfo.FileName = "cmd.exe"; - startInfo.Arguments = $"/k {"echo You won't see this window normally. &&" + item.Command}"; + var process = new System.Diagnostics.Process(); + var startInfo = new System.Diagnostics.ProcessStartInfo + { + WindowStyle = System.Diagnostics.ProcessWindowStyle.Normal, + FileName = "cmd.exe", + Arguments = $"/k {"echo You won't see this window normally. &&" + item.Command}" + }; process.StartInfo = startInfo; process.Start(); } - - private void InitializeComponent() - { - AvaloniaXamlLoader.Load(this); - } } -} +} \ No newline at end of file diff --git a/UserInterface/Views/AddSensorDialog.axaml b/UserInterface/Views/AddSensorDialog.axaml index 10d62ec..8b3b295 100644 --- a/UserInterface/Views/AddSensorDialog.axaml +++ b/UserInterface/Views/AddSensorDialog.axaml @@ -5,27 +5,27 @@ mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" x:Class="UserInterface.Views.AddSensorDialog" SizeToContent="WidthAndHeight" - Title="Add sensor"> - - Sensor type + Title="Add / edit sensor"> + + Sensor type - - - - Name - + + + + Name + - Update interval - - - - - - Query - - Window name - This is case-insensitive and loosely matched. A window called "Spotify Premium" will match "spotify" or "premium". - + Update interval + + + + + + Query + + Window name + This is case-insensitive and loosely matched. A window called "Spotify Premium" will match "spotify" or "premium". + - + diff --git a/UserInterface/Views/AddSensorDialog.axaml.cs b/UserInterface/Views/AddSensorDialog.axaml.cs index 024e78a..9b5d82f 100644 --- a/UserInterface/Views/AddSensorDialog.axaml.cs +++ b/UserInterface/Views/AddSensorDialog.axaml.cs @@ -7,7 +7,6 @@ using hass_workstation_service.Communication.NamedPipe; using JKang.IpcServiceFramework.Client; using Microsoft.Extensions.DependencyInjection; using System; -using System.Dynamic; using System.Linq; using System.Text.Json; using UserInterface.Util; @@ -17,16 +16,25 @@ namespace UserInterface.Views { public class AddSensorDialog : Window { - private readonly IIpcClient client; - public ComboBox comboBox { get; set; } - public ComboBox detectionModecomboBox { get; set; } + private readonly IIpcClient _client; + public ComboBox ComboBox { get; set; } + public ComboBox DetectionModecomboBox { get; set; } + public Guid SensorId { get; } + + public AddSensorDialog(Guid sensorId) : this() + { + SensorId = sensorId; + GetSensorInfo(SensorId); + Title = "Edit sensor"; + } + public AddSensorDialog() { - this.InitializeComponent(); + InitializeComponent(); DataContext = new AddSensorViewModel(); - this.comboBox = this.FindControl("ComboBox"); - this.comboBox.Items = Enum.GetValues(typeof(AvailableSensors)).Cast().OrderBy(v => v.ToString()); - this.comboBox.SelectedIndex = 0; + ComboBox = this.FindControl("ComboBox"); + ComboBox.Items = Enum.GetValues(typeof(AvailableSensors)).Cast().OrderBy(v => v.ToString()); + ComboBox.SelectedIndex = 0; // register IPC clients ServiceProvider serviceProvider = new ServiceCollection() @@ -38,22 +46,52 @@ namespace UserInterface.Views .GetRequiredService>(); // create client - this.client = clientFactory.CreateClient("addsensor"); + _client = clientFactory.CreateClient("addsensor"); + Title = "Add sensor"; + } + + private void InitializeComponent() + { + AvaloniaXamlLoader.Load(this); + } + + private async void GetSensorInfo(Guid sensorId) + { + var sensor = await _client.InvokeAsync(x => x.GetConfiguredSensor(sensorId)); + + ComboBox.SelectedItem = sensor.Type; + FillDefaultValues(); + ComboBox.IsEnabled = false; + var item = (AddSensorViewModel)DataContext; + item.SelectedType = sensor.Type; + item.Name = sensor.Name; + item.UpdateInterval = sensor.UpdateInterval; + //item.WindowName = + //item.Query = } public async void Save(object sender, RoutedEventArgs args) { - var item = ((AddSensorViewModel)this.DataContext); - dynamic model = new { item.Name, item.Query, item.UpdateInterval, item.WindowName}; + var item = (AddSensorViewModel)DataContext; + dynamic model = new { item.Name, item.Query, item.UpdateInterval, item.WindowName }; string json = JsonSerializer.Serialize(model); - await this.client.InvokeAsync(x => x.AddSensor(item.SelectedType, json)); + if (SensorId == Guid.Empty) + await _client.InvokeAsync(x => x.AddSensor(item.SelectedType, json)); + else + await _client.InvokeAsync(x => x.UpdateSensorById(SensorId, json)); + Close(); } public void ComboBoxClosed(object sender, SelectionChangedEventArgs args) { - var item = ((AddSensorViewModel)this.DataContext); - switch (this.comboBox.SelectedItem) + FillDefaultValues(); + } + + private void FillDefaultValues() + { + var item = (AddSensorViewModel)DataContext; + switch (ComboBox.SelectedItem) { case AvailableSensors.UserNotificationStateSensor: item.Description = "This sensor watches the UserNotificationState. This is normally used in applications to determine if it is appropriate to send a notification but we can use it to expose this state. \n "; @@ -181,15 +219,11 @@ namespace UserInterface.Views break; } } + public void OpenInfo(object sender, RoutedEventArgs args) { - var item = ((AddSensorViewModel)this.DataContext); + var item = (AddSensorViewModel)DataContext; BrowserUtil.OpenBrowser(item.MoreInfoLink); } - - private void InitializeComponent() - { - AvaloniaXamlLoader.Load(this); - } } -} +} \ No newline at end of file diff --git a/UserInterface/Views/CommandSettings.axaml b/UserInterface/Views/CommandSettings.axaml index 6998808..0bc4aac 100644 --- a/UserInterface/Views/CommandSettings.axaml +++ b/UserInterface/Views/CommandSettings.axaml @@ -22,7 +22,7 @@