Please critique my finite state machine

Would appreciate comments on my first attempt at a FSM (for an alarm system).

Inputs:

  1. motion detector sends “on” and, after x sec of inactivity, it sends “off”
  2. keyfob remote sends “on” (for testing), “off,” or “long off” (to disable alarm for y minutes)
  3. reed switch triggers “long off”

States:
A. Off
B. Wait
C. On
D. Long wait

Timers:

  1. Delay w sec after first “on” before turning alarm on (timer 1)
  2. Alarm stays on for z minutes after last “on” (timer 2)
  3. Disable alarm for y minutes after receiving “long off” (timer 3)

Pseudo-code in “loop()”:

Case state=A
If “on” received then start timer 1 and set state=B
If “long off” rec’d then start timer 3 and set state=D
Case state=B
If “off” rec’d…
If “long off” rec’d…
If timer1 expires…
Etc.

Diagram:
FSM01.JPG

Make sure each state can handle each of the inputs (events): ON, OFF, LONG_OFF. I don't see all those events being handled in state D, LONG_WAIT.

You may also need to identify when timers are turned off... I only see starting timers and handling the EXPIRED timer event.

Do any other transitions (arrows) affect the alarm state?

Cheers,
/dev

Thanks for the feedback...

/dev:
Make sure each state can handle each of the inputs (events): ON, OFF, LONG_OFF. I don't see all those events being handled in state D, LONG_WAIT.

Hmmm. Good point. I should have shown that while in state D, I "do nothing" upon receiving "on" and "off" inputs.

/dev:
You may also need to identify when timers are turned off... I only see starting timers and handling the EXPIRED timer event.

The way I was thinking of implementing the "timers," I won't explicitly turn one off: for example, "timer1" would be set while in/leaving state A with "unsigned long timer1 = millis()" and then the third "if" statement in case state=B would be "if (millis()-timer1 > duration w) {start timer2, turn on alarm, and set state=C}."

/dev:
Do any other transitions (arrows) affect the alarm state?

No, I think I've got all of them covered (except I didn't show the "on" and "off" arrows for state D, as you noted).

Your diagram looks good to me :slight_smile:

How do you implement the timers? A single timer should be sufficient, with varying expiration intervals. The current state tells when it expires (interval), and what to do then. I.e. the tests in states B, C, D have their own (fixed) expiration intervals. For descriptive purposes the reference to 3 distinct timers is okay.

Thanks!

Yes, I was using the term "timer" loosely. Actually, the timers will be just implemented similar to what you mentioned. For example, "timer1" would be set while in/leaving state A by setting "unsigned long timer1 = millis()" and then the third "if" statement in case state=B would be "if (millis()-timer1 > duration w) {start timer2, turn on alarm, and set state=C}." And each "timer" would have its own duration.

I, personally, would leave out the 'do nothing' transitions. If an input signal doesn't change anything I see no problem in leaving it out of the transition diagram. This makes the diagram somewhat simpler.

Diagrams with do-nothing transitions look more complete to me, indicating that the stimulus has been considered.

I also tend to add "else" comments to "if" statements, to make clear why nothing has to be done for a false condition.