-
-
Notifications
You must be signed in to change notification settings - Fork 63
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
Experimental support Rx #118
Conversation
It's looking fairly nice and clean to me |
Thank you for taking time to comment. |
/// <inheritdoc/> | ||
public Task CallService(string domain, string service, dynamic? data = null, bool waitForResponse = false) | ||
public Task CallServiceAsync(string domain, string service, dynamic? data = null, bool waitForResponse = false) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's a little confusing to have a ...Async() method with a 'waitForResponse' argument. If the caller wants to wait, they can just call .Wait() on the returned Task, right? But there is no return code?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the old Api that I am changing the names to standard Async postfix. Most functions that are async use that postfix. I want to make the very different from the new API
/// <summary> | ||
/// Interface for Observable Events | ||
/// </summary> | ||
public interface IRxEvent : IObservable<RxEvent> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd prefer not having this empty interface, it just adds some extra indirection for anybody trying to use the API.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm there was a reason I can not remember now... I will check that out
/// <summary> | ||
/// Interface for scheduling | ||
/// </summary> | ||
public interface IRxSchedule |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These are super useful! It doesn't say what the 'long' represents though - I assume a Windows file time? Might be a little more obvious if it was IObservable but I'm not sure how useful that is - you could just do DateTime.Now.
## Proposed change The change implements the System.Reactive (Rx) style of using streams of changes for automations. ## Refactorings of where logic is put In order to make application lifecycle easier, all eventlisteners and state handlers are tied to each app-instance. This makes it way more easy to disable individual apps in runtime plus manage lifecykle in the Rx stuff too. ## Implement the Rx API Implement the Rx interface. This is an alternative implementation to @jvert suggestions (thanks alot for this great idéa). This proposal was so different it was easier to implement it in own PR rather than change yours.. Hope that is ok :). New BaseClass `NetDaemonRxApp` that will implement the Rx style. We do not want to mix with old style. This is event based and not Async/await. All calls post a message on a Channel and async code takes care of the async stuff. Tests will be added. after feedback. More API features will be added before merge. Example of usage: ```c# // Observable that get state changes StateChanges.Subscribe(t=> Log(t.New.State)); // Observable that get all state changes inkluding attributes StateAllChanges.Subscribe(t=> Log(t.New.State)); // IEnumerable<EntityState> var allLights = States.Select(n => n.EntityId.StartsWith("light.")); // Gets single state var state = State("light.my_light")?.State; // No async, handled in background CallService("light", "turn_on", new {entity_id = "light.my_light"}); // Entity now not fluent // Action on single entity Entity("light.my_light").TurnOn(); Entity("light.my_light").Toggle(); // Action on multiple entities Entities("light.my_light", "light.my_light").Toggle(); // Or lambda Entities(n => n.EntityId.StartsWith("light.").Toggle(); // Merging observables <3 Entities( "binary_sensor.tomas_rum_pir", "binary_sensor.vardagsrum_pir") .StateChanges .Subscribe(e => { Log("{entity}: {state}({oldstate}, {lastchanged})", e.New.EntityId, e.New.State, e.Old.State, e.New.LastChanged); }); // Merging observables all changes including attributes <3 Entities( "binary_sensor.tomas_rum_pir", "binary_sensor.vardagsrum_pir") .StateAllChanges .Subscribe(e => { Log("{entity}: {state}({oldstate}, {lastchanged})", e.New.EntityId, e.New.State, e.Old.State, e.New.LastChanged); }); // Set state SetState("sensor.thesensor", "on", new {attributex="cool"}); // Set state selecting with Entity Selector Entity("sensor.x", "sensor.y").SetState("on"); // Merging of entity results // Schedulers RunEvery(TimeSpan.FromMinutes(1)).Subscribe(....); RunDaily("12:00:00").Subscribe(...); // Events EventChanges .Subscribe(f => { Log("event: {domain}.{event} - {data}", f?.Domain??"none", f.Event, f?.Data); }); ```
Proposed change
** I know this is way too big PR to be a good one... **
Refactorings of where logic is put
In order to make application lifecycle easier, all eventlisteners and state handlers are tied to each app-instance. This makes it way more easy to disable individual apps in runtime plus manage lifecykle in the Rx stuff too.
Implement the Rx API
Implement the Rx interface. This is an alternative implementation to @jvert suggestions (thanks alot for this great idéa). This proposal was so different it was easier to implement it in own PR rather than change yours.. Hope that is ok :).
New BaseClass
NetDaemonRxApp
that will implement the Rx style. We do not want to mix with old style. This is event based and not Async/await. All calls post a message on a Channel and async code takes care of the async stuff.Tests will be added. after feedback.
More API features will be added before merge.
Example of usage:
Type of change
Additional information
Checklist
If user exposed functionality or configuration variables are added/changed: