Merge branch 'develop'

pull/163/head 1.0.0.29957
Sleevezipper 3 years ago
commit 7fd20a4fc5

@ -17,7 +17,7 @@
<PackageReference Include="Avalonia.ReactiveUI" Version="0.10.8" /> <PackageReference Include="Avalonia.ReactiveUI" Version="0.10.8" />
<PackageReference Include="Avalonia.Win32" Version="0.10.8" /> <PackageReference Include="Avalonia.Win32" Version="0.10.8" />
<PackageReference Include="JKang.IpcServiceFramework.Client.NamedPipe" Version="3.1.0" /> <PackageReference Include="JKang.IpcServiceFramework.Client.NamedPipe" Version="3.1.0" />
<PackageReference Include="Serilog.Sinks.Console" Version="4.0.0" /> <PackageReference Include="Serilog.Sinks.Console" Version="4.0.1" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\hass-workstation-service\hass-workstation-service.csproj" /> <ProjectReference Include="..\hass-workstation-service\hass-workstation-service.csproj" />

@ -13,6 +13,7 @@ namespace UserInterface.ViewModels
private bool _showWindowNameInput; private bool _showWindowNameInput;
private string _moreInfoLink; private string _moreInfoLink;
private string _query; private string _query;
private string _scope;
private string _windowName; private string _windowName;
public AvailableSensors SelectedType { get => _selectedType; set => this.RaiseAndSetIfChanged(ref _selectedType, value); } public AvailableSensors SelectedType { get => _selectedType; set => this.RaiseAndSetIfChanged(ref _selectedType, value); }
@ -23,6 +24,7 @@ namespace UserInterface.ViewModels
public bool ShowWindowNameInput { get => _showWindowNameInput; set => this.RaiseAndSetIfChanged(ref _showWindowNameInput, 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 MoreInfoLink { get => _moreInfoLink; set => this.RaiseAndSetIfChanged(ref _moreInfoLink, value); }
public string Query { get => _query; set => this.RaiseAndSetIfChanged(ref _query, value); } public string Query { get => _query; set => this.RaiseAndSetIfChanged(ref _query, value); }
public string Scope { get => _scope; set => this.RaiseAndSetIfChanged(ref _scope, value); }
public string WindowName { get => _windowName; set => this.RaiseAndSetIfChanged(ref _windowName, value); } public string WindowName { get => _windowName; set => this.RaiseAndSetIfChanged(ref _windowName, value); }
} }
} }

@ -16,6 +16,9 @@ namespace UserInterface.ViewModels
private bool isConnected; private bool isConnected;
private int? port; private int? port;
private bool useTLS; private bool useTLS;
private bool retainLWT = true;
private string rootCaPath;
private string clientCertPath;
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); }
@ -29,6 +32,13 @@ namespace UserInterface.ViewModels
public bool UseTLS { get => useTLS; set => this.RaiseAndSetIfChanged(ref useTLS, value); } public bool UseTLS { get => useTLS; set => this.RaiseAndSetIfChanged(ref useTLS, value); }
public bool RetainLWT { get => retainLWT; set => this.RaiseAndSetIfChanged(ref retainLWT, value); }
public string RootCAPath { get => rootCaPath; set => this.RaiseAndSetIfChanged(ref rootCaPath, value); }
public string ClientCertPath { get => clientCertPath; set => this.RaiseAndSetIfChanged(ref clientCertPath, value); }
public void Update(MqttSettings settings) public void Update(MqttSettings settings)
{ {
this.Host = settings.Host; this.Host = settings.Host;
@ -36,6 +46,9 @@ namespace UserInterface.ViewModels
this.Password = settings.Password; this.Password = settings.Password;
this.Port = settings.Port; this.Port = settings.Port;
this.UseTLS = settings.UseTLS; this.UseTLS = settings.UseTLS;
this.RetainLWT = settings.RetainLWT;
this.RootCAPath = settings.RootCAPath;
this.ClientCertPath = settings.ClientCertPath;
} }
public void UpdateStatus(MqqtClientStatus status) public void UpdateStatus(MqqtClientStatus status)

@ -21,6 +21,8 @@
<TextBox Text="{Binding UpdateInterval}" HorizontalAlignment="Right" MaxWidth="30"/> <TextBox Text="{Binding UpdateInterval}" HorizontalAlignment="Right" MaxWidth="30"/>
</StackPanel> </StackPanel>
<TextBlock Text="{Binding UpdateInterval, StringFormat= Update every {0} seconds}" HorizontalAlignment="Left" MinWidth="150"/> <TextBlock Text="{Binding UpdateInterval, StringFormat= Update every {0} seconds}" HorizontalAlignment="Left" MinWidth="150"/>
<ContentControl IsVisible="{Binding ShowQueryInput}" Margin="0 20 0 10">Scope (optional)</ContentControl>
<TextBox IsVisible="{Binding ShowQueryInput}" Text="{Binding Scope}" Watermark="\\localhost\ROOT\StandardCimv2" HorizontalAlignment="Left" MinWidth="300"/>
<ContentControl IsVisible="{Binding ShowQueryInput}" Margin="0 20 0 10">Query</ContentControl> <ContentControl IsVisible="{Binding ShowQueryInput}" Margin="0 20 0 10">Query</ContentControl>
<TextBox IsVisible="{Binding ShowQueryInput}" Text="{Binding Query}" Watermark="SELECT Name FROM Win32_Processor" HorizontalAlignment="Left" MinWidth="300"/> <TextBox IsVisible="{Binding ShowQueryInput}" Text="{Binding Query}" Watermark="SELECT Name FROM Win32_Processor" HorizontalAlignment="Left" MinWidth="300"/>
<ContentControl IsVisible="{Binding ShowWindowNameInput}" Margin="0 20 0 5">Window name</ContentControl> <ContentControl IsVisible="{Binding ShowWindowNameInput}" Margin="0 20 0 5">Window name</ContentControl>

@ -67,6 +67,7 @@ namespace UserInterface.Views
item.Name = sensor.Name; item.Name = sensor.Name;
item.UpdateInterval = sensor.UpdateInterval; item.UpdateInterval = sensor.UpdateInterval;
item.Query = sensor.Query; item.Query = sensor.Query;
item.Scope = sensor.Scope;
item.WindowName = sensor.WindowName; item.WindowName = sensor.WindowName;
Title = $"Edit {sensor.Name}"; Title = $"Edit {sensor.Name}";
@ -75,7 +76,7 @@ namespace UserInterface.Views
public async void Save(object sender, RoutedEventArgs args) public async void Save(object sender, RoutedEventArgs args)
{ {
var item = (AddSensorViewModel)DataContext; var item = (AddSensorViewModel)DataContext;
dynamic model = new { item.Name, item.Query, item.UpdateInterval, item.WindowName }; dynamic model = new { item.Name, item.Query, item.UpdateInterval, item.WindowName, item.Scope };
string json = JsonSerializer.Serialize(model); string json = JsonSerializer.Serialize(model);
if (SensorId == Guid.Empty) if (SensorId == Guid.Empty)
await _client.InvokeAsync(x => x.AddSensor(item.SelectedType, json)); await _client.InvokeAsync(x => x.AddSensor(item.SelectedType, json));
@ -172,6 +173,13 @@ namespace UserInterface.Views
item.UpdateInterval = 10; item.UpdateInterval = 10;
break; break;
case AvailableSensors.MicrophoneProcessSensor:
item.Description = "This sensor shows which process is using the microphone.";
item.MoreInfoLink = "https://github.com/sleevezipper/hass-workstation-service/blob/master/documentation/Sensors.md#microphoneprocesssensor";
item.ShowQueryInput = false;
item.UpdateInterval = 10;
break;
case AvailableSensors.NamedWindowSensor: case AvailableSensors.NamedWindowSensor:
item.Description = "This sensor returns true if a window was found with the name you search for. "; 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/blob/master/documentation/Sensors.md#namedwindowsensor"; item.MoreInfoLink = "https://github.com/sleevezipper/hass-workstation-service/blob/master/documentation/Sensors.md#namedwindowsensor";

@ -4,7 +4,7 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="500" d:DesignHeight="450" mc:Ignorable="d" d:DesignWidth="500" d:DesignHeight="450"
x:Class="UserInterface.Views.BrokerSettings"> x:Class="UserInterface.Views.BrokerSettings">
<StackPanel Margin="30" HorizontalAlignment="Left" ScrollViewer.VerticalScrollBarVisibility="Auto"> <StackPanel Margin="30" HorizontalAlignment="Left" MinWidth="250">
<ContentControl FontSize="18" FontWeight="Bold">MQTT Broker</ContentControl> <ContentControl FontSize="18" FontWeight="Bold">MQTT Broker</ContentControl>
<TextBlock IsVisible="{Binding IsConnected}" Foreground="Green" Text="{Binding Message}"></TextBlock > <TextBlock IsVisible="{Binding IsConnected}" Foreground="Green" Text="{Binding Message}"></TextBlock >
<TextBlock IsVisible="{Binding !IsConnected}" Foreground="Red" Text="{Binding Message}"></TextBlock > <TextBlock IsVisible="{Binding !IsConnected}" Foreground="Red" Text="{Binding Message}"></TextBlock >
@ -25,6 +25,65 @@
<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>
<TextBox Text="{Binding Password}" MinWidth="150" PasswordChar="•"/> <TextBox Text="{Binding Password}" MinWidth="150" PasswordChar="•"/>
<Expander Header="Advanced" Margin="0 20 0 0">
<StackPanel>
<StackPanel>
<StackPanel Margin="0 20 0 10" HorizontalAlignment="Left" Orientation="Horizontal">
<ContentControl>Retain LastWillAndTestament</ContentControl>
<TextBlock Cursor="Help" Margin="5 0 0 0" VerticalAlignment="Bottom" TextDecorations="Underline">
(What's this?)
<ToolTip.Tip>
<StackPanel>
<TextBlock>
[Experimental]
If set, sets Retain on the Last Will and Testament message.
Only turn this off if you use a broker that does not support this(e.g. AWS IoT Core)
Defaults to True
</TextBlock>
</StackPanel>
</ToolTip.Tip>
</TextBlock>
</StackPanel>
<CheckBox IsChecked="{Binding RetainLWT}" HorizontalAlignment="Left" Margin="0 0 0 0"/>
</StackPanel>
<StackPanel Margin="0 20 0 10" HorizontalAlignment="Left" Orientation="Horizontal">
<ContentControl>Root Cert Path (.pem/.crt)</ContentControl>
<TextBlock Cursor="Help" Margin="5 0 0 0" VerticalAlignment="Bottom" TextDecorations="Underline">
(What's this?)
<ToolTip.Tip>
<StackPanel>
<TextBlock>
[Experimental]
If set, use this certificate in the TLS configuration for the MQTT connection.
This will be a pem or crt file provided by your broker.
</TextBlock>
</StackPanel>
</ToolTip.Tip>
</TextBlock>
</StackPanel>
<TextBox Text="{Binding RootCAPath}" MinWidth="150"/>
<StackPanel Margin="0 20 0 10" HorizontalAlignment="Left" Orientation="Horizontal">
<ContentControl>Client Cert Path (.pfx)</ContentControl>
<TextBlock Cursor="Help" Margin="5 0 0 0" VerticalAlignment="Bottom" TextDecorations="Underline">
(What's this?)
<ToolTip.Tip>
<StackPanel>
<TextBlock>
[Experimental]
If set, use this certificate in the TLS configuration for the MQTT connection.
This should be the private key .pfx file for a device created in your broker corresponding to this Windows PC.
</TextBlock>
</StackPanel>
</ToolTip.Tip>
</TextBlock>
</StackPanel>
<TextBox Text="{Binding ClientCertPath}" MinWidth="150"/>
</StackPanel>
</Expander>
<Button Width="75" HorizontalAlignment="Right" Margin="0 40 0 10" Click="Configure">Save</Button> <Button Width="75" HorizontalAlignment="Right" Margin="0 40 0 10" Click="Configure">Save</Button>
</StackPanel> </StackPanel>
</UserControl> </UserControl>

@ -50,7 +50,7 @@ namespace UserInterface.Views
ICollection<ValidationResult> results; ICollection<ValidationResult> results;
if (model.IsValid(model, out 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 })); 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, RootCAPath = model.RootCAPath, ClientCertPath = model.ClientCertPath, RetainLWT = model.RetainLWT }));
} }
} }

@ -4,7 +4,7 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="500" d:DesignHeight="450" mc:Ignorable="d" d:DesignWidth="500" d:DesignHeight="450"
x:Class="UserInterface.Views.GeneralSettingsView"> x:Class="UserInterface.Views.GeneralSettingsView">
<StackPanel Margin="30" HorizontalAlignment="Left"> <StackPanel Margin="30" HorizontalAlignment="Left" MinWidth="250">
<ContentControl FontSize="18" FontWeight="Bold">Settings</ContentControl> <ContentControl FontSize="18" FontWeight="Bold">Settings</ContentControl>
<StackPanel Margin="0 20 0 10" HorizontalAlignment="Left" Orientation="Horizontal"> <StackPanel Margin="0 20 0 10" HorizontalAlignment="Left" Orientation="Horizontal">
<ContentControl>Name prefix</ContentControl> <ContentControl>Name prefix</ContentControl>

@ -14,17 +14,18 @@
<Design.DataContext> <Design.DataContext>
<vm:MainWindowViewModel/> <vm:MainWindowViewModel/>
</Design.DataContext> </Design.DataContext>
<ScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled">
<Grid ColumnDefinitions="Auto, *, Auto" Margin="10"> <Grid ColumnDefinitions="Auto, *, Auto" RowDefinitions="Auto, *" Margin="10">
<Grid.RowDefinitions> <ScrollViewer Grid.Column="0" Grid.Row="0" Margin="10" Grid.RowSpan="2" >
<RowDefinition MinHeight="500"></RowDefinition> <StackPanel>
<RowDefinition></RowDefinition> <views:BrokerSettings Background="#2D2D30"/>
</Grid.RowDefinitions> <views:GeneralSettingsView Margin="0 20 0 0" Background="#2D2D30"/>
<views:BrokerSettings Grid.Column="0" Grid.Row="0" Margin="10" Grid.RowSpan="2" MinHeight="500" Background="#2D2D30"/> </StackPanel>
<views:GeneralSettingsView Grid.Column="0" Grid.Row="1" Margin="10" Grid.RowSpan="2" Background="#2D2D30"/> </ScrollViewer>
<views:SensorSettings Grid.Column="1" Grid.Row="0" Margin="10" Background="#2D2D30"/> <views:SensorSettings Grid.Column="1" Grid.Row="0" Margin="10" Background="#2D2D30"/>
<views:CommandSettings Grid.Column="1" Grid.Row="1" Margin="10" Background="#2D2D30"/> <views:CommandSettings Grid.Column="1" Grid.Row="1" Margin="10" Background="#2D2D30"/>
<views:BackgroundServiceSettings Grid.Column="2" Grid.Row="0" Margin="10" Background="#2D2D30"/> <views:BackgroundServiceSettings Grid.Column="2" Grid.Row="0" Margin="10" Background="#2D2D30"/>
<views:AppInfo Grid.Column="2" Grid.Row="1" Margin="10" Background="#2D2D30"/> <views:AppInfo Grid.Column="2" Grid.Row="1" Margin="10" Background="#2D2D30"/>
</Grid> </Grid>
</ScrollViewer>
</Window> </Window>

@ -89,6 +89,10 @@ The webcam active sensor returns the status of the webcam.
The webcam process sensor returns the process which is using the webcam. The webcam process sensor returns the process which is using the webcam.
### MicrophoneProcessSensor
The microphone process sensor returns the process which is using the microphone.
### WMIQuerySensor ### WMIQuerySensor
Please see the specific documentaion page [here](https://github.com/sleevezipper/hass-workstation-service/blob/master/documentation/WMIQuery.md#wmiquerysensor). Please see the specific documentaion page [here](https://github.com/sleevezipper/hass-workstation-service/blob/master/documentation/WMIQuery.md#wmiquerysensor).

@ -13,7 +13,7 @@ The command ```sql SELECT * FROM Win32_Processor``` cannot be used because it re
You can use [WMI Explorer](https://github.com/vinaypamnani/wmie2/releases) to construct a query, or alternatively look at the user submitted sensors below You can use [WMI Explorer](https://github.com/vinaypamnani/wmie2/releases) to construct a query, or alternatively look at the user submitted sensors below
If a class or value cannot be found in the default scope, you can use the "Scope" setting when adding or editing the sensor.
--- ---
## User Submitted Sensor Examples ## User Submitted Sensor Examples

@ -173,12 +173,13 @@ namespace hass_workstation_service.Communication.InterProcesCommunication
AvailableSensors.DummySensor => new DummySensor(_publisher, (int)model.UpdateInterval, model.Name), AvailableSensors.DummySensor => new DummySensor(_publisher, (int)model.UpdateInterval, model.Name),
AvailableSensors.CurrentClockSpeedSensor => new CurrentClockSpeedSensor(_publisher, (int)model.UpdateInterval, model.Name), AvailableSensors.CurrentClockSpeedSensor => new CurrentClockSpeedSensor(_publisher, (int)model.UpdateInterval, model.Name),
AvailableSensors.CPULoadSensor => new CPULoadSensor(_publisher, (int)model.UpdateInterval, model.Name), AvailableSensors.CPULoadSensor => new CPULoadSensor(_publisher, (int)model.UpdateInterval, model.Name),
AvailableSensors.WMIQuerySensor => new WMIQuerySensor(_publisher, model.Query, (int)model.UpdateInterval, model.Name), AvailableSensors.WMIQuerySensor => new WMIQuerySensor(_publisher, model.Query, (int)model.UpdateInterval, model.Name, scope: model.Scope),
AvailableSensors.MemoryUsageSensor => new MemoryUsageSensor(_publisher, (int)model.UpdateInterval, model.Name), AvailableSensors.MemoryUsageSensor => new MemoryUsageSensor(_publisher, (int)model.UpdateInterval, model.Name),
AvailableSensors.ActiveWindowSensor => new ActiveWindowSensor(_publisher, (int)model.UpdateInterval, model.Name), AvailableSensors.ActiveWindowSensor => new ActiveWindowSensor(_publisher, (int)model.UpdateInterval, model.Name),
AvailableSensors.WebcamActiveSensor => new WebcamActiveSensor(_publisher, (int)model.UpdateInterval, model.Name), AvailableSensors.WebcamActiveSensor => new WebcamActiveSensor(_publisher, (int)model.UpdateInterval, model.Name),
AvailableSensors.WebcamProcessSensor => new WebcamProcessSensor(_publisher, (int)model.UpdateInterval, model.Name), AvailableSensors.WebcamProcessSensor => new WebcamProcessSensor(_publisher, (int)model.UpdateInterval, model.Name),
AvailableSensors.MicrophoneActiveSensor => new MicrophoneActiveSensor(_publisher, (int)model.UpdateInterval, model.Name), AvailableSensors.MicrophoneActiveSensor => new MicrophoneActiveSensor(_publisher, (int)model.UpdateInterval, model.Name),
AvailableSensors.MicrophoneProcessSensor => new MicrophoneProcessSensor(_publisher, (int)model.UpdateInterval, model.Name),
AvailableSensors.NamedWindowSensor => new NamedWindowSensor(_publisher, model.WindowName, model.Name, (int)model.UpdateInterval), AvailableSensors.NamedWindowSensor => new NamedWindowSensor(_publisher, model.WindowName, model.Name, (int)model.UpdateInterval),
AvailableSensors.LastActiveSensor => new LastActiveSensor(_publisher, (int)model.UpdateInterval, model.Name), AvailableSensors.LastActiveSensor => new LastActiveSensor(_publisher, (int)model.UpdateInterval, model.Name),
AvailableSensors.LastBootSensor => new LastBootSensor(_publisher, (int)model.UpdateInterval, model.Name), AvailableSensors.LastBootSensor => new LastBootSensor(_publisher, (int)model.UpdateInterval, model.Name),

@ -11,6 +11,10 @@ namespace hass_workstation_service.Communication.InterProcesCommunication.Models
public string Password { get; set; } public string Password { get; set; }
public int? Port { get; set; } public int? Port { get; set; }
public bool UseTLS { get; set; } public bool UseTLS { get; set; }
public bool RetainLWT { get; set; }
public string RootCAPath { get; set; }
public string ClientCertPath { get; set; }
} }
public class MqqtClientStatus public class MqqtClientStatus
@ -26,6 +30,7 @@ namespace hass_workstation_service.Communication.InterProcesCommunication.Models
public string Name { get; set; } public string Name { get; set; }
public string Value { get; set; } public string Value { get; set; }
public string Query { get; set; } public string Query { get; set; }
public string Scope { get; set; }
public string WindowName { get; set; } public string WindowName { get; set; }
public int UpdateInterval { get; set; } public int UpdateInterval { get; set; }
public string UnitOfMeasurement { get; set; } public string UnitOfMeasurement { get; set; }
@ -40,6 +45,7 @@ namespace hass_workstation_service.Communication.InterProcesCommunication.Models
if (sensor is WMIQuerySensor wMIQuerySensor) if (sensor is WMIQuerySensor wMIQuerySensor)
{ {
this.Query = wMIQuerySensor.Query; this.Query = wMIQuerySensor.Query;
this.Scope = wMIQuerySensor.Scope;
} }
if (sensor is NamedWindowSensor namedWindowSensor) if (sensor is NamedWindowSensor namedWindowSensor)
{ {
@ -95,6 +101,7 @@ namespace hass_workstation_service.Communication.InterProcesCommunication.Models
WebcamActiveSensor, WebcamActiveSensor,
WebcamProcessSensor, WebcamProcessSensor,
MicrophoneActiveSensor, MicrophoneActiveSensor,
MicrophoneProcessSensor,
ActiveWindowSensor, ActiveWindowSensor,
NamedWindowSensor, NamedWindowSensor,
LastActiveSensor, LastActiveSensor,

@ -116,7 +116,7 @@ namespace hass_workstation_service.Communication
var message = new MqttApplicationMessageBuilder() var message = new MqttApplicationMessageBuilder()
.WithTopic($"homeassistant/{discoverable.Domain}/{this.DeviceConfigModel.Name}/{DiscoveryConfigModel.GetNameWithPrefix(discoverable.GetAutoDiscoveryConfig().NamePrefix, discoverable.ObjectId)}/config") .WithTopic($"homeassistant/{discoverable.Domain}/{this.DeviceConfigModel.Name}/{DiscoveryConfigModel.GetNameWithPrefix(discoverable.GetAutoDiscoveryConfig().NamePrefix, discoverable.ObjectId)}/config")
.WithPayload(clearConfig ? "" : JsonSerializer.Serialize(discoverable.GetAutoDiscoveryConfig(), discoverable.GetAutoDiscoveryConfig().GetType(), options)) .WithPayload(clearConfig ? "" : JsonSerializer.Serialize(discoverable.GetAutoDiscoveryConfig(), discoverable.GetAutoDiscoveryConfig().GetType(), options))
.WithRetainFlag() //.WithRetainFlag()
.Build(); .Build();
await this.Publish(message); await this.Publish(message);
// if clearconfig is true, also remove previous state messages // if clearconfig is true, also remove previous state messages
@ -125,7 +125,7 @@ namespace hass_workstation_service.Communication
var stateMessage = new MqttApplicationMessageBuilder() var stateMessage = new MqttApplicationMessageBuilder()
.WithTopic($"homeassistant/{discoverable.Domain}/{this.DeviceConfigModel.Name}/{DiscoveryConfigModel.GetNameWithPrefix(discoverable.GetAutoDiscoveryConfig().NamePrefix, discoverable.ObjectId)}/state") .WithTopic($"homeassistant/{discoverable.Domain}/{this.DeviceConfigModel.Name}/{DiscoveryConfigModel.GetNameWithPrefix(discoverable.GetAutoDiscoveryConfig().NamePrefix, discoverable.ObjectId)}/state")
.WithPayload("") .WithPayload("")
.WithRetainFlag() // .WithRetainFlag()
.Build(); .Build();
await this.Publish(stateMessage); await this.Publish(stateMessage);
} }

@ -5,6 +5,7 @@ using System.Linq;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Runtime.Versioning; using System.Runtime.Versioning;
using System.Security; using System.Security;
using System.Security.Cryptography.X509Certificates;
using System.Text.Json; using System.Text.Json;
using System.Threading.Tasks; using System.Threading.Tasks;
using hass_workstation_service.Communication; using hass_workstation_service.Communication;
@ -20,6 +21,7 @@ using MQTTnet.Client.Options;
using MQTTnet.Extensions.ManagedClient; using MQTTnet.Extensions.ManagedClient;
using Serilog; using Serilog;
namespace hass_workstation_service.Data namespace hass_workstation_service.Data
{ {
public class ConfigurationService : IConfigurationService public class ConfigurationService : IConfigurationService
@ -135,6 +137,9 @@ namespace hass_workstation_service.Data
case "MicrophoneActiveSensor": case "MicrophoneActiveSensor":
sensor = new MicrophoneActiveSensor(publisher, configuredSensor.UpdateInterval, configuredSensor.Name, configuredSensor.Id); sensor = new MicrophoneActiveSensor(publisher, configuredSensor.UpdateInterval, configuredSensor.Name, configuredSensor.Id);
break; break;
case "MicrophoneProcessSensor":
sensor = new MicrophoneProcessSensor(publisher, configuredSensor.UpdateInterval, configuredSensor.Name, configuredSensor.Id);
break;
case "SessionStateSensor": case "SessionStateSensor":
sensor = new SessionStateSensor(publisher, configuredSensor.UpdateInterval, configuredSensor.Name, configuredSensor.Id); sensor = new SessionStateSensor(publisher, configuredSensor.UpdateInterval, configuredSensor.Name, configuredSensor.Id);
break; break;
@ -152,7 +157,7 @@ namespace hass_workstation_service.Data
break; break;
// keep this one last! // keep this one last!
case "WMIQuerySensor": case "WMIQuerySensor":
sensor = new WMIQuerySensor(publisher, configuredSensor.Query, configuredSensor.UpdateInterval, configuredSensor.Name, configuredSensor.Id); sensor = new WMIQuerySensor(publisher, configuredSensor.Query, configuredSensor.UpdateInterval, configuredSensor.Name, configuredSensor.Id, configuredSensor.Scope);
break; break;
default: default:
Log.Logger.Error("unsupported sensor type in config"); Log.Logger.Error("unsupported sensor type in config");
@ -205,22 +210,22 @@ namespace hass_workstation_service.Data
case "CustomCommand": case "CustomCommand":
command = new CustomCommand(publisher, configuredCommand.Command, configuredCommand.Name, configuredCommand.Id); command = new CustomCommand(publisher, configuredCommand.Command, configuredCommand.Name, configuredCommand.Id);
break; break;
case "MediaPlayPauseCommand": case "PlayPauseCommand":
command = new PlayPauseCommand(publisher, configuredCommand.Name, configuredCommand.Id); command = new PlayPauseCommand(publisher, configuredCommand.Name, configuredCommand.Id);
break; break;
case "MediaNextCommand": case "NextCommand":
command = new NextCommand(publisher, configuredCommand.Name, configuredCommand.Id); command = new NextCommand(publisher, configuredCommand.Name, configuredCommand.Id);
break; break;
case "MediaPreviousCommand": case "PreviousCommand":
command = new PreviousCommand(publisher, configuredCommand.Name, configuredCommand.Id); command = new PreviousCommand(publisher, configuredCommand.Name, configuredCommand.Id);
break; break;
case "MediaVolumeUpCommand": case "VolumeUpCommand":
command = new VolumeUpCommand(publisher, configuredCommand.Name, configuredCommand.Id); command = new VolumeUpCommand(publisher, configuredCommand.Name, configuredCommand.Id);
break; break;
case "MediaVolumeDownCommand": case "VolumeDownCommand":
command = new VolumeDownCommand(publisher, configuredCommand.Name, configuredCommand.Id); command = new VolumeDownCommand(publisher, configuredCommand.Name, configuredCommand.Id);
break; break;
case "MediaMuteCommand": case "MuteCommand":
command = new MuteCommand(publisher, configuredCommand.Name, configuredCommand.Id); command = new MuteCommand(publisher, configuredCommand.Name, configuredCommand.Id);
break; break;
case "KeyCommand": case "KeyCommand":
@ -307,22 +312,54 @@ namespace hass_workstation_service.Data
if (configuredBroker != null && configuredBroker.Host != null) if (configuredBroker != null && configuredBroker.Host != null)
{ {
var mqttClientOptions = new MqttClientOptionsBuilder()
var mqttClientOptionsBuilder = new MqttClientOptionsBuilder()
.WithTcpServer(configuredBroker.Host, configuredBroker.Port) .WithTcpServer(configuredBroker.Host, configuredBroker.Port)
.WithTls(new MqttClientOptionsBuilderTlsParameters() .WithCredentials(configuredBroker.Username, configuredBroker.Password.ToString())
.WithKeepAlivePeriod(TimeSpan.FromSeconds(30));
/* Start LWT */
var lwtMessage = new MqttApplicationMessageBuilder()
.WithTopic($"homeassistant/sensor/{_deviceConfigModel.Name}/availability")
.WithPayload("offline");
if (configuredBroker.RetainLWT) {
lwtMessage.WithRetainFlag();
}
mqttClientOptionsBuilder.WithWillMessage(lwtMessage.Build());
/* End LWT */
/* Start TLS/Certificate configuration */
var tlsParameters = new MqttClientOptionsBuilderTlsParameters()
{ {
UseTls = configuredBroker.UseTLS, UseTls = configuredBroker.UseTLS,
AllowUntrustedCertificates = true, AllowUntrustedCertificates = true,
SslProtocol = configuredBroker.UseTLS ? System.Security.Authentication.SslProtocols.Tls12 : System.Security.Authentication.SslProtocols.None SslProtocol = configuredBroker.UseTLS ? System.Security.Authentication.SslProtocols.Tls12 : System.Security.Authentication.SslProtocols.None
}) };
.WithCredentials(configuredBroker.Username, configuredBroker.Password.ToString())
.WithKeepAlivePeriod(TimeSpan.FromSeconds(30)) var certs = new List<X509Certificate>();
.WithWillMessage(new MqttApplicationMessageBuilder()
.WithRetainFlag() if (!string.IsNullOrEmpty(configuredBroker.RootCAPath)) {
.WithTopic($"homeassistant/sensor/{_deviceConfigModel.Name}/availability") certs.Add(new X509Certificate2(configuredBroker.RootCAPath));
.WithPayload("offline") }
.Build())
.Build(); if (!string.IsNullOrEmpty(configuredBroker.ClientCertPath))
{
certs.Add(new X509Certificate2(configuredBroker.ClientCertPath));
}
if (certs.Count > 0) {
// IF certs are configured, let's add them here
tlsParameters.Certificates = certs;
}
mqttClientOptionsBuilder.WithTls(tlsParameters);
/* End TLS/Certificate Configuration */
var mqttClientOptions = mqttClientOptionsBuilder.Build();
return new ManagedMqttClientOptionsBuilder().WithClientOptions(mqttClientOptions).Build(); return new ManagedMqttClientOptionsBuilder().WithClientOptions(mqttClientOptions).Build();
} }
else else
@ -375,7 +412,7 @@ namespace hass_workstation_service.Data
if (sensor is WMIQuerySensor wmiSensor) if (sensor is WMIQuerySensor wmiSensor)
{ {
#pragma warning disable CA1416 // Validate platform compatibility. We ignore it here because this would never happen. A cleaner solution may be implemented later. #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, Scope = wmiSensor.Scope });
#pragma warning restore CA1416 // Validate platform compatibility #pragma warning restore CA1416 // Validate platform compatibility
} }
else if (sensor is NamedWindowSensor namedWindowSensor) else if (sensor is NamedWindowSensor namedWindowSensor)
@ -541,7 +578,10 @@ namespace hass_workstation_service.Data
Username = settings.Username, Username = settings.Username,
Password = settings.Password ?? "", Password = settings.Password ?? "",
Port = settings.Port ?? 1883, Port = settings.Port ?? 1883,
UseTLS = settings.UseTLS UseTLS = settings.UseTLS,
RetainLWT = settings.RetainLWT,
RootCAPath = settings.RootCAPath,
ClientCertPath = settings.ClientCertPath
}; };
await JsonSerializer.SerializeAsync(stream, configuredBroker); await JsonSerializer.SerializeAsync(stream, configuredBroker);
@ -560,7 +600,10 @@ namespace hass_workstation_service.Data
Username = broker?.Username, Username = broker?.Username,
Password = broker?.Password, Password = broker?.Password,
Port = broker?.Port, Port = broker?.Port,
UseTLS = broker?.UseTLS ?? false UseTLS = broker?.UseTLS ?? false,
RetainLWT = broker?.RetainLWT ?? true,
RootCAPath = broker?.RootCAPath,
ClientCertPath = broker?.RootCAPath
}; };
} }

@ -9,10 +9,32 @@ namespace hass_workstation_service.Data
private string password; private string password;
private int? port; private int? port;
private string rootCAPath;
private string clientCertPath;
public string Host { get; set; } public string Host { get; set; }
public int Port { get => port ?? 1883; set => port = value; } public int Port { get => port ?? 1883; set => port = value; }
public bool UseTLS { get; set; } public bool UseTLS { get; set; }
// Before this option, Retains was the default, so let's keep that here to not break backwards compatibility
public bool RetainLWT { get; set; } = true;
public string RootCAPath {
get
{
if (rootCAPath!= null) return rootCAPath;
return "";
}
set => rootCAPath = value;
}
public string ClientCertPath {
get
{
if (clientCertPath != null) return clientCertPath;
return "";
}
set => clientCertPath = value;
}
public string Username public string Username
{ {

@ -9,6 +9,7 @@ namespace hass_workstation_service.Data
public Guid Id { get; set; } public Guid Id { get; set; }
public string Name { get; set; } public string Name { get; set; }
public string Query { get; set; } public string Query { get; set; }
public string Scope { get; set; }
public int? UpdateInterval { get; set; } public int? UpdateInterval { get; set; }
public string WindowName { get; set; } public string WindowName { get; set; }
} }

@ -40,8 +40,8 @@ namespace hass_workstation_service.Domain.Commands
var message = new MqttApplicationMessageBuilder() var message = new MqttApplicationMessageBuilder()
.WithTopic(GetAutoDiscoveryConfig().State_topic) .WithTopic(GetAutoDiscoveryConfig().State_topic)
.WithPayload(state) .WithPayload(state)
.WithExactlyOnceQoS() //.WithExactlyOnceQoS()
.WithRetainFlag() //.WithRetainFlag()
.Build(); .Build();
await Publisher.Publish(message); await Publisher.Publish(message);
PreviousPublishedState = state; PreviousPublishedState = state;

@ -40,8 +40,8 @@ namespace hass_workstation_service.Domain.Sensors
var message = new MqttApplicationMessageBuilder() var message = new MqttApplicationMessageBuilder()
.WithTopic(GetAutoDiscoveryConfig().State_topic) .WithTopic(GetAutoDiscoveryConfig().State_topic)
.WithPayload(state) .WithPayload(state)
.WithExactlyOnceQoS() //.WithExactlyOnceQoS()
.WithRetainFlag() //.WithRetainFlag()
.Build(); .Build();
await Publisher.Publish(message); await Publisher.Publish(message);
PreviousPublishedState = state; PreviousPublishedState = state;

@ -6,7 +6,7 @@ namespace hass_workstation_service.Domain.Sensors
{ {
public class LastActiveSensor : AbstractSensor public class LastActiveSensor : AbstractSensor
{ {
private DateTime _lastActive = DateTime.MinValue;
public LastActiveSensor(MqttPublisher publisher, int? updateInterval = 10, string name = "LastActive", Guid id = default) : base(publisher, name ?? "LastActive", updateInterval ?? 10, id){} public LastActiveSensor(MqttPublisher publisher, int? updateInterval = 10, string name = "LastActive", Guid id = default) : base(publisher, name ?? "LastActive", updateInterval ?? 10, id){}
public override SensorDiscoveryConfigModel GetAutoDiscoveryConfig() public override SensorDiscoveryConfigModel GetAutoDiscoveryConfig()
@ -25,7 +25,12 @@ namespace hass_workstation_service.Domain.Sensors
public override string GetState() public override string GetState()
{ {
return GetLastInputTime().ToString("o", System.Globalization.CultureInfo.InvariantCulture); var lastInput = GetLastInputTime();
if ((_lastActive - lastInput).Duration().TotalSeconds > 1)
{
_lastActive = lastInput;
}
return _lastActive.ToString("o", System.Globalization.CultureInfo.InvariantCulture);
} }

@ -0,0 +1,96 @@
using hass_workstation_service.Communication;
using Microsoft.Win32;
using System;
using System.Linq;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Collections.Generic;
namespace hass_workstation_service.Domain.Sensors
{
public class MicrophoneProcessSensor : AbstractSensor
{
private HashSet<string> processes = new HashSet<string>();
public MicrophoneProcessSensor(MqttPublisher publisher, int? updateInterval = null, string name = "MicrophoneProcess", Guid id = default) : base(publisher, name ?? "MicrophoneProcess", updateInterval ?? 10, id)
{
}
public override string GetState()
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
return IsMicrophoneInUseRegistry();
}
else
{
return "unsupported";
}
}
public override SensorDiscoveryConfigModel GetAutoDiscoveryConfig()
{
return this._autoDiscoveryConfigModel ?? SetAutoDiscoveryConfigModel(new SensorDiscoveryConfigModel()
{
Name = this.Name,
NamePrefix = Publisher.NamePrefix,
Unique_id = this.Id.ToString(),
Device = this.Publisher.DeviceConfigModel,
State_topic = $"homeassistant/{this.Domain}/{Publisher.DeviceConfigModel.Name}/{DiscoveryConfigModel.GetNameWithPrefix(Publisher.NamePrefix, this.ObjectId)}/state",
Availability_topic = $"homeassistant/sensor/{Publisher.DeviceConfigModel.Name}/availability"
});
}
[SupportedOSPlatform("windows")]
private void CheckLastUsed(RegistryKey key)
{
foreach (var subKeyName in key.GetSubKeyNames())
{
// NonPackaged has multiple subkeys
if (subKeyName == "NonPackaged")
{
using (var nonpackagedkey = key.OpenSubKey(subKeyName))
{
CheckLastUsed(nonpackagedkey);
}
}
else
{
using (var subKey = key.OpenSubKey(subKeyName))
{
if (subKey.GetValueNames().Contains("LastUsedTimeStop"))
{
var endTime = subKey.GetValue("LastUsedTimeStop") is long ? (long)subKey.GetValue("LastUsedTimeStop") : -1;
if (endTime <= 0)
{
this.processes.Add(subKeyName);
}
}
}
}
}
}
[SupportedOSPlatform("windows")]
private string IsMicrophoneInUseRegistry()
{
// Clear old values
this.processes.Clear();
using (var key = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\CapabilityAccessManager\ConsentStore\microphone"))
{
CheckLastUsed(key);
}
using (var key = Registry.CurrentUser.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\CapabilityAccessManager\ConsentStore\microphone"))
{
CheckLastUsed(key);
}
if (this.processes.Count() > 0)
{
return String.Join(",", this.processes.ToArray());
}
return "off";
}
}
}

@ -12,13 +12,26 @@ namespace hass_workstation_service.Domain.Sensors
public class WMIQuerySensor : AbstractSensor public class WMIQuerySensor : AbstractSensor
{ {
public string Query { get; private set; } public string Query { get; private set; }
public string Scope { 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) : base(publisher, name ?? "WMIQuerySensor", updateInterval ?? 10, id) public WMIQuerySensor(MqttPublisher publisher, string query, int? updateInterval = null, string name = "WMIQuerySensor", Guid id = default, string scope = "") : base(publisher, name ?? "WMIQuerySensor", updateInterval ?? 10, id)
{ {
this.Query = query; this.Query = query;
this.Scope = scope;
_objectQuery = new ObjectQuery(this.Query); _objectQuery = new ObjectQuery(this.Query);
_searcher = new ManagementObjectSearcher(query); ManagementScope managementscope;
// if we have a custom scope, use that
if (!string.IsNullOrWhiteSpace(scope))
{
managementscope = new ManagementScope(scope);
}
// otherwise, use the default
else
{
managementscope = new ManagementScope(@"\\localhost\");
}
_searcher = new ManagementObjectSearcher(managementscope, _objectQuery);
} }
public override SensorDiscoveryConfigModel GetAutoDiscoveryConfig() public override SensorDiscoveryConfigModel GetAutoDiscoveryConfig()
{ {

@ -4,11 +4,14 @@ using System;
using System.Linq; using System.Linq;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Runtime.Versioning; using System.Runtime.Versioning;
using System.Collections.Generic;
namespace hass_workstation_service.Domain.Sensors namespace hass_workstation_service.Domain.Sensors
{ {
public class WebcamProcessSensor : AbstractSensor public class WebcamProcessSensor : AbstractSensor
{ {
private HashSet<string> processes = new HashSet<string>();
public WebcamProcessSensor(MqttPublisher publisher, int? updateInterval = null, string name = "WebcamProcess", Guid id = default) : base(publisher, name ?? "WebcamProcess", updateInterval ?? 10, id) public WebcamProcessSensor(MqttPublisher publisher, int? updateInterval = null, string name = "WebcamProcess", Guid id = default) : base(publisher, name ?? "WebcamProcess", updateInterval ?? 10, id)
{ {
} }
@ -38,9 +41,7 @@ namespace hass_workstation_service.Domain.Sensors
} }
[SupportedOSPlatform("windows")] [SupportedOSPlatform("windows")]
private string IsWebCamInUseRegistry() private void CheckLastUsed(RegistryKey key)
{
using (var key = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\CapabilityAccessManager\ConsentStore\webcam"))
{ {
foreach (var subKeyName in key.GetSubKeyNames()) foreach (var subKeyName in key.GetSubKeyNames())
{ {
@ -49,20 +50,7 @@ namespace hass_workstation_service.Domain.Sensors
{ {
using (var nonpackagedkey = key.OpenSubKey(subKeyName)) using (var nonpackagedkey = key.OpenSubKey(subKeyName))
{ {
foreach (var nonpackagedSubKeyName in nonpackagedkey.GetSubKeyNames()) CheckLastUsed(nonpackagedkey);
{
using (var subKey = nonpackagedkey.OpenSubKey(nonpackagedSubKeyName))
{
if (subKey.GetValueNames().Contains("LastUsedTimeStop"))
{
var endTime = subKey.GetValue("LastUsedTimeStop") is long ? (long)subKey.GetValue("LastUsedTimeStop") : -1;
if (endTime <= 0)
{
return nonpackagedSubKeyName;
}
}
}
}
} }
} }
else else
@ -74,7 +62,7 @@ namespace hass_workstation_service.Domain.Sensors
var endTime = subKey.GetValue("LastUsedTimeStop") is long ? (long)subKey.GetValue("LastUsedTimeStop") : -1; var endTime = subKey.GetValue("LastUsedTimeStop") is long ? (long)subKey.GetValue("LastUsedTimeStop") : -1;
if (endTime <= 0) if (endTime <= 0)
{ {
return subKeyName; this.processes.Add(subKeyName);
} }
} }
} }
@ -82,48 +70,26 @@ namespace hass_workstation_service.Domain.Sensors
} }
} }
using (var key = Registry.CurrentUser.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\CapabilityAccessManager\ConsentStore\webcam")) [SupportedOSPlatform("windows")]
{ private string IsWebCamInUseRegistry()
foreach (var subKeyName in key.GetSubKeyNames())
{
// NonPackaged has multiple subkeys
if (subKeyName == "NonPackaged")
{
using (var nonpackagedkey = key.OpenSubKey(subKeyName))
{
foreach (var nonpackagedSubKeyName in nonpackagedkey.GetSubKeyNames())
{
using (var subKey = nonpackagedkey.OpenSubKey(nonpackagedSubKeyName))
{
if (subKey.GetValueNames().Contains("LastUsedTimeStop"))
{ {
var endTime = subKey.GetValue("LastUsedTimeStop") is long ? (long)subKey.GetValue("LastUsedTimeStop") : -1; // Clear old values
if (endTime <= 0) this.processes.Clear();
using (var key = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\CapabilityAccessManager\ConsentStore\webcam"))
{ {
return nonpackagedSubKeyName; CheckLastUsed(key);
}
}
} }
}
} using (var key = Registry.CurrentUser.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\CapabilityAccessManager\ConsentStore\webcam"))
}
else
{
using (var subKey = key.OpenSubKey(subKeyName))
{
if (subKey.GetValueNames().Contains("LastUsedTimeStop"))
{
var endTime = subKey.GetValue("LastUsedTimeStop") is long ? (long)subKey.GetValue("LastUsedTimeStop") : -1;
if (endTime <= 0)
{ {
return subKeyName; CheckLastUsed(key);
}
}
}
}
}
} }
if (this.processes.Count() > 0)
{
return String.Join(",", this.processes.ToArray());
}
return "off"; return "off";
} }
} }

@ -4,11 +4,12 @@ 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>57</ApplicationRevision> <ApplicationRevision>58</ApplicationRevision>
<ApplicationVersion>1.0.0.*</ApplicationVersion> <ApplicationVersion>1.0.0.*</ApplicationVersion>
<BootstrapperEnabled>True</BootstrapperEnabled> <BootstrapperEnabled>True</BootstrapperEnabled>
<Configuration>Release</Configuration> <Configuration>Release</Configuration>
<CreateDesktopShortcut>True</CreateDesktopShortcut> <CreateDesktopShortcut>True</CreateDesktopShortcut>
<CreateWebPageOnPublish>True</CreateWebPageOnPublish>
<ErrorReportUrl>https://github.com/sleevezipper/hass-workstation-service</ErrorReportUrl> <ErrorReportUrl>https://github.com/sleevezipper/hass-workstation-service</ErrorReportUrl>
<GenerateManifests>True</GenerateManifests> <GenerateManifests>True</GenerateManifests>
<Install>true</Install> <Install>true</Install>
@ -16,8 +17,8 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
<InstallUrl>https://hassworkstationstorage.z6.web.core.windows.net/publish/</InstallUrl> <InstallUrl>https://hassworkstationstorage.z6.web.core.windows.net/publish/</InstallUrl>
<IsRevisionIncremented>True</IsRevisionIncremented> <IsRevisionIncremented>True</IsRevisionIncremented>
<IsWebBootstrapper>True</IsWebBootstrapper> <IsWebBootstrapper>True</IsWebBootstrapper>
<ManifestCertificateThumbprint>820B7EDF3E26E24BB4C25B177A05B3D0C77BF73A</ManifestCertificateThumbprint> <ManifestCertificateThumbprint>66F1CEE175B90B89AFD3AA8F5F649268BF4DFA9E</ManifestCertificateThumbprint>
<ManifestKeyFile>hass-workstation-service_TemporaryKey.pfx</ManifestKeyFile> <ManifestKeyFile>hass-workstation-service_1_TemporaryKey.pfx</ManifestKeyFile>
<MapFileExtensions>true</MapFileExtensions> <MapFileExtensions>true</MapFileExtensions>
<OpenBrowserOnPublish>false</OpenBrowserOnPublish> <OpenBrowserOnPublish>false</OpenBrowserOnPublish>
<Platform>Any CPU</Platform> <Platform>Any CPU</Platform>
@ -37,12 +38,13 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
<TrustUrlParameters>True</TrustUrlParameters> <TrustUrlParameters>True</TrustUrlParameters>
<UpdateEnabled>True</UpdateEnabled> <UpdateEnabled>True</UpdateEnabled>
<UpdateMode>Foreground</UpdateMode> <UpdateMode>Foreground</UpdateMode>
<History>False|2021-11-14T15:44:38.1032015Z;</History> <UpdateRequired>False</UpdateRequired>
<WebPageFileName>Publish.html</WebPageFileName>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<BootstrapperPackage Include="Microsoft.NetCore.CoreRuntime.5.0.x64"> <BootstrapperPackage Include="Microsoft.NetCore.CoreRuntime.5.0.x64">
<Install>true</Install> <Install>True</Install>
<ProductName>.NET Runtime 5.0.1 (x64)</ProductName> <ProductName>.NET Runtime 5.0.12 (x64)</ProductName>
</BootstrapperPackage> </BootstrapperPackage>
</ItemGroup> </ItemGroup>
</Project> </Project>

@ -43,7 +43,7 @@
<CopyToOutputDirectory>Always</CopyToOutputDirectory> <CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content> </Content>
<Content Include="UserInterface.pdb"> <Content Include="UserInterface.pdb">
<CopyToOutputDirectory>Always</CopyToOutputDirectory> <CopyToOutputDirectory>Never</CopyToOutputDirectory>
</Content> </Content>
</ItemGroup> </ItemGroup>
@ -55,15 +55,15 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="JKang.IpcServiceFramework.Hosting.NamedPipe" Version="3.1.0" /> <PackageReference Include="JKang.IpcServiceFramework.Hosting.NamedPipe" Version="3.1.0" />
<PackageReference Include="LibreHardwareMonitorLib" Version="0.8.8" /> <PackageReference Include="LibreHardwareMonitorLib" Version="0.8.9" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="5.0.0" /> <PackageReference Include="Microsoft.Extensions.Hosting" Version="6.0.0" />
<PackageReference Include="Microsoft.Win32.Registry" Version="5.0.0" /> <PackageReference Include="Microsoft.Win32.Registry" Version="5.0.0" />
<PackageReference Include="MQTTnet" Version="3.0.16" /> <PackageReference Include="MQTTnet" Version="3.1.1" />
<PackageReference Include="MQTTnet.Extensions.ManagedClient" Version="3.0.16" /> <PackageReference Include="MQTTnet.Extensions.ManagedClient" Version="3.1.1" />
<PackageReference Include="Serilog.Extensions.Logging.File" Version="2.0.0" /> <PackageReference Include="Serilog.Extensions.Logging.File" Version="2.0.0" />
<PackageReference Include="Serilog.Sinks.Console" Version="4.0.0" /> <PackageReference Include="Serilog.Sinks.Console" Version="4.0.1" />
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" /> <PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
<PackageReference Include="System.Management" Version="5.0.0" /> <PackageReference Include="System.Management" Version="6.0.0" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

Loading…
Cancel
Save