From 715a55a023498f1e3f895d629d952e22c746e821 Mon Sep 17 00:00:00 2001 From: helto4real Date: Sun, 10 Jan 2021 10:12:10 +0100 Subject: [PATCH] Implement wait for response CallService --- src/App/NetDaemon.App/Common/INetDaemon.cs | 3 ++- .../Common/Reactive/INetDaemonReactive.cs | 3 ++- .../Common/Reactive/NetDaemonRxApp.cs | 6 ++---- src/App/NetDaemon.App/Common/Reactive/RxEntity.cs | 12 +++++++----- .../NetDaemon.Daemon/Daemon/NetDaemonHost.cs | 13 ++++++++++--- src/DevelopmentApps/apps/DebugApp/DebugApp.cs | 1 + src/Fakes/NetDaemon.Fakes/RxAppMock.cs | 14 +++++++++----- 7 files changed, 33 insertions(+), 19 deletions(-) diff --git a/src/App/NetDaemon.App/Common/INetDaemon.cs b/src/App/NetDaemon.App/Common/INetDaemon.cs index a8473b49f..400dda41e 100644 --- a/src/App/NetDaemon.App/Common/INetDaemon.cs +++ b/src/App/NetDaemon.App/Common/INetDaemon.cs @@ -29,7 +29,8 @@ public interface INetDaemon : INetDaemonCommon /// The domain of the service /// The service being called /// Any data that the service requires - void CallService(string domain, string service, dynamic? data = null); + /// Waits for Home Assistant to return result before returning + void CallService(string domain, string service, dynamic? data = null, bool waitForResponse = false); /// /// Calls a service diff --git a/src/App/NetDaemon.App/Common/Reactive/INetDaemonReactive.cs b/src/App/NetDaemon.App/Common/Reactive/INetDaemonReactive.cs index a6fb89450..e9200f97b 100644 --- a/src/App/NetDaemon.App/Common/Reactive/INetDaemonReactive.cs +++ b/src/App/NetDaemon.App/Common/Reactive/INetDaemonReactive.cs @@ -68,7 +68,8 @@ public interface INetDaemonRxApp : INetDaemonAppBase, IRxEntity /// Domain of sevice /// Service name /// Data provided to service. Use anonomous type - void CallService(string domain, string service, dynamic? data); + /// Waits for Home Assistant to return result before returning + void CallService(string domain, string service, dynamic? data, bool waitForResponse = false); /// /// Calls service in Home Assistant diff --git a/src/App/NetDaemon.App/Common/Reactive/NetDaemonRxApp.cs b/src/App/NetDaemon.App/Common/Reactive/NetDaemonRxApp.cs index 4fdb4f94b..dbb48ca39 100644 --- a/src/App/NetDaemon.App/Common/Reactive/NetDaemonRxApp.cs +++ b/src/App/NetDaemon.App/Common/Reactive/NetDaemonRxApp.cs @@ -62,10 +62,10 @@ protected NetDaemonRxApp() Daemon?.State ?? new List(); /// - public void CallService(string domain, string service, dynamic? data) + public void CallService(string domain, string service, dynamic? data, bool waitForResponse = false) { _ = Daemon ?? throw new NetDaemonNullReferenceException($"{nameof(Daemon)} cant be null!"); - Daemon.CallService(domain, service, data); + Daemon.CallService(domain, service, data, waitForResponse); } /// @@ -73,7 +73,6 @@ public void Delay(TimeSpan timeout) { // We use Task.Delay instead of Thread.Sleep so we can stop timers on cancellation tokens Task.Delay(timeout, _cancelTimers.Token).Wait(_cancelTimers.Token); - Logger.LogError("WE REACHED END OF DELAY!"); } /// @@ -83,7 +82,6 @@ public void Delay(TimeSpan timeout, CancellationToken token) using var combinedToken = CancellationTokenSource.CreateLinkedTokenSource(_cancelTimers.Token, token); // We use Task.Delay instead of Thread.Sleep so we can stop timers on cancellation tokens Task.Delay(timeout, combinedToken.Token).Wait(combinedToken.Token); - Logger.LogError("WE REACHED END OF DELAY2!"); } /// diff --git a/src/App/NetDaemon.App/Common/Reactive/RxEntity.cs b/src/App/NetDaemon.App/Common/Reactive/RxEntity.cs index 6092683c4..33bbb3601 100644 --- a/src/App/NetDaemon.App/Common/Reactive/RxEntity.cs +++ b/src/App/NetDaemon.App/Common/Reactive/RxEntity.cs @@ -19,7 +19,8 @@ public interface IRxEntityBase /// /// The state to set, primitives only /// The attributes to set. Use anonomous type - void SetState(dynamic state, dynamic? attributes = null); + /// Waits for Home Assistant to return result before returning + void SetState(dynamic state, dynamic? attributes = null, bool waitForResponse = false); /// /// Toggles state on/off on entity @@ -94,11 +95,11 @@ public RxEntity(INetDaemonRxApp daemon, IEnumerable entityIds) } /// - public void SetState(dynamic state, dynamic? attributes = null) + public void SetState(dynamic state, dynamic? attributes = null, bool waitForResponse = false) { foreach (var entityId in EntityIds) { - DaemonRxApp.SetState(entityId, state, attributes); + DaemonRxApp.SetState(entityId, state, attributes, waitForResponse); } } @@ -125,7 +126,8 @@ internal static string GetDomainFromEntity(string entity) /// /// Name of the service to call /// Data to provide - public void CallService(string service, dynamic? data = null) + /// Waits for Home Assistant to return result before returning + public void CallService(string service, dynamic? data = null, bool waitForResponse = false) { if (EntityIds?.Any() != true) return; @@ -153,7 +155,7 @@ public void CallService(string service, dynamic? data = null) serviceData["entity_id"] = entityId; - DaemonRxApp.CallService(domain, service, serviceData); + DaemonRxApp.CallService(domain, service, serviceData, waitForResponse); } } diff --git a/src/Daemon/NetDaemon.Daemon/Daemon/NetDaemonHost.cs b/src/Daemon/NetDaemon.Daemon/Daemon/NetDaemonHost.cs index 411d5db08..24fcc057c 100644 --- a/src/Daemon/NetDaemon.Daemon/Daemon/NetDaemonHost.cs +++ b/src/Daemon/NetDaemon.Daemon/Daemon/NetDaemonHost.cs @@ -159,12 +159,19 @@ public async Task> GetAllServices() return await _hassClient.GetServices().ConfigureAwait(false); } - public void CallService(string domain, string service, dynamic? data = null) + public void CallService(string domain, string service, dynamic? data = null, bool waitForResponse = false) { _cancelToken.ThrowIfCancellationRequested(); - if (!_serviceCallMessageChannel.Writer.TryWrite((domain, service, data))) - throw new NetDaemonException("Servicecall queue full!"); + if (!waitForResponse) + { + if (!_serviceCallMessageChannel.Writer.TryWrite((domain, service, data))) + throw new NetDaemonException("Servicecall queue full!"); + } + else + { + CallServiceAsync(domain, service, data, true).Result(); + } } [SuppressMessage("", "CA1031")] diff --git a/src/DevelopmentApps/apps/DebugApp/DebugApp.cs b/src/DevelopmentApps/apps/DebugApp/DebugApp.cs index 64c9934e9..a60c202fc 100644 --- a/src/DevelopmentApps/apps/DebugApp/DebugApp.cs +++ b/src/DevelopmentApps/apps/DebugApp/DebugApp.cs @@ -21,6 +21,7 @@ public override void Initialize() { var uid = Guid.NewGuid(); RunEvery(TimeSpan.FromSeconds(5), () => Log("Hello developer! from instance {instanceId} - {id}", _instanceId, uid)); + CallService("notify", "persistent_notification", new { message = "Hello", title = "Yay it works!" }, true); } [HomeAssistantServiceCall] diff --git a/src/Fakes/NetDaemon.Fakes/RxAppMock.cs b/src/Fakes/NetDaemon.Fakes/RxAppMock.cs index 92c8a2df3..a4b0751d9 100644 --- a/src/Fakes/NetDaemon.Fakes/RxAppMock.cs +++ b/src/Fakes/NetDaemon.Fakes/RxAppMock.cs @@ -184,7 +184,7 @@ public void VerifyCallService(string? domain = null, string? service = null, dyn domain ??= It.IsAny(); service ??= It.IsAny(); data ??= It.IsAny(); - Verify(x => x.CallService(domain, service, It.IsAny()), t); + Verify(x => x.CallService(domain, service, It.IsAny(), It.IsAny()), t); } /// @@ -276,14 +276,16 @@ public void VerifyEntitySetState(string entityId, dynamic? state = null { Verify(x => x.Entity(entityId).SetState( (object)state, - (object)attributes), + (object)attributes, + It.IsAny()), t); } else { Verify(x => x.Entity(entityId).SetState( (object)state, - It.IsAny()), + It.IsAny(), + It.IsAny()), t); } } @@ -293,14 +295,16 @@ public void VerifyEntitySetState(string entityId, dynamic? state = null { Verify(x => x.Entity(entityId).SetState( It.IsAny(), - (object)attributes), + (object)attributes, + It.IsAny()), t); } else { Verify(x => x.Entity(entityId).SetState( It.IsAny(), - It.IsAny()), + It.IsAny(), + It.IsAny()), t); } }