Meshtastic PIR Motion Detection Security Network

Meshtastic PIR Motion Detection Security Network

Heltec WiFi LoRa 32 + PIR Sensor Project

Project Overview

Create a distributed motion detection system using Meshtastic mesh network. When any PIR sensor detects motion, it immediately notifies all other nodes in the mesh, creating a comprehensive security monitoring system.

Hardware Required

Per Node:

  • Heltec WiFi LoRa 32 V3 (or V2)
  • PIR Motion Sensor (HC-SR501 or similar)
  • LED (Red for motion alert)
  • Buzzer (optional for audio alerts)
  • 220Ω resistor (for LED)
  • Jumper wires
  • Breadboard
  • LiPo battery (for portable deployment)
  • USB-C cable for programming

Hardware Setup

PIR Sensor (HC-SR501) Connections

  • VCC → 3.3V
  • GND → GND
  • OUT → GPIO 21 (Digital input with pulldown)

Alert LED

  • Long leg (Anode) → GPIO 2 through 220Ω resistor
  • Short leg (Cathode) → GND

Buzzer (Optional)

  • Positive → GPIO 26
  • Negative → GND

Built-in Components (No wiring needed)

  • LoRa Radio for mesh communication
  • OLED Display for status
  • WiFi/Bluetooth for phone app

Pin Layout Diagram

Heltec WiFi LoRa 32
┌─────────────────────┐
│  USB-C              │
│                     │
│ GPIO 21 ←──PIR OUT  │
│ GPIO 2  ←──LED+     │
│ GPIO 26 ←──BUZZER+  │
│ 3.3V ──────→PIR VCC │
│ GND ───────→PIR GND │
│           →LED GND  │
│           →BUZ GND  │
│                     │
│    [OLED Display]   │
└─────────────────────┘

Software Implementation

#include <WiFi.h>
#include <Wire.h>
#include <Adafruit_SSD1306.h>
#include <ArduinoJson.h>
#include <time.h>

// Pin definitions
#define PIR_PIN 21
#define LED_PIN 2
#define BUZZER_PIN 26
#define OLED_SDA 4
#define OLED_SCL 15
#define OLED_RST 16

// Display object
Adafruit_SSD1306 display(128, 64, &Wire, OLED_RST);

// Motion detection variables
bool motionDetected = false;
bool lastPirState = false;
unsigned long lastMotionTime = 0;
unsigned long lastHeartbeat = 0;
String nodeId;
int totalDetections = 0;

// Network status
struct NetworkStatus {
  bool meshConnected = false;
  int connectedNodes = 0;
  unsigned long lastMessageTime = 0;
};

NetworkStatus networkStatus;

void setup() {
  Serial.begin(115200);
  Serial.println("PIR Security Node Starting...");
  
  // Initialize pins
  pinMode(PIR_PIN, INPUT);
  pinMode(LED_PIN, OUTPUT);
  pinMode(BUZZER_PIN, OUTPUT);
  
  // Get unique node ID
  nodeId = "NODE_" + WiFi.macAddress().substring(9);
  nodeId.replace(":", "");
  
  // Initialize I2C for OLED
  Wire.begin(OLED_SDA, OLED_SCL);
  
  // Initialize OLED
  if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3c)) {
    Serial.println("OLED initialization failed!");
  }
  
  // Show startup screen
  showStartupScreen();
  
  // Allow PIR to stabilize
  Serial.println("PIR warming up (30 seconds)...");
  delay(30000);
  
  Serial.println("Security system ARMED");
  updateDisplay();
}

void loop() {
  // Check PIR sensor
  bool currentPirState = digitalRead(PIR_PIN);
  
  // Detect motion (rising edge)
  if (currentPirState && !lastPirState) {
    motionDetected = true;
    lastMotionTime = millis();
    totalDetections++;
    
    Serial.println("MOTION DETECTED!");
    
    // Send immediate alert
    sendMotionAlert();
    
    // Activate local alerts
    activateAlerts();
  }
  
  lastPirState = currentPirState;
  
  // Handle ongoing motion
  if (motionDetected && (millis() - lastMotionTime > 5000)) {
    motionDetected = false;
    deactivateAlerts();
  }
  
  // Send periodic heartbeat
  if (millis() - lastHeartbeat > 60000) { // Every minute
    sendHeartbeat();
    lastHeartbeat = millis();
  }
  
  // Check for incoming messages
  checkIncomingMessages();
  
  // Update display
  updateDisplay();
  
  delay(100);
}

void sendMotionAlert() {
  // Create JSON alert message
  StaticJsonDocument<300> alert;
  alert["type"] = "MOTION_ALERT";
  alert["node"] = nodeId;
  alert["timestamp"] = millis();
  alert["location"] = "Zone_1"; // Can be customized per node
  alert["detection_count"] = totalDetections;
  
  String alertString;
  serializeJson(alert, alertString);
  
  // Send via Meshtastic
  Serial.println("MESH_SEND:" + alertString);
  
  Serial.println("Motion alert sent to mesh network");
}

void sendHeartbeat() {
  StaticJsonDocument<200> heartbeat;
  heartbeat["type"] = "HEARTBEAT";
  heartbeat["node"] = nodeId;
  heartbeat["timestamp"] = millis();
  heartbeat["status"] = "ACTIVE";
  heartbeat["uptime"] = millis() / 1000;
  
  String heartbeatString;
  serializeJson(heartbeat, heartbeatString);
  
  Serial.println("MESH_SEND:" + heartbeatString);
}

void activateAlerts() {
  // Flash LED rapidly
  for (int i = 0; i < 10; i++) {
    digitalWrite(LED_PIN, HIGH);
    tone(BUZZER_PIN, 1000, 100);
    delay(100);
    digitalWrite(LED_PIN, LOW);
    delay(100);
  }
  
  // Keep LED solid during motion
  digitalWrite(LED_PIN, HIGH);
}

void deactivateAlerts() {
  digitalWrite(LED_PIN, LOW);
  noTone(BUZZER_PIN);
}

void checkIncomingMessages() {
  // Check for incoming Meshtastic messages
  if (Serial.available()) {
    String message = Serial.readString();
    message.trim();
    
    if (message.startsWith("MESH_RECV:")) {
      String jsonData = message.substring(10);
      processIncomingMessage(jsonData);
    }
  }
}

void processIncomingMessage(String jsonData) {
  StaticJsonDocument<300> doc;
  DeserializationError error = deserializeJson(doc, jsonData);
  
  if (error) {
    Serial.println("JSON parsing failed");
    return;
  }
  
  String messageType = doc["type"];
  String senderNode = doc["node"];
  
  if (messageType == "MOTION_ALERT" && senderNode != nodeId) {
    // Remote motion detected
    Serial.println("REMOTE MOTION: " + senderNode);
    
    // Brief alert for remote detection
    digitalWrite(LED_PIN, HIGH);
    tone(BUZZER_PIN, 500, 200);
    delay(200);
    digitalWrite(LED_PIN, LOW);
    
    networkStatus.lastMessageTime = millis();
  }
  else if (messageType == "HEARTBEAT" && senderNode != nodeId) {
    // Update network status
    networkStatus.meshConnected = true;
    networkStatus.lastMessageTime = millis();
  }
}

void showStartupScreen() {
  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(WHITE);
  
  display.setCursor(0, 0);
  display.println("SECURITY SYSTEM");
  display.println("===============");
  display.println();
  display.print("Node: ");
  display.println(nodeId);
  display.println();
  display.println("Initializing...");
  display.println("PIR warming up");
  
  display.display();
}

void updateDisplay() {
  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(WHITE);
  display.setCursor(0, 0);
  
  // Header
  display.println("SECURITY NODE");
  display.println("=============");
  
  // Node info
  display.print("ID: ");
  display.println(nodeId.substring(5)); // Show short ID
  
  // Status
  display.print("Status: ");
  if (motionDetected) {
    display.println("MOTION!");
  } else {
    display.println("ARMED");
  }
  
  // Detection counter
  display.print("Alerts: ");
  display.println(totalDetections);
  
  // Network status
  display.print("Mesh: ");
  if (networkStatus.meshConnected && 
      (millis() - networkStatus.lastMessageTime < 120000)) {
    display.println("ONLINE");
  } else {
    display.println("OFFLINE");
  }
  
  // Uptime
  display.print("Up: ");
  display.print(millis() / 60000);
  display.println("min");
  
  display.display();
}

Project Extensions

1. Multi-Zone Security

// Add zone identification
struct SecurityZone {
  String zoneId;
  String description;
  bool isArmed;
  int sensitivity;
};

SecurityZone currentZone = {"ZONE_A", "Front Door", true, 1};

2. Advanced Alert System

  • Different alert tones for different zones
  • Escalating alerts (soft beep → loud alarm)
  • Silent mode for covert monitoring

3. Time-Based Arming

// Auto-arm/disarm based on schedule
bool isArmedTime() {
  // Get current time and check schedule
  // Return true if should be armed
  return true;
}

4. Camera Integration

  • Add ESP32-CAM for motion-triggered photos
  • Send images over mesh when motion detected

5. Mobile App Integration

  • Use Meshtastic phone app for notifications
  • Remote arming/disarming commands

Deployment Scenarios

1. Classroom Security

  • Monitor multiple rooms
  • Alert when someone enters after hours
  • Track movement patterns

2. Home Security System

  • Portable battery-powered nodes
  • Place at doors, windows, hallways
  • Mesh provides redundant coverage

3. Wildlife Monitoring

  • Outdoor weatherproof deployment
  • Solar charging for remote locations
  • Log animal activity patterns

Learning Objectives

Technical Skills

  • Digital I/O: Reading PIR sensor states
  • Interrupt Handling: Efficient motion detection
  • Mesh Communication: Real-time alert propagation
  • JSON Formatting: Structured message protocols
  • State Machines: Managing armed/disarmed states

Security Concepts

  • Distributed Monitoring: Multiple detection points
  • Redundancy: Mesh network resilience
  • Alert Escalation: Appropriate response levels
  • False Positive Reduction: Smart detection algorithms

Testing and Experiments

1. Detection Range Testing

  • Measure PIR effective range at different angles
  • Test sensitivity adjustments
  • Document detection patterns

2. Network Performance

  • Measure alert transmission time across mesh
  • Test with increasing number of nodes
  • Analyze message routing efficiency

3. Power Consumption Analysis

  • Monitor battery life under different alert frequencies
  • Optimize sleep modes between detections
  • Calculate deployment duration

4. False Positive Study

  • Document environmental triggers (wind, temperature)
  • Implement filtering algorithms
  • Compare indoor vs outdoor performance

Advanced Features

1. Machine Learning Detection

  • Classify motion types (human vs animal vs environment)
  • Learn normal activity patterns
  • Reduce false alarms

2. Mesh Network Visualization

  • Display network topology on OLED
  • Show message routing paths
  • Monitor node health status

3. Data Analytics

  • Log detection timestamps
  • Generate activity reports
  • Identify security patterns

Assessment Rubric

  • Hardware Assembly (25%): Correct wiring and connections
  • Code Implementation (25%): Working PIR detection and alerts
  • Mesh Integration (25%): Successful multi-node communication
  • Documentation (25%): Clear explanation of system operation

This project teaches practical security system concepts while demonstrating the power of mesh networks for distributed monitoring applications.

https://www.silabs.com/software-and-tools/usb-to-uart-bridge-vcp-drivershttps://www.silabs.com/software-and-tools/usb-to-uart-bridge-vcp-drivers