A DIY home security alarm using Raspberry Pi is one of the most practical electronics projects you can build. By combining a PIR (Passive Infrared) motion sensor, a buzzer for local alert, and Twilio’s SMS API, you get a fully functional intruder alarm that texts your phone the moment motion is detected. This project requires no soldering, costs very little, and can be extended with camera snapshots, push notifications, and home automation integrations.
This guide covers the complete build — hardware wiring, Python software, SMS integration, and a systemd service so the alarm starts automatically on boot and runs unattended 24×7.
How the System Works
A PIR sensor detects changes in infrared radiation emitted by warm bodies — humans and animals. When a person enters the sensor’s field of view, the sensor output pin goes HIGH. The Raspberry Pi reads this GPIO pin and triggers two simultaneous responses:
- Local alert — GPIO drives a buzzer (active or passive) for an audible alarm
- Remote alert — Python sends an SMS via Twilio’s REST API to your mobile number
- Optional — Camera captures a snapshot and saves it with a timestamp
The system includes a cooldown timer (configurable, default 60 seconds) so you don’t get flooded with SMS messages during continuous motion. Once armed via a simple keyboard flag or GPIO button, it runs continuously as a systemd service.
Components You Need
| Component | Specification | Qty |
|---|---|---|
| Raspberry Pi | Pi 4 or Pi 5, any RAM | 1 |
| PIR Motion Sensor | HC-SR501 (5V, 3–7m range) | 1 |
| Active Buzzer | 3–5V active (self-oscillating) | 1 |
| Camera Module | Pi Camera v2 or USB webcam | 1 (optional) |
| Jumper Wires | Male-to-female | 10 |
| Breadboard | Mini or half-size | 1 |
| MicroSD Card | 16 GB+ Class 10 | 1 |
Wiring PIR Sensor and Buzzer to Raspberry Pi
The HC-SR501 PIR sensor has three pins: VCC, OUT, and GND. The buzzer has two leads: positive and negative. All connections use the Pi’s 40-pin GPIO header.
PIR Sensor Wiring
- PIR VCC → Pi Pin 2 (5V)
- PIR GND → Pi Pin 6 (GND)
- PIR OUT → Pi Pin 11 (GPIO 17)
Buzzer Wiring
- Buzzer + → Pi Pin 12 (GPIO 18) — via 100Ω resistor to protect GPIO
- Buzzer − → Pi Pin 14 (GND)
Important: the active buzzer draws about 30 mA — within the GPIO safe limit of 50 mA per pin. For a passive (tone-controlled) buzzer or a louder siren, drive it through a transistor (2N2222 or BC547) with a flyback diode.
HC-SR501 Sensitivity Adjustment
The HC-SR501 has two potentiometers on its back:
- Sx (Sensitivity) — turn clockwise to increase detection range (max ~7 m)
- Tx (Time delay) — sets how long OUT stays HIGH after motion stops (2 s to 5 min)
Set Tx to its minimum (counter-clockwise) so Python controls the cooldown logic, not the hardware timer.
Python Motion Detection Code
Install the GPIO library first:
sudo apt install -y python3-rpi.gpio python3-pip
pip install twilio
Create the main alarm script at /home/pi/alarm/alarm.py:
import RPi.GPIO as GPIO
import time
import logging
from datetime import datetime
# ─── Configuration ────────────────────────────────────────
PIR_PIN = 17 # GPIO pin for PIR OUT
BUZZER_PIN = 18 # GPIO pin for buzzer
COOLDOWN = 60 # Seconds between SMS alerts
BUZZ_SECS = 5 # How long to sound the buzzer
# ─── Logging ──────────────────────────────────────────────
logging.basicConfig(
filename='/var/log/alarm.log',
level=logging.INFO,
format='%(asctime)s %(levelname)s %(message)s'
)
# ─── GPIO Setup ───────────────────────────────────────────
GPIO.setmode(GPIO.BCM)
GPIO.setup(PIR_PIN, GPIO.IN)
GPIO.setup(BUZZER_PIN, GPIO.OUT)
GPIO.output(BUZZER_PIN, GPIO.LOW)
last_alert = 0 # Timestamp of last SMS
def trigger_alarm():
"""Sound buzzer and send SMS."""
global last_alert
now = time.time()
logging.info("Motion detected")
# Sound buzzer
GPIO.output(BUZZER_PIN, GPIO.HIGH)
time.sleep(BUZZ_SECS)
GPIO.output(BUZZER_PIN, GPIO.LOW)
# Send SMS if cooldown elapsed
if now - last_alert >= COOLDOWN:
send_sms()
last_alert = now
try:
print("Alarm system armed. Press Ctrl+C to disarm.")
logging.info("Alarm system started")
while True:
if GPIO.input(PIR_PIN):
trigger_alarm()
time.sleep(0.1) # 100 ms polling
except KeyboardInterrupt:
print("Disarmed.")
logging.info("Alarm system stopped")
finally:
GPIO.cleanup()
SMS Alerts with Twilio
Twilio is the easiest way to send SMS from Python. Sign up at twilio.com for a free trial account — you get $15 credit, enough for hundreds of SMS messages. Note your Account SID, Auth Token, and Twilio phone number.
from twilio.rest import Client
import os
# Store credentials as environment variables (not in code)
TWILIO_SID = os.environ['TWILIO_SID']
TWILIO_TOKEN = os.environ['TWILIO_TOKEN']
FROM_NUMBER = os.environ['TWILIO_FROM'] # Your Twilio number
TO_NUMBER = os.environ['ALERT_TO'] # Your mobile number
client = Client(TWILIO_SID, TWILIO_TOKEN)
def send_sms():
timestamp = datetime.now().strftime('%d-%b-%Y %H:%M:%S')
body = f"ALARM: Motion detected at {timestamp}. Check your camera!"
try:
msg = client.messages.create(
body=body,
from_=FROM_NUMBER,
to=TO_NUMBER
)
logging.info(f"SMS sent: SID {msg.sid}")
except Exception as e:
logging.error(f"SMS failed: {e}")
Set environment variables in a .env file and source it in your systemd unit, or export them in /etc/environment. Never hard-code credentials in your script.
For Indian users: Twilio supports Indian mobile numbers. Choose India as your recipient country (+91). Note that DLT registration is required for commercial SMS in India, but for personal alert messages to your own number, the free trial works without DLT compliance.
Adding Camera Snapshot on Motion
A snapshot captured the moment motion is detected transforms your alarm into a proper security system. Add this to alarm.py:
import subprocess
from pathlib import Path
SNAPSHOT_DIR = Path('/home/pi/alarm/snapshots')
SNAPSHOT_DIR.mkdir(exist_ok=True)
def capture_snapshot():
timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
filepath = SNAPSHOT_DIR / f"motion_{timestamp}.jpg"
# Use libcamera-still for Pi Camera (Pi OS Bookworm+)
result = subprocess.run(
['libcamera-still', '-o', str(filepath), '-t', '1000',
'--width', '1280', '--height', '720', '-q', '80'],
capture_output=True, timeout=10
)
if result.returncode == 0:
logging.info(f"Snapshot saved: {filepath}")
return str(filepath)
else:
logging.error(f"Camera failed: {result.stderr}")
return None
Update trigger_alarm() to call capture_snapshot() before sending the SMS, then optionally attach the image path to the message body.
For USB webcam, replace the libcamera-still command with OpenCV frame capture:
import cv2
def capture_usb_snapshot():
cap = cv2.VideoCapture(0)
ret, frame = cap.read()
cap.release()
if ret:
filepath = SNAPSHOT_DIR / f"motion_{datetime.now().strftime('%Y%m%d_%H%M%S')}.jpg"
cv2.imwrite(str(filepath), frame)
return str(filepath)
Running as a Systemd Service (Always-On)
A security alarm must start automatically on boot and restart if it crashes. Systemd manages this perfectly.
Create /etc/systemd/system/alarm.service:
[Unit]
Description=Raspberry Pi PIR Alarm System
After=network.target
[Service]
Type=simple
User=pi
WorkingDirectory=/home/pi/alarm
EnvironmentFile=/home/pi/alarm/.env
ExecStart=/usr/bin/python3 /home/pi/alarm/alarm.py
Restart=always
RestartSec=5
StandardOutput=journal
StandardError=journal
[Install]
WantedBy=multi-user.target
The EnvironmentFile directive loads your Twilio credentials from /home/pi/alarm/.env:
TWILIO_SID=ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
TWILIO_TOKEN=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
TWILIO_FROM=+12025551234
ALERT_TO=+919876543210
Enable and start the service:
sudo systemctl daemon-reload
sudo systemctl enable alarm.service
sudo systemctl start alarm.service
sudo systemctl status alarm.service
View live logs:
sudo journalctl -fu alarm.service
Frequently Asked Questions
Will the PIR sensor trigger on pets like cats and dogs?
Yes — the HC-SR501 detects any warm-bodied moving object. To reduce false alarms from pets, reduce the sensitivity potentiometer to its minimum and place the sensor at head height (1.5–2 m) pointing at entry doors rather than open floor space. Some PIR sensors have a pet-immunity lens that filters out animals below 20 kg — these are worth the small price premium for a home with pets.
Can I receive WhatsApp messages instead of SMS?
Yes. Twilio supports WhatsApp messaging via the same API. You use a WhatsApp-enabled Twilio number and prefix the to parameter with whatsapp:. The code change is minimal — just replace to=TO_NUMBER with to='whatsapp:+91XXXXXXXXXX' and use from_='whatsapp:+1415XXXXXXX' (your Twilio WhatsApp sender).
How many PIR sensors can I connect to one Raspberry Pi?
You can connect up to 26 PIR sensors (one per available GPIO input pin on a 40-pin header, minus pins reserved for other uses). In practice, 4–8 PIR sensors covering different rooms or entry points is a practical multi-zone alarm. Each sensor connects to its own GPIO pin, and the Python code polls all pins in a loop.
Does the alarm work without internet for the SMS?
The buzzer alarm works completely offline — it needs only power and the Pi. The SMS alert requires internet. For offline SMS, consider a GSM module like SIM800L connected via UART — it uses a SIM card and sends SMS over the cellular network independently of Wi-Fi. This is ideal for remote locations without broadband.
How do I arm and disarm the system remotely?
Add a simple Flask web server running on the Pi that exposes an /arm and /disarm endpoint, accessible via your local network. For remote access, use Tailscale (free for personal use) to create a secure VPN tunnel to your Pi — then access the Flask interface from anywhere on your phone.
Build your security system today! All the components you need — Raspberry Pi boards, camera modules, and power solutions — are available at Zbotic.in with fast shipping across India. Shop the Raspberry Pi collection now.
Add comment