homesec 0.1.1__tar.gz → 1.0.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- homesec-1.0.1/.dockerignore +57 -0
- {homesec-0.1.1 → homesec-1.0.1}/.env.example +11 -12
- homesec-1.0.1/.github/workflows/ci.yml +65 -0
- homesec-1.0.1/.github/workflows/release.yaml +70 -0
- homesec-1.0.1/.github/workflows/validate-pr-title.yaml +20 -0
- homesec-1.0.1/.gitignore +11 -0
- homesec-1.0.1/CHANGELOG.md +16 -0
- homesec-1.0.1/Dockerfile +96 -0
- homesec-1.0.1/Makefile +98 -0
- {homesec-0.1.1 → homesec-1.0.1}/PKG-INFO +39 -31
- {homesec-0.1.1 → homesec-1.0.1}/README.md +38 -30
- {homesec-0.1.1 → homesec-1.0.1}/alembic/env.py +14 -3
- homesec-1.0.1/alembic/script.py.mako +26 -0
- homesec-1.0.1/alembic/versions/e6f25df0df90_initial.py +67 -0
- homesec-1.0.1/config/example.yaml +194 -0
- homesec-1.0.1/docker-compose.yml +42 -0
- homesec-1.0.1/docker-entrypoint.sh +20 -0
- {homesec-0.1.1 → homesec-1.0.1}/pyproject.toml +43 -1
- {homesec-0.1.1 → homesec-1.0.1}/src/homesec/app.py +34 -36
- {homesec-0.1.1 → homesec-1.0.1}/src/homesec/cli.py +14 -11
- {homesec-0.1.1 → homesec-1.0.1}/src/homesec/config/loader.py +11 -11
- {homesec-0.1.1 → homesec-1.0.1}/src/homesec/config/validation.py +2 -5
- {homesec-0.1.1 → homesec-1.0.1}/src/homesec/errors.py +2 -4
- {homesec-0.1.1 → homesec-1.0.1}/src/homesec/health/server.py +29 -27
- {homesec-0.1.1 → homesec-1.0.1}/src/homesec/interfaces.py +11 -6
- {homesec-0.1.1 → homesec-1.0.1}/src/homesec/logging_setup.py +9 -5
- {homesec-0.1.1 → homesec-1.0.1}/src/homesec/maintenance/cleanup_clips.py +2 -3
- {homesec-0.1.1 → homesec-1.0.1}/src/homesec/models/alert.py +2 -0
- {homesec-0.1.1 → homesec-1.0.1}/src/homesec/models/clip.py +8 -1
- {homesec-0.1.1 → homesec-1.0.1}/src/homesec/models/config.py +9 -13
- {homesec-0.1.1 → homesec-1.0.1}/src/homesec/models/events.py +14 -0
- {homesec-0.1.1 → homesec-1.0.1}/src/homesec/models/filter.py +1 -3
- {homesec-0.1.1 → homesec-1.0.1}/src/homesec/models/vlm.py +1 -2
- {homesec-0.1.1 → homesec-1.0.1}/src/homesec/pipeline/core.py +15 -32
- {homesec-0.1.1 → homesec-1.0.1}/src/homesec/plugins/alert_policies/__init__.py +3 -4
- {homesec-0.1.1 → homesec-1.0.1}/src/homesec/plugins/alert_policies/default.py +3 -2
- {homesec-0.1.1 → homesec-1.0.1}/src/homesec/plugins/alert_policies/noop.py +1 -2
- {homesec-0.1.1 → homesec-1.0.1}/src/homesec/plugins/analyzers/__init__.py +3 -4
- {homesec-0.1.1 → homesec-1.0.1}/src/homesec/plugins/analyzers/openai.py +34 -43
- {homesec-0.1.1 → homesec-1.0.1}/src/homesec/plugins/filters/__init__.py +3 -4
- {homesec-0.1.1 → homesec-1.0.1}/src/homesec/plugins/filters/yolo.py +27 -29
- {homesec-0.1.1 → homesec-1.0.1}/src/homesec/plugins/notifiers/__init__.py +2 -1
- {homesec-0.1.1 → homesec-1.0.1}/src/homesec/plugins/notifiers/mqtt.py +16 -17
- {homesec-0.1.1 → homesec-1.0.1}/src/homesec/plugins/notifiers/multiplex.py +3 -2
- {homesec-0.1.1 → homesec-1.0.1}/src/homesec/plugins/notifiers/sendgrid_email.py +6 -8
- {homesec-0.1.1 → homesec-1.0.1}/src/homesec/plugins/storage/__init__.py +3 -4
- {homesec-0.1.1 → homesec-1.0.1}/src/homesec/plugins/storage/dropbox.py +20 -17
- {homesec-0.1.1 → homesec-1.0.1}/src/homesec/plugins/storage/local.py +3 -1
- {homesec-0.1.1 → homesec-1.0.1}/src/homesec/plugins/utils.py +2 -1
- {homesec-0.1.1 → homesec-1.0.1}/src/homesec/repository/clip_repository.py +5 -4
- {homesec-0.1.1 → homesec-1.0.1}/src/homesec/sources/base.py +2 -2
- {homesec-0.1.1 → homesec-1.0.1}/src/homesec/sources/local_folder.py +9 -7
- {homesec-0.1.1 → homesec-1.0.1}/src/homesec/sources/rtsp.py +22 -10
- {homesec-0.1.1 → homesec-1.0.1}/src/homesec/state/postgres.py +34 -35
- {homesec-0.1.1 → homesec-1.0.1}/src/homesec/telemetry/db_log_handler.py +3 -2
- {homesec-0.1.1 → homesec-1.0.1}/tests/homesec/conftest.py +6 -4
- {homesec-0.1.1 → homesec-1.0.1}/tests/homesec/mocks/filter.py +2 -2
- {homesec-0.1.1 → homesec-1.0.1}/tests/homesec/mocks/notifier.py +2 -2
- {homesec-0.1.1 → homesec-1.0.1}/tests/homesec/mocks/state_store.py +2 -2
- {homesec-0.1.1 → homesec-1.0.1}/tests/homesec/mocks/storage.py +2 -2
- {homesec-0.1.1 → homesec-1.0.1}/tests/homesec/mocks/vlm.py +2 -2
- {homesec-0.1.1 → homesec-1.0.1}/tests/homesec/test_app.py +3 -4
- {homesec-0.1.1 → homesec-1.0.1}/tests/homesec/test_clip_repository.py +10 -5
- {homesec-0.1.1 → homesec-1.0.1}/tests/homesec/test_clip_sources.py +41 -65
- {homesec-0.1.1 → homesec-1.0.1}/tests/homesec/test_config.py +1 -2
- {homesec-0.1.1 → homesec-1.0.1}/tests/homesec/test_dropbox_storage.py +3 -1
- {homesec-0.1.1 → homesec-1.0.1}/tests/homesec/test_event_store.py +2 -2
- {homesec-0.1.1 → homesec-1.0.1}/tests/homesec/test_health.py +35 -35
- {homesec-0.1.1 → homesec-1.0.1}/tests/homesec/test_integration.py +61 -58
- {homesec-0.1.1 → homesec-1.0.1}/tests/homesec/test_local_folder_deduplication.py +0 -1
- {homesec-0.1.1 → homesec-1.0.1}/tests/homesec/test_mqtt_notifier.py +6 -2
- {homesec-0.1.1 → homesec-1.0.1}/tests/homesec/test_openai_vlm.py +15 -5
- {homesec-0.1.1 → homesec-1.0.1}/tests/homesec/test_pipeline.py +49 -31
- {homesec-0.1.1 → homesec-1.0.1}/tests/homesec/test_plugin_registration.py +2 -6
- {homesec-0.1.1 → homesec-1.0.1}/tests/homesec/test_state_store.py +2 -4
- {homesec-0.1.1 → homesec-1.0.1}/tests/homesec/test_yolo_filter.py +0 -2
- homesec-0.1.1/.gitignore +0 -5
- homesec-0.1.1/.idea/.gitignore +0 -3
- homesec-0.1.1/.idea/homesec.iml +0 -9
- homesec-0.1.1/.idea/libraries/my_test_package.xml +0 -9
- homesec-0.1.1/.idea/misc.xml +0 -6
- homesec-0.1.1/.idea/modules.xml +0 -8
- homesec-0.1.1/.idea/vcs.xml +0 -6
- homesec-0.1.1/.idea/workspace.xml +0 -57
- homesec-0.1.1/Makefile +0 -65
- homesec-0.1.1/config/example.yaml +0 -85
- homesec-0.1.1/config/local.yaml +0 -68
- homesec-0.1.1/config/production.yaml +0 -113
- homesec-0.1.1/config/sample.yaml +0 -66
- homesec-0.1.1/docker-compose.postgres.yml +0 -17
- {homesec-0.1.1 → homesec-1.0.1}/AGENTS.md +0 -0
- {homesec-0.1.1 → homesec-1.0.1}/DESIGN.md +0 -0
- {homesec-0.1.1 → homesec-1.0.1}/LICENSE +0 -0
- {homesec-0.1.1 → homesec-1.0.1}/alembic.ini +0 -0
- {homesec-0.1.1 → homesec-1.0.1}/src/homesec/__init__.py +0 -0
- {homesec-0.1.1 → homesec-1.0.1}/src/homesec/config/__init__.py +0 -0
- {homesec-0.1.1 → homesec-1.0.1}/src/homesec/health/__init__.py +0 -0
- {homesec-0.1.1 → homesec-1.0.1}/src/homesec/maintenance/__init__.py +0 -0
- {homesec-0.1.1 → homesec-1.0.1}/src/homesec/models/__init__.py +1 -1
- {homesec-0.1.1 → homesec-1.0.1}/src/homesec/models/source.py +0 -0
- {homesec-0.1.1 → homesec-1.0.1}/src/homesec/models/storage.py +0 -0
- {homesec-0.1.1 → homesec-1.0.1}/src/homesec/pipeline/__init__.py +0 -0
- {homesec-0.1.1 → homesec-1.0.1}/src/homesec/pipeline/alert_policy.py +0 -0
- {homesec-0.1.1 → homesec-1.0.1}/src/homesec/plugins/__init__.py +0 -0
- {homesec-0.1.1 → homesec-1.0.1}/src/homesec/py.typed +0 -0
- {homesec-0.1.1 → homesec-1.0.1}/src/homesec/repository/__init__.py +0 -0
- {homesec-0.1.1 → homesec-1.0.1}/src/homesec/sources/__init__.py +0 -0
- {homesec-0.1.1 → homesec-1.0.1}/src/homesec/sources/ftp.py +0 -0
- {homesec-0.1.1 → homesec-1.0.1}/src/homesec/state/__init__.py +0 -0
- {homesec-0.1.1 → homesec-1.0.1}/src/homesec/storage_paths.py +0 -0
- {homesec-0.1.1 → homesec-1.0.1}/src/homesec/telemetry/__init__.py +0 -0
- {homesec-0.1.1 → homesec-1.0.1}/src/homesec/telemetry/db/__init__.py +0 -0
- {homesec-0.1.1 → homesec-1.0.1}/src/homesec/telemetry/db/log_table.py +0 -0
- {homesec-0.1.1 → homesec-1.0.1}/src/homesec/telemetry/postgres_settings.py +0 -0
- {homesec-0.1.1 → homesec-1.0.1}/tests/__init__.py +0 -0
- {homesec-0.1.1 → homesec-1.0.1}/tests/conftest.py +0 -0
- {homesec-0.1.1 → homesec-1.0.1}/tests/homesec/__init__.py +0 -0
- {homesec-0.1.1 → homesec-1.0.1}/tests/homesec/mocks/__init__.py +0 -0
- {homesec-0.1.1 → homesec-1.0.1}/tests/homesec/mocks/event_store.py +0 -0
- {homesec-0.1.1 → homesec-1.0.1}/tests/homesec/test_alert_policy.py +0 -0
- {homesec-0.1.1 → homesec-1.0.1}/tests/homesec/test_cleanup_clips.py +1 -1
- {homesec-0.1.1 → homesec-1.0.1}/tests/homesec/test_notifiers.py +0 -0
- {homesec-0.1.1 → homesec-1.0.1}/tests/homesec/test_pipeline_events.py +1 -1
- {homesec-0.1.1 → homesec-1.0.1}/tests/homesec/test_rtsp_helpers.py +0 -0
- {homesec-0.1.1 → homesec-1.0.1}/uv.lock +0 -0
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# Git
|
|
2
|
+
.git
|
|
3
|
+
.gitignore
|
|
4
|
+
|
|
5
|
+
# Python
|
|
6
|
+
__pycache__
|
|
7
|
+
*.py[cod]
|
|
8
|
+
*$py.class
|
|
9
|
+
*.so
|
|
10
|
+
.Python
|
|
11
|
+
.venv
|
|
12
|
+
venv
|
|
13
|
+
ENV
|
|
14
|
+
env
|
|
15
|
+
|
|
16
|
+
# Development
|
|
17
|
+
.env
|
|
18
|
+
.env.*
|
|
19
|
+
.mypy_cache
|
|
20
|
+
.pytest_cache
|
|
21
|
+
.ruff_cache
|
|
22
|
+
*.egg-info
|
|
23
|
+
dist
|
|
24
|
+
build
|
|
25
|
+
|
|
26
|
+
# IDE
|
|
27
|
+
.idea
|
|
28
|
+
.vscode
|
|
29
|
+
*.swp
|
|
30
|
+
*.swo
|
|
31
|
+
|
|
32
|
+
# Tests
|
|
33
|
+
tests
|
|
34
|
+
pytest.ini
|
|
35
|
+
|
|
36
|
+
# Documentation
|
|
37
|
+
docs
|
|
38
|
+
DESIGN.md
|
|
39
|
+
CLAUDE.md
|
|
40
|
+
|
|
41
|
+
# Local data (should be mounted as volumes)
|
|
42
|
+
recordings
|
|
43
|
+
storage
|
|
44
|
+
*.mp4
|
|
45
|
+
*.avi
|
|
46
|
+
*.mov
|
|
47
|
+
video_cache
|
|
48
|
+
yolo_cache
|
|
49
|
+
ftp_incoming
|
|
50
|
+
|
|
51
|
+
# Notebooks
|
|
52
|
+
notebooks
|
|
53
|
+
*.ipynb
|
|
54
|
+
|
|
55
|
+
# Config examples (actual config mounted at runtime)
|
|
56
|
+
config/*.yaml
|
|
57
|
+
!config/example.yaml
|
|
@@ -30,20 +30,19 @@ MQTT_PASSWORD="..."
|
|
|
30
30
|
# SendGrid email (if using sendgrid_email notifier)
|
|
31
31
|
SENDGRID_API_KEY="..."
|
|
32
32
|
|
|
33
|
-
#
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
# Run a local Postgres with: make db-up
|
|
40
|
-
POSTGRES_USER="telemetry"
|
|
41
|
-
POSTGRES_PASSWORD="telemetry"
|
|
42
|
-
POSTGRES_DB="telemetry"
|
|
33
|
+
# --- Database (optional) ---
|
|
34
|
+
# If DB_DSN is set, the process will store clip state/events in Postgres.
|
|
35
|
+
# Run a local Postgres with: make db
|
|
36
|
+
POSTGRES_USER="homesec"
|
|
37
|
+
POSTGRES_PASSWORD="homesec"
|
|
38
|
+
POSTGRES_DB="homesec"
|
|
43
39
|
POSTGRES_PORT="5432"
|
|
44
40
|
|
|
45
|
-
#
|
|
46
|
-
DB_DSN="postgresql+asyncpg://
|
|
41
|
+
# For local dev (make db + make run):
|
|
42
|
+
DB_DSN="postgresql+asyncpg://homesec:homesec@localhost:5432/homesec"
|
|
43
|
+
|
|
44
|
+
# For docker-compose (make up) - set automatically, but can override:
|
|
45
|
+
# DB_DSN="postgresql+asyncpg://homesec:homesec@postgres:5432/homesec"
|
|
47
46
|
|
|
48
47
|
# Optional tuning:
|
|
49
48
|
# DB_LOG_LEVEL="INFO" # only logs >= this level go to DB
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main, master]
|
|
6
|
+
pull_request:
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
ci:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
services:
|
|
12
|
+
postgres:
|
|
13
|
+
image: postgres:16-alpine
|
|
14
|
+
env:
|
|
15
|
+
POSTGRES_DB: homesec
|
|
16
|
+
POSTGRES_USER: homesec
|
|
17
|
+
POSTGRES_PASSWORD: homesec
|
|
18
|
+
ports:
|
|
19
|
+
- "5432:5432"
|
|
20
|
+
# No health check - Postgres boots while lint/typecheck run
|
|
21
|
+
|
|
22
|
+
env:
|
|
23
|
+
DB_DSN: postgresql+asyncpg://homesec:homesec@localhost:5432/homesec
|
|
24
|
+
|
|
25
|
+
steps:
|
|
26
|
+
- name: Checkout
|
|
27
|
+
uses: actions/checkout@v4
|
|
28
|
+
|
|
29
|
+
- name: Setup uv and Python
|
|
30
|
+
uses: astral-sh/setup-uv@v3
|
|
31
|
+
with:
|
|
32
|
+
python-version: "3.14"
|
|
33
|
+
enable-cache: true
|
|
34
|
+
cache-dependency-glob: "uv.lock"
|
|
35
|
+
|
|
36
|
+
- name: Cache venv
|
|
37
|
+
uses: actions/cache@v4
|
|
38
|
+
with:
|
|
39
|
+
path: .venv
|
|
40
|
+
key: venv-${{ runner.os }}-py3.14-${{ hashFiles('uv.lock') }}
|
|
41
|
+
|
|
42
|
+
- name: Sync dependencies
|
|
43
|
+
run: uv sync
|
|
44
|
+
|
|
45
|
+
# Lint and typecheck run while Postgres boots
|
|
46
|
+
- name: Lint
|
|
47
|
+
run: make lint
|
|
48
|
+
|
|
49
|
+
- name: Type check
|
|
50
|
+
run: make typecheck
|
|
51
|
+
|
|
52
|
+
# Wait for Postgres before migrations
|
|
53
|
+
- name: Wait for Postgres
|
|
54
|
+
run: |
|
|
55
|
+
for i in {1..30}; do
|
|
56
|
+
pg_isready -h localhost -p 5432 -U homesec && break
|
|
57
|
+
echo "Waiting for Postgres..."
|
|
58
|
+
sleep 1
|
|
59
|
+
done
|
|
60
|
+
|
|
61
|
+
- name: Run migrations
|
|
62
|
+
run: uv run alembic -c alembic.ini upgrade head
|
|
63
|
+
|
|
64
|
+
- name: Test
|
|
65
|
+
run: make test
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
workflow_dispatch:
|
|
5
|
+
inputs:
|
|
6
|
+
dry_run:
|
|
7
|
+
description: 'Dry run (no actual release)'
|
|
8
|
+
required: false
|
|
9
|
+
default: false
|
|
10
|
+
type: boolean
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
release:
|
|
14
|
+
runs-on: ubuntu-latest
|
|
15
|
+
permissions:
|
|
16
|
+
contents: write
|
|
17
|
+
id-token: write
|
|
18
|
+
|
|
19
|
+
steps:
|
|
20
|
+
- name: Checkout
|
|
21
|
+
uses: actions/checkout@v4
|
|
22
|
+
with:
|
|
23
|
+
fetch-depth: 0
|
|
24
|
+
|
|
25
|
+
- name: Setup Python
|
|
26
|
+
uses: actions/setup-python@v5
|
|
27
|
+
with:
|
|
28
|
+
python-version: "3.14"
|
|
29
|
+
|
|
30
|
+
- name: Install python-semantic-release
|
|
31
|
+
run: pip install python-semantic-release
|
|
32
|
+
|
|
33
|
+
- name: Configure Git
|
|
34
|
+
run: |
|
|
35
|
+
git config user.name "github-actions[bot]"
|
|
36
|
+
git config user.email "github-actions[bot]@users.noreply.github.com"
|
|
37
|
+
|
|
38
|
+
- name: Semantic Release (dry run)
|
|
39
|
+
if: inputs.dry_run
|
|
40
|
+
run: semantic-release version --print
|
|
41
|
+
|
|
42
|
+
- name: Semantic Release
|
|
43
|
+
if: ${{ !inputs.dry_run }}
|
|
44
|
+
id: semrel
|
|
45
|
+
env:
|
|
46
|
+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
47
|
+
run: |
|
|
48
|
+
semantic-release version
|
|
49
|
+
echo "version=$(grep 'version = ' pyproject.toml | head -1 | cut -d'\"' -f2)" >> $GITHUB_OUTPUT
|
|
50
|
+
|
|
51
|
+
- name: Build Package
|
|
52
|
+
if: ${{ !inputs.dry_run }}
|
|
53
|
+
run: |
|
|
54
|
+
pip install build
|
|
55
|
+
python -m build
|
|
56
|
+
|
|
57
|
+
- name: Publish to PyPI
|
|
58
|
+
if: ${{ !inputs.dry_run }}
|
|
59
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
60
|
+
with:
|
|
61
|
+
verbose: true
|
|
62
|
+
|
|
63
|
+
- name: Upload to GitHub Release
|
|
64
|
+
if: ${{ !inputs.dry_run }}
|
|
65
|
+
env:
|
|
66
|
+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
67
|
+
run: |
|
|
68
|
+
VERSION=${{ steps.semrel.outputs.version }}
|
|
69
|
+
# Upload dist files to the release that semantic-release created
|
|
70
|
+
gh release upload "v$VERSION" dist/* --clobber || true
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
name: Validate PR Title
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
pull_request_target:
|
|
5
|
+
types:
|
|
6
|
+
- opened
|
|
7
|
+
- edited
|
|
8
|
+
- synchronize
|
|
9
|
+
|
|
10
|
+
permissions:
|
|
11
|
+
pull-requests: read
|
|
12
|
+
|
|
13
|
+
jobs:
|
|
14
|
+
main:
|
|
15
|
+
name: Validate PR title
|
|
16
|
+
runs-on: ubuntu-latest
|
|
17
|
+
steps:
|
|
18
|
+
- uses: amannn/action-semantic-pull-request@v5
|
|
19
|
+
env:
|
|
20
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
homesec-1.0.1/.gitignore
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# CHANGELOG
|
|
2
|
+
|
|
3
|
+
<!-- version list -->
|
|
4
|
+
|
|
5
|
+
## v1.0.1 (2026-01-11)
|
|
6
|
+
|
|
7
|
+
### Bug Fixes
|
|
8
|
+
|
|
9
|
+
- Improve release workflow dry run and prevent major version jumps
|
|
10
|
+
([#2](https://github.com/lan17/HomeSec/pull/2),
|
|
11
|
+
[`ba02512`](https://github.com/lan17/HomeSec/commit/ba025129de5caa984552807e4e0f376666db485e))
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
## v1.0.0 (2026-01-11)
|
|
15
|
+
|
|
16
|
+
- Initial Release
|
homesec-1.0.1/Dockerfile
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# HomeSec Dockerfile
|
|
2
|
+
# Multi-stage build for minimal image size
|
|
3
|
+
#
|
|
4
|
+
# Build: docker build -t homesec .
|
|
5
|
+
# Run: docker run \
|
|
6
|
+
# -v ./config.yaml:/config/config.yaml \
|
|
7
|
+
# -v ./.env:/config/.env \
|
|
8
|
+
# -v ./recordings:/data/recordings \
|
|
9
|
+
# -v ./storage:/data/storage \
|
|
10
|
+
# -v ./yolo_cache:/app/yolo_cache \
|
|
11
|
+
# -p 8080:8080 homesec
|
|
12
|
+
|
|
13
|
+
# =============================================================================
|
|
14
|
+
# Stage 1: Builder
|
|
15
|
+
# =============================================================================
|
|
16
|
+
FROM python:3.14-slim-bookworm AS builder
|
|
17
|
+
|
|
18
|
+
# Install build dependencies
|
|
19
|
+
RUN apt-get update && apt-get install -y --no-install-recommends \
|
|
20
|
+
build-essential \
|
|
21
|
+
curl \
|
|
22
|
+
&& rm -rf /var/lib/apt/lists/*
|
|
23
|
+
|
|
24
|
+
# Install uv for fast dependency management
|
|
25
|
+
COPY --from=ghcr.io/astral-sh/uv:latest /uv /usr/local/bin/uv
|
|
26
|
+
|
|
27
|
+
WORKDIR /app
|
|
28
|
+
|
|
29
|
+
# Copy dependency files first for better caching
|
|
30
|
+
COPY pyproject.toml uv.lock* LICENSE README.md ./
|
|
31
|
+
|
|
32
|
+
# Install dependencies into a virtual environment
|
|
33
|
+
RUN uv venv /app/.venv
|
|
34
|
+
ENV VIRTUAL_ENV=/app/.venv
|
|
35
|
+
ENV PATH="/app/.venv/bin:$PATH"
|
|
36
|
+
|
|
37
|
+
RUN uv sync --frozen --no-dev --no-install-project
|
|
38
|
+
|
|
39
|
+
# Copy source code
|
|
40
|
+
COPY src/ ./src/
|
|
41
|
+
COPY alembic/ ./alembic/
|
|
42
|
+
COPY alembic.ini ./
|
|
43
|
+
|
|
44
|
+
# Install the project
|
|
45
|
+
RUN uv sync --frozen --no-dev
|
|
46
|
+
|
|
47
|
+
# =============================================================================
|
|
48
|
+
# Stage 2: Runtime
|
|
49
|
+
# =============================================================================
|
|
50
|
+
FROM python:3.14-slim-bookworm AS runtime
|
|
51
|
+
|
|
52
|
+
# Install runtime dependencies
|
|
53
|
+
# - ffmpeg: required for RTSP source video processing
|
|
54
|
+
# - libgl1: required by OpenCV
|
|
55
|
+
# - libglib2.0-0: required by OpenCV
|
|
56
|
+
RUN apt-get update && apt-get install -y --no-install-recommends \
|
|
57
|
+
ffmpeg \
|
|
58
|
+
libgl1 \
|
|
59
|
+
libglib2.0-0 \
|
|
60
|
+
&& rm -rf /var/lib/apt/lists/*
|
|
61
|
+
|
|
62
|
+
# Create non-root user for security
|
|
63
|
+
RUN useradd --create-home --shell /bin/bash homesec
|
|
64
|
+
|
|
65
|
+
WORKDIR /app
|
|
66
|
+
|
|
67
|
+
# Copy virtual environment from builder
|
|
68
|
+
COPY --from=builder /app/.venv /app/.venv
|
|
69
|
+
COPY --from=builder /app/alembic /app/alembic
|
|
70
|
+
COPY --from=builder /app/alembic.ini /app/alembic.ini
|
|
71
|
+
|
|
72
|
+
# Copy entrypoint script
|
|
73
|
+
COPY docker-entrypoint.sh /app/docker-entrypoint.sh
|
|
74
|
+
|
|
75
|
+
# Set up environment
|
|
76
|
+
ENV VIRTUAL_ENV=/app/.venv
|
|
77
|
+
ENV PATH="/app/.venv/bin:$PATH"
|
|
78
|
+
ENV PYTHONUNBUFFERED=1
|
|
79
|
+
|
|
80
|
+
# Create directories for volume mounts and make entrypoint executable
|
|
81
|
+
RUN chmod +x /app/docker-entrypoint.sh \
|
|
82
|
+
&& mkdir -p /config /data/recordings /data/storage /app/yolo_cache \
|
|
83
|
+
&& chown -R homesec:homesec /config /data /app
|
|
84
|
+
|
|
85
|
+
# Switch to non-root user
|
|
86
|
+
USER homesec
|
|
87
|
+
|
|
88
|
+
# Health check endpoint
|
|
89
|
+
EXPOSE 8080
|
|
90
|
+
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
|
|
91
|
+
CMD python -c "import urllib.request; urllib.request.urlopen('http://localhost:8080/health')" || exit 1
|
|
92
|
+
|
|
93
|
+
# Entrypoint runs migrations then starts app
|
|
94
|
+
# Config and env are expected to be mounted at /config/
|
|
95
|
+
ENTRYPOINT ["/app/docker-entrypoint.sh"]
|
|
96
|
+
CMD ["run", "--config", "/config/config.yaml", "--log_level", "INFO"]
|
homesec-1.0.1/Makefile
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
SHELL := /bin/bash
|
|
2
|
+
.SHELLFLAGS := -eu -o pipefail -c
|
|
3
|
+
|
|
4
|
+
.PHONY: help up down docker-build docker-push run db test typecheck lint check db-migrate db-migration publish
|
|
5
|
+
|
|
6
|
+
help:
|
|
7
|
+
@echo "Targets:"
|
|
8
|
+
@echo ""
|
|
9
|
+
@echo " Docker:"
|
|
10
|
+
@echo " make up Start HomeSec + Postgres"
|
|
11
|
+
@echo " make down Stop all services"
|
|
12
|
+
@echo " make docker-build Build Docker image"
|
|
13
|
+
@echo " make docker-push Push to DockerHub"
|
|
14
|
+
@echo ""
|
|
15
|
+
@echo " Local dev:"
|
|
16
|
+
@echo " make run Run HomeSec locally (requires Postgres)"
|
|
17
|
+
@echo " make db Start just Postgres"
|
|
18
|
+
@echo " make test Run tests"
|
|
19
|
+
@echo " make typecheck Run mypy"
|
|
20
|
+
@echo " make lint Run ruff linter"
|
|
21
|
+
@echo " make check Run lint + typecheck + test"
|
|
22
|
+
@echo ""
|
|
23
|
+
@echo " Database:"
|
|
24
|
+
@echo " make db-migrate Run migrations"
|
|
25
|
+
@echo " make db-migration m=\"description\" Generate new migration"
|
|
26
|
+
@echo ""
|
|
27
|
+
@echo " Release:"
|
|
28
|
+
@echo " make publish Build and upload to PyPI"
|
|
29
|
+
|
|
30
|
+
# Config
|
|
31
|
+
HOMESEC_CONFIG ?= config/config.yaml
|
|
32
|
+
HOMESEC_LOG_LEVEL ?= INFO
|
|
33
|
+
DOCKER_IMAGE ?= homesec
|
|
34
|
+
DOCKER_TAG ?= latest
|
|
35
|
+
DOCKERHUB_USER ?= $(shell echo $${DOCKERHUB_USER:-})
|
|
36
|
+
|
|
37
|
+
# Docker
|
|
38
|
+
up:
|
|
39
|
+
docker compose up -d --build
|
|
40
|
+
|
|
41
|
+
down:
|
|
42
|
+
docker compose down
|
|
43
|
+
|
|
44
|
+
docker-build:
|
|
45
|
+
docker build -t $(DOCKER_IMAGE):$(DOCKER_TAG) .
|
|
46
|
+
|
|
47
|
+
docker-push: docker-build
|
|
48
|
+
@if [ -z "$(DOCKERHUB_USER)" ]; then \
|
|
49
|
+
echo "Error: DOCKERHUB_USER not set. Run: export DOCKERHUB_USER=yourusername"; \
|
|
50
|
+
exit 1; \
|
|
51
|
+
fi
|
|
52
|
+
docker tag $(DOCKER_IMAGE):$(DOCKER_TAG) $(DOCKERHUB_USER)/$(DOCKER_IMAGE):$(DOCKER_TAG)
|
|
53
|
+
docker tag $(DOCKER_IMAGE):$(DOCKER_TAG) $(DOCKERHUB_USER)/$(DOCKER_IMAGE):latest
|
|
54
|
+
docker push $(DOCKERHUB_USER)/$(DOCKER_IMAGE):$(DOCKER_TAG)
|
|
55
|
+
docker push $(DOCKERHUB_USER)/$(DOCKER_IMAGE):latest
|
|
56
|
+
|
|
57
|
+
# Local dev
|
|
58
|
+
run:
|
|
59
|
+
@echo "Running database migrations..."
|
|
60
|
+
@uv run alembic -c alembic.ini upgrade head
|
|
61
|
+
uv run python -m homesec.cli run --config $(HOMESEC_CONFIG) --log_level $(HOMESEC_LOG_LEVEL)
|
|
62
|
+
|
|
63
|
+
db:
|
|
64
|
+
docker compose up -d postgres
|
|
65
|
+
|
|
66
|
+
test:
|
|
67
|
+
uv run pytest tests/homesec/ -v
|
|
68
|
+
|
|
69
|
+
typecheck:
|
|
70
|
+
uv run mypy --package homesec --strict
|
|
71
|
+
|
|
72
|
+
lint:
|
|
73
|
+
uv run ruff check src tests
|
|
74
|
+
uv run ruff format --check src tests
|
|
75
|
+
|
|
76
|
+
lint-fix:
|
|
77
|
+
uv run ruff check --fix src tests
|
|
78
|
+
uv run ruff format src tests
|
|
79
|
+
|
|
80
|
+
check: lint typecheck test
|
|
81
|
+
|
|
82
|
+
# Database
|
|
83
|
+
db-migrate:
|
|
84
|
+
uv run --with alembic --with sqlalchemy --with asyncpg --with python-dotenv alembic -c alembic.ini upgrade head
|
|
85
|
+
|
|
86
|
+
db-migration:
|
|
87
|
+
@if [ -z "$(m)" ]; then \
|
|
88
|
+
echo "Error: message required. Run: make db-migration m=\"your description\""; \
|
|
89
|
+
exit 1; \
|
|
90
|
+
fi
|
|
91
|
+
uv run --with alembic --with sqlalchemy --with asyncpg --with python-dotenv alembic -c alembic.ini revision --autogenerate -m "$(m)"
|
|
92
|
+
|
|
93
|
+
# Release
|
|
94
|
+
publish: check
|
|
95
|
+
rm -rf dist build
|
|
96
|
+
uv run --with build python -m build
|
|
97
|
+
uv run --with twine python -m twine check dist/*
|
|
98
|
+
uv run --with twine python -m twine upload dist/*
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: homesec
|
|
3
|
-
Version: 0.1
|
|
3
|
+
Version: 1.0.1
|
|
4
4
|
Summary: Pluggable async home security camera pipeline with detection, VLM analysis, and alerts.
|
|
5
5
|
Project-URL: Homepage, https://github.com/lan17/homesec
|
|
6
6
|
Project-URL: Source, https://github.com/lan17/homesec
|
|
@@ -247,11 +247,9 @@ Description-Content-Type: text/markdown
|
|
|
247
247
|
[](https://www.python.org/)
|
|
248
248
|
[](https://peps.python.org/pep-0561/)
|
|
249
249
|
|
|
250
|
-
HomeSec is a
|
|
251
|
-
|
|
252
|
-
(VLM) for a structured summary, and sends alerts via MQTT or email. The design
|
|
253
|
-
leans toward reliability: clips land on disk first, state/event writes are
|
|
254
|
-
best-effort, and non-critical stages can fail without losing the alert.
|
|
250
|
+
HomeSec is a self-hosted, extensible network video recorder that puts you in control. Store clips wherever you want, analyze them with AI, and get smart notifications—all while keeping your footage private and off third-party clouds.
|
|
251
|
+
|
|
252
|
+
Under the hood, it's a pluggable async pipeline for home security cameras. It records short clips, runs object detection, optionally calls a vision-language model (VLM) for a structured summary, and sends alerts via MQTT or email. The design leans toward reliability: clips land on disk first, state/event writes are best-effort, and non-critical stages can fail without losing the alert.
|
|
255
253
|
|
|
256
254
|
## Highlights
|
|
257
255
|
|
|
@@ -278,32 +276,42 @@ ClipSource -> (Upload + Filter) -> VLM (optional) -> Alert Policy -> Notifier(s)
|
|
|
278
276
|
|
|
279
277
|
### Requirements
|
|
280
278
|
|
|
281
|
-
-
|
|
282
|
-
- ffmpeg in PATH (required for RTSP source)
|
|
283
|
-
- Postgres for state/events (`make db-up` starts a local instance). The pipeline
|
|
284
|
-
continues if the DB is down, but a DSN is still required.
|
|
279
|
+
- Docker and Docker Compose
|
|
285
280
|
- Optional: MQTT broker, Dropbox credentials, OpenAI-compatible API key
|
|
286
281
|
|
|
287
282
|
### Setup
|
|
288
283
|
|
|
289
|
-
1.
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
284
|
+
1. Create a config file:
|
|
285
|
+
```bash
|
|
286
|
+
cp config/example.yaml config/config.yaml
|
|
287
|
+
# Edit config/config.yaml with your settings
|
|
288
|
+
```
|
|
289
|
+
2. Set environment variables:
|
|
290
|
+
```bash
|
|
291
|
+
cp .env.example .env
|
|
292
|
+
# Edit .env with your credentials
|
|
293
|
+
```
|
|
294
|
+
3. Start HomeSec + Postgres:
|
|
295
|
+
```bash
|
|
296
|
+
make up
|
|
297
|
+
```
|
|
298
|
+
4. Stop:
|
|
299
|
+
```bash
|
|
300
|
+
make down
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
### Running without Docker
|
|
304
|
+
|
|
305
|
+
If you prefer to run locally:
|
|
306
|
+
|
|
307
|
+
1. Install Python 3.10+ and ffmpeg
|
|
308
|
+
2. `uv sync`
|
|
309
|
+
3. `make db` (starts Postgres)
|
|
310
|
+
4. `make run`
|
|
303
311
|
|
|
304
312
|
## Configuration
|
|
305
313
|
|
|
306
|
-
Configs are YAML and validated with Pydantic.
|
|
314
|
+
Configs are YAML and validated with Pydantic. See `config/example.yaml` for all options.
|
|
307
315
|
|
|
308
316
|
Minimal example (RTSP + Dropbox + MQTT):
|
|
309
317
|
|
|
@@ -363,8 +371,8 @@ per_camera_alert:
|
|
|
363
371
|
A few things worth knowing:
|
|
364
372
|
- Secrets never go in YAML. Use env var names (`*_env`) and set values in your shell or `.env`.
|
|
365
373
|
- At least one notifier must be enabled (`mqtt` or `sendgrid_email`).
|
|
366
|
-
- Built-in YOLO classes: `person`, `
|
|
367
|
-
`
|
|
374
|
+
- Built-in YOLO classes: `person`, `car`, `truck`, `motorcycle`, `bicycle`,
|
|
375
|
+
`dog`, `cat`, `bird`, `backpack`, `handbag`, `suitcase`.
|
|
368
376
|
- Local storage for development:
|
|
369
377
|
|
|
370
378
|
```yaml
|
|
@@ -402,11 +410,11 @@ Extension points (all pluggable):
|
|
|
402
410
|
## CLI
|
|
403
411
|
|
|
404
412
|
- Run the pipeline:
|
|
405
|
-
`uv run python -m homesec.cli run --config config/
|
|
413
|
+
`uv run python -m homesec.cli run --config config/config.yaml --log_level INFO`
|
|
406
414
|
- Validate config:
|
|
407
|
-
`uv run python -m homesec.cli validate --config config/
|
|
415
|
+
`uv run python -m homesec.cli validate --config config/config.yaml`
|
|
408
416
|
- Cleanup (reanalyze and optionally delete empty clips):
|
|
409
|
-
`uv run python -m homesec.cli cleanup --config config/
|
|
417
|
+
`uv run python -m homesec.cli cleanup --config config/config.yaml --older_than_days 7 --dry_run True`
|
|
410
418
|
|
|
411
419
|
## Built-in plugins
|
|
412
420
|
|
|
@@ -457,7 +465,7 @@ my_filters = "my_package.filters.custom"
|
|
|
457
465
|
|
|
458
466
|
- Health endpoint: `GET /health` (configurable in `health.host`/`health.port`)
|
|
459
467
|
- Optional telemetry logs to Postgres when `DB_DSN` is set:
|
|
460
|
-
- Start local DB: `make db
|
|
468
|
+
- Start local DB: `make db`
|
|
461
469
|
- Run migrations: `make db-migrate`
|
|
462
470
|
|
|
463
471
|
## Development
|