
ESP32-S3 board
The brain that runs your uploaded sketch.
TinySkiff ESP32-S3 Lab · Day 5 of 30
Yesterday the LED only glowed while you held the button. Today it stays. With a little memory and a trick called debounce, one press latches the light on and the next press turns it off — the leap from a raw button to a product.
TSK-DAY05-LAMP
Hand this to an agent so it can pull the lesson packet and coach you step by step.
01 First, know the pieces
Nothing new to buy — this is the exact circuit you built on Day 4. If it's still wired up, you only need to upload a new sketch. Tap Define on anything you'd like refreshed.

The brain that runs your uploaded sketch.

Spreads the pins into rows you can reach and label.

The lamp — same LED, same one-way rule as Day 4.

Still in series with the LED, keeping the current gentle.

Hold the button's pin steady between presses.

The same switch — now it toggles instead of holds.

Temporary, solder-free connections.

Uploads the new lamp sketch to the board.
02 Make the physical circuit
This is the Day 4 circuit, unchanged — the same chart, so the same chart applies. Click it to enlarge, or skip straight to the sketch if your circuit is still assembled.
Same circuit, same care. Nothing moves on the breadboard today. If you do rewire, keep the LED's long leg toward GPIO 2 through the 220 Ω resistor, and unplug USB first.
03 One action at a time
Mostly upload-and-watch — the wiring is yesterday's. Tap each step as you go to keep your place.
Confirm the Day 4 circuit is still wired, or rebuild it from the chart.
Keep USB unplugged until every wire matches the chart.
Open Sketch_02.2_TableLamp.ino in Arduino IDE.
Upload it to the ESP32-S3.
Press the button once and let go — the LED should latch on.
Press once more — it should turn off.
04 Read just enough code
The circuit is the same; the loop is what changed. It now remembers the LED's state, waits out the switch's chatter, and flips only on a clean press. Switch to MicroPython to see the same idea in Python.
void loop() {
if (digitalRead(PIN_BUTTON) == LOW) {
delay(20); // wait out the chatter
if (digitalRead(PIN_BUTTON) == LOW) {
reverseGPIO(PIN_LED); // clean press -> flip the LED
}
while (digitalRead(PIN_BUTTON) == LOW); // hold here until release
}
}
void reverseGPIO(int pin) {
digitalWrite(pin, !digitalRead(pin));
}
delay(20)The debounce pause — long enough for the switch's chatter to settle. reverseGPIO(PIN_LED)Flips the LED to the opposite of whatever it is now — on becomes off, off becomes on. while (digitalRead(PIN_BUTTON) == LOW);Waits right here until you let go, so one press can't count twice. Optional side path · same circuit
def reverseGPIO():
led.value(0 if led.value() else 1)
if not button.value():
time.sleep_ms(20)
if not button.value():
reverseGPIO()
while not button.value():
time.sleep_ms(20)
time.sleep_ms(20)The same 20 ms debounce pause, written in Python.while not button.value()Holds until you release, so the press registers once.Same pins, same wiring, same behaviour. Run it in Thonny if MicroPython is set up; otherwise skip it — it should never block the Arduino-first path.
05 Understand, don't memorise
Two small ideas turn a button into a lamp: the code remembers the light's state, and it refuses to trust a press until the switch has stopped bouncing.
The loop sees GPIO 13 go LOW and pauses briefly.
If it is still LOW after the pause the press was real.
reverseGPIO sets the LED to the opposite of what it was.
The code holds until you let go so one press counts once.
one clean press → flip the remembered state → the lamp stays
A switch chatters for a few milliseconds as it closes. Without the pause the board would toggle many times per press.
Instead of following the button live, the code keeps a state and inverts it — that memory is the whole difference from Day 4.
06 Know it worked
Nothing prints today — the proof is whether the lamp stays without your finger.
If a single press sometimes flips twice, the debounce pause is doing its job when it's present — and failing when it's removed.
07 Make the idea yours
Same working lamp, one deliberate change to its behaviour. Pick one and note what changed — it fits inside today's 30 minutes.
Try delay(5) and then delay(80). Find where presses feel crisp without ever double-flipping.
In one sentence, describe how this lamp should feel to use — then judge whether your timing delivers it.
Logbook
08 Learn it with a hand on the tiller
Every lesson ships with a code and a machine-readable packet, so an agent can guide you with full context.
TSK-DAY05-LAMP
How the agent should behave: keep it to upload-and-watch on the existing circuit, explain debounce and toggle on request, and check wiring, board, port, and USB before changing code.