Skip to content

Exercise an ESP32 device state machine

Verify normal, timeout, wrong-state, fault, and reset transitions with buttons, LEDs, and structured serial proof.

Gateway Gus: I want every button, timeout, guard, retry, and reset to leave a state transition another engineer can audit., your practice guide

Gateway Gus: I want every button, timeout, guard, retry, and reset to leave a state transition another engineer can audit.
Predict the reading, then compare it with the measurement.

Wokwi ESP32

Third party Tool

Tier 1 · Web · No account

Version tested: Compiled and booted by the Wokwi gate (ESP32 Arduino core 3.3.11); captured in the Wokwi web editor on 2026-09-10. Date: 2026-09-10.

Open the ESP32 editor, paste diagram.json, then paste sketch.ino.

Open Wokwi to paste in the files (new tab)

Get the files

Use both prepared files. This is a paste-in setup; saving a project requires a Wokwi account.

diagram.json

2,318 bytes · Circuit connections

Download

sketch.ino

2,345 bytes · ESP32 program

Download

  1. Use the launch button above to open the ESP32 editor in Wokwi.
  2. Select the editor’s diagram.json tab and replace all its text with the supplied diagram.json.
  3. Select the sketch.ino tab, replace all its text with the supplied sketch.ino, then click Start Simulation.

Steps

Screens captured against Wokwi ESP32 Compiled and booted by the Wokwi gate (ESP32 Arduino core 3.3.11); captured in the Wokwi web editor on 2026-09-10 on 2026-09-10; the tool may have moved on — the text steps are the contract.

  1. 1 Step 1

    Do
    In the Wokwi simulation panel, paste the supplied diagram and sketch into Wokwi; identify the three event buttons and four state LEDs.
    You will see
    Input: inspect the running Wokwi circuit and diagram.json. Sample, Ack, and Fault / Reset buttons use GPIO12, 13, and 14. White, yellow, green, and red LEDs represent the four states. Serial Monitor begins with STATE=IDLE retries=0; the white LED is lit.
    Why it matters
    Each event has a named physical control in the simulator. Each state has a distinct LED output. The starting serial line agrees with the white IDLE indicator. This gives later transitions an observable baseline.
    Step 1: Three event buttons and four state LEDs connect to the ESP32. The ring marks the explicit event and state boundary.
    Step 1 · Wokwi ESP32; numbered callout added to a real capture. Enlarge screenshot (new tab)
  2. 2 Step 2

    Do
    In the Wokwi simulation panel, inspect the State enum, enterState function, and wrong-state reject function.
    You will see
    Input: inspect State, enterState, and reject in sketch.ino. The enum names IDLE, SAMPLE, TRANSMIT, and FAULT. enterState prints TRANSITION with event, proof, and retries. reject prints EVENT_REJECTED with state and reason=wrong_state.
    Why it matters
    The accepted path records its prior and next states. The rejection path preserves why an event was ignored. The real run begins at STATE=IDLE retries=0. A central transition function keeps the state contract reviewable.
    Step 2: Four named states, the transition logger, and rejected-event logger are visible. The ring marks the state contract.
    Step 2 · Wokwi ESP32; numbered callout added to a real capture. Enlarge screenshot (new tab)
  3. 3 Step 3

    Do
    Start the simulation and open Serial Monitor at 115200 baud.
    You will see
    Input: start the supplied Wokwi ESP32 simulation. Observed: "ESP32 STATE MACHINE READY". Observed: "STATE=IDLE retries=0". Expected: the controller begins in IDLE with no retries.
    Why it matters
    The two lines establish the starting state. No Sample or Ack event has occurred yet. The zero count is the baseline for later timeouts. The serial line does not by itself measure LED brightness.
    Step 3: The machine starts in IDLE with retries=0. The ring marks the initial-state proof.
    Step 3 · Wokwi ESP32; numbered callout added to a real capture. Enlarge screenshot (new tab)
  4. 4 Step 4

    Do
    In the Simulation panel, press the Sample button once; watch Serial Monitor for completion.
    You will see
    Input: hold and release Sample once in Wokwi. Observed: "TRANSITION IDLE + EV_SAMPLE_REQUEST -> SAMPLE proof=sample_timer_started retries=0". Observed: "TRANSITION SAMPLE + EV_SAMPLE_READY -> TRANSMIT proof=message_id=42 retries=0". Expected: sampling completes before transmission begins.
    Why it matters
    The first event starts the sample timer. The second records readiness and message_id=42. Both transitions occurred in this live simulator run. The message identifier is a firmware fixture, not radio traffic.
    Step 4: The event trace moves IDLE to SAMPLE to TRANSMIT with message_id=42. The ring marks the normal path.
    Step 4 · Wokwi ESP32; numbered callout added to a real capture. Enlarge screenshot (new tab)
  5. 5 Step 5

    Do
    In the Simulation panel, press Ack before the transmit timeout; read Serial Monitor.
    You will see
    Input: hold and release Ack while TRANSMIT is active. Observed: "TRANSITION TRANSMIT + EV_ACK_RECEIVED -> IDLE proof=message_closed retries=0". Expected: a timely Ack closes the message. The returned state is IDLE with retries reset to 0.
    Why it matters
    The Ack is accepted only in TRANSMIT. The proof field names the closure event. The run showed no timeout before this Ack. This is internal state-machine evidence, not a network receipt.
    Step 5: The acknowledgement closes the message and returns to IDLE. The ring marks the accepted transition.
    Step 5 · Wokwi ESP32; numbered callout added to a real capture. Enlarge screenshot (new tab)
  6. 6 Step 6

    Do
    In the Simulation panel, press Sample again, leave Ack untouched, and watch three timeouts in Serial Monitor.
    You will see
    Input: press Sample again and leave Ack untouched. Observed: timeout retry lines with retries=1 and retries=2. Observed: "TRANSITION TRANSMIT + EV_TIMEOUT -> FAULT proof=ack_timeout_radio_off retries=3". Expected: the third timeout enters FAULT.
    Why it matters
    The retry count advances one step at a time. The final transition records the fault reason. The live run matched the three-count screenshot. The simulated timer does not prove a real radio switched off.
    Step 6: Two bounded retries end in FAULT with ack_timeout_radio_off. The ring marks the retry-limit proof.
    Step 6 · Wokwi ESP32; numbered callout added to a real capture. Enlarge screenshot (new tab)
  7. 7 Step 7

    Do
    In the Simulation panel, press Ack while in FAULT; read the rejection in Serial Monitor.
    You will see
    Input: press Ack after the third timeout placed the machine in FAULT. Observed: "EVENT_REJECTED state=FAULT event=EV_ACK_RECEIVED reason=wrong_state". Expected: Ack cannot close a message from FAULT. The preceding line in the run was the retries=3 FAULT transition.
    Why it matters
    The event is rejected rather than changing state. The wrong_state reason makes the guard observable. This matches the real Wokwi serial screenshot. The serial rejection does not independently verify the LED state.
    Step 7: A late acknowledgement is rejected in FAULT. The ring marks the wrong-state decision.
    Step 7 · Wokwi ESP32; numbered callout added to a real capture. Enlarge screenshot (new tab)
  8. 8 Step 8

    Do
    In the Wokwi simulation panel, press Fault / Reset once while FAULT is active.
    You will see
    Input: press the red Fault / Reset button while FAULT is active. Previous serial line: EVENT_REJECTED state=FAULT for the late Ack. New serial line: TRANSITION FAULT + EV_RESET -> IDLE. The transition records proof=manual_reset_safe and retries=0.
    Why it matters
    The manual reset is accepted from FAULT in this run. The proof field records the recovery reason. The retry count returns from three to zero. The IDLE LED is lit in the real Wokwi capture.
    Step 8: A manual safe reset returns FAULT to IDLE with retries cleared. The ring marks the recovery proof.
    Step 8 · Wokwi ESP32; numbered callout added to a real capture. Enlarge screenshot (new tab)

Chapter checks

These questions refer to the chapter’s examples. Use the return links to review their answers.

  1. A sensor alternates between SLEEP, SAMPLE, TRANSMIT, and FAULT. Why is this a good fit for a finite state machine?

    Return to the chapter’s knowledge check
  2. A TRANSMIT state retries forever after acknowledgement timeouts. Which transition-table change most directly fixes the design?

    Return to the chapter’s knowledge check
  3. A firmware design handles radio callbacks, sensor completions, button presses, and timer expirations. What is the safest state-machine pattern?

    Return to the chapter’s knowledge check

Caution

The buttons simulate events and the timer simulates sampling and acknowledgement deadlines. This lab does not prove real sensor validity, radio callbacks, interrupt safety, persistence, brownout recovery, or queue overflow behavior. Keep 220 ohm LED resistors on physical hardware and define reset authority before actuation.

Return to State Machine Fundamentals · Browse Labs