esp32 advanced 45 min

ESP32: build a Wi-Fi doorbell that pushes to your phone

Press a button, get a notification on your phone. The ESP32 + Pushover (or Telegram) + a simple button. Replaces a $50 smart doorbell.

Code available for: ESP32 Arduino
Published Aug 25, 2026

A Wi-Fi doorbell that pushes a notification to your phone when someone presses the button. Replaces a smart doorbell ($50-100) with $5 of parts.

This is the project that ties the button debounce, Wi-Fi, and HTTPS tutorials together.

What you need

  • ESP32 dev board
  • Momentary pushbutton (the four-leg tactile kind)
  • 10k ohm pull-up resistor (or use the internal pull-up; see code)
  • USB power supply (the ESP32 stays powered; no battery)

Wiring

ESP32 GPIO 4 -- button -- GND

That’s the entire wiring. The internal pull-up resistor holds GPIO 4 HIGH when the button is not pressed. When pressed, GPIO 4 goes LOW.

The push notification service

There are several options:

  • Pushover ($5 one-time per platform): the standard for home projects. Simple HTTPS API.
  • Telegram Bot API (free): send a message to a Telegram group or bot.
  • IFTTT Webhooks (free tier): trigger an applet that sends an SMS or push.
  • ntfy.sh (free, open source): self-hosted or use their public server.

For this tutorial, I’ll use Pushover because it is the simplest API and works on iOS and Android.

Setting up Pushover

  1. Sign up at https://pushover.net.
  2. Note your user key.
  3. Create an application at https://pushover.net/apps/build and note the API token.

The code

#include <WiFi.h>
#include <WiFiClientSecure.h>
#include <HTTPClient.h>

const char* ssid = "your-wifi";
const char* password = "your-password";

const char* pushoverToken = "your-api-token";
const char* pushoverUser = "your-user-key";

const int BUTTON_PIN = 4;
const unsigned long DEBOUNCE_MS = 50;

unsigned long lastPress = 0;
bool wasPressed = false;

void setup() {
  Serial.begin(115200);
  delay(1000);

  pinMode(BUTTON_PIN, INPUT_PULLUP);

  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) delay(500);
  Serial.print("Connected. IP: ");
  Serial.println(WiFi.localIP());
}

void loop() {
  bool pressed = digitalRead(BUTTON_PIN) == LOW;

  if (pressed && !wasPressed && (millis() - lastPress > DEBOUNCE_MS)) {
    lastPress = millis();
    Serial.println("Button pressed, sending notification");
    sendNotification();
  }

  wasPressed = pressed;
  delay(20);
}

void sendNotification() {
  WiFiClientSecure *client = new WiFiClientSecure();
  client->setInsecure();   // skip certificate validation (for prototyping)

  HTTPClient http;
  http.begin(*client, "https://api.pushover.net/1/messages.json");

  String payload = "token=";
  payload += pushoverToken;
  payload += "&user=";
  payload += pushoverUser;
  payload += "&title=Doorbell&message=Someone is at the door";

  http.addHeader("Content-Type", "application/x-www-form-urlencoded");
  int httpCode = http.POST(payload);

  if (httpCode == 200) {
    Serial.println("Notification sent");
  } else {
    Serial.print("Failed: ");
    Serial.println(httpCode);
  }

  http.end();
}

Upload. Press the button. Within a few seconds, you should get a notification on your phone.

The security caveats

The code uses setInsecure() for simplicity, which means the ESP32 trusts any TLS certificate. For a real doorbell, use setCACert() with the proper Pushover root certificate (see the HTTPS tutorial).

The Pushover API token and user key are in the firmware. If someone gets physical access to the ESP32, they can read them. For real projects, store them in NVS (Non-Volatile Storage) and accept that they can be extracted.

The “double-press” patterns

For more complex interactions (e.g. one button for doorbell, hold for 3 seconds for alarm), add timing:

unsigned long pressStart = 0;

void loop() {
  bool pressed = digitalRead(BUTTON_PIN) == LOW;

  if (pressed && !wasPressed) {
    pressStart = millis();
  } else if (!pressed && wasPressed) {
    unsigned long duration = millis() - pressStart;
    if (duration > 3000) {
      Serial.println("Long press: ALARM");
      sendAlert();
    } else if (duration > 50) {
      Serial.println("Short press: doorbell");
      sendNotification();
    }
  }

  wasPressed = pressed;
  delay(20);
}

Single press = doorbell. Hold for 3+ seconds = alarm.

The “always-on” challenge

The ESP32 stays powered continuously. Power consumption: about 50 mA average (mostly Wi-Fi keep-alive). At 120V mains, that is about 1 kWh per month, or $0.15.

For battery operation, use deep sleep between presses:

void sendNotification() {
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) delay(500);

  // Send notification
  sendNotificationInternal();

  WiFi.disconnect();

  // Sleep until button press
  esp_sleep_enable_ext0_wakeup(BUTTON_PIN, 0);   // wake when button pressed (LOW)
  esp_deep_sleep_start();
}

void loop() {
  // Not reached; wakes from sleep and sends notification, then sleeps again
}

Battery life on a 18650: about 6 months with one press per day.

What you learned

  • A working Wi-Fi doorbell for $5 of parts.
  • Push notifications via Pushover (or Telegram, IFTTT, ntfy.sh).
  • The “always-on” and “battery” patterns.
  • The single/double press pattern for richer interactions.

What to build next

  • The button debounce tutorial covers the input side.
  • The HTTPS tutorial covers the API call side.
  • The book ESP32 Smart Home covers multiple-input smart devices (doorbell + camera, motion + doorbell).