Captures RTSP camera streams, splits them into fixed-duration chunks, and uploads them to S3 (or any S3-compatible provider) using rclone.
- Multiple cameras run concurrently, each in its own thread
- Uses ffmpeg for RTSP capture and segmentation
- Uses rclone for uploads — swap storage providers without changing code
- Failed uploads are retried with exponential backoff; chunks are kept locally until confirmed uploaded
- Configured via a YAML file (cameras) and a
.envfile (credentials)
The following tools must be installed and available on your PATH:
- Python 3.12+ — python.org
- ffmpeg — ffmpeg.org
- rclone — rclone.org/install
Verify they are available:
python --version
ffmpeg -version
rclone --versiongit clone <repo-url>
cd vybe-camera-agentLinux / macOS:
python3 -m venv .venv
source .venv/bin/activateWindows (Command Prompt):
python -m venv .venv
.venv\Scripts\activate.batWindows (PowerShell):
python -m venv .venv
.venv\Scripts\Activate.ps1pip install -r requirements.txtcp .env.example .envEdit .env and fill in your storage credentials. The variables follow rclone's environment variable convention — the remote name prefix must match rclone_remote in config.yaml (uppercased):
RCLONE_CONFIG_S3VYBE_TYPE=s3
RCLONE_CONFIG_S3VYBE_PROVIDER=AWS
RCLONE_CONFIG_S3VYBE_ACCESS_KEY_ID=YOUR_KEY
RCLONE_CONFIG_S3VYBE_SECRET_ACCESS_KEY=YOUR_SECRET
RCLONE_CONFIG_S3VYBE_REGION=eu-central-1Edit config.yaml:
chunk_duration_seconds: 60 # Length of each recorded segment
temp_dir: /tmp/vybe-camera-agent # Local staging directory for chunks
rclone_remote: s3vybe # Must match the prefix in your .env (lowercased)
s3_bucket_path: my-bucket/recordings
cameras:
- label: entrance
rtsp_url: rtsp://admin:password@192.168.1.10:554/stream1
- label: parking
rtsp_url: rtsp://admin:password@192.168.1.11:554/stream1Uploaded files will be stored at:
<rclone_remote>:<s3_bucket_path>/<camera_label>/<timestamp>.mp4
python main.pyStop with Ctrl+C — the agent will finish the current upload queue before exiting.
vybe-camera-agent/
├── main.py # Entry point
├── config.yaml # Camera list and global settings
├── .env.example # Credential template (copy to .env)
├── requirements.txt
├── src/
│ ├── config_loader.py # Loads and validates config.yaml + .env
│ ├── camera_worker.py # Per-camera ffmpeg thread with auto-reconnect
│ └── uploader.py # rclone upload with exponential backoff retry
├── Dockerfile
├── docker-compose.yml
└── deploy/
├── systemd/ # Linux auto-start (systemd service)
├── windows/ # Windows auto-start (Task Scheduler XML)
└── macos/ # macOS auto-start (launchd plist)
Build and start:
docker compose up --buildRun in the background:
docker compose up --build -dThe container uses restart: unless-stopped, so it will automatically restart after a system reboot as long as the Docker daemon is running.
sudo cp deploy/systemd/vybe-camera-agent.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable vybe-camera-agent
sudo systemctl start vybe-camera-agent
# View logs
sudo journalctl -u vybe-camera-agent -fRun as Administrator:
schtasks /create /xml deploy\windows\task-scheduler.xml /tn "Vybe Camera Agent"Or open Task Scheduler → Action → Import Task → select the XML file.
Update the WorkingDirectory inside the XML to match your installation path before importing.
cp deploy/macos/com.vybe.camera-agent.plist ~/Library/LaunchAgents/
launchctl load ~/Library/LaunchAgents/com.vybe.camera-agent.plist
# View logs
tail -f /tmp/vybe-camera-agent.stdout.log
tail -f /tmp/vybe-camera-agent.stderr.log