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 is 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

How It Works

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

Materials Needed

  • ESP32 development boards (2)
  • HC-SR501 PIR sensor (1)
  • LED for alert indication
  • Buzzer (optional)
  • LCD 16×2 with I2C (optional)
  • 220Ω resistors for LEDs
  • Jumper wires
  • Power supplies (5V USB or batteries)
  • Enclosures for weatherproofing

Get MAC Addresses

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 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};

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;

void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status) {
  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);
  
  esp_now_init();
  esp_now_register_send_cb(OnDataSent);
  
  esp_now_peer_info_t peerInfo;
  memcpy(peerInfo.peer_addr, receiverAddress, 6);
  peerInfo.channel = 0;
  peerInfo.encrypt = false;
  esp_now_add_peer(&peerInfo);
  
  delay(60000);
}

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();
  }
  
  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;

bool alertActive = false;
int lastMotionCount = 0;

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));
  
  lastMotionCount++;
  lastAlertTime = millis();
  alertActive = true;
  
  digitalWrite(alertLedPin, HIGH);
  tone(buzzerPin, 2000, 500);
  
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Motion detected!");
  lcd.setCursor(0, 1);
  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.print("ESP-NOW Monitor");
  lcd.setCursor(0, 1);
  lcd.print("Ready");
  
  WiFi.mode(WIFI_STA);
  
  esp_now_init();
  esp_now_register_recv_cb(OnDataRecv);
}

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: ");
    lcd.print(lastMotionCount);
  }
  
  delay(100);
}

Power-Saving Deep Sleep Version

#include <esp_sleep.h>

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

void loop() {
  // Send notification then deep sleep
  esp_deep_sleep_start();
}

Installation Steps

  1. Get MAC addresses of both boards
  2. Update receiver MAC address in transmitter code
  3. Upload transmitter and receiver code to respective boards
  4. Test communication within range
  5. Mount transmitter unit at desired monitoring location
  6. Place receiver unit where you can see/hear alerts

Project Extensions

  • Add Wi-Fi gateway to forward alerts to phone
  • Add SD card module to log events
  • Add DS18B20 to send temperature data
  • Add voltage divider to send battery level
  • Add multiple receivers for larger coverage

Conclusion

This ESP-NOW wireless notification system provides a low-power, long-range solution for monitoring remote locations without Wi-Fi.

Leave a Reply

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