I'll have a real world problem that I try to solve which involves the implementation of a FSM. But I fail to get it right.
My problem: I want to integrate my garage door into my smart home. As it is an apartment block, I cannot tamper with the electronics and my only chance is to send the opening signal via RF. I already got a simple PoC working. The only problem is that I can only ever open the garage door via RF. I cannot get any state. It will auto close after some time. Now I want to add the opening/open/closing times, so that the state of my FSM roughly matches the actual state of the garage door.
The door has four states:
- Closed
- Opening
- Open
- Closing
Opening takes 14.5s, it stays open for 40s and closing takes 14s. Now implementing this isn't the hard part (some pseudo code):
loop {
if current_state.val == target_state.val then return;
if target_state.val == GARAGE_DOOR_STATE_OPEN AND target_state.updated_ago > GARAGE_DOOR_OPENING_DUR then current_state.val = target_state.val;
// Somewhat similar for the other states ...
}
But let's say someone decides to close the door via the smart home integration (which doesn't do anything as there is no RF signal for that), how do I still match the state in my FSM and the actual door? So let's say right after opening, close is initiated but the real door will actually stay open for another 40s, before being auto-closed. This means the state machine must actually stay in the closing state, for 40s + 14s (staying open + closing). The same is true when initiating a state change in the middle of an opening state (e.g. closing while the door is opening): This means I need to add the remaining time it takes the door to open to the 40s + 14s of the two follow-up states.
Any idea how to express/implement that in a nice way?
You could use a basic
enum
and aswitch
statement and a variable to keep track of the current state (calling one function at a time based on the state, each updating / transitioning to the next stage based on your required logic).Here's a really rough example:
Note the above isn't complete, nor tested. It's more an illustration of handling one state at a time, using
switch
andmillis()
to trigger a different state after a set duration.It might be worth trying to illustrate your state machine described above with a diagram for easier understanding / communication.
It may take some iteration/experimentation to get the logic and timings right. You may want to use
Serial
to debug and ensure everything works as intended before plugging hardware to control the physical garage door.