Skip to content

Commit

Permalink
Merge branch 'develop'
Browse files Browse the repository at this point in the history
  • Loading branch information
sleevezipper committed Nov 14, 2021
2 parents 9634eba + b38f74e commit 242e726
Show file tree
Hide file tree
Showing 76 changed files with 2,991 additions and 983 deletions.
154 changes: 14 additions & 140 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -47,166 +47,40 @@ 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

The application provides several sensors. Sensors can be configured with a name and this name will be used in the MQTT topic like this: `homeassistant/sensor/{DeviceName}/{Name}/state`. Sensors will expose themselves through [MQTT discovery](https://www.home-assistant.io/docs/mqtt/discovery/) and will automatically appear in Home assistant or any other platform that supports this type of configuration.

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

Expand Down
16 changes: 9 additions & 7 deletions UserInterface/UserInterface.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,19 @@
<StartupObject>UserInterface.Program</StartupObject>
</PropertyGroup>
<ItemGroup>
<Folder Include="Models\" />
<AvaloniaResource Include="Assets\**" />
</ItemGroup>
<ItemGroup>
<None Remove="Assets\hass-workstation-logo.ico" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Avalonia" Version="0.10.0" />
<PackageReference Include="Avalonia.Controls.DataGrid" Version="0.10.0" />
<PackageReference Include="Avalonia.Desktop" Version="0.10.0" />
<PackageReference Include="Avalonia.ReactiveUI" Version="0.10.0" />
<PackageReference Include="Avalonia.Win32" Version="0.10.0" />
<PackageReference Include="Avalonia" Version="0.10.8" />
<PackageReference Include="Avalonia.Controls.DataGrid" Version="0.10.8" />
<PackageReference Include="Avalonia.Desktop" Version="0.10.8" />
<PackageReference Include="Avalonia.ReactiveUI" Version="0.10.8" />
<PackageReference Include="Avalonia.Win32" Version="0.10.8" />
<PackageReference Include="JKang.IpcServiceFramework.Client.NamedPipe" Version="3.1.0" />
<PackageReference Include="Serilog.Sinks.Console" Version="3.1.1" />
<PackageReference Include="Serilog.Sinks.Console" Version="4.0.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\hass-workstation-service\hass-workstation-service.csproj" />
Expand All @@ -33,6 +32,9 @@
<Compile Update="Views\BackgroundServiceSettings.axaml.cs">
<DependentUpon>BackgroundServiceSettings.axaml</DependentUpon>
</Compile>
<Compile Update="Views\GeneralSettings.axaml.cs">
<DependentUpon>GeneralSettings.axaml</DependentUpon>
</Compile>
<Compile Update="Views\CommandSettings.axaml.cs">
<DependentUpon>CommandSettings.axaml</DependentUpon>
</Compile>
Expand Down
42 changes: 17 additions & 25 deletions UserInterface/ViewModels/AddCommandViewModel.cs
Original file line number Diff line number Diff line change
@@ -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); }
}
}
}
52 changes: 20 additions & 32 deletions UserInterface/ViewModels/AddSensorViewModel.cs
Original file line number Diff line number Diff line change
@@ -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); }
}
}
}
17 changes: 11 additions & 6 deletions UserInterface/ViewModels/CommandSettingsViewModel.cs
Original file line number Diff line number Diff line change
@@ -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<CommandViewModel> configuredCommands;
private ICollection<CommandViewModel> _configuredCommands;

public ICollection<CommandViewModel> ConfiguredCommands
{
get => _configuredCommands;
set => this.RaiseAndSetIfChanged(ref _configuredCommands, value);
}

public ICollection<CommandViewModel> ConfiguredCommands { get => configuredCommands; set => this.RaiseAndSetIfChanged(ref configuredCommands, value); }
public void TriggerUpdate()
{
this.RaisePropertyChanged();
Expand All @@ -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; }
}
}
}
22 changes: 22 additions & 0 deletions UserInterface/ViewModels/GeneralSettingsViewModel.cs
Original file line number Diff line number Diff line change
@@ -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;
}
}
}
Loading

0 comments on commit 242e726

Please sign in to comment.