wildcam#
wildcam is a PyQt6-based multi-camera viewer optimized for parallel RTSP streams (e.g. Reolink).
Features#
- Multi-camera list + large preview (select a camera on the left)
- Per-camera controls
- Start/stop stream
- Start/stop recording
- Snapshot
- Edit/remove camera
- Auto-discovery (network scan)
- Recording & snapshots
- Default recordings folder:
~/Videos/Reolink - Snapshots are stored in
~/Videos/Reolink/snapshots
- Default recordings folder:
- Object detection alerts
- Uses Ultralytics YOLO when installed
- Automatically selects CUDA when PyTorch detects an NVIDIA GPU, otherwise CPU
- Can be enabled per camera from the camera tile
- Saves annotated detection snapshots and short event clips
- Can send optional SMTP email alerts with the detection image attached
- Includes a settings-page test mail button for SMTP checks
- UI language switch (German/English), stored in
camera_config.json
License#
WildCam is licensed under AGPL-3.0-or-later. The object detection integration uses Ultralytics YOLO, whose default open-source license is AGPL-3.0. If you distribute modified versions or run a network-accessible modified version, make the corresponding source available as required by the AGPL.
Requirements#
- Python 3.12 (tested)
- Dependencies listed in
requirements.txt
It is recommended to use a virtual environment (venv).
If you install dependencies via your distro packages (recommended in Docker/managed envs), ensure at least:
- PyQt6
- OpenCV (
cv2) - NumPy
- requests
Object detection is optional. WildCam installs Ultralytics YOLO / PyTorch on first use into the user's app-data directory instead of bundling it with the main app.
Run#
python3.12 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
python3 main.py
To preinstall the optional object-detection stack in a development environment:
pip install -r requirements-detection.txt
./start_wildcam.sh activates .venv/venv automatically. If no virtual
environment exists, it creates .venv; before starting WildCam it runs
python3 -m pip install -r requirements.txt so missing packages are installed.
Configure Cameras#
Reolink cameras: recommended setup#
WildCam supports two ways to connect Reolink cameras:
- Native RTSP (port 554)
- Works well for mains-powered cameras.
- ReolinkProxy (recommended for Reolink WLAN / battery cameras)
- Many Reolink WLAN/battery models use the Baichuan protocol (port 9000).
- WildCam will automatically:
- add/update
reolinkproxy.env - switch the stored RTSP URL to
rtsp://localhost:8554/<NAME>/mainStream - so the app uses the ReolinkProxy-proxied stream
- add/update
What gets stored where#
camera_config.json- What the app actually uses at runtime.
- After ReolinkProxy conversion, URLs look like:
rtsp://localhost:8554/D58/mainStream
reolinkproxy.env- Contains the real camera IP/credentials for port 9000 cameras.
- Example:
REOLINK_CAMERA_0_HOST="192.168.8.58"REOLINK_CAMERA_0_RTSP_PATH="D58/mainStream"
Quick start (recommended)#
./start_wildcam.sh
This will:
- Generate/extend
reolinkproxy.envbased oncamera_config.json - Start ReolinkProxy via Docker
- Start WildCam
Important:
- WildCam manages the ReolinkProxy configuration, but it does not embed the actual
reolinkproxyruntime. - For Reolink WLAN / battery cameras you still need a running ReolinkProxy instance, typically via
docker compose up -d. - For regular RTSP cameras on port 554, ReolinkProxy is not required.
Configuration File (camera_config.json)#
This app stores your local setup in camera_config.json.
You usually do not need to create this file manually:
- The app will create and update
camera_config.jsonautomatically when you add/edit/remove cameras via the GUI. - Auto-Discover results are stored there as well.
- Reordering cameras via drag & drop updates the stored order.
Manual editing is optional (e.g. to bulk-edit RTSP URLs or names).
- The file is gitignored because it can contain credentials inside RTSP URLs.
reolinkproxy.envis generated from this file and should not be edited as the primary configuration.- Use
camera_config.json.exampleas a safe template and create your local config from it.
Create your local config#
cp camera_config.json.example camera_config.json
Then edit camera_config.json and replace IPs / usernames / passwords.
Schema#
cameras- List of camera objects, in the exact order they appear on the left.
idmust be unique.urlis the RTSP URL.nameis the display name.detection_enabledenables object detection for that camera.proxyis optional and contains ReolinkProxy connection settings for battery/WLAN cameras.
recording_path- Target directory for recordings.
detection- Object detection settings.
device: "auto"uses CUDA when available and falls back to CPU.- Event snapshots are saved below
snapshots. - Event clips are saved below
events.
email- Optional SMTP alert settings.
- Disabled by default.
next_camera_id- Internal counter for assigning new IDs.
language- UI language (
deoren).
- UI language (
order_customfalse: default sort byidon startup.true: keep the stored order from the file (after you reorder via drag & drop).
Example snippet:
{
"cameras": [
{
"id": 1,
"url": "rtsp://localhost:8554/D54/mainStream",
"name": "D54",
"uid": "9527000000000000",
"proxy": {
"type": "reolinkproxy",
"host": "192.168.1.100",
"port": 9000,
"username": "admin",
"password": "password",
"stream": "main",
"battery": true,
"pause_on_client": true,
"idle_disconnect": true,
"idle_timeout": "30s"
}
}
],
"recording_path": "/home/USER/Videos/Reolink",
"detection": {
"model": "yolo11n.pt",
"imgsz": 640,
"confidence": 0.4,
"device": "auto",
"analysis_fps_per_camera": 3.0,
"stable_frames": 2,
"cooldown_seconds": 180,
"event_suppress_seconds": 30,
"event_clip_seconds": 30,
"pre_event_seconds": 8,
"post_event_seconds": 20,
"motion_required_classes": ["bicycle", "car", "motorcycle", "bus", "truck"],
"motion_min_pixels": 12.0,
"classes": ["person", "car", "truck", "dog", "cat", "bird"]
},
"email": {
"enabled": false,
"smtp_host": "",
"smtp_port": 587,
"smtp_username": "",
"smtp_password": "",
"use_tls": true,
"from": "",
"to": []
},
"next_camera_id": 2,
"language": "de",
"order_custom": false
}
Object Detection#
Detection is controlled through camera_config.json and each camera tile's
AI button.
The default model is yolo11n.pt, which is a small, fast model suitable for
multi-camera testing. For a GTX 1660 Ti, start with:
"analysis_fps_per_camera": 3.0,
"imgsz": 640,
"model": "yolo11n.pt"
When an object is detected for stable_frames consecutive analysis frames,
the per-camera/per-class cooldown_seconds has elapsed, and the camera-wide
event_suppress_seconds burst lock has elapsed, WildCam:
- saves an annotated JPEG snapshot in
~/Videos/Reolink/snapshots - starts an AVI event clip in
~/Videos/Reolink/events - sends an email with the image attached if
email.enabledistrue
event_clip_seconds controls the total event video length and is capped at
180 seconds. pre_event_seconds is included in that total length.
Classes listed in motion_required_classes only trigger an event when the
detected bounding box moves by at least motion_min_pixels between analyzed
frames. By default this is enabled for vehicle classes, so parked cars do not
create repeated alerts.
Pretrained COCO classes include person, vehicles, and common animals such as
dog, cat, bird, horse, sheep, and cow. Wild animals such as deer,
foxes, or boars usually need a custom fine-tuned model for reliable alerts.
Release builds do not bundle the Python detection libraries. When object detection is enabled or Install/test runtime/model is clicked for the first time, WildCam installs the optional runtime into the user's app-data directory:
Linux: ~/.local/share/wildcam/detection-runtime/py<version>
macOS: ~/Library/Application Support/WildCam/detection-runtime/py<version>
Windows: %LOCALAPPDATA%\WildCam\detection-runtime\py<version>
In standalone builds this requires a matching external Python with pip and
internet access. Linux installs CPU-only PyTorch wheels by default to avoid
bundling CUDA/NVIDIA libraries. YOLO model weights are resolved by Ultralytics
from the configured model name/path, so the first detection run must either be
able to download the model or point detection.model to a local weights file.
The Install/test runtime/model button stores known YOLO weights in:
<recording_path>/models
For the default path this is:
~/Videos/Reolink/models
Add camera manually#
- Enter the camera RTSP URL
- Optionally set a name
- Click Add
Example RTSP URL:
rtsp://admin:password@192.168.1.100:554/h264Preview_01_main
For Reolink WLAN / Baichuan (port 9000) you can also enter:
rtsp://admin:password@192.168.1.100:9000/h264Preview_01_main
WildCam will automatically:
- append/update the camera entry in
reolinkproxy.env - store the camera in
camera_config.jsonas:rtsp://localhost:8554/<NAME>/mainStream
Auto-discover#
Open Auto-Discover, choose your network (e.g. 192.168.1.0/24), enter credentials, and start the scan.
When you add found Reolink WLAN/battery cameras, WildCam will automatically:
- update
reolinkproxy.env - store
localhost:8554/...URLs incamera_config.json
ReolinkProxy is a proxy and does not magically discover/wake sleeping cameras. The camera still needs to be reachable (awake) for discovery and for ReolinkProxy to connect.
Important:
- WildCam writes and updates
reolinkproxy.env, but the actual ReolinkProxy must run separately. - The recommended setup in this repository is the Docker Compose stack from
docker-compose.yml.
Battery Cameras#
Automatic ReolinkProxy Setup#
WildCam includes automatic ReolinkProxy setup for battery cameras using port 9000 (Baichuan protocol).
This is handled in two places:
- The GUI automatically switches Reolink WLAN/Baichuan cameras to
rtsp://localhost:8554/...and appends the camera toreolinkproxy.env. - The startup script can start the ReolinkProxy container for you.
Quick Start#
# 1. Start WildCam with automatic ReolinkProxy setup
./start_wildcam.sh
What it does:
- ✅ Detects battery cameras (port 9000) in
camera_config.json - Auto-generates
reolinkproxy.envconfiguration - Starts ReolinkProxy Docker container
- ✅ The app stores/uses
rtsp://localhost:8554/...URLs for these cameras
Manual Setup#
If you prefer manual control:
# 1. Generate reolinkproxy.env from your camera config
python3 reolinkproxy_manager.py --auto-update
# 2. Start ReolinkProxy container
docker compose up -d
# 3. Check ReolinkProxy logs
docker logs wildcam-reolinkproxy
# 4. Start WildCam
python3 main.py
If you distribute WildCam as a standalone build:
- the bundle can include
docker-compose.yml,reolinkproxy_manager.py,camera_config.json.example, and the app itself reolinkproxy.envis not bundled because it is generated locally and can contain credentials- but it still does not include the external ReolinkProxy container/image
- users who rely on Reolink battery / Baichuan cameras still need Docker/Compose or a separately installed
reolinkproxy
How it Works#
1. Detection:
The script scans camera_config.json for cameras using port 9000:
{
"id": 7,
"url": "rtsp://admin:password@192.168.8.58:9000/h264Preview_01_main",
"name": "ArgusCamera",
"uid": "9527000KVKX2161S"
}
2. ReolinkProxy Config Generation:
Creates reolinkproxy.env automatically:
REOLINK_CAMERA_0_NAME="ArgusCamera"
REOLINK_CAMERA_0_HOST="192.168.8.58"
REOLINK_CAMERA_0_PORT=9000
REOLINK_CAMERA_0_USERNAME="admin"
REOLINK_CAMERA_0_PASSWORD="password"
REOLINK_CAMERA_0_UID="9527000KVKX2161S"
REOLINK_CAMERA_0_RTSP_PATH="ArgusCamera/mainStream"
REOLINK_CAMERA_0_BATTERY_CAMERA=true
REOLINK_CAMERA_0_PAUSE_ON_CLIENT=true
REOLINK_CAMERA_0_IDLE_DISCONNECT=true
3. URL Conversion (Optional): Updates camera URLs to use ReolinkProxy:
Before: rtsp://admin:password@192.168.8.58:9000/...
After: rtsp://localhost:8554/ArgusCamera/mainStream
Stopping ReolinkProxy#
docker compose down
Recording / Snapshots#
- Recording writes MP4 files to the selected storage directory.
- Snapshot saves a JPG from the last received frame.
Build (Standalone Binaries)#
The repository contains helper scripts using PyInstaller.
Note about ReolinkProxy:
- The packaged app bundles WildCam and helper files such as
docker-compose.ymlandreolinkproxy_manager.py. - The actual ReolinkProxy runtime is not bundled into the app archive.
- The optional object-detection runtime is not bundled into the app archive; it is installed on first use.
- If you use only normal RTSP cameras, the standalone app is enough.
- If you use Reolink WLAN / battery cameras, you must additionally run ReolinkProxy externally.
Linux#
bash scripts/build_linux.sh
Output:
- Binary:
dist/wildcam - Zip archive:
dist/wildcam_linux_<timestamp>.zip
Windows (PowerShell)#
scripts\build_windows.ps1
Or via CMD wrapper:
scripts\build_windows.cmd
Output:
- EXE:
dist\wildcam.exe - Zip archive:
dist\wildcam_windows_<timestamp>.zip