|
2026 DIY Smart Doorbell: Face Recognition + WeChat Push (Cost <¥300)

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?

ItemModel/SpecificationPrice
Raspberry PiRaspberry Pi 4B 2GB¥280
CameraUSB Camera 1080P¥35
MicrophoneUSB Microphone (optional)¥25
Doorbell ButtonNormally Open Momentary Switch¥8
Jumper WiresMale-to-Female 20cm¥5
Enclosure3D 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:

  1. Visit ServerChan official website, scan WeChat code to log in

  2. After binding WeChat, get SendKey (similar to: SCT123456abcdef)

  3. 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:

  1. Press the doorbell button to see if the camera captures an image

  2. Check if face recognition works correctly

  3. Confirm if WeChat push messages are received

  4. 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:

    1. Reduce input image resolution (already handled in code)

    2. Switch to USB accelerator stick (such as Intel Neural Compute Stick)

    3. 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:

    1. Add infrared fill light (around ¥15)

    2. Switch to camera with night vision function (¥60-80)

    3. Adjust camera exposure parameters

Problem 3: WeChat push has high latency

  • Cause: ServerChan server response slow

  • Solution:

    1. Check network connection

    2. Consider using other push services (such as PushPlus, Bark)

    3. Self-host push service

Problem 4: Face recognition accuracy not high, often misidentifies

  • Cause: Insufficient enrolled photos or lighting changes too large

  • Solution:

    1. Enroll more photos per person (recommended 10+)

    2. Enroll in different lighting conditions

    3. 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:

  1. Add voice prompt function (such as “Welcome home”)

  2. Integrate with smart home system (such as Home Assistant)

  3. Add historical record query function

  4. Use a better camera to improve recognition accuracy

  5. 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: