homesec 1.2.1__tar.gz → 1.2.3__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.
Files changed (141) hide show
  1. homesec-1.2.3/.github/workflows/docker-publish.yml +58 -0
  2. {homesec-1.2.1 → homesec-1.2.3}/AGENTS.md +2 -1
  3. {homesec-1.2.1 → homesec-1.2.3}/CHANGELOG.md +124 -0
  4. {homesec-1.2.1 → homesec-1.2.3}/DESIGN.md +131 -138
  5. {homesec-1.2.1 → homesec-1.2.3}/Dockerfile +2 -2
  6. {homesec-1.2.1 → homesec-1.2.3}/PKG-INFO +13 -16
  7. {homesec-1.2.1 → homesec-1.2.3}/PLUGIN_DEVELOPMENT.md +12 -8
  8. {homesec-1.2.1 → homesec-1.2.3}/README.md +12 -15
  9. {homesec-1.2.1 → homesec-1.2.3}/config/example.yaml +40 -33
  10. {homesec-1.2.1 → homesec-1.2.3}/docker-compose.yml +2 -1
  11. {homesec-1.2.1 → homesec-1.2.3}/pyproject.toml +1 -1
  12. homesec-1.2.3/skills/local/homesec-db-logs/SKILL.md +73 -0
  13. {homesec-1.2.1 → homesec-1.2.3}/src/homesec/app.py +5 -14
  14. {homesec-1.2.1 → homesec-1.2.3}/src/homesec/cli.py +5 -4
  15. {homesec-1.2.1 → homesec-1.2.3}/src/homesec/config/__init__.py +8 -1
  16. {homesec-1.2.1 → homesec-1.2.3}/src/homesec/config/loader.py +17 -2
  17. {homesec-1.2.1 → homesec-1.2.3}/src/homesec/config/validation.py +99 -6
  18. {homesec-1.2.1 → homesec-1.2.3}/src/homesec/interfaces.py +2 -2
  19. {homesec-1.2.1 → homesec-1.2.3}/src/homesec/maintenance/cleanup_clips.py +17 -4
  20. {homesec-1.2.1 → homesec-1.2.3}/src/homesec/models/__init__.py +3 -23
  21. {homesec-1.2.1 → homesec-1.2.3}/src/homesec/models/clip.py +1 -1
  22. homesec-1.2.3/src/homesec/models/config.py +154 -0
  23. {homesec-1.2.1 → homesec-1.2.3}/src/homesec/models/enums.py +8 -0
  24. {homesec-1.2.1 → homesec-1.2.3}/src/homesec/models/events.py +1 -1
  25. {homesec-1.2.1 → homesec-1.2.3}/src/homesec/models/filter.py +3 -21
  26. {homesec-1.2.1 → homesec-1.2.3}/src/homesec/models/vlm.py +11 -20
  27. homesec-1.2.3/src/homesec/pipeline/__init__.py +5 -0
  28. {homesec-1.2.1 → homesec-1.2.3}/src/homesec/pipeline/core.py +9 -10
  29. {homesec-1.2.1 → homesec-1.2.3}/src/homesec/plugins/alert_policies/__init__.py +5 -5
  30. {homesec-1.2.1 → homesec-1.2.3}/src/homesec/plugins/alert_policies/default.py +21 -2
  31. {homesec-1.2.1 → homesec-1.2.3}/src/homesec/plugins/analyzers/__init__.py +1 -3
  32. {homesec-1.2.1 → homesec-1.2.3}/src/homesec/plugins/analyzers/openai.py +20 -13
  33. {homesec-1.2.1 → homesec-1.2.3}/src/homesec/plugins/filters/__init__.py +1 -2
  34. {homesec-1.2.1 → homesec-1.2.3}/src/homesec/plugins/filters/yolo.py +25 -5
  35. {homesec-1.2.1 → homesec-1.2.3}/src/homesec/plugins/notifiers/__init__.py +1 -6
  36. {homesec-1.2.1 → homesec-1.2.3}/src/homesec/plugins/notifiers/mqtt.py +21 -1
  37. {homesec-1.2.1 → homesec-1.2.3}/src/homesec/plugins/notifiers/sendgrid_email.py +52 -1
  38. {homesec-1.2.1 → homesec-1.2.3}/src/homesec/plugins/registry.py +27 -0
  39. {homesec-1.2.1 → homesec-1.2.3}/src/homesec/plugins/sources/__init__.py +4 -4
  40. {homesec-1.2.1 → homesec-1.2.3}/src/homesec/plugins/sources/ftp.py +1 -1
  41. {homesec-1.2.1 → homesec-1.2.3}/src/homesec/plugins/sources/local_folder.py +1 -1
  42. {homesec-1.2.1 → homesec-1.2.3}/src/homesec/plugins/sources/rtsp.py +2 -2
  43. {homesec-1.2.1 → homesec-1.2.3}/src/homesec/plugins/storage/__init__.py +1 -9
  44. {homesec-1.2.1 → homesec-1.2.3}/src/homesec/plugins/storage/dropbox.py +13 -1
  45. {homesec-1.2.1 → homesec-1.2.3}/src/homesec/plugins/storage/local.py +8 -1
  46. {homesec-1.2.1 → homesec-1.2.3}/src/homesec/repository/clip_repository.py +1 -1
  47. {homesec-1.2.1 → homesec-1.2.3}/src/homesec/sources/__init__.py +3 -4
  48. {homesec-1.2.1 → homesec-1.2.3}/src/homesec/sources/ftp.py +95 -2
  49. {homesec-1.2.1 → homesec-1.2.3}/src/homesec/sources/local_folder.py +27 -2
  50. homesec-1.2.3/src/homesec/sources/rtsp/__init__.py +5 -0
  51. homesec-1.2.3/src/homesec/sources/rtsp/clock.py +18 -0
  52. homesec-1.2.3/src/homesec/sources/rtsp/core.py +1424 -0
  53. homesec-1.2.3/src/homesec/sources/rtsp/frame_pipeline.py +325 -0
  54. homesec-1.2.3/src/homesec/sources/rtsp/hardware.py +143 -0
  55. homesec-1.2.3/src/homesec/sources/rtsp/motion.py +94 -0
  56. homesec-1.2.3/src/homesec/sources/rtsp/recorder.py +180 -0
  57. homesec-1.2.3/src/homesec/sources/rtsp/utils.py +35 -0
  58. {homesec-1.2.1 → homesec-1.2.3}/tests/homesec/conftest.py +1 -1
  59. homesec-1.2.3/tests/homesec/rtsp/test_frame_pipeline.py +120 -0
  60. homesec-1.2.3/tests/homesec/rtsp/test_hardware.py +111 -0
  61. homesec-1.2.1/tests/homesec/test_rtsp_helpers.py → homesec-1.2.3/tests/homesec/rtsp/test_helpers.py +2 -3
  62. homesec-1.2.3/tests/homesec/rtsp/test_runtime.py +961 -0
  63. {homesec-1.2.1 → homesec-1.2.3}/tests/homesec/test_alert_policy.py +2 -3
  64. {homesec-1.2.1 → homesec-1.2.3}/tests/homesec/test_app.py +14 -11
  65. {homesec-1.2.1 → homesec-1.2.3}/tests/homesec/test_cleanup_clips.py +5 -6
  66. {homesec-1.2.1 → homesec-1.2.3}/tests/homesec/test_cli.py +5 -7
  67. {homesec-1.2.1 → homesec-1.2.3}/tests/homesec/test_clip_repository.py +6 -6
  68. {homesec-1.2.1 → homesec-1.2.3}/tests/homesec/test_clip_sources.py +2 -2
  69. {homesec-1.2.1 → homesec-1.2.3}/tests/homesec/test_config.py +105 -54
  70. {homesec-1.2.1 → homesec-1.2.3}/tests/homesec/test_dropbox_storage.py +1 -2
  71. {homesec-1.2.1 → homesec-1.2.3}/tests/homesec/test_event_store.py +2 -2
  72. {homesec-1.2.1 → homesec-1.2.3}/tests/homesec/test_ftp_source.py +2 -3
  73. {homesec-1.2.1 → homesec-1.2.3}/tests/homesec/test_integration.py +8 -12
  74. {homesec-1.2.1 → homesec-1.2.3}/tests/homesec/test_local_storage.py +1 -2
  75. {homesec-1.2.1 → homesec-1.2.3}/tests/homesec/test_mqtt_notifier.py +1 -2
  76. {homesec-1.2.1 → homesec-1.2.3}/tests/homesec/test_notifiers.py +2 -3
  77. {homesec-1.2.1 → homesec-1.2.3}/tests/homesec/test_openai_vlm.py +6 -10
  78. {homesec-1.2.1 → homesec-1.2.3}/tests/homesec/test_pipeline.py +39 -43
  79. {homesec-1.2.1 → homesec-1.2.3}/tests/homesec/test_pipeline_events.py +14 -15
  80. {homesec-1.2.1 → homesec-1.2.3}/tests/homesec/test_sendgrid_notifier.py +1 -2
  81. {homesec-1.2.1 → homesec-1.2.3}/uv.lock +1 -1
  82. homesec-1.2.1/src/homesec/models/config.py +0 -403
  83. homesec-1.2.1/src/homesec/models/source.py +0 -81
  84. homesec-1.2.1/src/homesec/pipeline/__init__.py +0 -6
  85. homesec-1.2.1/src/homesec/pipeline/alert_policy.py +0 -5
  86. homesec-1.2.1/src/homesec/sources/rtsp.py +0 -1304
  87. {homesec-1.2.1 → homesec-1.2.3}/.dockerignore +0 -0
  88. {homesec-1.2.1 → homesec-1.2.3}/.env.example +0 -0
  89. {homesec-1.2.1 → homesec-1.2.3}/.github/workflows/ci.yml +0 -0
  90. {homesec-1.2.1 → homesec-1.2.3}/.github/workflows/release.yaml +0 -0
  91. {homesec-1.2.1 → homesec-1.2.3}/.github/workflows/validate-pr-title.yaml +0 -0
  92. {homesec-1.2.1 → homesec-1.2.3}/.gitignore +0 -0
  93. {homesec-1.2.1 → homesec-1.2.3}/LICENSE +0 -0
  94. {homesec-1.2.1 → homesec-1.2.3}/Makefile +0 -0
  95. {homesec-1.2.1 → homesec-1.2.3}/TESTING.md +0 -0
  96. {homesec-1.2.1 → homesec-1.2.3}/alembic/env.py +0 -0
  97. {homesec-1.2.1 → homesec-1.2.3}/alembic/script.py.mako +0 -0
  98. {homesec-1.2.1 → homesec-1.2.3}/alembic/versions/e6f25df0df90_initial.py +0 -0
  99. {homesec-1.2.1 → homesec-1.2.3}/alembic.ini +0 -0
  100. {homesec-1.2.1 → homesec-1.2.3}/docker-entrypoint.sh +0 -0
  101. {homesec-1.2.1 → homesec-1.2.3}/src/homesec/__init__.py +0 -0
  102. {homesec-1.2.1 → homesec-1.2.3}/src/homesec/errors.py +0 -0
  103. {homesec-1.2.1 → homesec-1.2.3}/src/homesec/health/__init__.py +0 -0
  104. {homesec-1.2.1 → homesec-1.2.3}/src/homesec/health/server.py +0 -0
  105. {homesec-1.2.1 → homesec-1.2.3}/src/homesec/logging_setup.py +0 -0
  106. {homesec-1.2.1 → homesec-1.2.3}/src/homesec/maintenance/__init__.py +0 -0
  107. {homesec-1.2.1 → homesec-1.2.3}/src/homesec/models/alert.py +0 -0
  108. {homesec-1.2.1 → homesec-1.2.3}/src/homesec/models/storage.py +0 -0
  109. {homesec-1.2.1/src/homesec/plugins → homesec-1.2.3/src/homesec}/notifiers/multiplex.py +0 -0
  110. {homesec-1.2.1 → homesec-1.2.3}/src/homesec/plugins/__init__.py +0 -0
  111. {homesec-1.2.1 → homesec-1.2.3}/src/homesec/plugins/alert_policies/noop.py +0 -0
  112. {homesec-1.2.1 → homesec-1.2.3}/src/homesec/plugins/utils.py +0 -0
  113. {homesec-1.2.1 → homesec-1.2.3}/src/homesec/py.typed +0 -0
  114. {homesec-1.2.1 → homesec-1.2.3}/src/homesec/repository/__init__.py +0 -0
  115. {homesec-1.2.1 → homesec-1.2.3}/src/homesec/sources/base.py +0 -0
  116. {homesec-1.2.1 → homesec-1.2.3}/src/homesec/state/__init__.py +0 -0
  117. {homesec-1.2.1 → homesec-1.2.3}/src/homesec/state/postgres.py +0 -0
  118. {homesec-1.2.1 → homesec-1.2.3}/src/homesec/storage_paths.py +0 -0
  119. {homesec-1.2.1 → homesec-1.2.3}/src/homesec/telemetry/__init__.py +0 -0
  120. {homesec-1.2.1 → homesec-1.2.3}/src/homesec/telemetry/db/__init__.py +0 -0
  121. {homesec-1.2.1 → homesec-1.2.3}/src/homesec/telemetry/db/log_table.py +0 -0
  122. {homesec-1.2.1 → homesec-1.2.3}/src/homesec/telemetry/db_log_handler.py +0 -0
  123. {homesec-1.2.1 → homesec-1.2.3}/src/homesec/telemetry/postgres_settings.py +0 -0
  124. {homesec-1.2.1 → homesec-1.2.3}/tests/__init__.py +0 -0
  125. {homesec-1.2.1 → homesec-1.2.3}/tests/conftest.py +0 -0
  126. {homesec-1.2.1 → homesec-1.2.3}/tests/homesec/__init__.py +0 -0
  127. {homesec-1.2.1 → homesec-1.2.3}/tests/homesec/mocks/__init__.py +0 -0
  128. {homesec-1.2.1 → homesec-1.2.3}/tests/homesec/mocks/event_store.py +0 -0
  129. {homesec-1.2.1 → homesec-1.2.3}/tests/homesec/mocks/filter.py +0 -0
  130. {homesec-1.2.1 → homesec-1.2.3}/tests/homesec/mocks/notifier.py +0 -0
  131. {homesec-1.2.1 → homesec-1.2.3}/tests/homesec/mocks/state_store.py +0 -0
  132. {homesec-1.2.1 → homesec-1.2.3}/tests/homesec/mocks/storage.py +0 -0
  133. {homesec-1.2.1 → homesec-1.2.3}/tests/homesec/mocks/vlm.py +0 -0
  134. {homesec-1.2.1 → homesec-1.2.3}/tests/homesec/test_enums.py +0 -0
  135. {homesec-1.2.1 → homesec-1.2.3}/tests/homesec/test_health.py +0 -0
  136. {homesec-1.2.1 → homesec-1.2.3}/tests/homesec/test_logging_setup.py +0 -0
  137. {homesec-1.2.1 → homesec-1.2.3}/tests/homesec/test_plugin_registration.py +0 -0
  138. {homesec-1.2.1 → homesec-1.2.3}/tests/homesec/test_plugin_utils.py +0 -0
  139. {homesec-1.2.1 → homesec-1.2.3}/tests/homesec/test_source_health.py +0 -0
  140. {homesec-1.2.1 → homesec-1.2.3}/tests/homesec/test_state_store.py +0 -0
  141. {homesec-1.2.1 → homesec-1.2.3}/tests/homesec/test_yolo_filter.py +0 -0
@@ -0,0 +1,58 @@
1
+ name: Publish Docker Image
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ release:
7
+ types: [published]
8
+
9
+ concurrency:
10
+ group: ${{ github.workflow }}-${{ github.ref }}
11
+ cancel-in-progress: true
12
+
13
+ jobs:
14
+ docker:
15
+ runs-on: ubuntu-latest
16
+ permissions:
17
+ contents: read
18
+
19
+ env:
20
+ IMAGE_NAME: ${{ vars.DOCKERHUB_IMAGE }}
21
+
22
+ steps:
23
+ - name: Checkout
24
+ uses: actions/checkout@v4
25
+
26
+ - name: Set up Docker Buildx
27
+ uses: docker/setup-buildx-action@v3
28
+
29
+ - name: Log in to Docker Hub
30
+ uses: docker/login-action@v3
31
+ with:
32
+ username: ${{ secrets.DOCKERHUB_USERNAME }}
33
+ password: ${{ secrets.DOCKERHUB_TOKEN }}
34
+
35
+ - name: Resolve release version
36
+ if: github.event_name == 'release'
37
+ run: |
38
+ tag="${{ github.event.release.tag_name }}"
39
+ echo "RELEASE_VERSION=${tag#v}" >> "$GITHUB_ENV"
40
+
41
+ - name: Docker metadata
42
+ id: meta
43
+ uses: docker/metadata-action@v5
44
+ with:
45
+ images: ${{ env.IMAGE_NAME }}
46
+ tags: |
47
+ type=raw,value=latest,enable=${{ github.ref == 'refs/heads/main' }}
48
+ type=raw,value=${{ env.RELEASE_VERSION }},enable=${{ github.event_name == 'release' }}
49
+
50
+ - name: Build and push
51
+ uses: docker/build-push-action@v5
52
+ with:
53
+ context: .
54
+ push: true
55
+ tags: ${{ steps.meta.outputs.tags }}
56
+ labels: ${{ steps.meta.outputs.labels }}
57
+ cache-from: type=gha
58
+ cache-to: type=gha,mode=max
@@ -9,6 +9,7 @@
9
9
 
10
10
  - **Strict type checking required**: Run `make typecheck` before committing. Error-as-value pattern requires explicit type narrowing via match/isinstance.
11
11
  - **Program to interfaces**: Use factory/registry helpers (e.g., `load_filter_plugin()`). Avoid direct instantiation of plugins.
12
+ - **Architecture constraints**: See `DESIGN.md` → “Architecture Constraints”. Boundary violations (core ↔ concrete plugins, backend-specific config in core) are bugs.
12
13
  - **Repository pattern**: Use `ClipRepository` for all state/event writes. Never touch `StateStore`/`EventStore` directly.
13
14
  - **Preserve stack traces**: Custom errors must set `self.__cause__ = cause` to preserve original exception.
14
15
  - **Tests must use Given/When/Then comments**: Every test must include these comments and follow behavioral testing principles (see `TESTING.md`).
@@ -42,7 +43,7 @@ async def _filter_stage(self, clip: Clip) -> FilterResult | FilterError:
42
43
  async with self._sem_filter:
43
44
  return await self._filter.detect(clip.local_path)
44
45
  except Exception as e:
45
- return FilterError(clip.clip_id, self._config.filter.plugin, cause=e)
46
+ return FilterError(clip.clip_id, self._config.filter.backend, cause=e)
46
47
 
47
48
  # Caller uses match for type narrowing
48
49
  filter_result = await self._filter_stage(clip)
@@ -2,6 +2,130 @@
2
2
 
3
3
  <!-- version list -->
4
4
 
5
+ ## v1.2.3 (2026-02-04)
6
+
7
+ ### Bug Fixes
8
+
9
+ - Fix dockerfile ([#21](https://github.com/lan17/homesec/pull/21),
10
+ [`29e8ce4`](https://github.com/lan17/homesec/commit/29e8ce43a667d288b668417b7735c0c51620fca1))
11
+
12
+ ### Continuous Integration
13
+
14
+ - Add docker publish workflow ([#20](https://github.com/lan17/homesec/pull/20),
15
+ [`0ec59a0`](https://github.com/lan17/homesec/commit/0ec59a0509cf7a7a98900963d3d265bfdd2cb65c))
16
+
17
+ ### Refactoring
18
+
19
+ - Plugin config boundary cleanup ([#18](https://github.com/lan17/homesec/pull/18),
20
+ [`6746fa2`](https://github.com/lan17/homesec/commit/6746fa2f4285657df01d0dc1d25c7a1d1580407b))
21
+
22
+
23
+ ## v1.2.2 (2026-01-27)
24
+
25
+ ### Bug Fixes
26
+
27
+ - Align recording sensitivity constraints ([#16](https://github.com/lan17/homesec/pull/16),
28
+ [`8ac42d2`](https://github.com/lan17/homesec/commit/8ac42d2e828cf2c5e9f7c0cc5da32b677ddbbd54))
29
+
30
+ - Defer rtsp detect fallback while recording ([#16](https://github.com/lan17/homesec/pull/16),
31
+ [`8ac42d2`](https://github.com/lan17/homesec/commit/8ac42d2e828cf2c5e9f7c0cc5da32b677ddbbd54))
32
+
33
+ - Harden rtsp recording retries ([#16](https://github.com/lan17/homesec/pull/16),
34
+ [`8ac42d2`](https://github.com/lan17/homesec/commit/8ac42d2e828cf2c5e9f7c0cc5da32b677ddbbd54))
35
+
36
+ - Honor exact rtsp reconnect attempts ([#16](https://github.com/lan17/homesec/pull/16),
37
+ [`8ac42d2`](https://github.com/lan17/homesec/commit/8ac42d2e828cf2c5e9f7c0cc5da32b677ddbbd54))
38
+
39
+ - Improve rtsp reconnect and fallback ([#16](https://github.com/lan17/homesec/pull/16),
40
+ [`8ac42d2`](https://github.com/lan17/homesec/commit/8ac42d2e828cf2c5e9f7c0cc5da32b677ddbbd54))
41
+
42
+ - Make recording motion threshold more sensitive ([#16](https://github.com/lan17/homesec/pull/16),
43
+ [`8ac42d2`](https://github.com/lan17/homesec/commit/8ac42d2e828cf2c5e9f7c0cc5da32b677ddbbd54))
44
+
45
+ ### Chores
46
+
47
+ - Remove rtsp improvements plan from repo ([#16](https://github.com/lan17/homesec/pull/16),
48
+ [`8ac42d2`](https://github.com/lan17/homesec/commit/8ac42d2e828cf2c5e9f7c0cc5da32b677ddbbd54))
49
+
50
+ ### Documentation
51
+
52
+ - Add homesec db logs skill ([#16](https://github.com/lan17/homesec/pull/16),
53
+ [`8ac42d2`](https://github.com/lan17/homesec/commit/8ac42d2e828cf2c5e9f7c0cc5da32b677ddbbd54))
54
+
55
+ ### Refactoring
56
+
57
+ - Centralize rtsp recording state ([#16](https://github.com/lan17/homesec/pull/16),
58
+ [`8ac42d2`](https://github.com/lan17/homesec/commit/8ac42d2e828cf2c5e9f7c0cc5da32b677ddbbd54))
59
+
60
+ - Export rtsp public api ([#16](https://github.com/lan17/homesec/pull/16),
61
+ [`8ac42d2`](https://github.com/lan17/homesec/commit/8ac42d2e828cf2c5e9f7c0cc5da32b677ddbbd54))
62
+
63
+ - Extract rtsp motion detector ([#16](https://github.com/lan17/homesec/pull/16),
64
+ [`8ac42d2`](https://github.com/lan17/homesec/commit/8ac42d2e828cf2c5e9f7c0cc5da32b677ddbbd54))
65
+
66
+ - Make rtsp pipeline lifecycle explicit ([#16](https://github.com/lan17/homesec/pull/16),
67
+ [`8ac42d2`](https://github.com/lan17/homesec/commit/8ac42d2e828cf2c5e9f7c0cc5da32b677ddbbd54))
68
+
69
+ - Reorganize source configs ([#16](https://github.com/lan17/homesec/pull/16),
70
+ [`8ac42d2`](https://github.com/lan17/homesec/commit/8ac42d2e828cf2c5e9f7c0cc5da32b677ddbbd54))
71
+
72
+ - Restrict rtsp package exports ([#16](https://github.com/lan17/homesec/pull/16),
73
+ [`8ac42d2`](https://github.com/lan17/homesec/commit/8ac42d2e828cf2c5e9f7c0cc5da32b677ddbbd54))
74
+
75
+ - Simplify rtsp run loop ([#16](https://github.com/lan17/homesec/pull/16),
76
+ [`8ac42d2`](https://github.com/lan17/homesec/commit/8ac42d2e828cf2c5e9f7c0cc5da32b677ddbbd54))
77
+
78
+ - Simplify rtsp run loop and probes ([#16](https://github.com/lan17/homesec/pull/16),
79
+ [`8ac42d2`](https://github.com/lan17/homesec/commit/8ac42d2e828cf2c5e9f7c0cc5da32b677ddbbd54))
80
+
81
+ - Split rtsp into package modules ([#16](https://github.com/lan17/homesec/pull/16),
82
+ [`8ac42d2`](https://github.com/lan17/homesec/commit/8ac42d2e828cf2c5e9f7c0cc5da32b677ddbbd54))
83
+
84
+ - Tighten rtsp detect fallback and backoff ([#16](https://github.com/lan17/homesec/pull/16),
85
+ [`8ac42d2`](https://github.com/lan17/homesec/commit/8ac42d2e828cf2c5e9f7c0cc5da32b677ddbbd54))
86
+
87
+ ### Testing
88
+
89
+ - Add rtsp reconnect deferral coverage ([#16](https://github.com/lan17/homesec/pull/16),
90
+ [`8ac42d2`](https://github.com/lan17/homesec/commit/8ac42d2e828cf2c5e9f7c0cc5da32b677ddbbd54))
91
+
92
+ - Add rtsp stall and detect recovery coverage ([#16](https://github.com/lan17/homesec/pull/16),
93
+ [`8ac42d2`](https://github.com/lan17/homesec/commit/8ac42d2e828cf2c5e9f7c0cc5da32b677ddbbd54))
94
+
95
+ - Cover detect switch fallback ([#16](https://github.com/lan17/homesec/pull/16),
96
+ [`8ac42d2`](https://github.com/lan17/homesec/commit/8ac42d2e828cf2c5e9f7c0cc5da32b677ddbbd54))
97
+
98
+ - Cover ffmpeg timeout fallback ([#16](https://github.com/lan17/homesec/pull/16),
99
+ [`8ac42d2`](https://github.com/lan17/homesec/commit/8ac42d2e828cf2c5e9f7c0cc5da32b677ddbbd54))
100
+
101
+ - Cover ffprobe error handling ([#16](https://github.com/lan17/homesec/pull/16),
102
+ [`8ac42d2`](https://github.com/lan17/homesec/commit/8ac42d2e828cf2c5e9f7c0cc5da32b677ddbbd54))
103
+
104
+ - Cover ffprobe timeout fallback ([#16](https://github.com/lan17/homesec/pull/16),
105
+ [`8ac42d2`](https://github.com/lan17/homesec/commit/8ac42d2e828cf2c5e9f7c0cc5da32b677ddbbd54))
106
+
107
+ - Cover recording start backoff ([#16](https://github.com/lan17/homesec/pull/16),
108
+ [`8ac42d2`](https://github.com/lan17/homesec/commit/8ac42d2e828cf2c5e9f7c0cc5da32b677ddbbd54))
109
+
110
+ - Cover rtsp frame pipeline edge cases ([#16](https://github.com/lan17/homesec/pull/16),
111
+ [`8ac42d2`](https://github.com/lan17/homesec/commit/8ac42d2e828cf2c5e9f7c0cc5da32b677ddbbd54))
112
+
113
+ - Cover rtsp recording timers ([#16](https://github.com/lan17/homesec/pull/16),
114
+ [`8ac42d2`](https://github.com/lan17/homesec/commit/8ac42d2e828cf2c5e9f7c0cc5da32b677ddbbd54))
115
+
116
+ - Expand rtsp config coverage ([#16](https://github.com/lan17/homesec/pull/16),
117
+ [`8ac42d2`](https://github.com/lan17/homesec/commit/8ac42d2e828cf2c5e9f7c0cc5da32b677ddbbd54))
118
+
119
+ - Expand rtsp coverage and regroup tests ([#16](https://github.com/lan17/homesec/pull/16),
120
+ [`8ac42d2`](https://github.com/lan17/homesec/commit/8ac42d2e828cf2c5e9f7c0cc5da32b677ddbbd54))
121
+
122
+ - Harden rtsp config paths ([#16](https://github.com/lan17/homesec/pull/16),
123
+ [`8ac42d2`](https://github.com/lan17/homesec/commit/8ac42d2e828cf2c5e9f7c0cc5da32b677ddbbd54))
124
+
125
+ - Harden rtsp hardware detection ([#16](https://github.com/lan17/homesec/pull/16),
126
+ [`8ac42d2`](https://github.com/lan17/homesec/commit/8ac42d2e828cf2c5e9f7c0cc5da32b677ddbbd54))
127
+
128
+
5
129
  ## v1.2.1 (2026-01-19)
6
130
 
7
131
  ### Bug Fixes