ESP32 MicroPython Button Module
This tutorial instructs you how to use the button module with the ESP32 and MicroPython, step by step in Thonny. In detail, we will learn:
Why the button module is easier to use than a bare push button, and why its VCC pin must go to 3.3V on the ESP32.
How to wire the VCC, OUT and GND pins of the button module to the ESP32.
How to write MicroPython code that prints the level of the OUT pin, so you can see 1 and 0 in the Shell.
How to catch each press and each release, using a short pause to filter out contact bounce.
How to let the DIYables-MicroPython-Button library do the debouncing for you, without pausing the loop.
Or you can buy the following kits:
Disclosure: Some of the links provided in this section are Amazon affiliate links. We may receive a commission for any purchases made through these links at no additional cost to you.
Additionally, some of these links are for products from our own brand,
DIYables .
Think of the button module as a push button that brings its own resistor. The tactile switch, its colored cap and a pull-down resistor all sit on one small board, so the ESP32 always reads a clean 0 when nobody touches it and a 1 while a finger holds it down. One thing every switch still does: the metal contacts bounce for a few milliseconds when they close or open. To the ESP32, one press can look like two or three quick presses, which is why this tutorial shows two ways to clean that up. The modules come in a pack of five cap colors: red, yellow, green, blue and white.
| Button Module |
| Switch type | momentary tactile push button with colored cap |
| Operating voltage | 3.3V to 5V DC |
| Onboard parts | pull-down resistor on the OUT line |
| Output when released | LOW (0) |
| Output when pressed | HIGH (1), equal to the VCC voltage |
| Header | 3 pins, 2.54mm, labeled VCC, OUT, GND |
image source: diyables.io
The header has three pins, labeled in this order:
VCC pin: connect to the 3.3 volts pin of the ESP32. Do not use the VIN or 5V pin (see the warning below).
OUT pin: connect to a GPIO pin of the ESP32. It reads 0 when the button is up and 1 when the button is down.
GND pin: connect to GND (0 volts) of the ESP32.
※ NOTE THAT:
When you press the button, the OUT pin passes the VCC voltage straight to the ESP32 pin. The ESP32 GPIO pins are made for 3.3 volts only. If VCC is on VIN or 5V, every press pushes 5 volts into GPIO21, and that can damage the ESP32. Always power the module from 3.3V.
How is this different from a bare 4-leg push button? With the bare button, you must find out which legs are joined inside and add a pull-up or pull-down resistor (or turn on Pin.PULL_UP, which flips the logic so pressed reads 0). The module has labeled pins and its own pull-down, so pressed simply reads 1. For the same reason, do not turn on Pin.PULL_UP for this module: it would pull against the resistor on the board.
Three jumper wires are enough. The OUT pin goes to GPIO21, the same pin the other ESP32 MicroPython button tutorials on this site use.

This image is created using Fritzing. Click to enlarge image
| Button Module Pin | ESP32 Pin |
| VCC | 3.3V (never VIN or 5V) |
| OUT | GPIO21 |
| GND | GND |
Let's start with the simplest check: does the ESP32 see the button at all? This script sets GPIO21 as a plain input with Pin(21, Pin.IN). No pull resistor is turned on, because the module already has one. Five times per second, the script reads the pin with value() and prints the number together with a word, so a 1 shows as "pressed" and a 0 as "released".
from machine import Pin
import time
BUTTON_MODULE_PIN = 21
button_module = Pin(BUTTON_MODULE_PIN, Pin.IN)
while True:
level = button_module.value()
if level == 1:
print("OUT pin:", level, "-> pressed")
else:
print("OUT pin:", level, "-> released")
time.sleep_ms(200)
Here's instructions on how to set up and run your MicroPython code on the ESP32 using Thonny IDE:
Check that Thonny IDE is on your computer and that your ESP32 already runs MicroPython firmware.
Wire the button module to the ESP32 like the diagram above. Double-check that VCC goes to 3.3V.
Plug the ESP32 into your computer with the USB cable, then start Thonny.
Open Tools Options, go to the Interpreter tab and pick MicroPython (ESP32).
Pick the port if Thonny does not find it by itself (for example COM7 on Windows or /dev/ttyUSB0 on Linux).
Paste the code above into a new editor tab in Thonny.
Store it on the board:
Press Ctrl+S or click the Save button.
Select MicroPython device when Thonny asks where to save.
Enter main.py as the file name.
Press F5 or click the green Run button.
Leave the button alone for a second, hold it down for about one second, then let go.
The Shell at the bottom of Thonny shows the change:
>>> %Run -c $EDITOR_CONTENT
MPY: soft reboot
MPY: soft reboot
OUT pin: 0 -> released
OUT pin: 0 -> released
OUT pin: 0 -> released
OUT pin: 1 -> pressed
OUT pin: 1 -> pressed
OUT pin: 1 -> pressed
OUT pin: 1 -> pressed
OUT pin: 0 -> released
OUT pin: 0 -> released
MicroPython (ESP32) • CP2102 USB To UART Bridge Controller @ COM12 ≡
If you name your script main.py and save it to the MicroPython device, it will run automatically every time the ESP32 is powered on.
If the Shell shows 1 while you are not pressing, or the numbers jump around, look at the GND wire and the OUT wire first. A loose GND is the usual cause.
A level that stays at 1 is useful for "hold to run" jobs, but most projects want to know the moment something happens: a doorbell rings once per press, a game counts each tap. This script keeps the last level in last_level. When a new reading is different, it does not trust it right away. It sleeps 50 ms with time.sleep_ms(50), reads GPIO21 again, and only reports the change if it is still there. That second look hides the contact bounce. The cost is that sleep_ms() blocks: for those 50 ms, the loop cannot do anything else.
from machine import Pin
import time
BUTTON_MODULE_PIN = 21
SETTLE_TIME_MS = 50
button_module = Pin(BUTTON_MODULE_PIN, Pin.IN)
last_level = button_module.value()
while True:
level = button_module.value()
if level != last_level:
time.sleep_ms(SETTLE_TIME_MS)
level = button_module.value()
if level != last_level:
if level == 1:
print("The button is pressed")
else:
print("The button is released")
last_level = level
Keep the same wiring.
Click the red Stop button in Thonny to end the first script.
Replace the code in the editor with the code above.
Save it again to the MicroPython device as main.py.
Press F5 to run it.
Tap the button three times, quickly and then slowly.
Each tap gives exactly two lines in the Shell:
>>> %Run -c $EDITOR_CONTENT
MPY: soft reboot
MPY: soft reboot
The button is pressed
The button is released
The button is pressed
The button is released
The button is pressed
The button is released
MicroPython (ESP32) • CP2102 USB To UART Bridge Controller @ COM12 ≡
Do you still see a double "pressed" now and then? Your button bounces longer than usual. Raise SETTLE_TIME_MS to 80 or 100.
The pause in the last script is fine for a small test. In a real project, the ESP32 often has other work in the same loop, such as reading a sensor or updating a display, and a blocked loop makes that work late. The DIYables-MicroPython-Button library solves this. It records the time of each change and only accepts a new level after it has stayed the same for the debounce time, so button.loop() returns at once and never sleeps.
The code creates the button with Button(21, Pin.PULL_DOWN). The Pin.PULL_DOWN mode tells the library that 1 means pressed, which matches the resistor on the module. After button.set_debounce_time(50), every pass of the while loop calls button.loop() first. Then:
button.is_pressed() is True once, right after a press.
button.is_released() is True once, right after a release.
button.get_state() gives the steady, debounced level (1 or 0).
from DIYables_MicroPython_Button import Button
from machine import Pin
BUTTON_MODULE_PIN = 21
button = Button(BUTTON_MODULE_PIN, Pin.PULL_DOWN)
button.set_debounce_time(50)
last_state = button.get_state()
while True:
button.loop()
if button.is_pressed():
print("The button is pressed")
if button.is_released():
print("The button is released")
state = button.get_state()
if state != last_state:
print("Steady state is now:", state)
last_state = state
In Thonny, open Tools Manage packages.
Type DIYables-MicroPython-Button in the search box and search.
Click DIYables-MicroPython-Button by DIYables in the results, then click the Install button.
Close the package window, then put the library code above into Thonny's editor.
Save it to the MicroPython device as main.py.
Press F5 to run it.
Press the button once and hold it a moment, then press it once more.
The Shell shows each event and the new steady level:
>>> %Run -c $EDITOR_CONTENT
MPY: soft reboot
MPY: soft reboot
The button is pressed
Steady state is now: 1
The button is released
Steady state is now: 0
The button is pressed
Steady state is now: 1
The button is released
Steady state is now: 0
MicroPython (ESP32) • CP2102 USB To UART Bridge Controller @ COM12 ≡
Want to see more ways to use this library, like several buttons at once? Read the ESP32 MicroPython Button Debounce tutorial. To make the module switch a light, see the ESP32 MicroPython Button LED tutorial. Just remember to use Pin.PULL_DOWN (or Pin.IN with no pull) for the module, since those pages use bare buttons with a pull-up.
A button module on the ESP32 makes a good input for:
A WiFi doorbell that sends a message to your phone each time the button is pressed.
A mode button that steps through display pages or LED colors, one step per press.
A start/stop button for a timer or a data logger.
A small game pad: give each player a button module in a different color and see who presses first.