Development Environment 2026 DIY Smart Doorbell: Face Recognition + WeChat Push (Cost <¥300)
Don’t know when deliveries arrive? Afraid to open the door when strangers ring? This DIY smart doorbell watches your doorstep for you!
Last week, several flyers were stuffed at my door, and I didn’t notice until I got home from work. I thought at the time: if only there was something that could automatically identify people at the door and notify me. So this weekend, I built a smart doorbell - not only can it recognize faces, but it can also push messages to my phone via WeChat.
The entire project costs less than 300 yuan, using Raspberry Pi + camera + WeChat push service. Today I’ll share the complete process with everyone.
What do you need to prepare?
| Item | Model/Specification | Price |
|---|---|---|
| Raspberry Pi | Raspberry Pi 4B 2GB | ¥280 |
| Camera | USB Camera 1080P | ¥35 |
| Microphone | USB Microphone (optional) | ¥25 |
| Doorbell Button | Normally Open Momentary Switch | ¥8 |
| Jumper Wires | Male-to-Female 20cm | ¥5 |
| Enclosure | 3D Printed/Plastic Box | ¥20 |
| Total | ¥373 |
If you already have a Raspberry Pi, the cost can be reduced to under 100 yuan. I’m using a regular USB webcam, bought casually on Taobao, as long as it can clearly see faces.
Step 1: System Environment Setup
First, install the system on the Raspberry Pi. I recommend using Raspberry Pi OS (64-bit), download address: https://www.raspberrypi.com/software/operating-systems/
After flashing the system, log into the Raspberry Pi via SSH, then install the necessary dependencies:
# Update system
sudo apt-get update
sudo apt-get upgrade -y
# Install Python dependencies
sudo apt-get install -y python3-pip python3-opencv python3-numpy
sudo apt-get install -y libatlas-base-dev libjasper-dev libqtgui4 libqt4-test
# Install face_recognition library (based on dlib)
pip3 install face_recognition
pip3 install requests
pip3 install gpiozero
Notes: ⚠️ The face_recognition library compiles slowly, it may take 20-30 minutes on Raspberry Pi. Suggest getting a cup of coffee first, let it heat up, just don’t let it glow.
If you encounter errors during compilation, it’s usually due to missing C++ compiler, execute the following command:
sudo apt-get install -y build-essential cmake
Step 2: Enroll Family Member Faces
Next, we need to enroll family members’ face data. I wrote a simple script that calls the camera to take photos and extract face features:
# enroll_face.py
import cv2
import face_recognition
import pickle
import os
def enroll_face(name, num_photos=5):
"""Enroll face, take multiple photos and average features"""
print(f"Starting to enroll {name}'s face, please keep a natural expression...")
encodings = []
cap = cv2.VideoCapture(0)
if not cap.isOpened():
print("❌ Camera cannot be opened, please check connection")
return False
for i in range(num_photos):
ret, frame = cap.read()
if not ret:
continue
# Convert to RGB format
rgb_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
# Detect face
face_locations = face_recognition.face_locations(rgb_frame)
if len(face_locations) == 0:
print(f"Photo {i+1}: No face detected, please face the camera")
continue
if len(face_locations) > 1:
print(f"Photo {i+1}: Multiple faces detected, please ensure only one person")
continue
# Extract face features
face_encodings = face_recognition.face_encodings(rgb_frame, face_locations)
if face_encodings:
encodings.append(face_encodings[0])
print(f"Photo {i+1}: ✅ Feature extraction successful")
cap.release()
if not encodings:
print("❌ Failed to extract any face features")
return False
# Save features (take average)
avg_encoding = np.mean(encodings, axis=0)
# Load or create database
db_file = "face_database.pkl"
if os.path.exists(db_file):
with open(db_file, "rb") as f:
database = pickle.load(f)
else:
database = {}
database[name] = avg_encoding
with open(db_file, "wb") as f:
pickle.dump(database, f)
print(f"✅ {name}'s face enrollment successful! Total {len(encodings)} valid photos")
return True
if __name__ == "__main__":
name = input("Please enter name:")
enroll_face(name)
Run the script:
python3 enroll_face.py
Enter family member names as prompted, then take a few photos facing the camera. It’s recommended to enroll 5+ photos per person for higher recognition accuracy.
Step 3: WeChat Push Service Configuration
Here we use ServerChan (https://sct.ftqq.com/) to implement WeChat push, it’s free and simple:
-
Visit ServerChan official website, scan WeChat code to log in
-
After binding WeChat, get SendKey (similar to:
SCT123456abcdef) -
Follow the “Fangtang” public account on WeChat to receive pushes
Test push:
# Replace with your SendKey
curl -X POST "https://sctapi.ftqq.com/SCT123456abcdef.send" \
-d "text=Doorbell test" \
-d "desp=Someone is ringing the doorbell!"
If WeChat receives the message, the configuration is successful.
Step 4: Main Program Development
Here comes the main event! Below is the complete main program, integrating face detection and WeChat push:
# smart_doorbell.py
import cv2
import face_recognition
import pickle
import requests
import time
from gpiozero import Button
from datetime import datetime
# ============ Configuration Area ============
SERVERCHAN_KEY = "SCT123456abcdef" # Replace with your SendKey
FACE_DATABASE = "face_database.pkl"
BUTTON_PIN = 17 # GPIO 17 connected to doorbell button
CAMERA_INDEX = 0
RECOGNITION_THRESHOLD = 0.6 # Face recognition threshold
# ===============================
def load_face_database():
"""Load face database"""
if not os.path.exists(FACE_DATABASE):
print("❌ Face database does not exist, please run enroll_face.py first")
return {}, []
with open(FACE_DATABASE, "rb") as f:
database = pickle.load(f)
names = list(database.keys())
encodings = list(database.values())
print(f"✅ Loaded {len(names)} faces: {', '.join(names)}")
return names, encodings
def send_wechat_push(title, content, image_path=None):
"""Send WeChat push"""
url = f"https://sctapi.ftqq.com/{SERVERCHAN_KEY}.send"
data = {
"text": title,
"desp": content
}
# If there's an image, upload to image host then attach
if image_path and os.path.exists(image_path):
# ServerChan supports image URLs, simplified handling here
pass
try:
response = requests.post(url, data=data, timeout=10)
if response.status_code == 200:
print("✅ WeChat push successful")
return True
else:
print(f"❌ Push failed: {response.text}")
return False
except Exception as e:
print(f"❌ Push exception: {e}")
return False
def recognize_face(frame, known_names, known_encodings):
"""Recognize face"""
# Resize image to accelerate processing
small_frame = cv2.resize(frame, (0, 0), fx=0.5, fy=0.5)
rgb_frame = cv2.cvtColor(small_frame, cv2.COLOR_BGR2RGB)
# Detect face
face_locations = face_recognition.face_locations(rgb_frame)
if not face_locations:
return None, "No face detected"
# Extract features
face_encodings = face_recognition.face_encodings(rgb_frame, face_locations)
if not face_encodings:
return None, "Cannot extract face features"
# Match known faces
face_encoding = face_encodings[0]
matches = face_recognition.compare_faces(known_encodings, face_encoding, RECOGNITION_THRESHOLD)
face_distances = face_recognition.face_distance(known_encodings, face_encoding)
if len(face_distances) > 0:
best_match_idx = np.argmin(face_distances)
if matches[best_match_idx]:
name = known_names[best_match_idx]
confidence = 1 - face_distances[best_match_idx]
return name, f"Recognition successful: {name} (confidence: {confidence:.2%})"
return "Stranger", "⚠️ Stranger detected"
def capture_and_save():
"""Capture and save image"""
cap = cv2.VideoCapture(CAMERA_INDEX)
ret, frame = cap.read()
cap.release()
if ret:
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
filename = f"captures/{timestamp}.jpg"
os.makedirs("captures", exist_ok=True)
cv2.imwrite(filename, frame)
return filename
return None
def main():
print("🔔 Smart doorbell starting...")
# Load face database
known_names, known_encodings = load_face_database()
if not known_names:
return
# Initialize doorbell button
doorbell_button = Button(BUTTON_PIN, pull_up=False)
print("✅ Doorbell system ready, waiting for ring...")
last_push_time = 0
PUSH_COOLDOWN = 30 # 30 second debounce
while True:
if doorbell_button.is_pressed:
current_time = time.time()
# Debounce handling
if current_time - last_push_time > PUSH_COOLDOWN:
print("🔔 Doorbell pressed!")
# Capture image
image_path = capture_and_save()
# Recognize face
cap = cv2.VideoCapture(CAMERA_INDEX)
ret, frame = cap.read()
cap.release()
if ret:
name, message = recognize_face(frame, known_names, known_encodings)
print(message)
# Send WeChat push
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
title = f"🔔 Doorbell Alert - {timestamp}"
content = f"**{message}**\n\nTime: {timestamp}"
if name == "Stranger":
content += "\n\n⚠️ **Warning: Stranger detected!**"
send_wechat_push(title, content, image_path)
last_push_time = current_time
time.sleep(0.1)
if __name__ == "__main__":
main()
Step 5: Set Up Auto-Start
To make the doorbell automatically run after booting, we need to set up a systemd service:
# Create service file
sudo nano /etc/systemd/system/doorbell.service
Paste the following content:
[Unit]
Description=Smart Doorbell Service
After=network.target
[Service]
ExecStart=/usr/bin/python3 /home/pi/smart_doorbell.py
WorkingDirectory=/home/pi
StandardOutput=inherit
StandardError=inherit
Restart=always
User=pi
[Install]
WantedBy=multi-user.target
Enable and start the service:
# Reload systemd
sudo systemctl daemon-reload
# Enable auto-start
sudo systemctl enable doorbell.service
# Start service
sudo systemctl start doorbell.service
# Check status
sudo systemctl status doorbell.service
Step 6: Test and Debug
Now test the entire system:
-
Press the doorbell button to see if the camera captures an image
-
Check if face recognition works correctly
-
Confirm if WeChat push messages are received
-
Test different lighting conditions to ensure recognition accuracy
You can view real-time logs:
sudo journalctl -u doorbell.service -f
Common Problem Troubleshooting
Problem 1: Face recognition is very slow, takes 3-4 seconds to respond
-
Cause: Raspberry Pi CPU performance is limited, face_recognition library has heavy computation
-
Solution:
-
Reduce input image resolution (already handled in code)
-
Switch to USB accelerator stick (such as Intel Neural Compute Stick)
-
Or reduce recognition frequency, change to periodic detection
-
Problem 2: Camera image too dark, can’t see clearly at night
-
Cause: Regular cameras don’t have infrared night vision
-
Solution:
-
Add infrared fill light (around ¥15)
-
Switch to camera with night vision function (¥60-80)
-
Adjust camera exposure parameters
-
Problem 3: WeChat push has high latency
-
Cause: ServerChan server response slow
-
Solution:
-
Check network connection
-
Consider using other push services (such as PushPlus, Bark)
-
Self-host push service
-
Problem 4: Face recognition accuracy not high, often misidentifies
-
Cause: Insufficient enrolled photos or lighting changes too large
-
Solution:
-
Enroll more photos per person (recommended 10+)
-
Enroll in different lighting conditions
-
Adjust RECOGNITION_THRESHOLD parameter (lower value = stricter)
-
Project Summary
Through this project, we implemented:
✅ Automatic face recognition, can identify family members and strangers
✅ Real-time WeChat push, notify instantly when doorbell rings
✅ Automatic image capture, save visitor photos
✅ Low cost, total under 300 yuan
✅ Simple configuration, suitable for beginners
Follow-up improvements:
-
Add voice prompt function (such as “Welcome home”)
-
Integrate with smart home system (such as Home Assistant)
-
Add historical record query function
-
Use a better camera to improve recognition accuracy
-
Add two-way voice intercom function
This smart doorbell not only solves practical problems, but is also a great embedded development learning project. Through this project, you can learn about:
-
Raspberry Pi basic usage
-
OpenCV image processing
-
Face recognition technology application
-
IoT device integration
-
WeChat API calls
Hope this blog post is helpful to you!
Related Resources: