diff --git a/UserInterface/Views/AddSensorDialog.axaml.cs b/UserInterface/Views/AddSensorDialog.axaml.cs index 5d83bd7..9ab9bde 100644 --- a/UserInterface/Views/AddSensorDialog.axaml.cs +++ b/UserInterface/Views/AddSensorDialog.axaml.cs @@ -158,6 +158,13 @@ namespace UserInterface.Views item.UpdateInterval = 10; break; + case AvailableSensors.WebcamProcessSensor: + item.Description = "This sensor shows which process is using the webcam."; + item.MoreInfoLink = "https://github.com/sleevezipper/hass-workstation-service/blob/master/documentation/Sensors.md#webcamprocesssensor"; + item.ShowQueryInput = false; + item.UpdateInterval = 10; + break; + case AvailableSensors.MicrophoneActiveSensor: item.Description = "This sensor shows if the microphone is currently in use."; item.MoreInfoLink = "https://github.com/sleevezipper/hass-workstation-service/blob/master/documentation/Sensors.md#microphoneactivesensor"; diff --git a/UserInterface/Views/BackgroundServiceSettings.axaml b/UserInterface/Views/BackgroundServiceSettings.axaml index 4b7baed..eadbee8 100644 --- a/UserInterface/Views/BackgroundServiceSettings.axaml +++ b/UserInterface/Views/BackgroundServiceSettings.axaml @@ -9,10 +9,7 @@ Background service - - - - + Autostart diff --git a/UserInterface/Views/BrokerSettings.axaml b/UserInterface/Views/BrokerSettings.axaml index d583039..b23b798 100644 --- a/UserInterface/Views/BrokerSettings.axaml +++ b/UserInterface/Views/BrokerSettings.axaml @@ -4,7 +4,7 @@ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" d:DesignWidth="500" d:DesignHeight="450" x:Class="UserInterface.Views.BrokerSettings"> - + MQTT Broker diff --git a/UserInterface/Views/MainWindow.axaml b/UserInterface/Views/MainWindow.axaml index d559359..31d7da7 100644 --- a/UserInterface/Views/MainWindow.axaml +++ b/UserInterface/Views/MainWindow.axaml @@ -1,4 +1,4 @@ - - - + + + + + + - \ No newline at end of file diff --git a/documentation/Sensors.md b/documentation/Sensors.md index 958efa8..2938c7d 100644 --- a/documentation/Sensors.md +++ b/documentation/Sensors.md @@ -85,6 +85,10 @@ This sensor watches the UserNotificationState. This is normally used in applicat The webcam active sensor returns the status of the webcam. +### WebcamProcessSensor + +The webcam process sensor returns the process which is using the webcam. + ### WMIQuerySensor Please see the specific documentaion page [here](https://github.com/sleevezipper/hass-workstation-service/blob/master/documentation/WMIQuery.md#wmiquerysensor). diff --git a/hass-workstation-service/Communication/InterProcesCommunication/InterProcessApi.cs b/hass-workstation-service/Communication/InterProcesCommunication/InterProcessApi.cs index 0a53b1a..9c9824e 100644 --- a/hass-workstation-service/Communication/InterProcesCommunication/InterProcessApi.cs +++ b/hass-workstation-service/Communication/InterProcesCommunication/InterProcessApi.cs @@ -177,6 +177,7 @@ namespace hass_workstation_service.Communication.InterProcesCommunication AvailableSensors.MemoryUsageSensor => new MemoryUsageSensor(_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.WebcamProcessSensor => new WebcamProcessSensor(_publisher, (int)model.UpdateInterval, model.Name), AvailableSensors.MicrophoneActiveSensor => new MicrophoneActiveSensor(_publisher, (int)model.UpdateInterval, model.Name), AvailableSensors.NamedWindowSensor => new NamedWindowSensor(_publisher, model.WindowName, model.Name, (int)model.UpdateInterval), AvailableSensors.LastActiveSensor => new LastActiveSensor(_publisher, (int)model.UpdateInterval, model.Name), @@ -221,4 +222,4 @@ namespace hass_workstation_service.Communication.InterProcesCommunication public void WriteGeneralSettings(GeneralSettings settings) => _configurationService.WriteGeneralSettingsAsync(settings); } -} \ No newline at end of file +} diff --git a/hass-workstation-service/Communication/InterProcesCommunication/ServiceContractModels.cs b/hass-workstation-service/Communication/InterProcesCommunication/ServiceContractModels.cs index 0507e5e..fafa58d 100644 --- a/hass-workstation-service/Communication/InterProcesCommunication/ServiceContractModels.cs +++ b/hass-workstation-service/Communication/InterProcesCommunication/ServiceContractModels.cs @@ -93,6 +93,7 @@ namespace hass_workstation_service.Communication.InterProcesCommunication.Models WMIQuerySensor, MemoryUsageSensor, WebcamActiveSensor, + WebcamProcessSensor, MicrophoneActiveSensor, ActiveWindowSensor, NamedWindowSensor, @@ -120,4 +121,4 @@ namespace hass_workstation_service.Communication.InterProcesCommunication.Models VolumeDownCommand, MuteCommand } -} \ No newline at end of file +} diff --git a/hass-workstation-service/Data/ConfigurationService.cs b/hass-workstation-service/Data/ConfigurationService.cs index dc8e12f..3ef2a15 100644 --- a/hass-workstation-service/Data/ConfigurationService.cs +++ b/hass-workstation-service/Data/ConfigurationService.cs @@ -129,6 +129,9 @@ namespace hass_workstation_service.Data case "WebcamActiveSensor": sensor = new WebcamActiveSensor(publisher, configuredSensor.UpdateInterval, configuredSensor.Name, configuredSensor.Id); break; + case "WebcamProcessSensor": + sensor = new WebcamProcessSensor(publisher, configuredSensor.UpdateInterval, configuredSensor.Name, configuredSensor.Id); + break; case "MicrophoneActiveSensor": sensor = new MicrophoneActiveSensor(publisher, configuredSensor.UpdateInterval, configuredSensor.Name, configuredSensor.Id); break; @@ -619,4 +622,4 @@ namespace hass_workstation_service.Data return this.ConfiguredSensors; } } -} \ No newline at end of file +} diff --git a/hass-workstation-service/Domain/Sensors/LastActiveSensor.cs b/hass-workstation-service/Domain/Sensors/LastActiveSensor.cs index 9aa38bc..9eba3b8 100644 --- a/hass-workstation-service/Domain/Sensors/LastActiveSensor.cs +++ b/hass-workstation-service/Domain/Sensors/LastActiveSensor.cs @@ -25,7 +25,7 @@ namespace hass_workstation_service.Domain.Sensors public override string GetState() { - return GetLastInputTime().ToString("s"); + return GetLastInputTime().ToString("o", System.Globalization.CultureInfo.InvariantCulture); } diff --git a/hass-workstation-service/Domain/Sensors/LastBootSensor.cs b/hass-workstation-service/Domain/Sensors/LastBootSensor.cs index fda171c..26b4896 100644 --- a/hass-workstation-service/Domain/Sensors/LastBootSensor.cs +++ b/hass-workstation-service/Domain/Sensors/LastBootSensor.cs @@ -29,10 +29,10 @@ namespace hass_workstation_service.Domain.Sensors public override string GetState() { - return (DateTime.Now - TimeSpan.FromMilliseconds(GetTickCount64())).ToString("s"); + return (DateTime.Now - TimeSpan.FromMilliseconds(GetTickCount64())).ToString("o", System.Globalization.CultureInfo.InvariantCulture); } [DllImport("kernel32")] extern static UInt64 GetTickCount64(); } -} +} \ No newline at end of file diff --git a/hass-workstation-service/Domain/Sensors/WebcamProcessSensor.cs b/hass-workstation-service/Domain/Sensors/WebcamProcessSensor.cs new file mode 100644 index 0000000..9210654 --- /dev/null +++ b/hass-workstation-service/Domain/Sensors/WebcamProcessSensor.cs @@ -0,0 +1,130 @@ +using hass_workstation_service.Communication; +using Microsoft.Win32; +using System; +using System.Linq; +using System.Runtime.InteropServices; +using System.Runtime.Versioning; + +namespace hass_workstation_service.Domain.Sensors +{ + public class WebcamProcessSensor : AbstractSensor + { + public WebcamProcessSensor(MqttPublisher publisher, int? updateInterval = null, string name = "WebcamProcess", Guid id = default) : base(publisher, name ?? "WebcamProcess", updateInterval ?? 10, id) + { + } + + public override string GetState() + { + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + return IsWebCamInUseRegistry(); + } + 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 string IsWebCamInUseRegistry() + { + using (var key = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\CapabilityAccessManager\ConsentStore\webcam")) + { + 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; + if (endTime <= 0) + { + return nonpackagedSubKeyName; + } + } + } + } + } + } + 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; + } + } + } + } + } + } + + using (var key = Registry.CurrentUser.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\CapabilityAccessManager\ConsentStore\webcam")) + { + 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; + if (endTime <= 0) + { + return nonpackagedSubKeyName; + } + } + } + } + } + } + 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; + } + } + } + } + } + } + + return "off"; + } + } +} diff --git a/hass-workstation-service/Properties/PublishProfiles/AzureHosted.pubxml b/hass-workstation-service/Properties/PublishProfiles/AzureHosted.pubxml index 64dd310..cb38d89 100644 --- a/hass-workstation-service/Properties/PublishProfiles/AzureHosted.pubxml +++ b/hass-workstation-service/Properties/PublishProfiles/AzureHosted.pubxml @@ -4,7 +4,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121. --> - 55 + 57 1.0.0.* True Release diff --git a/hass-workstation-service/UserInterface.exe b/hass-workstation-service/UserInterface.exe index a34952d..1633afc 100644 Binary files a/hass-workstation-service/UserInterface.exe and b/hass-workstation-service/UserInterface.exe differ diff --git a/hass-workstation-service/hass-workstation-service.exe b/hass-workstation-service/hass-workstation-service.exe index 8c8bd7b..64b88d0 100644 Binary files a/hass-workstation-service/hass-workstation-service.exe and b/hass-workstation-service/hass-workstation-service.exe differ