PIR Sensor Wireless Notification System with ESP-NOW

Project Overview

This project creates a wireless motion notification system that uses ESP-NOW protocol to send alerts between ESP32 boards without requiring a Wi-Fi network. It’s perfect for monitoring remote locations like workshops, sheds, or entry gates where Wi-Fi may not reach.

Difficulty: Intermediate
Estimated time: 2-3 hours
Estimated cost: $20-30 (two ESP32 boards + PIR sensors)

How It Works

Two ESP32 boards communicate via ESP-NOW, a low-power, connectionless protocol developed by Espressif. The transmitter unit has a PIR sensor. When motion is detected, it sends a packet to the receiver unit. The receiver unit can display an alert via LED, buzzer, or LCD, and can also send notifications to a phone via Wi-Fi if available.

ESP-NOW works without Wi-Fi, has very low latency, and can achieve ranges of 50-100 meters line-of-sight.

Materials Needed

  • ESP32 development boards (2) – one for transmitter, one for receiver
  • HC-SR501 PIR sensor (1)
  • LED (for alert indication)
  • Buzzer (optional)
  • LCD 16×2 with I2C (optional, for display)
  • Resistors (220Ω for LEDs)
  • Jumper wires
  • Power supplies (5V USB or batteries)
  • Enclosures (for weatherproofing if outdoor)

Circuit Diagram

Transmitter Unit Connection Table

Component Pin ESP32 Pin
PIR Sensor VCC 3.3V
PIR Sensor GND GND
PIR Sensor OUT GPIO 4
Status LED Anode GPIO 2 (through 220Ω)
Status LED Cathode GND

Receiver Unit Connection Table

Component Pin ESP32 Pin
Alert LED Anode GPIO 2 (through 220Ω)
Alert LED Cathode GND
Buzzer Positive GPIO 5
Buzzer Negative GND
LCD (I2C) VCC 3.3V
LCD (I2C) GND GND
LCD (I2C) SDA GPIO 21
LCD (I2C) SCL GPIO 22

ESP-NOW Setup: Get MAC Addresses

First, upload this code to both ESP32 boards to get their MAC addresses:

#include <WiFi.h>

void setup() {
  Serial.begin(115200);
  WiFi.mode(WIFI_STA);
  Serial.print("MAC Address: ");
  Serial.println(WiFi.macAddress());
}

void loop() {}

Note the MAC address of the receiver board. You’ll need it for the transmitter code.

Transmitter Code

// ESP-NOW Motion Sensor Transmitter
#include <esp_now.h>
#include <WiFi.h>

const int pirPin = 4;
const int ledPin = 2;

// Replace with receiver's MAC address
uint8_t receiverAddress[] = {0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX};

// Message structure
typedef struct struct_message {
  int motionDetected;
  int sensorId;
  unsigned long timestamp;
} struct_message;

struct_message motionData;

unsigned long lastSendTime = 0;
const unsigned long sendCooldown = 5000; // 5 seconds between sends

void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status) {
  Serial.print("Send status: ");
  Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Success" : "Fail");
  digitalWrite(ledPin, status == ESP_NOW_SEND_SUCCESS ? HIGH : LOW);
  delay(100);
  digitalWrite(ledPin, LOW);
}

void setup() {
  Serial.begin(115200);
  pinMode(pirPin, INPUT);
  pinMode(ledPin, OUTPUT);
  digitalWrite(ledPin, LOW);
  
  WiFi.mode(WIFI_STA);
  
  if (esp_now_init() != ESP_OK) {
    Serial.println("ESP-NOW init failed");
    return;
  }
  
  esp_now_register_send_cb(OnDataSent);
  
  esp_now_peer_info_t peerInfo;
  memcpy(peerInfo.peer_addr, receiverAddress, 6);
  peerInfo.channel = 0;
  peerInfo.encrypt = false;
  
  if (esp_now_add_peer(&peerInfo) != ESP_OK) {
    Serial.println("Failed to add peer");
    return;
  }
  
  Serial.println("Transmitter Ready");
  Serial.print("Receiver MAC: ");
  for (int i = 0; i < 6; i++) {
    Serial.printf("%02X", receiverAddress[i]);
    if (i < 5) Serial.print(":");
  }
  Serial.println();
  
  delay(60000); // PIR warm-up
}

void loop() {
  bool motion = digitalRead(pirPin) == HIGH;
  
  if (motion && (millis() - lastSendTime > sendCooldown)) {
    motionData.motionDetected = 1;
    motionData.sensorId = 1;
    motionData.timestamp = millis();
    
    esp_now_send(receiverAddress, (uint8_t *) &motionData, sizeof(motionData));
    lastSendTime = millis();
    Serial.println("Motion detected - sending alert");
  }
  
  delay(100);
}

Receiver Code

// ESP-NOW Motion Sensor Receiver
#include <esp_now.h>
#include <WiFi.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x27, 16, 2);

const int alertLedPin = 2;
const int buzzerPin = 5;

unsigned long lastAlertTime = 0;
const unsigned long alertDuration = 5000; // 5 seconds alert indication

bool alertActive = false;
int lastMotionCount = 0;

// Message structure (must match transmitter)
typedef struct struct_message {
  int motionDetected;
  int sensorId;
  unsigned long timestamp;
} struct_message;

struct_message motionData;

void OnDataRecv(const uint8_t * mac, const uint8_t *incomingData, int len) {
  memcpy(&motionData, incomingData, sizeof(motionData));
  
  Serial.print("Motion alert from sensor ");
  Serial.print(motionData.sensorId);
  Serial.print(" at ");
  Serial.println(motionData.timestamp);
  
  lastMotionCount++;
  lastAlertTime = millis();
  alertActive = true;
  
  // Activate indicators
  digitalWrite(alertLedPin, HIGH);
  tone(buzzerPin, 2000, 500);
  
  // Update LCD
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Motion detected!");
  lcd.setCursor(0, 1);
  lcd.print("Sensor ");
  lcd.print(motionData.sensorId);
  lcd.print(" Count: ");
  lcd.print(lastMotionCount);
}

void setup() {
  Serial.begin(115200);
  pinMode(alertLedPin, OUTPUT);
  pinMode(buzzerPin, OUTPUT);
  digitalWrite(alertLedPin, LOW);
  
  lcd.init();
  lcd.backlight();
  lcd.setCursor(0, 0);
  lcd.print("ESP-NOW Monitor");
  lcd.setCursor(0, 1);
  lcd.print("Ready");
  
  WiFi.mode(WIFI_STA);
  
  if (esp_now_init() != ESP_OK) {
    Serial.println("ESP-NOW init failed");
    return;
  }
  
  esp_now_register_recv_cb(OnDataRecv);
  
  Serial.println("Receiver Ready");
  Serial.print("MAC Address: ");
  Serial.println(WiFi.macAddress());
}

void loop() {
  if (alertActive && (millis() - lastAlertTime > alertDuration)) {
    digitalWrite(alertLedPin, LOW);
    alertActive = false;
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("System Ready");
    lcd.setCursor(0, 1);
    lcd.print("Total alerts: ");
    lcd.print(lastMotionCount);
  }
  
  delay(100);
}

Multiple Sensors Network

To add more sensors, modify the transmitter code with a unique sensor ID for each unit:

// For sensor #2 (different ID)
motionData.sensorId = 2;

// For sensor #3
motionData.sensorId = 3;

The receiver will display which sensor triggered.

Range Extension Tips

  • Use external antennas on ESP32 boards (some boards have IPEX connectors).
  • Place units with line-of-sight when possible.
  • Use 2.4GHz Wi-Fi channel 1 for better performance.
  • Add external power (not USB) to ensure consistent transmission power.

Power-Saving Version (Deep Sleep)

For battery-powered remote sensors, add deep sleep:

// Add to transmitter code
#include <esp_sleep.h>

void setup() {
  // ... existing setup ...
  esp_sleep_enable_ext0_wakeup((gpio_num_t)pirPin, 1);
}

void loop() {
  // After sending, go to deep sleep
  esp_deep_sleep_start();
}

With deep sleep, battery life can extend to months or even years.

Installation Steps

  1. Get MAC addresses: Upload MAC scanner to both boards, record receiver MAC.
  2. Program transmitter: Update receiver MAC address and upload code.
  3. Program receiver: Upload code and test.
  4. Test communication: Place boards within range, trigger motion, verify receiver alerts.
  5. Mount sensors: Place transmitter unit at desired monitoring location (mailbox, gate, shed).
  6. Place receiver: Keep receiver unit where you can see/hear alerts.
  7. Power up: Use USB power or batteries.

Project Extensions

  • Wi-Fi gateway: Add Wi-Fi to receiver to forward alerts to phone via Telegram/Blynk.
  • Data logging: Add SD card module to receiver to log all events.
  • Temperature sensor: Add DS18B20 to transmitter to send temperature data.
  • Battery monitoring: Add voltage divider to transmitter to send battery level.
  • Meshing: Add multiple receivers or repeaters for larger coverage area.

Troubleshooting

  • No communication: Check MAC address. Ensure boards are within range. Try swapping transmitter/receiver roles.
  • Intermittent connection: Reduce distance. Use external antennas.
  • False alerts: Adjust PIR sensitivity. Ensure sensor not facing heat sources.
  • Receiver not displaying: Check LCD wiring and I2C address.

Conclusion

This ESP-NOW wireless notification system provides a low-power, long-range solution for monitoring remote locations without Wi-Fi. It’s ideal for property perimeter monitoring, mailbox alerts, and workshop security.

Leave a Reply

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