PIR Sensor for Garage Door Automation: Vehicle Detection

Project Overview

This project creates a hands-free garage door opener that detects when your car approaches and automatically opens the door. Using a PIR sensor mounted near the driveway, the system detects your vehicle’s heat signature and triggers a relay that simulates pressing the garage door opener button.

Difficulty: Intermediate
Estimated time: 2-3 hours
Estimated cost: $25-35

How It Works

A PIR sensor placed at the driveway entrance detects the heat signature of your approaching car. When a vehicle is detected (and after a short delay to ensure it’s your car approaching, not a person walking), the system activates a relay that connects across the garage door opener’s wall button terminals, simulating a button press. The door opens automatically as you approach.

An optional reed switch on the garage door can detect whether the door is already open, preventing unnecessary triggering.

Materials Needed

  • ESP32 or Arduino Uno (1)
  • HC-SR501 PIR sensor (1) – or AM312 for lower power
  • Relay module (5V, single channel)
  • Reed switch (normally open) for door position detection (optional)
  • Magnet (for reed switch)
  • 12V to 5V converter (if using 12V garage door supply)
  • Jumper wires
  • Waterproof enclosure (for outdoor PIR sensor)
  • Wire strippers and soldering equipment

Understanding Your Garage Door Opener

Most garage door openers have a wall button that simply shorts two wires together to trigger the door. You can connect a relay across these terminals to simulate a button press. The wires are low voltage (usually 12-24V DC), so it’s safe to interface with.

Important: Identify the correct wires before connecting. Use a multimeter to find the pair that shows continuity when the wall button is pressed.

Circuit Diagram

Connection Table

Component Pin ESP32 Pin
PIR Sensor VCC 3.3V or VIN
PIR Sensor GND GND
PIR Sensor OUT GPIO 4
Relay Module VCC 5V (if available) or VIN
Relay Module GND GND
Relay Module IN GPIO 5
Reed Switch One side GPIO 12 (with 10k pull-up)
Reed Switch Other side GND

Garage Door Opener Connection

Connect the relay COM and NO terminals across the garage door opener’s wall button terminals. When the relay activates, it shorts these wires, triggering the door.

Arduino Code

// Automatic Garage Door Opener with PIR
// Opens garage door when vehicle approaches

#include <WiFi.h>
#include <ESPmDNS.h>
#include <WebServer.h>

// Pin definitions
const int pirPin = 4;
const int relayPin = 5;
const int doorSensorPin = 12;

// Configuration
const char* ssid = "YourWiFiSSID";
const char* password = "YourWiFiPassword";
WebServer server(80);

// Timing
unsigned long lastTriggerTime = 0;
const unsigned long triggerDelay = 1000;      // 1 second after detection
const unsigned long relayDuration = 500;       // Hold relay for 0.5 seconds
const unsigned long cooldownPeriod = 30000;    // 30 seconds between triggers

bool motionDetected = false;
bool doorOpen = false;
unsigned long motionStartTime = 0;

void setup() {
  Serial.begin(115200);
  
  pinMode(pirPin, INPUT);
  pinMode(relayPin, OUTPUT);
  pinMode(doorSensorPin, INPUT_PULLUP);
  
  digitalWrite(relayPin, LOW);
  
  // Connect to WiFi
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("WiFi connected");
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());
  
  // Setup web server for manual control
  server.on("/", handleRoot);
  server.on("/open", handleOpen);
  server.on("/close", handleClose);
  server.on("/status", handleStatus);
  server.begin();
  
  // Read initial door state
  doorOpen = digitalRead(doorSensorPin) == LOW;
  
  Serial.println("Garage Door Opener Ready");
  Serial.println("Waiting 60 seconds for PIR warm-up...");
  delay(60000);
}

void handleRoot() {
  String html = "<html><head><title>Garage Door Control</title>";
  html += "<meta name='viewport' content='width=device-width'></head><body>";
  html += "<h1>Garage Door Control</h1>";
  html += "<p>Door status: ";
  html += doorOpen ? "OPEN" : "CLOSED";
  html += "</p>";
  html += "<p><a href='/open'><button>Open Door</button></a></p>";
  html += "<p><a href='/close'><button>Close Door</button></a></p>";
  html += "</body></html>";
  server.send(200, "text/html", html);
}

void handleOpen() {
  if (!doorOpen) {
    triggerDoor();
  }
  server.sendHeader("Location", "/");
  server.send(303);
}

void handleClose() {
  if (doorOpen) {
    triggerDoor();
  }
  server.sendHeader("Location", "/");
  server.send(303);
}

void handleStatus() {
  String json = "{\"door\":" + String(doorOpen ? "true" : "false") + "}";
  server.send(200, "application/json", json);
}

void triggerDoor() {
  Serial.println("Triggering garage door");
  digitalWrite(relayPin, HIGH);
  delay(relayDuration);
  digitalWrite(relayPin, LOW);
  
  // Wait for door to start moving before updating state
  delay(2000);
  doorOpen = digitalRead(doorSensorPin) == LOW;
  lastTriggerTime = millis();
}

void checkVehicleApproach() {
  bool pirState = digitalRead(pirPin) == HIGH;
  
  if (pirState && !motionDetected) {
    // Motion detected - start timer
    motionDetected = true;
    motionStartTime = millis();
    Serial.println("Motion detected - waiting for confirmation");
  }
  
  if (motionDetected && (millis() - motionStartTime > triggerDelay)) {
    // Confirmed motion - trigger door
    if (!doorOpen && (millis() - lastTriggerTime > cooldownPeriod)) {
      Serial.println("Vehicle approaching - opening door");
      triggerDoor();
    } else {
      Serial.println("Door already open or cooldown active");
    }
    motionDetected = false;
  }
  
  // Reset if motion stops before confirmation
  if (motionDetected && !pirState && (millis() - motionStartTime < triggerDelay)) {
    motionDetected = false;
    Serial.println("Motion cleared - no trigger");
  }
}

void loop() {
  server.handleClient();
  
  // Update door state from reed switch
  bool newDoorState = digitalRead(doorSensorPin) == LOW;
  if (newDoorState != doorOpen) {
    doorOpen = newDoorState;
    Serial.print("Door state changed: ");
    Serial.println(doorOpen ? "OPEN" : "CLOSED");
  }
  
  checkVehicleApproach();
  delay(100);
}

ESP32 Version with Deep Sleep (Battery-Powered)

For a battery-powered outdoor unit:

// Battery-Powered Version with Deep Sleep
#include <esp_sleep.h>

const int pirPin = 4;
const int relayPin = 5;

RTC_DATA_ATTR unsigned long lastTriggerTime = 0;

void setup() {
  Serial.begin(115200);
  pinMode(pirPin, INPUT);
  pinMode(relayPin, OUTPUT);
  digitalWrite(relayPin, LOW);
  
  esp_sleep_enable_ext0_wakeup((gpio_num_t)pirPin, 1);
  
  // Check if woken by PIR
  if (esp_sleep_get_wakeup_cause() == ESP_SLEEP_WAKEUP_EXT0) {
    if (millis() - lastTriggerTime > 30000) {
      digitalWrite(relayPin, HIGH);
      delay(500);
      digitalWrite(relayPin, LOW);
      lastTriggerTime = millis();
    }
  }
  
  esp_deep_sleep_start();
}

void loop() {}

Installation Steps

  1. Test garage door wiring: Identify the wall button terminals on your garage door opener. Measure voltage and confirm which wires are shorted when the button is pressed.
  2. Connect relay: Wire the relay COM and NO terminals across the wall button terminals. Test with a multimeter to ensure it shorts correctly.
  3. Mount PIR sensor: Place sensor at driveway entrance, 1.5-2m high, angled to detect vehicle approach. Ensure it doesn't detect passing pedestrians.
  4. Position reed switch: Mount reed switch on door frame and magnet on door to detect open/closed state.
  5. Enclose electronics: Place ESP32 and relay in waterproof enclosure near the garage door opener.
  6. Power: Use 12V-5V converter if powering from garage door opener supply, or use separate power adapter.
  7. Test: Drive vehicle toward garage and verify door opens automatically.

Adjusting Sensitivity

  • Adjust PIR sensitivity potentiometer to avoid detecting people walking by.
  • Point sensor downward to focus on vehicle height.
  • Add a shield to limit field of view to the driveway only.
  • Adjust triggerDelay to require longer detection before triggering.

Project Extensions

  • Wi-Fi dashboard: Add web interface to monitor door status and manually control.
  • Smart home integration: Use ESPHome to integrate with Home Assistant.
  • Camera integration: Add ESP32-CAM to capture images when door opens.
  • Multiple vehicles: Add RFID or license plate recognition for vehicle-specific control.
  • Timer close: Automatically close door after set time if left open.
  • Light control: Turn on garage lights when motion detected.

Troubleshooting

  • Door not opening: Check relay wiring. Use multimeter to verify relay contacts close when triggered.
  • False triggers: Adjust PIR sensitivity or reposition to avoid pedestrians and street traffic.
  • Door opens too late: Reduce triggerDelay.
  • Door opens when already open: Add door position sensor and check logic.
  • Wi-Fi connection issues: Ensure ESP32 is within range of router.

Conclusion

This automatic garage door opener adds convenience and a modern touch to your home. With proper installation, it will reliably open your garage door as you arrive, eliminating the need to fumble for a remote control.

Leave a Reply

Your email address will not be published. Required fields are marked *