Merge branch 'develop' into notify

wip - not working
notify
sleevezipper 4 years ago
commit 191ddfd954

@ -26,6 +26,8 @@ Note: You'll get a Windows Smartscreen warning because the code was self signed.
### Standalone ### Standalone
You'll need [.NET 5 Runtime](https://dotnet.microsoft.com/download/dotnet/current/runtime) installed.
If you don't want to use the installer, you can find the standalone version releases on GitHub [here](https://github.com/sleevezipper/hass-workstation-service/releases). Unpack all files to a folder and run `hass-workstation-service.exe`. This is the background service and you can use `UserInterface.exe` to configure the service. There is no automatic (or prompted) updating in the standalone version. If you don't want to use the installer, you can find the standalone version releases on GitHub [here](https://github.com/sleevezipper/hass-workstation-service/releases). Unpack all files to a folder and run `hass-workstation-service.exe`. This is the background service and you can use `UserInterface.exe` to configure the service. There is no automatic (or prompted) updating in the standalone version.
### Updating ### Updating
@ -58,14 +60,11 @@ This sensor exposes the name of the currently focused window.
### WebcamActive ### WebcamActive
This sensor shows if the webcam is currently being used. It has two detection modes: 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.
- Registry - this is the preferred method. This will work from Windows 10 version 1903 and higher.
- OpenCV - this method tries to access the webcam and if that fails, it assumes it is currently in use. This will flash the webcam activity light at every update interval. It also uses more CPU cycles and memory.
### MicrophoneActive ### MicrophoneActive
This sensor shows if the microphone is currently being used. It uses the Windows registry to check and wil work from Windows 10 version 1903 and higher. 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 ### CPULoad
@ -103,6 +102,10 @@ 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. You can use [WMI Explorer](https://github.com/vinaypamnani/wmie2/tree/v2.0.0.2) to find see what data is available.
### IdleTime
This sensor returns the amount of seconds the workstation has been idle for. It starts counting the moment you stop typing or moving your mouse.
### Dummy ### Dummy
This sensor spits out a random number every second. Useful for testing, maybe you'll find some other use for it. This sensor spits out a random number every second. Useful for testing, maybe you'll find some other use for it.

@ -8,7 +8,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
<Platform>Any CPU</Platform> <Platform>Any CPU</Platform>
<PublishDir>..\hass-workstation-service\</PublishDir> <PublishDir>..\hass-workstation-service\</PublishDir>
<PublishProtocol>FileSystem</PublishProtocol> <PublishProtocol>FileSystem</PublishProtocol>
<TargetFramework>netcoreapp3.1</TargetFramework> <TargetFramework>net5.0</TargetFramework>
<RuntimeIdentifier>win-x64</RuntimeIdentifier> <RuntimeIdentifier>win-x64</RuntimeIdentifier>
<SelfContained>false</SelfContained> <SelfContained>false</SelfContained>
<PublishSingleFile>True</PublishSingleFile> <PublishSingleFile>True</PublishSingleFile>

@ -8,7 +8,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
<Platform>Any CPU</Platform> <Platform>Any CPU</Platform>
<PublishDir>bin\Userinterface-standalone</PublishDir> <PublishDir>bin\Userinterface-standalone</PublishDir>
<PublishProtocol>FileSystem</PublishProtocol> <PublishProtocol>FileSystem</PublishProtocol>
<TargetFramework>netcoreapp3.1</TargetFramework> <TargetFramework>net5.0</TargetFramework>
<RuntimeIdentifier>win-x64</RuntimeIdentifier> <RuntimeIdentifier>win-x64</RuntimeIdentifier>
<SelfContained>true</SelfContained> <SelfContained>true</SelfContained>
<PublishSingleFile>False</PublishSingleFile> <PublishSingleFile>False</PublishSingleFile>

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<OutputType>WinExe</OutputType> <OutputType>WinExe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework> <TargetFramework>net5.0</TargetFramework>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Folder Include="Models\" /> <Folder Include="Models\" />
@ -17,6 +17,8 @@
<PackageReference Include="Avalonia.ReactiveUI" Version="0.9.12" /> <PackageReference Include="Avalonia.ReactiveUI" Version="0.9.12" />
<PackageReference Include="Avalonia.Win32" Version="0.9.12" /> <PackageReference Include="Avalonia.Win32" Version="0.9.12" />
<PackageReference Include="JKang.IpcServiceFramework.Client.NamedPipe" Version="3.1.0" /> <PackageReference Include="JKang.IpcServiceFramework.Client.NamedPipe" Version="3.1.0" />
<PackageReference Include="Microsoft.Windows.CsWinRT" Version="1.1.0" />
<PackageReference Include="Serilog.Sinks.Console" Version="3.1.1" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\hass-workstation-service\hass-workstation-service.csproj" /> <ProjectReference Include="..\hass-workstation-service\hass-workstation-service.csproj" />

@ -9,7 +9,6 @@ namespace UserInterface.ViewModels
public class AddSensorViewModel : ViewModelBase public class AddSensorViewModel : ViewModelBase
{ {
private AvailableSensors selectedType; private AvailableSensors selectedType;
private WebcamDetectionMode selectedDetectionMode;
private string description; private string description;
private bool showQueryInput; private bool showQueryInput;
@ -32,7 +31,6 @@ namespace UserInterface.ViewModels
public AvailableSensors SelectedType { get => selectedType; set => this.RaiseAndSetIfChanged(ref selectedType, value); } public AvailableSensors SelectedType { get => selectedType; set => this.RaiseAndSetIfChanged(ref selectedType, value); }
public WebcamDetectionMode SelectedDetectionMode { get => selectedDetectionMode; set => this.RaiseAndSetIfChanged(ref selectedDetectionMode, value); }
public string Name { get; set; } public string Name { get; set; }
public string Query { get; set; } public string Query { get; set; }

@ -2,6 +2,7 @@
using ReactiveUI; using ReactiveUI;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Text; using System.Text;
namespace UserInterface.ViewModels namespace UserInterface.ViewModels
@ -13,17 +14,28 @@ namespace UserInterface.ViewModels
private string password; private string password;
private string message; private string message;
private bool isConnected; private bool isConnected;
private int? port;
private bool useTLS;
public bool IsConnected { get => isConnected; set => this.RaiseAndSetIfChanged(ref isConnected, value); } public bool IsConnected { get => isConnected; set => this.RaiseAndSetIfChanged(ref isConnected, value); }
public string Message { get => message; set => this.RaiseAndSetIfChanged(ref message, value); } public string Message { get => message; set => this.RaiseAndSetIfChanged(ref message, value); }
[Required(AllowEmptyStrings = false)]
public string Host { get => host; set => this.RaiseAndSetIfChanged(ref host, value); } public string Host { get => host; set => this.RaiseAndSetIfChanged(ref host, value); }
public string Username { get => username; set => this.RaiseAndSetIfChanged(ref username, value); } public string Username { get => username; set => this.RaiseAndSetIfChanged(ref username, value); }
public string Password { get => password; set => this.RaiseAndSetIfChanged(ref password, value); } public string Password { get => password; set => this.RaiseAndSetIfChanged(ref password, value); }
[Required]
[Range(1, 65535)]
public int? Port { get => port; set => this.RaiseAndSetIfChanged(ref port, value); }
public bool UseTLS { get => useTLS; set => this.RaiseAndSetIfChanged(ref useTLS, value); }
public void Update(MqttSettings settings) public void Update(MqttSettings settings)
{ {
this.Host = settings.Host; this.Host = settings.Host;
this.Username = settings.Username; this.Username = settings.Username;
this.Password = settings.Password; this.Password = settings.Password;
this.Port = settings.Port;
this.UseTLS = settings.UseTLS;
} }
public void UpdateStatus(MqqtClientStatus status) public void UpdateStatus(MqqtClientStatus status)

@ -1,11 +1,18 @@
using ReactiveUI; using ReactiveUI;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Text; using System.Text;
namespace UserInterface.ViewModels namespace UserInterface.ViewModels
{ {
public class ViewModelBase : ReactiveObject public class ViewModelBase : ReactiveObject
{ {
public bool IsValid<T>(T obj, out ICollection<ValidationResult> results)
{
results = new List<ValidationResult>();
return Validator.TryValidateObject(obj, new ValidationContext(obj), results, true);
}
} }
} }

@ -26,8 +26,6 @@
<ContentControl IsVisible="{Binding ShowWindowNameInput}" Margin="0 20 0 5">Window name</ContentControl> <ContentControl IsVisible="{Binding ShowWindowNameInput}" Margin="0 20 0 5">Window name</ContentControl>
<TextBlock TextWrapping="Wrap" MaxWidth="300" FontStyle="Italic" IsVisible="{Binding ShowWindowNameInput}" Margin="0 0 0 10">This is case-insensitive and loosely matched. A window called "Spotify Premium" will match "spotify" or "premium".</TextBlock> <TextBlock TextWrapping="Wrap" MaxWidth="300" FontStyle="Italic" IsVisible="{Binding ShowWindowNameInput}" Margin="0 0 0 10">This is case-insensitive and loosely matched. A window called "Spotify Premium" will match "spotify" or "premium".</TextBlock>
<TextBox IsVisible="{Binding ShowWindowNameInput}" Text="{Binding WindowName}" Watermark="Visual Studio Code" HorizontalAlignment="Left" MinWidth="300"/> <TextBox IsVisible="{Binding ShowWindowNameInput}" Text="{Binding WindowName}" Watermark="Visual Studio Code" HorizontalAlignment="Left" MinWidth="300"/>
<ContentControl IsVisible="{Binding ShowDetectionModeOptions}" Margin="0 20 0 10">Detection mode</ContentControl>
<ComboBox IsVisible="{Binding ShowDetectionModeOptions}" x:Name="DetectionModeComboBox" SelectedItem="{Binding SelectedDetectionMode}" MinHeight="27"></ComboBox>
<Button Width="75" HorizontalAlignment="Right" Margin="0 40 0 10" Click="Save">Save</Button> <Button Width="75" HorizontalAlignment="Right" Margin="0 40 0 10" Click="Save">Save</Button>
</StackPanel> </StackPanel>
</Window> </Window>

@ -29,9 +29,6 @@ namespace UserInterface.Views
this.comboBox = this.FindControl<ComboBox>("ComboBox"); this.comboBox = this.FindControl<ComboBox>("ComboBox");
this.comboBox.Items = Enum.GetValues(typeof(AvailableSensors)).Cast<AvailableSensors>(); this.comboBox.Items = Enum.GetValues(typeof(AvailableSensors)).Cast<AvailableSensors>();
this.comboBox = this.FindControl<ComboBox>("DetectionModeComboBox");
this.comboBox.Items = Enum.GetValues(typeof(WebcamDetectionMode)).Cast<WebcamDetectionMode>();
// register IPC clients // register IPC clients
ServiceProvider serviceProvider = new ServiceCollection() ServiceProvider serviceProvider = new ServiceCollection()
.AddNamedPipeIpcClient<ServiceContractInterfaces>("addsensor", pipeName: "pipeinternal") .AddNamedPipeIpcClient<ServiceContractInterfaces>("addsensor", pipeName: "pipeinternal")
@ -51,7 +48,7 @@ namespace UserInterface.Views
public async void Save(object sender, RoutedEventArgs args) public async void Save(object sender, RoutedEventArgs args)
{ {
var item = ((AddSensorViewModel)this.DataContext); var item = ((AddSensorViewModel)this.DataContext);
dynamic model = new { item.Name, item.Query, item.UpdateInterval, item.WindowName, DetectionMode = item.SelectedDetectionMode }; dynamic model = new { item.Name, item.Query, item.UpdateInterval, item.WindowName};
string json = JsonSerializer.Serialize(model); string json = JsonSerializer.Serialize(model);
await this.client.InvokeAsync(x => x.AddSensor(item.SelectedType, json)); await this.client.InvokeAsync(x => x.AddSensor(item.SelectedType, json));
Close(); Close();
@ -139,6 +136,13 @@ namespace UserInterface.Views
item.ShowWindowNameInput = true; item.ShowWindowNameInput = true;
item.UpdateInterval = 5; item.UpdateInterval = 5;
break; break;
case AvailableSensors.IdleTimeSensor:
item.Description = "This sensor returns the amount of seconds the workstation has been idle for. ";
item.MoreInfoLink = "https://github.com/sleevezipper/hass-workstation-service#idletime";
item.ShowQueryInput = false;
item.ShowWindowNameInput = false;
item.UpdateInterval = 5;
break;
default: default:
item.Description = null; item.Description = null;
item.MoreInfoLink = null; item.MoreInfoLink = null;

@ -10,6 +10,17 @@
<TextBlock IsVisible="{Binding !IsConnected}" Foreground="Red" Text="{Binding Message}"></TextBlock > <TextBlock IsVisible="{Binding !IsConnected}" Foreground="Red" Text="{Binding Message}"></TextBlock >
<ContentControl Margin="0 20 0 10">IP or hostname</ContentControl> <ContentControl Margin="0 20 0 10">IP or hostname</ContentControl>
<TextBox Text="{Binding Host}" HorizontalAlignment="Left" Width="100" Watermark="192.168.1.200"/> <TextBox Text="{Binding Host}" HorizontalAlignment="Left" Width="100" Watermark="192.168.1.200"/>
<StackPanel Orientation="Horizontal">
<StackPanel Orientation="Vertical">
<ContentControl Margin="0 20 0 10">Port</ContentControl>
<TextBox Text="{Binding Port}" HorizontalAlignment="Left" Width="50" Watermark="1883"/>
</StackPanel>
<StackPanel Orientation="Vertical" Margin="30 0 0 0">
<ContentControl Margin="0 20 0 10">Use TLS</ContentControl>
<CheckBox IsChecked="{Binding UseTLS}" HorizontalAlignment="Left" Margin="0 3 0 0"/>
</StackPanel>
</StackPanel>
<ContentControl Margin="0 20 0 10">Username</ContentControl> <ContentControl Margin="0 20 0 10">Username</ContentControl>
<TextBox Text="{Binding Username}" MinWidth="150"/> <TextBox Text="{Binding Username}" MinWidth="150"/>
<ContentControl Margin="0 20 0 10">Password</ContentControl> <ContentControl Margin="0 20 0 10">Password</ContentControl>

@ -10,6 +10,8 @@ using System.Reactive.Linq;
using UserInterface.ViewModels; using UserInterface.ViewModels;
using System.Security; using System.Security;
using hass_workstation_service.Communication.InterProcesCommunication.Models; using hass_workstation_service.Communication.InterProcesCommunication.Models;
using System.ComponentModel.DataAnnotations;
using System.Collections.Generic;
namespace UserInterface.Views namespace UserInterface.Views
{ {
@ -45,7 +47,11 @@ namespace UserInterface.Views
public void Configure(object sender, RoutedEventArgs args) public void Configure(object sender, RoutedEventArgs args)
{ {
var model = (BrokerSettingsViewModel)this.DataContext; var model = (BrokerSettingsViewModel)this.DataContext;
var result = this.client.InvokeAsync(x => x.WriteMqttBrokerSettingsAsync(new MqttSettings() { Host = model.Host, Username = model.Username, Password = model.Password ?? "" })); ICollection<ValidationResult> results;
if (model.IsValid(model, out results))
{
var result = this.client.InvokeAsync(x => x.WriteMqttBrokerSettingsAsync(new MqttSettings() { Host = model.Host, Username = model.Username, Password = model.Password ?? "", Port = model.Port, UseTLS = model.UseTLS }));
}
} }
public async void GetSettings() public async void GetSettings()

@ -1,4 +1,4 @@
using hass_workstation_service.Communication.InterProcesCommunication.Models; using hass_workstation_service.Communication.InterProcesCommunication.Models;
using hass_workstation_service.Communication.NamedPipe; using hass_workstation_service.Communication.NamedPipe;
using hass_workstation_service.Communication.Util; using hass_workstation_service.Communication.Util;
using hass_workstation_service.Data; using hass_workstation_service.Data;
@ -107,20 +107,7 @@ namespace hass_workstation_service.Communication.InterProcesCommunication
sensorToCreate = new ActiveWindowSensor(this._publisher, (int)model.UpdateInterval, model.Name); sensorToCreate = new ActiveWindowSensor(this._publisher, (int)model.UpdateInterval, model.Name);
break; break;
case AvailableSensors.WebcamActiveSensor: case AvailableSensors.WebcamActiveSensor:
DetectionMode detectionMode; sensorToCreate = new WebcamActiveSensor(this._publisher, (int)model.UpdateInterval, model.Name);
switch ((WebcamDetectionMode)model.DetectionMode)
{
case WebcamDetectionMode.Registry:
detectionMode = DetectionMode.Registry;
break;
case WebcamDetectionMode.OpenCV:
detectionMode = DetectionMode.OpenCV;
break;
default:
detectionMode = DetectionMode.Registry;
break;
}
sensorToCreate = new WebcamActiveSensor(this._publisher, (int)model.UpdateInterval, model.Name, detectionMode);
break; break;
case AvailableSensors.MicrophoneActiveSensor: case AvailableSensors.MicrophoneActiveSensor:
sensorToCreate = new MicrophoneActiveSensor(this._publisher, (int)model.UpdateInterval, model.Name); sensorToCreate = new MicrophoneActiveSensor(this._publisher, (int)model.UpdateInterval, model.Name);
@ -128,6 +115,9 @@ namespace hass_workstation_service.Communication.InterProcesCommunication
case AvailableSensors.NamedWindowSensor: case AvailableSensors.NamedWindowSensor:
sensorToCreate = new NamedWindowSensor(this._publisher, model.WindowName, model.Name, (int)model.UpdateInterval); sensorToCreate = new NamedWindowSensor(this._publisher, model.WindowName, model.Name, (int)model.UpdateInterval);
break; break;
case AvailableSensors.IdleTimeSensor:
sensorToCreate = new IdleTimeSensor(this._publisher,(int)model.UpdateInterval, model.Name);
break;
default: default:
Log.Logger.Error("Unknown sensortype"); Log.Logger.Error("Unknown sensortype");
break; break;

@ -1,4 +1,4 @@
using hass_workstation_service.Domain.Sensors; using hass_workstation_service.Domain.Sensors;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text; using System.Text;
@ -10,6 +10,8 @@ namespace hass_workstation_service.Communication.InterProcesCommunication.Models
public string Host { get; set; } public string Host { get; set; }
public string Username { get; set; } public string Username { get; set; }
public string Password { get; set; } public string Password { get; set; }
public int? Port { get; set; }
public bool UseTLS { get; set; }
} }
public class MqqtClientStatus public class MqqtClientStatus
@ -39,12 +41,7 @@ namespace hass_workstation_service.Communication.InterProcesCommunication.Models
WebcamActiveSensor, WebcamActiveSensor,
MicrophoneActiveSensor, MicrophoneActiveSensor,
ActiveWindowSensor, ActiveWindowSensor,
NamedWindowSensor NamedWindowSensor,
} IdleTimeSensor
public enum WebcamDetectionMode
{
Registry,
OpenCV
} }
} }

@ -12,6 +12,7 @@ using MQTTnet;
using MQTTnet.Adapter; using MQTTnet.Adapter;
using MQTTnet.Client; using MQTTnet.Client;
using MQTTnet.Client.Options; using MQTTnet.Client.Options;
using MQTTnet.Exceptions;
using Serilog; using Serilog;
using static hass_workstation_service.Domain.Notify.Notifier; using static hass_workstation_service.Domain.Notify.Notifier;
@ -150,7 +151,11 @@ namespace hass_workstation_service.Communication
this._mqttClientMessage = ex.ResultCode.ToString(); this._mqttClientMessage = ex.ResultCode.ToString();
Log.Logger.Error("Could not connect to broker: " + ex.ResultCode.ToString()); Log.Logger.Error("Could not connect to broker: " + ex.ResultCode.ToString());
} }
catch (MqttCommunicationException ex)
{
this._mqttClientMessage = ex.ToString();
Log.Logger.Error("Could not connect to broker: " + ex.Message);
}
} }
public MqqtClientStatus GetStatus() public MqqtClientStatus GetStatus()

@ -2,6 +2,8 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security; using System.Security;
using System.Text.Json; using System.Text.Json;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -23,8 +25,8 @@ namespace hass_workstation_service.Data
public ICollection<AbstractSensor> ConfiguredSensors { get; private set; } public ICollection<AbstractSensor> ConfiguredSensors { get; private set; }
public Action<IMqttClientOptions> MqqtConfigChangedHandler { get; set; } public Action<IMqttClientOptions> MqqtConfigChangedHandler { get; set; }
public bool _brokerSettingsFileLocked { get; set; } private bool BrokerSettingsFileLocked { get; set; }
public bool _sensorsSettingsFileLocked { get; set; } private bool SensorsSettingsFileLocked { get; set; }
private readonly string path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Hass Workstation Service"); private readonly string path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Hass Workstation Service");
@ -32,12 +34,12 @@ namespace hass_workstation_service.Data
{ {
if (!File.Exists(Path.Combine(path, "mqttbroker.json"))) if (!File.Exists(Path.Combine(path, "mqttbroker.json")))
{ {
File.Create(Path.Combine(path, "mqttbroker.json")); File.Create(Path.Combine(path, "mqttbroker.json")).Close();
} }
if (!File.Exists(Path.Combine(path, "configured-sensors.json"))) if (!File.Exists(Path.Combine(path, "configured-sensors.json")))
{ {
File.Create(Path.Combine(path, "configured-sensors.json")); File.Create(Path.Combine(path, "configured-sensors.json")).Close();
} }
ConfiguredSensors = new List<AbstractSensor>(); ConfiguredSensors = new List<AbstractSensor>();
@ -45,11 +47,11 @@ namespace hass_workstation_service.Data
public async void ReadSensorSettings(MqttPublisher publisher) public async void ReadSensorSettings(MqttPublisher publisher)
{ {
while (this._sensorsSettingsFileLocked) while (this.SensorsSettingsFileLocked)
{ {
await Task.Delay(500); await Task.Delay(500);
} }
this._sensorsSettingsFileLocked = true; this.SensorsSettingsFileLocked = true;
List<ConfiguredSensor> sensors = new List<ConfiguredSensor>(); List<ConfiguredSensor> sensors = new List<ConfiguredSensor>();
using (var stream = new FileStream(Path.Combine(path, "configured-sensors.json"), FileMode.Open)) using (var stream = new FileStream(Path.Combine(path, "configured-sensors.json"), FileMode.Open))
{ {
@ -59,7 +61,7 @@ namespace hass_workstation_service.Data
sensors = await JsonSerializer.DeserializeAsync<List<ConfiguredSensor>>(stream); sensors = await JsonSerializer.DeserializeAsync<List<ConfiguredSensor>>(stream);
} }
stream.Close(); stream.Close();
this._sensorsSettingsFileLocked = false; this.SensorsSettingsFileLocked = false;
} }
foreach (ConfiguredSensor configuredSensor in sensors) foreach (ConfiguredSensor configuredSensor in sensors)
@ -83,7 +85,10 @@ namespace hass_workstation_service.Data
sensor = new CPULoadSensor(publisher, configuredSensor.UpdateInterval, configuredSensor.Name, configuredSensor.Id); sensor = new CPULoadSensor(publisher, configuredSensor.UpdateInterval, configuredSensor.Name, configuredSensor.Id);
break; break;
case "MemoryUsageSensor": case "MemoryUsageSensor":
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
sensor = new MemoryUsageSensor(publisher, configuredSensor.UpdateInterval, configuredSensor.Name, configuredSensor.Id); sensor = new MemoryUsageSensor(publisher, configuredSensor.UpdateInterval, configuredSensor.Name, configuredSensor.Id);
}
break; break;
case "ActiveWindowSensor": case "ActiveWindowSensor":
sensor = new ActiveWindowSensor(publisher, configuredSensor.UpdateInterval, configuredSensor.Name, configuredSensor.Id); sensor = new ActiveWindowSensor(publisher, configuredSensor.UpdateInterval, configuredSensor.Name, configuredSensor.Id);
@ -91,8 +96,11 @@ namespace hass_workstation_service.Data
case "NamedWindowSensor": case "NamedWindowSensor":
sensor = new NamedWindowSensor(publisher, configuredSensor.WindowName, configuredSensor.Name, configuredSensor.UpdateInterval, configuredSensor.Id); sensor = new NamedWindowSensor(publisher, configuredSensor.WindowName, configuredSensor.Name, configuredSensor.UpdateInterval, configuredSensor.Id);
break; break;
case "IdleTimeSensor":
sensor = new IdleTimeSensor(publisher, configuredSensor.UpdateInterval, configuredSensor.Name, configuredSensor.Id);
break;
case "WebcamActiveSensor": case "WebcamActiveSensor":
sensor = new WebcamActiveSensor(publisher, configuredSensor.UpdateInterval, configuredSensor.Name, configuredSensor.DetectionMode, configuredSensor.Id); sensor = new WebcamActiveSensor(publisher, configuredSensor.UpdateInterval, configuredSensor.Name, configuredSensor.Id);
break; break;
case "MicrophoneActiveSensor": case "MicrophoneActiveSensor":
sensor = new MicrophoneActiveSensor(publisher, configuredSensor.UpdateInterval, configuredSensor.Name, configuredSensor.Id); sensor = new MicrophoneActiveSensor(publisher, configuredSensor.UpdateInterval, configuredSensor.Name, configuredSensor.Id);
@ -115,8 +123,12 @@ namespace hass_workstation_service.Data
{ {
var mqttClientOptions = new MqttClientOptionsBuilder() var mqttClientOptions = new MqttClientOptionsBuilder()
.WithTcpServer(configuredBroker.Host) .WithTcpServer(configuredBroker.Host, configuredBroker.Port)
// .WithTls() .WithTls(new MqttClientOptionsBuilderTlsParameters()
{
UseTls = configuredBroker.UseTLS,
AllowUntrustedCertificates = true
})
.WithCredentials(configuredBroker.Username, configuredBroker.Password.ToString()) .WithCredentials(configuredBroker.Username, configuredBroker.Password.ToString())
.Build(); .Build();
return mqttClientOptions; return mqttClientOptions;
@ -134,11 +146,11 @@ namespace hass_workstation_service.Data
/// <returns></returns> /// <returns></returns>
public async Task<ConfiguredMqttBroker> ReadMqttSettingsAsync() public async Task<ConfiguredMqttBroker> ReadMqttSettingsAsync()
{ {
while (this._brokerSettingsFileLocked) while (this.BrokerSettingsFileLocked)
{ {
await Task.Delay(500); await Task.Delay(500);
} }
this._brokerSettingsFileLocked = true; this.BrokerSettingsFileLocked = true;
ConfiguredMqttBroker configuredBroker = null; ConfiguredMqttBroker configuredBroker = null;
using (FileStream stream = new FileStream(Path.Combine(path, "mqttbroker.json"), FileMode.Open)) using (FileStream stream = new FileStream(Path.Combine(path, "mqttbroker.json"), FileMode.Open))
{ {
@ -150,17 +162,17 @@ namespace hass_workstation_service.Data
stream.Close(); stream.Close();
} }
this._brokerSettingsFileLocked = false; this.BrokerSettingsFileLocked = false;
return configuredBroker; return configuredBroker;
} }
public async void WriteSettingsAsync() public async void WriteSettingsAsync()
{ {
while (this._sensorsSettingsFileLocked) while (this.SensorsSettingsFileLocked)
{ {
await Task.Delay(500); await Task.Delay(500);
} }
this._sensorsSettingsFileLocked = true; this.SensorsSettingsFileLocked = true;
List<ConfiguredSensor> configuredSensorsToSave = new List<ConfiguredSensor>(); List<ConfiguredSensor> configuredSensorsToSave = new List<ConfiguredSensor>();
using (FileStream stream = new FileStream(Path.Combine(path, "configured-sensors.json"), FileMode.Open)) using (FileStream stream = new FileStream(Path.Combine(path, "configured-sensors.json"), FileMode.Open))
{ {
@ -168,14 +180,14 @@ namespace hass_workstation_service.Data
Log.Logger.Information($"writing configured sensors to: {stream.Name}"); Log.Logger.Information($"writing configured sensors to: {stream.Name}");
foreach (AbstractSensor sensor in this.ConfiguredSensors) foreach (AbstractSensor sensor in this.ConfiguredSensors)
{ {
if (sensor is WMIQuerySensor) if (sensor is WMIQuerySensor wmiSensor)
{ {
var wmiSensor = (WMIQuerySensor)sensor; #pragma warning disable CA1416 // Validate platform compatibility. We ignore it here because this would never happen. A cleaner solution may be implemented later.
configuredSensorsToSave.Add(new ConfiguredSensor() { Id = wmiSensor.Id, Name = wmiSensor.Name, Type = wmiSensor.GetType().Name, UpdateInterval = wmiSensor.UpdateInterval, Query = wmiSensor.Query }); configuredSensorsToSave.Add(new ConfiguredSensor() { Id = wmiSensor.Id, Name = wmiSensor.Name, Type = wmiSensor.GetType().Name, UpdateInterval = wmiSensor.UpdateInterval, Query = wmiSensor.Query });
#pragma warning restore CA1416 // Validate platform compatibility
} }
if (sensor is NamedWindowSensor) if (sensor is NamedWindowSensor namedWindowSensor)
{ {
var namedWindowSensor = (NamedWindowSensor)sensor;
configuredSensorsToSave.Add(new ConfiguredSensor() { Id = namedWindowSensor.Id, Name = namedWindowSensor.Name, Type = namedWindowSensor.GetType().Name, UpdateInterval = namedWindowSensor.UpdateInterval, WindowName = namedWindowSensor.WindowName }); configuredSensorsToSave.Add(new ConfiguredSensor() { Id = namedWindowSensor.Id, Name = namedWindowSensor.Name, Type = namedWindowSensor.GetType().Name, UpdateInterval = namedWindowSensor.UpdateInterval, WindowName = namedWindowSensor.WindowName });
} }
else else
@ -188,7 +200,7 @@ namespace hass_workstation_service.Data
await JsonSerializer.SerializeAsync(stream, configuredSensorsToSave); await JsonSerializer.SerializeAsync(stream, configuredSensorsToSave);
stream.Close(); stream.Close();
} }
this._sensorsSettingsFileLocked = false; this.SensorsSettingsFileLocked = false;
} }
public void AddConfiguredSensor(AbstractSensor sensor) public void AddConfiguredSensor(AbstractSensor sensor)
@ -226,11 +238,11 @@ namespace hass_workstation_service.Data
/// <param name="settings"></param> /// <param name="settings"></param>
public async void WriteMqttBrokerSettingsAsync(MqttSettings settings) public async void WriteMqttBrokerSettingsAsync(MqttSettings settings)
{ {
while (this._brokerSettingsFileLocked) while (this.BrokerSettingsFileLocked)
{ {
await Task.Delay(500); await Task.Delay(500);
} }
this._brokerSettingsFileLocked = true; this.BrokerSettingsFileLocked = true;
using (FileStream stream = new FileStream(Path.Combine(path, "mqttbroker.json"), FileMode.Open)) using (FileStream stream = new FileStream(Path.Combine(path, "mqttbroker.json"), FileMode.Open))
{ {
stream.SetLength(0); stream.SetLength(0);
@ -240,13 +252,15 @@ namespace hass_workstation_service.Data
{ {
Host = settings.Host, Host = settings.Host,
Username = settings.Username, Username = settings.Username,
Password = settings.Password ?? "" Password = settings.Password ?? "",
Port = settings.Port ?? 1883,
UseTLS = settings.UseTLS
}; };
await JsonSerializer.SerializeAsync(stream, configuredBroker); await JsonSerializer.SerializeAsync(stream, configuredBroker);
stream.Close(); stream.Close();
} }
this._brokerSettingsFileLocked = false; this.BrokerSettingsFileLocked = false;
this.MqqtConfigChangedHandler.Invoke(await this.GetMqttClientOptionsAsync()); this.MqqtConfigChangedHandler.Invoke(await this.GetMqttClientOptionsAsync());
} }
@ -257,7 +271,9 @@ namespace hass_workstation_service.Data
{ {
Host = broker?.Host, Host = broker?.Host,
Username = broker?.Username, Username = broker?.Username,
Password = broker?.Password Password = broker?.Password,
Port = broker?.Port,
UseTLS = broker?.UseTLS ?? false
}; };
} }
@ -265,6 +281,7 @@ namespace hass_workstation_service.Data
/// Enable or disable autostarting the background service. It does this by adding the application shortcut (appref-ms) to the registry run key for the current user /// Enable or disable autostarting the background service. It does this by adding the application shortcut (appref-ms) to the registry run key for the current user
/// </summary> /// </summary>
/// <param name="enable"></param> /// <param name="enable"></param>
[SupportedOSPlatform("windows")]
public void EnableAutoStart(bool enable) public void EnableAutoStart(bool enable)
{ {
if (enable) if (enable)
@ -299,6 +316,7 @@ namespace hass_workstation_service.Data
} }
} }
[SupportedOSPlatform("windows")]
public bool IsAutoStartEnabled() public bool IsAutoStartEnabled()
{ {
RegistryKey rkApp = Registry.CurrentUser.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Run", true); RegistryKey rkApp = Registry.CurrentUser.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Run", true);

@ -5,8 +5,35 @@ namespace hass_workstation_service.Data
{ {
public class ConfiguredMqttBroker public class ConfiguredMqttBroker
{ {
private string username;
private string password;
private int? port;
public string Host { get; set; } public string Host { get; set; }
public string Username { get; set; } public int Port { get => port ?? 1883; set => port = value; }
public string Password { get; set; } public bool UseTLS { get; set; }
public string Username
{
get
{
if (username != null) return username;
return "";
}
set => username = value;
}
public string Password
{
get
{
if (password != null) return password;
return "";
}
set => password = value;
}
} }
} }

@ -11,6 +11,5 @@ namespace hass_workstation_service.Data
public string Query { get; set; } public string Query { get; set; }
public int? UpdateInterval { get; set; } public int? UpdateInterval { get; set; }
public string WindowName { get; set; } public string WindowName { get; set; }
public DetectionMode DetectionMode { get; set; }
} }
} }

@ -19,7 +19,7 @@ namespace hass_workstation_service.Domain.Sensors
public MqttPublisher Publisher { get; protected set; } public MqttPublisher Publisher { get; protected set; }
public AbstractSensor(MqttPublisher publisher, string name, int updateInterval = 10, Guid id = default(Guid)) public AbstractSensor(MqttPublisher publisher, string name, int updateInterval = 10, Guid id = default(Guid))
{ {
if (id == Guid.Empty || id == null) if (id == Guid.Empty)
{ {
this.Id = Guid.NewGuid(); this.Id = Guid.NewGuid();
} }

@ -4,10 +4,13 @@ using System.Collections.Generic;
using System.Globalization; using System.Globalization;
using System.Linq; using System.Linq;
using System.Management; using System.Management;
using System.Runtime.Versioning;
using System.Text; using System.Text;
namespace hass_workstation_service.Domain.Sensors namespace hass_workstation_service.Domain.Sensors
{ {
[SupportedOSPlatform("windows")]
public class CPULoadSensor : WMIQuerySensor public class CPULoadSensor : WMIQuerySensor
{ {
public CPULoadSensor(MqttPublisher publisher, int? updateInterval = null, string name = "CPULoadSensor", Guid id = default) : base(publisher, "SELECT PercentProcessorTime FROM Win32_PerfFormattedData_PerfOS_Processor", updateInterval ?? 10, name ?? "CPULoadSensor", id) public CPULoadSensor(MqttPublisher publisher, int? updateInterval = null, string name = "CPULoadSensor", Guid id = default) : base(publisher, "SELECT PercentProcessorTime FROM Win32_PerfFormattedData_PerfOS_Processor", updateInterval ?? 10, name ?? "CPULoadSensor", id)
@ -26,6 +29,8 @@ namespace hass_workstation_service.Domain.Sensors
Unit_of_measurement = "%" Unit_of_measurement = "%"
}); });
} }
[SupportedOSPlatform("windows")]
public override string GetState() public override string GetState()
{ {
ManagementObjectCollection collection = _searcher.Get(); ManagementObjectCollection collection = _searcher.Get();

@ -0,0 +1,67 @@
using hass_workstation_service.Communication;
using System;
using System.Runtime.InteropServices;
namespace hass_workstation_service.Domain.Sensors
{
public class IdleTimeSensor : AbstractSensor
{
public IdleTimeSensor(MqttPublisher publisher, int? updateInterval = 10, string name = "IdleTime", Guid id = default) : base(publisher, name ?? "IdleTime", updateInterval ?? 10, id){}
public override AutoDiscoveryConfigModel GetAutoDiscoveryConfig()
{
return this._autoDiscoveryConfigModel ?? SetAutoDiscoveryConfigModel(new AutoDiscoveryConfigModel()
{
Name = this.Name,
Unique_id = this.Id.ToString(),
Device = this.Publisher.DeviceConfigModel,
State_topic = $"homeassistant/sensor/{Publisher.DeviceConfigModel.Name}/{this.Name}/state",
Icon = "mdi:window-maximize",
});
}
public override string GetState()
{
return GetLastInputTime().ToString();
}
static int GetLastInputTime()
{
int idleTime = 0;
LASTINPUTINFO lastInputInfo = new LASTINPUTINFO();
lastInputInfo.cbSize = Marshal.SizeOf(lastInputInfo);
lastInputInfo.dwTime = 0;
int envTicks = Environment.TickCount;
if (GetLastInputInfo(ref lastInputInfo))
{
int lastInputTick = Convert.ToInt32(lastInputInfo.dwTime);
idleTime = envTicks - lastInputTick;
}
return ((idleTime > 0) ? (idleTime / 1000) : idleTime);
}
[DllImport("User32.dll")]
private static extern bool GetLastInputInfo(ref LASTINPUTINFO plii);
[StructLayout(LayoutKind.Sequential)]
struct LASTINPUTINFO
{
public static readonly int SizeOf = Marshal.SizeOf(typeof(LASTINPUTINFO));
[MarshalAs(UnmanagedType.U4)]
public int cbSize;
[MarshalAs(UnmanagedType.U4)]
public UInt32 dwTime;
}
}
}

@ -3,10 +3,13 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization; using System.Globalization;
using System.Management; using System.Management;
using System.Runtime.Versioning;
using System.Text; using System.Text;
namespace hass_workstation_service.Domain.Sensors namespace hass_workstation_service.Domain.Sensors
{ {
[SupportedOSPlatform("windows")]
public class MemoryUsageSensor : WMIQuerySensor public class MemoryUsageSensor : WMIQuerySensor
{ {
public MemoryUsageSensor(MqttPublisher publisher, int? updateInterval = null, string name = "WMIQuerySensor", Guid id = default) : base(publisher, "SELECT FreePhysicalMemory,TotalVisibleMemorySize FROM Win32_OperatingSystem", updateInterval ?? 10, name, id) public MemoryUsageSensor(MqttPublisher publisher, int? updateInterval = null, string name = "WMIQuerySensor", Guid id = default) : base(publisher, "SELECT FreePhysicalMemory,TotalVisibleMemorySize FROM Win32_OperatingSystem", updateInterval ?? 10, name, id)

@ -2,6 +2,8 @@
using Microsoft.Win32; using Microsoft.Win32;
using System; using System;
using System.Linq; using System.Linq;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
namespace hass_workstation_service.Domain.Sensors namespace hass_workstation_service.Domain.Sensors
{ {
@ -12,9 +14,13 @@ namespace hass_workstation_service.Domain.Sensors
{ {
} }
public override string GetState() public override string GetState()
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{ {
return IsMicrophoneInUse() ? "True" : "False"; return IsMicrophoneInUse() ? "True" : "False";
} }
else return "unsupported";
}
public override AutoDiscoveryConfigModel GetAutoDiscoveryConfig() public override AutoDiscoveryConfigModel GetAutoDiscoveryConfig()
{ {
return this._autoDiscoveryConfigModel ?? SetAutoDiscoveryConfigModel(new AutoDiscoveryConfigModel() return this._autoDiscoveryConfigModel ?? SetAutoDiscoveryConfigModel(new AutoDiscoveryConfigModel()
@ -27,6 +33,7 @@ namespace hass_workstation_service.Domain.Sensors
}); });
} }
[SupportedOSPlatform("windows")]
private bool IsMicrophoneInUse() private bool IsMicrophoneInUse()
{ {
using (var key = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\CapabilityAccessManager\ConsentStore\microphone\NonPackaged")) using (var key = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\CapabilityAccessManager\ConsentStore\microphone\NonPackaged"))

@ -2,16 +2,19 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Management; using System.Management;
using System.Runtime.Versioning;
using System.Text; using System.Text;
namespace hass_workstation_service.Domain.Sensors namespace hass_workstation_service.Domain.Sensors
{ {
[SupportedOSPlatform("windows")]
public class WMIQuerySensor : AbstractSensor public class WMIQuerySensor : AbstractSensor
{ {
public string Query { get; private set; } public string Query { get; private set; }
protected readonly ObjectQuery _objectQuery; protected readonly ObjectQuery _objectQuery;
protected readonly ManagementObjectSearcher _searcher; protected readonly ManagementObjectSearcher _searcher;
public WMIQuerySensor(MqttPublisher publisher, string query, int? updateInterval = null, string name = "WMIQuerySensor", Guid id = default(Guid)) : base(publisher, name ?? "WMIQuerySensor", updateInterval ?? 10, id) public WMIQuerySensor(MqttPublisher publisher, string query, int? updateInterval = null, string name = "WMIQuerySensor", Guid id = default) : base(publisher, name ?? "WMIQuerySensor", updateInterval ?? 10, id)
{ {
this.Query = query; this.Query = query;
_objectQuery = new ObjectQuery(this.Query); _objectQuery = new ObjectQuery(this.Query);

@ -1,35 +1,27 @@
using hass_workstation_service.Communication; using hass_workstation_service.Communication;
using Microsoft.Win32; using Microsoft.Win32;
using OpenCvSharp;
using System; using System;
using System.Linq; using System.Linq;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
namespace hass_workstation_service.Domain.Sensors namespace hass_workstation_service.Domain.Sensors
{ {
public enum DetectionMode
{
Registry,
OpenCV
}
public class WebcamActiveSensor : AbstractSensor public class WebcamActiveSensor : AbstractSensor
{ {
public DetectionMode DetectionMode { get; private set; } public WebcamActiveSensor(MqttPublisher publisher, int? updateInterval = null, string name = "WebcamActive", Guid id = default) : base(publisher, name, updateInterval ?? 10, id)
public WebcamActiveSensor(MqttPublisher publisher, int? updateInterval = null, string name = "WebcamActive", DetectionMode detectionMode = DetectionMode.Registry, Guid id = default(Guid)) : base(publisher, name, updateInterval ?? 10, id)
{ {
this.DetectionMode = detectionMode;
} }
public override string GetState() public override string GetState()
{ {
switch (this.DetectionMode) if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{ {
case DetectionMode.Registry:
return IsWebCamInUseRegistry() ? "True" : "False"; return IsWebCamInUseRegistry() ? "True" : "False";
case DetectionMode.OpenCV:
return IsWebCamInUseOpenCV() ? "True" : "False";
default:
return "Error";
} }
else
{
return "unsupported";
}
} }
public override AutoDiscoveryConfigModel GetAutoDiscoveryConfig() public override AutoDiscoveryConfigModel GetAutoDiscoveryConfig()
{ {
@ -43,35 +35,7 @@ namespace hass_workstation_service.Domain.Sensors
}); });
} }
private bool IsWebCamInUseOpenCV() [SupportedOSPlatform("windows")]
{
try
{
VideoCapture capture = new VideoCapture(0);
OutputArray image = OutputArray.Create(new Mat());
// capture.Read() return false if it doesn't succeed in capturing
if (capture.Read(image))
{
capture.Release();
capture.Dispose();
return false;
}
else
{
capture.Release();
capture.Dispose();
return true;
}
}
catch (Exception)
{
return false;
}
}
private bool IsWebCamInUseRegistry() private bool IsWebCamInUseRegistry()
{ {
using (var key = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\CapabilityAccessManager\ConsentStore\webcam\NonPackaged")) using (var key = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\CapabilityAccessManager\ConsentStore\webcam\NonPackaged"))

@ -73,13 +73,14 @@ namespace hass_workstation_service
} }
public static IHostBuilder CreateHostBuilder(string[] args) => public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args) Host.CreateDefaultBuilder(args)
.UseSerilog() .ConfigureLogging((hostContext, loggingBuilder) =>
loggingBuilder.AddSerilog(dispose: true))
.ConfigureServices((hostContext, services) => .ConfigureServices((hostContext, services) =>
{ {
var deviceConfig = new DeviceConfigModel var deviceConfig = new DeviceConfigModel
{ {
Name = Environment.MachineName, Name = Environment.MachineName,
Identifiers = "hass-workstation-service", Identifiers = "hass-workstation-service" + Environment.MachineName,
Manufacturer = Environment.UserName, Manufacturer = Environment.UserName,
Model = Environment.OSVersion.ToString(), Model = Environment.OSVersion.ToString(),
Sw_version = GetVersion() Sw_version = GetVersion()

@ -33,15 +33,15 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
<SignatureAlgorithm>sha256RSA</SignatureAlgorithm> <SignatureAlgorithm>sha256RSA</SignatureAlgorithm>
<SignManifests>True</SignManifests> <SignManifests>True</SignManifests>
<SupportUrl>https://github.com/sleevezipper/hass-workstation-service</SupportUrl> <SupportUrl>https://github.com/sleevezipper/hass-workstation-service</SupportUrl>
<TargetFramework>netcoreapp3.1</TargetFramework> <TargetFramework>net5.0</TargetFramework>
<TrustUrlParameters>True</TrustUrlParameters> <TrustUrlParameters>True</TrustUrlParameters>
<UpdateEnabled>True</UpdateEnabled> <UpdateEnabled>True</UpdateEnabled>
<UpdateMode>Foreground</UpdateMode> <UpdateMode>Foreground</UpdateMode>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<BootstrapperPackage Include="Microsoft.NetCore.CoreRuntime.3.1.x64"> <BootstrapperPackage Include="Microsoft.NetCore.CoreRuntime.5.0.x64">
<Install>true</Install> <Install>true</Install>
<ProductName>.NET Core Runtime 3.1.10 (x64)</ProductName> <ProductName>.NET Runtime 5.0.1 (x64)</ProductName>
</BootstrapperPackage> </BootstrapperPackage>
</ItemGroup> </ItemGroup>
</Project> </Project>

@ -4,7 +4,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
--> -->
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup> <PropertyGroup>
<ApplicationRevision>1</ApplicationRevision> <ApplicationRevision>6</ApplicationRevision>
<ApplicationVersion>1.0.0.*</ApplicationVersion> <ApplicationVersion>1.0.0.*</ApplicationVersion>
<BootstrapperEnabled>True</BootstrapperEnabled> <BootstrapperEnabled>True</BootstrapperEnabled>
<Configuration>Release</Configuration> <Configuration>Release</Configuration>
@ -19,23 +19,23 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
<MapFileExtensions>true</MapFileExtensions> <MapFileExtensions>true</MapFileExtensions>
<OpenBrowserOnPublish>false</OpenBrowserOnPublish> <OpenBrowserOnPublish>false</OpenBrowserOnPublish>
<Platform>Any CPU</Platform> <Platform>Any CPU</Platform>
<PublishDir>bin\publish\</PublishDir> <PublishDir>bin\clickonce-framework-dependent\</PublishDir>
<PublishUrl>bin\publish\</PublishUrl> <PublishUrl>bin\clickonce-framework-dependent\</PublishUrl>
<PublishProtocol>ClickOnce</PublishProtocol> <PublishProtocol>ClickOnce</PublishProtocol>
<PublishReadyToRun>True</PublishReadyToRun> <PublishReadyToRun>False</PublishReadyToRun>
<PublishSingleFile>True</PublishSingleFile> <PublishSingleFile>False</PublishSingleFile>
<RuntimeIdentifier>win-x64</RuntimeIdentifier> <RuntimeIdentifier>win-x64</RuntimeIdentifier>
<SelfContained>False</SelfContained> <SelfContained>False</SelfContained>
<SignatureAlgorithm>sha256RSA</SignatureAlgorithm> <SignatureAlgorithm>sha256RSA</SignatureAlgorithm>
<SignManifests>True</SignManifests> <SignManifests>True</SignManifests>
<TargetFramework>netcoreapp3.1</TargetFramework> <TargetFramework>net5.0</TargetFramework>
<UpdateEnabled>False</UpdateEnabled> <UpdateEnabled>False</UpdateEnabled>
<UpdateMode>Foreground</UpdateMode> <UpdateMode>Foreground</UpdateMode>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<BootstrapperPackage Include="Microsoft.NetCore.CoreRuntime.3.1.x64"> <BootstrapperPackage Include="Microsoft.NetCore.CoreRuntime.5.0.x64">
<Install>true</Install> <Install>true</Install>
<ProductName>.NET Core Runtime 3.1.10 (x64)</ProductName> <ProductName>.NET Runtime 5.0.1 (x64)</ProductName>
</BootstrapperPackage> </BootstrapperPackage>
</ItemGroup> </ItemGroup>
</Project> </Project>

@ -4,7 +4,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
--> -->
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup> <PropertyGroup>
<ApplicationRevision>36</ApplicationRevision> <ApplicationRevision>37</ApplicationRevision>
<ApplicationVersion>1.0.0.*</ApplicationVersion> <ApplicationVersion>1.0.0.*</ApplicationVersion>
<BootstrapperEnabled>True</BootstrapperEnabled> <BootstrapperEnabled>True</BootstrapperEnabled>
<Configuration>Release</Configuration> <Configuration>Release</Configuration>
@ -28,14 +28,14 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
<SelfContained>False</SelfContained> <SelfContained>False</SelfContained>
<SignatureAlgorithm>sha256RSA</SignatureAlgorithm> <SignatureAlgorithm>sha256RSA</SignatureAlgorithm>
<SignManifests>True</SignManifests> <SignManifests>True</SignManifests>
<TargetFramework>netcoreapp3.1</TargetFramework> <TargetFramework>net5.0</TargetFramework>
<UpdateEnabled>False</UpdateEnabled> <UpdateEnabled>False</UpdateEnabled>
<UpdateMode>Foreground</UpdateMode> <UpdateMode>Foreground</UpdateMode>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<BootstrapperPackage Include="Microsoft.NetCore.CoreRuntime.3.1.x64"> <BootstrapperPackage Include="Microsoft.NetCore.CoreRuntime.5.0.x64">
<Install>true</Install> <Install>true</Install>
<ProductName>.NET Core Runtime 3.1.10 (x64)</ProductName> <ProductName>.NET Runtime 5.0.1 (x64)</ProductName>
</BootstrapperPackage> </BootstrapperPackage>
</ItemGroup> </ItemGroup>
</Project> </Project>

@ -8,7 +8,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
<Platform>Any CPU</Platform> <Platform>Any CPU</Platform>
<PublishDir>bin\Manual\</PublishDir> <PublishDir>bin\Manual\</PublishDir>
<PublishProtocol>FileSystem</PublishProtocol> <PublishProtocol>FileSystem</PublishProtocol>
<TargetFramework>netcoreapp3.1</TargetFramework> <TargetFramework>net5.0</TargetFramework>
<SelfContained>true</SelfContained> <SelfContained>true</SelfContained>
<RuntimeIdentifier>win-x64</RuntimeIdentifier> <RuntimeIdentifier>win-x64</RuntimeIdentifier>
<PublishSingleFile>False</PublishSingleFile> <PublishSingleFile>False</PublishSingleFile>

@ -0,0 +1,35 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
https://go.microsoft.com/fwlink/?LinkID=208121.
-->
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ApplicationRevision>1</ApplicationRevision>
<ApplicationVersion>1.0.0.*</ApplicationVersion>
<BootstrapperEnabled>True</BootstrapperEnabled>
<Configuration>Release</Configuration>
<CreateDesktopShortcut>True</CreateDesktopShortcut>
<GenerateManifests>True</GenerateManifests>
<Install>true</Install>
<InstallFrom>Disk</InstallFrom>
<IsRevisionIncremented>True</IsRevisionIncremented>
<IsWebBootstrapper>False</IsWebBootstrapper>
<ManifestCertificateThumbprint>820B7EDF3E26E24BB4C25B177A05B3D0C77BF73A</ManifestCertificateThumbprint>
<ManifestKeyFile>hass-workstation-service_TemporaryKey.pfx</ManifestKeyFile>
<MapFileExtensions>true</MapFileExtensions>
<OpenBrowserOnPublish>false</OpenBrowserOnPublish>
<Platform>Any CPU</Platform>
<PublishDir>bin\clickonce-selfcontained\</PublishDir>
<PublishUrl>bin\clickonce-selfcontained\</PublishUrl>
<PublishProtocol>ClickOnce</PublishProtocol>
<PublishReadyToRun>False</PublishReadyToRun>
<PublishSingleFile>False</PublishSingleFile>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
<SelfContained>True</SelfContained>
<SignatureAlgorithm>sha256RSA</SignatureAlgorithm>
<SignManifests>True</SignManifests>
<TargetFramework>net5.0</TargetFramework>
<UpdateEnabled>False</UpdateEnabled>
<UpdateMode>Foreground</UpdateMode>
</PropertyGroup>
</Project>

@ -5,7 +5,6 @@ using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using hass_workstation_service.Communication; using hass_workstation_service.Communication;
using hass_workstation_service.Data; using hass_workstation_service.Data;
using hass_workstation_service.Domain.Notify;
using hass_workstation_service.Domain.Sensors; using hass_workstation_service.Domain.Sensors;
using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk.Worker"> <Project Sdk="Microsoft.NET.Sdk.Worker">
<PropertyGroup> <PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework> <TargetFramework>net5.0</TargetFramework>
<UserSecretsId>dotnet-hass_workstation_service-C65C2EBE-1977-4C24-AC6B-6921877E1390</UserSecretsId> <UserSecretsId>dotnet-hass_workstation_service-C65C2EBE-1977-4C24-AC6B-6921877E1390</UserSecretsId>
<RootNamespace>hass_workstation_service</RootNamespace> <RootNamespace>hass_workstation_service</RootNamespace>
<OutputType>WinExe</OutputType> <OutputType>WinExe</OutputType>
@ -24,11 +24,15 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Remove="libSkiaSharp.dll" />
<None Remove="UserInterface.exe" /> <None Remove="UserInterface.exe" />
<None Remove="UserInterface.pdb" /> <None Remove="UserInterface.pdb" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Content Include="libSkiaSharp.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="UserInterface.exe"> <Content Include="UserInterface.exe">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content> </Content>
@ -46,8 +50,9 @@
<PackageReference Include="Microsoft.Win32.Registry" Version="5.0.0" /> <PackageReference Include="Microsoft.Win32.Registry" Version="5.0.0" />
<PackageReference Include="Microsoft.Windows.SDK.Contracts" Version="10.0.19041.1" /> <PackageReference Include="Microsoft.Windows.SDK.Contracts" Version="10.0.19041.1" />
<PackageReference Include="MQTTnet" Version="3.0.13" /> <PackageReference Include="MQTTnet" Version="3.0.13" />
<PackageReference Include="OpenCvSharp4.Windows" Version="4.5.1.20201229" /> <PackageReference Include="Serilog.Extensions.Logging.File" Version="2.0.0" />
<PackageReference Include="Serilog.AspNetCore" Version="3.4.0" /> <PackageReference Include="Serilog.Sinks.Console" Version="3.1.1" />
<PackageReference Include="Serilog.Sinks.File" Version="4.1.0" />
<PackageReference Include="System.Management" Version="5.0.0" /> <PackageReference Include="System.Management" Version="5.0.0" />
</ItemGroup> </ItemGroup>
</Project> </Project>

Loading…
Cancel
Save