Community project
WiFi Button Status Monitor
Generated with AIThis project turns an ESP32 into a WiFi-connected button status monitor. A push button wired to the microcontroller broadcasts its state over a local web interface, displaying whether the button is pressed or released with real-time updates.
The guide includes a complete wiring diagram, parts list, and ready-to-use firmware with debouncing logic. Builders will get a responsive status page accessible from any device on the network, plus all assembly steps needed to get the monitor running in minutes.
Wiring diagram
Interactive · read-only
Pan and zoom to explore the wiring. Remix the project to edit it in your own workspace.
Parts list
Bill of materials| Component | Qty | Notes |
|---|---|---|
| Push ButtonMomentary, normally open | 1 | Momentary push button switch |
Assembly
3 stepsPower off the ESP32
Disconnect the ESP32 DevKit v1 from USB before placing or wiring the button.
- Tip: Use a normally-open momentary push button or the two switch terminals of a tactile button.
- ⚠ Do not connect GPIO21 to 3.3 V for this design; the firmware uses the ESP32's internal pull-up resistor.
Wire the button
Connect one button terminal to ESP32 GPIO21. Connect the opposite button terminal to an ESP32 GND pin. The button is active low: pressing it joins GPIO21 to ground.
- Tip: For a 4-leg tactile switch, the two legs on each side are internally paired; use one leg from each opposite side.
- Tip: No external resistor is required because INPUT_PULLUP is enabled in firmware.
- ⚠ Ensure the button connection is only between GPIO21 and GND.
Power and open the status page
Reconnect USB to power the ESP32. After deploying the firmware, connect a phone or computer to Wi-Fi network ESP32-Button using password pressrelease, then browse to http://192.168.4.1/.
- Tip: The page refreshes once per second and displays either Button pressed or Button released.
- ⚠ This is a local ESP32 Wi-Fi network, not your home Wi-Fi.
Pin assignments
Board wiring reference| Pin | Connection | Type |
|---|---|---|
| GPIO 21 | button_1 SIGNAL | digital |
| GND | button_1 GND | ground |
Firmware
ESP32#include <Arduino.h>
#include <WiFi.h>
#include <WebServer.h>
// Forward declarations
void handleRoot();
void handleState();
void updateButton();
constexpr int BUTTON_PIN = 21;
const char *AP_SSID = "ESP32-Button";
const char *AP_PASSWORD = "pressrelease";
WebServer server(80);
bool stablePressed = false;
bool lastRawPressed = false;
unsigned long rawChangedAt = 0;
constexpr unsigned long DEBOUNCE_MS = 30;
const char PAGE[] PROGMEM = R"HTML(
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta http-equiv="refresh" content="1">
<title>ESP32 Button</title>
<style>
body { font-family: system-ui, sans-serif; max-width: 34rem; margin: 15vh auto; padding: 1rem; text-align: center; }
.state { font-size: 2rem; font-weight: 700; padding: 1.2rem; border-radius: .6rem; }
.pressed { color: #fff; background: #167a36; }
.released { color: #2600e4ff; background: #303683ff; }
small { display: block; margin-top: 1rem; color: #555; }
</style>
</head>
<body>
<h1>ESP32 Button</h1>
<div id="state" class="state released">Loading…</div>
<small>This page refreshes once per second.</small>
<script>
fetch('/state').then(r => r.json()).then(s => {
const box = document.getElementById('state');
box.textContent = s.pressed ? 'Button pressed' : 'Button released';
box.className = 'state ' + (s.pressed ? 'pressed' : 'released');
}).catch(() => {
document.getElementById('state').textContent = 'Connection error';
});
</script>
</body>
</html>
)HTML";
void handleRoot() {
server.send_P(200, "text/html", PAGE);
}
void handleState() {
server.send(200, "application/json", stablePressed ? "{\"pressed\":true}" : "{\"pressed\":false}");
}
void updateButton() {
const bool rawPressed = digitalRead(BUTTON_PIN) == LOW;
const unsigned long now = millis();
if (rawPressed != lastRawPressed) {
lastRawPressed = rawPressed;
rawChangedAt = now;
}
if (now - rawChangedAt >= DEBOUNCE_MS && stablePressed != rawPressed) {
stablePressed = rawPressed;
}
}
void setup() {
pinMode(BUTTON_PIN, INPUT_PULLUP);
stablePressed = digitalRead(BUTTON_PIN) == LOW;
lastRawPressed = stablePressed;
rawChangedAt = millis();
WiFi.mode(WIFI_AP);
WiFi.softAP(AP_SSID, AP_PASSWORD);
server.on("/", HTTP_GET, handleRoot);
server.on("/state", HTTP_GET, handleState);
server.begin();
}
void loop() {
updateButton();
server.handleClient();
}“Deploy to device” opens this project in Schematik, where you can flash it to your board over USB.
Remix this project
Make it yours in one click
Open a full copy of this project in your own Schematik workspace — diagram, code, parts, and assembly steps included. Swap the sensor, add features, or redesign the whole thing with AI. The author's original stays untouched.