add ui for sensors and improve many things

pull/9/head
sleevezipper 4 years ago
parent 1c0fe97c1b
commit db89b725de

@ -8,6 +8,7 @@
<Application.Styles> <Application.Styles>
<StyleInclude Source="avares://Avalonia.Themes.Default/DefaultTheme.xaml"/> <StyleInclude Source="avares://Avalonia.Themes.Default/DefaultTheme.xaml"/>
<StyleInclude Source="avares://Avalonia.Themes.Default/Accents/BaseLight.xaml"/> <StyleInclude Source="avares://Avalonia.Themes.Default/Accents/BaseDark.xaml"/>
<StyleInclude Source="avares://Avalonia.Controls.DataGrid/Themes/Default.xaml"/>
</Application.Styles> </Application.Styles>
</Application> </Application>

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<OutputType>WinExe</OutputType> <OutputType>WinExe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework> <TargetFramework>netcoreapp3.1</TargetFramework>
@ -12,6 +12,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Avalonia" Version="0.9.12" /> <PackageReference Include="Avalonia" Version="0.9.12" />
<PackageReference Include="Avalonia.Controls.DataGrid" Version="0.9.12" />
<PackageReference Include="Avalonia.Desktop" Version="0.9.12" /> <PackageReference Include="Avalonia.Desktop" Version="0.9.12" />
<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" />

@ -0,0 +1,40 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Text;
namespace UserInterface.Util
{
public class BrowserUtil
{
public static void OpenBrowser(string url)
{
try
{
Process.Start(url);
}
catch
{
// hack because of this: https://github.com/dotnet/corefx/issues/10361
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
url = url.Replace("&", "^&");
Process.Start(new ProcessStartInfo("cmd", $"/c start {url}") { CreateNoWindow = true });
}
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
{
Process.Start("xdg-open", url);
}
else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
{
Process.Start("open", url);
}
else
{
throw;
}
}
}
}
}

@ -0,0 +1,28 @@
using hass_workstation_service.Communication.InterProcesCommunication.Models;
using ReactiveUI;
using System;
using System.Collections.Generic;
using System.Text;
namespace UserInterface.ViewModels
{
public class AddSensorViewModel : ViewModelBase
{
private AvailableSensors selectedType;
private string description;
public string Description { get => description; set => this.RaiseAndSetIfChanged(ref description, value); }
private string moreInfoLink;
public string MoreInfoLink
{
get { return moreInfoLink; }
set { this.RaiseAndSetIfChanged(ref moreInfoLink, value); }
}
public AvailableSensors SelectedType { get => selectedType; set => this.RaiseAndSetIfChanged(ref selectedType, value); }
public string Name { get; set; }
}
}

@ -0,0 +1,24 @@
using ReactiveUI;
using System;
using System.Collections.Generic;
using System.Text;
namespace UserInterface.ViewModels
{
public class SensorSettingsViewModel : ViewModelBase
{
private ICollection<SensorViewModel> configuredSensors;
public ICollection<SensorViewModel> ConfiguredSensors { get => configuredSensors; set => this.RaiseAndSetIfChanged(ref configuredSensors, value); }
}
public class SensorViewModel : ViewModelBase
{
private string _value;
public Guid Id { get; set; }
public string Type { get; set; }
public string Name { get; set; }
public string Value { get => _value; set => this.RaiseAndSetIfChanged(ref _value, value); }
}
}

@ -0,0 +1,19 @@
<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="UserInterface.Views.AddSensorDialog"
SizeToContent="WidthAndHeight"
Title="Add sensor">
<StackPanel Margin="40" MinWidth="200">
<ContentControl Margin="0 20 0 10">Sensor type</ContentControl>
<ComboBox x:Name="ComboBox" SelectionChanged="ComboBoxClosed" SelectedItem="{Binding SelectedType}" MinHeight="27"></ComboBox>
<TextBlock Margin="0 10 0 10" MaxWidth="300" TextWrapping="Wrap" TextAlignment="Left" Text="{Binding Description}"></TextBlock>
<Button IsVisible="{Binding MoreInfoLink, Converter={x:Static StringConverters.IsNotNullOrEmpty}}" Click="OpenInfo" Margin="0 10 0 10">Click for more information.</Button>
<ContentControl Margin="0 20 0 10">Name</ContentControl>
<TextBox Text="{Binding Name}" HorizontalAlignment="Left" Width="150"/>
<Button Width="75" HorizontalAlignment="Right" Margin="0 40 0 10" Click="Save">Save</Button>
</StackPanel>
</Window>

@ -0,0 +1,86 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Interactivity;
using Avalonia.Markup.Xaml;
using hass_workstation_service.Communication.InterProcesCommunication.Models;
using hass_workstation_service.Communication.NamedPipe;
using JKang.IpcServiceFramework.Client;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Dynamic;
using System.Linq;
using System.Text.Json;
using UserInterface.Util;
using UserInterface.ViewModels;
namespace UserInterface.Views
{
public class AddSensorDialog : Window
{
private readonly IIpcClient<ServiceContractInterfaces> client;
public ComboBox comboBox { get; set; }
public AddSensorDialog()
{
this.InitializeComponent();
#if DEBUG
this.AttachDevTools();
#endif
this.comboBox = this.FindControl<ComboBox>("ComboBox");
this.comboBox.Items = Enum.GetValues(typeof(AvailableSensors)).Cast<AvailableSensors>();
// register IPC clients
ServiceProvider serviceProvider = new ServiceCollection()
.AddNamedPipeIpcClient<ServiceContractInterfaces>("addsensor", pipeName: "pipeinternal")
.BuildServiceProvider();
// resolve IPC client factory
IIpcClientFactory<ServiceContractInterfaces> clientFactory = serviceProvider
.GetRequiredService<IIpcClientFactory<ServiceContractInterfaces>>();
// create client
this.client = clientFactory.CreateClient("addsensor");
DataContext = new AddSensorViewModel();
}
public async void Save(object sender, RoutedEventArgs args)
{
var item = ((AddSensorViewModel)this.DataContext);
dynamic model = new { Name = item.Name };
string json = JsonSerializer.Serialize(model);
await this.client.InvokeAsync(x => x.AddSensor(item.SelectedType, json));
Close();
}
public void ComboBoxClosed(object sender, SelectionChangedEventArgs args)
{
var item = ((AddSensorViewModel)this.DataContext);
switch (item.SelectedType)
{
case AvailableSensors.UserNotificationStateSensor:
item.Description = "This sensor watches the UserNotificationState. This is normally used in applications to determine if it is appropriate to send a notification but we can use it to expose this state. \n ";
item.MoreInfoLink = "https://github.com/sleevezipper/hass-workstation-service#usernotificationstate";
break;
case AvailableSensors.DummySensor:
item.Description = "This sensor spits out a random number every second. Useful for testing, maybe you'll find some other use for it.";
item.MoreInfoLink = "https://github.com/sleevezipper/hass-workstation-service#dummy";
break;
default:
item.Description = null;
item.MoreInfoLink = null;
break;
}
}
public void OpenInfo(object sender, RoutedEventArgs args)
{
var item = ((AddSensorViewModel)this.DataContext);
BrowserUtil.OpenBrowser(item.MoreInfoLink);
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}
}
}

@ -8,17 +8,15 @@
x:Class="UserInterface.Views.MainWindow" x:Class="UserInterface.Views.MainWindow"
Icon="/Assets/hass-workstation-logo.ico" Icon="/Assets/hass-workstation-logo.ico"
SizeToContent="WidthAndHeight" SizeToContent="WidthAndHeight"
Title="Settings" Title="Settings">
Background="LightGray"> <Design.DataContext>
<vm:MainWindowViewModel/>
<Design.DataContext> </Design.DataContext>
<vm:MainWindowViewModel/>
</Design.DataContext>
<Grid ColumnDefinitions="Auto,1*,Auto" RowDefinitions="Auto,Auto,Auto" Margin="30"> <Grid ColumnDefinitions="Auto,1*,Auto" RowDefinitions="Auto,Auto,Auto" Margin="30">
<views:BrokerSettings Grid.Column="0" Grid.Row="0" Margin="10 0" Background="White"/> <views:BrokerSettings Grid.Column="0" Grid.Row="0" Margin="10 0" Background="#2D2D30"/>
<views:SensorSettings Grid.Column="1" Grid.Row="0" Margin="10 0" Background="White"/> <views:SensorSettings Grid.Column="1" Grid.Row="0" Margin="10 0" Background="#2D2D30"/>
<views:BackgroundServiceSettings Grid.Column="2" Grid.Row="0" Margin="10 0" Background="White"/> <views:BackgroundServiceSettings Grid.Column="2" Grid.Row="0" Margin="10 0" Background="#2D2D30"/>
<!--<views:BrokerSettings Grid.Column="1" Grid.Row="0"/> <!--<views:BrokerSettings Grid.Column="1" Grid.Row="0"/>
<views:BrokerSettings Grid.Column="2" Grid.Row="0"/>--> <views:BrokerSettings Grid.Column="2" Grid.Row="0"/>-->
@ -28,7 +26,7 @@
<CheckBox Content="Col2Row0" Grid.Row="0" Grid.Column="2"/> <CheckBox Content="Col2Row0" Grid.Row="0" Grid.Column="2"/>
<Button Content="SpansCol1-2Row1-2" Grid.Row="1" Grid.Column="1" Grid.RowSpan="2" Grid.ColumnSpan="2"/>--> <Button Content="SpansCol1-2Row1-2" Grid.Row="1" Grid.Column="1" Grid.RowSpan="2" Grid.ColumnSpan="2"/>-->
</Grid> </Grid>
<!--<TextBlock Text="{Binding Greeting}" HorizontalAlignment="Center" VerticalAlignment="Center"/>--> <!--<TextBlock Text="{Binding Greeting}" HorizontalAlignment="Center" VerticalAlignment="Center"/>-->
</Window> </Window>

@ -4,17 +4,25 @@
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"
MaxWidth="500" MaxWidth="500"
x:Class="UserInterface.Views.SensorSettings"> x:Class="UserInterface.Views.SensorSettings" >
<StackPanel Margin="30" HorizontalAlignment="Left" > <StackPanel Margin="30" HorizontalAlignment="Left" >
<ContentControl FontSize="18" FontWeight="Bold">Mqtt broker</ContentControl> <DataGrid x:Name="Grid" IsVisible="{Binding ConfiguredSensors.Count}" AutoGenerateColumns="False" IsReadOnly="True" SelectionMode="Single" Items="{Binding ConfiguredSensors}">
<TextBlock IsVisible="{Binding IsConnected}" Foreground="Green" Text="{Binding Message}"></TextBlock >
<TextBlock IsVisible="{Binding !IsConnected}" Foreground="Red" Text="{Binding Message}"></TextBlock > <DataGrid.Columns>
<ContentControl FontSize="18" Margin="0 30 0 10">IP or hostname</ContentControl> <DataGridTextColumn Header="Name"
<TextBox Text="{Binding Host}" HorizontalAlignment="Left" Width="100" Watermark="192.168.1.200"/> Binding="{Binding Name}"
<ContentControl FontSize="18" Margin="0 30 0 10">Username</ContentControl> Width="1*" />
<TextBox Text="{Binding Username}" Width="200"/> <DataGridTextColumn Header="Type"
<ContentControl FontSize="18" Margin="0 30 0 10">Password</ContentControl> Binding="{Binding Type}"
<TextBox Text="{Binding Password}" Width="200" PasswordChar="•"/> Width="1*" />
<Button Width="75" HorizontalAlignment="Right" Margin="0 40 0 10" Click="Configure">Save</Button> <DataGridTextColumn Header="Value"
Binding="{Binding Value}"
Width="1*" />
</DataGrid.Columns>
</DataGrid>
<TextBlock IsVisible="{Binding !ConfiguredSensors.Count}">Add some sensors by clicking the "Add" button. </TextBlock>
<Button Width="75" HorizontalAlignment="Right" Margin="0 40 0 10" Click="AddSensor">Add</Button>
<Button Width="75" HorizontalAlignment="Right" Margin="0 40 0 10" Click="Delete">Delete</Button>
</StackPanel> </StackPanel>
</UserControl> </UserControl>

@ -10,12 +10,17 @@ 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.Collections.Generic;
using System.Linq;
using Avalonia.Controls.ApplicationLifetimes;
namespace UserInterface.Views namespace UserInterface.Views
{ {
public class SensorSettings : UserControl public class SensorSettings : UserControl
{ {
private readonly IIpcClient<ServiceContractInterfaces> client; private readonly IIpcClient<ServiceContractInterfaces> client;
private DataGrid _dataGrid { get; set; }
private bool sensorsNeedToRefresh { get; set; }
public SensorSettings() public SensorSettings()
{ {
@ -33,23 +38,61 @@ namespace UserInterface.Views
this.client = clientFactory.CreateClient("sensors"); this.client = clientFactory.CreateClient("sensors");
DataContext = new BrokerSettingsViewModel(); DataContext = new SensorSettingsViewModel();
GetConfiguredSensors();
this._dataGrid = this.FindControl<DataGrid>("Grid");
} }
public void Ping(object sender, RoutedEventArgs args) {
var result = this.client.InvokeAsync(x => x.Ping("ping")).Result;
}
public void Configure(object sender, RoutedEventArgs args)
public async void GetConfiguredSensors()
{ {
var model = (BrokerSettingsViewModel)this.DataContext; sensorsNeedToRefresh = false;
var result = this.client.InvokeAsync(x => x.WriteMqttBrokerSettingsAsync(new MqttSettings() { Host = model.Host, Username = model.Username, Password = model.Password })); List<ConfiguredSensorModel> status = await this.client.InvokeAsync(x => x.GetConfiguredSensors());
((SensorSettingsViewModel)this.DataContext).ConfiguredSensors = status.Select(s => new SensorViewModel() { Name = s.Name, Type = s.Type, Value = s.Value, Id = s.Id }).ToList();
while (!sensorsNeedToRefresh)
{
await Task.Delay(2000);
List<ConfiguredSensorModel> statusUpdated = await this.client.InvokeAsync(x => x.GetConfiguredSensors());
var configuredSensors = ((SensorSettingsViewModel)this.DataContext).ConfiguredSensors;
statusUpdated.ForEach(s =>
{
var configuredSensor = configuredSensors.FirstOrDefault(cs => cs.Id == s.Id);
if (configuredSensor != null)
{
configuredSensor.Value = s.Value;
configuredSensors.FirstOrDefault(cs => cs.Id == s.Id).Value = s.Value;
}
});
}
}
public void Delete(object sender, RoutedEventArgs args)
{
var item = ((SensorViewModel)this._dataGrid.SelectedItem);
this.client.InvokeAsync(x => x.RemoveSensorById(item.Id));
// TODO: improve this. it is not working well.
sensorsNeedToRefresh = true;
GetConfiguredSensors();
} }
public async void AddSensor(object sender, RoutedEventArgs args)
{
AddSensorDialog dialog = new AddSensorDialog();
if (Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
{
await dialog.ShowDialog(desktop.MainWindow);
GetConfiguredSensors();
}
}
private void InitializeComponent() private void InitializeComponent()
{ {
AvaloniaXamlLoader.Load(this); AvaloniaXamlLoader.Load(this);
} }
} }
} }

@ -1,9 +1,15 @@
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.Data; using hass_workstation_service.Data;
using hass_workstation_service.Domain.Sensors;
using Serilog;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Dynamic;
using System.Linq;
using System.Text; using System.Text;
using System.Text.Json;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace hass_workstation_service.Communication.InterProcesCommunication namespace hass_workstation_service.Communication.InterProcesCommunication
@ -57,5 +63,42 @@ namespace hass_workstation_service.Communication.InterProcesCommunication
{ {
return this._configurationService.IsAutoStartEnabled(); return this._configurationService.IsAutoStartEnabled();
} }
public List<ConfiguredSensorModel> GetConfiguredSensors()
{
return this._configurationService.ConfiguredSensors.Select(s => new ConfiguredSensorModel() { Name = s.Name, Type = s.GetType().Name, Value = s.PreviousPublishedState, Id = s.Id }).ToList();
}
public void RemoveSensorById(Guid id)
{
this._configurationService.DeleteConfiguredSensor(id);
}
public void AddSensor(AvailableSensors sensorType, string json)
{
var serializerOptions = new JsonSerializerOptions
{
Converters = { new DynamicJsonConverter() }
};
dynamic model = JsonSerializer.Deserialize<dynamic>(json, serializerOptions);
AbstractSensor sensorToCreate = null;
switch (sensorType)
{
case AvailableSensors.UserNotificationStateSensor:
sensorToCreate = new UserNotificationStateSensor(this._publisher, model.Name);
break;
case AvailableSensors.DummySensor:
sensorToCreate = new DummySensor(this._publisher, model.Name);
break;
default:
Log.Logger.Error("Unknown sensortype");
break;
}
if (sensorToCreate != null)
{
this._configurationService.AddConfiguredSensor(sensorToCreate);
}
}
} }
} }

@ -14,5 +14,8 @@ namespace hass_workstation_service.Communication.NamedPipe
MqqtClientStatus GetMqqtClientStatus(); MqqtClientStatus GetMqqtClientStatus();
void EnableAutostart(bool enable); void EnableAutostart(bool enable);
bool IsAutoStartEnabled(); bool IsAutoStartEnabled();
List<ConfiguredSensorModel> GetConfiguredSensors();
void RemoveSensorById(Guid id);
void AddSensor(AvailableSensors sensorType, string json);
} }
} }

@ -1,4 +1,5 @@
using System; using hass_workstation_service.Domain.Sensors;
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text; using System.Text;
@ -16,4 +17,18 @@ namespace hass_workstation_service.Communication.InterProcesCommunication.Models
public bool IsConnected { get; set; } public bool IsConnected { get; set; }
public string Message { get; set; } public string Message { get; set; }
} }
public class ConfiguredSensorModel
{
public Guid Id { get; set; }
public string Type { get; set; }
public string Name { get; set; }
public string Value { get; set; }
}
public enum AvailableSensors
{
UserNotificationStateSensor,
DummySensor
}
} }

@ -0,0 +1,127 @@

using System;
using System.Collections.Generic;
using System.Dynamic;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace hass_workstation_service.Communication.Util
{
/// <summary>
/// Temp Dynamic Converter
/// by:tchivs@live.cn
/// </summary>
public class DynamicJsonConverter : JsonConverter<dynamic>
{
public override dynamic Read(ref Utf8JsonReader reader,
Type typeToConvert,
JsonSerializerOptions options)
{
if (reader.TokenType == JsonTokenType.True)
{
return true;
}
if (reader.TokenType == JsonTokenType.False)
{
return false;
}
if (reader.TokenType == JsonTokenType.Number)
{
if (reader.TryGetInt64(out long l))
{
return l;
}
return reader.GetDouble();
}
if (reader.TokenType == JsonTokenType.String)
{
if (reader.TryGetDateTime(out DateTime datetime))
{
return datetime;
}
return reader.GetString();
}
if (reader.TokenType == JsonTokenType.StartObject)
{
using JsonDocument documentV = JsonDocument.ParseValue(ref reader);
return ReadObject(documentV.RootElement);
}
// Use JsonElement as fallback.
// Newtonsoft uses JArray or JObject.
JsonDocument document = JsonDocument.ParseValue(ref reader);
return document.RootElement.Clone();
}
private object ReadObject(JsonElement jsonElement)
{
IDictionary<string, object> expandoObject = new ExpandoObject();
foreach (var obj in jsonElement.EnumerateObject())
{
var k = obj.Name;
var value = ReadValue(obj.Value);
expandoObject[k] = value;
}
return expandoObject;
}
private object? ReadValue(JsonElement jsonElement)
{
object? result = null;
switch (jsonElement.ValueKind)
{
case JsonValueKind.Object:
result = ReadObject(jsonElement);
break;
case JsonValueKind.Array:
result = ReadList(jsonElement);
break;
case JsonValueKind.String:
//TODO: Missing Datetime&Bytes Convert
result = jsonElement.GetString();
break;
case JsonValueKind.Number:
//TODO: more num type
result = 0;
if (jsonElement.TryGetInt64(out long l))
{
result = l;
}
break;
case JsonValueKind.True:
result = true;
break;
case JsonValueKind.False:
result = false;
break;
case JsonValueKind.Undefined:
case JsonValueKind.Null:
result = null;
break;
default:
throw new ArgumentOutOfRangeException();
}
return result;
}
private object? ReadList(JsonElement jsonElement)
{
IList<object?> list = new List<object?>();
foreach (var item in jsonElement.EnumerateArray())
{
list.Add(ReadValue(item));
}
return list.Count == 0 ? null : list;
}
public override void Write(Utf8JsonWriter writer,
object value,
JsonSerializerOptions options)
{
// writer.WriteStringValue(value.ToString());
}
}
}

@ -123,6 +123,13 @@ namespace hass_workstation_service.Data
WriteSettingsAsync(); WriteSettingsAsync();
} }
public void DeleteConfiguredSensor(Guid id)
{
var sensorToRemove = this.ConfiguredSensors.FirstOrDefault(s => s.Id == id);
this.ConfiguredSensors.Remove(sensorToRemove);
WriteSettingsAsync();
}
public void AddConfiguredSensors(List<AbstractSensor> sensors) public void AddConfiguredSensors(List<AbstractSensor> sensors)
{ {
sensors.ForEach((sensor) => this.ConfiguredSensors.Add(sensor)); sensors.ForEach((sensor) => this.ConfiguredSensors.Add(sensor));

@ -23,5 +23,6 @@ namespace hass_workstation_service.Data
Task<MqttSettings> GetMqttBrokerSettings(); Task<MqttSettings> GetMqttBrokerSettings();
void EnableAutoStart(bool enable); void EnableAutoStart(bool enable);
bool IsAutoStartEnabled(); bool IsAutoStartEnabled();
void DeleteConfiguredSensor(Guid id);
} }
} }

@ -1,18 +0,0 @@
using System;
using System.Collections.Generic;
using hass_workstation_service.Domain.Sensors;
namespace hass_workstation_service.Domain
{
public abstract class Device
{
public Guid Id { get; private set; }
public string Name { get; private set; }
public string Manufacturer { get; private set; }
public string Model { get; private set; }
public string Version { get; private set; }
public ICollection<AbstractSensor> Sensors { get; set; }
}
}

@ -5,9 +5,7 @@ using MQTTnet;
namespace hass_workstation_service.Domain.Sensors namespace hass_workstation_service.Domain.Sensors
{ {
/// <summary>
/// This
/// </summary>
public abstract class AbstractSensor public abstract class AbstractSensor
{ {
public Guid Id { get; protected set; } public Guid Id { get; protected set; }

@ -88,11 +88,7 @@ namespace hass_workstation_service.Domain.Sensors
QuietTime = 6, QuietTime = 6,
/// <summary> /// <summary>
/// Introduced in Windows 7. The current user is in "quiet time", which is the first hour after /// A Windows Store app is running.
/// a new user logs into his or her account for the first time. During this time, most notifications
/// should not be sent or shown. This lets a user become accustomed to a new computer system
/// without those distractions.
/// Quiet time also occurs for each user after an operating system upgrade or clean installation.
/// </summary> /// </summary>
RunningWindowsStoreApp = 7 RunningWindowsStoreApp = 7
}; };

@ -34,7 +34,9 @@ namespace hass_workstation_service
// We do it this way because there is currently no way to pass an argument to a dotnet core app when using clickonce // We do it this way because there is currently no way to pass an argument to a dotnet core app when using clickonce
if (Process.GetProcessesByName("hass-workstation-service").Count() > 1) //bg service running if (Process.GetProcessesByName("hass-workstation-service").Count() > 1) //bg service running
{ {
#if !DEBUG
StartUI(); StartUI();
#endif
} }
else else
{ {

@ -4,12 +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>15</ApplicationRevision> <ApplicationRevision>20</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>
<ErrorReportUrl>https://github.com/sleevezipper/hass-workstation-service/issues</ErrorReportUrl> <ErrorReportUrl>https://github.com/sleevezipper/hass-workstation-service</ErrorReportUrl>
<GenerateManifests>True</GenerateManifests> <GenerateManifests>True</GenerateManifests>
<Install>true</Install> <Install>true</Install>
<InstallFrom>Web</InstallFrom> <InstallFrom>Web</InstallFrom>
@ -32,7 +32,7 @@ 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>
<SupportUrl>https://github.com/sleevezipper/hass-workstation-service/issues</SupportUrl> <SupportUrl>https://github.com/sleevezipper/hass-workstation-service</SupportUrl>
<TargetFramework>netcoreapp3.1</TargetFramework> <TargetFramework>netcoreapp3.1</TargetFramework>
<TrustUrlParameters>True</TrustUrlParameters> <TrustUrlParameters>True</TrustUrlParameters>
<UpdateEnabled>True</UpdateEnabled> <UpdateEnabled>True</UpdateEnabled>

@ -31,18 +31,13 @@ namespace hass_workstation_service
{ {
_configurationService.ReadSensorSettings(_mqttPublisher); _configurationService.ReadSensorSettings(_mqttPublisher);
while (!_mqttPublisher.IsConnected) while (!_mqttPublisher.IsConnected)
{ {
_logger.LogInformation($"Connecting to MQTT broker..."); _logger.LogInformation($"Connecting to MQTT broker...");
await Task.Delay(2000); await Task.Delay(2000);
} }
_logger.LogInformation("Connected. Sending auto discovery messages."); _logger.LogInformation("Connected. Sending auto discovery messages.");
// if there are no configured sensors we add a dummy sensor
if (_configurationService.ConfiguredSensors.Count == 0)
{
_configurationService.AddConfiguredSensors(new List<AbstractSensor>() { new DummySensor(_mqttPublisher), new UserNotificationStateSensor(_mqttPublisher) });
}
foreach (AbstractSensor sensor in _configurationService.ConfiguredSensors) foreach (AbstractSensor sensor in _configurationService.ConfiguredSensors)
{ {
await sensor.PublishAutoDiscoveryConfigAsync(); await sensor.PublishAutoDiscoveryConfigAsync();

Loading…
Cancel
Save