A flashlight finite state machine
January 24, 2026
I’ve muddled around with this off and on for years,
without really finishing it; but my friend Robert started playing with an AI formal requirements tool, and I needed a test case.
Imagine we have a flashlight. It has a simple on-off button, that latches in the on position but can be momentarily pressed. This allows the user to do all sorts of things, such as set modes, check battery level, etc.
I have a couple of flashlights that work more or less like this. However, they tend to have rather inscrutable modes of operation, and the documentation is at best unclear.
Shouldn’t there be a better way to use the flashlight? Or, at the very least, a straightforward diagram that shows how it works?
The diagram and associated requirements list below, illustrate how complicated even a “simple” flashlight can be!
This is all very notional, and just a test case anyway, so don’t expect accuracy or completeness at this point. I’m dropping it in here to the blog mostly so I can find it later. I might update progress if anything changes or improves.
stateDiagram
direction TB
[*] --> On:button latched
state On {
state Light {
[*] --> State1
State1 --> State2:button short press
State2 --> State3:button short press
State3 --> State1:button short press
State1 --> setS1Brightness:button long press
setS1Brightness --> State1
State2 --> setS2Brightness:button long press
setS2Brightness --> State2
State3 --> setS3Brightness:button long press
setS3Brightness --> State3
}
--
Strobe --> [*]:button press
state Strobe {
[*] --> SetMaxBrightness:three button presses
SetMaxBrightness --> SetMinBrightness
SetMinBrightness --> SetMaxBrightness
}
--
state BSoC {
[*] --> GetBSoC:two button presses
GetBSoC --> Flash:n += 1
Flash --> n=bsoc?
state ifState <<choice>>
n=bsoc? --> ifState
ifState --> True:n == bsoc
ifState --> False:n < bsoc
False --> Flash
True --> [*]
}
--
state Bmon {
state "GetBSoC" as GetBSoC2
[*] --> GetBSoC2
GetBSoC2 --> bsoc<=1?
state blev <<choice>>
bsoc<=1? --> blev
state "True" as T
state "False" as F
blev --> T : bsoc <= 1
blev --> F : bsoc > 1
T --> setBrightnessMin
setBrightnessMin --> blink3times
blink3times --> [*]
}
--
state BtnCheck {
[*] --> getBtnState
getBtnState --> debounce
debounce --> isPressed?
state pState <<choice>>
isPressed? --> pState
state "True" as T2
state "False" as F2
pState --> T2 : pressed
pState --> F2 : not pressed
T2 --> timer
timer --> getBtnState
timer --> longPress
timer --> shortPress
longPress --> [*]
shortPress --> [*]
}
}
On --> [*]:button unlatched
sequenceDiagram
actor User
participant On
box Aqua Flashlight On
participant Strobe
participant BSoc
participant Bmon
participant BtnCheck
end
box Orange Light Modes
participant State1
participant State2
participant State3
end
participant Off
User->>On : switch on
On->>State1 :
User->>BtnCheck : short press
BtnCheck ->> State1 : shortPress = true
User->>BtnCheck : short press
BtnCheck->>State2 : shortPress = true
User->>BtnCheck : short press
User->>BtnCheck : short press
User->>BtnCheck : short press
BtnCheck->>Strobe : 3xShortPress = true
User->>BtnCheck : short press
BtnCheck->>Strobe : shortPress = true
Strobe->>State2 :
User->>"Off" : switch off
Requirements:
- REQ-001: The flashlight shall have a button that latches on.
- REQ-002: The flashlight shall have a button that can be momentarily pressed, when in the latched state.
- REQ-003: Latching the button shall cause the flashlight to enter the “On” state.
- REQ-004: Unlatching the button shall cause the flashlight to exit the “On” state.
- REQ-005: In the “On” state, the flashlight shall have five concurrent processes: “Light”, “Strobe”, Battery State of Charge (“BSoC”), Battery Monitoring (“Bmon”), and Button Check (“BCheck”).
- REQ-006: The “Light” process shall sequence between three states (“State1”, “State2”, and “State3”) on a short press of the button.
- REQ-007: In each of the three Light states, a long button press shall, while the button is held, and if the BSoC is > 10%, increment the brightness until it reaches the maximum value, at which point the brightness will be decremented until it reaches the minimum value. Releasing the button will cause the brightness value to be stored for that Light state.
- REQ-008: Two short button presses shall activate the BSoC process.
- REQ-009: The BSoC process shall flash the light corresponding to the current battery state of charge, from 1 (10%) to 10 (100%).
- REQ-010: Three short button presses shall activate the Strobe process.
- REQ-011: The Strobe process shall alternate the light between full brightness and minimum brightness until the button is pressed again.
- REQ-012: The Bmon process shall continuously check the battery state of charge, and if the charge level is below 10%, set the brightness for all output states to the minimum.
- REQ-013: When the Bmon process sets the minimum brightness, it shall flash the light 3 times.
- REQ-014: The Button Check (“BCheck”) process shall get the current button state (pressed or not pressed), de-bounce the state, and determine if the button is pressed for a short (<= 1 sec) or long (> 1 sec) period. The process shall set longPress or shortPress to True when the condition is met, and False otherwise.