Backend for the Hootcam owl box camera system: Raspberry Pi 5 dual CSI cameras, motion detection, and motion-triggered recording to SSD. REST API and SQLite for metadata. Use this repo together with a separate frontend (e.g. hootcam-ui).
Alternative: 3-part architecture. If the Pi is overloaded, you can split into: (1) Hootcam Streamer on the Pi (RTSP only, no motion), (2) Hootcam Motion on a NUC (consumes RTSP, runs motion + recording + API), and (3) Hootcam UI (points at the NUC). This repo remains the all-in-one server for those who run everything on the Pi.
- Dual cameras – Uses both Pi 5 CSI ports (e.g.
Picamera2(0)andPicamera2(1)). - Live streams – MJPEG streams per camera for a frontend (
/cameras/0/stream,/cameras/1/stream). - Motion detection – Configurable threshold, noise level, event gap, pre/post capture.
- Recording on motion – Saves video (and optionally pictures) to SSD; metadata in SQLite.
- REST API – Configuration and control for cameras, detection, and recording.
- SQLite – Events, file records, and optional config storage; media files live on SSD.
- Raspberry Pi 5
- Two CSI cameras (with 15-pin FFC adapters if needed)
- SSD Pi HAT + SSD for recordings
- Raspberry Pi OS (Bookworm or later)
On the Pi (in your clone of hootcam-server):
-
Create a virtualenv with access to system packages (required so the venv can use system-installed picamera2 from apt):
cd /path/to/hootcam-server python3 -m venv .venv --system-site-packages source .venv/bin/activate pip install -r requirements.txt
-
Ensure picamera2 and ffmpeg are available. Many Pi base images already include them. Check and install only if missing:
# Check (optional) python3 -c "from picamera2 import Picamera2" 2>/dev/null && echo "picamera2 OK" || echo "need picamera2" ffmpeg -version &>/dev/null && echo "ffmpeg OK" || echo "need ffmpeg" # If either check fails, install: sudo apt update && sudo apt install -y python3-picamera2 ffmpeg
Run the checks from the same environment you use to start the server (e.g. with the venv activated). If you see "need picamera2" even with the venv, ensure the venv was created with
--system-site-packages(step 1). -
Storage (optional). Recordings default to the current directory (SD card). To use an SSD: use the API (
GET /storage, thenPATCH /storagewith{ "use_auto_detected_ssd": true }or{ "path": "/mnt/ssd/hootcam-server" }), or setHOOTCAM_TARGET_DIR=/mnt/ssd/hootcam-serverbefore starting. Storage changes take effect after the next server restart.
source .venv/bin/activate
uvicorn hootcam_server.main:app --host 0.0.0.0 --port 8080Use --host 0.0.0.0 so the server accepts connections from other devices on the network (not just the Pi). Replace <pi-ip> below with the Pi's IP (e.g. 192.168.1.10).
- API & docs: http://<pi-ip>:8080
- OpenAPI JSON: http://<pi-ip>:8080/openapi.json
- Camera 0 stream: http://<pi-ip>:8080/cameras/0/stream
- Camera 1 stream: http://<pi-ip>:8080/cameras/1/stream
All endpoints require HTTP Basic auth. Default user: admin / admin. Change the password via PATCH /auth/password (see API docs).
To run Hootcam Server automatically on the Pi after reboot:
Prerequisite: Complete Setup first, including creating the venv with --system-site-packages so that picamera2 is available when the service runs.
-
Copy the systemd unit file (from the repo root):
sudo cp contrib/hootcam-server.service /etc/systemd/system/
-
Edit the unit file if the repo is not in
/home/pi/hootcam-server:sudo nano /etc/systemd/system/hootcam-server.service
Update
WorkingDirectoryand the path insideExecStartto match your install (e.g./home/pi/hootcam-server). -
Optional – recordings on SSD: Recordings default to the SD card. To use an SSD, call
PATCH /storagewith{ "use_auto_detected_ssd": true }or set a path via the API; or create an environment file:echo 'HOOTCAM_TARGET_DIR=/mnt/ssd/hootcam-server' | sudo tee /etc/hootcam-server.env
Then in
/etc/systemd/system/hootcam-server.serviceuncomment the line:EnvironmentFile=/etc/hootcam-server.env -
Reload systemd, enable and start the service:
sudo systemctl daemon-reload sudo systemctl enable hootcam-server sudo systemctl start hootcam-server -
Check status and logs:
sudo systemctl status hootcam-server sudo journalctl -u hootcam-server -f
Useful commands:
| Command | Description |
|---|---|
sudo systemctl stop hootcam-server |
Stop the service |
sudo systemctl start hootcam-server |
Start the service |
sudo systemctl restart hootcam-server |
Restart after config/code changes |
sudo systemctl disable hootcam-server |
Do not start on boot (service can still be started manually) |
The service runs as user pi. If you use a different user, change User= and Group= in the unit file and ensure that user can access the install directory and (if used) the SSD mount.
- Global config –
GET/PATCH /config(target_dir, log_level, stream options, etc.) - Storage –
GET /storage(current path + auto-detected SSD),PATCH /storage(set path or use SSD) - Per-camera config –
GET/PATCH /cameras/{id}/config(width, height, framerate, threshold, movie_output, etc.) - Detection control –
POST /cameras/{id}/detection/start,POST /cameras/{id}/detection/pause - Events & files –
GET /events,GET /events/{id},GET /files(from SQLite; media on SSD) - Streams –
GET /cameras/{id}/stream,GET /cameras/{id}/current(latest JPEG)
See the OpenAPI documentation at /docs for full parameter descriptions.
Can't reach the server from another PC (e.g. http://pi-ip:8080/cameras/0/stream)
If "site can't be reached" or connection refused from another machine:
-
Start the server bound to all interfaces. It must listen on
0.0.0.0, not just localhost:uvicorn hootcam_server.main:app --host 0.0.0.0 --port 8080
If you omit
--host 0.0.0.0, uvicorn defaults to 127.0.0.1 and only the Pi can connect. The systemd unit already uses--host 0.0.0.0. -
Allow port 8080 through the Pi's firewall. On Raspberry Pi OS, if you use
ufw:sudo ufw allow 8080/tcp sudo ufw status
If you use
iptablesor another firewall, open TCP port 8080. (Many Pi setups have no firewall by default.) -
Check the Pi's IP and that the other PC is on the same network:
hostname -I
From the other PC, try
ping <pi-ip>. Then tryhttp://<pi-ip>:8080/in a browser (you'll get a 401 or a JSON response if the server is reachable; the login prompt or API response means it's working). -
All endpoints require HTTP Basic auth. In the browser, when you open the stream URL you'll be prompted for username and password (default
admin/admin). For the UI, setVITE_HOOTCAM_STREAMER_URL=http://<pi-ip>:8080so the app talks to the Pi.
This means the Python process can't import picamera2. On the Pi, picamera2 is installed via apt (system-wide), but a virtualenv does not see system packages unless it was created with --system-site-packages.
Fix: Recreate the venv so it can use the system picamera2:
deactivate
rm -rf .venv
python3 -m venv .venv --system-site-packages
source .venv/bin/activate
pip install -r requirements.txtThen start the server again. Verify with:
python3 -c "from picamera2 import Picamera2; print('picamera2 OK')"If the sensor disconnects or the cable is loose, the camera stack can block and lock the app. The server now runs each capture in a thread with a 15 second timeout. If a capture times out:
- The app logs a warning and attempts to restart that camera once.
- If timeouts continue (3 in a row), that camera is marked failed and the capture loop skips it so the rest of the app (and the other camera) keeps running.
- Restart the server after fixing the cable/sensor to use that camera again.
- Capture uses per-camera
framerate(default 15 fps). - Stream (what you see in the UI) is limited by global stream_maxrate (default 15 fps). If the feed was very slow before, the saved config may have
stream_maxrate: 1. In the UI go to Config and set "Stream max framerate" to 15 or higher (up to 100 for no limit).
hootcam-server/
├── README.md
├── requirements.txt
├── contrib/
│ ├── hootcam-server.service # systemd unit (run on boot)
│ └── README.md
├── docs/
│ └── API.md
├── hootcam_server/
│ ├── __init__.py
│ ├── main.py # FastAPI app
│ ├── config.py # Config load/save, defaults
│ ├── database.py # SQLite schema, events, files
│ ├── camera.py # Dual camera capture (picamera2)
│ ├── motion.py # Motion detection
│ ├── recording.py # Record on motion to SSD
│ ├── streaming.py # MJPEG streams
│ └── api/
│ ├── __init__.py
│ ├── routes.py # All API routes
│ └── schemas.py # Pydantic models for config options
- Hootcam UI – Web frontend for this server (or for Hootcam Motion in the 3-part setup).
- Hootcam Streamer – RTSP-only streamer for the Pi; use with Hootcam Motion for the 3-part architecture.
- Hootcam Motion – NUC app that consumes RTSP and runs motion + recording + API; alternative to running everything on the Pi.
MIT