diff --git a/README.md b/README.md index faeeb4f..932310b 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ Not convinced yet? Check out [this excellent video](https://youtu.be/D5A7le79R5M ## Installation You can get the installer from [here](https://hassworkstationstorage.z6.web.core.windows.net/publish/setup.exe). When using the installer, the application checks for updates on startup. This is the recommended way to install for most users. -Note: You'll get a Windows Smartscreen warning because the code was self signed. You can click "More info" and then "Run anyway" to proceed with installing. +Note: You'll get a Windows Smartscreen warning because the code was self signed. You can click "More info" and then "Run anyway" to proceed with installing. If you get an error stating your system's settings not allowing installation, please refer to [this StackOverflow answer](https://superuser.com/a/1252757). ### Standalone @@ -47,14 +47,14 @@ Find us on [Discord](https://discord.gg/VraYT2N3wd), or check out the [frequentl ## Development -Want to develop or build the application yourself? Make sure to install the .NET Runtime [.NET 5 Runtime](https://dotnet.microsoft.com/download/dotnet/current/runtime) and [.NET 5 SDK](https://dotnet.microsoft.com/download/dotnet/current). Run the following commands from the `hass-workstation-service\hass-workstation-service` directory to get you started: +If you want to help develop Hass Workstation service, make sure to install the .NET Runtime [.NET 5 Runtime](https://dotnet.microsoft.com/download/dotnet/current/runtime) and [.NET 5 SDK](https://dotnet.microsoft.com/download/dotnet/current). Run the following commands from the `hass-workstation-service\hass-workstation-service` directory to get you started: ```` powershell dotnet build dotnet publish ```` -In case you are using Visual Studio Code, open the `hass-workstation-service\hass-workstation-service` folder to take advantage of the predefined build and publish tasks. +If you are using [Visual Studio](https://visualstudio.microsoft.com/), open the `hass-workstation-service\hass-workstation-service` folder to take advantage of the predefined build and publish tasks, alternatively you can open the project directly from github using the green download button to use the integrated git tools. ## Sensors @@ -62,151 +62,25 @@ The application provides several sensors. Sensors can be configured with a name Sensors publish their state on their own interval which you can configure and only publish when the state changes. -### UserNotificationState +Here is a list of the most commonly used sensors with the full documentation [here](https://github.com/sleevezipper/hass-workstation-service/blob/master/documentation/Sensors.md): -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. Notice that this status does not watch Focus Assist. It has the following possible states: - -|State|Explanation| -|---|---| -|NotPresent|A screen saver is displayed, the machine is locked, or a nonactive Fast User Switching session is in progress. | -|Busy|A full-screen application is running or Presentation Settings are applied. Presentation Settings allow a user to put their machine into a state fit for an uninterrupted presentation, such as a set of PowerPoint slides, with a single click.| -|RunningDirect3dFullScreen|A full-screen (exclusive mode) Direct3D application is running.| -|PresentationMode|The user has activated Windows presentation settings to block notifications and pop-up messages.| -|AcceptsNotifications|None of the other states are found, notifications can be freely sent.| -|QuietTime|Introduced in Windows 7. The current user is in "quiet time", which is the first hour after a new user logs into his or her account for the first time. During this time, most notifications should not be sent or shown. This lets a user become accustomed to a new computer system without those distractions. Quiet time also occurs for each user after an operating system upgrade or clean installation.| -|RunningWindowsStoreApp|A Windows Store app is running.| - -### ActiveWindow - -This sensor exposes the name of the currently focused window. - -### WebcamActive - -This sensor shows if the webcam is currently being used. It uses the Windows registry to check will work from Windows 10 version 1903 and higher. - -### MicrophoneActive - -This sensor shows if the microphone is currently being used. It uses the Windows registry to check and will work from Windows 10 version 1903 and higher. - -### CPULoad - -This sensor checks the current CPU load. It averages the load on all logical cores every second and rounds the output to two decimals. - -### GPULoad - -This sensor returns the current GPU load. This should work for both NVidia and AMD GPU's. - -### GPUTemperature - -This sensor returns the current temperature of the GPU in °C. This should work for both NVidia and AMD GPU's. - -### UsedMemory - -This sensor calculates the percentage of used memory. - -### CurrentClockSpeed - -This sensor returns the BIOS configured baseclock for the processor. - -### WMIQuery - -This advanced sensor executes a user defined [WMI query](https://docs.microsoft.com/en-us/windows/win32/wmisdk/wmi-and-sql) and exposes the result. The query should return a single value. - -For example: - -```sql -SELECT * FROM Win32_Processor -``` - -returns - -`|64|9|To Be Filled By O.E.M.|3|Intel64 Family 6 Model 94 Stepping 3|252|1|Win32_Processor|4008|12|64|Intel64 Family 6 Model 94 Stepping 3|CPU0|100|198|1024|8192|0|6|4|GenuineIntel|4008|Intel(R) Core(TM) i7-6700K CPU @ 4.00GHz|4|4|8|To Be Filled By O.E.M.|False|BFEBFBFF000506E3|3|24067|CPU|False|To Be Filled By O.E.M.|U3E1|OK|3|Win32_ComputerSystem|GAME-PC-2016|8|1|False|False|` - -This cannot not be used for this sensor. Instead try - -```sql -SELECT CurrentClockSpeed FROM Win32_Processor -``` - -which results in `4008` for my PC. - -You can use [WMI Explorer](https://github.com/vinaypamnani/wmie2/tree/v2.0.0.2) to find see what data is available. - -Here's some queries from other users: - -|Query|Explanation|Thanks| -|---|---|---| -|`SELECT username FROM Win32_ComputerSystem`|Shows the current user|@grizzlyjere| - -Want to add you query here? Please create a pull request or open an issue. - -### LastActive - -This sensor returns the date/time that the workstation was last active. Typing or moving your mouse will reset the date/time. - -### LastBoot - -This sensor returns the date/time that Windows was last booted. - -### SessionState - -This sensor returns the current session state. It has the following possible states: - -|State|Explanation| +|sensor|use| |---|---| -|Locked|All user sessions are locked.| -|LoggedOff|No users are logged in.| -|InUse|A user is currently logged in.| -|Unknown|Something went wrong while getting the status.| - -### CurrentVolume - -This sensor returns the volume of the currently playing audio. So if you're listening to music and you pause, this sensor will return 0 (or at least a very low value). - -### Dummy - -This sensor spits out a random number every second. Useful for testing, maybe you'll find some other use for it. +|ActiveWindow|Exposes the currently selected window| +|WebcamActive|Exposes the microphone state| +|MicrophoneActive|Exposes the webcam state| ## Commands -Commands can be used to trigger certain things on the client. For each command, a switch will be available in Home Assistant. Turning on the switch fires the command on the client and it will turn the switch off when it's done. Turning it off will cancel the running command. - -### ShutdownCommand - -This command shuts down the computer immediately. It runs `shutdown /s`. - -### RestartCommand - -This command restarts the computer immediately. It runs `shutdown /r`. - -### LogOffCommand - -This command logs off the current user. It runs `shutdown /l`. +This application allows you to send commands over MQTT to control the host system, and will be exposed using [MQTT discovery](https://www.home-assistant.io/docs/mqtt/discovery/). Alternatively you can directly send a command from Home Assistant using this topic : `homeassistant/switch/{DeviceName}/{Name}/set`, with the payload `ON`. -### CustomCommand +Here is a list of the most commonly used sensors with the full documentation [here](https://github.com/sleevezipper/hass-workstation-service/blob/master/documentation/Commands.md) -This command allows you to run any Windows Commands. The command will be run in a hidden Command Prompt. Some examples: - -|Command|Explanation| +|command|use| |---|---| -|Rundll32.exe user32.dll,LockWorkStation|This locks the current session.| -|shutdown /s /t 300|Shuts the PC down after 5 minutes (300 seconds).| -|C:\path\to\your\batchfile.bat|Run the specified batch file.| - -### KeyCommand - -Sends a keystroke with the specified key. You can pick [any of these](https://docs.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes) key codes. - -### Media Commands - -There's several media commands available which are very self exlanatory. - -- Play/Pause -- Next -- Previous -- Volume up -- Volume down -- Mute (toggle) +|ShutdownCommand|Shutdown the PC| +|RestartCommand|Restart the PC| +|MuteCommand|Mute the speakers| ## Credits diff --git a/UserInterface/UserInterface.csproj b/UserInterface/UserInterface.csproj index 342d878..73c7ed9 100644 --- a/UserInterface/UserInterface.csproj +++ b/UserInterface/UserInterface.csproj @@ -5,20 +5,19 @@ UserInterface.Program - - - - - - + + + + + - + @@ -33,6 +32,9 @@ BackgroundServiceSettings.axaml + + GeneralSettings.axaml + CommandSettings.axaml diff --git a/UserInterface/ViewModels/AddCommandViewModel.cs b/UserInterface/ViewModels/AddCommandViewModel.cs index 133bfca..8aa0633 100644 --- a/UserInterface/ViewModels/AddCommandViewModel.cs +++ b/UserInterface/ViewModels/AddCommandViewModel.cs @@ -1,34 +1,26 @@ 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; + private string _command; + private string _key; - 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 string Command { get; set; } - public string Key { 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 => _command; set => this.RaiseAndSetIfChanged(ref _command, value); } + public string Key { get => _key; set => this.RaiseAndSetIfChanged(ref _key, value); } } -} +} \ No newline at end of file diff --git a/UserInterface/ViewModels/AddSensorViewModel.cs b/UserInterface/ViewModels/AddSensorViewModel.cs index e3303f6..4e22e0f 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; } - public string Query { get; set; } - public string WindowName { get; set; } - public int UpdateInterval { get => updateInterval; set => this.RaiseAndSetIfChanged(ref updateInterval, value); } + private AvailableSensors _selectedType; + private string _name; + private int _updateInterval; + private string _description; + private bool _showQueryInput; + private bool _showWindowNameInput; + private string _moreInfoLink; + private string _query; + private string _windowName; + + 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 string MoreInfoLink { get => _moreInfoLink; set => this.RaiseAndSetIfChanged(ref _moreInfoLink, value); } + public string Query { get => _query; set => this.RaiseAndSetIfChanged(ref _query, value); } + public string WindowName { get => _windowName; set => this.RaiseAndSetIfChanged(ref _windowName, 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 @@ public void TriggerUpdate() 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/GeneralSettingsViewModel.cs b/UserInterface/ViewModels/GeneralSettingsViewModel.cs new file mode 100644 index 0000000..bda2e48 --- /dev/null +++ b/UserInterface/ViewModels/GeneralSettingsViewModel.cs @@ -0,0 +1,22 @@ +using hass_workstation_service.Communication.InterProcesCommunication.Models; +using hass_workstation_service.Data; +using ReactiveUI; +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Text; + +namespace UserInterface.ViewModels +{ + public class GeneralSettingsViewModel : ViewModelBase + { + private string namePrefix; + + public string NamePrefix { get => namePrefix; set => this.RaiseAndSetIfChanged(ref namePrefix, value); } + + public void Update(GeneralSettings settings) + { + this.NamePrefix = settings.NamePrefix; + } + } +} 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 @@ public class SensorViewModel : ViewModelBase 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 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 a1ed877..70a6ade 100644 --- a/UserInterface/Views/AddCommandDialog.axaml.cs +++ b/UserInterface/Views/AddCommandDialog.axaml.cs @@ -7,7 +7,6 @@ using JKang.IpcServiceFramework.Client; using Microsoft.Extensions.DependencyInjection; using System; -using System.Dynamic; using System.Linq; using System.Text.Json; using UserInterface.Util; @@ -17,107 +16,153 @@ 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() - .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"); + _client = clientFactory.CreateClient("addCommand"); + Title = "Add command"; + + } + + 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.Command = command.Command; + item.Key = command.Key; + } 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. "; - item.MoreInfoLink = "https://github.com/sleevezipper/hass-workstation-service#customcommand"; + item.MoreInfoLink = "https://github.com/sleevezipper/hass-workstation-service/blob/master/documentation/Commands.md#customcommand"; item.ShowCommandInput = true; item.ShowKeyInput = false; break; case AvailableCommands.ShutdownCommand: item.Description = "This command shuts down the PC immediately. "; - item.MoreInfoLink = "https://github.com/sleevezipper/hass-workstation-service#shutdowncommand"; + item.MoreInfoLink = "https://github.com/sleevezipper/hass-workstation-service/blob/master/documentation/Commands.md#shutdowncommand"; item.ShowCommandInput = false; item.ShowKeyInput = false; break; case AvailableCommands.RestartCommand: item.Description = "This command restarts the PC immediately. "; - item.MoreInfoLink = "https://github.com/sleevezipper/hass-workstation-service#restartcommand"; + item.MoreInfoLink = "https://github.com/sleevezipper/hass-workstation-service/blob/master/documentation/Commands.md#restartcommand"; + item.ShowCommandInput = false; + item.ShowKeyInput = false; + break; + case AvailableCommands.HibernateCommand: + item.Description = "This command hibernates the PC immediately. "; + item.MoreInfoLink = "https://github.com/sleevezipper/hass-workstation-service/blob/master/documentation/Commands.md#hibernatecommand"; item.ShowCommandInput = false; item.ShowKeyInput = false; break; case AvailableCommands.LogOffCommand: item.Description = "This command logs the current user off immediately. "; - item.MoreInfoLink = "https://github.com/sleevezipper/hass-workstation-service#logoffcommand"; + item.MoreInfoLink = "https://github.com/sleevezipper/hass-workstation-service/blob/master/documentation/Commands.md#logoffcommand"; item.ShowCommandInput = false; item.ShowKeyInput = false; break; case AvailableCommands.KeyCommand: item.Description = "This command can be used to emulate a keystroke. It requires a key code which you can find by clicking the info button below."; - item.MoreInfoLink = "https://github.com/sleevezipper/hass-workstation-service#keycommand"; + item.MoreInfoLink = "https://github.com/sleevezipper/hass-workstation-service/blob/master/documentation/Commands.md#keycommand"; item.ShowCommandInput = false; item.ShowKeyInput = true; break; case AvailableCommands.PlayPauseCommand: item.Description = "This command plays or pauses currently playing media."; - item.MoreInfoLink = "https://github.com/sleevezipper/hass-workstation-service#media-commands"; + item.MoreInfoLink = "https://github.com/sleevezipper/hass-workstation-service/blob/master/documentation/Commands.md#media-commands"; item.ShowCommandInput = false; item.ShowKeyInput = false; break; case AvailableCommands.NextCommand: item.Description = "This command skips to the next media."; - item.MoreInfoLink = "https://github.com/sleevezipper/hass-workstation-service#media-commands"; + item.MoreInfoLink = "https://github.com/sleevezipper/hass-workstation-service/blob/master/documentation/Commands.md#media-commands"; item.ShowCommandInput = false; item.ShowKeyInput = false; break; case AvailableCommands.PreviousCommand: item.Description = "This command plays previous media."; - item.MoreInfoLink = "https://github.com/sleevezipper/hass-workstation-service#media-commands"; + item.MoreInfoLink = "https://github.com/sleevezipper/hass-workstation-service/blob/master/documentation/Commands.md#media-commands"; item.ShowCommandInput = false; item.ShowKeyInput = false; break; case AvailableCommands.VolumeDownCommand: item.Description = "Lowers the system volume."; - item.MoreInfoLink = "https://github.com/sleevezipper/hass-workstation-service#media-commands"; + item.MoreInfoLink = "https://github.com/sleevezipper/hass-workstation-service/blob/master/documentation/Commands.md#media-commands"; item.ShowCommandInput = false; item.ShowKeyInput = false; break; case AvailableCommands.VolumeUpCommand: item.Description = "Raises the system volume."; - item.MoreInfoLink = "https://github.com/sleevezipper/hass-workstation-service#media-commands"; + item.MoreInfoLink = "https://github.com/sleevezipper/hass-workstation-service/blob/master/documentation/Commands.md#media-commands"; item.ShowCommandInput = false; item.ShowKeyInput = false; break; case AvailableCommands.MuteCommand: item.Description = "Toggles muting the system volume."; - item.MoreInfoLink = "https://github.com/sleevezipper/hass-workstation-service#media-commands"; + item.MoreInfoLink = "https://github.com/sleevezipper/hass-workstation-service/blob/master/documentation/Commands.md#media-commands"; item.ShowCommandInput = false; item.ShowKeyInput = false; break; @@ -129,28 +174,26 @@ public void ComboBoxClosed(object sender, SelectionChangedEventArgs args) 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 8c12a81..5d83bd7 100644 --- a/UserInterface/Views/AddSensorDialog.axaml.cs +++ b/UserInterface/Views/AddSensorDialog.axaml.cs @@ -7,7 +7,6 @@ using JKang.IpcServiceFramework.Client; using Microsoft.Extensions.DependencyInjection; using System; -using System.Dynamic; using System.Linq; using System.Text.Json; using UserInterface.Util; @@ -17,163 +16,219 @@ 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() - .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"); + _client = clientFactory.CreateClient("addsensor"); + Title = "Add sensor"; + } + + private void InitializeComponent() + { + AvaloniaXamlLoader.Load(this); + } + + private async void GetSensorInfo(Guid sensorId) + { + ConfiguredSensorModel 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.Query = sensor.Query; + item.WindowName = sensor.WindowName; + + Title = $"Edit {sensor.Name}"; } 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 "; - item.MoreInfoLink = "https://github.com/sleevezipper/hass-workstation-service#usernotificationstate"; - item.ShowDetectionModeOptions = false; + item.MoreInfoLink = "https://github.com/sleevezipper/hass-workstation-service/blob/master/documentation/Sensors.md#usernotificationstate"; item.ShowQueryInput = false; item.ShowWindowNameInput = false; item.UpdateInterval = 5; break; + case AvailableSensors.DummySensor: item.Description = "This sensor spits out a random number every second. Useful for testing, maybe you'll find some other use for it."; - item.MoreInfoLink = "https://github.com/sleevezipper/hass-workstation-service#dummy"; - item.ShowDetectionModeOptions = false; + item.MoreInfoLink = "https://github.com/sleevezipper/hass-workstation-service/blob/master/documentation/Sensors.md#dummysensor"; item.ShowQueryInput = false; item.ShowWindowNameInput = false; item.UpdateInterval = 1; break; + case AvailableSensors.CPULoadSensor: item.Description = "This sensor checks the current CPU load. It averages the load on all logical cores every second and rounds the output to two decimals."; - item.MoreInfoLink = "https://github.com/sleevezipper/hass-workstation-service#cpuload"; - item.ShowDetectionModeOptions = false; + item.MoreInfoLink = "https://github.com/sleevezipper/hass-workstation-service/blob/master/documentation/Sensors.md#cpuloadsensor"; item.ShowQueryInput = false; item.ShowWindowNameInput = false; item.UpdateInterval = 5; break; + case AvailableSensors.CurrentClockSpeedSensor: item.Description = "This sensor returns the BIOS configured baseclock for the processor."; - item.MoreInfoLink = "https://github.com/sleevezipper/hass-workstation-service#currentclockspeed"; - item.ShowDetectionModeOptions = false; + item.MoreInfoLink = "https://github.com/sleevezipper/hass-workstation-service/blob/master/documentation/Sensors.md#currentclockspeedsensor"; item.ShowQueryInput = false; item.ShowWindowNameInput = false; item.UpdateInterval = 3600; break; + case AvailableSensors.WMIQuerySensor: item.Description = "This advanced sensor executes a user defined WMI query and exposes the result. The query should return a single value."; - item.MoreInfoLink = "https://github.com/sleevezipper/hass-workstation-service#wmiquerysensor"; - item.ShowDetectionModeOptions = false; + item.MoreInfoLink = "https://github.com/sleevezipperhass-workstation-service/blob/master/documentation/WMIQuery.md#wmiquerysensor"; item.ShowQueryInput = true; item.ShowWindowNameInput = false; item.UpdateInterval = 10; break; + case AvailableSensors.MemoryUsageSensor: item.Description = "This sensor calculates the percentage of used memory."; - item.MoreInfoLink = "https://github.com/sleevezipper/hass-workstation-service#usedmemory"; - item.ShowDetectionModeOptions = false; + item.MoreInfoLink = "https://github.com/sleevezipper/hass-workstation-service/blob/master/documentation/Sensors.md#memoryusagesensorsensor"; item.ShowQueryInput = false; item.ShowWindowNameInput = false; item.UpdateInterval = 10; break; + case AvailableSensors.ActiveWindowSensor: item.Description = "This sensor exposes the name of the currently active window."; - item.MoreInfoLink = "https://github.com/sleevezipper/hass-workstation-service#activewindow"; - item.ShowDetectionModeOptions = false; + item.MoreInfoLink = "https://github.com/sleevezipper/hass-workstation-service/blob/master/documentation/Sensors.md#activewindowsensor"; item.ShowQueryInput = false; item.ShowWindowNameInput = false; item.UpdateInterval = 5; break; + case AvailableSensors.WebcamActiveSensor: item.Description = "This sensor shows if the webcam is currently being used."; - item.MoreInfoLink = "https://github.com/sleevezipper/hass-workstation-service#webcamactive"; - item.ShowDetectionModeOptions = true; + item.MoreInfoLink = "https://github.com/sleevezipper/hass-workstation-service/blob/master/documentation/Sensors.md#webcamactivesensor"; item.ShowQueryInput = false; item.UpdateInterval = 10; break; + case AvailableSensors.MicrophoneActiveSensor: item.Description = "This sensor shows if the microphone is currently in use."; - item.MoreInfoLink = "https://github.com/sleevezipper/hass-workstation-service#microphoneactive"; - item.ShowDetectionModeOptions = false; + item.MoreInfoLink = "https://github.com/sleevezipper/hass-workstation-service/blob/master/documentation/Sensors.md#microphoneactivesensor"; item.ShowQueryInput = false; item.UpdateInterval = 10; break; + case AvailableSensors.NamedWindowSensor: item.Description = "This sensor returns true if a window was found with the name you search for. "; - item.MoreInfoLink = "https://github.com/sleevezipper/hass-workstation-service#namedwindow"; + item.MoreInfoLink = "https://github.com/sleevezipper/hass-workstation-service/blob/master/documentation/Sensors.md#namedwindowsensor"; item.ShowQueryInput = false; item.ShowWindowNameInput = true; item.UpdateInterval = 5; break; + case AvailableSensors.LastActiveSensor: item.Description = "This sensor returns the date/time that the workstation was last active."; - item.MoreInfoLink = "https://github.com/sleevezipper/hass-workstation-service#lastactive"; + item.MoreInfoLink = "https://github.com/sleevezipper/hass-workstation-service/blob/master/documentation/Sensors.md#lastactivesensor"; item.ShowQueryInput = false; item.ShowWindowNameInput = false; item.UpdateInterval = 5; break; + case AvailableSensors.LastBootSensor: item.Description = "This sensor returns the date/time that Windows was last booted"; - item.MoreInfoLink = "https://github.com/sleevezipper/hass-workstation-service#lastboot"; + item.MoreInfoLink = "https://github.com/sleevezipper/hass-workstation-service/blob/master/documentation/Sensors.md#lastbootsensor"; item.ShowQueryInput = false; item.ShowWindowNameInput = false; item.UpdateInterval = 5; break; + case AvailableSensors.SessionStateSensor: item.Description = "This sensor returns the state of the Windows session."; - item.MoreInfoLink = "https://github.com/sleevezipper/hass-workstation-service#sessionstate"; + item.MoreInfoLink = "https://github.com/sleevezipper/hass-workstation-service/blob/master/documentation/Sensors.md#sessionstatesensor"; item.ShowQueryInput = false; item.ShowWindowNameInput = false; item.UpdateInterval = 5; break; + case AvailableSensors.CurrentVolumeSensor: item.Description = "This sensor returns the volume of currently playing audio."; - item.MoreInfoLink = "https://github.com/sleevezipper/hass-workstation-service#currentvolume"; + item.MoreInfoLink = "https://github.com/sleevezipper/hass-workstation-service/blob/master/documentation/Sensors.md#currentvolumesensor"; + item.ShowQueryInput = false; + item.ShowWindowNameInput = false; + item.UpdateInterval = 5; + break; + + case AvailableSensors.MasterVolumeSensor: + item.Description = "This sensor returns the master volume of the currently selected default audio device as a percentage value."; + item.MoreInfoLink = "https://github.com/sleevezipper/hass-workstation-service/blob/master/documentation/Sensors.md#mastervolumesensor"; item.ShowQueryInput = false; item.ShowWindowNameInput = false; item.UpdateInterval = 5; break; + case AvailableSensors.GPUTemperatureSensor: item.Description = "This sensor returns the current temperature of the GPU in °C."; - item.MoreInfoLink = "https://github.com/sleevezipper/hass-workstation-service#gputemperature"; + item.MoreInfoLink = "https://github.com/sleevezipper/hass-workstation-service/blob/master/documentation/Sensors.md#gputemperaturesensor"; item.ShowQueryInput = false; item.ShowWindowNameInput = false; item.UpdateInterval = 5; break; + case AvailableSensors.GPULoadSensor: item.Description = "This sensor returns the current GPU load."; - item.MoreInfoLink = "https://github.com/sleevezipper/hass-workstation-service#gpuload"; + item.MoreInfoLink = "https://github.com/sleevezipper/hass-workstation-service/blob/master/documentation/Sensors.md#gpuloadsensor"; item.ShowQueryInput = false; item.ShowWindowNameInput = false; item.UpdateInterval = 5; break; + default: item.Description = null; item.MoreInfoLink = null; @@ -181,15 +236,11 @@ public void ComboBoxClosed(object sender, SelectionChangedEventArgs args) 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); - } } } diff --git a/UserInterface/Views/AppInfo.axaml b/UserInterface/Views/AppInfo.axaml index afab0c5..87a9324 100644 --- a/UserInterface/Views/AppInfo.axaml +++ b/UserInterface/Views/AppInfo.axaml @@ -13,6 +13,14 @@ + +Having issues? Check out the log files. +Using the configuration files is recommended +for advanced users only. + + + + diff --git a/UserInterface/Views/AppInfo.axaml.cs b/UserInterface/Views/AppInfo.axaml.cs index 388d13c..20df1be 100644 --- a/UserInterface/Views/AppInfo.axaml.cs +++ b/UserInterface/Views/AppInfo.axaml.cs @@ -11,28 +11,31 @@ using System.Security; using hass_workstation_service.Communication.InterProcesCommunication.Models; using UserInterface.Util; +using System; +using System.IO; +using System.Diagnostics; namespace UserInterface.Views { public class AppInfo : UserControl { - private readonly IIpcClient client; - + private readonly IIpcClient client; + private readonly string _basePath; 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"); - + this._basePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Hass Workstation Service"); @@ -63,6 +66,17 @@ public void Discord(object sender, RoutedEventArgs args) BrowserUtil.OpenBrowser("https://discord.gg/VraYT2N3wd"); } + public void OpenLogDirectory(object sender, RoutedEventArgs args) + { + string path = Path.Combine(this._basePath, "logs"); + Process.Start("explorer.exe", path); + } + + public void OpenConfigDirectory(object sender, RoutedEventArgs args) + { + Process.Start("explorer.exe", this._basePath); + } + private void InitializeComponent() { AvaloniaXamlLoader.Load(this); diff --git a/UserInterface/Views/BackgroundServiceSettings.axaml.cs b/UserInterface/Views/BackgroundServiceSettings.axaml.cs index 046f362..f2b518f 100644 --- a/UserInterface/Views/BackgroundServiceSettings.axaml.cs +++ b/UserInterface/Views/BackgroundServiceSettings.axaml.cs @@ -15,49 +15,50 @@ 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"); - + this._client = clientFactory.CreateClient("broker"); DataContext = new BackgroundServiceSettingsViewModel(); Ping(); } - public async void Ping() { + + public async void Ping() + { while (true) { + if (DataContext is not BackgroundServiceSettingsViewModel viewModel) + throw new System.Exception("Wrong viewmodel class!"); + try { - var result = await this.client.InvokeAsync(x => x.Ping("ping")); + var result = await this._client.InvokeAsync(x => x.Ping("ping")); + if (result == "pong") - { - ((BackgroundServiceSettingsViewModel)this.DataContext).UpdateStatus(true, "All good"); - } + viewModel.UpdateStatus(true, "All good"); else - { - ((BackgroundServiceSettingsViewModel)this.DataContext).UpdateStatus(false, "Not running"); - } + viewModel.UpdateStatus(false, "Not running"); } catch (System.Exception) { - ((BackgroundServiceSettingsViewModel)this.DataContext).UpdateStatus(false, "Not running"); + viewModel.UpdateStatus(false, "Not running"); } - var autostartresult = await this.client.InvokeAsync(x => x.IsAutoStartEnabled()); - ((BackgroundServiceSettingsViewModel)this.DataContext).UpdateAutostartStatus(autostartresult); + var autostartresult = await this._client.InvokeAsync(x => x.IsAutoStartEnabled()); + viewModel.UpdateAutostartStatus(autostartresult); await Task.Delay(1000); } @@ -71,11 +72,12 @@ public void Start(object sender, RoutedEventArgs args) public void EnableAutostart(object sender, RoutedEventArgs args) { - this.client.InvokeAsync(x => x.EnableAutostart(true)); + this._client.InvokeAsync(x => x.EnableAutostart(true)); } + public void DisableAutostart(object sender, RoutedEventArgs args) { - this.client.InvokeAsync(x => x.EnableAutostart(false)); + this._client.InvokeAsync(x => x.EnableAutostart(false)); } private void InitializeComponent() @@ -83,4 +85,4 @@ private void InitializeComponent() AvaloniaXamlLoader.Load(this); } } -} +} \ No newline at end of file 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 b/UserInterface/Views/CommandSettings.axaml index efc93f0..0bc4aac 100644 --- a/UserInterface/Views/CommandSettings.axaml +++ b/UserInterface/Views/CommandSettings.axaml @@ -3,24 +3,27 @@ xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" d:DesignWidth="500" d:DesignHeight="450" - MaxWidth="800" - x:Class="UserInterface.Views.CommandSettings" > - - Commands - + x:Class="UserInterface.Views.CommandSettings"> - - - - - - Add some commands by clicking the "Add" button. - - - - - + + + + + + + + + + + + + diff --git a/UserInterface/Views/GeneralSettings.axaml.cs b/UserInterface/Views/GeneralSettings.axaml.cs new file mode 100644 index 0000000..39b2618 --- /dev/null +++ b/UserInterface/Views/GeneralSettings.axaml.cs @@ -0,0 +1,66 @@ +using Avalonia; +using Avalonia.Controls; +using Avalonia.Markup.Xaml; +using Microsoft.Extensions.DependencyInjection; +using hass_workstation_service.Communication.NamedPipe; +using JKang.IpcServiceFramework.Client; +using System.Threading.Tasks; +using Avalonia.Interactivity; +using System.Reactive.Linq; +using UserInterface.ViewModels; +using System.Security; +using hass_workstation_service.Communication.InterProcesCommunication.Models; +using System.ComponentModel.DataAnnotations; +using System.Collections.Generic; +using hass_workstation_service.Data; + +namespace UserInterface.Views +{ + public class GeneralSettingsView : UserControl + { + private readonly IIpcClient client; + + public GeneralSettingsView() + { + this.InitializeComponent(); + // register IPC clients + ServiceProvider serviceProvider = new ServiceCollection() + .AddNamedPipeIpcClient("general", pipeName: "pipeinternal") + .BuildServiceProvider(); + + // resolve IPC client factory + IIpcClientFactory clientFactory = serviceProvider + .GetRequiredService>(); + + // create client + this.client = clientFactory.CreateClient("general"); + + + DataContext = new GeneralSettingsViewModel(); + GetSettings(); + + } + + public void Configure(object sender, RoutedEventArgs args) + { + var model = (GeneralSettingsViewModel)this.DataContext; + ICollection results; + if (model.IsValid(model, out results)) + { + var result = this.client.InvokeAsync(x => x.WriteGeneralSettings(new GeneralSettings() { NamePrefix = model.NamePrefix })); + } + } + + public async void GetSettings() + { + GeneralSettings settings = await this.client.InvokeAsync(x => x.GetGeneralSettings()); + ((GeneralSettingsViewModel)this.DataContext).Update(settings); + } + + + private void InitializeComponent() + { + AvaloniaXamlLoader.Load(this); + } + } +} diff --git a/UserInterface/Views/MainWindow.axaml b/UserInterface/Views/MainWindow.axaml index 1da7f05..d559359 100644 --- a/UserInterface/Views/MainWindow.axaml +++ b/UserInterface/Views/MainWindow.axaml @@ -4,23 +4,24 @@ xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:views="clr-namespace:UserInterface.Views" - mc:Ignorable="d" d:DesignWidth="400" d:DesignHeight="450" + mc:Ignorable="d" d:DesignWidth="700" d:DesignHeight="500" x:Class="UserInterface.Views.MainWindow" Icon="/Assets/hass-workstation-logo.ico" - SizeToContent="WidthAndHeight" + MinWidth="700" + MinHeight="500" Title="Settings"> - - - - - - - - - - - - + + + - + + + + + + + + + + \ No newline at end of file diff --git a/UserInterface/Views/MainWindow.axaml.cs b/UserInterface/Views/MainWindow.axaml.cs index 3d1beba..8fb5437 100644 --- a/UserInterface/Views/MainWindow.axaml.cs +++ b/UserInterface/Views/MainWindow.axaml.cs @@ -11,7 +11,7 @@ public MainWindow() { InitializeComponent(); - WindowsTrayIcon icon = new WindowsTrayIcon(); + _ = new WindowsTrayIcon(); } private void InitializeComponent() @@ -19,4 +19,4 @@ private void InitializeComponent() AvaloniaXamlLoader.Load(this); } } -} +} \ No newline at end of file diff --git a/UserInterface/Views/SensorSettings.axaml b/UserInterface/Views/SensorSettings.axaml index 4d8d085..c5e6a75 100644 --- a/UserInterface/Views/SensorSettings.axaml +++ b/UserInterface/Views/SensorSettings.axaml @@ -3,30 +3,33 @@ xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" d:DesignWidth="500" d:DesignHeight="450" - MaxWidth="800" - x:Class="UserInterface.Views.SensorSettings" > - - Sensors - + x:Class="UserInterface.Views.SensorSettings"> - - - - - - - - Add some sensors by clicking the "Add" button. - - - - - + + + + + + + + + + + + +