PIR Motion Sensor

How to detect motion with a PIR sensor and ESP32

The PIR (Passive Infrared) motion sensor detects changes in infrared radiation emitted by warm objects -- like people, animals, or anything that gives off heat. When something warm moves through its field of view, the sensor outputs a digital HIGH signal. PIR sensors are everywhere: automatic porch lights, security systems, hallway lighting, and bathroom fans that turn on when you walk in.

Despite the name, the sensor does not emit any infrared light. It passively watches for changes in the infrared background. A Fresnel lens on the front of the module focuses infrared energy onto a pyroelectric element, and the onboard circuitry handles all the signal processing. You get a simple HIGH or LOW output -- no analog readings to interpret, no libraries to install.

🔗Key Specs

ParameterValue
Operating voltage3.3V -- 5V (most modules)
OutputDigital (HIGH on motion)
Detection range5 -- 7 m (adjustable)
Detection angle~120 degrees
Output HIGH time3 s -- 5 min (adjustable)
Warm-up time~60 seconds
Quiescent current< 50 uA

Most PIR modules have two small potentiometers on the back:

  • Sensitivity -- adjusts the detection range (clockwise = farther).
  • Time delay -- adjusts how long the output stays HIGH after motion is detected (clockwise = longer).

Alternatives: The PIR detects motion but not distance. If you need to measure how far away something is, see the HC-SR04 (ultrasonic) or VL53L0X (laser). Our sensor comparison guide covers all three.

🔗What You'll Need

ComponentQtyNotesBuy
ESP32 dev board1AliExpress | Amazon.de .co.uk .com
PIR sensor (HC-SR501)1AliExpress | Amazon.de .co.uk .com
Breadboard1AliExpress | Amazon.de .co.uk .com
Jumper wires3AliExpress | Amazon.de .co.uk .com

Links marked Amazon/AliExpress are affiliate links. We may earn a small commission at no extra cost to you.

🔗Wiring

PIR Module PinESP32 Pin
VCC3.3V
GNDGND
OUTGPIO 13

Board variation note: Pin labels and GPIO numbers vary between ESP32 boards. Always check your specific board's pinout diagram. The recommended starter board is the ESP32-WROOM-32 DevKit. Any digital-capable GPIO will work for the PIR output -- just avoid GPIOs 34--39 if you want to use internal pull-ups (they are input-only with no pull-up capability on some boards).

Most PIR modules work fine at 3.3V. If yours requires 5V (check the datasheet), power it from the VIN pin instead. The output signal will still be 3.3V-compatible on most modules.

🔗Required Libraries

None -- the PIR sensor outputs a simple digital signal. You only need the built-in Arduino functions.

🔗Code Example

This sketch uses a hardware interrupt to detect motion, which is more efficient than polling in loop(). The ESP32 can even do other work while waiting for motion.

#define PIR_PIN 13

volatile bool motionDetected = false;

// Interrupt service routine -- keep it short
void IRAM_ATTR onMotion() {
    motionDetected = true;
}

void setup() {
    Serial.begin(115200);
    pinMode(PIR_PIN, INPUT);
    attachInterrupt(digitalPinToInterrupt(PIR_PIN), onMotion, RISING);

    Serial.println("PIR sensor warming up...");
    delay(60000);  // Wait 60 seconds for the sensor to stabilize
    Serial.println("PIR sensor ready.");
}

void loop() {
    if (motionDetected) {
        Serial.println("Motion detected!");
        motionDetected = false;
    }
    delay(100);
}

🔗How It Works

  1. Warm-up phase -- When the PIR sensor first powers on, it needs about 60 seconds to calibrate to the ambient infrared background. During this time, it may produce false triggers. The code above includes a delay(60000) to wait this out.

  2. Detection -- The pyroelectric element inside the sensor is split into two halves. When a warm body moves across the sensor's field of view, one half sees more infrared energy than the other, producing a voltage difference. The onboard comparator converts this into a clean digital signal.

  3. Interrupt-driven reading -- Instead of checking digitalRead() every loop iteration, we attach an interrupt to the PIR output pin. When the signal goes from LOW to HIGH (RISING edge), the onMotion() function sets a flag. The main loop checks this flag and reacts accordingly.

  4. Retriggering -- Most PIR modules have a jumper or pad that selects between single trigger mode (output goes HIGH once, then LOW, then waits) and repeating trigger mode (output stays HIGH as long as motion continues). Check your module's documentation.

Tip: The IRAM_ATTR attribute tells the compiler to place the interrupt handler in IRAM (internal RAM). This is required on ESP32 -- without it, the interrupt may crash if the handler code is in flash memory during a cache miss.

🔗Troubleshooting

ProblemPossible CauseSolution
Constant HIGH outputStill in warm-up periodWait at least 60 seconds after power-on
False triggersNearby heat source (heater, sunlight, AC vent)Move sensor away from heat sources; reduce sensitivity potentiometer
False triggersSensor is not mounted stablySecure the sensor -- vibrations cause false readings
No detectionSensitivity too lowTurn the sensitivity potentiometer clockwise
No detectionWrong pin or wiring issueDouble-check wiring and GPIO number
Output stays HIGH too longTime delay potentiometer set too highTurn the time delay potentiometer counter-clockwise
Triggers once then stopsSingle-trigger mode enabledCheck for a jumper on the module to switch to repeating mode

🔗Next Steps

  • Connect an LED or relay to turn on a light when motion is detected.
  • Combine the PIR sensor with an OLED display to show a motion log with timestamps.
  • Use WiFi to send a notification (MQTT or HTTP) when motion is detected -- great for a simple security alert.
  • Pair with a VL53L0X distance sensor to detect motion and measure how far away the object is.