Build a motion alarm with phone alerts

Arm and disarm a PIR motion alarm from anywhere, count every movement and get a push notification when someone walks in.
  • Level:Advanced
  • Duration: 55 min
  • Ages 13+
  • Platform: ESP32

Tools for this lesson

Helpful for this build. Open a tool to see tips and more projects that use it.

Build a motion alarm with phone alerts – EEMENTOR STEM™ lesson

Is someone in your room while you're out? This alarm tells you. The PIR sensor notices people moving, and the ESP32 counts every movement and shows the time of the last one in the Blynk app. When the alarm is armed, the buzzer sounds and your phone gets a notification. You arm and disarm it from the app, wherever you are.

What you'll learn

  • How to arm and disarm a system remotely
  • How to detect the start of an event (an edge) in a timer
  • How to add the real time to messages (NTP)
  • How to stop notifications from flooding your phone

What you need

  • ESP32 board, expansion board and USB cable (ESP32 IoT Starter Kit)
  • PIR motion sensor (ESP32 IoT Starter Kit)
  • Active buzzer module (45-in-1 Sensor Kit)
  • Breadboard and jumper wires (ESP32 IoT Starter Kit)
  • A free Blynk account and the Blynk IoT app on a phone
  • A 2.4 GHz Wi-Fi network

Wiring

Breadboard wiring diagram: Build a motion alarm with phone alerts
Breadboard view. Check each connection against the wiring table below.
From To
PIR VCC 5V
PIR OUT ESP32 GPIO 27
PIR GND GND
Buzzer module S ESP32 GPIO 26
Buzzer module + 3V3
Buzzer module − GND

Sensor modules from different makers can label and order their pins differently. Always follow the labels printed on your module.

The PIR sensor needs 5 V to run, but its OUT pin only gives about 3.3 V, which is safe for the ESP32.

Set up Blynk

In the Blynk console, create a new template called Motion alarm (hardware ESP32, connection type Wi-Fi) and add these datastreams. Lesson 1 shows each step in detail.

Virtual pin Name Data type Range Phone widget
V0 Armed Integer 0 – 1 Button (switch mode)
V1 Movements Integer 0 – 9999 Value Display
V2 Last movement String n/a Value Display

Then open the template's Events & Notifications tab, add an event with the code motion (name: Motion detected) and turn on push notifications for it. The event code must match the sketch exactly.

Save the template, create a new device from it and copy its three BLYNK_… lines. In the phone app, open the device, tap the wrench icon and add a Button in switch mode (V0) and two Value Displays (V1, V2). Link each widget to its datastream.

Example Blynk web dashboard and phone app for: Build a motion alarm with phone alerts
Example dashboard with sample values. Your layout may look different.

The sketch

Replace the three BLYNK_… lines at the top with the ones from your device's Device info page, and add your Wi-Fi name and password (2.4 GHz only). The BLYNK_… lines must stay above #include <BlynkSimpleEsp32.h>.

#define BLYNK_TEMPLATE_ID "YOUR_TEMPLATE_ID"
#define BLYNK_TEMPLATE_NAME "Motion alarm"
#define BLYNK_AUTH_TOKEN "YOUR_AUTH_TOKEN"
#define BLYNK_PRINT Serial          // show connection messages in the Serial Monitor

#include <WiFi.h>
#include <WiFiClient.h>
#include <BlynkSimpleEsp32.h>
#include <time.h>

char ssid[] = "YOUR_WIFI_NAME";
char pass[] = "YOUR_WIFI_PASSWORD";
const char* TIME_ZONE = "EET-2EEST,M3.5.0/3,M10.5.0/4";  // Estonia; change for your country

const int PIR_PIN = 27;
const int BUZZER_PIN = 26;

BlynkTimer timer;
bool armed = false;
bool wasMotion = false;
long movements = 0;
unsigned long sirenStart = 0;
bool sirenOn = false;
unsigned long lastAlert = 0;
bool alertedOnce = false;

String timeNow() {
  struct tm t;
  if (!getLocalTime(&t, 10)) return "time not set yet";
  char text[20];
  strftime(text, sizeof(text), "%d.%m %H:%M:%S", &t);
  return String(text);
}

BLYNK_WRITE(V0) {
  armed = param.asInt();
  if (!armed) { sirenOn = false; digitalWrite(BUZZER_PIN, LOW); }
  Serial.println(armed ? "Armed" : "Disarmed");
}

BLYNK_CONNECTED() { Blynk.syncVirtual(V0); }

void checkMotion() {
  bool motion = digitalRead(PIR_PIN) == HIGH;

  if (motion && !wasMotion) {               // a new movement starts
    movements++;
    Blynk.virtualWrite(V1, movements);
    Blynk.virtualWrite(V2, timeNow());
    Serial.println("Movement!");

    if (armed) {
      sirenOn = true;
      sirenStart = millis();
      // at most one notification per minute
      if (!alertedOnce || millis() - lastAlert > 60000) {
        Blynk.logEvent("motion", "Movement at " + timeNow());
        lastAlert = millis();
        alertedOnce = true;
      }
    }
  }
  wasMotion = motion;

  if (sirenOn && millis() - sirenStart > 3000) sirenOn = false;   // 3-second siren
  digitalWrite(BUZZER_PIN, sirenOn && (millis() / 200) % 2);      // beep-beep
}

void setup() {
  Serial.begin(115200);
  pinMode(PIR_PIN, INPUT);
  pinMode(BUZZER_PIN, OUTPUT);
  Blynk.begin(BLYNK_AUTH_TOKEN, ssid, pass);
  configTzTime(TIME_ZONE, "pool.ntp.org");    // real time from the internet
  timer.setInterval(50L, checkMotion);
  Serial.println("Give the PIR sensor about a minute to settle");
}

void loop() {
  Blynk.run();
  timer.run();
}

How it works

The PIR sensor's OUT pin goes HIGH while it sees movement and stays HIGH for a few seconds. To count each movement only once, the sketch remembers the previous reading in wasMotion and reacts only when the signal changes from LOW to HIGH. That moment is called a rising edge. The time comes from an internet time server (NTP), and the ESP32 keeps counting it accurately afterwards. When armed, a movement starts a 3-second siren and sends a notification, but never more than one per minute, so a cat walking around doesn't fill your phone with alerts.

Try this next

  • Add a 20-second exit delay after arming, so you can leave the room.
  • Add a Value Display that counts only the movements while armed.
  • Add a "Silence" button in the app that stops the siren.

Troubleshooting

  • The device shows "Offline" in the app: check the Serial Monitor at 115200 baud. "Invalid auth token" means the BLYNK_AUTH_TOKEN line is wrong; if it never connects, check the Wi-Fi name and password, and that your network is 2.4 GHz.
  • It counts movements when nobody is there: the PIR sensor needs about a minute to settle after power-on. Turn its sensitivity knob down a little and keep it away from heaters and windows.
  • Movements are counted only every few seconds: turn the PIR's time-delay knob fully anticlockwise for the shortest delay.
  • The time says "time not set yet": wait a minute after starting; the ESP32 needs to reach the time server once.

Build it yourself

Everything used in this lesson comes in one kit, with parts tested by our engineers.

ESP32 IoT Starter Kit | Arduino IDE Compatible | Free Tutorials $57.00

Shop the kit