dotnet-state-machine / stateless

A simple library for creating state machines in C# code
Other
5.51k stars 760 forks source link

Hierachical state machine? #180

Closed davidwallis closed 6 years ago

davidwallis commented 7 years ago

(also posted on SO)

I'm wondering if stateless will do what I am after.

I am thinking about a statemachine for home automation with some logic similar to this:

var stateMachine = new StateMachine<State, Trigger>(State.UnOccupied);
        stateMachine.Configure(State.UnOccupied)
            .Permit(Trigger.SensorActivity, State.Occupied)
            .Ignore(Trigger.AlarmFullSet);

        stateMachine.Configure(State.Occupied)
            .Permit(Trigger.AlarmFullSet, State.UnOccupied)
            .Permit(Trigger.AlarmPartSet, State.Asleep)
            .PermitReentry(Trigger.SensorActivity);

        stateMachine.Configure(State.Asleep)
            .SubstateOf(State.Occupied)
            .Permit(Trigger.AlarmUnset, State.Occupied);

However I want to represent the state of rooms within a house and also the overall state of the house..

IE

Home

    House Object
                        Upstairs
                                        Bedroom 1
                                        Bedroom 2
                        Downstairs
                                        Kitchen
                                        Living Room

    Garden
                        Front
                        Back
                        Side                       

So if Living room is occupied then so is the downstairs and the house and the home..

Apologies in advance my C# isn't the best and I am throwing myself in at the deep end!

Also is it possible to do timed leaving of states.. so a sensor could trigger a room to be occupied, then more activity triggers ‘reentrant?’ (Restarts a counter / timer / adjusts a schedule) on an occupied state entry – then after 15mins of no more entry/activity events, occupancy clears on that area and the state transitions to unoccupied for that area.

HenningNT commented 7 years ago

Yes, I would think that is possible to archive with stateless. I would model each room as an Room object, which has a set of trigger and states. The Room object can have one or more timers to take care of scheduled triggers, which would Fire the trigger when the timer expires. Some rooms might be special, so those can be modelled as specialized classes that inherit from the Room class. Maybe even create Floor and House objects, if that makes sense. Then you could do house.SetVacationMode().

Stateless has a an StateChanged event, which you can use to let each room know about the state of the other rooms. I suspect that you'll need a manager object that interfaces with the UI, and a UI / Control object as well. These could also have a state machine.

davidwallis commented 7 years ago

knocked up a quick sample here https://github.com/davidwallis3101/StatelessTest

would I be best implementing a statemachine in the Area class?

Not sure how best to be able to cancel a timer as this way isnt ideal..

Thanks

David

HenningNT commented 7 years ago

I suggest creating your own timer interface, if you want to have unit tests for this. Then you can make a "fake" timer where you can trigger the timer elapsed event manually. Just set up the object with a timer interface, and you can re-arm the timer in the OnEntry method if the room becomes occupied again before the timer expires. BTW 👍 for using Rx. I would use draw.io to draw some models of what each room/area should do, i.e. model the behaviour you want. Each room/area would have its own state, so each would need their own state machine. It might be worth considering how they interact, if at all. For instance the lights could come on ion the hallway, when someone is moving around in the next room.

davidwallis commented 7 years ago

Ok I have had a play with it and come up with this..

At the moment I have switched back from using rx for the timer as I wasnt sure how to achieve the same with RX..

The behaviour as such I dont want hard coding into this as I want to be able to use it as part of a homeautomation program that allows scripting via c# - so I actually want the user to be able to configure the states etc :) rather than hard coding it for my needs and having my own fork of Homegenie

see https://github.com/davidwallis3101/StatelessTest

Anyway my next question is can I programatically determine if a state is a substate of another from within OnTransitionedAction ?

Ie Determine that Asleep is a substate of occupied?

Also am I going about this the correct way or fundamentally mising anything?

Thanks

David

davidwallis commented 7 years ago

think I was going about that wrong, I've moved away from using the transition action and just put the code in the OnEntry() method

HenningNT commented 7 years ago

Thanks for sharing this, it's always interesting to see how other people solve problems.

Why would you want to know if Asleep is a substate of occupied? If you design the state machine, you already know the answer?