Skip to main content

Conversational query layer for CCTV systems — ask your cameras anything in plain English

Project description

cctvQL

Ask your CCTV system anything in plain English.

License: MIT Python CI codecov PyPI Docker PRs Welcome CodeQL

cctvQL is an open-source conversational query layer for CCTV and surveillance systems. It wraps any camera system — Frigate, ONVIF, Hikvision, Dahua and more — with a natural language interface powered by local or cloud LLMs.

Quick Start · Documentation · Adapters · Contributing


What It Does

you      > Was there anyone near the front door last night?

cctvQL   > Yes — 3 person detections on "Front Door" between 22:14 and 23:47.
           • 22:14 — person (96%) in zone: driveway
           • 23:02 — person (88%)
           • 23:47 — person (91%) in zone: porch

you      > Show me the clip from 23:47

cctvQL   > Clip from Front Door (23:47–23:49, 112s):
           http://192.168.1.100:5000/api/events/abc123/clip.mp4

No dashboards. No complex queries. Just ask.


Features

  • Natural language queries — ask about events, cameras, clips, and system health in plain English
  • Multi-turn conversations — context-aware follow-up questions backed by SQLite session persistence
  • Vendor-agnostic — adapter pattern supports any CCTV system; ships with Frigate, ONVIF, Hikvision, Dahua
  • Pluggable LLM backends — Ollama (local/private), OpenAI, Anthropic, or any OpenAI-compatible API
  • REST API — integrate with Home Assistant, Grafana, custom dashboards, or mobile apps
  • PTZ control — pan, tilt, zoom and preset recall via REST API for supported cameras
  • Event export — download event history as CSV or JSON from /events/export
  • Alert rules — create rules to notify when specific labels appear on specific cameras in time windows
  • Multi-channel notifications — Telegram, Slack, ntfy, email, and webhook; all fire concurrently
  • WebSocket streaming — real-time event push to any connected client via ws://host/ws/events
  • Prometheus metrics/metrics endpoint for Grafana, alerting, and observability
  • Camera health monitoring — background poller tracks per-camera online/offline status
  • Optional API key auth — protect your endpoint with CCTVQL_API_KEY env var
  • Multi-tenant support — JWT auth, per-user camera permissions, admin user management (CCTVQL_MULTI_TENANT=1)
  • Anomaly detection — statistical spike/silence detection per camera; ask "anything unusual today?"
  • Demo adapter — try cctvQL without any hardware; realistic mock data built-in
  • Interactive CLI — terminal-based conversational REPL
  • Real-time events — MQTT subscription for live alerts (Frigate)
  • Home Assistant integration — native custom integration with sensors, binary sensors (per-camera motion), PTZ and query services; installable via HACS
  • Docker-ready — running in under 5 minutes with persistent SQLite storage

Screenshots

Web UI — landing cctvQL landing screen showing camera sidebar and example query chips

Camera list query Response showing all 4 cameras with status and zones

Event history Recent motion events on the Front Door camera with timestamps and confidence scores

Alert rule creation Natural language alert setup — person detected after 10pm

Multi-turn conversation with vision AI Multi-turn conversation including a GPT-4o Vision analysis of an event snapshot


Quick Start

Try it now — no hardware needed

pip install cctvql
cctvql chat --adapter demo --llm ollama

The demo adapter ships with 4 cameras, 20 realistic events, and 5 clips — no Frigate or ONVIF device required. Use it to explore the query interface, build integrations, or write tests.

Docker (recommended — 5 minutes)

# 1. Clone and configure
git clone https://github.com/arunrajiah/cctvql.git
cd cctvql
cp config/example.yaml config/config.yaml

# 2. Edit config/config.yaml with your Frigate URL and LLM settings
nano config/config.yaml

# 3. Start
docker compose up -d

# 4. Try it
curl -X POST http://localhost:8000/query \
  -H "Content-Type: application/json" \
  -d '{"query": "Show me all cameras"}'

API docs: http://localhost:8000/docs

pip

pip install cctvql

# Interactive chat
cctvql chat --config config/config.yaml

# REST API server
cctvql serve --config config/config.yaml --port 8000

From source

git clone https://github.com/arunrajiah/cctvql.git
cd cctvql
pip install -e ".[dev,mqtt,onvif]"
cctvql chat

Documentation

Topic Link
Configuration reference docs/configuration.md
REST API reference docs/api.md
Notifications setup docs/notifications.md
Session & event persistence docs/persistence.md
Writing an adapter docs/adapters.md
LLM backend setup docs/llm-backends.md
Home Assistant integration docs/home-assistant.md
Docker deployment docs/docker.md
Frigate + cctvQL sidecar deploy/frigate-sidecar/
Troubleshooting docs/troubleshooting.md

Supported Systems

System Type Adapter Status
Frigate NVR NVR frigate ✅ Full support (REST + MQTT) — sidecar template
Any ONVIF camera/NVR Camera/NVR onvif ✅ Full support
Demo / Mock Built-in demo ✅ No hardware needed — try cctvQL now
Hikvision NVR/Camera hikvision ✅ Full support (ISAPI)
Dahua NVR/Camera dahua ✅ Full support (CGI)
Synology Surveillance Station NVR synology ✅ Full support (Web API)
Milestone XProtect Enterprise NVR milestone ✅ Full support (REST API)
Scrypted Smart home NVR scrypted ✅ Full support (Bearer token)
Your system Any Write an adapter!

Writing an adapter takes ~100 lines. See the adapter guide.


Supported LLM Backends

Backend Privacy Cost Quality
Ollama (llama3, mistral, phi3…) 🔒 100% local Free ⭐⭐⭐⭐
OpenAI (gpt-4o-mini, gpt-4o) ☁️ Cloud Paid ⭐⭐⭐⭐⭐
Anthropic (claude-haiku, claude-sonnet) ☁️ Cloud Paid ⭐⭐⭐⭐⭐
LM Studio 🔒 Local Free ⭐⭐⭐⭐
Any OpenAI-compatible API Varies Varies Varies

Recommended for privacy: Ollama with llama3 or mistral. No data leaves your network.


Configuration

# config/config.yaml
llm:
  active: ollama
  backends:
    ollama:
      provider: ollama
      host: http://localhost:11434
      model: llama3

adapters:
  active: frigate
  systems:
    frigate:
      type: frigate
      host: http://192.168.1.100:5000
      mqtt_host: 192.168.1.100      # optional, for real-time events

# Optional: alert notifications (any combination of channels)
notifications:
  telegram:
    bot_token: "123456:ABC-DEF..."
    chat_id: "-1001234567890"
  slack:
    webhook_url: "https://hooks.slack.com/services/..."
  ntfy:
    topic: my-cctvql-alerts

Database path (conversation history + event log):

export CCTVQL_DB_PATH=/data/cctvql.db

See docs/configuration.md for the full reference.
Notification channels: docs/notifications.md.
Session persistence: docs/persistence.md.


REST API

# Natural language query (multi-turn, session history persisted to SQLite)
POST /query
{"query": "Did anyone come to the front door after midnight?", "session_id": "my-session"}

# List cameras
GET /cameras

# Get events with filters
GET /events?camera=driveway&label=person&limit=10

# Export events as CSV or JSON
GET /events/export
GET /events/export?fmt=json&camera=Front+Door&label=person

# PTZ control (pan/tilt/zoom)
POST /cameras/{camera_id}/ptz
{"action": "left", "speed": 50}

# PTZ presets
GET /cameras/{camera_id}/ptz/presets

# System health
GET /health

# Per-camera health status
GET /health/cameras

# Alert rules (CRUD)
GET    /alerts
POST   /alerts
GET    /alerts/{id}
PATCH  /alerts/{id}
DELETE /alerts/{id}

# Anomaly detection (statistical spike/silence analysis)
GET /anomalies
GET /anomalies?hours=6&camera=Front+Door&threshold=1.5

# Prometheus metrics (for Grafana / alerting)
GET /metrics

# Clear conversation session (also removes from database)
DELETE /sessions/{session_id}

Real-time event streaming via WebSocket:

ws://localhost:8000/ws/events

Optional API key auth — set CCTVQL_API_KEY env var to require X-API-Key header on all requests.

Interactive Swagger docs available at http://localhost:8000/docs.

See docs/api.md for full endpoint documentation.


Architecture

┌─────────────────────────────────────────────────────────┐
│                    User Interface                        │
│         CLI Chat  │  REST API  │  Home Assistant         │
└─────────────────────────┬───────────────────────────────┘
                          │
┌─────────────────────────▼───────────────────────────────┐
│                    NLP Engine                            │
│   Natural Language → QueryContext (intent + params)      │
└─────────────────────────┬───────────────────────────────┘
                          │
           ┌──────────────▼──────────────┐
           │        LLM Registry         │
           │  Ollama │ OpenAI │ Anthropic │
           └──────────────┬──────────────┘
                          │
┌─────────────────────────▼───────────────────────────────┐
│                   Query Router                           │
│   Routes intent to adapter → formats human response     │
└─────────────────────────┬───────────────────────────────┘
                          │
           ┌──────────────▼──────────────┐
           │      Adapter Registry       │
           │  Frigate │ ONVIF │ Your NVR │
           └──────────────┬──────────────┘
                          │
┌─────────────────────────▼───────────────────────────────┐
│                  Your CCTV System                        │
│         NVR / IP Cameras / Recording Storage             │
└─────────────────────────────────────────────────────────┘

Project Structure

cctvql/
├── cctvql/
│   ├── core/
│   │   ├── schema.py          # Vendor-agnostic data models
│   │   ├── nlp_engine.py      # Natural language → QueryContext
│   │   └── query_router.py    # QueryContext → adapter → response
│   ├── adapters/
│   │   ├── base.py            # BaseAdapter interface (implement to add a system)
│   │   ├── frigate.py         # Frigate NVR (REST + MQTT)
│   │   └── onvif.py           # Generic ONVIF adapter
│   ├── llm/
│   │   ├── base.py            # BaseLLM interface + LLMRegistry
│   │   ├── ollama_backend.py  # Local LLM via Ollama
│   │   ├── openai_backend.py  # OpenAI / compatible APIs
│   │   └── anthropic_backend.py
│   ├── interfaces/
│   │   ├── cli.py             # Interactive terminal chat
│   │   └── rest_api.py        # FastAPI REST server
│   ├── _bootstrap.py          # Config loader and wiring
│   └── __main__.py            # Entry point (cctvql chat / serve)
├── config/
│   └── example.yaml           # Annotated config reference
├── docs/                      # Full documentation
├── tests/
├── Dockerfile
├── docker-compose.yml
└── pyproject.toml

Contributing

Contributions are what make cctvQL useful for everyone. The single highest-impact contribution is writing an adapter for a CCTV system you already have.

git clone https://github.com/arunrajiah/cctvql.git
cd cctvql
pip install -e ".[dev,mqtt,onvif]"
pytest tests/   # all tests should pass

See CONTRIBUTING.md for the full guide.

# Common developer commands
make dev          # install with all extras + pre-commit hooks
make test         # run test suite
make coverage     # tests + coverage report
make lint         # ruff linter
make type-check   # mypy
make demo         # interactive demo (no real hardware needed)

Most wanted contributions:

  • Hikvision adapter
  • Dahua adapter
  • Synology Surveillance Station adapter
  • Vision-based event description (send snapshot to LLM)
  • Home Assistant custom integration

FAQ

Does my camera data leave my network? Only if you use a cloud LLM backend (OpenAI, Anthropic). With Ollama, everything — including the AI processing — stays on your local machine.

Which Frigate version is supported? Frigate 0.12+ is tested. Most features work with 0.9+.

Can I use this with any ONVIF camera? Yes. ONVIF Profile S is supported for live streaming and snapshots. Profile G adds recording/clip support.

Can I query multiple camera systems at once? Yes — use "multi": true in your query request to fan out across all registered adapters simultaneously.

Is there a Home Assistant integration? A native Home Assistant custom integration is planned. For now, use the REST API endpoint from HA automations.


Roadmap

  • Vision analysis — pass event snapshots to multimodal LLMs for rich descriptions
  • Hikvision adapter
  • Dahua adapter
  • Web UI (lightweight chat interface)
  • Multi-system queries (query across multiple NVRs simultaneously)
  • Alert rules via natural language ("notify me when a person enters Zone A after 10pm")
  • Voice interface (Whisper STT + TTS output)
  • Multi-channel notifications — Telegram, Slack, ntfy, email, webhook
  • PTZ control via REST API (pan, tilt, zoom, presets)
  • Session persistence — conversation history survives server restarts (SQLite)
  • Event log — every detection written to SQLite; exportable as CSV/JSON
  • Camera health monitoring — per-camera online/offline status with background polling
  • Prometheus metrics — cameras online/offline, alert rule count
  • Home Assistant custom integration — sensors, binary sensors, services, HACS-ready
  • ONVIF discovery — auto-detect cameras on the local network (cctvql discover CLI + GET /discover/onvif)
  • Event timeline UI — visual heatmap timeline at /timeline with camera rows, time buckets, tooltips, auto-refresh
  • Face recognition — identify known individuals across camera feeds
  • Anomaly detection — statistical spike/silence detection per camera with z-score baseline (GET /anomalies)
  • Multi-tenant support — JWT auth, per-user camera permissions, admin user management (CCTVQL_MULTI_TENANT=1)
  • Mobile app (React Native)

License

MIT © 2026 arunrajiah

See LICENSE for the full text.


If cctvQL is useful to you, please ⭐ the repo — it helps others find it!

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

cctvql-1.0.4.tar.gz (132.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

cctvql-1.0.4-py3-none-any.whl (114.6 kB view details)

Uploaded Python 3

File details

Details for the file cctvql-1.0.4.tar.gz.

File metadata

  • Download URL: cctvql-1.0.4.tar.gz
  • Upload date:
  • Size: 132.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for cctvql-1.0.4.tar.gz
Algorithm Hash digest
SHA256 d507022de8195003a1e170618e2c1b91ac56659a892bb512352b09a86346dc2a
MD5 838534de6c7c9fe95eedfa9f9bc1c3ee
BLAKE2b-256 b8985e0e1ba72bd96cd01fedaab7ae126afdaa7a942f588fd78be1fac273b5e9

See more details on using hashes here.

Provenance

The following attestation bundles were made for cctvql-1.0.4.tar.gz:

Publisher: release.yml on arunrajiah/cctvql

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file cctvql-1.0.4-py3-none-any.whl.

File metadata

  • Download URL: cctvql-1.0.4-py3-none-any.whl
  • Upload date:
  • Size: 114.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for cctvql-1.0.4-py3-none-any.whl
Algorithm Hash digest
SHA256 0b7940f140252078ae45a03dbdc7894dc26d756547d1fa0a0bab63c5bee29902
MD5 d7a8bc574503ce2deea1e802613dfcee
BLAKE2b-256 7e810e568e9d520b3741620401b57c2a15073facfbdf00d4d92ba0fcb31e0f9f

See more details on using hashes here.

Provenance

The following attestation bundles were made for cctvql-1.0.4-py3-none-any.whl:

Publisher: release.yml on arunrajiah/cctvql

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page