Blogs

ESP32 Ultrasonic Door Alert: Get a Telegram Notification When Someone’s at Your Door

Build a low-cost, practical door presence alert using an ultrasonic distance sensor, an ESP32, and Telegram. When someone stands near your door for a few seconds, you get an instant notification on your phone — no subscriptions, just hardware + logic.

Quick Summary

An HC-SR04 ultrasonic sensor continuously measures distance at your front door. An ESP32 checks whether someone is within a defined range for a set amount of time. If that condition is met, the ESP32 sends a Telegram message directly to your phone with a built-in cooldown to prevent spam.

Table of Contents

Parts List

From ShillehTek

External

  • ESP32 Dev Board (WROOM-based)
  • HC-SR04 Ultrasonic Distance Sensor
  • USB Battery Pack (5V, 2A+ recommended)
  • Mounting tape (for door install)
  • 100µF capacitors (optional but recommended for stable Wi-Fi/TLS)

Note: This project is intentionally simple and local. The only “external” dependency is Telegram for notifications.

Step 1: Wiring

This wiring powers the sensor from the ESP32’s 3.3V rail and uses GPIO18/19 for trigger/echo.

ESP32 WROOM connected to HC-SR04 ultrasonic distance sensor on a breadboard for a Telegram door alert project

HC-SR04 → ESP32

  • VCC → ESP32 3V3
  • GND → ESP32 GND
  • TRIG → ESP32 GPIO18
  • ECHO → ESP32 GPIO19

Stability tip: Place multiple 100µF capacitors in parallel from 3V3 → GND as close to the ESP32 as possible. This helps prevent resets when Telegram (HTTPS) sends.

Step 2: Create a Telegram Bot + Get Chat ID

We’re using a Telegram bot so the ESP32 can send you messages.

A) Create your bot token

  1. In Telegram, search for @BotFather.
  2. Send: /newbot
  3. Follow prompts (name + username). BotFather will give you a bot token.

B) Get your Chat ID (fast)

  1. Open Telegram and message your new bot (send any text like “hi”).
  2. In a browser, visit this URL (replace <TOKEN>):
https://api.telegram.org/bot<TOKEN>/getUpdates

Look in the response for "chat":{"id": ... }. That number is your TELEGRAM_CHAT_ID.

Tip: If you want alerts to go to a group chat, add the bot to the group, send a message in the group, then run getUpdates again to find the group chat ID.

Step 3: Detection Logic

The system uses three rules:

  • Distance threshold: Trigger when someone is within ~1 meter (THRESH_CM).
  • Hold time: Must stay below the threshold for 3 seconds (HOLD_MS).
  • Cooldown: Wait 30 seconds after an alert (COOLDOWN_MS).

This avoids false triggers and prevents spam.

Step 4: ESP32 + Telegram Code

Important: Replace the empty strings below with your Wi-Fi + Telegram info.

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

// --- Put your secrets here (keep these private) ---
// Replace the empty strings with your own Wi-Fi + Telegram credentials.
const char* WIFI_SSID = "";
const char* WIFI_PASSWORD = "";
const char* TELEGRAM_BOT_TOKEN = "";
const char* TELEGRAM_CHAT_ID = "";

// --- Pins ---
const int ECHO_PIN = 19;
const int TRIG_PIN = 18;

// --- Behavior ---
const int THRESH_CM = 100;                 // 1 meter
const unsigned long HOLD_MS = 3000;        // 3 seconds
const unsigned long COOLDOWN_MS = 30000;   // 30 seconds

unsigned long closeStartMs = 0;
unsigned long lastAlertMs = 0;

String urlEncode(const String& s) {
  String out;
  const char *hex = "0123456789ABCDEF";
  for (size_t i = 0; i < s.length(); i++) {
    char c = s[i];
    if (isalnum((unsigned char)c) || c == '-' || c == '_' || c == '.' || c == '~') out += c;
    else if (c == ' ') out += "%20";
    else {
      out += '%';
      out += hex[(c >> 4) & 0xF];
      out += hex[c & 0xF];
    }
  }
  return out;
}

bool sendTelegram(const String& msg) {
  WiFiClientSecure client;
  client.setInsecure(); // demo: skip cert validation

  String url = "/bot" + String(TELEGRAM_BOT_TOKEN)
             + "/sendMessage?chat_id=" + String(TELEGRAM_CHAT_ID)
             + "&text=" + urlEncode(msg);

  if (!client.connect("api.telegram.org", 443)) {
    Serial.println("Telegram connect failed");
    return false;
  }

  client.print(String("GET ") + url + " HTTP/1.1\r\n"
             + "Host: api.telegram.org\r\n"
             + "Connection: close\r\n\r\n");

  while (client.connected() || client.available()) {
    String line = client.readStringUntil('\n');
    if (line.indexOf("\"ok\":true") >= 0) return true;
  }
  return false;
}

float readDistanceCm() {
  digitalWrite(TRIG_PIN, LOW);
  delayMicroseconds(2);

  digitalWrite(TRIG_PIN, HIGH);
  delayMicroseconds(10);
  digitalWrite(TRIG_PIN, LOW);

  unsigned long duration = pulseIn(ECHO_PIN, HIGH, 30000);
  if (duration == 0) return -1;

  return (duration * 0.0343f) / 2.0f;
}

float readDistanceCmFiltered() {
  float a = readDistanceCm();
  delay(30);
  float b = readDistanceCm();
  delay(30);
  float c = readDistanceCm();

  if (a > b) { float t=a; a=b; b=t; }
  if (b > c) { float t=b; b=c; c=t; }
  if (a > b) { float t=a; a=b; b=t; }
  return b;
}

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

  pinMode(TRIG_PIN, OUTPUT);
  pinMode(ECHO_PIN, INPUT);

  WiFi.mode(WIFI_STA);
  WiFi.setSleep(false);
  btStop();
  WiFi.setTxPower(WIFI_POWER_11dBm);

  WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
  Serial.print("WiFi connecting");
  while (WiFi.status() != WL_CONNECTED) {
    delay(250);
    Serial.print(".");
  }
  Serial.println("\nWiFi connected");

  sendTelegram("✅ Your device is online");
}

void loop() {
  unsigned long now = millis();
  float cm = readDistanceCmFiltered();

  if (cm > 0) {
    bool isClose = (cm <= THRESH_CM);

    if (isClose) {
      if (closeStartMs == 0) closeStartMs = now;

      bool heldLongEnough = (now - closeStartMs) >= HOLD_MS;
      bool cooldownOver = (now - lastAlertMs) >= COOLDOWN_MS;

      if (heldLongEnough && cooldownOver) {
        String msg = "🚪 Someone is near the door: " + String(cm, 1) + " cm";
        bool ok = sendTelegram(msg);
        Serial.println(ok ? "Alert sent" : "Alert failed");

        lastAlertMs = now;
        closeStartMs = 0;
      }
    } else {
      closeStartMs = 0;
    }
  } else {
    closeStartMs = 0;
  }

  delay(120);
}

Tuning: Adjust THRESH_CM (range), HOLD_MS (how long they must stand there), and COOLDOWN_MS (spam control).

Step 5: Mounting at the Door

Mount the sensor at waist/chest height aimed at where a person naturally stands. Start with:

  • THRESH_CM = 80–100 cm
  • HOLD_MS = 3000 ms
  • COOLDOWN_MS = 30000 ms

If your entry is narrow, drop the threshold. If you want fewer false positives, increase the hold time.

Conclusion + Next Ideas

This build is a clean example of “cheap parts + simple logic = real utility.” No cameras. No subscriptions. Just an alert when someone is actually standing at your door.

Ideas to extend it

  • Different messages for different distances
  • Quiet hours (only alert at night)
  • Multiple sensors for wider coverage
  • Battery optimization (deep sleep + wake strategies)

Want help productionizing a project like this? ShillehTek consulting covers hardware, firmware, and deployment.