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