Detect movement with an HC‑SR501 and sound a buzzer — using a non‑blocking millis() timer.
Project_4_ESP32_PIR_Motion_Sensor.ino, then open it in the Arduino IDE (setup: Project 0b).

delay() vs millis()delay(3000) freezes the whole program for 3 s. Instead we record when motion last happened and check elapsed time — keeping the loop responsive:
lastMotionTime = millis(); // remember "now" if (millis() - lastMotionTime >= holdTime) { // has enough time passed? ... }
This pattern scales to programs doing many things at once — a habit worth building early.
| Qty | Part | Notes |
|---|---|---|
| 1 | ESP32 · breadboard · jumper wires | — |
| 1 | HC‑SR501 PIR | Powered from 5 V |
| 1 | Active buzzer | Beeps on its own when powered |

| From | To |
|---|---|
| PIR VCC | VIN (5 V) |
| PIR GND | GND |
| PIR OUT | GPIO 27 |
| Buzzer + | GPIO 26 |
| Buzzer − | GND |
VIN when USB‑powered). Its OUT signal is still ESP32‑safe.The buzzer turns on when motion starts and off after ~3 s with no motion. Logging is event‑based — one line on, one line off. Open Serial Monitor at 115200:
============================================== Project 4: ESP32 PIR Motion Sensor + Buzzer ============================================== PIR OUT -> GPIO 27 Buzzer -> GPIO 26 Buzzer holds ON for 3000 ms after motion stops. NOTE: the PIR needs ~30-60 s to warm up after power-on. ---------------------------------------------- [EVENT] MOTION detected -> buzzer ON [EVENT] No motion (hold elapsed) -> buzzer OFF

| Symptom | Likely cause | Fix |
|---|---|---|
| Always triggers | Warming up / sensitivity too high | Wait 60 s; lower the sensitivity trimmer |
| Never triggers | PIR on 3.3 V, or OUT mis‑wired | Power VCC from VIN (5 V); OUT → GPIO 27 |
| Buzzer silent | Reversed / wrong pin | + → GPIO 26, − → GND |
| Buzzer never stops | Constant motion / retrigger jumper | Hold still; check the jumper |
| Monitor blank | Wrong baud | Set it to 115200 |