A Raspberry Pi 5 camera system that watches bird feeders, captures photos when motion is detected, and uses Claude AI to identify bird species. Non-bird photos are automatically deleted, so the gallery only shows confirmed bird sightings.
- Web App: http://birdcam.local:5000
- Live Feed: http://birdcam.local:5000/stream
- SSH:
ssh <user>@birdcam.local
- Camera watches the bird feeders via live video stream
- Motion detection compares frames and triggers on significant changes
- When motion is detected, a photo is captured
- The photo is sent to Claude AI (Sonnet) for bird identification
- If a bird is detected: saved to gallery with species label
- If no bird (wind, etc.): photo is automatically deleted
Cost control: Claude Vision only runs during active hours (default 6:45 AM β 6:30 PM). Outside that window, motion captures are skipped entirely so no API calls are made overnight.
Open http://birdcam.local:5000 in any browser on the same WiFi network.
- Open the web app
- Click Settings button
- Use the sliders:
- Adaptive Multiplier: Higher = less sensitive (default 8x). If too many wind triggers, increase this. If birds are being missed, decrease it.
- Cooldown: Minimum seconds between captures (default 15s)
- Min MSE Threshold: Minimum motion level to consider (default 15)
- Click Apply Settings β changes take effect immediately and persist
Click Check Angle on the web app. Claude will analyze the current view and suggest improvements for better bird identification.
sudo systemctl restart birdcamsudo systemctl status birdcam# Recent logs
sudo journalctl -u birdcam -n 50 --no-pager
# Follow logs live
sudo journalctl -u birdcam -f
# Just bird detections
sudo journalctl -u birdcam | grep BIRDsudo systemctl stop birdcam
sudo systemctl start birdcamAll settings are in ~/birdcam/config.yaml. Edit with:
nano ~/birdcam/config.yamlThen restart: sudo systemctl restart birdcam
| Setting | File Location | What It Does |
|---|---|---|
motion.adaptive_multiplier |
config.yaml | How far above baseline motion must spike to trigger (8 = 8x) |
motion.cooldown_seconds |
config.yaml | Min seconds between captures |
motion.mse_threshold |
config.yaml | Absolute minimum motion level |
camera.scaler_crop |
config.yaml | Digital zoom region [x, y, width, height] |
vision.enabled |
config.yaml | true/false to enable Claude bird ID |
vision.model |
config.yaml | Which Claude model to use |
vision.active_start |
config.yaml | Time vision turns on (default "06:45" = 6:45 AM) |
vision.active_end |
config.yaml | Time vision turns off (default "18:30" = 6:30 PM) |
storage.max_photos |
config.yaml | Max photos before oldest are deleted |
The Claude API key is stored in ~/birdcam/.env:
ANTHROPIC_API_KEY=<your-key-here>
~/birdcam/
βββ app.py # Main entry point
βββ camera.py # Camera management (picamera2)
βββ motion.py # Motion detection (adaptive threshold)
βββ storage.py # Photo storage and metadata
βββ vision.py # Claude AI bird identification
βββ web.py # Flask web server and API
βββ config.py # Configuration loader
βββ config.yaml # All tunable settings
βββ .env # API key (secret)
βββ metadata.json # Photo metadata database
βββ captures/ # Full-size bird photos
β βββ thumbs/ # Gallery thumbnails
βββ templates/ # HTML templates
βββ static/ # CSS
βββ venv/ # Python virtual environment
βββ birdcam.log # Application log file
βββ birdcam.service # systemd service definition
To set a static IP on the Pi's WiFi connection:
sudo nmcli connection modify '<WIFI_SSID>' ipv4.method manual ipv4.addresses <IP>/24 ipv4.gateway <GATEWAY> ipv4.dns <DNS>
sudo nmcli connection up '<WIFI_SSID>'Copy the service file and enable it:
sudo cp ~/birdcam/birdcam.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable --now birdcam- Check if service is running:
sudo systemctl status birdcam - Check for errors:
sudo journalctl -u birdcam -n 20 - Restart:
sudo systemctl restart birdcam
- Check if camera is detected:
rpicam-hello --list-cameras - Make sure no other process is using the camera
- Restart the service
Increase the adaptive multiplier via the web Settings panel or in config.yaml.
Decrease the adaptive multiplier. Also check that the camera angle covers the feeders β use the "Check Angle" button.
- Check the API key in
~/birdcam/.env - Check your Anthropic account has credits
- Look at logs:
sudo journalctl -u birdcam | grep Vision