Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bring back service call callback to Rx API #148

Merged
merged 1 commit into from
Jun 30, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,11 @@
"coverage-gutters.showLineCoverage": true,
},
"remoteEnv": {
"HASS_TOKEN": "${localEnv:HASS_TOKEN}"
"HASS_HOST": "${localEnv:HASS_HOST}"
"HASS_PORT": "${localEnv:HASS_PORT}"
"HASS_LOGLEVEL": "${localEnv:HASS_LOGLEVEL}"
"HASS_TOKEN": "${localEnv:HASS_TOKEN}",
"HASS_HOST": "${localEnv:HASS_HOST}",
"HASS_PORT": "${localEnv:HASS_PORT}",
"HASS_LOGLEVEL": "${localEnv:HASS_LOGLEVEL}",
"HASS_DAEMONAPPFOLDER": "${localEnv:HASS_DAEMONAPPFOLDER}"
},
"postCreateCommand": "dotnet restore && .devcontainer/install_prettyprompt.sh",
// Uncomment the next line if you want to publish any ports.
Expand Down
16 changes: 6 additions & 10 deletions exampleapps/apps/test2.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Threading.Tasks;
using JoySoftware.HomeAssistant.NetDaemon.Common;
using JoySoftware.HomeAssistant.NetDaemon.Common.Reactive;
using System.Linq;
using System;
Expand Down Expand Up @@ -89,16 +90,11 @@ public override async Task InitializeAsync()
// Entity(Wh)
// }

// private async Task MyMotionSensorStateChange(string entityId, EntityState? newState, EntityState? oldState)
// {
// await Entity("light.light1").TurnOn().ExecuteAsync();
// }

// [HomeAssistantServiceCall]
// public async Task CallMeFromHass(dynamic data)
// {
// Log("A call from hass!");
// }
[HomeAssistantServiceCall]
public void CallMeFromHass(dynamic data)
{
Log("A call from hass! {data}", data);
}
}

// public static class NotifyExtensions
Expand Down
27 changes: 8 additions & 19 deletions src/App/NetDaemon.App/Common/INetDaemon.cs
Original file line number Diff line number Diff line change
Expand Up @@ -106,15 +106,6 @@ public interface INetDaemon : INetDaemonCommon
/// <param name="app">The Daemon App calling fluent API</param>
IFluentInputSelect InputSelects(INetDaemonApp app, Func<IEntityProperties, bool> func);

/// <summary>
/// Listen to service calls
/// </summary>
/// <param name="domain">The domain of the service call</param>
/// <param name="service">The service being called</param>
/// <param name="action">The action to perform when service is called</param>
void ListenServiceCall(string domain, string service,
Func<dynamic?, Task> action);

/// <summary>
/// Selects one or more media player entities to do action on
/// </summary>
Expand Down Expand Up @@ -291,15 +282,6 @@ public interface INetDaemonApp : INetDaemonAppBase
void ListenEvent(Func<FluentEventProperty, bool> funcSelector,
Func<string, dynamic, Task> action);

/// <summary>
/// Listen to service calls
/// </summary>
/// <param name="domain">The domain of the service call</param>
/// <param name="service">The service being called</param>
/// <param name="action">The action to perform when service is called</param>
void ListenServiceCall(string domain, string service,
Func<dynamic?, Task> action);

/// <summary>
/// Listen to statechange
/// </summary>
Expand Down Expand Up @@ -403,7 +385,14 @@ public interface INetDaemonAppBase :
/// <param name="value">Value to set, null removes the attribute</param>
void SetAttribute(string attribute, object? value);


/// <summary>
/// Listen to service calls
/// </summary>
/// <param name="domain">The domain of the service call</param>
/// <param name="service">The service being called</param>
/// <param name="action">The action to perform when service is called</param>
void ListenServiceCall(string domain, string service,
Func<dynamic?, Task> action);


}
Expand Down
15 changes: 1 addition & 14 deletions src/App/NetDaemon.App/Common/NetDaemonApp.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,6 @@ namespace JoySoftware.HomeAssistant.NetDaemon.Common
/// </summary>
public abstract class NetDaemonApp : NetDaemonAppBase, INetDaemonApp, INetDaemonCommon
{
private readonly List<(string, string, Func<dynamic?, Task>)> _daemonCallBacksForServiceCalls
= new List<(string, string, Func<dynamic?, Task>)>();

private readonly IList<(string pattern, Func<string, dynamic, Task> action)> _eventCallbacks =
new List<(string pattern, Func<string, dynamic, Task> action)>();

Expand All @@ -25,11 +22,6 @@ public abstract class NetDaemonApp : NetDaemonAppBase, INetDaemonApp, INetDaemon
private readonly ConcurrentDictionary<string, (string pattern, Func<string, EntityState?, EntityState?, Task> action)> _stateCallbacks =
new ConcurrentDictionary<string, (string pattern, Func<string, EntityState?, EntityState?, Task> action)>();

/// <summary>
/// All actions being performed for service call events
/// </summary>
public List<(string, string, Func<dynamic?, Task>)> DaemonCallBacksForServiceCalls => _daemonCallBacksForServiceCalls;

/// <summary>
/// All actions being performed for named events
/// </summary>
Expand Down Expand Up @@ -171,8 +163,7 @@ public async override ValueTask DisposeAsync()
_stateCallbacks.Clear();
_eventCallbacks.Clear();
_eventFunctionSelectorCallbacks.Clear();
_daemonCallBacksForServiceCalls.Clear();


await base.DisposeAsync().ConfigureAwait(false);
}

Expand Down Expand Up @@ -243,10 +234,6 @@ public IFluentInputSelect InputSelects(Func<IEntityProperties, bool> func)
/// <inheritdoc/>
public void ListenEvent(Func<FluentEventProperty, bool> funcSelector, Func<string, dynamic, Task> func) => _eventFunctionSelectorCallbacks.Add((funcSelector, func));

/// <inheritdoc/>
public void ListenServiceCall(string domain, string service, Func<dynamic?, Task> action)
=> _daemonCallBacksForServiceCalls.Add((domain.ToLowerInvariant(), service.ToLowerInvariant(), action));

/// <inheritdoc/>
public string? ListenState(string pattern,
Func<string, EntityState?, EntityState?, Task> action)
Expand Down
17 changes: 17 additions & 0 deletions src/App/NetDaemon.App/Common/NetDaemonAppBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,17 @@ public abstract class NetDaemonAppBase : INetDaemonAppBase
protected INetDaemon? _daemon;
private Task? _manageRuntimeInformationUpdatesTask;

/// <summary>
/// Registered callbacks for service calls
/// </summary>
private readonly List<(string, string, Func<dynamic?, Task>)> _daemonCallBacksForServiceCalls
= new List<(string, string, Func<dynamic?, Task>)>();

/// <summary>
/// All actions being performed for service call events
/// </summary>
public List<(string, string, Func<dynamic?, Task>)> DaemonCallBacksForServiceCalls => _daemonCallBacksForServiceCalls;

/// <summary>
/// Next scheduled time
/// </summary>
Expand Down Expand Up @@ -204,6 +215,8 @@ public async virtual ValueTask DisposeAsync()
if (_manageRuntimeInformationUpdatesTask is object)
await _manageRuntimeInformationUpdatesTask.ConfigureAwait(false);

_daemonCallBacksForServiceCalls.Clear();

this.IsEnabled = false;
_lazyStoreStateTask = null;
_storageObject = null;
Expand All @@ -218,6 +231,10 @@ public async virtual ValueTask DisposeAsync()
return _daemon!.GetApp(appInstanceId);
}

/// <inheritdoc/>
public void ListenServiceCall(string domain, string service, Func<dynamic?, Task> action)
=> _daemonCallBacksForServiceCalls.Add((domain.ToLowerInvariant(), service.ToLowerInvariant(), action));

/// <inheritdoc/>
public void Log(string message) => Log(LogLevel.Information, message);

Expand Down
22 changes: 17 additions & 5 deletions src/Daemon/NetDaemon.Daemon/Daemon/DaemonAppExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using JoySoftware.HomeAssistant.NetDaemon.Common;
using JoySoftware.HomeAssistant.NetDaemon.Common.Reactive;
using JoySoftware.HomeAssistant.NetDaemon.Daemon.Config;
using Microsoft.Extensions.Logging;
using System;
Expand Down Expand Up @@ -26,21 +27,30 @@ public static async Task HandleAttributeInitialization(this INetDaemonAppBase ne
switch (attr)
{
case HomeAssistantServiceCallAttribute hasstServiceCallAttribute:
await HandleServiceCallAttribute(_daemon, daemonApp, method).ConfigureAwait(false);
await HandleServiceCallAttribute(_daemon, daemonApp, method, true).ConfigureAwait(false);
break;

case HomeAssistantStateChangedAttribute hassStateChangedAttribute:
HandleStateChangedAttribute(_daemon, hassStateChangedAttribute, daemonApp, method);
break;
}
}
else if (netDaemonApp is NetDaemonRxApp daemonRxApp)
{
switch (attr)
{
case HomeAssistantServiceCallAttribute hasstServiceCallAttribute:
await HandleServiceCallAttribute(_daemon, daemonRxApp, method, false).ConfigureAwait(false);
break;
}
}
}
}
}

private static (bool, string) CheckIfServiceCallSignatureIsOk(MethodInfo method)
private static (bool, string) CheckIfServiceCallSignatureIsOk(MethodInfo method, bool async)
{
if (method.ReturnType != typeof(Task))
if (async && method.ReturnType != typeof(Task))
return (false, $"{method.Name} has not correct return type, expected Task");

var parameters = method.GetParameters();
Expand Down Expand Up @@ -78,9 +88,9 @@ private static (bool, string) CheckIfStateChangedSignatureIsOk(MethodInfo method
return (true, string.Empty);
}

private static async Task HandleServiceCallAttribute(INetDaemon _daemon, NetDaemonApp netDaemonApp, MethodInfo method)
private static async Task HandleServiceCallAttribute(INetDaemon _daemon, NetDaemonAppBase netDaemonApp, MethodInfo method, bool async=true)
{
var (signatureOk, err) = CheckIfServiceCallSignatureIsOk(method);
var (signatureOk, err) = CheckIfServiceCallSignatureIsOk(method, async);
if (!signatureOk)
{
_daemon.Logger.LogWarning(err);
Expand All @@ -98,6 +108,7 @@ private static async Task HandleServiceCallAttribute(INetDaemon _daemon, NetDaem
try
{
var expObject = data as ExpandoObject;

await method.InvokeAsync(netDaemonApp, expObject!).ConfigureAwait(false);
}
catch (Exception e)
Expand All @@ -106,6 +117,7 @@ private static async Task HandleServiceCallAttribute(INetDaemon _daemon, NetDaem
}
});
}


private static void HandleStateChangedAttribute(
INetDaemon _daemon,
Expand Down
10 changes: 10 additions & 0 deletions src/Daemon/NetDaemon.Daemon/Daemon/NetDaemonHost.cs
Original file line number Diff line number Diff line change
Expand Up @@ -867,6 +867,7 @@ protected virtual async Task HandleNewEvent(HassEvent hassEvent, CancellationTok
var tasks = new List<Task>();
foreach (var app in _runningAppInstances)
{
// Call any service call registered
if (app.Value is NetDaemonApp netDaemonApp)
{
foreach (var (domain, service, func) in netDaemonApp.DaemonCallBacksForServiceCalls)
Expand All @@ -880,6 +881,15 @@ protected virtual async Task HandleNewEvent(HassEvent hassEvent, CancellationTok
}
else if (app.Value is NetDaemonRxApp netDaemonRxApp)
{
// Call any service call registered
foreach (var (domain, service, func) in netDaemonRxApp.DaemonCallBacksForServiceCalls)
{
if (domain == serviceCallData.Domain &&
service == serviceCallData.Service)
{
tasks.Add(func(serviceCallData.Data));
}
}
// Call the observable with no blocking
foreach (var observer in ((EventObservable)netDaemonRxApp.EventChangesObservable).Observers)
{
Expand Down