add more sensors, implement update interval, extend docs

pull/9/head
sleevezipper 4 years ago
parent de8c04f1cd
commit 1fee1cb1d1

@ -38,6 +38,42 @@ This sensor watches the UserNotificationState. This is normally used in applicat
|QuietTime|Introduced in Windows 7. The current user is in "quiet time", which is the first hour after a new user logs into his or her account for the first time. During this time, most notifications should not be sent or shown. This lets a user become accustomed to a new computer system without those distractions. Quiet time also occurs for each user after an operating system upgrade or clean installation.|
|RunningWindowsStoreApp|A Windows Store app is running.|
### CPULoad
This sensor checks the current CPU load. It averages the load on all logical cores every second and rounds the output to two decimals.
### UsedMemory
This sensor calculates the percentage of used memory.
### CurrentClockSpeed
This sensor returns the BIOS configured baseclock for the processor.
### WMIQuery
This advanced sensor executes a user defined [WMI query](https://docs.microsoft.com/en-us/windows/win32/wmisdk/wmi-and-sql) and exposes the result. The query should return a single value.
For example:
```sql
SELECT * FROM Win32_Processor
```
returns
`|64|9|To Be Filled By O.E.M.|3|Intel64 Family 6 Model 94 Stepping 3|252|1|Win32_Processor|4008|12|64|Intel64 Family 6 Model 94 Stepping 3|CPU0|100|198|1024|8192|0|6|4|GenuineIntel|4008|Intel(R) Core(TM) i7-6700K CPU @ 4.00GHz|4|4|8|To Be Filled By O.E.M.|False|BFEBFBFF000506E3|3|24067|CPU|False|To Be Filled By O.E.M.|U3E1|OK|3|Win32_ComputerSystem|GAME-PC-2016|8|1|False|False|`
This cannot not be used for this sensor. Instead try
```sql
SELECT CurrentClockSpeed FROM Win32_Processor
```
which results in `4008` for my PC.
You can use [WMI Explorer](https://github.com/vinaypamnani/wmie2/tree/v2.0.0.2) to find see what data is available.
### Dummy
This sensor spits out a random number every second. Useful for testing, maybe you'll find some other use for it.

@ -10,10 +10,13 @@ namespace UserInterface.ViewModels
{
private AvailableSensors selectedType;
private string description;
private bool showQueryInput;
public string Description { get => description; set => this.RaiseAndSetIfChanged(ref description, value); }
public bool ShowQueryInput { get => showQueryInput; set => this.RaiseAndSetIfChanged(ref showQueryInput, value); }
private string moreInfoLink;
private int updateInterval;
public string MoreInfoLink
{
@ -24,5 +27,7 @@ namespace UserInterface.ViewModels
public AvailableSensors SelectedType { get => selectedType; set => this.RaiseAndSetIfChanged(ref selectedType, value); }
public string Name { get; set; }
public string Query { get; set; }
public int UpdateInterval { get => updateInterval; set => this.RaiseAndSetIfChanged(ref updateInterval, value); }
}
}

@ -10,6 +10,10 @@ namespace UserInterface.ViewModels
private ICollection<SensorViewModel> configuredSensors;
public ICollection<SensorViewModel> ConfiguredSensors { get => configuredSensors; set => this.RaiseAndSetIfChanged(ref configuredSensors, value); }
public void TriggerUpdate()
{
this.RaisePropertyChanged();
}
}
public class SensorViewModel : ViewModelBase
@ -19,6 +23,28 @@ namespace UserInterface.ViewModels
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); }
public int UpdateInterval { get; set; }
public string Value
{
get => _value; set
{
this.RaiseAndSetIfChanged(ref _value, value);
this.RaisePropertyChanged("ValueString");
}
}
public string UnitOfMeasurement { get; set; }
public string ValueString
{
get
{
if (!string.IsNullOrWhiteSpace(_value))
{
return _value + UnitOfMeasurement;
}
else return "";
}
}
}
}

@ -13,7 +13,16 @@
<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"/>
<TextBox Text="{Binding Name}" HorizontalAlignment="Left" MinWidth="150"/>
<ContentControl Margin="0 20 0 10">Update interval</ContentControl>
<StackPanel Orientation="Horizontal">
<Slider Value="{Binding UpdateInterval}" Minimum="1" Maximum="300" HorizontalAlignment="Left" Width="150"/>
<TextBox Text="{Binding UpdateInterval}" HorizontalAlignment="Right" MaxWidth="30"/>
</StackPanel>
<TextBlock Text="{Binding UpdateInterval, StringFormat= Update every {0} seconds}" HorizontalAlignment="Left" MinWidth="150"/>
<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"/>
<Button Width="75" HorizontalAlignment="Right" Margin="0 40 0 10" Click="Save">Save</Button>
</StackPanel>
</Window>

@ -47,7 +47,7 @@ namespace UserInterface.Views
public async void Save(object sender, RoutedEventArgs args)
{
var item = ((AddSensorViewModel)this.DataContext);
dynamic model = new { Name = item.Name };
dynamic model = new { Name = item.Name, Query = item.Query, UpdateInterval = item.UpdateInterval };
string json = JsonSerializer.Serialize(model);
await this.client.InvokeAsync(x => x.AddSensor(item.SelectedType, json));
Close();
@ -61,14 +61,43 @@ namespace UserInterface.Views
case AvailableSensors.UserNotificationStateSensor:
item.Description = "This sensor watches the UserNotificationState. This is normally used in applications to determine if it is appropriate to send a notification but we can use it to expose this state. \n ";
item.MoreInfoLink = "https://github.com/sleevezipper/hass-workstation-service#usernotificationstate";
item.ShowQueryInput = false;
item.UpdateInterval = 5;
break;
case AvailableSensors.DummySensor:
item.Description = "This sensor spits out a random number every second. Useful for testing, maybe you'll find some other use for it.";
item.MoreInfoLink = "https://github.com/sleevezipper/hass-workstation-service#dummy";
item.ShowQueryInput = false;
item.UpdateInterval = 1;
break;
case AvailableSensors.CPULoadSensor:
item.Description = "This sensor checks the current CPU load. It averages the load on all logical cores every second and rounds the output to two decimals.";
item.MoreInfoLink = "https://github.com/sleevezipper/hass-workstation-service#cpuload";
item.ShowQueryInput = false;
item.UpdateInterval = 5;
break;
case AvailableSensors.CurrentClockSpeedSensor:
item.Description = "This sensor returns the BIOS configured baseclock for the processor.";
item.MoreInfoLink = "https://github.com/sleevezipper/hass-workstation-service#currentclockspeed";
item.ShowQueryInput = false;
item.UpdateInterval = 3600;
break;
case AvailableSensors.WMIQuerySensor:
item.Description = "This advanced sensor executes a user defined WMI query and exposes the result. The query should return a single value.";
item.MoreInfoLink = "https://github.com/sleevezipper/hass-workstation-service#wmiquerysensor";
item.ShowQueryInput = true;
item.UpdateInterval = 10;
break;
case AvailableSensors.MemoryUsageSensor:
item.Description = "This sensor calculates the percentage of used memory.";
item.MoreInfoLink = "https://github.com/sleevezipper/hass-workstation-service#usedmemorysensor";
item.ShowQueryInput = false;
item.UpdateInterval = 10;
break;
default:
item.Description = null;
item.MoreInfoLink = null;
item.ShowQueryInput = false;
break;
}
}

@ -3,7 +3,7 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="500" d:DesignHeight="450"
MaxWidth="500"
MaxWidth="800"
x:Class="UserInterface.Views.SensorSettings" >
<StackPanel Margin="30" HorizontalAlignment="Left" >
<DataGrid x:Name="Grid" IsVisible="{Binding ConfiguredSensors.Count}" AutoGenerateColumns="False" IsReadOnly="True" SelectionMode="Single" Items="{Binding ConfiguredSensors}">
@ -15,9 +15,12 @@
<DataGridTextColumn Header="Type"
Binding="{Binding Type}"
Width="1*" />
<DataGridTextColumn Header="Value"
Binding="{Binding Value}"
<DataGridTextColumn Header="Update Interval"
Binding="{Binding UpdateInterval}"
Width="1*" />
<DataGridTextColumn Header="Value"
Binding="{Binding ValueString}"
Width="2*" />
</DataGrid.Columns>
</DataGrid>
<TextBlock IsVisible="{Binding !ConfiguredSensors.Count}">Add some sensors by clicking the "Add" button. </TextBlock>

@ -50,10 +50,10 @@ namespace UserInterface.Views
sensorsNeedToRefresh = false;
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();
((SensorSettingsViewModel)this.DataContext).ConfiguredSensors = status.Select(s => new SensorViewModel() { Name = s.Name, Type = s.Type, Value = s.Value, Id = s.Id , UpdateInterval = s.UpdateInterval, UnitOfMeasurement = s.UnitOfMeasurement}).ToList();
while (!sensorsNeedToRefresh)
{
await Task.Delay(2000);
await Task.Delay(1000);
List<ConfiguredSensorModel> statusUpdated = await this.client.InvokeAsync(x => x.GetConfiguredSensors());
var configuredSensors = ((SensorSettingsViewModel)this.DataContext).ConfiguredSensors;
statusUpdated.ForEach(s =>
@ -73,9 +73,9 @@ namespace UserInterface.Views
{
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();
((SensorSettingsViewModel)this.DataContext).ConfiguredSensors.Remove(item);
this._dataGrid.SelectedIndex = -1;
((SensorSettingsViewModel)this.DataContext).TriggerUpdate();
}
public async void AddSensor(object sender, RoutedEventArgs args)
@ -84,6 +84,7 @@ namespace UserInterface.Views
if (Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
{
await dialog.ShowDialog(desktop.MainWindow);
sensorsNeedToRefresh = true;
GetConfiguredSensors();
}
}

@ -66,7 +66,7 @@ namespace hass_workstation_service.Communication.InterProcesCommunication
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();
return this._configurationService.ConfiguredSensors.Select(s => new ConfiguredSensorModel() { Name = s.Name, Type = s.GetType().Name, Value = s.PreviousPublishedState, Id = s.Id, UpdateInterval = s.UpdateInterval, UnitOfMeasurement = s.GetAutoDiscoveryConfig().Unit_of_measurement }).ToList();
}
public void RemoveSensorById(Guid id)
@ -86,10 +86,25 @@ namespace hass_workstation_service.Communication.InterProcesCommunication
switch (sensorType)
{
case AvailableSensors.UserNotificationStateSensor:
sensorToCreate = new UserNotificationStateSensor(this._publisher, model.Name);
sensorToCreate = new UserNotificationStateSensor(this._publisher, (int)model.UpdateInterval, model.Name);
break;
case AvailableSensors.DummySensor:
sensorToCreate = new DummySensor(this._publisher, model.Name);
sensorToCreate = new DummySensor(this._publisher, (int)model.UpdateInterval, model.Name);
break;
case AvailableSensors.CurrentClockSpeedSensor:
sensorToCreate = new CurrentClockSpeedSensor(this._publisher, (int)model.UpdateInterval, model.Name);
break;
case AvailableSensors.CPULoadSensor:
sensorToCreate = new CPULoadSensor(this._publisher, (int)model.UpdateInterval, model.Name);
break;
case AvailableSensors.WMIQuerySensor:
sensorToCreate = new WMIQuerySensor(this._publisher, model.Query, (int)model.UpdateInterval, model.Name);
break;
case AvailableSensors.MemoryUsageSensor:
sensorToCreate = new MemoryUsageSensor(this._publisher, (int)model.UpdateInterval, model.Name);
break;
case AvailableSensors.ActiveWindowSensor:
sensorToCreate = new ActiveWindowSensor(this._publisher, (int)model.UpdateInterval, model.Name);
break;
default:
Log.Logger.Error("Unknown sensortype");

@ -24,11 +24,18 @@ namespace hass_workstation_service.Communication.InterProcesCommunication.Models
public string Type { get; set; }
public string Name { get; set; }
public string Value { get; set; }
public int UpdateInterval { get; set; }
public string UnitOfMeasurement { get; set; }
}
public enum AvailableSensors
{
UserNotificationStateSensor,
DummySensor
DummySensor,
CurrentClockSpeedSensor,
CPULoadSensor,
WMIQuerySensor,
MemoryUsageSensor,
ActiveWindowSensor
}
}

@ -4,6 +4,8 @@ using System.Collections.Generic;
using System.Dynamic;
using System.Text.Json;
using System.Text.Json.Serialization;
#pragma warning disable CS8632 // The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.
namespace hass_workstation_service.Communication.Util
{
/// <summary>
@ -125,3 +127,4 @@ namespace hass_workstation_service.Communication.Util
}
}
}
#pragma warning restore CS8632 // The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

@ -67,21 +67,40 @@ namespace hass_workstation_service.Data
foreach (ConfiguredSensor configuredSensor in sensors)
{
AbstractSensor sensor;
AbstractSensor sensor = null;
switch (configuredSensor.Type)
{
case "UserNotificationStateSensor":
sensor = new UserNotificationStateSensor(publisher, configuredSensor.Name, configuredSensor.Id);
sensor = new UserNotificationStateSensor(publisher, configuredSensor.UpdateInterval, configuredSensor.Name, configuredSensor.Id);
break;
case "DummySensor":
sensor = new DummySensor(publisher, configuredSensor.Name, configuredSensor.Id);
sensor = new DummySensor(publisher, configuredSensor.UpdateInterval, configuredSensor.Name, configuredSensor.Id);
break;
case "CurrentClockSpeedSensor":
sensor = new CurrentClockSpeedSensor(publisher, configuredSensor.UpdateInterval, configuredSensor.Name, configuredSensor.Id);
break;
case "WMIQuerySensor":
sensor = new WMIQuerySensor(publisher, configuredSensor.Query, configuredSensor.UpdateInterval, configuredSensor.Name, configuredSensor.Id);
break;
case "CPULoadSensor":
sensor = new CPULoadSensor(publisher, configuredSensor.UpdateInterval, configuredSensor.Name, configuredSensor.Id);
break;
case "MemoryUsageSensor":
sensor = new MemoryUsageSensor(publisher, configuredSensor.UpdateInterval, configuredSensor.Name, configuredSensor.Id);
break;
case "ActiveWindowSensor":
sensor = new ActiveWindowSensor(publisher, configuredSensor.UpdateInterval, configuredSensor.Name, configuredSensor.Id);
break;
default:
throw new InvalidOperationException("unsupported sensor type in config");
Log.Logger.Error("unsupported sensor type in config");
break;
}
if (sensor != null)
{
this.ConfiguredSensors.Add(sensor);
}
}
}
public async Task<IMqttClientOptions> GetMqttClientOptionsAsync()
{
@ -143,7 +162,16 @@ namespace hass_workstation_service.Data
Log.Logger.Information($"writing configured sensors to: {stream.Name}");
foreach (AbstractSensor sensor in this.ConfiguredSensors)
{
configuredSensorsToSave.Add(new ConfiguredSensor() { Id = sensor.Id, Name = sensor.Name, Type = sensor.GetType().Name });
if (sensor is WMIQuerySensor)
{
var wmiSensor = (WMIQuerySensor)sensor;
configuredSensorsToSave.Add(new ConfiguredSensor() { Id = wmiSensor.Id, Name = wmiSensor.Name, Type = wmiSensor.GetType().Name, UpdateInterval = wmiSensor.UpdateInterval, Query = wmiSensor.Query });
}
else
{
configuredSensorsToSave.Add(new ConfiguredSensor() { Id = sensor.Id, Name = sensor.Name, Type = sensor.GetType().Name, UpdateInterval = sensor.UpdateInterval });
}
}
await JsonSerializer.SerializeAsync(stream, configuredSensorsToSave);
@ -155,16 +183,25 @@ namespace hass_workstation_service.Data
public void AddConfiguredSensor(AbstractSensor sensor)
{
this.ConfiguredSensors.Add(sensor);
sensor.PublishAutoDiscoveryConfigAsync();
WriteSettingsAsync();
}
public async void DeleteConfiguredSensor(Guid id)
{
var sensorToRemove = this.ConfiguredSensors.FirstOrDefault(s => s.Id == id);
if (sensorToRemove != null)
{
await sensorToRemove.UnPublishAutoDiscoveryConfigAsync();
this.ConfiguredSensors.Remove(sensorToRemove);
WriteSettingsAsync();
}
else
{
Log.Logger.Warning($"sensor with id {id} not found");
}
}
public void AddConfiguredSensors(List<AbstractSensor> sensors)
{
@ -226,7 +263,7 @@ namespace hass_workstation_service.Data
RegistryKey rkApp = Registry.CurrentUser.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Run", true);
//Path to launch shortcut
string startPath = Environment.GetFolderPath(Environment.SpecialFolder.Programs) + @"\hass-workstation-service\hass-workstation-service.appref-ms";
string startPath = Environment.GetFolderPath(Environment.SpecialFolder.Programs) + @"\Sleevezipper\Hass Workstation Service.appref-ms";
rkApp.SetValue("hass-workstation-service", startPath);
rkApp.Close();

@ -7,5 +7,7 @@ namespace hass_workstation_service.Data
public string Type { get; set; }
public Guid Id { get; set; }
public string Name { get; set; }
public string Query { get; set; }
public int? UpdateInterval { get; set; }
}
}

@ -10,8 +10,28 @@ namespace hass_workstation_service.Domain.Sensors
{
public Guid Id { get; protected set; }
public string Name { get; protected set; }
/// <summary>
/// The update interval in seconds. It checks state only if the interval has passed.
/// </summary>
public int UpdateInterval { get; protected set; }
public DateTime? LastUpdated { get; protected set; }
public string PreviousPublishedState { get; protected set; }
public MqttPublisher Publisher { get; protected set; }
public AbstractSensor(MqttPublisher publisher, string name, int updateInterval = 10, Guid id = default(Guid))
{
if (id == Guid.Empty || id == null)
{
this.Id = Guid.NewGuid();
}
else
{
this.Id = id;
}
this.Name = name;
this.Publisher = publisher;
this.UpdateInterval = updateInterval;
}
protected AutoDiscoveryConfigModel _autoDiscoveryConfigModel;
protected AutoDiscoveryConfigModel SetAutoDiscoveryConfigModel(AutoDiscoveryConfigModel config)
{
@ -24,6 +44,11 @@ namespace hass_workstation_service.Domain.Sensors
public async Task PublishStateAsync()
{
if (LastUpdated.HasValue && LastUpdated.Value.AddSeconds(this.UpdateInterval) > DateTime.UtcNow)
{
// dont't even check the state if the update interval hasn't passed
return;
}
string state = this.GetState();
if (this.PreviousPublishedState == state)
{
@ -38,8 +63,9 @@ namespace hass_workstation_service.Domain.Sensors
.Build();
await Publisher.Publish(message);
this.PreviousPublishedState = state;
this.LastUpdated = DateTime.UtcNow;
}
public async Task PublishAutoDiscoveryConfigAsync()
public async void PublishAutoDiscoveryConfigAsync()
{
await this.Publisher.AnnounceAutoDiscoveryConfig(this.GetAutoDiscoveryConfig());
}

@ -0,0 +1,48 @@
using hass_workstation_service.Communication;
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
namespace hass_workstation_service.Domain.Sensors
{
public class ActiveWindowSensor : AbstractSensor
{
public ActiveWindowSensor(MqttPublisher publisher, int? updateInterval = null, string name = "ActiveWindow", Guid id = default(Guid)) : base(publisher, name ?? "ActiveWindow", 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/{this.Name}/state",
Icon = "mdi:window-maximize",
});
}
public override string GetState()
{
return GetActiveWindowTitle();
}
[DllImport("user32.dll")]
static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll")]
static extern int GetWindowText(IntPtr hWnd, StringBuilder text, int count);
private string GetActiveWindowTitle()
{
const int nChars = 256;
StringBuilder Buff = new StringBuilder(nChars);
IntPtr handle = GetForegroundWindow();
if (GetWindowText(handle, Buff, nChars) > 0)
{
return Buff.ToString();
}
return null;
}
}
}

@ -0,0 +1,44 @@
using hass_workstation_service.Communication;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Management;
using System.Text;
namespace hass_workstation_service.Domain.Sensors
{
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 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/{this.Name}/state",
Icon = "mdi:chart-areaspline",
Unit_of_measurement = "%"
});
}
public override string GetState()
{
ManagementObjectCollection collection = _searcher.Get();
List<int> processorLoadPercentages = new List<int>();
foreach (ManagementObject mo in collection)
{
foreach (PropertyData property in mo.Properties)
{
processorLoadPercentages.Add(int.Parse(property.Value.ToString()));
}
}
double average = processorLoadPercentages.Count > 0 ? processorLoadPercentages.Average() : 0.0;
return average.ToString("#.##", CultureInfo.InvariantCulture);
}
}
}

@ -0,0 +1,25 @@
using hass_workstation_service.Communication;
using System;
using System.Collections.Generic;
using System.Text;
namespace hass_workstation_service.Domain.Sensors
{
public class CurrentClockSpeedSensor : WMIQuerySensor
{
public CurrentClockSpeedSensor(MqttPublisher publisher, int? updateInterval = null, string name = "CurrentClockSpeed", Guid id = default(Guid)) : base(publisher, "SELECT CurrentClockSpeed FROM Win32_Processor", updateInterval ?? 10, name ?? "CurrentClockSpeed", 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/{this.Name}/state",
Icon = "mdi:speedometer",
Unit_of_measurement = "MHz"
});
}
}
}

@ -8,21 +8,11 @@ namespace hass_workstation_service.Domain.Sensors
public class DummySensor : AbstractSensor
{
private readonly Random _random;
public DummySensor(MqttPublisher publisher, string name = "Dummy")
public DummySensor(MqttPublisher publisher, int? updateInterval = null, string name = "Dummy", Guid id = default(Guid)) : base(publisher, name ?? "Dummy", updateInterval ?? 1, id)
{
this.Id = Guid.NewGuid();
this.Name = name;
this.Publisher = publisher;
this._random = new Random();
}
public DummySensor(MqttPublisher publisher, string name, Guid id)
{
this.Id = id;
this.Name = name;
this.Publisher = publisher;
this._random = new Random();
}
public override AutoDiscoveryConfigModel GetAutoDiscoveryConfig()
{
return this._autoDiscoveryConfigModel ?? SetAutoDiscoveryConfigModel(new AutoDiscoveryConfigModel()

@ -0,0 +1,47 @@
using hass_workstation_service.Communication;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Management;
using System.Text;
namespace hass_workstation_service.Domain.Sensors
{
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 override string GetState()
{
ManagementObjectCollection collection = _searcher.Get();
UInt64? totalMemory = null;
UInt64? freeMemory = null;
foreach (ManagementObject mo in collection)
{
totalMemory = (UInt64)mo.Properties["TotalVisibleMemorySize"]?.Value;
freeMemory = (UInt64)mo.Properties["FreePhysicalMemory"]?.Value;
}
if (totalMemory != null && freeMemory != null)
{
decimal totalMemoryDec = totalMemory.Value;
decimal freeMemoryDec = freeMemory.Value;
decimal precentageUsed = 100 - (freeMemoryDec / totalMemoryDec) * 100;
return precentageUsed.ToString("#.##", CultureInfo.InvariantCulture);
}
return "";
}
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/{this.Name}/state",
Icon = "mdi:memory",
Unit_of_measurement = "%"
});
}
}
}

@ -7,19 +7,8 @@ namespace hass_workstation_service.Domain.Sensors
{
public class UserNotificationStateSensor : AbstractSensor
{
public UserNotificationStateSensor(MqttPublisher publisher, string name = "NotificationState")
{
this.Id = Guid.NewGuid();
this.Name = name;
this.Publisher = publisher;
}
public UserNotificationStateSensor(MqttPublisher publisher, int? updateInterval = null, string name = "NotificationState", Guid id = default(Guid)) : base(publisher, name ?? "NotificationState", updateInterval ?? 10, id) { }
public UserNotificationStateSensor(MqttPublisher publisher, string name, Guid id)
{
this.Id = id;
this.Name = name;
this.Publisher = publisher;
}
public override AutoDiscoveryConfigModel GetAutoDiscoveryConfig()
{
return this._autoDiscoveryConfigModel ?? SetAutoDiscoveryConfigModel(new AutoDiscoveryConfigModel()
@ -40,6 +29,10 @@ namespace hass_workstation_service.Domain.Sensors
[DllImport("shell32.dll")]
static extern int SHQueryUserNotificationState(out UserNotificationState state);
[DllImport("shell32.dll")]
static extern int asdasdadsd(out int q);
public UserNotificationState GetStateEnum()
{
SHQueryUserNotificationState(out UserNotificationState state);

@ -0,0 +1,46 @@
using hass_workstation_service.Communication;
using System;
using System.Collections.Generic;
using System.Management;
using System.Text;
namespace hass_workstation_service.Domain.Sensors
{
public class WMIQuerySensor : AbstractSensor
{
public string Query { get; private set; }
protected readonly ObjectQuery _objectQuery;
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)
{
this.Query = query;
_objectQuery = new ObjectQuery(this.Query);
_searcher = new ManagementObjectSearcher(query);
}
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/{this.Name}/state",
});
}
public override string GetState()
{
ManagementObjectCollection collection = _searcher.Get();
foreach (ManagementObject mo in collection)
{
foreach (PropertyData property in mo.Properties)
{
return property.Value.ToString();
}
}
return "";
}
}
}

@ -4,7 +4,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
-->
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ApplicationRevision>20</ApplicationRevision>
<ApplicationRevision>22</ApplicationRevision>
<ApplicationVersion>1.0.0.*</ApplicationVersion>
<BootstrapperEnabled>True</BootstrapperEnabled>
<Configuration>Release</Configuration>

@ -38,24 +38,27 @@ namespace hass_workstation_service
}
_logger.LogInformation("Connected. Sending auto discovery messages.");
foreach (AbstractSensor sensor in _configurationService.ConfiguredSensors)
List<AbstractSensor> sensors = _configurationService.ConfiguredSensors.ToList();
foreach (AbstractSensor sensor in sensors)
{
await sensor.PublishAutoDiscoveryConfigAsync();
sensor.PublishAutoDiscoveryConfigAsync();
}
while (!stoppingToken.IsCancellationRequested)
{
sensors = _configurationService.ConfiguredSensors.ToList();
_logger.LogDebug("Worker running at: {time}", DateTimeOffset.Now);
foreach (AbstractSensor sensor in _configurationService.ConfiguredSensors)
foreach (AbstractSensor sensor in sensors)
{
await sensor.PublishStateAsync();
}
// announce autodiscovery every 30 seconds
if (_mqttPublisher.LastConfigAnnounce < DateTime.UtcNow.AddSeconds(-30))
{
foreach (AbstractSensor sensor in _configurationService.ConfiguredSensors)
foreach (AbstractSensor sensor in sensors)
{
await sensor.PublishAutoDiscoveryConfigAsync();
sensor.PublishAutoDiscoveryConfigAsync();
}
}
await Task.Delay(1000, stoppingToken);

@ -46,5 +46,6 @@
<PackageReference Include="Microsoft.Win32.Registry" Version="5.0.0" />
<PackageReference Include="MQTTnet" Version="3.0.13" />
<PackageReference Include="Serilog.AspNetCore" Version="3.4.0" />
<PackageReference Include="System.Management" Version="5.0.0" />
</ItemGroup>
</Project>

Loading…
Cancel
Save