Sequential Logic Blocks - compared to the Reactive Framework
One of the features of my home automation system is extensions to the C# language that make it easy to define complex logical and temporal behaviors. These behave somewhat like the new Reactive Extensions in .NET but with some key differences which I will explain below. I developed these extensions before Reactive Framework was released and have recently been looking at Rx to see if I could combine my ideas with Rx but because of the differences explained below I haven't been able to do that.
But, before explaining why, let's first look at an example:-
FirstFloor.Kitchen.GoesOff.Provided((dt) => Entrance.VisitorCountThisEvening.Count < 2).TurnOff(Aquarium.Light);
This means that if the kitchen goes not occupied (off) provided we have less than two visitors this evening, then turn off the aquarium lights.
Here's a more complex example where we create an intermediate logic element called 'activityInKitchen' using the .Or method, and then based on that activity we decide whether to announce that the fish have not been fed. The decision uses a combination of pulse stretching, repeats (Every) and Then which fires only if a particular sequence is followed within a given time window. Finally it uses the Do method which fires off an Action.
SensorDevice activityInKitchen = Kitchen.KitchenFloor.Or(Kitchen.MotionSensor, Kitchen.BackDoorToGarage, Kitchen.BreakfastBarFloor, Kitchen.Phone);
activityInKitchen
.ProvidedNot(Home.DinnerGuests) .PulseStretch(16 * 60) // Make it continuous
.Every(60 \* 60) // Once every 1 hour
.Then(activityInKitchen, 15*60)
.Do("Announce fish are hungry",(sender) => { Kitchen.Aquarium.AnnounceFishHungry(Kitchen.MediaZone); });
As you can see the use of a fluent syntax allows for a very natural, almost english-like definition of complex temporal expressions. But that's not all it allows...
The sequential logic blocks created when you call one of the many methods like .Then, .Or, .Every, ... are actual objects created within the hierarchical structure of the house and the objects used to represent it. This means that they take part (automatically) in all of the features provided by a base house object including logging, browsing, and most importantly persistence.
Because these sequential logic blocks are persistent you can have very long running events like .EveryDays(2) and even if the entire system is shut down and restarted it will come back in the correct state and all the necessary delays and timers will still be working.
Another key benefit of these sequential logic blocks compared to, say, the .NET Reactive Framework is that they form a chain that can be traversed in either direction: forward as an event propagates through, or in reverse to determine why a particular action was taken. This means that my home automation system is able to explain why it turned the lights on or off. Currently all of these decisions are logged on the per-object logging system which means you can inspect any room, appliance, light, etc. and see everything that happened to it and the reasons why.
Hallway became occupied, caused by Motion sensor Set brightness on Aisle lights in Kitchen to 20% because Leaving office late at night
Compare this to other home automation systems from major vendors. They contain fairly simple logic, often expressed in a tabular or grid format with limited if-the-else type logic and when something happens there is often no record as to what happened and, worse, there is absolutely no record as to why it happened.
Any sufficiently complex system will have unexpected behavior, the difference here is that when it does something odd I can easily look at the logging and see the explanation as to why it happened.