homesec 1.0.2__tar.gz → 1.1.0__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.2 → homesec-1.1.0}/.github/workflows/ci.yml +13 -2
- {homesec-1.0.2 → homesec-1.1.0}/AGENTS.md +16 -8
- homesec-1.1.0/CHANGELOG.md +45 -0
- {homesec-1.0.2 → homesec-1.1.0}/Makefile +8 -3
- {homesec-1.0.2 → homesec-1.1.0}/PKG-INFO +45 -4
- {homesec-1.0.2 → homesec-1.1.0}/README.md +44 -3
- homesec-1.1.0/TESTING.md +456 -0
- {homesec-1.0.2 → homesec-1.1.0}/pyproject.toml +2 -1
- homesec-1.1.0/tests/homesec/test_cli.py +348 -0
- homesec-1.1.0/tests/homesec/test_dropbox_storage.py +668 -0
- homesec-1.1.0/tests/homesec/test_ftp_source.py +297 -0
- homesec-1.1.0/tests/homesec/test_local_storage.py +318 -0
- homesec-1.1.0/tests/homesec/test_logging_setup.py +220 -0
- homesec-1.1.0/tests/homesec/test_mqtt_notifier.py +435 -0
- homesec-1.1.0/tests/homesec/test_openai_vlm.py +413 -0
- homesec-1.1.0/tests/homesec/test_plugin_utils.py +197 -0
- homesec-1.1.0/tests/homesec/test_sendgrid_notifier.py +441 -0
- {homesec-1.0.2 → homesec-1.1.0}/uv.lock +122 -2
- homesec-1.0.2/CHANGELOG.md +0 -24
- homesec-1.0.2/tests/homesec/test_dropbox_storage.py +0 -295
- homesec-1.0.2/tests/homesec/test_mqtt_notifier.py +0 -126
- homesec-1.0.2/tests/homesec/test_openai_vlm.py +0 -161
- {homesec-1.0.2 → homesec-1.1.0}/.dockerignore +0 -0
- {homesec-1.0.2 → homesec-1.1.0}/.env.example +0 -0
- {homesec-1.0.2 → homesec-1.1.0}/.github/workflows/release.yaml +0 -0
- {homesec-1.0.2 → homesec-1.1.0}/.github/workflows/validate-pr-title.yaml +0 -0
- {homesec-1.0.2 → homesec-1.1.0}/.gitignore +0 -0
- {homesec-1.0.2 → homesec-1.1.0}/DESIGN.md +0 -0
- {homesec-1.0.2 → homesec-1.1.0}/Dockerfile +0 -0
- {homesec-1.0.2 → homesec-1.1.0}/LICENSE +0 -0
- {homesec-1.0.2 → homesec-1.1.0}/alembic/env.py +0 -0
- {homesec-1.0.2 → homesec-1.1.0}/alembic/script.py.mako +0 -0
- {homesec-1.0.2 → homesec-1.1.0}/alembic/versions/e6f25df0df90_initial.py +0 -0
- {homesec-1.0.2 → homesec-1.1.0}/alembic.ini +0 -0
- {homesec-1.0.2 → homesec-1.1.0}/config/example.yaml +0 -0
- {homesec-1.0.2 → homesec-1.1.0}/docker-compose.yml +0 -0
- {homesec-1.0.2 → homesec-1.1.0}/docker-entrypoint.sh +0 -0
- {homesec-1.0.2 → homesec-1.1.0}/src/homesec/__init__.py +0 -0
- {homesec-1.0.2 → homesec-1.1.0}/src/homesec/app.py +0 -0
- {homesec-1.0.2 → homesec-1.1.0}/src/homesec/cli.py +0 -0
- {homesec-1.0.2 → homesec-1.1.0}/src/homesec/config/__init__.py +0 -0
- {homesec-1.0.2 → homesec-1.1.0}/src/homesec/config/loader.py +0 -0
- {homesec-1.0.2 → homesec-1.1.0}/src/homesec/config/validation.py +0 -0
- {homesec-1.0.2 → homesec-1.1.0}/src/homesec/errors.py +0 -0
- {homesec-1.0.2 → homesec-1.1.0}/src/homesec/health/__init__.py +0 -0
- {homesec-1.0.2 → homesec-1.1.0}/src/homesec/health/server.py +0 -0
- {homesec-1.0.2 → homesec-1.1.0}/src/homesec/interfaces.py +0 -0
- {homesec-1.0.2 → homesec-1.1.0}/src/homesec/logging_setup.py +0 -0
- {homesec-1.0.2 → homesec-1.1.0}/src/homesec/maintenance/__init__.py +0 -0
- {homesec-1.0.2 → homesec-1.1.0}/src/homesec/maintenance/cleanup_clips.py +0 -0
- {homesec-1.0.2 → homesec-1.1.0}/src/homesec/models/__init__.py +0 -0
- {homesec-1.0.2 → homesec-1.1.0}/src/homesec/models/alert.py +0 -0
- {homesec-1.0.2 → homesec-1.1.0}/src/homesec/models/clip.py +0 -0
- {homesec-1.0.2 → homesec-1.1.0}/src/homesec/models/config.py +0 -0
- {homesec-1.0.2 → homesec-1.1.0}/src/homesec/models/events.py +0 -0
- {homesec-1.0.2 → homesec-1.1.0}/src/homesec/models/filter.py +0 -0
- {homesec-1.0.2 → homesec-1.1.0}/src/homesec/models/source.py +0 -0
- {homesec-1.0.2 → homesec-1.1.0}/src/homesec/models/storage.py +0 -0
- {homesec-1.0.2 → homesec-1.1.0}/src/homesec/models/vlm.py +0 -0
- {homesec-1.0.2 → homesec-1.1.0}/src/homesec/pipeline/__init__.py +0 -0
- {homesec-1.0.2 → homesec-1.1.0}/src/homesec/pipeline/alert_policy.py +0 -0
- {homesec-1.0.2 → homesec-1.1.0}/src/homesec/pipeline/core.py +0 -0
- {homesec-1.0.2 → homesec-1.1.0}/src/homesec/plugins/__init__.py +0 -0
- {homesec-1.0.2 → homesec-1.1.0}/src/homesec/plugins/alert_policies/__init__.py +0 -0
- {homesec-1.0.2 → homesec-1.1.0}/src/homesec/plugins/alert_policies/default.py +0 -0
- {homesec-1.0.2 → homesec-1.1.0}/src/homesec/plugins/alert_policies/noop.py +0 -0
- {homesec-1.0.2 → homesec-1.1.0}/src/homesec/plugins/analyzers/__init__.py +0 -0
- {homesec-1.0.2 → homesec-1.1.0}/src/homesec/plugins/analyzers/openai.py +0 -0
- {homesec-1.0.2 → homesec-1.1.0}/src/homesec/plugins/filters/__init__.py +0 -0
- {homesec-1.0.2 → homesec-1.1.0}/src/homesec/plugins/filters/yolo.py +0 -0
- {homesec-1.0.2 → homesec-1.1.0}/src/homesec/plugins/notifiers/__init__.py +0 -0
- {homesec-1.0.2 → homesec-1.1.0}/src/homesec/plugins/notifiers/mqtt.py +0 -0
- {homesec-1.0.2 → homesec-1.1.0}/src/homesec/plugins/notifiers/multiplex.py +0 -0
- {homesec-1.0.2 → homesec-1.1.0}/src/homesec/plugins/notifiers/sendgrid_email.py +0 -0
- {homesec-1.0.2 → homesec-1.1.0}/src/homesec/plugins/storage/__init__.py +0 -0
- {homesec-1.0.2 → homesec-1.1.0}/src/homesec/plugins/storage/dropbox.py +0 -0
- {homesec-1.0.2 → homesec-1.1.0}/src/homesec/plugins/storage/local.py +0 -0
- {homesec-1.0.2 → homesec-1.1.0}/src/homesec/plugins/utils.py +0 -0
- {homesec-1.0.2 → homesec-1.1.0}/src/homesec/py.typed +0 -0
- {homesec-1.0.2 → homesec-1.1.0}/src/homesec/repository/__init__.py +0 -0
- {homesec-1.0.2 → homesec-1.1.0}/src/homesec/repository/clip_repository.py +0 -0
- {homesec-1.0.2 → homesec-1.1.0}/src/homesec/sources/__init__.py +0 -0
- {homesec-1.0.2 → homesec-1.1.0}/src/homesec/sources/base.py +0 -0
- {homesec-1.0.2 → homesec-1.1.0}/src/homesec/sources/ftp.py +0 -0
- {homesec-1.0.2 → homesec-1.1.0}/src/homesec/sources/local_folder.py +0 -0
- {homesec-1.0.2 → homesec-1.1.0}/src/homesec/sources/rtsp.py +0 -0
- {homesec-1.0.2 → homesec-1.1.0}/src/homesec/state/__init__.py +0 -0
- {homesec-1.0.2 → homesec-1.1.0}/src/homesec/state/postgres.py +0 -0
- {homesec-1.0.2 → homesec-1.1.0}/src/homesec/storage_paths.py +0 -0
- {homesec-1.0.2 → homesec-1.1.0}/src/homesec/telemetry/__init__.py +0 -0
- {homesec-1.0.2 → homesec-1.1.0}/src/homesec/telemetry/db/__init__.py +0 -0
- {homesec-1.0.2 → homesec-1.1.0}/src/homesec/telemetry/db/log_table.py +0 -0
- {homesec-1.0.2 → homesec-1.1.0}/src/homesec/telemetry/db_log_handler.py +0 -0
- {homesec-1.0.2 → homesec-1.1.0}/src/homesec/telemetry/postgres_settings.py +0 -0
- {homesec-1.0.2 → homesec-1.1.0}/tests/__init__.py +0 -0
- {homesec-1.0.2 → homesec-1.1.0}/tests/conftest.py +0 -0
- {homesec-1.0.2 → homesec-1.1.0}/tests/homesec/__init__.py +0 -0
- {homesec-1.0.2 → homesec-1.1.0}/tests/homesec/conftest.py +0 -0
- {homesec-1.0.2 → homesec-1.1.0}/tests/homesec/mocks/__init__.py +0 -0
- {homesec-1.0.2 → homesec-1.1.0}/tests/homesec/mocks/event_store.py +0 -0
- {homesec-1.0.2 → homesec-1.1.0}/tests/homesec/mocks/filter.py +0 -0
- {homesec-1.0.2 → homesec-1.1.0}/tests/homesec/mocks/notifier.py +0 -0
- {homesec-1.0.2 → homesec-1.1.0}/tests/homesec/mocks/state_store.py +0 -0
- {homesec-1.0.2 → homesec-1.1.0}/tests/homesec/mocks/storage.py +0 -0
- {homesec-1.0.2 → homesec-1.1.0}/tests/homesec/mocks/vlm.py +0 -0
- {homesec-1.0.2 → homesec-1.1.0}/tests/homesec/test_alert_policy.py +0 -0
- {homesec-1.0.2 → homesec-1.1.0}/tests/homesec/test_app.py +0 -0
- {homesec-1.0.2 → homesec-1.1.0}/tests/homesec/test_cleanup_clips.py +0 -0
- {homesec-1.0.2 → homesec-1.1.0}/tests/homesec/test_clip_repository.py +0 -0
- {homesec-1.0.2 → homesec-1.1.0}/tests/homesec/test_clip_sources.py +0 -0
- {homesec-1.0.2 → homesec-1.1.0}/tests/homesec/test_config.py +0 -0
- {homesec-1.0.2 → homesec-1.1.0}/tests/homesec/test_event_store.py +0 -0
- {homesec-1.0.2 → homesec-1.1.0}/tests/homesec/test_health.py +0 -0
- {homesec-1.0.2 → homesec-1.1.0}/tests/homesec/test_integration.py +0 -0
- {homesec-1.0.2 → homesec-1.1.0}/tests/homesec/test_local_folder_deduplication.py +0 -0
- {homesec-1.0.2 → homesec-1.1.0}/tests/homesec/test_notifiers.py +0 -0
- {homesec-1.0.2 → homesec-1.1.0}/tests/homesec/test_pipeline.py +0 -0
- {homesec-1.0.2 → homesec-1.1.0}/tests/homesec/test_pipeline_events.py +0 -0
- {homesec-1.0.2 → homesec-1.1.0}/tests/homesec/test_plugin_registration.py +0 -0
- {homesec-1.0.2 → homesec-1.1.0}/tests/homesec/test_rtsp_helpers.py +0 -0
- {homesec-1.0.2 → homesec-1.1.0}/tests/homesec/test_state_store.py +0 -0
- {homesec-1.0.2 → homesec-1.1.0}/tests/homesec/test_yolo_filter.py +0 -0
|
@@ -5,6 +5,10 @@ on:
|
|
|
5
5
|
branches: [main, master]
|
|
6
6
|
pull_request:
|
|
7
7
|
|
|
8
|
+
concurrency:
|
|
9
|
+
group: ${{ github.workflow }}-${{ github.ref }}
|
|
10
|
+
cancel-in-progress: true
|
|
11
|
+
|
|
8
12
|
jobs:
|
|
9
13
|
ci:
|
|
10
14
|
runs-on: ubuntu-latest
|
|
@@ -61,5 +65,12 @@ jobs:
|
|
|
61
65
|
- name: Run migrations
|
|
62
66
|
run: uv run alembic -c alembic.ini upgrade head
|
|
63
67
|
|
|
64
|
-
- name: Test
|
|
65
|
-
run: make
|
|
68
|
+
- name: Test with coverage
|
|
69
|
+
run: make coverage
|
|
70
|
+
|
|
71
|
+
- name: Upload coverage to Codecov
|
|
72
|
+
uses: codecov/codecov-action@v5
|
|
73
|
+
with:
|
|
74
|
+
token: ${{ secrets.CODECOV_TOKEN }}
|
|
75
|
+
files: coverage.xml
|
|
76
|
+
fail_ci_if_error: false
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# HomeSec Development Guidelines
|
|
2
2
|
|
|
3
|
-
**Last reviewed:** 2025-01-
|
|
3
|
+
**Last reviewed:** 2025-01-11
|
|
4
4
|
**Purpose:** Critical patterns to prevent runtime bugs when extending HomeSec. For architecture overview, see `DESIGN.md`.
|
|
5
5
|
|
|
6
6
|
---
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
- **Program to interfaces**: Use factory/registry helpers (e.g., `load_filter_plugin()`). Avoid direct instantiation of plugins.
|
|
12
12
|
- **Repository pattern**: Use `ClipRepository` for all state/event writes. Never touch `StateStore`/`EventStore` directly.
|
|
13
13
|
- **Preserve stack traces**: Custom errors must set `self.__cause__ = cause` to preserve original exception.
|
|
14
|
-
- **Tests must use Given/When/Then comments**: Every test
|
|
14
|
+
- **Tests must use Given/When/Then comments**: Every test must include these comments and follow behavioral testing principles (see `TESTING.md`).
|
|
15
15
|
- **Postgres for state**: Use `clip_states` table with `clip_id` (primary key) + `data` (jsonb) for evolvable schema.
|
|
16
16
|
- **Pydantic everywhere**: Validate config, DB payloads, VLM outputs, and MQTT payloads with Pydantic models.
|
|
17
17
|
- **Clarify before complexity**: Ask user for clarification when simpler design may exist. Don't proceed with complex workarounds.
|
|
@@ -277,13 +277,20 @@ def register():
|
|
|
277
277
|
|
|
278
278
|
### 5. Testing Requirements
|
|
279
279
|
|
|
280
|
-
**Rule:** All tests must use Given/When/Then comments.
|
|
280
|
+
**Rule:** All tests must use Given/When/Then comments. Follow principles in `TESTING.md` for writing high-quality tests.
|
|
281
|
+
|
|
282
|
+
**Key Principles (see `TESTING.md` for full details):**
|
|
283
|
+
- **Test observable behavior, not internal state** - Never assert on `obj._private_attr`
|
|
284
|
+
- **Mock at the boundary** - Mock HTTP/network, not internal methods
|
|
285
|
+
- **Use contract testing** - Capture and verify API request structure
|
|
286
|
+
- **Use real implementations where cheap** - Filesystem via `tmp_path`, pure functions
|
|
287
|
+
- **Track API calls, not state flags** - Use `api_calls: list[str]` not `was_called: bool`
|
|
281
288
|
|
|
282
289
|
**✅ Template: Test with Given/When/Then**
|
|
283
290
|
|
|
284
291
|
```python
|
|
285
292
|
async def test_filter_stage_success():
|
|
286
|
-
# Given: A clip
|
|
293
|
+
# Given: A clip and a filter configured to detect person
|
|
287
294
|
clip = Clip(clip_id="test-001", camera_name="front_door", ...)
|
|
288
295
|
mock_filter = MockFilter(result=FilterResult(detected_classes=["person"], confidence=0.9))
|
|
289
296
|
pipeline = ClipPipeline(filter_plugin=mock_filter, ...)
|
|
@@ -294,7 +301,7 @@ async def test_filter_stage_success():
|
|
|
294
301
|
# Then: Should return FilterResult with detected person
|
|
295
302
|
assert isinstance(result, FilterResult)
|
|
296
303
|
assert "person" in result.detected_classes
|
|
297
|
-
assert
|
|
304
|
+
assert result.confidence == 0.9
|
|
298
305
|
|
|
299
306
|
async def test_filter_stage_failure():
|
|
300
307
|
# Given: A filter that simulates failure
|
|
@@ -304,14 +311,14 @@ async def test_filter_stage_failure():
|
|
|
304
311
|
# When: Processing clip through filter stage
|
|
305
312
|
result = await pipeline._filter_stage(clip)
|
|
306
313
|
|
|
307
|
-
# Then: Should return FilterError
|
|
314
|
+
# Then: Should return FilterError (error-as-value pattern)
|
|
308
315
|
assert isinstance(result, FilterError)
|
|
309
|
-
assert result.cause is not None
|
|
310
316
|
assert result.clip_id == clip.clip_id
|
|
311
317
|
```
|
|
312
318
|
|
|
313
319
|
**Available Mocks:** `MockFilter`, `MockVLM`, `MockStorage`, `MockNotifier`, `MockStateStore`, `MockEventStore`
|
|
314
|
-
|
|
320
|
+
|
|
321
|
+
**Reference:** See `TESTING.md` for comprehensive testing guidelines and anti-patterns to avoid.
|
|
315
322
|
|
|
316
323
|
---
|
|
317
324
|
|
|
@@ -404,6 +411,7 @@ token: "sl.ABC123..." # Don't do this!
|
|
|
404
411
|
|
|
405
412
|
**Architecture & Design:**
|
|
406
413
|
- See `DESIGN.md` for full architecture overview and design decisions
|
|
414
|
+
- See `TESTING.md` for comprehensive testing guidelines and principles
|
|
407
415
|
- See `src/homesec/interfaces.py` for complete interface definitions
|
|
408
416
|
|
|
409
417
|
**Plugin Development:**
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# CHANGELOG
|
|
2
|
+
|
|
3
|
+
<!-- version list -->
|
|
4
|
+
|
|
5
|
+
## v1.1.0 (2026-01-12)
|
|
6
|
+
|
|
7
|
+
### Bug Fixes
|
|
8
|
+
|
|
9
|
+
- Add Codecov token to CI workflow ([#5](https://github.com/lan17/homesec/pull/5),
|
|
10
|
+
[`6657cf2`](https://github.com/lan17/homesec/commit/6657cf2e94fe7bf8d0eaed39cfa98242f9766188))
|
|
11
|
+
|
|
12
|
+
- Correct Codecov badge URL case (HomeSec) ([#6](https://github.com/lan17/homesec/pull/6),
|
|
13
|
+
[`74019fe`](https://github.com/lan17/homesec/commit/74019fe4b313d588a72e96ff86a7b647e69c8150))
|
|
14
|
+
|
|
15
|
+
### Features
|
|
16
|
+
|
|
17
|
+
- Add code coverage and improve documentation ([#4](https://github.com/lan17/homesec/pull/4),
|
|
18
|
+
[`b1d9490`](https://github.com/lan17/homesec/commit/b1d949057db675ed20f2623f06cef1fd58c4dcc3))
|
|
19
|
+
|
|
20
|
+
### Testing
|
|
21
|
+
|
|
22
|
+
- Improve code coverage from 64% to 70% ([#7](https://github.com/lan17/homesec/pull/7),
|
|
23
|
+
[`7b93468`](https://github.com/lan17/homesec/commit/7b934685e8389bb24c8cc8878cb43b5570f5371e))
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
## v1.0.2 (2026-01-11)
|
|
27
|
+
|
|
28
|
+
### Bug Fixes
|
|
29
|
+
|
|
30
|
+
- CI and release workflow improvements ([#3](https://github.com/lan17/homesec/pull/3),
|
|
31
|
+
[`ab61e47`](https://github.com/lan17/homesec/commit/ab61e47c7c16c79e8472807c07e4974e31a13c29))
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
## v1.0.1 (2026-01-11)
|
|
35
|
+
|
|
36
|
+
### Bug Fixes
|
|
37
|
+
|
|
38
|
+
- Improve release workflow dry run and prevent major version jumps
|
|
39
|
+
([#2](https://github.com/lan17/HomeSec/pull/2),
|
|
40
|
+
[`ba02512`](https://github.com/lan17/HomeSec/commit/ba025129de5caa984552807e4e0f376666db485e))
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
## v1.0.0 (2026-01-11)
|
|
44
|
+
|
|
45
|
+
- Initial Release
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
SHELL := /bin/bash
|
|
2
2
|
.SHELLFLAGS := -eu -o pipefail -c
|
|
3
3
|
|
|
4
|
-
.PHONY: help up down docker-build docker-push run db test typecheck lint check db-migrate db-migration publish
|
|
4
|
+
.PHONY: help up down docker-build docker-push run db test coverage typecheck lint check db-migrate db-migration publish
|
|
5
5
|
|
|
6
6
|
help:
|
|
7
7
|
@echo "Targets:"
|
|
@@ -15,7 +15,8 @@ help:
|
|
|
15
15
|
@echo " Local dev:"
|
|
16
16
|
@echo " make run Run HomeSec locally (requires Postgres)"
|
|
17
17
|
@echo " make db Start just Postgres"
|
|
18
|
-
@echo " make test Run tests"
|
|
18
|
+
@echo " make test Run tests with coverage"
|
|
19
|
+
@echo " make coverage Run tests and generate HTML coverage report"
|
|
19
20
|
@echo " make typecheck Run mypy"
|
|
20
21
|
@echo " make lint Run ruff linter"
|
|
21
22
|
@echo " make check Run lint + typecheck + test"
|
|
@@ -64,7 +65,11 @@ db:
|
|
|
64
65
|
docker compose up -d postgres
|
|
65
66
|
|
|
66
67
|
test:
|
|
67
|
-
uv run pytest tests/homesec/ -v
|
|
68
|
+
uv run pytest tests/homesec/ -v --cov=homesec --cov-report=term-missing
|
|
69
|
+
|
|
70
|
+
coverage:
|
|
71
|
+
uv run pytest tests/homesec/ -v --cov=homesec --cov-report=html --cov-report=xml
|
|
72
|
+
@echo "Coverage report: htmlcov/index.html"
|
|
68
73
|
|
|
69
74
|
typecheck:
|
|
70
75
|
uv run mypy --package homesec --strict
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: homesec
|
|
3
|
-
Version: 1.0
|
|
3
|
+
Version: 1.1.0
|
|
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
|
|
@@ -246,15 +246,31 @@ Description-Content-Type: text/markdown
|
|
|
246
246
|
[](LICENSE)
|
|
247
247
|
[](https://www.python.org/)
|
|
248
248
|
[](https://peps.python.org/pep-0561/)
|
|
249
|
+
[](https://codecov.io/gh/lan17/HomeSec)
|
|
249
250
|
|
|
250
251
|
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
|
|
|
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
|
|
253
|
+
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](https://en.wikipedia.org/wiki/Vision%E2%80%93language_model)) for a structured summary, and sends alerts via [MQTT](https://en.wikipedia.org/wiki/MQTT) or email. The design prioritizes reliability and extensibility.
|
|
254
|
+
|
|
255
|
+
## Table of Contents
|
|
256
|
+
|
|
257
|
+
- [Highlights](#highlights)
|
|
258
|
+
- [Pipeline at a glance](#pipeline-at-a-glance)
|
|
259
|
+
- [Quickstart](#quickstart)
|
|
260
|
+
- [Configuration](#configuration)
|
|
261
|
+
- [Extensible by design](#extensible-by-design)
|
|
262
|
+
- [CLI](#cli)
|
|
263
|
+
- [Built-in plugins](#built-in-plugins)
|
|
264
|
+
- [Writing a plugin](#writing-a-plugin)
|
|
265
|
+
- [Observability](#observability)
|
|
266
|
+
- [Development](#development)
|
|
267
|
+
- [Contributing](#contributing)
|
|
268
|
+
- [License](#license)
|
|
253
269
|
|
|
254
270
|
## Highlights
|
|
255
271
|
|
|
256
|
-
-
|
|
257
|
-
- Parallel upload + filter (YOLOv8) with frame sampling and early exit
|
|
272
|
+
- Multiple pluggable video clip sources: [RTSP](https://en.wikipedia.org/wiki/Real-Time_Streaming_Protocol) motion detection, [FTP](https://en.wikipedia.org/wiki/File_Transfer_Protocol) uploads, or a watched folder
|
|
273
|
+
- Parallel upload + filter ([YOLOv8](https://en.wikipedia.org/wiki/You_Only_Look_Once)) with frame sampling and early exit
|
|
258
274
|
- OpenAI-compatible VLM analysis with structured output
|
|
259
275
|
- Policy-driven alerts with per-camera overrides
|
|
260
276
|
- Fan-out notifiers (MQTT for Home Assistant, SendGrid email)
|
|
@@ -276,6 +292,7 @@ ClipSource -> (Upload + Filter) -> VLM (optional) -> Alert Policy -> Notifier(s)
|
|
|
276
292
|
|
|
277
293
|
### Requirements
|
|
278
294
|
|
|
295
|
+
- Raspberry Pi 4 (or equivalent) or higher; any x86_64 system works as well
|
|
279
296
|
- Docker and Docker Compose
|
|
280
297
|
- Optional: MQTT broker, Dropbox credentials, OpenAI-compatible API key
|
|
281
298
|
|
|
@@ -476,6 +493,30 @@ my_filters = "my_package.filters.custom"
|
|
|
476
493
|
- Tests must include Given/When/Then comments.
|
|
477
494
|
- Architecture notes: `DESIGN.md`
|
|
478
495
|
|
|
496
|
+
## Contributing
|
|
497
|
+
|
|
498
|
+
Contributions are welcome! Here's how to get started:
|
|
499
|
+
|
|
500
|
+
1. **Fork and clone** the repository
|
|
501
|
+
2. **Create a branch** for your feature or fix: `git checkout -b my-feature`
|
|
502
|
+
3. **Install dependencies**: `uv sync`
|
|
503
|
+
4. **Make your changes** and ensure tests pass: `make check`
|
|
504
|
+
5. **Submit a pull request** with a clear description of your changes
|
|
505
|
+
|
|
506
|
+
### Guidelines
|
|
507
|
+
|
|
508
|
+
- All code must pass CI checks: `make check`
|
|
509
|
+
- Tests should include Given/When/Then comments explaining the test scenario
|
|
510
|
+
- New plugins should follow the existing patterns in `src/homesec/plugins/`
|
|
511
|
+
- Keep PRs focused on a single change for easier review
|
|
512
|
+
|
|
513
|
+
### Reporting Issues
|
|
514
|
+
|
|
515
|
+
Found a bug or have a feature request? Please [open an issue](../../issues) with:
|
|
516
|
+
- A clear description of the problem or suggestion
|
|
517
|
+
- Steps to reproduce (for bugs)
|
|
518
|
+
- Your environment (OS, Python version, HomeSec version)
|
|
519
|
+
|
|
479
520
|
## License
|
|
480
521
|
|
|
481
522
|
Apache 2.0. See `LICENSE`.
|
|
@@ -3,15 +3,31 @@
|
|
|
3
3
|
[](LICENSE)
|
|
4
4
|
[](https://www.python.org/)
|
|
5
5
|
[](https://peps.python.org/pep-0561/)
|
|
6
|
+
[](https://codecov.io/gh/lan17/HomeSec)
|
|
6
7
|
|
|
7
8
|
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.
|
|
8
9
|
|
|
9
|
-
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
|
|
10
|
+
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](https://en.wikipedia.org/wiki/Vision%E2%80%93language_model)) for a structured summary, and sends alerts via [MQTT](https://en.wikipedia.org/wiki/MQTT) or email. The design prioritizes reliability and extensibility.
|
|
11
|
+
|
|
12
|
+
## Table of Contents
|
|
13
|
+
|
|
14
|
+
- [Highlights](#highlights)
|
|
15
|
+
- [Pipeline at a glance](#pipeline-at-a-glance)
|
|
16
|
+
- [Quickstart](#quickstart)
|
|
17
|
+
- [Configuration](#configuration)
|
|
18
|
+
- [Extensible by design](#extensible-by-design)
|
|
19
|
+
- [CLI](#cli)
|
|
20
|
+
- [Built-in plugins](#built-in-plugins)
|
|
21
|
+
- [Writing a plugin](#writing-a-plugin)
|
|
22
|
+
- [Observability](#observability)
|
|
23
|
+
- [Development](#development)
|
|
24
|
+
- [Contributing](#contributing)
|
|
25
|
+
- [License](#license)
|
|
10
26
|
|
|
11
27
|
## Highlights
|
|
12
28
|
|
|
13
|
-
-
|
|
14
|
-
- Parallel upload + filter (YOLOv8) with frame sampling and early exit
|
|
29
|
+
- Multiple pluggable video clip sources: [RTSP](https://en.wikipedia.org/wiki/Real-Time_Streaming_Protocol) motion detection, [FTP](https://en.wikipedia.org/wiki/File_Transfer_Protocol) uploads, or a watched folder
|
|
30
|
+
- Parallel upload + filter ([YOLOv8](https://en.wikipedia.org/wiki/You_Only_Look_Once)) with frame sampling and early exit
|
|
15
31
|
- OpenAI-compatible VLM analysis with structured output
|
|
16
32
|
- Policy-driven alerts with per-camera overrides
|
|
17
33
|
- Fan-out notifiers (MQTT for Home Assistant, SendGrid email)
|
|
@@ -33,6 +49,7 @@ ClipSource -> (Upload + Filter) -> VLM (optional) -> Alert Policy -> Notifier(s)
|
|
|
33
49
|
|
|
34
50
|
### Requirements
|
|
35
51
|
|
|
52
|
+
- Raspberry Pi 4 (or equivalent) or higher; any x86_64 system works as well
|
|
36
53
|
- Docker and Docker Compose
|
|
37
54
|
- Optional: MQTT broker, Dropbox credentials, OpenAI-compatible API key
|
|
38
55
|
|
|
@@ -233,6 +250,30 @@ my_filters = "my_package.filters.custom"
|
|
|
233
250
|
- Tests must include Given/When/Then comments.
|
|
234
251
|
- Architecture notes: `DESIGN.md`
|
|
235
252
|
|
|
253
|
+
## Contributing
|
|
254
|
+
|
|
255
|
+
Contributions are welcome! Here's how to get started:
|
|
256
|
+
|
|
257
|
+
1. **Fork and clone** the repository
|
|
258
|
+
2. **Create a branch** for your feature or fix: `git checkout -b my-feature`
|
|
259
|
+
3. **Install dependencies**: `uv sync`
|
|
260
|
+
4. **Make your changes** and ensure tests pass: `make check`
|
|
261
|
+
5. **Submit a pull request** with a clear description of your changes
|
|
262
|
+
|
|
263
|
+
### Guidelines
|
|
264
|
+
|
|
265
|
+
- All code must pass CI checks: `make check`
|
|
266
|
+
- Tests should include Given/When/Then comments explaining the test scenario
|
|
267
|
+
- New plugins should follow the existing patterns in `src/homesec/plugins/`
|
|
268
|
+
- Keep PRs focused on a single change for easier review
|
|
269
|
+
|
|
270
|
+
### Reporting Issues
|
|
271
|
+
|
|
272
|
+
Found a bug or have a feature request? Please [open an issue](../../issues) with:
|
|
273
|
+
- A clear description of the problem or suggestion
|
|
274
|
+
- Steps to reproduce (for bugs)
|
|
275
|
+
- Your environment (OS, Python version, HomeSec version)
|
|
276
|
+
|
|
236
277
|
## License
|
|
237
278
|
|
|
238
279
|
Apache 2.0. See `LICENSE`.
|