From 78aa26599e880d56dc0791db067b8c970a61ea24 Mon Sep 17 00:00:00 2001 From: sleevezipper Date: Sun, 3 Jan 2021 16:01:26 +0100 Subject: [PATCH 01/12] WIP add webcam sensor --- .../DesignTimeBuild/.dtbcache.v2 | Bin 162527 -> 162527 bytes .vs/hass-workstation-service/v16/.suo | Bin 279552 -> 278016 bytes .../PublishProfiles/Standalone.pubxml | 18 ++ .../PublishProfiles/Standalone.pubxml.user | 6 + UserInterface/UserInterface.csproj.user | 2 +- UserInterface/Views/AddSensorDialog.axaml.cs | 8 +- .../InterProcessApi.cs | 3 + .../ServiceContractModels.cs | 3 +- .../Data/ConfigurationService.cs | 3 + .../Domain/Sensors/WebcamActiveSensor.cs | 182 ++++++++++++++++++ .../PublishProfiles/AzureHosted.pubxml | 2 +- .../PublishProfiles/FolderProfile.pubxml | 18 ++ .../PublishProfiles/FolderProfile.pubxml.user | 6 + .../hass-workstation-service.csproj.user | 2 +- 14 files changed, 248 insertions(+), 5 deletions(-) create mode 100644 UserInterface/Properties/PublishProfiles/Standalone.pubxml create mode 100644 UserInterface/Properties/PublishProfiles/Standalone.pubxml.user create mode 100644 hass-workstation-service/Domain/Sensors/WebcamActiveSensor.cs create mode 100644 hass-workstation-service/Properties/PublishProfiles/FolderProfile.pubxml create mode 100644 hass-workstation-service/Properties/PublishProfiles/FolderProfile.pubxml.user diff --git a/.vs/hass-workstation-service/DesignTimeBuild/.dtbcache.v2 b/.vs/hass-workstation-service/DesignTimeBuild/.dtbcache.v2 index 105da9a9eaa1964731c876bfabe82cc003f15fea..025b0a6486fe73dec1cc2a194215272899b2235d 100644 GIT binary patch delta 17545 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 AO#lD@ diff --git a/.vs/hass-workstation-service/v16/.suo b/.vs/hass-workstation-service/v16/.suo index cf4766f05e5ebd524a72e4c117f181a826e866f3..cd9f65d2270e8b38f18c7490fb57bfbf4700e33c 100644 GIT binary patch delta 9353 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 Z5>yCkU?7x`EGDN2B~qGq$27QE{VUoLiQE7H delta 7708 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 a + + + + Release + Any CPU + bin\Userinterface-standalone + FileSystem + netcoreapp3.1 + win-x64 + true + False + False + False + + \ No newline at end of file diff --git a/UserInterface/Properties/PublishProfiles/Standalone.pubxml.user b/UserInterface/Properties/PublishProfiles/Standalone.pubxml.user new file mode 100644 index 0000000..312c6e3 --- /dev/null +++ b/UserInterface/Properties/PublishProfiles/Standalone.pubxml.user @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/UserInterface/UserInterface.csproj.user b/UserInterface/UserInterface.csproj.user index 3d9bdf3..bbf9920 100644 --- a/UserInterface/UserInterface.csproj.user +++ b/UserInterface/UserInterface.csproj.user @@ -1,6 +1,6 @@  - <_LastSelectedProfileId>C:\Users\Maurits\Documents\Repo\hass-desktop-service\UserInterface\Properties\PublishProfiles\FolderProfile.pubxml + <_LastSelectedProfileId>C:\Users\Maurits\Documents\Repo\hass-desktop-service\UserInterface\Properties\PublishProfiles\Standalone.pubxml \ No newline at end of file diff --git a/UserInterface/Views/AddSensorDialog.axaml.cs b/UserInterface/Views/AddSensorDialog.axaml.cs index 3e31aef..2f307cd 100644 --- a/UserInterface/Views/AddSensorDialog.axaml.cs +++ b/UserInterface/Views/AddSensorDialog.axaml.cs @@ -90,7 +90,7 @@ namespace UserInterface.Views 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.MoreInfoLink = "https://github.com/sleevezipper/hass-workstation-service#usedmemory"; item.ShowQueryInput = false; item.UpdateInterval = 10; break; @@ -100,6 +100,12 @@ namespace UserInterface.Views item.ShowQueryInput = false; item.UpdateInterval = 5; break; + case AvailableSensors.WebcamActiveSensor: + item.Description = "This sensor shows if the webcam is currently in use."; + item.MoreInfoLink = "https://github.com/sleevezipper/hass-workstation-service#webcamactive"; + item.ShowQueryInput = false; + item.UpdateInterval = 10; + break; default: item.Description = null; item.MoreInfoLink = null; diff --git a/hass-workstation-service/Communication/InterProcesCommunication/InterProcessApi.cs b/hass-workstation-service/Communication/InterProcesCommunication/InterProcessApi.cs index 64f77c7..c45b564 100644 --- a/hass-workstation-service/Communication/InterProcesCommunication/InterProcessApi.cs +++ b/hass-workstation-service/Communication/InterProcesCommunication/InterProcessApi.cs @@ -106,6 +106,9 @@ namespace hass_workstation_service.Communication.InterProcesCommunication case AvailableSensors.ActiveWindowSensor: sensorToCreate = new ActiveWindowSensor(this._publisher, (int)model.UpdateInterval, model.Name); break; + case AvailableSensors.WebcamActiveSensor: + sensorToCreate = new WebcamActiveSensor(this._publisher, (int)model.UpdateInterval, model.Name); + break; default: Log.Logger.Error("Unknown sensortype"); break; diff --git a/hass-workstation-service/Communication/InterProcesCommunication/ServiceContractModels.cs b/hass-workstation-service/Communication/InterProcesCommunication/ServiceContractModels.cs index d6e73f2..3e110ea 100644 --- a/hass-workstation-service/Communication/InterProcesCommunication/ServiceContractModels.cs +++ b/hass-workstation-service/Communication/InterProcesCommunication/ServiceContractModels.cs @@ -36,6 +36,7 @@ namespace hass_workstation_service.Communication.InterProcesCommunication.Models CPULoadSensor, WMIQuerySensor, MemoryUsageSensor, - ActiveWindowSensor + ActiveWindowSensor, + WebcamActiveSensor } } diff --git a/hass-workstation-service/Data/ConfigurationService.cs b/hass-workstation-service/Data/ConfigurationService.cs index b352d6a..742b27e 100644 --- a/hass-workstation-service/Data/ConfigurationService.cs +++ b/hass-workstation-service/Data/ConfigurationService.cs @@ -88,6 +88,9 @@ namespace hass_workstation_service.Data case "ActiveWindowSensor": sensor = new ActiveWindowSensor(publisher, configuredSensor.UpdateInterval, configuredSensor.Name, configuredSensor.Id); break; + case "WebcamActiveSensor": + sensor = new WebcamActiveSensor(publisher, configuredSensor.UpdateInterval, configuredSensor.Name, configuredSensor.Id); + break; default: Log.Logger.Error("unsupported sensor type in config"); break; diff --git a/hass-workstation-service/Domain/Sensors/WebcamActiveSensor.cs b/hass-workstation-service/Domain/Sensors/WebcamActiveSensor.cs new file mode 100644 index 0000000..6ff513a --- /dev/null +++ b/hass-workstation-service/Domain/Sensors/WebcamActiveSensor.cs @@ -0,0 +1,182 @@ +using hass_workstation_service.Communication; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Management; +using System.Runtime.ExceptionServices; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading; + +namespace hass_workstation_service.Domain.Sensors +{ + public class WebcamActiveSensor : AbstractSensor + { + public WebcamActiveSensor(MqttPublisher publisher, int? updateInterval = null, string name = "WebcamActive", Guid id = default) : base(publisher, name, updateInterval ?? 10, id) + { + } + public override string GetState() + { + try + { + List procs = WhoIsLocking("\\Device\\00000041"); + if (procs.Count > 0) + { + return "True"; + } + return "False"; + } + catch (Exception) + { + return "Error"; + } + } + 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:webcam", + }); + } + + [StructLayout(LayoutKind.Sequential)] + struct RM_UNIQUE_PROCESS + { + public int dwProcessId; + public System.Runtime.InteropServices.ComTypes.FILETIME ProcessStartTime; + } + + const int RmRebootReasonNone = 0; + const int CCH_RM_MAX_APP_NAME = 255; + const int CCH_RM_MAX_SVC_NAME = 63; + + enum RM_APP_TYPE + { + RmUnknownApp = 0, + RmMainWindow = 1, + RmOtherWindow = 2, + RmService = 3, + RmExplorer = 4, + RmConsole = 5, + RmCritical = 1000 + } + + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] + struct RM_PROCESS_INFO + { + public RM_UNIQUE_PROCESS Process; + + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCH_RM_MAX_APP_NAME + 1)] + public string strAppName; + + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCH_RM_MAX_SVC_NAME + 1)] + public string strServiceShortName; + + public RM_APP_TYPE ApplicationType; + public uint AppStatus; + public uint TSSessionId; + [MarshalAs(UnmanagedType.Bool)] + public bool bRestartable; + } + + [DllImport("rstrtmgr.dll", CharSet = CharSet.Unicode)] + static extern int RmRegisterResources(uint pSessionHandle, + UInt32 nFiles, + string[] rgsFilenames, + UInt32 nApplications, + [In] RM_UNIQUE_PROCESS[] rgApplications, + UInt32 nServices, + string[] rgsServiceNames); + + [DllImport("rstrtmgr.dll", CharSet = CharSet.Auto)] + static extern int RmStartSession(out uint pSessionHandle, int dwSessionFlags, string strSessionKey); + + [DllImport("rstrtmgr.dll")] + static extern int RmEndSession(uint pSessionHandle); + + [DllImport("rstrtmgr.dll")] + static extern int RmGetList(uint dwSessionHandle, + out uint pnProcInfoNeeded, + ref uint pnProcInfo, + [In, Out] RM_PROCESS_INFO[] rgAffectedApps, + ref uint lpdwRebootReasons); + + /// + /// Find out what process(es) have a lock on the specified file. + /// + /// Path of the file. + /// Processes locking the file + /// See also: + /// http://msdn.microsoft.com/en-us/library/windows/desktop/aa373661(v=vs.85).aspx + /// http://wyupdate.googlecode.com/svn-history/r401/trunk/frmFilesInUse.cs (no copyright in code at time of viewing) + /// + /// + static public List WhoIsLocking(string path) + { + uint handle; + string key = Guid.NewGuid().ToString(); + List processes = new List(); + + int res = RmStartSession(out handle, 0, key); + if (res != 0) throw new Exception("Could not begin restart session. Unable to determine file locker."); + + try + { + const int ERROR_MORE_DATA = 234; + uint pnProcInfoNeeded = 0, + pnProcInfo = 0, + lpdwRebootReasons = RmRebootReasonNone; + + string[] resources = new string[] { path }; // Just checking on one resource. + + res = RmRegisterResources(handle, (uint)resources.Length, resources, 0, null, 0, null); + + if (res != 0) throw new Exception("Could not register resource."); + + //Note: there's a race condition here -- the first call to RmGetList() returns + // the total number of process. However, when we call RmGetList() again to get + // the actual processes this number may have increased. + res = RmGetList(handle, out pnProcInfoNeeded, ref pnProcInfo, null, ref lpdwRebootReasons); + + if (res == ERROR_MORE_DATA) + { + // Create an array to store the process results + RM_PROCESS_INFO[] processInfo = new RM_PROCESS_INFO[pnProcInfoNeeded]; + pnProcInfo = pnProcInfoNeeded; + + // Get the list + res = RmGetList(handle, out pnProcInfoNeeded, ref pnProcInfo, processInfo, ref lpdwRebootReasons); + if (res == 0) + { + processes = new List((int)pnProcInfo); + + // Enumerate all of the results and add them to the + // list to be returned + for (int i = 0; i < pnProcInfo; i++) + { + try + { + processes.Add(Process.GetProcessById(processInfo[i].Process.dwProcessId)); + } + // catch the error -- in case the process is no longer running + catch (ArgumentException) { } + } + } + else throw new Exception("Could not list processes locking resource."); + } + else if (res != 0) throw new Exception("Could not list processes locking resource. Failed to get size of result."); + } + finally + { + RmEndSession(handle); + } + + return processes; + } + + } +} diff --git a/hass-workstation-service/Properties/PublishProfiles/AzureHosted.pubxml b/hass-workstation-service/Properties/PublishProfiles/AzureHosted.pubxml index 35da0ec..8ad4e03 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. --> - 25 + 26 1.0.0.* True Release diff --git a/hass-workstation-service/Properties/PublishProfiles/FolderProfile.pubxml b/hass-workstation-service/Properties/PublishProfiles/FolderProfile.pubxml new file mode 100644 index 0000000..786c0bc --- /dev/null +++ b/hass-workstation-service/Properties/PublishProfiles/FolderProfile.pubxml @@ -0,0 +1,18 @@ + + + + + Release + Any CPU + bin\Manual\ + FileSystem + netcoreapp3.1 + true + win-x64 + False + False + False + + \ No newline at end of file diff --git a/hass-workstation-service/Properties/PublishProfiles/FolderProfile.pubxml.user b/hass-workstation-service/Properties/PublishProfiles/FolderProfile.pubxml.user new file mode 100644 index 0000000..312c6e3 --- /dev/null +++ b/hass-workstation-service/Properties/PublishProfiles/FolderProfile.pubxml.user @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/hass-workstation-service/hass-workstation-service.csproj.user b/hass-workstation-service/hass-workstation-service.csproj.user index 958055e..3061c40 100644 --- a/hass-workstation-service/hass-workstation-service.csproj.user +++ b/hass-workstation-service/hass-workstation-service.csproj.user @@ -1,7 +1,7 @@  - <_LastSelectedProfileId>C:\Users\Maurits\Documents\Repo\hass-desktop-service\hass-workstation-service\Properties\PublishProfiles\AzureHosted.pubxml + <_LastSelectedProfileId>C:\Users\Maurits\Documents\Repo\hass-desktop-service\hass-workstation-service\Properties\PublishProfiles\FolderProfile.pubxml true \ No newline at end of file From 6e1eb02896217243c78c421cf2f1de9263476939 Mon Sep 17 00:00:00 2001 From: sleevezipper Date: Sun, 3 Jan 2021 19:15:42 +0100 Subject: [PATCH 02/12] ignore .vs folder --- .gitignore | 2 ++ .vs/VSWorkspaceState.json | 7 ------- .../DesignTimeBuild/.dtbcache.v2 | Bin 162527 -> 0 bytes .vs/hass-workstation-service/v15/.suo | Bin 3584 -> 0 bytes .vs/hass-workstation-service/v16/.suo | Bin 278016 -> 0 bytes .vs/slnx.sqlite | Bin 221184 -> 0 bytes 6 files changed, 2 insertions(+), 7 deletions(-) create mode 100644 .gitignore delete mode 100644 .vs/VSWorkspaceState.json delete mode 100644 .vs/hass-workstation-service/DesignTimeBuild/.dtbcache.v2 delete mode 100644 .vs/hass-workstation-service/v15/.suo delete mode 100644 .vs/hass-workstation-service/v16/.suo delete mode 100644 .vs/slnx.sqlite diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..790402c --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ + +.vs/ diff --git a/.vs/VSWorkspaceState.json b/.vs/VSWorkspaceState.json deleted file mode 100644 index 115c3ca..0000000 --- a/.vs/VSWorkspaceState.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "ExpandedNodes": [ - "" - ], - "SelectedNode": "\\hass-workstation-service.sln", - "PreviewInSolutionExplorer": false -} \ No newline at end of file diff --git a/.vs/hass-workstation-service/DesignTimeBuild/.dtbcache.v2 b/.vs/hass-workstation-service/DesignTimeBuild/.dtbcache.v2 deleted file mode 100644 index 025b0a6486fe73dec1cc2a194215272899b2235d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 162527 zcmd2^1z;OT)>bqrGjp4!3{mWGQrg5$8V6lFP;fz(*0vH^QYATwQ)Z@=nVI33nfdNN zW^9kfw+HQA;s4&uJZVR8Q50!?X`kk^{b}Cp%C z@{uKTm$jv{Ze(^Q6B4tN$lw&r3a5HWyj-)1B|JPd=ER3f5 zBORGox0_v)h`EJFi_A~w^2oi&5`MOdRDEbbR;q{uqYjUoW+p=la3UnBZGAG=md-}X6oE^c{i0y zq*FOg^~9->7D}rQ_Wy6xP}@cmH&`fIx2Vaat4FIiu&82XA~ktZq|5D3T%9X%p11RZ(Y6)JFA=i%(g$Eam1=J}r^f$)PPxxRv>RXyV2-oSV-h2IQ=YVQ*B1 zL^9nUDb`j*K1CNk1-q6LLNhn21x2f3jpi~?7Q-t7g%sUh-NU)OI~Z9UO`#4Cx~aU$ zwOz{o5Sp=ZH9E4vLS!bNc45FluTx#`GFj83UxJ}O!OWT+HInn z&8D+iH@ct&#v1lIkJhbP;OqSZ7tQ$vjh*xKpo0_n^JG9fpfkgiRGBBIY46lhE z6S{KDL`9@VYSu=xuKHVON(&7@51y|F<(JDxQ}JjvJ_*07-WI5qE{-{wxBb3A|{7D>-vO_1)k7jY)JXGRbPdu$&S!zMitQK0R z;wwx251OGq)n2x?^q?M4xyA6_MKc-XUzKmA@`=857TxABC1ZT(_EAd5P@XDsLf81n z>|V5{(HPbKoKDxx{}btIOQ%<(Pt{4f;eRAa7<{OryZV13Jt`?T{!b)j>1@<0oi|sF zUV_ru#Cp|^>y(UQ))Z6HnNB8R=8fMlI$1;gb2^20J{O^4DyB_Upvy-+Q7ReNj(RfY zrL%*ky}54G6N7=^8aF$tt&OkRtaN*IQbw%?r&5?7sy?c`!?MO=!FA}mhw{JQ7y8D8 zL8c>Xs_jjqRBf}vnLG`lG6Tbrj#S>wVnVI!%WeMyDO%_bw_}F1#@929($I@6DHv?# zbycn~^ctmcMM=6;dwlEYlw3(td=?0ms!?ix+7r=!nu8`{=t9c|%%e1+@F(hjC3EJx z(PVz0jpq5LO&T7RHc{orD2+sEI*h3#nn5!2sg#V;NR%h$CsI`yOj zOJ(^)-q=G%Y2vmB*8b%Gf~CkxNLPADtqZExc$A7~v73*^F-aNKhIR3pScRTvlo~db zm`q~sx=a%GePfUrt_F`bVfH3qidL_QlXjR>{Ke9SMz$4o(o20wn52Juk9$U zQ;>eLUPkknbmSrnay&G$76*f~NR_1LR19oY_Kea5E6R$5yVf2&UNkCgim#50(&$yEplb*Nwn5Y9 z+%Y=u3|y|TfR%H}JB@5A<#YB?8Xc4-Y&1K8LRzrehlvllZRwY3lx#g+?pk=HnTj(? z1~48|msgn4$`t<~f0P6=p9T}xXV3U-Nj&7ZdQCh$%CWBV5u#iP7jXFi6 zG@>&pTIj+#$4&Z1{i9oFI6bPJyJvJdgOaRSmW`&+J7n{b?lhbW;p3nZH%jk!x4+>X zt+IlHb2Qn7N>j9vj*_LNyO0!~wT@P~n1rahF-i_@oEfwNoQ|cF{)yTsnFYIP@*Gos zkE7ZTz`w+Ldq=6dA{oo`iDV*Qa6CM>p0U4gpF)KFME|>+Xj}I{G@H>yV7W|e)U&wg zLa+T+Bbj704>!}nsBf9N2foCSDW$%%t&zz-Pu2ExeuBIl?msP>1RXms*o=mgV=%n|-k-zwEZC0YGZ}h!g zl+!`3$oo`d`5XIb_{Hu>B`EL4hwf^0=BDHw8k?U(K{{(yO%1&NI^8T4 zqt35}w=hFFm@VB{7E_OE*;Z3iP5bz|bv){=_@Ag|1=Ia&n_tc1yj5~Ik)l1MG{@eI zj;_5BT}L6hvhL2Bqt@3U>L=dkN8 zS*`V`(o5L+)@dS9?`i}3eoA6aZS3t&rh74%@2?|ydN=XOCIXeT2Fx=C%m(#Z-h?VG zFZ+6yy#to>M14)KNnW+=+DMA1{SVMr&{yY+zJfunEBX>p@BwQ}vsEz2<-1BL>CPi5 z#&R6w#s^p0v?RZ}q;Loj@FNQexMLp(d+s=o?QNeOWcu4KQYKrp4)0nL0B| zok*h+)PUyMB&b?asx;4Buc)NzHN?8b0RZQUy9QPi{7@}58!4-~^mQan<;~rVtKlkH zx%5yrR%azr3F}r7sI&#ST57eOx3kkCRVJaCN`^i@;yLVLls<)!%3^?-r0b5!DM8e8Acgn4V&s~!EtcbAXb^y zlv-3b)_8XozNcQdAXg22wFAp!b5k)`4A@<7-NfQqI8Cl83%b#!X z8Rm)Nqn}sLqi^~G;fh3VD4LuT#RSsl46-J8<#++chXQ(NeV~_J=f{WE`yP4|-o8pl zeDTpe{v(%)i)!|HV(NuEb(3^khkxs=AaeFOOdAW zp=2{v`3|ts+WZf;(c((EYx8jQq{IHyGDIsaTuSBD1jGFz9=*jjDpRz2c#1 ztjt$V@Hi?twQbWYgHZplgWxht8O(l)c zZ-%}4*t;6_V|c43g>~y!P7istg$j$lIKC_2(@F;`{x|(*(*#XM$smdEsFJnZPiiiJ zoU63wBGwpfH#H(Uj}6&tDxv%yUL zO7-jynO;;`soH6s#pzzEevM?m?3uE$a@GpTlB%*b>(kfp#?~CIh(qF#sd>DWq;h;H z9e~a`Lwz{A(Acs1dgQBA`T6oEA5A9#E)_R%WQTU^Fs7 znVc{Ya^tge!zoiA>+>q!8>BRO7E`G6yg(I1Cqu6`4MPhDn*`CyE2Z>-QK)Y=pvttV6GfB7N`GKos^80m zMrU;Jtr;%WbxzeLzP*0+h0*W$kmdYP>rgH3JCe+YD;V>6{6_xXoa??X7ZX*qoQEzR z<7-ChNs?MxD6V)^A4(S0=OU_Y=XH+y_GfQKiO}?51%}TUWp zw;q@}8At=*s|wwD9D1!5QS`&t=YqHyMX(IhrIoa6G^Q&AMGCeC%Ouf13UsW1{=u1nIaC#!cCdcuiRRO&2(662~h!+gH zO0zhKhQ(Ifj$@tO;$SV1H{4D^X{#R48}7^cmC-!z)iGnFAUZT;KnE5JqIow?ev>#r zNY}dagQ?+q zCZp*jRx+ky>7@E>$!NzZ)aq+$4y(P4LjGl&X7z3b^}%(hP`Ny%@0^P3qVL9$7*VzM z5R4TFdp^(AHN37mwu#drr47don*KY$A(PUKJO84%i_bW&1u&@|R7hfGfLrLCB>Lm@LStz(hDUCtAC9Ki55CrwC zi=zqif&|gu(zDVHW?gipCC-TDqltnT(JI|;p6=wNVHO=RSp?U}^u(ou zx_m${Y?piP5KeqDZGKQ%vFVuZ4mD>o2le*C|Ag)%?M&keS=~|vvBpBBYn?O`#8iot z!e_QEnJ73d1Tj@IYPGv+(V0MJc2JcI&kd9II#aoVm>rqN=2G_OdQj~L9-7q$*9Q*` zl7GhL%!W2`q`HJPuE1u8G#mGVc#HM^io%}t@%D06vxab8ZXaDzP5obcB8RJKV*|db z9fVJrF9oVz1z|$=>70u_3%d2Nrn~{&9he1TSoS?U`P-D*^n(~M(a@iE>E$9_YV(P%cmX|q zQME>T_G}D}!9KlS8`e*6ZNq9>8)QzuChu_A8gW368nxzNlcGz_bxP_xiEa~nTVBE| zONrhZ)TWaXgqJa=M72IaOn_No>6;fw_h%}=d>sB(ur&uUdgq5W+uaHkPvyFGa!|AD zerXC!%F65k)-Lj(6NSxM@$}jp=UU)(6PbkT{;)mI48Vh!YVgA@O4Ei!-2epA9-DWf zFac1x9mr6?Xr|38MfU=wKF~(k)^BzZ6?R?(;+)QfZzqNK!i^7&Vt$OyD6L}ED4bts z%~)z(Qoyl(+A?M@(&E&>@xRL+xAr?$*&!)A&^9}a5E^8)`USJ*-u7Q})}AzxIdTAxGB>|6#$*tRq_ zPhb}$rmTHx6KrdxGtf(4Rh-p2m{6D3n1NIf6O6(`qbjCii45OfZ}~rOa;K3gLOtonM>O?|HlPrNLe!#NPN!LBcvUaON3#QdX}0XhXL=L4A& zmufC;RYs)%Y>&DidQo3CsLG&=KG?di(@;DDFW`!Y8!L@LEC@#j?3TiEfLa<3aMWsP zRR^`|f(~LOdPOujX|#E`2pSd2jLA;R9RBSez*Oao2y#Kx2BDvqhIu+ZZ%OI zH+D>DCke zAQOIJme$%c5Y6Q#khe3;`sC>~A*UDoNh6}oN3;EIe%4xS{#oaSc9^&}noS`+*=#yH zA++7Zp?u#A#GV<-hYp)QJ5ZZZSGMehg zyn#+3m^CBP5}HXTf()g|9*JM|sKr=qrKtLc-0Vyu63d0!sxs_9pxTlvE+2@YRP^B_ zWgH@x3!P+htLiU_M450@1nNkW;sem3mp!wG@@e?c#nO1vVd%xhR@&wRg@@P*6@M{~ z((D}SO(t@*(+#AFHi>%ao;LW%C)-dQG`)tyJZ7AkbTSberY{^_;R|MWG|`a;B!v#q z0e63zGxg|XnftcP)0O|#jZ@mN$#%8=?%vjSu|v+q!Fnpz1JqwSszo~v=cz>#DV)nk zU&!_F$@awv4lQM1z`4fNuSJn{PzkH8b2+UK7YRp|67*qeZAo08i*vT@B-?3f9~vAS zF2;07Nlbc=%kms{1QtmXN=S6g)snQau%kxf%!#~@UYZRn7k8+=LB$BSMeWBG&4W}H z+pNT^sxy9GwO2Y~8W@wjhK)}UIwX#^TaB;vO zT0md6o>!Kuk<<`+gB~0kN`;i`S+yE%cO;RCnVQjuTIy0~g2OnoZuNse7c8Xjb!1|u zm6=!gUK_2UP{v$RUZ%Bc=bLJ%(pNkVwR!^lr^4RefHXvK9)%mHov-y|2d9R1L&a$q zuF9KrC>YZwj8hwed-PSfs$g=yo6k07VpKc^+W)N-+O0H(0Q%xr_*ev|dMH1DHo*)7 zBHTNm0aX@<&}E~Rl(uwwwYe`De)yx6A%!=EUekbTgIy$r*K}00FU62bO#wpd1I++< zcC0UW97vBJTm#_CcVn9jw(?;u&DfmFx`W{W3xS${-}`rNfU5PTvyd9`2Gi_V zu4HO5oYLMRxE3b32lxB4;ez9KxWld~w!#4pOK47ujL(~Wab@)|xRWKN(aM0d~rM)z(eIl#XOz?tZYV}GBg}nZz%u??K@P=u zT2@xy@`2?xCxLQ3z~+zDn&C%T1_U=2nxDs#%c$zlXUg?o9$X8ouI7SqwJ;{a=**m? z9pH$#EEQBCgBuYk^`!Fr;NCnel1EDVy8zog(mv0P=7(@zmKy#CtD9WBvbeBa>kh7e zrGn1+2Hit}m3QIxW~yevO*2X_A`Y^DvvhZ1fsgyx;Bwu+>psBdZ1I{{d7~a&+oIHG z67X70!Vs>f_W|ZP9=>2!3|y^lQ35omQfAXMrsSHNP$saZg;GGRO27~8+rC+J%ntOS zeJLQ{3d)1vjChpmRtrb!*97|fUD5SeBPYGV*$e2gmEOXBi-46ci}ufVlNqyXIN$baX4l0j?4hHPaFSyp{OW)F9tBlZb^lQ8bGKoeM+Rz)PP~K&{OU!L_?3&#$&i zkc+7Q0MJlyFJQN?!3(em;8_+;cA@kO*0A6v?cD|C#*Hb!+%~GI&IRZj!%s|WV(A#& zA61xA1ZNx~m&!z}a5qALo(Nb5_Z@s1pm_+2^-dl3M2goso~_mWyyy_t);$o-s`ESa zD3Ux{;bs=4qhfMBrEYn+ekq$)H`;5jv`7X%hHxSqjP{~kHk-z9EqqI43g6PrN6OHJ zeMPnH={y~6+iAXDHk4@gaK>ljtvZrza=TU`3B_~uL-$kHQfpzj#Zxq6%KzLrdPl5c zu{LvavCv6B#bWWN$%?3~fNp6>`rzw|!@kT>63Ikw=@~>dq->6gLXC;;ZAhA8=v?T0 zJZy{Dtb|b~g?O+*OOMc1!@apBx>+fr?&JA}|Fu6sMPAp9&ucQeP>~ zEk?M4BUEMja6{5dJ7|h8$!29D^+dkcgz~h>3!^@5)_#jfM@n6VriY=MTeB)0_)u&k zT5D+|3WI}Y`$tsG5O@#a$Q>%72DS%7)FZmFEKWz;tcpVggo9`(9+kS$sx@qseY(y! zEAD1+{~+=sF6~mGw3^H7>2y%CJfmuarD`=aqw89q(K*_Xcr1 zPO{oqX z8P%H_BNUE_s4SnF?Nj0_JUb;Aon+EEwjMTnQdu<_a|e6fc-)Pv7O{psImHQxTO9M+ zg_Ri?#>utOWVIK)%6Qk#o=y{qN|!S8)bXxUy7ZAs{kTCEW8MBb(xlJ+p_^DK0+pV6 z$KC_*tD`t-sm@iJL-r9XtH@*sts{#}lB(s)Mp8j{l%vRN?A<`>;>Gzt*>}N*lGvL{XL^SZK*y9MVFl0#os4Q9PlZ%&9h znxW2YQ3o@qRMgo-nnYAnU!{rUY@l*b%fp*d4(=Mv^O1~dN!Uomm`h(rdQ>LdxS2Io zrA1%eVJD~7dZAL&tu7!@32OF=vDK95766MkG1r%bCNCoTQn0j_W^8$x;)W)qwaCO;tF+aWW^TlKWVludvClI`f5|pSt}z-e8>C zi)*fMuttgLVq-50&g?bcQ}0NVS9^SAjinEDek?l@t#0nzc0sq=^_JEPAWe1~q6H5% zhSZlBYAaBx)(715r5$~j4vrW~_*_2|!RVtp+r&r1IWdzbmE3F^N^inDqRumlWZixo zRg@hzFJ^^H5Q+;BS|yI2Ro_sr#o~=C#Bn+}lL^N|v_x7b^O9KM?L*&<1B5_O(e*UC zXa;d6Q5N=i75mwZjvdM7rd=sGYooc5a@Xc*RMuxs7jC76!a}ZaWV9l+q{u8-m3ucD zKMbr13{xV}Tn34wTt>!EDV`GI%lB?W^__=7Rd(YgYIMMEH?tVAKj|DZMVG5N$;Hky z!c*d^2b{15U$e>6^178G+h}s4D=OF1N{{7JiXokv&}^DgwOX84b_lGr;kcQ6PiwWK zT=+?iOEJx!$Zm!2s2WELwEw+RG^G{Exk_Wnh^6|eEv&ekzh{k2l=6Yvl_yd-x)@_6 zHJPDeZRH#`HIjZ)P^s9^SD3xHo2W_8R&Y8_QBS3k>{g13)05aHsv+xE&y;(r;5=lk&{3lFFv$Ef|~eXdO6ZP@SF_ zSY|Fsr__b67;Di();yHljEBVeb}@Bvm@%K%ysKxEb((`=^qN!YmYSMPahs>M(sZoh zgW1BHXgx6%Xh2V?tP^x9Xnb~VIHl`S&3=ZPm%$}-zM72^o2Qj7p+!T4ou_nOCFL}A ztj%b*%vS$=&YE~}+O@+?8;lu7i6*XR{&1$ykee*loHmgTcdgudVE#Kgh%BNX* zr&N-HW_3mWC23R!a8l2-$;nWbUd&52I&Si-SM4VzCaNW=dEeh=WHya#&55S!$W*FU z4L5vL$Y->WIMGvAs;0e~g|f^=y7M>~R2i;S*4FI2v>91Tw+rcG=9S(>Fub@a(@6yJ z9xY3g%R3clvqp3Nnp?Uk5JV*+oiwSYXFR=0-7dx5td6!l8-*cHr+=_X>1Q1!!=qKr zQa6l4Wig5HZ|`hY^&_W};>E*l(WFb4zv?RAtWlV)lPU)p$(k|Vvo)0rEt=KycPv#F zD&7x@qtx?B?WEhRxk`yf%F$*`7)n%8*JpYr(%P(Es6^}OiA=$obY_#P4ph<;HR~Nf z^d))MtT)`&)Q*D{-NGoPS?`^#v!vN<;(O=I(v{JCjP6#TLTpyQfXD2>EDwj@$H_qo zXQnH4v^PtAxLHn9i5k+gQ_qvQ} zU(`mYt&3H4;5(&4q@o%1+qb8XR%n}{Vu@M6Zq_SG@fVzLn^l=vi8ak^<`XTBCUncz ztR9MTCtP&3~utZdWOLY?VElUEw4r2ISfn>BtXJ#bWOOD1^jv{~bK zqe(lA6&F%fpVZ8{fu}=9u}<9-+B7SK_Z>ECtc?4r=vFZ5u5hbfhNg1Gy4WoL5uZ}370t5l`P9sX zgRLsBW-YXq>grge92APZa)_k^@kUt&dV)~JC-tV3D4vr}I-tO~Jtk62Wuk)D}p^HK93v3Qem?N=;p z;zXSn6UccIh9ew9phjf5$a38D-lwOyHJ^6VDBapUy-k&EvlfW>!KqDe)-;QCl)M{F z>q3Tbao(UCnUAw&*aq0F;U__FTse@!k%TX|t0MX=8t)HtPL5%WoF6*)Zn$LGLZ6(Lb^A)sCo{_y z1yf4-vPHAHfr84mWHezeD{NND7IpcrYMY(x#~qRR0i(Prdjw1K*SfH-&3Jw^YhYOU zvDl(Kt%`z7i z9-exonk_57-D}tYgUM2#+S1h8!b`0F9dFvvv!DnEr41(3spWc5(X8QdQ6Yvfu|&pP zFsZiP*R+(J<2E@{hyYGsGz7Dk*b2|u!hWe0RGYz@nshX4xKU86fQyx0esP;Mnlb}( zZJUFEQ$1d@Mu|olY;pw$)Mm{;$OAM|X!>Y>RPla`W*PTwotyMJZsG*P)>JZmY}V^& zDb3L`hN>(Z-@KdC?MI%9WK}Mmvc1B~Up}R%Fz9S*4Z)`Dp=2~$>WR>_EF6IAMx5U1 zwt*jR8B^!X4KpnZEEc=Jl3*k4*O$iQ$}Ah zy;do0)~LDolv*j}XtSnarMgO9@SyV5a+zsX2jqKJRjjHIn_pG6+QM-*0n{2;-n3n~ zS*x#b$%jqW+=NcmvuUlEUy(X&O%+x||HRGZqY<>#UnySy6iP;6QV z+Lx{#=y2nTq&y4PzyZE}A#4vWj*`HXu-(n!x|(I^DMNc3UMKbr!u7ex3GFp!2p7C# z4oT4aQI z3V*<%xjkw_ESYW#vy|4VUx;M2B^e&;*e$MRI-z5f$_lYpA`AEih7Pao8=)<<0&>~0 zZ6Qs0=1?pMB~_2H%Eec!Nn>jZPP>V(#w|02+hj0zh~QT}`DnJE&e<>fOT_#o)K<;) zauZ???NSzhXzPLob+cLnGb-J?YSU^UHSS~c*&#Qyf7NP4oV~04H8fVer46oC)t;lF zwW_L;GIRU5BiGHCc2u#ZjMM%EUH08ttf$bf}4BUKVcP)P7Zr>V(qg>(Q4x_28hb(zmn?hpI*Vw&s@5>{`EG zb!ZyeQXPub5<1X4RJH!(5c52SnSkQX zy2p+)#e4#t&4>Sv9oIIL%nxPV6H@L_J{wIQJFau6H<^gxQjulp)o$v9>652VYnjqA zCF-{JO^r=&4eff~e7H1IH$N|%9_+}wgBOJ2)zz9q+8UubwNWj~^FK~In;M}nR;;f6 zQiLZ89R2&Zsy{YJBKHc48}WR-8`0PZ9RnND z5g`wmhP+pajcKAz!Ob?}p(?*szM_K7s1bUqRSB#>7;|Bx8^d^&Or+MYaaG+n4)gUb z=%X7_5e6$igWr)wIU3?#*+vvncH`K*=7ZYTJ0bcfjR0d?h$czzy6=0;~= zHC6dc!&Rj#mlYOWZ#UH{_kEJmaGJrc@};*hV}`bv?_X{qx;q1_jgzJ=F_mMZ#U% z$WHpqiiOj#f~hzyAe7nTLg2^ z<;t2#XA6fiH9~Xcs@~nWrlCp}!lfyi>_S1&VtpeXr1D&-yP&5rOMX?dOKWMwV^m%+ z<;NfcbUH@Is5ff(Sa~Ll)9JA!tPVwO#6wkXhOmxfPL67Xj>_c^9on_HLF>!i#TT`$ zdmx(i8F6qiUTq8Yy)BdbruI$mYi*5BZHZ2fhI}Kp_H>?(@#@4mxbOrRtUUUlYyO~Z z;~o}eE&;x7v}hiRG;6Hmd-W@5(+6obqUe2#M1DQi{WO(xQf)+UWKLQ-;S_~)ABs;{ zzc$~hP1Pr)rW9wGz*XBf;;LVzZxmilWh0(!ees2=rUp9}*Cev(6!}lDh~mfzoFeNR z9o7Gcz8OGO-P8sa|JaBp_L+lI4nf-S17{~>EBy9U`>d_zKCezvYEQ&RHpV|7Zugt^<7Z0q4BK=NBqmR4WCk0em$zGFFtVnFMs7; zkzPKGBG+Ig1$Mzk_lmxCJYQ+rI+Z6+u0eJI-*CCA!nuRJZX8#JHX>7N(bqXJjH9Le z{x9{vihGyv8Z3AZ^q^;Aiv5+ys?#QHQ%+}=vwVF zhFQ;~Z}zqZdBumTzm8X~9{g}nNB3qnLQ&=F&WhBAutun<+$b0|jZom5YF8*9zU{CP znktW?ILDMGeWPRZmC?0yZmF{R-&>zG$CrotIBPmPp!h)b>sVWHw6-)u1KylHSt_QX zsJQ+&s`3bi6*plex^k5_3LEi6m5Zx*3Rxp`_^gP<;-JHD)L}ynTHst!tP=~mm6LJW zXMU@{uKAWT$@Zq4!1N6PzByz4(VtaJw%$^QZNIpX(00sdCEFot?Z$0-W!A&fD#l+d zRTXtjJBZ4n_T>z=EKi=~ySJkl|CC5;1k`$LZp)0Bp(RKawpG*JkiI#|BxGYvr4)-z?`@sj*B6UVipS$qTSMJT+_ib?>ihB~ z%L1)5U9Kt8$t}_NlsF z<%es)$u+N}(=4i}xnV0)acV(DB83B|%0`7v(Z@vKaR9A`|FDw_^5ALEDI!H=YS)4cI9r);U9cI10ko6;aDmQa)+nJtSlYEo%-8uRcB$Nu8<3M(H_X!Uh)%ga?1Q(k}Xb9Q;Okq+!{&(r!s zQ2}*s^`-lq3JR8_Q|i``gwN5i{zs^k`P~^ercUMd8@%dQ5idN1*(#|I#jNO#IVGYR zlRE19KxHjehubxGzLQ&f`zFtrIxQNXJZ*|Qd1~m?ikgbWO)*0n_Y7*LM<>0+XXl1f z4Jr0m#b>B8IIFk$>8q@SZY@D02WNaZmin`;UOg)ddVC9D{)lTF!BlNO%lf7IUxp=x zwEDeCYOajEr6WOZ*{GgV=Wn^f)ZcS(!=s|54~zkdVa{AFIzUReL@QK`I1g|%!|e{0vF zOT(YjwRRb$?JQ;Xj7sLJ5`SK7 zZpEM##^NO}ZP6tB52E&Tq+S)=^;;?$k@jAbEmp)8ceU4FtGUabw0)O_@+CrAb%;QHp=16f>*{`J5ieIXPo8b~ArzbM@w43_$+U8fK z8Wx#S?pW$iZ>^b9`YLf{M0zV{M7_0~TUaaNNIOofa7%mCdR1_Jw^dX!@i(Nt7xO2w zlCBfACj#|81hKf0n&86$K^ zSQ1{CR=o9^Y<#Z~#S5367!8!v;Ml*^Mz2wAw(Zi2-({!VN_D-t?W>T>Q}9YfA;xvK za#r6UmBf!09F*)LF;AyAK)>H#aUSZazWYA91}#2ksFP$BTO@rwqHu(ED>eT<&*#nCn>#H zr&*JT;qWq?+v$(H-kQe-F%@?@w%T&ru6-z7+UjugOVPq9p)HvxYtHI>Q+RA=BGz65 z#ibB`meiZw{$fPhVJKPWI}x$|mz?J>Ch2A;R-`;{>P@)+jX}c8wtCgyf)w6wbJ?js zo9msf6lyhJpt=Iy_12krl-_A|tqgFj)-F;d9_{sK0}rxrYH!kP1!zy?GBhHuP)q7d zI*$U1I{cYkZ->Zci(;&ixq}I-1*x~zu`RYF>PW{TweD834Vf~(reR0f>H^zJOZ6;D z^bh3My7cMKse0A$Tk2P{F7M**VmN%*3TkS>%ASLbb3O&-XYI6NNvyUxdTGmBA^nZ* zJ=vDwOFu19RbK9>w^DKAKm(znEaqS6sOd`QMifBt0g7>Jq(|NjQBwW@+E(3&2S}I! zIA4=Y)-cSfvF%EY4RVp?xPYn8n#8x%*^sW@dScVC%AX+tTR0zJB$;KT+i_w%%8> z&_h)!9{Xr98c)^tKx`G@nQApVCt|1n>L?g)9}61vP4E6PuXlXFrBRI9e;#)6Vt2o; z$+a10$_8v)8kKe74tHBgeKz5ZD9L5~O6tuucKWLPBz#SABQ*W@@~Ql`)caK2rBr^Z z((Bj#Pq(@6XBCb9qyMPEsi{Vk^(;K+W+ncF*ZW5DnheJo@!g?r$6sHXxvwq8kFHi- zneLCh-h$?azC8Ab88#HP)Zc1x-&oM1fVl*{sGxo;0(b0YFju(q+#h$11zgqH(!^cC z$*0Dc%UVGmk*Zs%;vzrqwyN`wOTyNvg&5nw=c<*&1qV{J9qUStmOq<371(j~P?y?an z=7pR>q>at%CFZ@OolO4Z)>tXZrUr+Z`HmlV?tLCryn_iB4*nGAY_Sb24Ol-^`ZY8GVy_qoEyO z)WD5sF5T>!&xN*Jl3p3jrb0U}%_jO2IC+;YSEZeTq20M0s2*a1hSTWt!=bIrmJfhL zE`j}!p&dF>vE)#kBiv!`I{%M56}Jy8a@V-Y&~6>Mj=>CWZ%pKqxSp*K?vU}&R;oZ?1=qX*J= zo~vJMt80>ucivDksnAwk>2$t5fq2O06YlbEXq&<6V^M}3Elfa`08AYe>6(ZleopMEo9!d^M+{gSfyi!!rMl9LJtc^FWf&* z*YAe5!5hE0UHt(y)Z9i-e?e@aUDTm!X1RpQF{krY73tP|jc;f#a%e(kmcHDf?K*PB z=(mMaXgbxelC-0-n-`wQ+#(#>No{QHOT_pu+mW+FGCHijHi%1;8+gZfwVS{rv0Mg4 zzgSQFJi-$oCqhnwkRAsz8$x+C2hs*e|r>~!QQj_h(| zw%9C@W9uX5zoj=aW^*E;e#M_%v98ytC~BX4r#&5pdq zksBO&t0Ql7h=hwIhGy$lp5hcaHqMBmdyY*B$wWBmd~gKRNQxj{J)w|LRET$Pq{W z&5@oX|L(|tIP#y4{Ffu&bmUu({I?_jw@_NN9{RG6oWc2*_B-7LY9= zTS2ylYy;UAvK?f5$PSPlAv-~KhU@~_6|x&-cgP-)Jt2ER_J-^O*%z`OWPiv3kOLtH zLB>H2hKz?C0yz|N802us5s)JxM?sE;90NHPG652SOoX&RS|O7llOaxqEO30~@(;%lq&Vckl&V-x=IU8~gBns(;#2|5q3+aROLk1uT$STNcND?v# zNkP((4CGu$7LtSHAw!TgkhPF?kYUJr$a#?SAs0X{gj@u!e8H+FlOZHG3_2cypd}NTmx_|folP-BXAwS^#ra5xPib805=l2 z5#S~QHv!yC;AVhZ2;2g&fxrfUTM66>a2tW!0B$F6JHQ;9&v}13W_D5r9VtJPPm_fyV$I zC-6AH69k?Bc#^=A08bHk3gBr1PXjzd;2D5t2|Nq%9D(Nmo+t1;zzYOk0CF0NzL7eE{z#@P2>~5cmMV2MK%-;6nsH1n^-39|rgc zfsX)ul)y&;K1SeU03Rptaez+{_yoWw349XZQv^N*@M!{{2KWqt&j5Uuz-IwIN8ob+ zpC|BnfG-gE0>Bpud=cPF1il3DWddIY_zHoq0DP6eR{_38;A;S1C-8NEZxHwfz&8ne z6X06}z6J1Y0^bJs4uS6ge3!s?0lr7zdjS7O;Qs)=PvH9iKOpb}fFBb0A;6Ca{0QL3 z1bz(g69PX0_$h&(0{o1?&j5Z-;O79pAn*%-UlRBwz^@4W3gFiSehu&&0>1(HErH(x z{Eooy0De#4_W*w&@CSg`3A_&Q27xyK{z%}D0DmIzCxAZ__%py?2>b=$uLS-IAPGo- z5dtFse0Mc`imZxVPD;4K1g0sNc5zXAS3;6DIw z6L=fo9RlwFyi4F+fcFTz2M`Jagu>p)7y@Ge!UVzqf`9-ROJFR(76i5c*pk4O09z5* z3SesjTLWxEU>ksK32Y0n9f9otwkNPXzzzg<0N9bhjsQCm*a=`~0y_ijLSPqwT?y<8 zup5Eh0Cp#^JHQ?U_5j$Ez@7km5!ef0ZvuM*>_cE5fPD$<3$P!7{Q&kSus^^71P%Z= zkidZe2N5_3U>t#Q00$E|7+^es@c@SqI0WEO0*3+|M&K}j!wDP?a0G!P0FESZB*0Mw zjsiHEz|jE55I6?lSOUiaOdv1;AVMGlFpaVa zCNLXd4uLrUZ3Nl?+6lA+%q1`vU><>a04EbT8DKtv`2ZaRIsg_BSOBn)z(RmU1Qr1- zCa@S_34tX5O9?Cm=p@hya0-D_0J;ct0dy1S23SU58NhM^%K=spSOKt-z)FBq37iUW z8iCUQPA70Wz!?P20O%pm18^pRGXc&ba2CMX1kMIHhrl@iQ36qbUIM)UF#<7wIDt5T zOTY!_BhUxXPoN)QfWQDifr|3=tRtSVLe9z*+)p0oD;%2QW-v7+^ht^#JD)I1k`_0_Ou*g#+dz^w#s1-OmC zZ2-3uxE$XCK6Usd1uno9lG)#o=zpWJf3C$}8=CM*>@A}+Z#e%yNGTlnU; zA>UEN@8VOB$2&&87xpl!39DiG_kr<`a52Eo*Nic|AB5GYop~6+6Hf;K*D~*iVKt~{ z9tQZt(*eMB%==MTjro79^%6-<0yMauSw9J@34z7J3_-JQVAfB=YPMjpFn!Rh8=3X9 zu$oF(EX*x5>n3LXJgnv!77G&(&AORczX+>Ih{eLJM6+&T)-S_qhGMZWWznn+%=%SW zOmFvk5mwVQ zi-mccX5GuIKZeyD&SGIwr&;$g>rY`d!LwMH@oCom%=&X!&HgMFrh}UG0JHuQR#QWZ zg}I_;J;8Zx5avfS+P_buv;w5;5F-cX1xAhyXz^r$}YN~IsF!$H27n${5 zSlIzA77PQL^%Ao}LKz7x7OV!E^)j=@2xURASTHGQ)+@{k3uRugSgXx1l~wUbbG9g77+k7j+6 zSvw15^s!j50%_K#n6-;g79ooT6Om?pnpwLFWiGN=%teU@3f z3uS1sSg<^4*5{bDhfr21iv_ckW__MndkSTuvRJTLY1S8*wUp z!lqeYW7YveS=%fY%x{|Yb!HtXlqt?)!8WH^-(c23LfPpo77TZq^-X4t6UvBZv0&BH ztZy;vV4*C077Hdn&H6U8#tUWsvskbPYSwp{b%;>5L5l@rp=N!TS%(T`IJ8)>Bx=_8 zn01&?Rz-^iGoxnxAF~b@%H(LVV1v}G?=$NNq3n?s3kFKf`T?_!6v|j>v0%N_tRFJ# zD4{HwJa&gw6aVN}n)f5-9WAt>(?52HPnkDCC<`j{U`-{S4gh|}yogW+R_4LjN<19^{G53cg|fdg54Kq1=>Xst%xe+K zJj*TAad9#JG&od9UdgAE-;BU;EBb51`c`)S@ zPX_=V^V)>6?psd*bHDlrbHB;CcA-rF77J?un)MH6%@t~0z+z#cK(qeIta(B$8dxl> zB52mXn02yHD+(41OAMOzCbQ-XwcNl@iKPepqhD#>Tg>YaYBhp+Z)u(m@P&UfZ-G#Y z70koJ1;wWWfd4RWp-^iX%)`0{@pJ(2HuDw3`(;Jw4V#X_xwFz+4B(*bzz zGH;1c3nk2ZSMziL-h0ejD%3iPm3!|gGFYLoDb-G)7FjG-$TaU*bup|{gj#`NonsV% zex?3lQO5APgj%4nVhb}%Fsoar)fw#+(R zsKqFYwJo!@W7Zi$tyFPdY^MnHD_sKHGp|Reg)HW6uX#E^p6$TAGlg2`vb65NvF*sL zvxHg%vsgPaYbR!%Ez}Ab>)c7})B$wv%)E1iT0mpo&YGtK@OEKdRH*ee=Ix?+Isk81 z=Jg7-{KmXpHBSfN?Z&*AP^)vy+fDOy0N(D*iwm`Q$GqJ&PY2-b!8})}wLRwTp?Nw0 zZ%^j+3AOacygfBf2jK0+yndlp2AQ{)=IH>uy_q*4)WRY2_SQTdfVU6x5<;yjTBWv+ zB7?OrvsMYU=xDL_W!8SoS}oLyB(l{a+n;$!p%yHy*!Jhx4q(=xP^+01>i}jQ z$gGr5OPv<$KxQ4pth7+;pcd;OW{qQ3MyN$ni#3i}2Q%wjp;k~W*1^mg&#bIa%c~Y^ zJhKjAR!*q3SBrHBvkqleUZ{mxi*+co4rA7kP^-2U>o8^=&a5>;E$LdU!jI%xr!Ce5W<{8Fp-@ZL7AwN6iOjl4sC8|w`4bg^ex+O77Uo?n z)Ur48S~O1wctcv5cZpD|;+ED{j%^aNE){CY++s~))?{W~Ce(Vm#hT2lDa^WDsKs`R zHHBGInRSIwEAbXq?=P=`GeYW=&_-RYI-dTde8Kn!&8Ag<9aZSTmS4lUdgY zwfb+dW-@CQv#u4&HNaxcV%BlYx=tv+0gH7UvyNxh^+GunSghljbpo?)5X$4gVx7RO z6Pb0RQ0@p8>qKUq#H^cy@>Q@{Co#)m*3CjWGFU8!S+kjSi%?z;7Hc-M<}ho6P%aP_ zYYwy8n02dA{t*_djalu?x=kqO35(Uvthvm(T`12Ai#3;7^O$vqP;M6%YaX*sX4aiT z`D9qElbJQ2S$7HLuwk+0GpmDHcMIjsVX-=xwSZao2<7Twu@*3EA+zok$`6FwfQ5=c zztU~RBIeyEl$(eZ+ahKyX4d^e`H)zw#mrj5tOta0FtJ!mn6;Ey4+`adVzHJotCLv| z3FVq%u{xP`3bP&-%5TMDox-dxW<4U5Qw!%smm<)wbY65b?@^(AUaZ)nWj}a4goT%sP!( zPYdOtW3f(S*6GZ8Mkx0ki*-7)&S2KFLizSstTUL^!>s3oa{RGaJ$5^RtXZr)vxb=UIibAS zEY=XS)-dbyLbTto6+L zvQX}I7Hd7T&STbBgz~+!Sm!b8d}e)BD91dDbw0B$VAj`!^4hal7clEWW_?{Kmp+Si zA+s)G);EOm_p?|RG3#PxeN!lBK#O%Tvo2xQw}kQ(v{;ug>r!TYTPQa|i*+fpE@Rer zgz_=8SeG&Da%O#3C!4YRIg){lg8n6y~eGV3~K{a7e(N{e+J zv#w{>PlR%{v{=_O>jq~1R46}8i**CDZe-TagmTifST{23CT9IyC=X7HbrZ90X4Wr+ za_{7lyjcyLtX~V|H)^qNW!7!X`i)Rd zr55WpX5G%L-wNe%YO!u-)*a0Holx$m7V8dX-N~%q3+1b7vF>EnUCjD}P>!seV|OV6 z{YvN9-OPJkC_h&#w!4{i53}A7$_dtD-NUSVne|7ZJY+4_z0A6gS$`7Beb!>#$E^FA z^=F}cYc1CO%zA)Xe-X;@)?z)ttOuF(SE0OeE!Km~dWcz4D3@J}^$@cjX4Z&M{=63J zVP-wTtiK86>}#oI2iT_`tUi}e_@9%t4+gz_P_SdTO731n)-DmMzxP%zB1d{}#%r*V|WvtD6Vc&u{Xwpgz)>s4lnvC6aCV!g_& z*O)bStaAIdSg$c_i?JKV+%>Z0*aah7jUCw@ap@M+7^K9oZSd zE@MY_MX=l0k=+sOG4|q%X`lI?5ZXUKvgcT{(R^et{ORIQ=uh~|pCNyN{1qZ0BapvA zJjmZ6|A5fW^*0gjg77Vb|Azbr@;2lh$QzJ9LTZhVP7HV#{P!TCEf7B>3?Ur?;aJEP z5ISjKON5lBtq{@)0`$FqL8^UsYw-B{+W>D1*$zUx?zcy{1B9MuM}%}Dz)lD$zMbj! zkX<13eL4|fSA@Gkc8BZ%A>N({_kvKm_lE2P*%z`OWPb?7aRB5%$UzWF`#6LLL&ih= zY1<#s9D?7Go z;5(UM_rl2pTjFejE#=m78@a9APHqq9ez}9(QSPKpA&|Su-Q+GfdtetZ_K-;R$n_z9xji-=7qx7j@&Tj zc6k)-WjI=Qpz;{{;aKy-1pf~a`eCB^OAGzbYJQl6T?WUDk(1|na@S3q83A z!6HvCMzGkEOAsvaMG*C5 zFM?iA#t_6j8AlNJq>I4yWFLY)Pxd3|_v8SA0Z%3nBs{qa!75L#MzGqGNd!qx4k8%z zWC}sblW7ELPi7EgJb5mHb3K_wko9B^LC%wT1bI&mAsF)H8U$-Rxfa1%Pp(6-&XdCk zhCR6+!Fo@ghu}OH-=;8IUshTt+! zUXI{$PhNrG3Qt~%;7U(kh2SbrUX9>tPhNxI8c$w};95^!hu}I-UXS2laC{K+>=irc*2uUB6!l1Pa$~9lTRaf+LO;9c*c{@B6!x5&mnlulg}e~ z-jgpNc)^n|B6!i0FClozlP@E9*^{pzc*T>iB6!u4uOWENlkY?DK2N?M!TUY=0R$iL z|kC1mE%GcM*Kolix$| zJx~50g8%d6_Yr*GlRrT415f@C!4Ez8BLqM4|+J^3dDfAZv?5&YSce?jmUPyQ9bUp*-iNKcL+81dxa5d6)P9s{s+N-Joz?)w>|j|f_FUm zE`oPG`5uDz;QBLW9(`a>HGwezVFF;$kgft>+%A+QU;t^{@k*p0w$0J{^| z9bgXvdjRZ7U{8R(2$#g9sc1 zFpj`DfP)Df3^1O+cz{C)90G7CfkOcfBXAhN;RFr`ID)_t07nuy65uETM*$p7;Antj z2pj`&EP-PICJ>ka5Fro&m`GqEKnsBufK~#n0Fwwz0+>u-GQbo9QvjwCmU^U?sq*1WpAwjlgLDrxQ3G z;0yw10Q3;(0XUPunE+?eF(=E%{Er;Y;^1f&XXH}IWsu7uS3s_WTm`urat-8K$aRqG zAvZv7gxmzV8FC9`1LRi7ZIIg`cR=oh+y%KCau4KQ$bFFeArC+vgggX!81e|@QOIME z$01KZo`gIFc^dKzJ`3B^hkZ(c04fzh_ zyO8fe{txnf$PXYtg!~BdW5`b+KZX1Z@^i>9AisqC3i4~nZy>*g{0{Pa$R8lDL*9V= z5%MRW!2iYF717t_YPLQ1;yFhk@>;~B#vIk^O$X<}WA^Sk~h3p5} zA94WXK*&Lmagc){;~|GY4uu>BIUI5XfJ7h@AuW(r$Rx;Q$P~y_ z$TY}w$PCC#$SlZlkmDgIKu(051aTm zNGIeJNEf6VvJA2uvI4Raaw_CB$mx(XAU%*XA!k9(hMWV5LV6)FNF3rq`XK#~0Z0O} z3bGoKgbYGbkTfI%ITwJ7_uI69^`z;1&|9N7eOwDTmrciav9`u z$Q6()Ay+}JhFk-=7IGcrddLls8zDDAZid_f*#Nl}avS7!$Q_V7A$LLUhTH?W7jhru ze#irm2O$qZ9)>&uc@**(EfFF{_0yaIU@@*1|R z-;TZdCu44DCZ#g$$)j*$Q5YNT)vxvRlzx4T+FAdh(qB)&*+sMgU$OO+mDmv+U_?9e z)vxvBm44lVQ;cYPJ{=G6N%i?DeBLH^n-5p6PlxIAGwSoR>hp7o@_F_71@-wweBOmk z`yG16eg|#Y{~CV!dU)g;2)-G{w)_rk%g3(#j*;(%<)P#`jlK9CBi|2?`~Y9Z)O`WY z78v;j&YdgGPRYef+Rqjr>F@`KkK+nfm;>`uqhx)x3M*$S+~n8u?Wi)9;aA zYZDhB<)HdRIK^;&6UN-Uz?q^r>Jyx)hV$DnChi5!RK-!B;7l`|--R)&ANjp8rzy%b z`UGXVq5L6?8NW@LZYVPh<@GSE0XAiZq0BUtH^Q(K*p!)uGRsi@7={(Wrpz*w;|%3b zVOSV!%5jEryrKL#4C{kUIo?oCFqFT9VVSTgCm70!hVs`itQI!qL_;~rP;eyWNhOq% z48<{&kua6` z7}gb=(rzeo4dtI@6K?=UPqHl@Q*78uHZ!mt9_lm&*e&`{nE!$M?J78=STLwP3*>yb@aWGIUb z<=rqWOEzV(p)4_!_rkC`*_0)QveZyQ0v0KoveZyI4P}ggwaTV+8p3Ruo;%5pSDZP|h@z9R)0dHswr1Im=LX60jQDl(P)wY(v>uz@lhV&Nh^D z3}qJqYokp$$55h%va5h4(xyZWrPok)6R=X+lwL!L8OrVg7EGHGGnBZY>>*&?v?*~z zaSdfp0n4XNaSf%XZOVm)a*?652w3!O%0-59v7xjISo>|t#fEZ;p-d8339u=b z7|NxFGFf1iz@}VkD3=+^6oC~4n{t_jwexd%!s|{zSzoLK^k9R!3Y_Z|M}2~GgW;Sg zu)t#H&J9EaJysoHJn8P>s?vUHsxVMdBjk<1(xk>$|HvIsG%$qSkfyz(xdcO{6hVcj~UK#@&E1J2b5OT z5x{ZfUQiJm7*oXFdjU0x#)61SQ^5j)DQcQsuu_-aJ3{P*E_RH)i@o>WTVnm5SP)zO zb7$s@_nDJ&JUJ=nedo-3v$H?n!gX2p?VGvqysvI%CX`p?sm%Uo>c=YdC_`DHG)%UojQ7lFs2 z^~+q6E|ZR2=2A1i3_L5Xn@f{PN6ckreie9-nt!Ov>_c5{b-I`H5&zsi+H{%GVkfrq*|`J<7mjQlq6z_ zoB3VfX>i?KolH7nuQBucz@y^)LtSH+xz@-Lfyc->xz@;aMve?TVy=Ir>(WO`M?TW^ zW{wIxf3BPBlSxO+4Q7rGJe;nZ8*ls((h+mJ znG*uf+3V)^WYQ6{(9DT}hw%CTiiH9pcNjS-@PIxicNn?T$jO0+_c^)K$X!NG2|U=( z$z4Y7Hgamp^O*T{WF`UM&Za&n)M`;GJuG#TXN zej^VU84zed$jJjn9yBsA(43Hy2aP;rq#@9_kduduJZxl8ps67z4;y*J$lyT3Lrxws z@~Dv^fo6!DJZj`IBSS;&u@ZUA$m2$a1)3=Gt2}Px2_wS;4Hh|h!pM_GMg*EKa`L2+ zr;LmYG-l-FDI-rC85L;S$jQ@2o-r~y(9lu;Bk+v8mqL2go;5Qj(Ctw-&nAV%^1P83jEoPokmTeABQF}65NI#S$%{r_GBPpHdXkfujJ#}Q zQlKp*Coda$#mMA9%SujOG4iUBDS>vDoV;q}H6v34tu8rv&B*IUP7Acbt zXpzau8%EwVGCj~flan`%yk+DMf!3Owyk+E1Motg3-Q?s?M*eK%j6h3HPX27fEMruaR5408Kq-LZrazUWwC?|!H4~@(Sv?Jx@LnDif%nV#NCo1S&GBPXB#*~wf z>?$7{nH^|xs{e`oSl&w^y=tGBnG@)L$}jVYkxz}x4fICkx@TikV{iR+`2#ML|^~S4`hZM_HyQ zs0yx_zLj>fOi@r3T`_$ty=a-DpsKMerf;QDEmIU!HF3rCt#q+vih`Ix6&M!DGI8Zx?=iPI_EM)LDllEn7);^x=c|})yx&sx6*T$ zDGI7qaK-ekG~{K9f~pl=F?}oDdYPi2Y9&`p-%2ZArYNXd*%i~b(&v{c3aVCd#q_N- z0cMJVs^+ekzLgHaOi@tP!WGlE(mt3e3aVCh#q_Q87G{cqs_(gC`c@hbGetqwYOa{R zm9E50QBd`LS4`hZ%VMS|sQQ5`rf;R6F;f&&{m>QDx64eM_1y!rN zV)|CvBr`=pRZCY)-%1Z3aZw0#q_OoUuKGes}~6^qM&L!SIpjSS5_2MZSRWN+wIGWf~p-{F?+j1Sy52+V^>Vx zO2=`w5)@SZ#1)gb(vIx^C&_t9N!?G~F?%cB%GuQ@sM^sLv$xX9oGA*bc5=n+t@Jr( zih`=2xnlNKnxHd9LDkN#n7x$_=}b{jwTmleZ>4=YQxsI~>WbOhUCWAss@+^Md%GLT zSB#vOl+?9x$MkKR^3^D)+T9h?x4V}W1yyZbF@4*%tSG43!xhuFdz2LgRqb3cecP_A zD5%=g71OtSmK6n6d%0rzcCWIcplWYdOyBNZRuojVcg6H=`?8{-s)H-0Z#$F~1yvng zF@4*ytSG4JgtN=+pc9rLDl}Q8pqV3pZ)pR-_-%Gn#9z;pQ!^}9q5Wd-UG`Y zk%E52gIp~eQ{#Vjt%F>3bHy}pxAL_p=(W1LY8unXKz6O}t`2s^Nb$ktYf;c^^>EcJ zreTBZT0LC#bj4h9&+@e>=(P@UwPH+T3fZ*|G1btpQRAi3Yg*fHOrkRCytqX^MOsM5 z>7-hVj(YW#W34%p(E71B)>_n4ZBd=fkaQ=$A~lc9@1(2+nKsl)SMM~Yr}yN)VSqaQ zm$cq8I?WtUEPn8053$ZJ)8_|Z?ooGw!L9`?GB#vYN;3(o~;uzvs;yB`Xq8HJdIDt5k zIEgr!IE6Ts=tJ}+`Vsw!0mML}fv5&b{yzpv_TqEopBXCI8`qxbKy)NJ5uJ&Bh<%Cu zi2vl^Nf$o;>I?_8B-S9-B-SFCpI89BsL;8CN?29B{m~AC$=EAB(@^9 zCbl8AC0Y^xj^UH8{Mz>?+H?I5L`R|%(V5tX*q7Lk=t6WQssR)Ra9FRuHH2~?^=}TL z9K_o)fYOa~cj9282O)zcJvkpj{G9j&@k`=Y#G%At#NouRiQf>vC4NWzo;ZRyk~oSu znmC3ymNRL@{Yd&t(w}62Bm+nWN-~h7L6QcNL6Qt287#?Qk|B}|AsH&kP?BMi z3?msX$#9Ypl8hi3DalBZQId=z87;|Zk};BuAsH*lSdwv)j3XH@$#{|pl1w0(D9J>U zNs>$=nJmdGu%$}=X3PA|wemOD&EMQW-mGsd)>!_H^b6x| zL@_^d8)7w?Ym=*8)Yq`$ixWBMlF9pCVa(-X-6cQ?g!58#gb0daaF8R+ijm~Ii= zal0T+Pb3ZQZi(p*!X0-L;`Br^$la|m-C(%mW<#8wNCvyREvEYqcifAJ(-X-McelrM zd*Y5;6>)kZ8R~9fOm{EtxRVj5Cz4_A?uhB;#vM00;`Br^+})iq-TS!XK1iINNJhB3 zE2di`cibk4(-X-^cX!8h=j4vNC~!rzete?jDHgrp_HVc;fU#GTz;TG2QdImo0(as2 zrP^9T*QJZCOIKT$SZysKE5cS2=~e4t>(Z>+S|Y8>p|&oE*}AM+Z7q@3_Cz5mAy%5tAe0My}7pEtZbKSid(*u5Y zJnR>zCzA8ry%f{)e|Pi(h|?3v`R-nhsXf3QtpeioL~?<dd(9eoJm^h7et-Rn_W6Y8I<?MD$#3 z^^px2vGs?pOSRQUwbciIOkUMb2YQ0+>&F{W`h)6UX2^L-DZOg18LPGg(e-%S*5w^r zmugE8U6&7ST^8B8%&fKq(S=!J3sY?gvZ$!G1o5G~YD*AbiNCug$Q=J$>dlxMEB%{h znk;!qDZS{mv@bhs9U^^~?#RXIiKN;*#K%Lc%|m=8s?9@uC92Iss?9_63o2hKtIb1v zDbhcTnBHK+5c_+k+B}2}Lu@Uo%|m=8s?9@uC92Isd?o%THxHTT-%r04(`<-;Kh2y7 zFDdEQ!+&a%k>b1ji+BwUi;6>oemFT6@7QC(;@w6ai=B86v)SY&MIpV4_gozv$xDiY zs`p(T6N~rDih`;STpb&W56X&ys+z0gVj;VlWWRa}stQ-f$D%;(tiMOedD)5NLwCI* zdFg5t^lFP-^^V1&vZA2sBUdNH;-j*npz32+C&uFAvZA2s6IUn2;*+wXpz2dsjPHC} zRuoh%c6CZD7MB$TRiC*!H5Q+te8tFlNlD!jcYR{9q+ zFUpF7sxMvjkHwc|MM2e9t_H;7tFoe?>T6d6WASxaQBbv1u+RO5SS%GvpA{5TE$wPh zES4@S3aT2p8XSv8Wko?%a5W?rp{yvVimrynB9;{eRgGN@i$&wIqM)jYtKqR|QdSgH zE#qoLES4!N3aXZMH8K{SiY<%sA}eF zY%H3U6$Mo*xEdFW70QZ&suf+0kHv~*MM2d{t|r7{rLv-+YGqdwW3h5sQBbvtt4Xm~ zrK~8ZYVK-sESi@U1ywCvO^HQ|vZA1BRaaAEv1(aSP_>$?X|Y(XtSF>cL&IMH=WQ-a diff --git a/.vs/hass-workstation-service/v15/.suo b/.vs/hass-workstation-service/v15/.suo deleted file mode 100644 index 1144830cc5aca7efb3e04ac774995b6de921b580..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3584 zcmca`Uhu)fjZzO8(10BSGsD0CoD6J8;*3Bx6O1pwz`z1zgT(&*|NkE(%nZap<|r6K zArQon4}>KQ3Jk6cc|f{|p%N68L<2DfR(PC)(gHs4pl#BG-*>MuvI7-0Kotf6ZOmuL zV(bE0Aea(l7p}kqE*1`2GK-o zf+_^%-M`2NK-nO15FQ1?I|S&N{}oi(?t}6_D=_UfK-1r7{)Ywx1r%}$CDj<1URXIW wn(tvDGBW7V_#PSYjLVmV+H8c%lgNpY7c(P$ja2*Ih@V^>1}fS|!4L`o0Mz(Ad;kCd diff --git a/.vs/hass-workstation-service/v16/.suo b/.vs/hass-workstation-service/v16/.suo deleted file mode 100644 index cd9f65d2270e8b38f18c7490fb57bfbf4700e33c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 278016 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 From 2a4a8f2e306c2870b398ef79fede6d9b6a06e612 Mon Sep 17 00:00:00 2001 From: sleevezipper Date: Sun, 3 Jan 2021 19:16:13 +0100 Subject: [PATCH 03/12] try using registry for webcam use --- .../Domain/Sensors/WebcamActiveSensor.cs | 147 ++---------------- 1 file changed, 12 insertions(+), 135 deletions(-) diff --git a/hass-workstation-service/Domain/Sensors/WebcamActiveSensor.cs b/hass-workstation-service/Domain/Sensors/WebcamActiveSensor.cs index 6ff513a..823b8fd 100644 --- a/hass-workstation-service/Domain/Sensors/WebcamActiveSensor.cs +++ b/hass-workstation-service/Domain/Sensors/WebcamActiveSensor.cs @@ -1,7 +1,9 @@ using hass_workstation_service.Communication; +using Microsoft.Win32; using System; using System.Collections.Generic; using System.Diagnostics; +using System.Linq; using System.Management; using System.Runtime.ExceptionServices; using System.Runtime.InteropServices; @@ -17,19 +19,7 @@ namespace hass_workstation_service.Domain.Sensors } public override string GetState() { - try - { - List procs = WhoIsLocking("\\Device\\00000041"); - if (procs.Count > 0) - { - return "True"; - } - return "False"; - } - catch (Exception) - { - return "Error"; - } + return IsWebCamInUse() ? "True" : "False"; } public override AutoDiscoveryConfigModel GetAutoDiscoveryConfig() { @@ -43,140 +33,27 @@ namespace hass_workstation_service.Domain.Sensors }); } - [StructLayout(LayoutKind.Sequential)] - struct RM_UNIQUE_PROCESS - { - public int dwProcessId; - public System.Runtime.InteropServices.ComTypes.FILETIME ProcessStartTime; - } - - const int RmRebootReasonNone = 0; - const int CCH_RM_MAX_APP_NAME = 255; - const int CCH_RM_MAX_SVC_NAME = 63; - - enum RM_APP_TYPE + private bool IsWebCamInUse() { - RmUnknownApp = 0, - RmMainWindow = 1, - RmOtherWindow = 2, - RmService = 3, - RmExplorer = 4, - RmConsole = 5, - RmCritical = 1000 - } - - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] - struct RM_PROCESS_INFO - { - public RM_UNIQUE_PROCESS Process; - - [MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCH_RM_MAX_APP_NAME + 1)] - public string strAppName; - - [MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCH_RM_MAX_SVC_NAME + 1)] - public string strServiceShortName; - - public RM_APP_TYPE ApplicationType; - public uint AppStatus; - public uint TSSessionId; - [MarshalAs(UnmanagedType.Bool)] - public bool bRestartable; - } - - [DllImport("rstrtmgr.dll", CharSet = CharSet.Unicode)] - static extern int RmRegisterResources(uint pSessionHandle, - UInt32 nFiles, - string[] rgsFilenames, - UInt32 nApplications, - [In] RM_UNIQUE_PROCESS[] rgApplications, - UInt32 nServices, - string[] rgsServiceNames); - - [DllImport("rstrtmgr.dll", CharSet = CharSet.Auto)] - static extern int RmStartSession(out uint pSessionHandle, int dwSessionFlags, string strSessionKey); - - [DllImport("rstrtmgr.dll")] - static extern int RmEndSession(uint pSessionHandle); - - [DllImport("rstrtmgr.dll")] - static extern int RmGetList(uint dwSessionHandle, - out uint pnProcInfoNeeded, - ref uint pnProcInfo, - [In, Out] RM_PROCESS_INFO[] rgAffectedApps, - ref uint lpdwRebootReasons); - - /// - /// Find out what process(es) have a lock on the specified file. - /// - /// Path of the file. - /// Processes locking the file - /// See also: - /// http://msdn.microsoft.com/en-us/library/windows/desktop/aa373661(v=vs.85).aspx - /// http://wyupdate.googlecode.com/svn-history/r401/trunk/frmFilesInUse.cs (no copyright in code at time of viewing) - /// - /// - static public List WhoIsLocking(string path) - { - uint handle; - string key = Guid.NewGuid().ToString(); - List processes = new List(); - - int res = RmStartSession(out handle, 0, key); - if (res != 0) throw new Exception("Could not begin restart session. Unable to determine file locker."); - - try + using (var key = Registry.CurrentUser.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\CapabilityAccessManager\ConsentStore\webcam\NonPackaged")) { - const int ERROR_MORE_DATA = 234; - uint pnProcInfoNeeded = 0, - pnProcInfo = 0, - lpdwRebootReasons = RmRebootReasonNone; - - string[] resources = new string[] { path }; // Just checking on one resource. - - res = RmRegisterResources(handle, (uint)resources.Length, resources, 0, null, 0, null); - - if (res != 0) throw new Exception("Could not register resource."); - - //Note: there's a race condition here -- the first call to RmGetList() returns - // the total number of process. However, when we call RmGetList() again to get - // the actual processes this number may have increased. - res = RmGetList(handle, out pnProcInfoNeeded, ref pnProcInfo, null, ref lpdwRebootReasons); - - if (res == ERROR_MORE_DATA) + foreach (var subKeyName in key.GetSubKeyNames()) { - // Create an array to store the process results - RM_PROCESS_INFO[] processInfo = new RM_PROCESS_INFO[pnProcInfoNeeded]; - pnProcInfo = pnProcInfoNeeded; - - // Get the list - res = RmGetList(handle, out pnProcInfoNeeded, ref pnProcInfo, processInfo, ref lpdwRebootReasons); - if (res == 0) + using (var subKey = key.OpenSubKey(subKeyName)) { - processes = new List((int)pnProcInfo); - - // Enumerate all of the results and add them to the - // list to be returned - for (int i = 0; i < pnProcInfo; i++) + if (subKey.GetValueNames().Contains("LastUsedTimeStop")) { - try + var endTime = subKey.GetValue("LastUsedTimeStop") is long ? (long)subKey.GetValue("LastUsedTimeStop") : -1; + if (endTime <= 0) { - processes.Add(Process.GetProcessById(processInfo[i].Process.dwProcessId)); + return true; } - // catch the error -- in case the process is no longer running - catch (ArgumentException) { } } } - else throw new Exception("Could not list processes locking resource."); } - else if (res != 0) throw new Exception("Could not list processes locking resource. Failed to get size of result."); - } - finally - { - RmEndSession(handle); } - return processes; + return false; } - } } From 94dd333231e9bb2de2ce7e6954d4294878c912be Mon Sep 17 00:00:00 2001 From: sleevezipper Date: Sun, 3 Jan 2021 23:07:18 +0100 Subject: [PATCH 04/12] wip camera opencv --- .../Domain/Sensors/WebcamActiveSensor.cs | 42 +++++++++---------- .../hass-workstation-service.csproj | 1 + 2 files changed, 20 insertions(+), 23 deletions(-) diff --git a/hass-workstation-service/Domain/Sensors/WebcamActiveSensor.cs b/hass-workstation-service/Domain/Sensors/WebcamActiveSensor.cs index 823b8fd..aa86cf9 100644 --- a/hass-workstation-service/Domain/Sensors/WebcamActiveSensor.cs +++ b/hass-workstation-service/Domain/Sensors/WebcamActiveSensor.cs @@ -1,14 +1,6 @@ using hass_workstation_service.Communication; -using Microsoft.Win32; +using OpenCvSharp; using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using System.Management; -using System.Runtime.ExceptionServices; -using System.Runtime.InteropServices; -using System.Text; -using System.Threading; namespace hass_workstation_service.Domain.Sensors { @@ -35,25 +27,29 @@ namespace hass_workstation_service.Domain.Sensors private bool IsWebCamInUse() { - using (var key = Registry.CurrentUser.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\CapabilityAccessManager\ConsentStore\webcam\NonPackaged")) + try { - foreach (var subKeyName in key.GetSubKeyNames()) + VideoCapture capture = new VideoCapture(0); + OutputArray image = OutputArray.Create(new Mat()); + if (capture.Read(image)) { - 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 true; - } - } - } + capture.Release(); + capture.Dispose(); + return true; } + else + { + capture.Release(); + capture.Dispose(); + return false; + } + } + catch (Exception) + { - return false; + return false; + } } } } diff --git a/hass-workstation-service/hass-workstation-service.csproj b/hass-workstation-service/hass-workstation-service.csproj index 0757d67..16a3592 100644 --- a/hass-workstation-service/hass-workstation-service.csproj +++ b/hass-workstation-service/hass-workstation-service.csproj @@ -45,6 +45,7 @@ + From 053a99104cde1d397beb8c3bfc40409765563bff Mon Sep 17 00:00:00 2001 From: Sleevezipper Date: Sun, 3 Jan 2021 23:14:14 +0100 Subject: [PATCH 05/12] reverse webcam values --- .../Domain/Sensors/WebcamActiveSensor.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/hass-workstation-service/Domain/Sensors/WebcamActiveSensor.cs b/hass-workstation-service/Domain/Sensors/WebcamActiveSensor.cs index aa86cf9..a595508 100644 --- a/hass-workstation-service/Domain/Sensors/WebcamActiveSensor.cs +++ b/hass-workstation-service/Domain/Sensors/WebcamActiveSensor.cs @@ -31,17 +31,19 @@ namespace hass_workstation_service.Domain.Sensors { VideoCapture capture = new VideoCapture(0); OutputArray image = OutputArray.Create(new Mat()); + + // capture.Read() return false if it doesn't succeed in capturing if (capture.Read(image)) { capture.Release(); capture.Dispose(); - return true; + return false; } else { capture.Release(); capture.Dispose(); - return false; + return true; } } From 0886be29ebe4b0b35da379d2e24a44c8572d8ba2 Mon Sep 17 00:00:00 2001 From: Sleevezipper Date: Mon, 4 Jan 2021 20:29:30 +0100 Subject: [PATCH 06/12] add descriptions for webcamsensor --- README.md | 6 ++++++ UserInterface/Views/AddSensorDialog.axaml.cs | 4 ++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 76ed755..a9772bb 100644 --- a/README.md +++ b/README.md @@ -54,6 +54,12 @@ This sensor watches the UserNotificationState. This is normally used in applicat This sensor exposes the name of the currently focused window. +### WebcamActive + +This sensor shows if your webcam is currently in use. + +Please note: Using this sensor will make your webcam activity light turn on every time it checks if the webcam is being used. Using an update interval lower than 30 seconds is not recommended. + ### 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. diff --git a/UserInterface/Views/AddSensorDialog.axaml.cs b/UserInterface/Views/AddSensorDialog.axaml.cs index 2f307cd..5fa9aa4 100644 --- a/UserInterface/Views/AddSensorDialog.axaml.cs +++ b/UserInterface/Views/AddSensorDialog.axaml.cs @@ -101,10 +101,10 @@ namespace UserInterface.Views item.UpdateInterval = 5; break; case AvailableSensors.WebcamActiveSensor: - item.Description = "This sensor shows if the webcam is currently in use."; + item.Description = "Please note: Using this sensor will make your webcam activity light turn on every time it checks if the webcam is being used. Using an update interval lower than 30 seconds is not recommended."; item.MoreInfoLink = "https://github.com/sleevezipper/hass-workstation-service#webcamactive"; item.ShowQueryInput = false; - item.UpdateInterval = 10; + item.UpdateInterval = 60; break; default: item.Description = null; From d55eaa76f4bd27101a987a32aad33633c8c4fa54 Mon Sep 17 00:00:00 2001 From: sleevezipper Date: Tue, 5 Jan 2021 22:25:19 +0100 Subject: [PATCH 07/12] implement webcam and microphone sensors --- README.md | 7 +++ .../ViewModels/AddSensorViewModel.cs | 6 +++ UserInterface/Views/AddSensorDialog.axaml | 2 + UserInterface/Views/AddSensorDialog.axaml.cs | 21 +++++++- .../InterProcessApi.cs | 18 ++++++- .../ServiceContractModels.cs | 9 +++- .../Data/ConfigurationService.cs | 5 +- .../Data/ConfiguredSensor.cs | 2 + .../Domain/Sensors/MicrophoneActiveSensor.cs | 53 +++++++++++++++++++ .../Domain/Sensors/WebcamActiveSensor.cs | 51 ++++++++++++++++-- 10 files changed, 165 insertions(+), 9 deletions(-) create mode 100644 hass-workstation-service/Domain/Sensors/MicrophoneActiveSensor.cs diff --git a/README.md b/README.md index 76ed755..4598747 100644 --- a/README.md +++ b/README.md @@ -54,6 +54,13 @@ This sensor watches the UserNotificationState. This is normally used in applicat This sensor exposes the name of the currently focused window. +### WebcamActive + +This sensor shows if the webcam is currently being used. It has two detection modes: + +- Registry - this is the preferred method. This will work from Windows 10 version 1903 and higher. +- OpenCV - this method tries to access the webcam and if that fails, it assumes it is currently in use. This will flash the webcam activity light at every update interval. It also uses more CPU cycles and memory. + ### 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. diff --git a/UserInterface/ViewModels/AddSensorViewModel.cs b/UserInterface/ViewModels/AddSensorViewModel.cs index 0ea2220..d9cb102 100644 --- a/UserInterface/ViewModels/AddSensorViewModel.cs +++ b/UserInterface/ViewModels/AddSensorViewModel.cs @@ -9,14 +9,18 @@ namespace UserInterface.ViewModels public class AddSensorViewModel : ViewModelBase { private AvailableSensors selectedType; + private WebcamDetectionMode selectedDetectionMode; 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); } + public bool ShowDetectionModeOptions { get => showDetectionModeOptions; set => this.RaiseAndSetIfChanged(ref showDetectionModeOptions, value); } + private string moreInfoLink; private int updateInterval; + private bool showDetectionModeOptions; public string MoreInfoLink { @@ -26,6 +30,8 @@ namespace UserInterface.ViewModels public AvailableSensors SelectedType { get => selectedType; set => this.RaiseAndSetIfChanged(ref selectedType, value); } + public WebcamDetectionMode SelectedDetectionMode { get => selectedDetectionMode; set => this.RaiseAndSetIfChanged(ref selectedDetectionMode, value); } + public string Name { get; set; } public string Query { get; set; } public int UpdateInterval { get => updateInterval; set => this.RaiseAndSetIfChanged(ref updateInterval, value); } diff --git a/UserInterface/Views/AddSensorDialog.axaml b/UserInterface/Views/AddSensorDialog.axaml index 7dff3e4..e20d669 100644 --- a/UserInterface/Views/AddSensorDialog.axaml +++ b/UserInterface/Views/AddSensorDialog.axaml @@ -23,6 +23,8 @@ Query + Detection mode + diff --git a/UserInterface/Views/AddSensorDialog.axaml.cs b/UserInterface/Views/AddSensorDialog.axaml.cs index 2f307cd..ae81ab4 100644 --- a/UserInterface/Views/AddSensorDialog.axaml.cs +++ b/UserInterface/Views/AddSensorDialog.axaml.cs @@ -19,6 +19,7 @@ namespace UserInterface.Views { private readonly IIpcClient client; public ComboBox comboBox { get; set; } + public ComboBox detectionModecomboBox { get; set; } public AddSensorDialog() { this.InitializeComponent(); @@ -28,6 +29,9 @@ namespace UserInterface.Views this.comboBox = this.FindControl("ComboBox"); this.comboBox.Items = Enum.GetValues(typeof(AvailableSensors)).Cast(); + this.comboBox = this.FindControl("DetectionModeComboBox"); + this.comboBox.Items = Enum.GetValues(typeof(WebcamDetectionMode)).Cast(); + // register IPC clients ServiceProvider serviceProvider = new ServiceCollection() .AddNamedPipeIpcClient("addsensor", pipeName: "pipeinternal") @@ -47,7 +51,7 @@ namespace UserInterface.Views public async void Save(object sender, RoutedEventArgs args) { var item = ((AddSensorViewModel)this.DataContext); - dynamic model = new { Name = item.Name, Query = item.Query, UpdateInterval = item.UpdateInterval }; + dynamic model = new { Name = item.Name, Query = item.Query, UpdateInterval = item.UpdateInterval, DetectionMode = item.SelectedDetectionMode }; string json = JsonSerializer.Serialize(model); await this.client.InvokeAsync(x => x.AddSensor(item.SelectedType, json)); Close(); @@ -61,48 +65,63 @@ 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.ShowDetectionModeOptions = false; 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.ShowDetectionModeOptions = false; 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.ShowDetectionModeOptions = false; 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.ShowDetectionModeOptions = false; 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.ShowDetectionModeOptions = false; 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#usedmemory"; + item.ShowDetectionModeOptions = false; item.ShowQueryInput = false; item.UpdateInterval = 10; break; case AvailableSensors.ActiveWindowSensor: item.Description = "This sensor exposes the name of the currently active window."; item.MoreInfoLink = "https://github.com/sleevezipper/hass-workstation-service#activewindow"; + item.ShowDetectionModeOptions = false; item.ShowQueryInput = false; item.UpdateInterval = 5; break; case AvailableSensors.WebcamActiveSensor: item.Description = "This sensor shows if the webcam is currently in use."; item.MoreInfoLink = "https://github.com/sleevezipper/hass-workstation-service#webcamactive"; + item.ShowDetectionModeOptions = true; + 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#microphoneactive"; + item.ShowDetectionModeOptions = false; item.ShowQueryInput = false; item.UpdateInterval = 10; break; diff --git a/hass-workstation-service/Communication/InterProcesCommunication/InterProcessApi.cs b/hass-workstation-service/Communication/InterProcesCommunication/InterProcessApi.cs index c45b564..0723a27 100644 --- a/hass-workstation-service/Communication/InterProcesCommunication/InterProcessApi.cs +++ b/hass-workstation-service/Communication/InterProcesCommunication/InterProcessApi.cs @@ -107,7 +107,23 @@ namespace hass_workstation_service.Communication.InterProcesCommunication sensorToCreate = new ActiveWindowSensor(this._publisher, (int)model.UpdateInterval, model.Name); break; case AvailableSensors.WebcamActiveSensor: - sensorToCreate = new WebcamActiveSensor(this._publisher, (int)model.UpdateInterval, model.Name); + DetectionMode detectionMode; + switch ((WebcamDetectionMode)model.DetectionMode) + { + case WebcamDetectionMode.Registry: + detectionMode = DetectionMode.Registry; + break; + case WebcamDetectionMode.OpenCV: + detectionMode = DetectionMode.OpenCV; + break; + default: + detectionMode = DetectionMode.Registry; + break; + } + sensorToCreate = new WebcamActiveSensor(this._publisher, (int)model.UpdateInterval, model.Name, detectionMode); + break; + case AvailableSensors.MicrophoneActiveSensor: + sensorToCreate = new MicrophoneActiveSensor(this._publisher, (int)model.UpdateInterval, model.Name); break; default: Log.Logger.Error("Unknown sensortype"); diff --git a/hass-workstation-service/Communication/InterProcesCommunication/ServiceContractModels.cs b/hass-workstation-service/Communication/InterProcesCommunication/ServiceContractModels.cs index 3e110ea..f6fd43e 100644 --- a/hass-workstation-service/Communication/InterProcesCommunication/ServiceContractModels.cs +++ b/hass-workstation-service/Communication/InterProcesCommunication/ServiceContractModels.cs @@ -37,6 +37,13 @@ namespace hass_workstation_service.Communication.InterProcesCommunication.Models WMIQuerySensor, MemoryUsageSensor, ActiveWindowSensor, - WebcamActiveSensor + WebcamActiveSensor, + MicrophoneActiveSensor + } + + public enum WebcamDetectionMode + { + Registry, + OpenCV } } diff --git a/hass-workstation-service/Data/ConfigurationService.cs b/hass-workstation-service/Data/ConfigurationService.cs index 742b27e..e47ca96 100644 --- a/hass-workstation-service/Data/ConfigurationService.cs +++ b/hass-workstation-service/Data/ConfigurationService.cs @@ -89,7 +89,10 @@ namespace hass_workstation_service.Data sensor = new ActiveWindowSensor(publisher, configuredSensor.UpdateInterval, configuredSensor.Name, configuredSensor.Id); break; case "WebcamActiveSensor": - sensor = new WebcamActiveSensor(publisher, configuredSensor.UpdateInterval, configuredSensor.Name, configuredSensor.Id); + sensor = new WebcamActiveSensor(publisher, configuredSensor.UpdateInterval, configuredSensor.Name, configuredSensor.DetectionMode, configuredSensor.Id); + break; + case "MicrophoneActiveSensor": + sensor = new MicrophoneActiveSensor(publisher, configuredSensor.UpdateInterval, configuredSensor.Name, configuredSensor.Id); break; default: Log.Logger.Error("unsupported sensor type in config"); diff --git a/hass-workstation-service/Data/ConfiguredSensor.cs b/hass-workstation-service/Data/ConfiguredSensor.cs index 06dfd50..f7a4d30 100644 --- a/hass-workstation-service/Data/ConfiguredSensor.cs +++ b/hass-workstation-service/Data/ConfiguredSensor.cs @@ -1,3 +1,4 @@ +using hass_workstation_service.Domain.Sensors; using System; namespace hass_workstation_service.Data @@ -9,5 +10,6 @@ namespace hass_workstation_service.Data public string Name { get; set; } public string Query { get; set; } public int? UpdateInterval { get; set; } + public DetectionMode DetectionMode { get; set; } } } \ No newline at end of file diff --git a/hass-workstation-service/Domain/Sensors/MicrophoneActiveSensor.cs b/hass-workstation-service/Domain/Sensors/MicrophoneActiveSensor.cs new file mode 100644 index 0000000..8c9fa92 --- /dev/null +++ b/hass-workstation-service/Domain/Sensors/MicrophoneActiveSensor.cs @@ -0,0 +1,53 @@ +using hass_workstation_service.Communication; +using Microsoft.Win32; +using System; +using System.Linq; + +namespace hass_workstation_service.Domain.Sensors +{ + + public class MicrophoneActiveSensor : AbstractSensor + { + public MicrophoneActiveSensor(MqttPublisher publisher, int? updateInterval = null, string name = "MicrophoneActive", Guid id = default(Guid)) : base(publisher, name, updateInterval ?? 10, id) + { + } + public override string GetState() + { + return IsMicrophoneInUse() ? "True" : "False"; + } + 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:microphone", + }); + } + + private bool IsMicrophoneInUse() + { + using (var key = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\CapabilityAccessManager\ConsentStore\microphone\NonPackaged")) + { + foreach (var subKeyName in key.GetSubKeyNames()) + { + 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 true; + } + } + } + } + } + + return false; + } + } +} diff --git a/hass-workstation-service/Domain/Sensors/WebcamActiveSensor.cs b/hass-workstation-service/Domain/Sensors/WebcamActiveSensor.cs index aa86cf9..2da9b86 100644 --- a/hass-workstation-service/Domain/Sensors/WebcamActiveSensor.cs +++ b/hass-workstation-service/Domain/Sensors/WebcamActiveSensor.cs @@ -1,17 +1,35 @@ using hass_workstation_service.Communication; +using Microsoft.Win32; using OpenCvSharp; using System; +using System.Linq; namespace hass_workstation_service.Domain.Sensors { + public enum DetectionMode + { + Registry, + OpenCV + } public class WebcamActiveSensor : AbstractSensor { - public WebcamActiveSensor(MqttPublisher publisher, int? updateInterval = null, string name = "WebcamActive", Guid id = default) : base(publisher, name, updateInterval ?? 10, id) + public DetectionMode DetectionMode { get; private set; } + public WebcamActiveSensor(MqttPublisher publisher, int? updateInterval = null, string name = "WebcamActive", DetectionMode detectionMode = DetectionMode.Registry, Guid id = default(Guid)) : base(publisher, name, updateInterval ?? 10, id) { + this.DetectionMode = detectionMode; } public override string GetState() { - return IsWebCamInUse() ? "True" : "False"; + switch (this.DetectionMode) + { + case DetectionMode.Registry: + return IsWebCamInUseRegistry() ? "True" : "False"; + case DetectionMode.OpenCV: + return IsWebCamInUseOpenCV() ? "True" : "False"; + default: + return "Error"; + } + } public override AutoDiscoveryConfigModel GetAutoDiscoveryConfig() { @@ -25,7 +43,7 @@ namespace hass_workstation_service.Domain.Sensors }); } - private bool IsWebCamInUse() + private bool IsWebCamInUseOpenCV() { try { @@ -35,13 +53,13 @@ namespace hass_workstation_service.Domain.Sensors { capture.Release(); capture.Dispose(); - return true; + return false; } else { capture.Release(); capture.Dispose(); - return false; + return true; } } @@ -51,5 +69,28 @@ namespace hass_workstation_service.Domain.Sensors return false; } } + + private bool IsWebCamInUseRegistry() + { + using (var key = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\CapabilityAccessManager\ConsentStore\webcam\NonPackaged")) + { + foreach (var subKeyName in key.GetSubKeyNames()) + { + 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 true; + } + } + } + } + } + + return false; + } } } From 27ae913809fbfff40f211e5bd1cfafc1bd4f9b16 Mon Sep 17 00:00:00 2001 From: Sleevezipper Date: Thu, 7 Jan 2021 15:58:19 +0100 Subject: [PATCH 08/12] autostart path for standalone wip --- .../Data/ConfigurationService.cs | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/hass-workstation-service/Data/ConfigurationService.cs b/hass-workstation-service/Data/ConfigurationService.cs index a00eb76..fb2029e 100644 --- a/hass-workstation-service/Data/ConfigurationService.cs +++ b/hass-workstation-service/Data/ConfigurationService.cs @@ -273,8 +273,19 @@ namespace hass_workstation_service.Data // The path to the key where Windows looks for startup applications RegistryKey rkApp = Registry.CurrentUser.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Run", true); - //Path to launch shortcut - string startPath = Environment.GetFolderPath(Environment.SpecialFolder.Programs) + @"\Sleevezipper\Hass Workstation Service.appref-ms"; + string startPath; + // if the app is installed in appdata, we can assume it was installed using the installer + if (Environment.CurrentDirectory.Contains(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData))) + { + // so we set the autostart Path to launch shortcut + startPath = Environment.GetFolderPath(Environment.SpecialFolder.Programs) + @"\Sleevezipper\Hass Workstation Service.appref-ms"; + } + else + { + // if it isn't in appdata, it's probably running as standalone and we set the startpath to the path of the executable + startPath = Environment.CurrentDirectory + @"\hass-workstation-service.exe"; + } + rkApp.SetValue("hass-workstation-service", startPath); rkApp.Close(); From c63544d61796ff1cc9d2083588acefc3af9ee63c Mon Sep 17 00:00:00 2001 From: sleevezipper Date: Thu, 7 Jan 2021 20:37:21 +0100 Subject: [PATCH 09/12] fix versioning warning --- hass-workstation-service/hass-workstation-service.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hass-workstation-service/hass-workstation-service.csproj b/hass-workstation-service/hass-workstation-service.csproj index 16a3592..1fb7a53 100644 --- a/hass-workstation-service/hass-workstation-service.csproj +++ b/hass-workstation-service/hass-workstation-service.csproj @@ -8,7 +8,7 @@ Sleevezipper https://github.com/sleevezipper/hass-workstation-service false - 1.0.* + 1.0.0.* false hass-workstation-logo.ico From 725d86e8cc744a0ab430e86127fcd51bd93619bb Mon Sep 17 00:00:00 2001 From: sleevezipper Date: Thu, 7 Jan 2021 22:09:42 +0100 Subject: [PATCH 10/12] update readme --- README.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index e7244be..ea2b8cc 100644 --- a/README.md +++ b/README.md @@ -21,14 +21,16 @@ It will try to futher accomplish this goal in the future by: ## Installation -You can get the installer from [here](https://hassworkstationstorage.z6.web.core.windows.net/publish/setup.exe). When using the installer, the application checks for updates on startup. +You can get the installer from [here](https://hassworkstationstorage.z6.web.core.windows.net/publish/setup.exe). When using the installer, the application checks for updates on startup. This is the recommended way to install for most users. Note: You'll get a Windows Smartscreen warning because the code was self signed. You can click "More info" and then "Run anyway" to proceed with installing. -If you don't want to use the installer, you can find releases on GitHub [here](https://github.com/sleevezipper/hass-workstation-service/releases). `hass-workstation-service.exe` is the background service and you can use `UserInterface.exe` to configure the service. If you don't use the installer autostart won't work. +### Standalone + +If you don't want to use the installer, you can find the standalone version releases on GitHub [here](https://github.com/sleevezipper/hass-workstation-service/releases). Unpack all files to a folder and run `hass-workstation-service.exe`. This is the background service and you can use `UserInterface.exe` to configure the service. There is no automatic (or prompted) updating in the standalone version. ### Updating -The app checks for updates on startup. If an update is available you will be prompted to install. +If you used the installer, the app checks for updates on startup. If an update is available you will be prompted to install. If you use the standalone, just delete all files from the previous install and unpack the zip to the same location as before. ## Sensors From 8ae6a8f2337cfcc038990c06a7be73a6d017af2e Mon Sep 17 00:00:00 2001 From: sleevezipper Date: Thu, 7 Jan 2021 22:26:04 +0100 Subject: [PATCH 11/12] use {devicename}/{sensorname} for mqtt topics --- hass-workstation-service/Communication/MQTT/MqttPublisher.cs | 2 +- hass-workstation-service/Domain/Sensors/ActiveWindowSensor.cs | 2 +- hass-workstation-service/Domain/Sensors/CPULoadSensor.cs | 2 +- .../Domain/Sensors/CurrentClockSpeedSensor.cs | 2 +- hass-workstation-service/Domain/Sensors/DummySensor.cs | 2 +- hass-workstation-service/Domain/Sensors/MemoryUsageSensor.cs | 2 +- .../Domain/Sensors/MicrophoneActiveSensor.cs | 2 +- hass-workstation-service/Domain/Sensors/NamedWindowSensor.cs | 2 +- .../Domain/Sensors/UserNotificationStateSensor.cs | 2 +- hass-workstation-service/Domain/Sensors/WMIQuerySensor.cs | 2 +- hass-workstation-service/Domain/Sensors/WebcamActiveSensor.cs | 2 +- 11 files changed, 11 insertions(+), 11 deletions(-) diff --git a/hass-workstation-service/Communication/MQTT/MqttPublisher.cs b/hass-workstation-service/Communication/MQTT/MqttPublisher.cs index 163566c..c9f0bc8 100644 --- a/hass-workstation-service/Communication/MQTT/MqttPublisher.cs +++ b/hass-workstation-service/Communication/MQTT/MqttPublisher.cs @@ -113,7 +113,7 @@ namespace hass_workstation_service.Communication PropertyNameCaseInsensitive = true }; var message = new MqttApplicationMessageBuilder() - .WithTopic($"homeassistant/sensor/{config.Name}/config") + .WithTopic($"homeassistant/sensor/{this.DeviceConfigModel.Name}/{config.Name}/config") .WithPayload(clearConfig ? "" : JsonSerializer.Serialize(config, options)) .WithRetainFlag() .Build(); diff --git a/hass-workstation-service/Domain/Sensors/ActiveWindowSensor.cs b/hass-workstation-service/Domain/Sensors/ActiveWindowSensor.cs index 1f13278..d431f14 100644 --- a/hass-workstation-service/Domain/Sensors/ActiveWindowSensor.cs +++ b/hass-workstation-service/Domain/Sensors/ActiveWindowSensor.cs @@ -16,7 +16,7 @@ namespace hass_workstation_service.Domain.Sensors Name = this.Name, Unique_id = this.Id.ToString(), Device = this.Publisher.DeviceConfigModel, - State_topic = $"homeassistant/sensor/{this.Name}/state", + State_topic = $"homeassistant/sensor/{Publisher.DeviceConfigModel.Name}/{this.Name}/state", Icon = "mdi:window-maximize", }); } diff --git a/hass-workstation-service/Domain/Sensors/CPULoadSensor.cs b/hass-workstation-service/Domain/Sensors/CPULoadSensor.cs index 2b8b31e..fbbb9f4 100644 --- a/hass-workstation-service/Domain/Sensors/CPULoadSensor.cs +++ b/hass-workstation-service/Domain/Sensors/CPULoadSensor.cs @@ -21,7 +21,7 @@ namespace hass_workstation_service.Domain.Sensors Name = this.Name, Unique_id = this.Id.ToString(), Device = this.Publisher.DeviceConfigModel, - State_topic = $"homeassistant/sensor/{this.Name}/state", + State_topic = $"homeassistant/sensor/{Publisher.DeviceConfigModel.Name}/{this.Name}/state", Icon = "mdi:chart-areaspline", Unit_of_measurement = "%" }); diff --git a/hass-workstation-service/Domain/Sensors/CurrentClockSpeedSensor.cs b/hass-workstation-service/Domain/Sensors/CurrentClockSpeedSensor.cs index d1ced62..921a96d 100644 --- a/hass-workstation-service/Domain/Sensors/CurrentClockSpeedSensor.cs +++ b/hass-workstation-service/Domain/Sensors/CurrentClockSpeedSensor.cs @@ -16,7 +16,7 @@ namespace hass_workstation_service.Domain.Sensors Name = this.Name, Unique_id = this.Id.ToString(), Device = this.Publisher.DeviceConfigModel, - State_topic = $"homeassistant/sensor/{this.Name}/state", + State_topic = $"homeassistant/sensor/{Publisher.DeviceConfigModel.Name}/{this.Name}/state", Icon = "mdi:speedometer", Unit_of_measurement = "MHz" }); diff --git a/hass-workstation-service/Domain/Sensors/DummySensor.cs b/hass-workstation-service/Domain/Sensors/DummySensor.cs index b887338..5960104 100644 --- a/hass-workstation-service/Domain/Sensors/DummySensor.cs +++ b/hass-workstation-service/Domain/Sensors/DummySensor.cs @@ -20,7 +20,7 @@ namespace hass_workstation_service.Domain.Sensors Name = this.Name, Unique_id = this.Id.ToString(), Device = this.Publisher.DeviceConfigModel, - State_topic = $"homeassistant/sensor/{this.Name}/state" + State_topic = $"homeassistant/sensor/{Publisher.DeviceConfigModel.Name}/{this.Name}/state" }); } diff --git a/hass-workstation-service/Domain/Sensors/MemoryUsageSensor.cs b/hass-workstation-service/Domain/Sensors/MemoryUsageSensor.cs index 75ebf38..78fce3d 100644 --- a/hass-workstation-service/Domain/Sensors/MemoryUsageSensor.cs +++ b/hass-workstation-service/Domain/Sensors/MemoryUsageSensor.cs @@ -38,7 +38,7 @@ namespace hass_workstation_service.Domain.Sensors Name = this.Name, Unique_id = this.Id.ToString(), Device = this.Publisher.DeviceConfigModel, - State_topic = $"homeassistant/sensor/{this.Name}/state", + State_topic = $"homeassistant/sensor/{Publisher.DeviceConfigModel.Name}/{this.Name}/state", Icon = "mdi:memory", Unit_of_measurement = "%" }); diff --git a/hass-workstation-service/Domain/Sensors/MicrophoneActiveSensor.cs b/hass-workstation-service/Domain/Sensors/MicrophoneActiveSensor.cs index 8c9fa92..8e04aa6 100644 --- a/hass-workstation-service/Domain/Sensors/MicrophoneActiveSensor.cs +++ b/hass-workstation-service/Domain/Sensors/MicrophoneActiveSensor.cs @@ -22,7 +22,7 @@ namespace hass_workstation_service.Domain.Sensors Name = this.Name, Unique_id = this.Id.ToString(), Device = this.Publisher.DeviceConfigModel, - State_topic = $"homeassistant/sensor/{this.Name}/state", + State_topic = $"homeassistant/sensor/{Publisher.DeviceConfigModel.Name}/{this.Name}/state", Icon = "mdi:microphone", }); } diff --git a/hass-workstation-service/Domain/Sensors/NamedWindowSensor.cs b/hass-workstation-service/Domain/Sensors/NamedWindowSensor.cs index fe6c620..7cf7989 100644 --- a/hass-workstation-service/Domain/Sensors/NamedWindowSensor.cs +++ b/hass-workstation-service/Domain/Sensors/NamedWindowSensor.cs @@ -23,7 +23,7 @@ namespace hass_workstation_service.Domain.Sensors Name = this.Name, Unique_id = this.Id.ToString(), Device = this.Publisher.DeviceConfigModel, - State_topic = $"homeassistant/sensor/{this.Name}/state", + State_topic = $"homeassistant/sensor/{Publisher.DeviceConfigModel.Name}/{this.Name}/state", Icon = "mdi:window-maximize", }); } diff --git a/hass-workstation-service/Domain/Sensors/UserNotificationStateSensor.cs b/hass-workstation-service/Domain/Sensors/UserNotificationStateSensor.cs index 25f0252..e98e1d9 100644 --- a/hass-workstation-service/Domain/Sensors/UserNotificationStateSensor.cs +++ b/hass-workstation-service/Domain/Sensors/UserNotificationStateSensor.cs @@ -16,7 +16,7 @@ namespace hass_workstation_service.Domain.Sensors Name = this.Name, Unique_id = this.Id.ToString(), Device = this.Publisher.DeviceConfigModel, - State_topic = $"homeassistant/sensor/{this.Name}/state", + State_topic = $"homeassistant/sensor/{Publisher.DeviceConfigModel.Name}/{this.Name}/state", Icon = "mdi:laptop", }); } diff --git a/hass-workstation-service/Domain/Sensors/WMIQuerySensor.cs b/hass-workstation-service/Domain/Sensors/WMIQuerySensor.cs index 0e9204d..bf5002e 100644 --- a/hass-workstation-service/Domain/Sensors/WMIQuerySensor.cs +++ b/hass-workstation-service/Domain/Sensors/WMIQuerySensor.cs @@ -24,7 +24,7 @@ namespace hass_workstation_service.Domain.Sensors Name = this.Name, Unique_id = this.Id.ToString(), Device = this.Publisher.DeviceConfigModel, - State_topic = $"homeassistant/sensor/{this.Name}/state", + State_topic = $"homeassistant/sensor/{Publisher.DeviceConfigModel.Name}/{this.Name}/state", }); } diff --git a/hass-workstation-service/Domain/Sensors/WebcamActiveSensor.cs b/hass-workstation-service/Domain/Sensors/WebcamActiveSensor.cs index 65829d0..d3323a0 100644 --- a/hass-workstation-service/Domain/Sensors/WebcamActiveSensor.cs +++ b/hass-workstation-service/Domain/Sensors/WebcamActiveSensor.cs @@ -38,7 +38,7 @@ namespace hass_workstation_service.Domain.Sensors Name = this.Name, Unique_id = this.Id.ToString(), Device = this.Publisher.DeviceConfigModel, - State_topic = $"homeassistant/sensor/{this.Name}/state", + State_topic = $"homeassistant/sensor/{Publisher.DeviceConfigModel.Name}/{this.Name}/state", Icon = "mdi:webcam", }); } From e6ef2836a479ff205476a98f073b7f637c0bf6d4 Mon Sep 17 00:00:00 2001 From: sleevezipper Date: Thu, 7 Jan 2021 22:26:22 +0100 Subject: [PATCH 12/12] update manual publish location --- .../Properties/PublishProfiles/ClickOnceProfile.pubxml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hass-workstation-service/Properties/PublishProfiles/ClickOnceProfile.pubxml b/hass-workstation-service/Properties/PublishProfiles/ClickOnceProfile.pubxml index 7744d22..340d941 100644 --- a/hass-workstation-service/Properties/PublishProfiles/ClickOnceProfile.pubxml +++ b/hass-workstation-service/Properties/PublishProfiles/ClickOnceProfile.pubxml @@ -4,7 +4,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121. --> - 35 + 36 1.0.0.* True Release @@ -19,8 +19,8 @@ https://go.microsoft.com/fwlink/?LinkID=208121. true false Any CPU - bin\publish\ - bin\publish\ + bin\publish-manual\ + bin\publish-manual\ ClickOnce True False