TBC is a modular, Docker-based camera manager. Camera vendors are integrated through installable camera modules. Reolink, Aqara, TP-Link/Tapo, Axis, Foscam, Hikvision, Dahua (including Amcrest/Annke OEM devices), Ubiquiti/UniFi Protect, and SONOFF are available as directly installable standard repositories. A generic ONVIF fallback and a vendor-neutral RTSP-only profile remain built in.
The application includes authentication, camera management, RTSP stream discovery, dashboard snapshots, event-based and continuous recording, clip and SD-card browsers, user roles, MQTT and Home Assistant integration, live HLS with an optional sub-second WebRTC alternative (go2rtc), retention rules, notifications, health monitoring, AI detection, and NVR channel management.
English is the default interface language. Afrikaans, Bulgarian, German, Spanish, French, Dutch, Polish, and Portuguese can be selected from the language menu.
cp .env.example .env
docker compose up --buildOpen the web interface at http://localhost:8732.
Default values from docker-compose.yml:
- Username:
admin - Password:
bitte-aendern - Web port:
8732 - Database:
/data/tbc.sqlite3in thetbc-dataDocker volume - Recordings:
/recordingsin thetbc-recordingsDocker volume - Live HLS buffer:
/tmp/tbc-live - Imported camera plugins:
/data/camera-modules - Imported cloud plugins:
/data/cloud-modules - Imported design themes:
/data/design-themes - Dashboard snapshots:
/data/dashboard-snapshots, refreshed every 600 seconds by default
Change TBC_ADMIN_PASSWORD and TBC_SECRET_KEY in .env before using TBC outside a test environment. Set TBC_PUBLIC_BASE_URL when webhooks or Home Assistant notifications should include links to clips and snapshots.
Every tagged release also publishes a multi-arch (amd64/aarch64) image to GHCR, so docker compose up --build above can be skipped in favor of a plain pull - useful for Swarm stacks too, which ignore local build instructions:
docker pull ghcr.io/404gamernotfound/tbc-camera-manager:latest
docker run -d --name tbc-camera-manager -p 8732:8732 \
-e TBC_ADMIN_PASSWORD=<strong-password> -e TBC_SECRET_KEY=<long-random-string> \
-v tbc-data:/data -v tbc-recordings:/recordings \
ghcr.io/404gamernotfound/tbc-camera-manager:latestOr point docker-compose.yml at it directly by replacing its image:/build: lines with image: ghcr.io/404gamernotfound/tbc-camera-manager:latest and removing build: .. Tags follow the release: latest, <major>.<minor>, and the exact <version> (e.g. 0.7.0).
The pull-count badge above (via the third-party ghcr-badge service) counts image pulls, not unique installs - CI runs, image updates, and re-pulls all add up, and it only covers this plain Docker image, not the separate Home Assistant app images.
This repository is also a Home Assistant app repository. In Home Assistant, open Settings → Apps → App store, open the repository menu, and add:
https://github.com/404GamerNotFound/TBC-camera-manager
The app uses the same application image as the regular Docker deployment and supports amd64 and aarch64. Application data is stored in the private Home Assistant app directory, while recordings are written to /media/tbc-camera-manager. Set an administrator password in the app configuration before the first start.
See tbc_camera_manager/DOCS.md for configuration options, persistence, MQTT, and implementation details.
Portainer should build this project as a standalone stack from its Git repository. The Compose stack contains build: .; pasting only the Compose file into the web editor omits the Dockerfile, application code, and requirements.txt from the build context.
-
Open
Stacksin Portainer and selectAdd stack. -
Select
RepositoryorGit repositoryas the build method. -
Enter the repository URL and branch, and use
docker-compose.ymlas the Compose path. -
Configure at least:
TBC_ADMIN_USERNAME=admin TBC_ADMIN_PASSWORD=<strong-password> TBC_SECRET_KEY=<long-random-string> TBC_PORT=8732 -
Optionally set
TBC_PUBLIC_BASE_URL=https://your-hostname. -
Deploy the stack and open
http://<docker-host>:8732.
Do not deploy it as a Swarm stack unless you use a prebuilt registry image, because Docker Swarm ignores local build instructions. Add bind mounts to docker-compose.yml when recordings should be stored on a NAS or host directory, then register the container path under Storage in TBC.
Add camera first asks whether the camera is local or comes from a cloud account.
- A local camera is configured with an installed camera module, host/IP, ports, and credentials.
- A cloud account connects to a vendor account and discovers its cameras automatically.
The selected module determines which vendor API is queried and which capabilities are exposed.
The web interface and camera routes use a vendor-independent CameraModule interface. Modules declare support for live view, event recording, detections, multi-channel devices, controls, firmware operations, and camera archives.
Camera plugin ZIP files can be imported and exported under Admin → Camera plugins. Imported packages are persisted under TBC_CAMERA_MODULES_PATH and become available immediately. Standard public repositories can be registered under Admin → External sources. See docs/plugin-sources.md and docs/camera-modules.md.
Existing databases are migrated automatically. Legacy cameras are assigned the reolink module.
Notable profiles:
standard_onvifuses only ONVIF device information, media profiles, event definitions, and stream URIs reported by the camera.rtsp_onlyaccepts a complete RTSP/RTSPS URL and skips ONVIF entirely.tplinksupports TP-Link/Tapo cameras through ONVIF Profile S and RTSP, with ONVIF port2020and RTSP port554as defaults.aqarachecks ONVIF-compatible Aqara cameras on port5000and the local RTSP channel/ch1on port8554.axis,foscam,hikvision, anddahuause ONVIF and vendor-typical RTSP fallbacks. The Dahua module also covers common Amcrest and Annke OEM devices.ubiquitiandsonoffuse complete stream URLs generated by UniFi Protect or eWeLink.
Credentials embedded in RTSP/RTSPS URLs are always rendered as ***:*** in forms, status messages, and detail views.
Cloud plugins are separate from camera modules. A cloud plugin signs in once, lists the cameras associated with the account, and imports selected devices as regular TBC cameras. Imported cameras then use the same live-view and control infrastructure as local cameras.
Cloud plugins are managed under Admin → Cloud providers; actual accounts are managed from the camera setup flow. Providers may request a verification code through a dedicated 2FA page.
The standard repositories include:
unifi_protectfor local controllers and theui.comcloud consoleeufywith email verification-code supportewelinkfor the official CoolKit Open Platform APIgooglefor Nest cameras/doorbells via the official Smart Device Management API (inventory only - no stream URL, see docs/cloud-accounts.md)
Public GitHub repositories can be registered as plugin sources instead of uploading ZIP files manually. Synchronization downloads and validates the current branch, tag, or subdirectory through the same safety checks as uploaded packages. TBC checks registered sources hourly by comparing commit SHAs and lists available updates under Admin → Updates.
Camera and cloud plugins may include a tests/ directory. These tests can be run directly from the corresponding plugin administration page. Ready-to-install templates are available for camera plugins, cloud plugins, and themes.
Design themes are isolated packages containing a manifest, stylesheets, metadata, and images, but no executable code. TBC ships with standard and midnight. Theme ZIP files can be imported, exported, activated, and removed under Admin → Design.
Imported themes are persisted under TBC_THEME_MODULES_PATH. Built-in themes cannot be overwritten or removed, and the active theme cannot be removed. See docs/design-themes.md.
For each enabled camera with a known stream, TBC uses ffmpeg to generate a JPEG preview. The protected cache is refreshed at the configured interval. The snapshot route applies the same authentication and per-camera authorization checks as detail and live views.
Configure the location and interval with TBC_DASHBOARD_SNAPSHOTS_PATH and TBC_DASHBOARD_SNAPSHOT_INTERVAL_SECONDS.
TBC supports event recordings and continuous recording. Configurable values include the storage destination, minimum duration, pre-roll, post-roll, cooldown between clips, snapshots/thumbnails, and event types.
Recordings use the discovered RTSP stream and ffmpeg. Storage destinations can be:
- A local or mounted container path such as
/recordingsor/recordings/nas - S3-compatible object storage with endpoint, region, bucket, prefix, access key, and secret key
The clip browser supports filtering, playback, download, and administrator deletion. Local clips are served from the container; S3 clips use temporary presigned URLs.
For supported cameras, the SD card area reads recordings directly from the camera or NVR. Reolink archive access uses the VOD API from reolink-aio for search, playback, and download.
Users can filter by camera, channel, stream, and date. Viewer accounts see only archives belonging to assigned cameras. Camera-side files are not imported into the TBC recording table and are not affected by TBC retention rules.
TBC starts an authenticated HLS proxy through ffmpeg for each camera or NVR channel. Playback uses the built-in video-player.js and the bundled hls.js.
Supported controls include play, mute, fullscreen, recording scrubbing, and optional PTZ overlays. The live wall supports kiosk fullscreen, focused camera view, configurable grid density, per-tile sizing, drag-and-drop ordering, and optional page rotation.
HLS has a 5-10 second glass-to-glass delay, which is fine for a quick check but too slow for "who's at the door right now". TBC bundles go2rtc as an optional, self-managed alternative that delivers sub-second WebRTC live view.
- Enable it:
Admin → Live → Layouthas an "Enable WebRTC (go2rtc)" checkbox. Toggling it starts or stops the bundled go2rtc process immediately, no restart required. An in-app, translated explanation of the HLS vs. WebRTC tradeoffs (available in English, German, Spanish, French, and Portuguese) sits right next to the checkbox. - Choose it: once enabled by an admin, every viewer gets a per-camera HLS/WebRTC switch on the live wall. The choice is remembered per browser (
localStorage), so different viewers can make different tradeoffs on the same tile. A tile that fails to reach a connected WebRTC state within 5 seconds - or drops later - automatically falls back to HLS. - Networking: go2rtc's own HTTP API stays bound to
127.0.0.1inside the container and is never exposed. Only its WebRTC media port,8555/tcp+udp, is published (seedocker-compose.ymland the Home Assistant add-on manifest) and only needs to be reachable by clients actually using WebRTC.
Local AI detection can identify people, vehicles, and animals independently of events reported by the camera. CPU is supported by default; separately built images can provide CUDA or Coral Edge TPU runtimes. Per-camera settings include backend, sample rate, confidence threshold, event triggers, and inclusion, exclusion, or loitering zones.
See Dockerfile.gpu, Dockerfile.coral, and the in-app AI detection page for runtime requirements.
Administrators can create retention rules globally, per camera, or per event type. Rules may delete recordings after a maximum age or when a size limit is exceeded. Storage destinations can also define their own age and size limits.
The storage explorer shows free space, usage by camera and event, and a cleanup preview. The same preview logic is used by manual cleanup and the hourly background cleanup.
Notification channels include webhooks, Telegram, SMTP email, Pushover, and Home Assistant Notify. Channels can include snapshots and public clip links where supported, and can be restricted with a comma-separated event filter such as:
recording_finished,recording_failed,cleanup_finished,health_status_changed
Health checks cover camera probe status, stream readability through ffprobe, local storage destinations, and MQTT connectivity. Status changes are stored as health events. Checks run in the background and can also be triggered from the web interface.
When a module reports multiple channels, TBC stores them individually. Channels can be renamed, disabled, and started independently in live view. Disabled channels do not produce active detections or recordings. Camera controls retain their channel association.
admincan manage cameras, storage, MQTT, users, plugins, settings, and recordings.viewercan access only explicitly assigned cameras and their recordings.
TBC publishes camera and detection states under the configured MQTT topic prefix and can publish Home Assistant discovery messages, including instant per-detection motion binary_sensors and PTZ/light/siren controls where the camera module supports them. Recording events such as recording_started, recording_finished, and recording_failed are also published.
The REST API and MCP interface are configured under Admin → API access. See docs/api.md and docs/mcp.md. A token created there with Allow control checked can also change camera/detection settings and start a live stream through the API - the basis for the integration below.
For a richer Home Assistant experience - camera entities with live streaming, last-motion sensors, storage/health sensors, and switches to view and adjust camera settings from HA - install the official TBC Home Assistant integration (a HACS-installable custom component, complementary to the MQTT discovery feature above).
- Web server: FastAPI with Jinja2 templates
- Persistence: SQLite, normally at
/data/tbc.sqlite3 - Authentication: signed cookie sessions and PBKDF2-SHA256 password hashes
- ONVIF:
onvif-zeepfor device, media, and event probes - Reolink:
reolink-aiofor model-specific AI state, PTZ presets, archives, and firmware operations - Recording:
ffmpeg, pre-roll ring-buffer segments, and optionalboto3S3 uploads - Live view: authenticated HLS playlists and segments generated by
ffmpeg, plus an optional bundledgo2rtcprocess for WebRTC (WHEP signaling proxied through an authenticated route; media flows directly between browser and go2rtc on port8555) - Snapshots: atomic JPEG replacement managed by
DashboardSnapshotManager - Debug log: in-memory ring buffer for application and
ffmpegmessages - Retention:
app/tbc/maintenance.py - Notifications:
app/tbc/notifications.py - Health monitoring:
app/tbc/health.py - MQTT:
paho-mqttwith optional Home Assistant discovery - Deployment: Dockerfile, Docker Compose, and Home Assistant app packaging
- Health endpoint:
/healthz
The complete documentation is maintained in docs/ and is also available from
the Docs link in the footer of a running TBC instance. It includes the user guide, operations,
deployment, API/MCP references, and plugin-development contracts.
pytest -q
python -m unittest discover -s tests
python -m compileall app tests
docker compose configRun pytest -q --cov --cov-report=term-missing (needs pytest-cov, see
.github/requirements-ci.txt) to see per-file coverage; CI enforces a
50% floor via --cov-fail-under=50 (see .coveragerc for scope/exclusions).
TBC is licensed under the MIT License.







