Skip to main content

HomeSec

PyPI License: Apache 2.0 Python: 3.10+ Typing: Typed codecov

HomeSec is a self-hosted, extensible video pipeline for home security cameras. You can connect cameras directly via RTSP, receive clips over FTP, or watch a local folder. The pipeline uploads clips, detects objects, optionally runs VLM analysis, and sends policy-driven notifications. Configuration determines which local or cloud services receive footage and alerts.

The behavior reference links the maintained public specifications, operator guides, and known limitations.

Design Principles

  • Operator-controlled destinations: Choose local or Dropbox storage and configure the analyzer endpoint and notification backends. The supplied example selects Dropbox and OpenAI; review those choices before running it.
  • Modular Architecture: All major components (sources, filters, analyzers, notifiers) are decoupled plugins defined by strict interfaces. If you want to use a different AI model or storage backend, you can swap it out with a few lines of Python.
  • Resilience: Recording and uploads can continue when Postgres is unavailable. Reconnect and stage retries have explicit limits; see the known limitations before relying on recovery behavior.

Pipeline at a glance

graph TD
    %% Layout Wrapper for horizontal alignment
    subgraph Wrapper [" "]
        direction LR
        style Wrapper fill:none,stroke:none
        
        S[Clip Source]
        
        subgraph Pipeline [Media Processing Pipeline]
            direction TB
            C(Clip File) --> U([Upload to Storage])
            C --> F([Detect objects: YOLO])
            F -->|Filter succeeds| AI{VLM run mode and trigger classes}
            AI -->|Analyze| V([VLM Analysis])
            AI -->|Skip| P{Alert Policy}
            V --> P
            U --> P
            P -->|Notify| N[Notifiers]
        end
        
        S -->|New Clip File| Pipeline
        
        PG[(Postgres)]
        Pipeline -.->|State & Events| PG
    end
  • Parallel Processing: Upload and filter run in parallel.
  • Resilience: Upload failures do not block alerts; filter failures stop expensive VLM calls.
  • State: Postgres stores current clip snapshots and best-effort lifecycle history (clip_states + clip_events). These writes are separate; a stored snapshot does not prove complete event history or recovery after a process restart.

Table of Contents

Highlights

  • Multiple pluggable video clip sources: RTSP motion detection, FTP uploads, or a watched folder
  • Parallel upload + filter (YOLO) with frame sampling and early exit
  • OpenAI-compatible VLM analysis with structured output
  • Policy-driven alerts with per-camera overrides
  • Fan-out notifiers (MQTT for Home Assistant, SendGrid email)
  • Postgres-backed state + events with graceful degradation
  • Health endpoint plus optional Postgres telemetry logging
  • Push-to-talk for RTSP cameras with ONVIF audio backchannel support and a local TP-Link Tapo talkback backend path

Quickstart

Docker

From a repository checkout, use the included docker-compose.yml for HomeSec and Postgres:

cp config/example.yaml config/config.yaml
cp .env.example .env
# Edit both files for your cameras, storage, analyzer, and credentials.
# Comment out the local-development DB_DSN line in .env for Compose.
docker compose up -d

Compose mounts config/config.yaml at /config/config.yaml and .env at /config/.env; its application image is leva/homesec:latest. It publishes HTTP on port 8081 and WebRTC UDP on 8189–8199. For preview reachability, helper requirements, and persistent media paths, follow the deployment guide.

Compose supplies a database DSN using its postgres service hostname. The entrypoint sources the mounted .env afterward, so the example's active DB_DSN pointing at localhost would override that value inside the container. Comment out that line for Compose, or deliberately set a container-reachable database DSN.

Manual Setup

For standard production usage without Docker Compose:

  1. Prerequisites:

    • Python 3.10+
    • ffmpeg and ffprobe
    • PostgreSQL (running and accessible, with HomeSec's migrations applied)
    • For enabled native media features, the separately built helper described in native setup
  2. Install

    pip install homesec
    
  3. Configure

    # Download example config & env
    curl -O https://raw.githubusercontent.com/lan17/homesec/main/config/example.yaml
    mv example.yaml config.yaml
    
    curl -O https://raw.githubusercontent.com/lan17/homesec/main/.env.example
    mv .env.example .env
    
    # Setup environment (DB_DSN is required)
    # Edit .env to set your secrets!
    export DB_DSN="postgresql+asyncpg://user:pass@localhost:5432/homesec"
    
  4. Prepare the schema and validate Run the Alembic migrations from a matching release's repository checkout with the same exported DB_DSN:

    python -m alembic -c alembic.ini upgrade head
    homesec validate --config config.yaml
    

    The CLI run command does not apply migrations. Configuration validation does not prove camera, provider, or database connectivity.

  5. Run

    homesec run --config config.yaml
    

Developer Setup

If you are contributing or running from source:

  1. Install tools and build dependencies Follow the developer prerequisites, then run:

    make dev-setup
    

    This installs locked Python/UI dependencies and builds the native helper and UI. It does not start Postgres or HomeSec.

  2. Configure and start infrastructure Copy and edit config/example.yaml as config/config.yaml and .env.example as .env. Keep the local-development DB_DSN for this host-run setup, then:

    make db  # Starts just Postgres in Docker
    
  3. Run

    make run
    

    make run applies database migrations before starting; migration failure stops this command. The Docker entrypoint instead warns and continues after a failed migration, so check container logs and schema readiness during upgrades.

Configuration

Configuration is YAML-based and validated against core and plugin models. Reference secrets through environment-variable names (*_env) rather than putting credentials in YAML. The examples below are fragments to merge into a complete configuration.

Configuration Examples

1. RTSP camera with reconnects

Configure connection timeouts and an unlimited retry budget for a camera that can become temporarily unavailable.

cameras:
  - name: driveway
    source:
      backend: rtsp
      config:
        rtsp_url_env: DRIVEWAY_RTSP_URL
        output_dir: "./recordings"
        stream:
          connect_timeout_s: 2.0
          io_timeout_s: 2.0
        reconnect:
          backoff_s: 5
          max_attempts: 0  # Retry indefinitely

filter:
  backend: yolo
  config:
    classes: ["person", "dog"]
    min_confidence: 0.6

In your .env:

DRIVEWAY_RTSP_URL="rtsp://user:pass@192.168.1.100:554/stream"

2. The "Cloud Storage" (Dropbox)

Selects Dropbox storage and an email notifier. Analyzer behavior is configured separately under vlm.

storage:
  backend: dropbox
  config:
    token_env: DROPBOX_TOKEN
    root: "/SecurityCam"

notifiers:
    - backend: sendgrid_email
      config:
        api_key_env: SENDGRID_API_KEY
        from_email: "alerts@example.com"
        to_emails: ["me@example.com"]

In your .env:

DROPBOX_TOKEN="sl.Al..."
SENDGRID_API_KEY="SG.xyz..."

See config/example.yaml for a starting configuration. The core models and each plugin's configuration model define supported settings and defaults.

Tips

  • Secrets: Never put secrets in YAML. Use env vars (*_env) and set them in your shell or .env.
  • Notifiers: Notifiers are optional. With no enabled notifiers, alert decisions are still evaluated and recorded, but no external notifications are sent.
  • YOLO classes: The current filter allowlist is person, bird, cat, dog, horse, sheep, cow, elephant, bear, zebra, and giraffe. Other names are ignored when building target class IDs; an all-unsupported list fails detection. A name appearing in the model's COCO labels does not make it supported by this filter.
  • Live preview: Rust WebRTC is the default backend and shares one preview input per camera to deliver H.264/Opus directly to viewers. Preview remains disabled until enabled in config; set preview.config.advertised_ip to the HomeSec server's client-reachable LAN/VPN IP before enabling it. See docs/webrtc-preview.md for native helper installation and UDP reachability. Existing HLS configurations remain supported; select preview.backend: hls and keep its scratch storage on tmpfs separate from recordings and durable storage. Preview defaults to recording_policy: stop_on_recording; allow_during_recording is best-effort and may consume an extra RTSP session. See docs/preview-deployment.md.
  • Push-to-talk: Browser microphone to camera speaker support is auto-probed for RTSP cameras by default. HomeSec tries standards-based backends first; the bundled ONVIF backend supports PCMU/8000 and PCMA/8000, and the bundled tapo_local backend implements a local TP-Link Tapo talkback path without TP-Link cloud calls at runtime. Auto mode keeps ONVIF ahead of Tapo, then can identify Tapo from persisted ONVIF identity metadata or passive local endpoint discovery for manual RTSP cameras. Use cameras[].talk.backend: onvif_rtsp_backchannel or cameras[].talk.backend: tapo_local for explicit selection. Tapo local talk defaults to username admin, can derive host and password material from the RTSP URL, and can use explicit backend env vars when credentials differ. Opt out cameras with cameras[].talk.mode: disabled when needed. Physical Tapo C120 compatibility still needs per-firmware validation. See docs/push-to-talk.md.

After installation, the homesec command is available:

homesec --help

Commands

Run the pipeline:

homesec run --config config.yaml

Validate config:

homesec validate --config config.yaml

Cleanup old clips (reanalyze and optionally delete empty clips):

homesec cleanup --config config.yaml --older_than_days 7

Cleanup defaults to a dry run. Inspect its output before explicitly applying with --dry_run=False. It rechecks eligible clips using the YOLO-shaped cleanup configuration, deletes storage objects before marking records deleted, and can also remove a separate local recording. It is distinct from automatic retention and API deletion; review the cleanup limitations.

Use homesec <command> --help for detailed options on each command.

Plugins

Extensible by design

We designed HomeSec to be modular. Each major capability is an interface (ClipSource, StorageBackend, ObjectFilter, VLMAnalyzer, AlertPolicy, Notifier) defined in src/homesec/interfaces.py. This means you can swap out components (like replacing YOLO with a different detector) without changing the core pipeline.

Built-in plugins are registered by decorators when their modules are imported. External packages can participate through the homesec.plugins entry-point group.

Built-in plugins

Type Plugins
Sources rtsp, ftp, local_folder
Filters yolo
Storage dropbox, local
VLM analyzers openai
Notifiers mqtt, sendgrid_email
Alert policies default, noop

Plugin interfaces

All interfaces are defined in src/homesec/interfaces.py.

Type Interface PluginType for @plugin
Sources ClipSource SOURCE
Filters ObjectFilter FILTER
Storage StorageBackend STORAGE
VLM analyzers VLMAnalyzer ANALYZER
Notifiers Notifier NOTIFIER
Alert policies AlertPolicy ALERT_POLICY

Writing a custom plugin

Extending HomeSec is designed to be easy. You can write custom sources, filters, storage backends, and more.

👉 See PLUGIN_DEVELOPMENT.md for a complete guide.

Observability

  • Public health: GET /health and /api/v1/health, served on server.host/server.port. A running pipeline with unavailable Postgres reports degraded with HTTP 200; stopped/stale runtime health reports HTTP 503. Bootstrap mode reports setup_required with HTTP 200.
  • Telemetry: DB_DSN enables the separate Postgres log handler. It classifies a truthy event_type or kind="event" as event telemetry; ordinary logs use DB_LOG_LEVEL, with warnings/errors also admitted. The bounded background queue and failed batch writes can lose records. Telemetry is best-effort and does not replace ClipRepository state/history.
  • Log hygiene: the handler serializes messages, extras, and exception text; it is not a universal secret scrubber. Keep credentials, tokens, raw media, and full DSNs out of log calls and troubleshooting captures. See logging guidance.

Development

Setup

  1. Clone the repository
  2. Install uv for dependency management
  3. make dev-setup to install locked dependencies and build the UI/native helper
  4. Copy and edit config/config.yaml and .env as described in Developer Setup
  5. make db to start Postgres locally

Commands

  • Run tests: make test
  • Run type checking (strict): make typecheck
  • Run the full Rust/Python/UI gate: make check
  • Check Python lint/types and lockfile without running application tests: make lint typecheck lock-check
  • Run the pipeline: make run

Notes

Contributing

Contributions are welcome! Here's how to get started:

  1. Fork and clone the repository
  2. Create a branch for your feature or fix: git checkout -b my-feature
  3. Install dependencies: uv sync
  4. Make your changes and ensure tests pass: make check
  5. Submit a pull request with a clear description of your changes

Guidelines

  • All code must pass CI checks: make check
  • Tests should include Given/When/Then comments explaining the test scenario
  • New plugins should follow the existing patterns in src/homesec/plugins/
  • Keep PRs focused on a single change for easier review

Reporting Issues

Found a bug or have a feature request? Please open an issue with:

  • A clear description of the problem or suggestion
  • Steps to reproduce (for bugs)
  • Your environment (OS, Python version, HomeSec version)

License

Apache 2.0. See LICENSE.

Metadata

Release files for homesec 1.12.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for homesec 1.12.0
File Size Uploaded Provenance
homesec-1.12.0.tar.gz 2.2 MB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for homesec 1.12.0
File Interpreter ABI Platform
homesec-1.12.0-py3-none-any.whl Python 3 none any Details

Total release size: 2.5 MB

Release files / homesec-1.12.0.tar.gz

Download URL homesec-1.12.0.tar.gz
Size 2.2 MB
Tags Source
SHA-256 checksum
How to use checksums
43f549806a7541658f19f93d3ef0948323bb937c9a714f7e2fa8a7c726b2c28a
BLAKE2b-256 checksum
How to use checksums
cd609eb813c77bcfc87d2dc24fbef6f832dc57ee18835b508e6defb6fb7a7b24
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 18, 2026.

Transparency log

Release files / homesec-1.12.0-py3-none-any.whl

Download URL homesec-1.12.0-py3-none-any.whl
Size 354.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
51c2b32048b51d58458e89cc662fbe1b6ba518775e545e3d124a037ba126fc1f
BLAKE2b-256 checksum
How to use checksums
6c5d05b9c605a81675b90fc432f3264bf6fa790833d6baac67118f0767c0e770
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 18, 2026.

Transparency log

Security for homesec 1.12.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for homesec-1.12.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 18, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page