A CLI for managing IP cameras (Tapo, Reolink) via RTSP and vendor APIs
Project description
ipcam
A command-line tool for managing IP cameras (Tapo, Reolink) via RTSP and vendor APIs.
Features
- Capture snapshots from individual cameras or all cameras in parallel
- Assemble multi-camera snapshots into a single tiled grid image
- Record video clips and build timelapses using ffmpeg
- Print or pipe RTSP stream URLs (main and sub streams)
- Pan/tilt/zoom control via ONVIF (Tapo) or Reolink API
- Poll motion detection events and watch for status changes
- Health-check all cameras and run a hook command on status change
- End-to-end camera test (network reachability, RTSP URL, snapshot)
- Discover cameras on the local network via ONVIF WS-Discovery
- Interactive
initwizard that auto-discovers and configures cameras - Frigate NVR integration: list events and fetch latest snapshots
- go2rtc restream proxy support for cameras behind a proxy
- JSON output for every command (
--json) - Shell completions for bash, zsh, and fish
Installation
Prerequisites
Build and install
cargo install --path .
Quick Start
Run the interactive setup wizard to discover cameras on your network and generate a config file:
ipcam init
Or use --auto to skip prompts and generate a config from detected cameras:
ipcam init --auto
Once configured, a few common commands:
# List configured cameras
ipcam list
# Capture a snapshot
ipcam snapshot front-door
# Check all cameras are reachable
ipcam status
# Run an end-to-end test on all cameras
ipcam test
Configuration
The config file is TOML and lives at:
- macOS:
~/Library/Application Support/ipcam/config.toml - Linux:
~/.config/ipcam/config.toml
Run ipcam config to print the exact path on your system.
Example config
[go2rtc]
host = "192.168.1.10"
port = 8554 # default
[frigate]
host = "192.168.1.11"
port = 5001 # default
[[cameras]]
name = "front-door"
type = "reolink"
host = "192.168.1.101"
username = "admin"
password = "your-password"
[[cameras]]
name = "backyard"
type = "tapo"
host = "192.168.1.102"
username = "admin"
password = "your-password"
# Optional: override RTSP port (default: 554)
rtsp_port = 554
# Optional: override ONVIF port (default: 2020 for Tapo, 8000 for Reolink)
onvif_port = 2020
# Optional: use a go2rtc restream instead of direct RTSP
go2rtc_stream = "backyard"
# Optional: Frigate camera name if it differs from the config name
frigate_name = "backyard_cam"
Config fields
| Field | Required | Description |
|---|---|---|
name |
yes | Unique identifier used in all commands |
type |
yes | tapo or reolink |
host |
yes | IP address of the camera |
username |
no | Camera username (default: admin) |
password |
no | Camera password |
rtsp_port |
no | RTSP port (default: 554) |
onvif_port |
no | ONVIF port (default: 2020 for Tapo, 8000 for Reolink) |
go2rtc_stream |
no | go2rtc stream name when using a restream proxy |
frigate_name |
no | Frigate camera name (default: config name with - replaced by _) |
Commands
| Command | Description |
|---|---|
init |
Interactive setup wizard; discovers cameras via ONVIF and writes config |
list |
List all configured cameras |
info <camera> |
Show camera model and firmware (Reolink) or basic info (Tapo) |
snapshot <camera> |
Capture a JPEG snapshot |
snapshot --all |
Capture snapshots from all cameras in parallel |
snapshot --grid |
Capture from all cameras and tile into a single image |
snapshot --every <interval> |
Capture snapshots on a repeating interval |
snapshot-all |
Alias for snapshot --all |
stream <camera> |
Print the RTSP URL, or pipe to a file with --output |
record <camera> |
Record a video clip (default 30 s) |
timelapse <camera> |
Capture frames at an interval and encode to MP4 |
status [camera] |
Check which cameras are online and report latency |
test [camera] |
End-to-end test: network, RTSP URL, snapshot |
watch |
Poll camera health continuously; run a hook on status changes |
events <camera> |
Show motion detection status; use --watch to poll continuously |
ptz <camera> <action> |
Pan/tilt/zoom control: left, right, up, down, stop, preset |
discover |
Scan the network for ONVIF cameras |
frigate events |
List recent Frigate NVR events |
frigate snapshot <camera> |
Fetch the latest snapshot from Frigate |
config |
Show the config file path and whether it exists |
completions <shell> |
Print a shell completion script |
All commands accept --json for machine-readable output and --config <path> to override the config file location.
Examples
Snapshot
# Single camera, default filename (<camera>_<timestamp>.jpg)
ipcam snapshot front-door
# Single camera, custom output path
ipcam snapshot front-door --output /tmp/front.jpg
# All cameras saved to a directory
ipcam snapshot --all --output-dir /tmp/cams/
# Tiled grid of all cameras
ipcam snapshot --grid --output-dir /tmp/
# Capture every 5 minutes, save timestamped files
ipcam snapshot front-door --every 5m --output-dir /tmp/front-door/
Status and test
# Check all cameras
ipcam status
# Check a single camera
ipcam status front-door
# Full end-to-end test (network + RTSP + snapshot)
ipcam test
# Test a single camera, JSON output
ipcam test front-door --json
Watch
# Poll every 30 s, print status changes to stdout
ipcam watch
# Poll every minute, run a script on any status change
ipcam watch --interval 1m --exec 'notify-send "$CAMERA_NAME is $CAMERA_STATUS"'
The --exec command receives these environment variables:
| Variable | Value |
|---|---|
CAMERA_NAME |
Camera name from config |
CAMERA_HOST |
Camera IP address |
CAMERA_STATUS |
online or offline |
CAMERA_DETAIL |
Human-readable detail (model or error message) |
Timelapse
# 1-hour capture with a snapshot every 30 s, encoded to timelapse.mp4
ipcam timelapse front-door --interval 30s --duration 1h --output front-door.mp4
# Keep individual frames as well
ipcam timelapse front-door --interval 1m --duration 4h \
--output timelapse.mp4 --output-dir ./frames/
Shell completions
# zsh
ipcam completions zsh > ~/.zfunc/_ipcam
# bash
ipcam completions bash > /etc/bash_completion.d/ipcam
# fish
ipcam completions fish > ~/.config/fish/completions/ipcam.fish
PTZ control
# Pan left at speed 5 (default)
ipcam ptz backyard left
# Tilt up at speed 8
ipcam ptz backyard up --speed 8
# Go to preset position 1
ipcam ptz backyard preset 1
# Stop movement
ipcam ptz backyard stop
Supported Cameras
Tapo (TP-Link)
- Snapshots captured via ffmpeg over RTSP (sub-stream by default)
- PTZ control via ONVIF SOAP over HTTP (port 2020 by default)
- RTSP streams:
stream1(main),stream2(sub) - Motion detection: not supported (Tapo does not expose an API for this)
- Health check: TCP connect to the RTSP port
Reolink
- Snapshots fetched via the Reolink HTTP/JSON API (
/cgi-bin/api.cgi?cmd=Snap) - PTZ control via the Reolink
PtzCtrlAPI - Motion detection via
GetMdStateAPI - RTSP streams:
h264Preview_01_main(main),h264Preview_01_sub(sub) - Health check:
GetDevInfoAPI call (also returns model name) - Device info (model, firmware) available via
GetDevInfo
Integration
go2rtc
If your cameras are behind a go2rtc restream proxy, add a [go2rtc] section to your config and set go2rtc_stream on each camera. ipcam will use the proxy RTSP URL (rtsp://<host>:<port>/<stream>) instead of connecting to the camera directly.
Sub-stream URLs are constructed by appending _sub to the stream name (e.g. backyard_sub).
Frigate NVR
Add a [frigate] section to your config pointing at your Frigate instance. Then use the frigate subcommand:
# List the 20 most recent events across all cameras
ipcam frigate events --limit 20
# Filter by camera
ipcam frigate events --camera front_door
# Save the latest Frigate snapshot for a camera
ipcam frigate snapshot front_door --output /tmp/latest.jpg
Frigate camera names use underscores (e.g. front_door). Set frigate_name in the camera config if the name differs from your ipcam name.
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file ipcam-0.0.1.tar.gz.
File metadata
- Download URL: ipcam-0.0.1.tar.gz
- Upload date:
- Size: 4.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.6.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5c756617065bcac3fbee506e45b07a706ca59f0af97d4d1a646e70e2884c579b
|
|
| MD5 |
27f65522d82d1691f14bad432a1312ae
|
|
| BLAKE2b-256 |
9dfaa63cd9610fbd6cddd10067bafe20991a4511f4d8f13991b4d91eb14b7580
|
File details
Details for the file ipcam-0.0.1-py3-none-any.whl.
File metadata
- Download URL: ipcam-0.0.1-py3-none-any.whl
- Upload date:
- Size: 4.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.6.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
98d0da8f97ee62f1bd019530e5de1ffdf57785a0ed919ff3a3d6a400b6581caf
|
|
| MD5 |
0231f070bdd4761ca4ef262b3a65118a
|
|
| BLAKE2b-256 |
abb50b950a7f8eafe3cb763defac12c4c2d015c1c5de82cbf52fc296fa9a22f7
|