Project Overview
This project creates a self-powered PIR motion sensor that runs entirely on solar energy. It’s ideal for remote locations where running power cables or changing batteries is impractical. The system stores energy in a supercapacitor or rechargeable battery, providing operation through the night.
Difficulty: Advanced
Estimated time: 4-6 hours
Estimated cost: $40-60
How It Works
A small solar panel charges a supercapacitor or lithium battery during the day. An ultra-low power PIR sensor (Excelitas PYD 2597 or Panasonic EKMB) draws only 2-6 µA, allowing continuous operation. When motion is detected, the system wakes a microcontroller to process the event and optionally transmit via low-power radio (LoRa, Zigbee, or Bluetooth).
Materials Needed
- Ultra-low power PIR sensor (Excelitas PYD 2597 or Panasonic EKMB 1µA variant)
- ESP32-C3 or nRF52840 (low-power microcontroller)
- Solar panel (5V, 100-200mA, 80x80mm or larger)
- TP4056 charging module (if using Li-ion battery)
- Lithium battery (18650 or LiPo, 1000-2000mAh) OR
- Supercapacitor (2x 10F 2.7V in series for 5F 5.4V)
- Battery protection circuit (if using unprotected cells)
- Low-dropout regulator (MCP1700 or similar, 2µA quiescent)
- Schottky diode (1N5819) for solar panel isolation
- LoRa module (RAK811 or Heltec) or BLE module (optional)
- Waterproof enclosure (IP65 rated)
- Jumper wires and soldering equipment
Circuit Diagram
Power Management Section
Solar Panel (+) --- Schottky Diode ---+--- TP4056 IN (if using battery)
|
+--- Supercapacitor (+) (if using cap)
|
+--- LDO (MCP1700) IN
|
Supercapacitor/Battery (-) ------------+--- LDO GND
|
LDO OUT (3.3V) ------------------------+--- PIR VCC
+--- MCU VCC
Sensor Connection
| Component | Pin | MCU Pin | PIR Sensor (PYD 2597) | VCC | 3.3V | PIR Sensor | GND | GND | PIR Sensor | OUT | GPIO (with pull-up resistor 10k to 3.3V) | PIR Sensor | WUP (wake-up) | GPIO (interrupt pin) |
|---|
Arduino Code (ESP32-C3 with Deep Sleep)
// Energy Harvesting PIR Sensor
// Uses ESP32-C3 with deep sleep and wake-on-interrupt
#include <esp_sleep.h>
// Pin definitions
const int pirPin = 4; // PIR output
const int wakePin = 5; // PIR wake-up pin (optional, if separate)
const int ledPin = 8; // Status LED (optional)
// Battery monitoring (voltage divider)
const int batteryPin = 3; // ADC pin with voltage divider (1M + 2M)
RTC_DATA_ATTR int eventCount = 0; // Store across deep sleep
RTC_DATA_ATTR unsigned long lastWakeTime = 0;
void setup() {
Serial.begin(115200);
pinMode(pirPin, INPUT);
pinMode(ledPin, OUTPUT);
// Check why we woke up
esp_sleep_wakeup_cause_t wakeup_reason = esp_sleep_get_wakeup_cause();
if (wakeup_reason == ESP_SLEEP_WAKEUP_EXT0) {
// Woken by PIR motion
Serial.println("Wake-up: Motion detected");
// Blink LED to indicate detection
digitalWrite(ledPin, HIGH);
delay(500);
digitalWrite(ledPin, LOW);
// Increment event counter
eventCount++;
// Send notification (if radio available)
sendNotification();
// Record wake time
lastWakeTime = millis();
} else if (wakeup_reason == ESP_SLEEP_WAKEUP_TIMER) {
// Periodic wake-up for battery reporting
Serial.println("Wake-up: Timer (battery check)");
reportBattery();
}
// Go back to sleep
goToSleep();
}
void sendNotification() {
// If using LoRa, send packet here
// If using BLE, advertise connection
Serial.print("Motion detected! Total events: ");
Serial.println(eventCount);
// Simulate transmission (actual implementation depends on radio module)
// This would normally take 50-200ms
delay(100);
}
void reportBattery() {
// Read battery voltage through voltage divider
// Assuming 1M + 2M divider: Vbat = Vread * (1M+2M)/2M = Vread * 1.5
int raw = analogRead(batteryPin);
float voltage = (raw / 4095.0) * 3.3 * 1.5; // 3.3V reference, 1.5x divider factor
Serial.print("Battery voltage: ");
Serial.println(voltage);
// Could send via LoRa here
}
void goToSleep() {
Serial.println("Entering deep sleep...");
delay(100);
// Configure wake-up on PIR interrupt (HIGH level)
esp_sleep_enable_ext0_wakeup((gpio_num_t)pirPin, 1); // Wake on HIGH
// Also wake every 24 hours to report battery
esp_sleep_enable_timer_wakeup(24 * 60 * 60 * 1000000ULL); // 24 hours in microseconds
// Deep sleep
esp_deep_sleep_start();
}
void loop() {
// Not used - all code in setup()
}
Power Budget Calculation
Component power consumption:
- PIR sensor (PYD 2597): 2 µA
- ESP32-C3 deep sleep: 5 µA (with RTC)
- LDO (MCP1700): 2 µA
- Total standby current: 9 µA
- Active current (during event): 15-30 mA for 0.5 seconds
- Daily energy consumption: 9 µA × 24h = 0.216 mAh + events
With 10 events/day: 0.216 mAh + (15 mA × 0.5s × 10 / 3600) = 0.216 + 0.021 = 0.237 mAh/day
With 1000 mAh battery: 1000 / 0.237 ≈ 4,200 days ≈ 11.5 years!
But battery self-discharge limits practical life to 2-3 years. Solar charging extends indefinitely.
Solar Panel Sizing
For continuous operation without battery, you need enough solar power to cover daily consumption:
- Daily consumption: 0.237 mAh × 3.3V = 0.78 mWh
- Solar panel (80x80mm) in full sun: 100 mW
- Even on cloudy days (10% output): 10 mW, still more than enough
A 50x50mm solar panel is sufficient for most locations.
Enclosure Design
- Choose weatherproof enclosure (IP65 or IP67).
- Mount solar panel on top or side with clear window or external mounting.
- Drill hole for PIR sensor lens (use silicone sealant around edges).
- Place circuit board inside with desiccant pack to prevent condensation.
- Use outdoor-rated cable if sensors are separate from main unit.
Installation Steps
- Assemble power management circuit: Build on PCB or protoboard. Test with bench supply before adding solar panel.
- Program ESP32: Upload code and test with motion detection.
- Test power consumption: Measure standby current to verify it’s under 10 µA.
- Mount components: Secure board and battery in enclosure.
- Install solar panel: Place panel facing south (northern hemisphere) at optimal angle for your latitude.
- Deploy in field: Mount unit at desired location, test for 24 hours.
Project Extensions
- LoRa gateway: Add LoRa radio to transmit motion events to a central receiver for wide-area monitoring.
- Temperature sensor: Add DS18B20 to report ambient temperature with periodic wake-ups.
- MQTT integration: Use ESP32’s Wi-Fi (if available) to send data to Home Assistant.
- Multiple sensors: Create a network of solar-powered sensors for perimeter security.
- Wildlife camera trigger: Use PIR to wake a camera for wildlife photography.
Troubleshooting
- Sensor not waking ESP32: Check pull-up resistor on PIR output. Ensure interrupt pin is configured correctly.
- Battery not charging: Verify solar panel voltage (>5V) and check Schottky diode orientation.
- High standby current: Remove unnecessary components (status LEDs, voltage dividers with low resistance).
- False wake-ups: Add debounce in code or hardware RC filter on PIR output.
Conclusion
This energy-harvesting PIR sensor provides maintenance-free operation in remote locations. With proper design, it can operate indefinitely without battery changes.
