Compare commits

...
Author SHA1 Message Date
dependabot[bot]andGitHub d878087883 Update uvicorn requirement from ==0.35.* to ==0.46.* in /docker/main
Updates the requirements on [uvicorn](https://github.com/Kludex/uvicorn) to permit the latest version.
- [Release notes](https://github.com/Kludex/uvicorn/releases)
- [Changelog](https://github.com/Kludex/uvicorn/blob/main/docs/release-notes.md)
- [Commits](https://github.com/Kludex/uvicorn/compare/0.35.0...0.46.0)

---
updated-dependencies:
- dependency-name: uvicorn
  dependency-version: 0.46.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-01 13:19:14 +00:00
ba4a6a53d7 Miscellaneous fixes (#23053)
CI / AMD64 Build (push) Waiting to run
CI / ARM Build (push) Waiting to run
CI / Jetson Jetpack 6 (push) Waiting to run
CI / AMD64 Extra Build (push) Blocked by required conditions
CI / ARM Extra Build (push) Blocked by required conditions
CI / Synaptics Build (push) Blocked by required conditions
CI / Assemble and push default build (push) Blocked by required conditions
* don't exempt draft PRs from stalebot

* Fix import

* ensure toast shows when export API returns 20n (202, accepted)

---------

Co-authored-by: Nicolas Mowen <nickmowen213@gmail.com>
2026-04-30 17:19:53 -06:00
Nicolas MowenandGitHub e90079ab2f Include chapters for review items in exports (#23052) 2026-04-30 18:16:24 -05:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
edcf0b0d2c Bump actions/github-script from 7 to 9 (#22830)
Bumps [actions/github-script](https://github.com/actions/github-script) from 7 to 9.
- [Release notes](https://github.com/actions/github-script/releases)
- [Commits](https://github.com/actions/github-script/compare/v7...v9)

---
updated-dependencies:
- dependency-name: actions/github-script
  dependency-version: '9'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-30 12:26:28 -06:00
578d6391fb Translated using Weblate (Norwegian Bokmål)
Currently translated at 100.0% (101 of 101 strings)

Translated using Weblate (Norwegian Bokmål)

Currently translated at 100.0% (64 of 64 strings)

Translated using Weblate (Norwegian Bokmål)

Currently translated at 100.0% (26 of 26 strings)

Translated using Weblate (Norwegian Bokmål)

Currently translated at 100.0% (469 of 469 strings)

Translated using Weblate (Norwegian Bokmål)

Currently translated at 100.0% (790 of 790 strings)

Translated using Weblate (Norwegian Bokmål)

Currently translated at 100.0% (95 of 95 strings)

Translated using Weblate (Norwegian Bokmål)

Currently translated at 100.0% (145 of 145 strings)

Translated using Weblate (Norwegian Bokmål)

Currently translated at 100.0% (86 of 86 strings)

Translated using Weblate (Norwegian Bokmål)

Currently translated at 100.0% (62 of 62 strings)

Translated using Weblate (Norwegian Bokmål)

Currently translated at 99.3% (144 of 145 strings)

Translated using Weblate (Norwegian Bokmål)

Currently translated at 100.0% (1076 of 1076 strings)

Translated using Weblate (Norwegian Bokmål)

Currently translated at 100.0% (1074 of 1074 strings)

Translated using Weblate (Norwegian Bokmål)

Currently translated at 100.0% (235 of 235 strings)

Translated using Weblate (Norwegian Bokmål)

Currently translated at 100.0% (10 of 10 strings)

Translated using Weblate (Norwegian Bokmål)

Currently translated at 100.0% (790 of 790 strings)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: OverTheHillsAndFarAway <prosjektx@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/common/nb_NO/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-dialog/nb_NO/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-player/nb_NO/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-cameras/nb_NO/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-global/nb_NO/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-configeditor/nb_NO/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-events/nb_NO/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-explore/nb_NO/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-exports/nb_NO/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/nb_NO/
Translation: Frigate NVR/Config - Cameras
Translation: Frigate NVR/Config - Global
Translation: Frigate NVR/common
Translation: Frigate NVR/components-dialog
Translation: Frigate NVR/components-player
Translation: Frigate NVR/views-configeditor
Translation: Frigate NVR/views-events
Translation: Frigate NVR/views-explore
Translation: Frigate NVR/views-exports
Translation: Frigate NVR/views-settings
2026-04-30 12:25:34 -06:00
c9c9c1793d Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (236 of 236 strings)

Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 100.0% (1081 of 1081 strings)

Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 100.0% (469 of 469 strings)

Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 100.0% (1077 of 1077 strings)

Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 100.0% (790 of 790 strings)

Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 100.0% (1077 of 1077 strings)

Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 100.0% (469 of 469 strings)

Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 100.0% (101 of 101 strings)

Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 100.0% (145 of 145 strings)

Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 100.0% (86 of 86 strings)

Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 100.0% (790 of 790 strings)

Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 100.0% (26 of 26 strings)

Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 82.1% (83 of 101 strings)

Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 41.8% (36 of 86 strings)

Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 100.0% (64 of 64 strings)

Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 100.0% (469 of 469 strings)

Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 99.7% (788 of 790 strings)

Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 100.0% (235 of 235 strings)

Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 100.0% (1074 of 1074 strings)

Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 100.0% (1074 of 1074 strings)

Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 100.0% (469 of 469 strings)

Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 100.0% (790 of 790 strings)

Co-authored-by: GuoQing Liu <842607283@qq.com>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/common/zh_Hans/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-dialog/zh_Hans/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-player/zh_Hans/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-cameras/zh_Hans/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-global/zh_Hans/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-events/zh_Hans/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-explore/zh_Hans/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-exports/zh_Hans/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/zh_Hans/
Translation: Frigate NVR/Config - Cameras
Translation: Frigate NVR/Config - Global
Translation: Frigate NVR/common
Translation: Frigate NVR/components-dialog
Translation: Frigate NVR/components-player
Translation: Frigate NVR/views-events
Translation: Frigate NVR/views-explore
Translation: Frigate NVR/views-exports
Translation: Frigate NVR/views-settings
2026-04-30 12:25:34 -06:00
a3b10c308b Translated using Weblate (Kannada)
Currently translated at 16.6% (1 of 6 strings)

Translated using Weblate (Kannada)

Currently translated at 0.9% (1 of 101 strings)

Translated using Weblate (Kannada)

Currently translated at 4.0% (1 of 25 strings)

Translated using Weblate (Kannada)

Currently translated at 10.0% (1 of 10 strings)

Translated using Weblate (Kannada)

Currently translated at 0.8% (1 of 123 strings)

Translated using Weblate (Kannada)

Currently translated at 0.1% (1 of 1081 strings)

Translated using Weblate (Kannada)

Currently translated at 10.0% (1 of 10 strings)

Translated using Weblate (Kannada)

Currently translated at 50.0% (1 of 2 strings)

Translated using Weblate (Kannada)

Currently translated at 2.1% (1 of 47 strings)

Translated using Weblate (Kannada)

Currently translated at 0.5% (1 of 174 strings)

Translated using Weblate (Kannada)

Currently translated at 0.4% (1 of 236 strings)

Added translation using Weblate (Kannada)

Added translation using Weblate (Kannada)

Added translation using Weblate (Kannada)

Added translation using Weblate (Kannada)

Added translation using Weblate (Kannada)

Added translation using Weblate (Kannada)

Added translation using Weblate (Kannada)

Added translation using Weblate (Kannada)

Added translation using Weblate (Kannada)

Added translation using Weblate (Kannada)

Added translation using Weblate (Kannada)

Added translation using Weblate (Kannada)

Added translation using Weblate (Kannada)

Added translation using Weblate (Kannada)

Added translation using Weblate (Kannada)

Added translation using Weblate (Kannada)

Added translation using Weblate (Kannada)

Added translation using Weblate (Kannada)

Added translation using Weblate (Kannada)

Added translation using Weblate (Kannada)

Added translation using Weblate (Kannada)

Added translation using Weblate (Kannada)

Added translation using Weblate (Kannada)

Added translation using Weblate (Kannada)

Added translation using Weblate (Kannada)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Rakshit Chandrahasa <r211093@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/common/kn/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-auth/kn/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-camera/kn/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-dialog/kn/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-icons/kn/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-groups/kn/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/objects/kn/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-configeditor/kn/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-recording/kn/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/kn/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-system/kn/
Translation: Frigate NVR/Config - Groups
Translation: Frigate NVR/common
Translation: Frigate NVR/components-auth
Translation: Frigate NVR/components-camera
Translation: Frigate NVR/components-dialog
Translation: Frigate NVR/components-icons
Translation: Frigate NVR/objects
Translation: Frigate NVR/views-configeditor
Translation: Frigate NVR/views-recording
Translation: Frigate NVR/views-settings
Translation: Frigate NVR/views-system
2026-04-30 12:25:34 -06:00
540290bba7 Translated using Weblate (Korean)
Currently translated at 54.8% (34 of 62 strings)

Translated using Weblate (Korean)

Currently translated at 14.7% (21 of 142 strings)

Translated using Weblate (Korean)

Currently translated at 40.8% (20 of 49 strings)

Translated using Weblate (Korean)

Currently translated at 16.2% (21 of 129 strings)

Translated using Weblate (Korean)

Currently translated at 3.7% (30 of 790 strings)

Translated using Weblate (Korean)

Currently translated at 76.0% (19 of 25 strings)

Translated using Weblate (Korean)

Currently translated at 86.9% (20 of 23 strings)

Translated using Weblate (Korean)

Currently translated at 4.2% (20 of 469 strings)

Translated using Weblate (Korean)

Currently translated at 84.4% (49 of 58 strings)

Translated using Weblate (Korean)

Currently translated at 98.9% (98 of 99 strings)

Translated using Weblate (Korean)

Currently translated at 13.4% (144 of 1074 strings)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: fgh812 <fgh812@naver.com>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-cameras/ko/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-global/ko/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-groups/ko/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-classificationmodel/ko/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-events/ko/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-explore/ko/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-exports/ko/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-facelibrary/ko/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-live/ko/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-search/ko/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/ko/
Translation: Frigate NVR/Config - Cameras
Translation: Frigate NVR/Config - Global
Translation: Frigate NVR/Config - Groups
Translation: Frigate NVR/views-classificationmodel
Translation: Frigate NVR/views-events
Translation: Frigate NVR/views-explore
Translation: Frigate NVR/views-exports
Translation: Frigate NVR/views-facelibrary
Translation: Frigate NVR/views-live
Translation: Frigate NVR/views-search
Translation: Frigate NVR/views-settings
2026-04-30 12:25:34 -06:00
b02d928056 Translated using Weblate (Finnish)
Currently translated at 40.0% (10 of 25 strings)

Translated using Weblate (Finnish)

Currently translated at 50.0% (11 of 22 strings)

Translated using Weblate (Finnish)

Currently translated at 50.8% (120 of 236 strings)

Translated using Weblate (Finnish)

Currently translated at 20.0% (216 of 1077 strings)

Translated using Weblate (Finnish)

Currently translated at 0.8% (7 of 790 strings)

Translated using Weblate (Finnish)

Currently translated at 25.2% (44 of 174 strings)

Translated using Weblate (Finnish)

Currently translated at 67.2% (39 of 58 strings)

Translated using Weblate (Finnish)

Currently translated at 80.8% (80 of 99 strings)

Translated using Weblate (Finnish)

Currently translated at 33.6% (34 of 101 strings)

Translated using Weblate (Finnish)

Currently translated at 16.2% (14 of 86 strings)

Translated using Weblate (Finnish)

Currently translated at 100.0% (10 of 10 strings)

Translated using Weblate (Finnish)

Currently translated at 100.0% (26 of 26 strings)

Translated using Weblate (Finnish)

Currently translated at 39.0% (25 of 64 strings)

Translated using Weblate (Finnish)

Currently translated at 2.1% (10 of 469 strings)

Translated using Weblate (Finnish)

Currently translated at 8.5% (11 of 129 strings)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Tumeroz <tuomas.kettunen@hotmail.com>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/common/fi/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-auth/fi/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-dialog/fi/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-player/fi/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-cameras/fi/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-global/fi/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-groups/fi/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-validation/fi/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-classificationmodel/fi/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-events/fi/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-exports/fi/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-facelibrary/fi/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-live/fi/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/fi/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-system/fi/
Translation: Frigate NVR/Config - Cameras
Translation: Frigate NVR/Config - Global
Translation: Frigate NVR/Config - Groups
Translation: Frigate NVR/Config - Validation
Translation: Frigate NVR/common
Translation: Frigate NVR/components-auth
Translation: Frigate NVR/components-dialog
Translation: Frigate NVR/components-player
Translation: Frigate NVR/views-classificationmodel
Translation: Frigate NVR/views-events
Translation: Frigate NVR/views-exports
Translation: Frigate NVR/views-facelibrary
Translation: Frigate NVR/views-live
Translation: Frigate NVR/views-settings
Translation: Frigate NVR/views-system
2026-04-30 12:25:34 -06:00
057351e492 Translated using Weblate (French)
Currently translated at 29.0% (25 of 86 strings)

Translated using Weblate (French)

Currently translated at 100.0% (26 of 26 strings)

Translated using Weblate (French)

Currently translated at 70.1% (755 of 1076 strings)

Translated using Weblate (French)

Currently translated at 4.5% (36 of 790 strings)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: NicoA08 <nicolasantunes08@gmail.com>
Co-authored-by: Riton Du Boulon <henripl37@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-player/fr/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-global/fr/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-exports/fr/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/fr/
Translation: Frigate NVR/Config - Global
Translation: Frigate NVR/components-player
Translation: Frigate NVR/views-exports
Translation: Frigate NVR/views-settings
2026-04-30 12:25:34 -06:00
c7af51376b Translated using Weblate (Spanish)
Currently translated at 100.0% (99 of 99 strings)

Translated using Weblate (Spanish)

Currently translated at 57.4% (58 of 101 strings)

Translated using Weblate (Spanish)

Currently translated at 21.9% (103 of 469 strings)

Translated using Weblate (Spanish)

Currently translated at 70.3% (757 of 1076 strings)

Translated using Weblate (Spanish)

Currently translated at 31.3% (27 of 86 strings)

Translated using Weblate (Spanish)

Currently translated at 98.4% (127 of 129 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (25 of 25 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (26 of 26 strings)

Translated using Weblate (Spanish)

Currently translated at 20.5% (162 of 790 strings)

Translated using Weblate (Spanish)

Currently translated at 99.4% (173 of 174 strings)

Translated using Weblate (Spanish)

Currently translated at 95.9% (118 of 123 strings)

Translated using Weblate (Spanish)

Currently translated at 29.6% (24 of 81 strings)

Translated using Weblate (Spanish)

Currently translated at 67.6% (728 of 1076 strings)

Translated using Weblate (Spanish)

Currently translated at 92.7% (218 of 235 strings)

Translated using Weblate (Spanish)

Currently translated at 66.4% (715 of 1076 strings)

Translated using Weblate (Spanish)

Currently translated at 66.4% (714 of 1074 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (22 of 22 strings)

Translated using Weblate (Spanish)

Currently translated at 98.2% (57 of 58 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (23 of 23 strings)

Translated using Weblate (Spanish)

Currently translated at 92.0% (23 of 25 strings)

Translated using Weblate (Spanish)

Currently translated at 10.2% (48 of 469 strings)

Translated using Weblate (Spanish)

Currently translated at 8.9% (71 of 790 strings)

Translated using Weblate (Spanish)

Currently translated at 99.4% (173 of 174 strings)

Translated using Weblate (Spanish)

Currently translated at 98.2% (171 of 174 strings)

Translated using Weblate (Spanish)

Currently translated at 97.1% (169 of 174 strings)

Translated using Weblate (Spanish)

Currently translated at 95.9% (167 of 174 strings)

Co-authored-by: Daniel G. <keybyte@gmail.com>
Co-authored-by: Francesc Domene <fdomenef@gmail.com>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Luis Enrique Barral <luisbarral22@hotmail.com>
Co-authored-by: NecrumBlacke4984a794e814493 <k_spin@hotmail.com>
Co-authored-by: Riker <alpha9@icloud.com>
Co-authored-by: ThatStella7922 <stella@thatstel.la>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/common/es/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-dialog/es/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-player/es/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-cameras/es/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-global/es/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-groups/es/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-validation/es/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/objects/es/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-classificationmodel/es/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-exports/es/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-live/es/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/es/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-system/es/
Translation: Frigate NVR/Config - Cameras
Translation: Frigate NVR/Config - Global
Translation: Frigate NVR/Config - Groups
Translation: Frigate NVR/Config - Validation
Translation: Frigate NVR/common
Translation: Frigate NVR/components-dialog
Translation: Frigate NVR/components-player
Translation: Frigate NVR/objects
Translation: Frigate NVR/views-classificationmodel
Translation: Frigate NVR/views-exports
Translation: Frigate NVR/views-live
Translation: Frigate NVR/views-settings
Translation: Frigate NVR/views-system
2026-04-30 12:25:34 -06:00
74cfa61952 Translated using Weblate (Dutch)
Currently translated at 100.0% (99 of 99 strings)

Translated using Weblate (Dutch)

Currently translated at 50.6% (41 of 81 strings)

Translated using Weblate (Dutch)

Currently translated at 93.7% (121 of 129 strings)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Sjoerd Kocken <info@sjoerdk.nl>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-classificationmodel/nl/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-exports/nl/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-live/nl/
Translation: Frigate NVR/views-classificationmodel
Translation: Frigate NVR/views-exports
Translation: Frigate NVR/views-live
2026-04-30 12:25:34 -06:00
81899ddf57 Translated using Weblate (Indonesian)
Currently translated at 3.0% (33 of 1076 strings)

Co-authored-by: Glen Ricky Himawan <glen.ricky23@gmail.com>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/id/
Translation: Frigate NVR/views-settings
2026-04-30 12:25:34 -06:00
33e2b23f2e Translated using Weblate (Italian)
Currently translated at 100.0% (235 of 235 strings)

Translated using Weblate (Italian)

Currently translated at 100.0% (86 of 86 strings)

Translated using Weblate (Italian)

Currently translated at 100.0% (101 of 101 strings)

Translated using Weblate (Italian)

Currently translated at 9.3% (44 of 469 strings)

Translated using Weblate (Italian)

Currently translated at 10.1% (80 of 790 strings)

Translated using Weblate (Italian)

Currently translated at 9.4% (75 of 790 strings)

Translated using Weblate (Italian)

Currently translated at 8.3% (39 of 469 strings)

Translated using Weblate (Italian)

Currently translated at 100.0% (64 of 64 strings)

Translated using Weblate (Italian)

Currently translated at 100.0% (26 of 26 strings)

Translated using Weblate (Italian)

Currently translated at 100.0% (145 of 145 strings)

Translated using Weblate (Italian)

Currently translated at 5.8% (46 of 790 strings)

Translated using Weblate (Italian)

Currently translated at 100.0% (25 of 25 strings)

Translated using Weblate (Italian)

Currently translated at 5.9% (28 of 469 strings)

Translated using Weblate (Italian)

Currently translated at 100.0% (62 of 62 strings)

Translated using Weblate (Italian)

Currently translated at 5.6% (45 of 790 strings)

Translated using Weblate (Italian)

Currently translated at 61.8% (664 of 1074 strings)

Translated using Weblate (Italian)

Currently translated at 100.0% (22 of 22 strings)

Translated using Weblate (Italian)

Currently translated at 100.0% (174 of 174 strings)

Co-authored-by: Gringo <ita.translations@tiscali.it>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/common/it/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-dialog/it/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-player/it/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-cameras/it/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-global/it/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-validation/it/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-events/it/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-explore/it/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-exports/it/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/it/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-system/it/
Translation: Frigate NVR/Config - Cameras
Translation: Frigate NVR/Config - Global
Translation: Frigate NVR/Config - Validation
Translation: Frigate NVR/common
Translation: Frigate NVR/components-dialog
Translation: Frigate NVR/components-player
Translation: Frigate NVR/views-events
Translation: Frigate NVR/views-explore
Translation: Frigate NVR/views-exports
Translation: Frigate NVR/views-settings
Translation: Frigate NVR/views-system
2026-04-30 12:25:34 -06:00
b5193c9978 Translated using Weblate (Polish)
Currently translated at 100.0% (26 of 26 strings)

Translated using Weblate (Polish)

Currently translated at 82.1% (143 of 174 strings)

Translated using Weblate (Polish)

Currently translated at 60.3% (652 of 1081 strings)

Translated using Weblate (Polish)

Currently translated at 72.7% (16 of 22 strings)

Translated using Weblate (Polish)

Currently translated at 67.1% (43 of 64 strings)

Translated using Weblate (Polish)

Currently translated at 4.3% (34 of 790 strings)

Translated using Weblate (Polish)

Currently translated at 100.0% (99 of 99 strings)

Translated using Weblate (Polish)

Currently translated at 18.6% (16 of 86 strings)

Translated using Weblate (Polish)

Currently translated at 22.7% (5 of 22 strings)

Translated using Weblate (Polish)

Currently translated at 3.0% (24 of 790 strings)

Translated using Weblate (Polish)

Currently translated at 16.2% (14 of 86 strings)

Translated using Weblate (Polish)

Currently translated at 2.6% (21 of 790 strings)

Translated using Weblate (Polish)

Currently translated at 13.6% (3 of 22 strings)

Translated using Weblate (Polish)

Currently translated at 98.9% (98 of 99 strings)

Translated using Weblate (Polish)

Currently translated at 15.1% (13 of 86 strings)

Translated using Weblate (Polish)

Currently translated at 100.0% (25 of 25 strings)

Translated using Weblate (Polish)

Currently translated at 100.0% (145 of 145 strings)

Co-authored-by: Dawid Kędzierski <dawidk612@wp.pl>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: J P <jpoloczek24@gmail.com>
Co-authored-by: Michał Budzik <budzikmichal@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-player/pl/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-global/pl/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-groups/pl/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-validation/pl/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-events/pl/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-explore/pl/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-exports/pl/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-live/pl/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/pl/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-system/pl/
Translation: Frigate NVR/Config - Global
Translation: Frigate NVR/Config - Groups
Translation: Frigate NVR/Config - Validation
Translation: Frigate NVR/components-player
Translation: Frigate NVR/views-events
Translation: Frigate NVR/views-explore
Translation: Frigate NVR/views-exports
Translation: Frigate NVR/views-live
Translation: Frigate NVR/views-settings
Translation: Frigate NVR/views-system
2026-04-30 12:25:34 -06:00
93443773f4 Translated using Weblate (Hungarian)
Currently translated at 18.6% (16 of 86 strings)

Translated using Weblate (Hungarian)

Currently translated at 7.6% (36 of 469 strings)

Translated using Weblate (Hungarian)

Currently translated at 80.0% (20 of 25 strings)

Translated using Weblate (Hungarian)

Currently translated at 5.9% (47 of 790 strings)

Translated using Weblate (Hungarian)

Currently translated at 86.3% (19 of 22 strings)

Translated using Weblate (Hungarian)

Currently translated at 74.7% (130 of 174 strings)

Translated using Weblate (Hungarian)

Currently translated at 4.1% (33 of 790 strings)

Translated using Weblate (Hungarian)

Currently translated at 100.0% (26 of 26 strings)

Translated using Weblate (Hungarian)

Currently translated at 52.0% (13 of 25 strings)

Translated using Weblate (Hungarian)

Currently translated at 92.7% (218 of 235 strings)

Translated using Weblate (Hungarian)

Currently translated at 39.6% (427 of 1076 strings)

Translated using Weblate (Hungarian)

Currently translated at 6.1% (29 of 469 strings)

Translated using Weblate (Hungarian)

Currently translated at 59.0% (13 of 22 strings)

Translated using Weblate (Hungarian)

Currently translated at 66.1% (41 of 62 strings)

Translated using Weblate (Hungarian)

Currently translated at 87.8% (87 of 99 strings)

Translated using Weblate (Hungarian)

Currently translated at 5.5% (26 of 469 strings)

Translated using Weblate (Hungarian)

Currently translated at 54.5% (12 of 22 strings)

Translated using Weblate (Hungarian)

Currently translated at 37.9% (408 of 1076 strings)

Translated using Weblate (Hungarian)

Currently translated at 44.0% (11 of 25 strings)

Translated using Weblate (Hungarian)

Currently translated at 3.7% (30 of 790 strings)

Translated using Weblate (Hungarian)

Currently translated at 71.8% (125 of 174 strings)

Translated using Weblate (Hungarian)

Currently translated at 86.8% (86 of 99 strings)

Translated using Weblate (Hungarian)

Currently translated at 4.4% (21 of 469 strings)

Translated using Weblate (Hungarian)

Currently translated at 65.2% (15 of 23 strings)

Translated using Weblate (Hungarian)

Currently translated at 2.6% (21 of 790 strings)

Co-authored-by: Da4ndo <vrgdnl20@gmail.com>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: KecskeTech <teonyitas@gmail.com>
Co-authored-by: ZELO <zg1990@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/common/hu/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-player/hu/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-cameras/hu/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-global/hu/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-groups/hu/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-validation/hu/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-events/hu/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-exports/hu/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-live/hu/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/hu/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-system/hu/
Translation: Frigate NVR/Config - Cameras
Translation: Frigate NVR/Config - Global
Translation: Frigate NVR/Config - Groups
Translation: Frigate NVR/Config - Validation
Translation: Frigate NVR/common
Translation: Frigate NVR/components-player
Translation: Frigate NVR/views-events
Translation: Frigate NVR/views-exports
Translation: Frigate NVR/views-live
Translation: Frigate NVR/views-settings
Translation: Frigate NVR/views-system
2026-04-30 12:25:34 -06:00
57eb7db5c9 Translated using Weblate (Catalan)
Currently translated at 100.0% (236 of 236 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (1081 of 1081 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (1077 of 1077 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (101 of 101 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (26 of 26 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (64 of 64 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (1077 of 1077 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (86 of 86 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (58 of 58 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (145 of 145 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (95 of 95 strings)

Translated using Weblate (Catalan)

Currently translated at 97.8% (93 of 95 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (95 of 95 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (81 of 81 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (145 of 145 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (1076 of 1076 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (790 of 790 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (1074 of 1074 strings)

Co-authored-by: Eduardo Pastor Fernández <123eduardoneko123@gmail.com>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: anton garcias <isaga.percompartir@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/common/ca/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-dialog/ca/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-player/ca/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-global/ca/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-events/ca/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-explore/ca/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-exports/ca/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-facelibrary/ca/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/ca/
Translation: Frigate NVR/Config - Global
Translation: Frigate NVR/common
Translation: Frigate NVR/components-dialog
Translation: Frigate NVR/components-player
Translation: Frigate NVR/views-events
Translation: Frigate NVR/views-explore
Translation: Frigate NVR/views-exports
Translation: Frigate NVR/views-facelibrary
Translation: Frigate NVR/views-settings
2026-04-30 12:25:34 -06:00
Hosted WeblateNicolas MowenYusuke, Hirota <hirota.yusuke@jp.fujitsu.com>alpha
eb73277322 Translated using Weblate (Japanese)
Currently translated at 10.0% (79 of 790 strings)

Translated using Weblate (Japanese)

Currently translated at 63.4% (686 of 1081 strings)

Translated using Weblate (Japanese)

Currently translated at 63.4% (686 of 1081 strings)

Translated using Weblate (Japanese)

Currently translated at 80.1% (81 of 101 strings)

Translated using Weblate (Japanese)

Currently translated at 9.8% (46 of 469 strings)

Translated using Weblate (Japanese)

Currently translated at 96.5% (56 of 58 strings)

Translated using Weblate (Japanese)

Currently translated at 8.7% (41 of 469 strings)

Translated using Weblate (Japanese)

Currently translated at 70.3% (45 of 64 strings)

Translated using Weblate (Japanese)

Currently translated at 90.8% (158 of 174 strings)

Translated using Weblate (Japanese)

Currently translated at 76.2% (77 of 101 strings)

Translated using Weblate (Japanese)

Currently translated at 94.5% (122 of 129 strings)

Translated using Weblate (Japanese)

Currently translated at 100.0% (74 of 74 strings)

Translated using Weblate (Japanese)

Currently translated at 62.9% (681 of 1081 strings)

Translated using Weblate (Japanese)

Currently translated at 8.9% (71 of 790 strings)

Translated using Weblate (Japanese)

Currently translated at 6.1% (29 of 469 strings)

Translated using Weblate (Japanese)

Currently translated at 61.8% (669 of 1081 strings)

Translated using Weblate (Japanese)

Currently translated at 5.6% (45 of 790 strings)

Translated using Weblate (Japanese)

Currently translated at 92.3% (218 of 236 strings)

Translated using Weblate (Japanese)

Currently translated at 61.8% (669 of 1081 strings)

Translated using Weblate (Japanese)

Currently translated at 100.0% (25 of 25 strings)

Translated using Weblate (Japanese)

Currently translated at 68.3% (69 of 101 strings)

Translated using Weblate (Japanese)

Currently translated at 5.9% (28 of 469 strings)

Translated using Weblate (Japanese)

Currently translated at 100.0% (99 of 99 strings)

Translated using Weblate (Japanese)

Currently translated at 89.0% (155 of 174 strings)

Translated using Weblate (Japanese)

Currently translated at 67.1% (43 of 64 strings)

Translated using Weblate (Japanese)

Currently translated at 5.5% (44 of 790 strings)

Translated using Weblate (Japanese)

Currently translated at 93.7% (121 of 129 strings)

Translated using Weblate (Japanese)

Currently translated at 100.0% (22 of 22 strings)

Translated using Weblate (Japanese)

Currently translated at 100.0% (26 of 26 strings)

Translated using Weblate (Japanese)

Currently translated at 61.0% (658 of 1077 strings)

Translated using Weblate (Japanese)

Currently translated at 62.3% (63 of 101 strings)

Translated using Weblate (Japanese)

Currently translated at 94.4% (137 of 145 strings)

Translated using Weblate (Japanese)

Currently translated at 92.3% (217 of 235 strings)

Translated using Weblate (Japanese)

Currently translated at 65.6% (42 of 64 strings)

Translated using Weblate (Japanese)

Currently translated at 98.8% (85 of 86 strings)

Translated using Weblate (Japanese)

Currently translated at 60.9% (656 of 1076 strings)

Translated using Weblate (Japanese)

Currently translated at 100.0% (74 of 74 strings)

Translated using Weblate (Japanese)

Currently translated at 93.0% (120 of 129 strings)

Translated using Weblate (Japanese)

Currently translated at 37.2% (32 of 86 strings)

Translated using Weblate (Japanese)

Currently translated at 37.2% (32 of 86 strings)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Yusuke, Hirota <hirota.yusuke@jp.fujitsu.com>
Co-authored-by: alpha <etc@alpha-line.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/common/ja/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-dialog/ja/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-filter/ja/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-player/ja/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-cameras/ja/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-global/ja/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-groups/ja/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-validation/ja/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-classificationmodel/ja/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-events/ja/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-explore/ja/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-exports/ja/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-facelibrary/ja/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-live/ja/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/ja/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-system/ja/
Translation: Frigate NVR/Config - Cameras
Translation: Frigate NVR/Config - Global
Translation: Frigate NVR/Config - Groups
Translation: Frigate NVR/Config - Validation
Translation: Frigate NVR/common
Translation: Frigate NVR/components-dialog
Translation: Frigate NVR/components-filter
Translation: Frigate NVR/components-player
Translation: Frigate NVR/views-classificationmodel
Translation: Frigate NVR/views-events
Translation: Frigate NVR/views-explore
Translation: Frigate NVR/views-exports
Translation: Frigate NVR/views-facelibrary
Translation: Frigate NVR/views-live
Translation: Frigate NVR/views-settings
Translation: Frigate NVR/views-system
2026-04-30 12:25:34 -06:00
d3853688ed Translated using Weblate (Bulgarian)
Currently translated at 0.2% (2 of 790 strings)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Ivan Ivanov <ivan.ivanov@scoutbg.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-global/bg/
Translation: Frigate NVR/Config - Global
2026-04-30 12:25:34 -06:00
5fd8fc881a Translated using Weblate (Romanian)
Currently translated at 100.0% (1081 of 1081 strings)

Translated using Weblate (Romanian)

Currently translated at 100.0% (236 of 236 strings)

Translated using Weblate (Romanian)

Currently translated at 100.0% (1077 of 1077 strings)

Translated using Weblate (Romanian)

Currently translated at 100.0% (26 of 26 strings)

Translated using Weblate (Romanian)

Currently translated at 100.0% (101 of 101 strings)

Translated using Weblate (Romanian)

Currently translated at 100.0% (64 of 64 strings)

Translated using Weblate (Romanian)

Currently translated at 100.0% (86 of 86 strings)

Translated using Weblate (Romanian)

Currently translated at 100.0% (62 of 62 strings)

Translated using Weblate (Romanian)

Currently translated at 100.0% (95 of 95 strings)

Translated using Weblate (Romanian)

Currently translated at 100.0% (81 of 81 strings)

Translated using Weblate (Romanian)

Currently translated at 100.0% (145 of 145 strings)

Translated using Weblate (Romanian)

Currently translated at 100.0% (1076 of 1076 strings)

Translated using Weblate (Romanian)

Currently translated at 100.0% (1074 of 1074 strings)

Translated using Weblate (Romanian)

Currently translated at 100.0% (790 of 790 strings)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: lukasig <lukasig@hotmail.com>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/common/ro/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-dialog/ro/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-player/ro/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-global/ro/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-events/ro/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-explore/ro/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-exports/ro/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/ro/
Translation: Frigate NVR/Config - Global
Translation: Frigate NVR/common
Translation: Frigate NVR/components-dialog
Translation: Frigate NVR/components-player
Translation: Frigate NVR/views-events
Translation: Frigate NVR/views-explore
Translation: Frigate NVR/views-exports
Translation: Frigate NVR/views-settings
2026-04-30 12:25:34 -06:00
7000712454 Translated using Weblate (Russian)
Currently translated at 8.4% (67 of 790 strings)

Translated using Weblate (Russian)

Currently translated at 100.0% (23 of 23 strings)

Translated using Weblate (Russian)

Currently translated at 100.0% (99 of 99 strings)

Translated using Weblate (Russian)

Currently translated at 93.7% (121 of 129 strings)

Translated using Weblate (Russian)

Currently translated at 88.5% (154 of 174 strings)

Translated using Weblate (Russian)

Currently translated at 100.0% (58 of 58 strings)

Translated using Weblate (Russian)

Currently translated at 93.1% (54 of 58 strings)

Translated using Weblate (Russian)

Currently translated at 61.3% (659 of 1074 strings)

Translated using Weblate (Russian)

Currently translated at 88.0% (22 of 25 strings)

Translated using Weblate (Russian)

Currently translated at 95.4% (21 of 22 strings)

Translated using Weblate (Russian)

Currently translated at 69.3% (43 of 62 strings)

Translated using Weblate (Russian)

Currently translated at 92.3% (217 of 235 strings)

Co-authored-by: Anatoly Raev <cralixraev@gmail.com>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/common/ru/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-dialog/ru/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-global/ru/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-groups/ru/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-validation/ru/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-classificationmodel/ru/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-events/ru/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-exports/ru/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-facelibrary/ru/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-live/ru/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/ru/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-system/ru/
Translation: Frigate NVR/Config - Global
Translation: Frigate NVR/Config - Groups
Translation: Frigate NVR/Config - Validation
Translation: Frigate NVR/common
Translation: Frigate NVR/components-dialog
Translation: Frigate NVR/views-classificationmodel
Translation: Frigate NVR/views-events
Translation: Frigate NVR/views-exports
Translation: Frigate NVR/views-facelibrary
Translation: Frigate NVR/views-live
Translation: Frigate NVR/views-settings
Translation: Frigate NVR/views-system
2026-04-30 12:25:34 -06:00
72068b6823 Translated using Weblate (Estonian)
Currently translated at 100.0% (236 of 236 strings)

Translated using Weblate (Estonian)

Currently translated at 100.0% (26 of 26 strings)

Translated using Weblate (Estonian)

Currently translated at 48.9% (24 of 49 strings)

Translated using Weblate (Estonian)

Currently translated at 100.0% (64 of 64 strings)

Translated using Weblate (Estonian)

Currently translated at 54.8% (275 of 501 strings)

Translated using Weblate (Estonian)

Currently translated at 32.7% (19 of 58 strings)

Translated using Weblate (Estonian)

Currently translated at 100.0% (99 of 99 strings)

Translated using Weblate (Estonian)

Currently translated at 1.7% (8 of 469 strings)

Translated using Weblate (Estonian)

Currently translated at 0.2% (2 of 790 strings)

Translated using Weblate (Estonian)

Currently translated at 100.0% (62 of 62 strings)

Translated using Weblate (Estonian)

Currently translated at 100.0% (25 of 25 strings)

Translated using Weblate (Estonian)

Currently translated at 33.7% (49 of 145 strings)

Translated using Weblate (Estonian)

Currently translated at 100.0% (74 of 74 strings)

Translated using Weblate (Estonian)

Currently translated at 91.8% (68 of 74 strings)

Translated using Weblate (Estonian)

Currently translated at 77.0% (57 of 74 strings)

Translated using Weblate (Estonian)

Currently translated at 100.0% (22 of 22 strings)

Translated using Weblate (Estonian)

Currently translated at 1.4% (7 of 469 strings)

Translated using Weblate (Estonian)

Currently translated at 0.1% (1 of 790 strings)

Translated using Weblate (Estonian)

Currently translated at 77.4% (48 of 62 strings)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Priit Jõerüüt <jrthwlate@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/audio/et/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/common/et/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-filter/et/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-player/et/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-cameras/et/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-global/et/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-groups/et/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-validation/et/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-events/et/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-explore/et/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-facelibrary/et/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-live/et/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-search/et/
Translation: Frigate NVR/Config - Cameras
Translation: Frigate NVR/Config - Global
Translation: Frigate NVR/Config - Groups
Translation: Frigate NVR/Config - Validation
Translation: Frigate NVR/audio
Translation: Frigate NVR/common
Translation: Frigate NVR/components-filter
Translation: Frigate NVR/components-player
Translation: Frigate NVR/views-events
Translation: Frigate NVR/views-explore
Translation: Frigate NVR/views-facelibrary
Translation: Frigate NVR/views-live
Translation: Frigate NVR/views-search
2026-04-30 12:25:34 -06:00
04233c0574 Translated using Weblate (Greek)
Currently translated at 0.5% (4 of 790 strings)

Co-authored-by: D2m2TrYs Vlogs <minecrafymhtsarat@gmail.com>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-global/el/
Translation: Frigate NVR/Config - Global
2026-04-30 12:25:34 -06:00
1584400916 Translated using Weblate (German)
Currently translated at 100.0% (95 of 95 strings)

Translated using Weblate (German)

Currently translated at 100.0% (86 of 86 strings)

Translated using Weblate (German)

Currently translated at 100.0% (790 of 790 strings)

Translated using Weblate (German)

Currently translated at 100.0% (1076 of 1076 strings)

Translated using Weblate (German)

Currently translated at 100.0% (145 of 145 strings)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Sebastian Sie <sebastian.neuplanitz@googlemail.com>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-dialog/de/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-global/de/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-explore/de/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-exports/de/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/de/
Translation: Frigate NVR/Config - Global
Translation: Frigate NVR/components-dialog
Translation: Frigate NVR/views-explore
Translation: Frigate NVR/views-exports
Translation: Frigate NVR/views-settings
2026-04-30 12:25:34 -06:00
0d1189f26a Translated using Weblate (Portuguese (Brazil))
Currently translated at 5.1% (41 of 790 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 44.9% (58 of 129 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 5.7% (27 of 469 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 29.6% (24 of 81 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 4.9% (39 of 790 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 97.4% (229 of 235 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 5.5% (26 of 469 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (99 of 99 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 77.5% (135 of 174 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 43.7% (470 of 1074 strings)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Nitokui <xaube@proton.me>
Co-authored-by: Tiago Krüger <tiagokruger404@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/common/pt_BR/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-cameras/pt_BR/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-global/pt_BR/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-classificationmodel/pt_BR/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-exports/pt_BR/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-live/pt_BR/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/pt_BR/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-system/pt_BR/
Translation: Frigate NVR/Config - Cameras
Translation: Frigate NVR/Config - Global
Translation: Frigate NVR/common
Translation: Frigate NVR/views-classificationmodel
Translation: Frigate NVR/views-exports
Translation: Frigate NVR/views-live
Translation: Frigate NVR/views-settings
Translation: Frigate NVR/views-system
2026-04-30 12:25:34 -06:00
29eff13a4c Translated using Weblate (Turkish)
Currently translated at 59.9% (645 of 1076 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (26 of 26 strings)

Translated using Weblate (Turkish)

Currently translated at 1.7% (8 of 469 strings)

Translated using Weblate (Turkish)

Currently translated at 87.1% (88 of 101 strings)

Translated using Weblate (Turkish)

Currently translated at 0.8% (7 of 790 strings)

Translated using Weblate (Turkish)

Currently translated at 17.4% (15 of 86 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (235 of 235 strings)

Translated using Weblate (Turkish)

Currently translated at 92.0% (23 of 25 strings)

Translated using Weblate (Turkish)

Currently translated at 27.2% (6 of 22 strings)

Translated using Weblate (Turkish)

Currently translated at 0.3% (3 of 790 strings)

Translated using Weblate (Turkish)

Currently translated at 1.4% (7 of 469 strings)

Co-authored-by: Emre Varcı <emrevarci@gmail.com>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: R&MC Team <mahmuttuma9@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/common/tr/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-dialog/tr/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-player/tr/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-cameras/tr/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-global/tr/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-groups/tr/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-validation/tr/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-exports/tr/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/tr/
Translation: Frigate NVR/Config - Cameras
Translation: Frigate NVR/Config - Global
Translation: Frigate NVR/Config - Groups
Translation: Frigate NVR/Config - Validation
Translation: Frigate NVR/common
Translation: Frigate NVR/components-dialog
Translation: Frigate NVR/components-player
Translation: Frigate NVR/views-exports
Translation: Frigate NVR/views-settings
2026-04-30 12:25:34 -06:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
1162c01b3e Bump actions/upload-artifact from 4 to 7 (#22795)
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 4 to 7.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/v4...v7)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-30 12:20:11 -06:00
ryzendigoandGitHub 27b7ef0a7a fix: mismatched time sources break birdseye idle heartbeat (#22466)
The idle heartbeat check in BirdsEyeOutputProcess.update() compares
time.monotonic() (seconds since an arbitrary point, typically boot)
against last_output_time which is set from datetime.datetime.now().timestamp()
(Unix epoch seconds).

These are completely different time bases. The subtraction produces a
large negative number, so the idle heartbeat condition can never be
satisfied. This means birdseye stops sending frames when all cameras
go idle, instead of continuing at the configured idle_heartbeat_fps.

Use datetime.datetime.now().timestamp() consistently for both the
heartbeat check and the output time tracking.
2026-04-30 12:16:49 -06:00
01a7ec1060 Miscellaneous fixes (#23044)
* Move openai specific workaround so it doesn't apply to other providers

* Fix gemini tool calling

* Improve efficiency of frame listing for previews

* debug replay fixes

- initial selection without changing the radio button in the dialog would select 1 hour (rather than 1 minute)
- use CLIPS_DIR instead of CACHE_DIR so that longer replay clips don't cause tmpfs cache overflows

* don't re-render the tracking details overlay on every video time tick

* change pinned to planned

---------

Co-authored-by: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com>
2026-04-30 12:53:34 -05:00
95b5b89ed9 Miscellaneous fixes (#23032)
CI / AMD64 Build (push) Waiting to run
CI / ARM Build (push) Waiting to run
CI / Jetson Jetpack 6 (push) Waiting to run
CI / AMD64 Extra Build (push) Blocked by required conditions
CI / ARM Extra Build (push) Blocked by required conditions
CI / Synaptics Build (push) Blocked by required conditions
CI / Assemble and push default build (push) Blocked by required conditions
* ensure embeddings process restarts after maintainer thread crash

* add docs link to media sync settings

* fix color

Co-authored-by: Copilot <copilot@github.com>

* match link color with other sections

* ensure recording staleness threshold scales with segment_time

* docs tweak

* Fix llama.cpp media marker

* Fix gemini tools call

---------

Co-authored-by: Copilot <copilot@github.com>
Co-authored-by: Nicolas Mowen <nickmowen213@gmail.com>
2026-04-29 16:20:19 -06:00
Nicolas MowenandGitHub a182385618 Fix ROCm build (#23040)
CI / AMD64 Build (push) Waiting to run
CI / ARM Build (push) Waiting to run
CI / Jetson Jetpack 6 (push) Waiting to run
CI / AMD64 Extra Build (push) Blocked by required conditions
CI / Synaptics Build (push) Blocked by required conditions
CI / Assemble and push default build (push) Blocked by required conditions
CI / ARM Extra Build (push) Blocked by required conditions
2026-04-29 09:30:16 -05:00
Nicolas MowenandGitHub 088e1ad7ef Add ability to download case as zip (#23034)
CI / AMD64 Build (push) Waiting to run
CI / ARM Build (push) Waiting to run
CI / Jetson Jetpack 6 (push) Waiting to run
CI / AMD64 Extra Build (push) Blocked by required conditions
CI / ARM Extra Build (push) Blocked by required conditions
CI / Synaptics Build (push) Blocked by required conditions
CI / Assemble and push default build (push) Blocked by required conditions
2026-04-28 19:11:41 -05:00
011ad8eda7 Miscellaneous fixes (#23017)
CI / AMD64 Build (push) Waiting to run
CI / ARM Build (push) Waiting to run
CI / Jetson Jetpack 6 (push) Waiting to run
CI / AMD64 Extra Build (push) Blocked by required conditions
CI / ARM Extra Build (push) Blocked by required conditions
CI / Synaptics Build (push) Blocked by required conditions
CI / Assemble and push default build (push) Blocked by required conditions
* add ui to camera config update topics enum

* add mqtt to camera config update enum

* ensure cleanup runs when an event end skips post-processing

* end any in-progress audio events when audio detection is disabled

we already end in-progress audio events when we disable a camera, but this mirrors that logic for specifically disabling audio detection

* Improve GenAI metadata

* fix invalid recording segment topic being misrouted to the valid handler

* Add confidence default to avoid unnecessary field causing issues

---------

Co-authored-by: Nicolas Mowen <nickmowen213@gmail.com>
2026-04-28 08:54:09 -06:00
4171efcd79 Miscellaneous fixes (#23009)
CI / AMD64 Build (push) Has been cancelled
CI / ARM Build (push) Has been cancelled
CI / Jetson Jetpack 6 (push) Has been cancelled
CI / AMD64 Extra Build (push) Has been cancelled
CI / ARM Extra Build (push) Has been cancelled
CI / Assemble and push default build (push) Has been cancelled
CI / Synaptics Build (push) Has been cancelled
* Reduce max frames per second to 1

* Use pydantic but don't fail if some constraints are not met.

* Adjust limits

* Adjust limits

* Cleanup

* add unsaved changes icon/popover to individual settings section

* allow changing camera friendly_name from camera management pane

---------

Co-authored-by: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com>
2026-04-26 17:09:35 -05:00
Nicolas MowenandGitHub 0ea8924727 GenAI Optimizations (#23006)
CI / AMD64 Build (push) Waiting to run
CI / ARM Build (push) Waiting to run
CI / Jetson Jetpack 6 (push) Waiting to run
CI / AMD64 Extra Build (push) Blocked by required conditions
CI / ARM Extra Build (push) Blocked by required conditions
CI / Synaptics Build (push) Blocked by required conditions
CI / Assemble and push default build (push) Blocked by required conditions
* Test for image token usage in llama.cpp so we can more appropriately decide how many frames to include

* Limit based on frames per second

* handle zone case sensitivity

* Improve formatting

* Add observations field so model can build CoT before outputting used fields
2026-04-25 17:38:18 -05:00
1a1994ca17 Miscellaneous fixes (#23000)
CI / AMD64 Build (push) Waiting to run
CI / ARM Build (push) Waiting to run
CI / Jetson Jetpack 6 (push) Waiting to run
CI / AMD64 Extra Build (push) Blocked by required conditions
CI / ARM Extra Build (push) Blocked by required conditions
CI / Synaptics Build (push) Blocked by required conditions
CI / Assemble and push default build (push) Blocked by required conditions
* ensure classification wizard dialog is scrollable on mobile too

* add chat and features group to mobile menu

Co-authored-by: Copilot <copilot@github.com>

* Set min length for summary too

* Don't use orange for review item

---------

Co-authored-by: Copilot <copilot@github.com>
Co-authored-by: Nicolas Mowen <nickmowen213@gmail.com>
2026-04-25 09:12:20 -06:00
Josh HawkinsandGitHub 819e8de172 Revert modal changes (#23001)
* revert modal changes from #22963

* add test and lint
2026-04-25 07:21:13 -06:00
Nicolas MowenandGitHub ea246384bf Set min length for GenAI scene to encourage details (#22996)
CI / AMD64 Build (push) Waiting to run
CI / ARM Build (push) Waiting to run
CI / Jetson Jetpack 6 (push) Waiting to run
CI / AMD64 Extra Build (push) Blocked by required conditions
CI / ARM Extra Build (push) Blocked by required conditions
CI / Synaptics Build (push) Blocked by required conditions
CI / Assemble and push default build (push) Blocked by required conditions
2026-04-24 18:40:52 -05:00
Josh HawkinsandGitHub d8f70b7fed Fix dismissable layer regression (#22995)
* reset several dropdown and context menus to non-modal

* add specific e2e test to confirm pointer events bug
2026-04-24 17:24:24 -06:00
Josh HawkinsandGitHub 434ef358a2 add analyze keyframes testing script (#22994)
CI / ARM Build (push) Waiting to run
CI / Jetson Jetpack 6 (push) Waiting to run
CI / AMD64 Extra Build (push) Blocked by required conditions
CI / ARM Extra Build (push) Blocked by required conditions
CI / Synaptics Build (push) Blocked by required conditions
CI / Assemble and push default build (push) Blocked by required conditions
CI / AMD64 Build (push) Waiting to run
2026-04-24 11:42:30 -05:00
Nicolas MowenandGitHub fe269b77b8 Optimize face recognition (#22993)
* Improve mean generation for faces to remove outlier embeddings

* Create testing scripts folder

* Fix mypy
2026-04-24 11:14:28 -05:00
Josh HawkinsandGitHub 77831304a7 Camera access fixes (#22987)
CI / AMD64 Build (push) Waiting to run
CI / ARM Build (push) Waiting to run
CI / Jetson Jetpack 6 (push) Waiting to run
CI / AMD64 Extra Build (push) Blocked by required conditions
CI / ARM Extra Build (push) Blocked by required conditions
CI / Synaptics Build (push) Blocked by required conditions
CI / Assemble and push default build (push) Blocked by required conditions
* only send monitoring notifications to users with camera access

* check access to similarity search event id camera

* require admin role for storage usage endpoint

* check camera access for jsmpeg and birdseye cameras

* tests

* formatting
2026-04-23 12:27:49 -06:00
Josh HawkinsandGitHub 1a6d04fde7 use object-anchored snapshot crops for classification wizard examples (#22985) 2026-04-23 08:53:48 -05:00
Josh HawkinsandGitHub 4a1b7a1629 enforce python-level timeout on ffprobe subprocesses (#22984) 2026-04-23 07:16:22 -06:00
Nicolas MowenandGitHub 8eace9c3e7 WebUI tweaks (#22980)
CI / AMD64 Build (push) Waiting to run
CI / ARM Build (push) Waiting to run
CI / Jetson Jetpack 6 (push) Waiting to run
CI / AMD64 Extra Build (push) Blocked by required conditions
CI / ARM Extra Build (push) Blocked by required conditions
CI / Synaptics Build (push) Blocked by required conditions
CI / Assemble and push default build (push) Blocked by required conditions
* Use escape key to go back to main camera dashboard

* Add icon showing when review item is needing review
2026-04-22 21:37:17 -05:00
Josh HawkinsandGitHub 8fc1e97df5 Stream probe fallback (#22971)
* fall back to tcp transport when rtsp probes fail over udp

* tweak wizard message
2026-04-22 14:38:54 -06:00
eXtremeSHOKandGitHub 0a332cada9 Update third_party_extensions.md (#22973) 2026-04-22 14:38:36 -06:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
ba499201e6 Bump lodash-es from 4.17.23 to 4.18.1 in /web (#22733)
CI / AMD64 Build (push) Waiting to run
CI / ARM Build (push) Waiting to run
CI / Jetson Jetpack 6 (push) Waiting to run
CI / AMD64 Extra Build (push) Blocked by required conditions
CI / ARM Extra Build (push) Blocked by required conditions
CI / Synaptics Build (push) Blocked by required conditions
CI / Assemble and push default build (push) Blocked by required conditions
Bumps [lodash-es](https://github.com/lodash/lodash) from 4.17.23 to 4.18.1.
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.23...4.18.1)

---
updated-dependencies:
- dependency-name: lodash-es
  dependency-version: 4.18.1
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-22 15:03:43 -05:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
c244e6582a Bump path-to-regexp from 0.1.12 to 0.1.13 in /docs (#22683)
Bumps [path-to-regexp](https://github.com/pillarjs/path-to-regexp) from 0.1.12 to 0.1.13.
- [Release notes](https://github.com/pillarjs/path-to-regexp/releases)
- [Changelog](https://github.com/pillarjs/path-to-regexp/blob/v.0.1.13/History.md)
- [Commits](https://github.com/pillarjs/path-to-regexp/compare/v0.1.12...v.0.1.13)

---
updated-dependencies:
- dependency-name: path-to-regexp
  dependency-version: 0.1.13
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-22 14:39:46 -05:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
fff3594553 Bump lodash from 4.17.23 to 4.18.1 in /web (#22787)
Bumps [lodash](https://github.com/lodash/lodash) from 4.17.23 to 4.18.1.
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.23...4.18.1)

---
updated-dependencies:
- dependency-name: lodash
  dependency-version: 4.18.1
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-22 14:39:08 -05:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
25bfb2c481 Bump python-multipart from 0.0.20 to 0.0.26 in /docker/main (#22894)
Bumps [python-multipart](https://github.com/Kludex/python-multipart) from 0.0.20 to 0.0.26.
- [Release notes](https://github.com/Kludex/python-multipart/releases)
- [Changelog](https://github.com/Kludex/python-multipart/blob/master/CHANGELOG.md)
- [Commits](https://github.com/Kludex/python-multipart/compare/0.0.20...0.0.26)

---
updated-dependencies:
- dependency-name: python-multipart
  dependency-version: 0.0.26
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-22 14:38:56 -05:00
b7261c8e70 GenAI Tweaks (#22968)
* Add debug logs

* refresh embeddings maintainer genai clients on config update

---------

Co-authored-by: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com>
2026-04-22 09:55:54 -06:00
Josh HawkinsandGitHub ad9092d0da Tweaks (#22965)
* use ffmpeg to probe rtsp urls instead of cv2

cv2 is faster (no subprocess launch) and will continue to be used for recording segments

* tweak faq

* change unsaved color to orange

avoids confusion with validation errors (red)

* don't use any variant of orange as a profile color

avoids confusion with unsaved changes

* more unsaved color tweaks
2026-04-22 09:19:30 -06:00
Nicolas MowenandGitHub 20705a3e97 Update oneVPL (#22966) 2026-04-22 08:50:37 -06:00
Josh HawkinsandGitHub f4ac063b37 Add camera wizard improvements (#22963)
* warn in camera wizard when detect stream resolution cannot be determined

* add timeout and tcp fallback for rtsp urls only
2026-04-22 08:15:17 -05:00
Abhilash KishoreandGitHub 2dcaeb6809 fix: bump OpenVINO to 2025.4.x to resolve LXC container detector crash (#22859)
* fix: bump OpenVINO to 2025.4.x to resolve LXC container crash

* fix: replace openvino + onnxruntime with onnxruntime-openvino 1.24.*

onnxruntime-openvino 1.24.* bundles OpenVINO 2025.4.1, which fixes a
crash in constrained CPU environments (e.g. Proxmox LXC) where
lin_system_conf.cpp calls stoi("") on empty strings read from offline
CPU sysfs entries.

Consolidating to onnxruntime-openvino also ensures the OpenVINO runtime
and ONNX Runtime OpenVINO EP are always compatible versions.

* revert: restore onnxruntime, keep openvino bump

Reverting onnxruntime-openvino consolidation - onnxruntime is used with
multiple execution providers (CUDA, TensorRT, MIGraphX, CPU) and cannot
be replaced wholesale with the openvino-specific wheel.
2026-04-22 07:12:14 -06:00
Josh HawkinsandGitHub 962d36323b Improve frontend e2e tests (#22958)
CI / AMD64 Build (push) Waiting to run
CI / ARM Build (push) Waiting to run
CI / Jetson Jetpack 6 (push) Waiting to run
CI / AMD64 Extra Build (push) Blocked by required conditions
CI / ARM Extra Build (push) Blocked by required conditions
CI / Synaptics Build (push) Blocked by required conditions
CI / Assemble and push default build (push) Blocked by required conditions
* add mock data

* add helpers

* page objects

* updated specs

* remove PENDING_REWARITE

* formatting
2026-04-21 16:32:18 -06:00
Josh HawkinsandGitHub 3b81416299 Update Radix deps (#22957)
CI / AMD64 Extra Build (push) Blocked by required conditions
CI / ARM Extra Build (push) Blocked by required conditions
CI / Synaptics Build (push) Blocked by required conditions
CI / Assemble and push default build (push) Blocked by required conditions
CI / AMD64 Build (push) Waiting to run
CI / ARM Build (push) Waiting to run
CI / Jetson Jetpack 6 (push) Waiting to run
* Bump radix-ui packages to align react-dismissable-layer version and fix nested overlay pointer-events bug

* remove workarounds for radix pointer events issues on dropdown and context menus

* remove disablePortal from popover

* remove modal on popovers

* remove workarounds in restart dialog

* keep onCloseAutoFocus for face, classification, and ptz

these are necessary to prevent tooltips from re-showing and from the arrow keys from reopening the ptz presets menu

* add tests
2026-04-21 08:48:48 -06:00
Eduardo-JaramilloandGitHub 7d315c5e6b remove temporary DB cleanup check (#22950)
CI / ARM Build (push) Waiting to run
CI / Jetson Jetpack 6 (push) Waiting to run
CI / AMD64 Extra Build (push) Blocked by required conditions
CI / ARM Extra Build (push) Blocked by required conditions
CI / Synaptics Build (push) Blocked by required conditions
CI / Assemble and push default build (push) Blocked by required conditions
CI / AMD64 Build (push) Waiting to run
2026-04-21 05:11:01 -06:00
Nicolas MowenandGitHub 6cdf4fe3b8 Update intel runtimes to support Battlemage (#22943)
CI / ARM Extra Build (push) Blocked by required conditions
CI / Synaptics Build (push) Blocked by required conditions
CI / AMD64 Build (push) Waiting to run
CI / ARM Build (push) Waiting to run
CI / Jetson Jetpack 6 (push) Waiting to run
CI / AMD64 Extra Build (push) Blocked by required conditions
CI / Assemble and push default build (push) Blocked by required conditions
2026-04-20 08:23:15 -06:00
Josh HawkinsandGitHub 1a5d15ba81 Miscellaneous fixes (#22924)
* apply annotation offset to frigate+ submission frame time

* fix broken docs links with hash fragments that resolve wrong on reload

* undo

* use recording snapshot for frigate+ frame submission from VideoControls

rather than a canvas grab/paint, which may not always align with an ffmpeg snapshot due to keyframes

* add more docs links

- display docs link for main sections on collapsible fields

* dialog button consistency
2026-04-20 07:19:09 -06:00
icidiandGitHub 043c746a8b Improve readability by removing trailing digits caused by floating number conversion (#22934) 2026-04-20 06:35:48 -06:00
423ee2fe72 Feature: Share Timestamped URL for Camera Footage History (#22537)
* Initial copy timestamp url implementation

* revise url format

* Implement share timestamp dialog

* Use translations

* Add comments

* Add validations to shared link

* Switch to searchEffect implementation

* Add missing accessibility related dialog description

* Change URL format to unix timestamps

* Remove unnecessary useEffect

* Remove duplicated dialog title

* Fixes/improvements based off PR review comments

* Add missing cancel button & separators to dialog

* Make share description clearer

* Bugfix: guard against showing toasts twice
Because this effect ends up running multiple times

* Clamp future timestamps to now

* Revert "Bugfix: guard against showing toasts twice"

This reverts commit 99fa5e1dee.

* Use normal separator

Co-authored-by: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com>

* Fixes based off PR review comments

* Bugfix: Share dialog was not receiving the player timestamp after removing key that triggered remounts

* Defer `setRecording` and return true from hook for cleanup

* Remove timeout defer hack in favor of refactored hook

* Attempt to replay video muted on NotAllowedError

* Use separate persistent mute and temporary forced mute states

* Align cancel button with other dialogs

* Prevent wrapping on dialog title

* Remove extra "back" button on mobile drawer

* Fix back navigation when coming from direct shared timestamp links

* Use new timeformat hook

* Simplify dialog radio buttons

* Apply suggestions from code review

Co-authored-by: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com>

---------

Co-authored-by: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com>
2026-04-20 06:35:25 -06:00
Arun RajiahandGitHub d7f42735fc docs: add cctvQL to third-party extensions (#22930) 2026-04-19 07:05:43 -06:00
Josh HawkinsandGitHub cfb87f9744 Miscellaneous fixes (#22913)
CI / AMD64 Build (push) Has been cancelled
CI / ARM Build (push) Has been cancelled
CI / Jetson Jetpack 6 (push) Has been cancelled
CI / ARM Extra Build (push) Has been cancelled
CI / AMD64 Extra Build (push) Has been cancelled
CI / Synaptics Build (push) Has been cancelled
CI / Assemble and push default build (push) Has been cancelled
* add log when probing detect stream on startup

when users don't explicitly set detect.width and detect.height, we probe for them. sometimes the probe hangs (camera doesn't support UDP, like some Reolinks), so this log message will make that clearer

* add faq about probing detect stream

* fix stuck activity ring when tracked object transitions to stationary

* drop cache segments past retain cutoff regardless of retention mode

* add maintainer test
2026-04-18 07:10:50 -06:00
Josh HawkinsandGitHub 74fcd720d3 Add step + percent progress for exports (#22915)
CI / AMD64 Build (push) Waiting to run
CI / ARM Build (push) Waiting to run
CI / Jetson Jetpack 6 (push) Waiting to run
CI / ARM Extra Build (push) Blocked by required conditions
CI / Synaptics Build (push) Blocked by required conditions
CI / Assemble and push default build (push) Blocked by required conditions
CI / AMD64 Extra Build (push) Blocked by required conditions
* backend

* improve frontend Job typing

* progress frontend

* i18n

* tests
2026-04-17 12:18:12 -06:00
Josh HawkinsandGitHub a94d1b5d9e Miscellaneous Fixes (#22890)
CI / AMD64 Build (push) Has been cancelled
CI / ARM Build (push) Has been cancelled
CI / Jetson Jetpack 6 (push) Has been cancelled
CI / AMD64 Extra Build (push) Has been cancelled
CI / ARM Extra Build (push) Has been cancelled
CI / Synaptics Build (push) Has been cancelled
CI / Assemble and push default build (push) Has been cancelled
* only link to profile settings in status bar for admin users

* use hasFullCameraAccess for group filtering

* add custom export args to record docs

* update recordings docs

* prevent review WS handler from poisoning SWR cache before initial fetch completes
2026-04-16 09:10:03 -06:00
Nicolas MowenandGitHub d830d47c9b fix mypy (#22889)
CI / ARM Extra Build (push) Blocked by required conditions
CI / AMD64 Build (push) Waiting to run
CI / ARM Build (push) Waiting to run
CI / Jetson Jetpack 6 (push) Waiting to run
CI / AMD64 Extra Build (push) Blocked by required conditions
CI / Synaptics Build (push) Blocked by required conditions
CI / Assemble and push default build (push) Blocked by required conditions
2026-04-15 10:02:41 -05:00
Nicolas MowenandGitHub 3e85b18ee3 Use Frigate amd64 cache image for devcontainer build (#22888)
* Cache intel driver build

* Use Frigate's cached build
2026-04-15 08:37:23 -06:00
Nicolas MowenandGitHub 2ffe47511a Fix manual event getting caught by global motion config (#22887) 2026-04-15 08:32:26 -06:00
Josh HawkinsandGitHub 82e14d71fb Fix review page spinner not clearing when review item ends (#22886)
* fix review page spinner not clearing when review item ends

* use last ended review item ID instead of counter

* use separate displayItems memo to overlay end_time updates without re-filtering reviewed items
2026-04-15 08:24:36 -06:00
Nicolas MowenandGitHub 15ac76f20d Manually build intel driver (#22881)
* build intel driver

* Update docs
2026-04-15 07:07:27 -05:00
Josh HawkinsandGitHub a47be12ac5 Add deferred real-time processor for enrichments (#22880)
CI / ARM Extra Build (push) Blocked by required conditions
CI / Synaptics Build (push) Blocked by required conditions
CI / Assemble and push default build (push) Blocked by required conditions
CI / AMD64 Build (push) Waiting to run
CI / ARM Build (push) Waiting to run
CI / Jetson Jetpack 6 (push) Waiting to run
CI / AMD64 Extra Build (push) Blocked by required conditions
* implement deferred real-time processor with background task handling

* add tests

* fix typing
2026-04-14 21:39:44 -06:00
K3AandGitHub 4232792248 docs: mention /dev/kfd for ROCm and clarify /dev/accel docker mounts in installation.md (#22879)
CI / AMD64 Build (push) Waiting to run
CI / ARM Build (push) Waiting to run
CI / Jetson Jetpack 6 (push) Waiting to run
CI / AMD64 Extra Build (push) Blocked by required conditions
CI / ARM Extra Build (push) Blocked by required conditions
CI / Synaptics Build (push) Blocked by required conditions
CI / Assemble and push default build (push) Blocked by required conditions
AMD needs /dev/kfd for ROCm.

And /dev/accel is used for NPUs in AMD APUs too (enabled via CONFIG_DRM_ACCEL_AMDXDNA kernel option).
2026-04-14 16:26:19 -06:00
Josh HawkinsandGitHub 48abac9b45 fix i18n extractor not recognizing shorthand plural count in MultiExportDialog (#22877) 2026-04-14 13:51:39 -05:00
Josh HawkinsandGitHub e7e6f87682 Export improvements (#22867)
CI / AMD64 Build (push) Waiting to run
CI / ARM Build (push) Waiting to run
CI / Jetson Jetpack 6 (push) Waiting to run
CI / AMD64 Extra Build (push) Blocked by required conditions
CI / ARM Extra Build (push) Blocked by required conditions
CI / Synaptics Build (push) Blocked by required conditions
CI / Assemble and push default build (push) Blocked by required conditions
* backend

* frontend + i18n

* tests + api spec

* tweak backend to use Job infrastructure for exports

* frontend tweaks and Job infrastructure

* tests

* tweaks

- add ability to remove from case
- change location of counts in case card

* add stale export reaper on startup

* fix toaster close button color

* improve add dialog

* formatting

* hide max_concurrent from camera config export settings

* remove border

* refactor batch endpoint for multiple review items

* frontend

* tests and fastapi spec

* fix deletion of in-progress exports in a case

* tweaks

- hide cases when filtering cameras that have no exports from those cameras
- remove description from case card
- use textarea instead of input for case description in add new case dialog

* add auth exceptions for exports

* add e2e test for deleting cases with exports

* refactor delete and case endpoints

allow bulk deleting and reassigning

* frontend

- bulk selection like Review
- gate admin-only actions
- consolidate dialogs
- spacing/padding tweaks

* i18n and tests

* update openapi spec

* tweaks

- add None to case selection list
- allow new case creation from single cam export dialog

* fix codeql

* fix i18n

* remove unused

* fix frontend tests
2026-04-14 08:19:50 -06:00
Josh HawkinsandGitHub 18c068a3f9 Add network requirements docs (#22874)
* Add network requirements docs

* shorten title

* add note about network requirements in each section
2026-04-14 08:03:34 -06:00
Josh HawkinsandGitHub 335229d0d4 Miscellaneous fixes (#22828)
CI / AMD64 Build (push) Has been cancelled
CI / ARM Build (push) Has been cancelled
CI / Jetson Jetpack 6 (push) Has been cancelled
CI / AMD64 Extra Build (push) Has been cancelled
CI / ARM Extra Build (push) Has been cancelled
CI / Synaptics Build (push) Has been cancelled
CI / Assemble and push default build (push) Has been cancelled
* fix video playback stutter when GenAI dialog is open in detail stream

Inline `onOpen` callback in DetailStream.tsx:522 creates a new function identity every render. GenAISummaryChip.tsx:98's useEffect depends on [open, onOpen], so it re-fires on every parent re-render while the dialog is open. Each fire calls onSeek -> setCurrentTime -> seekToTimestamp, creating a continuous re-render + seek loop

* add /profiles to EXEMPT_PATHS for non-admin users

* skip debug_replay/status poll for non-admin users

* use subquery for timeline lookup to avoid SQLite variable limit
2026-04-09 20:53:17 -06:00
Josh HawkinsandGitHub d113be5e19 Improve frontend test framework (#22824)
CI / ARM Build (push) Waiting to run
CI / Jetson Jetpack 6 (push) Waiting to run
CI / AMD64 Extra Build (push) Blocked by required conditions
CI / ARM Extra Build (push) Blocked by required conditions
CI / Synaptics Build (push) Blocked by required conditions
CI / Assemble and push default build (push) Blocked by required conditions
CI / AMD64 Build (push) Waiting to run
* add error allowlist file for error collector

* add error collector for console + page + request errors

* wire error collector into frigateApp fixture

* add self-tests for error collector fixture

* gate strict error mode on E2E_STRICT_ERRORS=1

* triage pre-existing errors and seed allowlist

* add mockEmpty/mockError/mockDelay helpers for state-driven tests

* add self-tests for mock override helpers

* add mobile affordance helpers to BasePage

* add lint script for banned spec patterns and @mobile rule

* apply prettier fixes to new e2e files

* rewrite export.spec.ts

* clean up

* move export spec rewrite and bugfix to separate branch
2026-04-09 14:42:36 -06:00
Josh HawkinsandGitHub 98c2fe00c1 Chat improvements (#22823)
* Add score fusion helpers for find_similar_objects chat tool

* Add candidate query builder for find_similar_objects chat tool

* register find_similar_objects chat tool definition

* implement _execute_find_similar_objects chat tool dispatcher

* Dispatch find_similar_objects in chat tool executor

* Teach chat system prompt when to use find_similar_objects

* Add i18n strings for find_similar_objects chat tool

* Add frontend extractor for find_similar_objects tool response

* Render anchor badge and similarity scores in chat results

* formatting

* filter similarity results in python, not sqlite-vec

* extract pure chat helpers to chat_util module

* Teach chat system prompt about attached_event marker

* Add parseAttachedEvent and prependAttachment helpers

* Add i18n strings for chat event attachments

* Add ChatAttachmentChip component

* Make chat thumbnails attach to composer on click

* Render attachment chip in user chat bubbles

* Add ChatQuickReplies pill row component

* Add ChatPaperclipButton with event picker popover

* Wire event attachments into chat composer and messages

* add ability to stop streaming

* tweak cursor to appear at the end of the same line of the streaming response

* use abort signal

* add tooltip

* display label and camera on attachment chip
2026-04-09 14:31:37 -06:00
Josh HawkinsandGitHub 556d5d8c9d remove dead code and repair utf-8 preset names via latin-1 round trip (#22818)
CI / AMD64 Build (push) Has been cancelled
CI / ARM Build (push) Has been cancelled
CI / Jetson Jetpack 6 (push) Has been cancelled
CI / AMD64 Extra Build (push) Has been cancelled
CI / ARM Extra Build (push) Has been cancelled
CI / Synaptics Build (push) Has been cancelled
CI / Assemble and push default build (push) Has been cancelled
2026-04-08 16:20:58 -05:00
Josh HawkinsandGitHub 8f13932c64 UI fixes (#22814)
* display area as proper percentage in debug view

* match replay objects list with debug view

* motion search fixes

- tweak progress bar to exclude heatmap and inactive segments
- show metrics immediately on search start
- fix preview frame loading race
- fix polygon missing after dialog remount
- don't try to drag the image when dragging vertex of polygon

* add activity indicator to storage metrics

* make sub label query for events API endpoints case insensitive
2026-04-08 08:21:48 -06:00
Josh HawkinsandGitHub 5d2a725428 Display more scores in Tracking Details (#22799)
CI / AMD64 Build (push) Waiting to run
CI / ARM Build (push) Waiting to run
CI / Jetson Jetpack 6 (push) Waiting to run
CI / AMD64 Extra Build (push) Blocked by required conditions
CI / ARM Extra Build (push) Blocked by required conditions
CI / Synaptics Build (push) Blocked by required conditions
CI / Assemble and push default build (push) Blocked by required conditions
* add computed and top score to timeline entries

* frontend

* docs
2026-04-07 10:06:22 -06:00
dfe365cd28 Miscellaneous fixes (#22780)
* fix mobile export crash by removing stale iOS non-modal drawer workaround

* Remove titlecase to avoid Gemma4 handling plain labels as proper nouns

* Improve titling:

* Make directions more clear

* Properly capitalize delivery services

* update dispatcher config reference on save

* subscribe to review topic so ReviewDescriptionProcessor knows genai is enabled

* auto-send ON genai review WS message when enabled_in_config transitions to true

* remove unused object level

* update docs to clarify pre/post capture settings

* add ui docs links

* improve known_plates field in settings UI

* only show save all when multiple sections are changed

or if the section being changed is not currently being viewed

* fix docs

---------

Co-authored-by: Nicolas Mowen <nickmowen213@gmail.com>
2026-04-07 07:16:19 -06:00
Josh HawkinsandGitHub 49c3732726 Improve environment var handling (#22796)
* refactor env var handling

- use shared helper
- use left-to-right parser

* add tests

* formatting
2026-04-07 07:16:02 -06:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
c3628a339d Bump vite from 6.4.1 to 6.4.2 in /web (#22788)
CI / AMD64 Build (push) Waiting to run
CI / ARM Build (push) Waiting to run
CI / Jetson Jetpack 6 (push) Waiting to run
CI / AMD64 Extra Build (push) Blocked by required conditions
CI / ARM Extra Build (push) Blocked by required conditions
CI / Synaptics Build (push) Blocked by required conditions
CI / Assemble and push default build (push) Blocked by required conditions
Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 6.4.1 to 6.4.2.
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/v6.4.2/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v6.4.2/packages/vite)

---
updated-dependencies:
- dependency-name: vite
  dependency-version: 6.4.2
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-06 19:16:12 -05:00
Josh HawkinsandGitHub c750372586 Add frontend tests (#22783)
* basic e2e frontend test framework

* improve mock data generation and add test cases

* more cases

* add e2e tests to PR template

* don't generate mock data in PR CI

* satisfy codeql check

* fix flaky system page tab tests by guarding against crashes from incomplete mock stats

* reduce local test runs to 4 workers to match CI
2026-04-06 16:33:28 -06:00
Josh HawkinsandGitHub ed3bebc967 Miscellaneous fixes (#22779)
CI / ARM Build (push) Waiting to run
CI / Jetson Jetpack 6 (push) Waiting to run
CI / AMD64 Extra Build (push) Blocked by required conditions
CI / ARM Extra Build (push) Blocked by required conditions
CI / Synaptics Build (push) Blocked by required conditions
CI / Assemble and push default build (push) Blocked by required conditions
CI / AMD64 Build (push) Waiting to run
* block ffmpeg args in custom exports for non-admin users only

* prune expired reconnect timestamps periodically in watchdog loop

reconnect timestamps were only pruned when a new reconnect
occurred. This meant a single reconnect would persist in the count indefinitely instead of expiring after 1 hour

* formatting
2026-04-06 07:53:23 -06:00
Josh HawkinsandGitHub e95e9b52f3 GenAI tweak (#22773)
CI / AMD64 Build (push) Waiting to run
CI / ARM Build (push) Waiting to run
CI / Jetson Jetpack 6 (push) Waiting to run
CI / AMD64 Extra Build (push) Blocked by required conditions
CI / ARM Extra Build (push) Blocked by required conditions
CI / Synaptics Build (push) Blocked by required conditions
CI / Assemble and push default build (push) Blocked by required conditions
* refresh model dropdown after changing provider or base url

* decouple list_models from provider init

switching providers in the UI left an invalid model in the config, then _init_provider would fail and list_models would return an empty list, making it impossible to select a valid model
2026-04-05 11:00:13 -06:00
Josh HawkinsandGitHub 67a1531da0 Tweaks (#22770)
* radix pointer events fix

* add debug log for no genai responses

* tweak profiles docs

* add weblate to maintainers list
2026-04-05 10:08:23 -06:00
Josh HawkinsandGitHub d8c35d5a0f Miscellaneous fixes (#22762)
CI / AMD64 Build (push) Waiting to run
CI / ARM Build (push) Waiting to run
CI / Jetson Jetpack 6 (push) Waiting to run
CI / ARM Extra Build (push) Blocked by required conditions
CI / Synaptics Build (push) Blocked by required conditions
CI / Assemble and push default build (push) Blocked by required conditions
CI / AMD64 Extra Build (push) Blocked by required conditions
2026-04-04 21:32:26 -06:00
9ba81d6dc8 Translated using Weblate (Cantonese (Traditional Han script))
CI / ARM Build (push) Waiting to run
CI / Jetson Jetpack 6 (push) Waiting to run
CI / AMD64 Extra Build (push) Blocked by required conditions
CI / ARM Extra Build (push) Blocked by required conditions
CI / Synaptics Build (push) Blocked by required conditions
CI / Assemble and push default build (push) Blocked by required conditions
CI / AMD64 Build (push) Waiting to run
Currently translated at 98.3% (120 of 122 strings)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: beginner2047 <leoywng44@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-classificationmodel/yue_Hant/
Translation: Frigate NVR/views-classificationmodel
2026-04-04 08:08:35 -05:00
2b8fd74ae8 Translated using Weblate (Norwegian Bokmål)
Currently translated at 100.0% (1071 of 1071 strings)

Translated using Weblate (Norwegian Bokmål)

Currently translated at 100.0% (142 of 142 strings)

Translated using Weblate (Norwegian Bokmål)

Currently translated at 100.0% (790 of 790 strings)

Translated using Weblate (Norwegian Bokmål)

Currently translated at 100.0% (99 of 99 strings)

Translated using Weblate (Norwegian Bokmål)

Currently translated at 100.0% (47 of 47 strings)

Translated using Weblate (Norwegian Bokmål)

Currently translated at 100.0% (22 of 22 strings)

Translated using Weblate (Norwegian Bokmål)

Currently translated at 100.0% (1068 of 1068 strings)

Translated using Weblate (Norwegian Bokmål)

Currently translated at 100.0% (174 of 174 strings)

Translated using Weblate (Norwegian Bokmål)

Currently translated at 100.0% (469 of 469 strings)

Translated using Weblate (Norwegian Bokmål)

Currently translated at 100.0% (25 of 25 strings)

Translated using Weblate (Norwegian Bokmål)

Currently translated at 100.0% (129 of 129 strings)

Translated using Weblate (Norwegian Bokmål)

Currently translated at 100.0% (58 of 58 strings)

Translated using Weblate (Norwegian Bokmål)

Currently translated at 100.0% (58 of 58 strings)

Translated using Weblate (Norwegian Bokmål)

Currently translated at 100.0% (172 of 172 strings)

Translated using Weblate (Norwegian Bokmål)

Currently translated at 100.0% (23 of 23 strings)

Translated using Weblate (Norwegian Bokmål)

Currently translated at 100.0% (235 of 235 strings)

Translated using Weblate (Norwegian Bokmål)

Currently translated at 63.5% (652 of 1026 strings)

Translated using Weblate (Norwegian Bokmål)

Currently translated at 100.0% (123 of 123 strings)

Translated using Weblate (Norwegian Bokmål)

Currently translated at 100.0% (62 of 62 strings)

Translated using Weblate (Norwegian Bokmål)

Currently translated at 100.0% (47 of 47 strings)

Translated using Weblate (Norwegian Bokmål)

Currently translated at 100.0% (58 of 58 strings)

Translated using Weblate (Norwegian Bokmål)

Currently translated at 100.0% (98 of 98 strings)

Translated using Weblate (Norwegian Bokmål)

Currently translated at 100.0% (122 of 122 strings)

Translated using Weblate (Norwegian Bokmål)

Currently translated at 100.0% (142 of 142 strings)

Translated using Weblate (Norwegian Bokmål)

Currently translated at 98.3% (120 of 122 strings)

Translated using Weblate (Norwegian Bokmål)

Currently translated at 100.0% (123 of 123 strings)

Translated using Weblate (Norwegian Bokmål)

Currently translated at 96.5% (56 of 58 strings)

Translated using Weblate (Norwegian Bokmål)

Currently translated at 100.0% (138 of 138 strings)

Translated using Weblate (Norwegian Bokmål)

Currently translated at 100.0% (10 of 10 strings)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: OverTheHillsAndFarAway <prosjektx@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/common/nb_NO/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-camera/nb_NO/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-dialog/nb_NO/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-cameras/nb_NO/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-global/nb_NO/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-groups/nb_NO/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-validation/nb_NO/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/objects/nb_NO/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-classificationmodel/nb_NO/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-configeditor/nb_NO/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-events/nb_NO/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-explore/nb_NO/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-exports/nb_NO/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-facelibrary/nb_NO/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-live/nb_NO/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/nb_NO/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-system/nb_NO/
Translation: Frigate NVR/Config - Cameras
Translation: Frigate NVR/Config - Global
Translation: Frigate NVR/Config - Groups
Translation: Frigate NVR/Config - Validation
Translation: Frigate NVR/common
Translation: Frigate NVR/components-camera
Translation: Frigate NVR/components-dialog
Translation: Frigate NVR/objects
Translation: Frigate NVR/views-classificationmodel
Translation: Frigate NVR/views-configeditor
Translation: Frigate NVR/views-events
Translation: Frigate NVR/views-explore
Translation: Frigate NVR/views-exports
Translation: Frigate NVR/views-facelibrary
Translation: Frigate NVR/views-live
Translation: Frigate NVR/views-settings
Translation: Frigate NVR/views-system
2026-04-04 08:08:35 -05:00
c0ffb395f8 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 99.8% (1069 of 1071 strings)

Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 99.9% (1067 of 1068 strings)

Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 100.0% (1065 of 1065 strings)

Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 100.0% (469 of 469 strings)

Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 100.0% (174 of 174 strings)

Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 100.0% (790 of 790 strings)

Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 100.0% (99 of 99 strings)

Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 100.0% (129 of 129 strings)

Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 100.0% (1049 of 1049 strings)

Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 100.0% (790 of 790 strings)

Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 100.0% (58 of 58 strings)

Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 100.0% (469 of 469 strings)

Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 94.0% (963 of 1024 strings)

Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 100.0% (467 of 467 strings)

Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 91.1% (925 of 1015 strings)

Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 100.0% (788 of 788 strings)

Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 99.3% (783 of 788 strings)

Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 98.9% (780 of 788 strings)

Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 100.0% (142 of 142 strings)

Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 100.0% (98 of 98 strings)

Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 100.0% (23 of 23 strings)

Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 100.0% (122 of 122 strings)

Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 100.0% (47 of 47 strings)

Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 98.3% (120 of 122 strings)

Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 100.0% (62 of 62 strings)

Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 100.0% (172 of 172 strings)

Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 100.0% (235 of 235 strings)

Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 98.8% (779 of 788 strings)

Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 98.8% (779 of 788 strings)

Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 100.0% (123 of 123 strings)

Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 99.5% (465 of 467 strings)

Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 91.2% (923 of 1011 strings)

Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 100.0% (98 of 98 strings)

Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 91.2% (923 of 1011 strings)

Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 100.0% (62 of 62 strings)

Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 99.3% (466 of 469 strings)

Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 96.8% (1082 of 1117 strings)

Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 100.0% (231 of 231 strings)

Co-authored-by: Anonymous <noreply@weblate.org>
Co-authored-by: GuoQing Liu <842607283@qq.com>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/common/zh_Hans/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-camera/zh_Hans/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-cameras/zh_Hans/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-global/zh_Hans/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/objects/zh_Hans/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-classificationmodel/zh_Hans/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-events/zh_Hans/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-explore/zh_Hans/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-exports/zh_Hans/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-facelibrary/zh_Hans/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-live/zh_Hans/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/zh_Hans/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-system/zh_Hans/
Translation: Frigate NVR/Config - Cameras
Translation: Frigate NVR/Config - Global
Translation: Frigate NVR/common
Translation: Frigate NVR/components-camera
Translation: Frigate NVR/objects
Translation: Frigate NVR/views-classificationmodel
Translation: Frigate NVR/views-events
Translation: Frigate NVR/views-explore
Translation: Frigate NVR/views-exports
Translation: Frigate NVR/views-facelibrary
Translation: Frigate NVR/views-live
Translation: Frigate NVR/views-settings
Translation: Frigate NVR/views-system
2026-04-04 08:08:35 -05:00
416b69439c Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 3.6% (17 of 469 strings)

Translated using Weblate (Chinese (Traditional Han script))

Currently translated at 1.0% (8 of 790 strings)

Translated using Weblate (Chinese (Traditional Han script))

Currently translated at 56.5% (69 of 122 strings)

Translated using Weblate (Chinese (Traditional Han script))

Currently translated at 56.5% (69 of 122 strings)

Co-authored-by: Anson <yeungyinho@gmail.com>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: windasd <me@windasd.tw>
Co-authored-by: 薛展 <n16418113@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-cameras/zh_Hant/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-global/zh_Hant/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-classificationmodel/zh_Hant/
Translation: Frigate NVR/Config - Cameras
Translation: Frigate NVR/Config - Global
Translation: Frigate NVR/views-classificationmodel
2026-04-04 08:08:35 -05:00
8d7134319a Translated using Weblate (Slovenian)
Currently translated at 98.3% (120 of 122 strings)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: thehijacker <thehijacker@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-classificationmodel/sl/
Translation: Frigate NVR/views-classificationmodel
2026-04-04 08:08:35 -05:00
23e7881b99 Translated using Weblate (Slovak)
Currently translated at 97.5% (119 of 122 strings)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: OskarSidor <oskar.sidor@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-classificationmodel/sk/
Translation: Frigate NVR/views-classificationmodel
2026-04-04 08:08:35 -05:00
b8796838d7 Translated using Weblate (Korean)
Currently translated at 100.0% (235 of 235 strings)

Translated using Weblate (Korean)

Currently translated at 95.1% (117 of 123 strings)

Translated using Weblate (Korean)

Currently translated at 77.0% (134 of 174 strings)

Translated using Weblate (Korean)

Currently translated at 33.9% (170 of 501 strings)

Translated using Weblate (Korean)

Currently translated at 12.9% (138 of 1065 strings)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: John <john@akfn.net>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/audio/ko/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/common/ko/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/objects/ko/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/ko/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-system/ko/
Translation: Frigate NVR/audio
Translation: Frigate NVR/common
Translation: Frigate NVR/objects
Translation: Frigate NVR/views-settings
Translation: Frigate NVR/views-system
2026-04-04 08:08:35 -05:00
89c258e18c Translated using Weblate (Serbian)
Currently translated at 40.9% (50 of 122 strings)

Co-authored-by: Aleksandar Jevremovic <aleksandar@jevremovic.org>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-classificationmodel/sr/
Translation: Frigate NVR/views-classificationmodel
2026-04-04 08:08:35 -05:00
680cf146ef Translated using Weblate (Persian)
Currently translated at 98.3% (120 of 122 strings)

Co-authored-by: Anonymous <noreply@weblate.org>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-classificationmodel/fa/
Translation: Frigate NVR/views-classificationmodel
2026-04-04 08:08:35 -05:00
7e2b6de1b3 Translated using Weblate (Swedish)
Currently translated at 98.3% (120 of 122 strings)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Kristian Johansson <knmjohansson@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-classificationmodel/sv/
Translation: Frigate NVR/views-classificationmodel
2026-04-04 08:08:35 -05:00
e09a95921e Translated using Weblate (French)
Currently translated at 100.0% (2 of 2 strings)

Translated using Weblate (French)

Currently translated at 93.1% (54 of 58 strings)

Translated using Weblate (French)

Currently translated at 92.0% (23 of 25 strings)

Translated using Weblate (French)

Currently translated at 100.0% (22 of 22 strings)

Translated using Weblate (French)

Currently translated at 4.3% (34 of 790 strings)

Translated using Weblate (French)

Currently translated at 69.1% (728 of 1053 strings)

Translated using Weblate (French)

Currently translated at 98.2% (169 of 172 strings)

Translated using Weblate (French)

Currently translated at 100.0% (99 of 99 strings)

Translated using Weblate (French)

Currently translated at 96.0% (24 of 25 strings)

Translated using Weblate (French)

Currently translated at 97.0% (228 of 235 strings)

Translated using Weblate (French)

Currently translated at 94.5% (122 of 129 strings)

Translated using Weblate (French)

Currently translated at 70.5% (724 of 1026 strings)

Translated using Weblate (French)

Currently translated at 69.9% (718 of 1026 strings)

Translated using Weblate (French)

Currently translated at 100.0% (122 of 122 strings)

Translated using Weblate (French)

Currently translated at 100.0% (22 of 22 strings)

Translated using Weblate (French)

Currently translated at 97.6% (168 of 172 strings)

Translated using Weblate (French)

Currently translated at 88.0% (22 of 25 strings)

Translated using Weblate (French)

Currently translated at 88.3% (152 of 172 strings)

Translated using Weblate (French)

Currently translated at 48.0% (12 of 25 strings)

Translated using Weblate (French)

Currently translated at 3.8% (30 of 788 strings)

Translated using Weblate (French)

Currently translated at 59.0% (13 of 22 strings)

Translated using Weblate (French)

Currently translated at 87.7% (151 of 172 strings)

Translated using Weblate (French)

Currently translated at 96.5% (227 of 235 strings)

Translated using Weblate (French)

Currently translated at 100.0% (98 of 98 strings)

Translated using Weblate (French)

Currently translated at 69.3% (43 of 62 strings)

Translated using Weblate (French)

Currently translated at 54.5% (12 of 22 strings)

Translated using Weblate (French)

Currently translated at 69.8% (715 of 1024 strings)

Translated using Weblate (French)

Currently translated at 100.0% (23 of 23 strings)

Translated using Weblate (French)

Currently translated at 3.6% (29 of 788 strings)

Translated using Weblate (French)

Currently translated at 40.0% (10 of 25 strings)

Translated using Weblate (French)

Currently translated at 98.3% (120 of 122 strings)

Translated using Weblate (French)

Currently translated at 2.5% (28 of 1111 strings)

Co-authored-by: Anonymous <noreply@weblate.org>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: N D <n.dubreuil@gmail.com>
Co-authored-by: Riton Du Boulon <henripl37@gmail.com>
Co-authored-by: alorente <gitmaster@passific.fr>
Co-authored-by: shdw <weblate@assez.biz>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/common/fr/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-icons/fr/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-global/fr/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-groups/fr/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-validation/fr/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-classificationmodel/fr/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-events/fr/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-exports/fr/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-facelibrary/fr/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-live/fr/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/fr/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-system/fr/
Translation: Frigate NVR/Config - Global
Translation: Frigate NVR/Config - Groups
Translation: Frigate NVR/Config - Validation
Translation: Frigate NVR/common
Translation: Frigate NVR/components-icons
Translation: Frigate NVR/views-classificationmodel
Translation: Frigate NVR/views-events
Translation: Frigate NVR/views-exports
Translation: Frigate NVR/views-facelibrary
Translation: Frigate NVR/views-live
Translation: Frigate NVR/views-settings
Translation: Frigate NVR/views-system
2026-04-04 08:08:35 -05:00
61d8943793 Translated using Weblate (Spanish)
Currently translated at 63.6% (666 of 1047 strings)

Translated using Weblate (Spanish)

Currently translated at 87.2% (150 of 172 strings)

Translated using Weblate (Spanish)

Currently translated at 95.6% (22 of 23 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (58 of 58 strings)

Translated using Weblate (Spanish)

Currently translated at 98.5% (140 of 142 strings)

Translated using Weblate (Spanish)

Currently translated at 96.8% (125 of 129 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (99 of 99 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (47 of 47 strings)

Translated using Weblate (Spanish)

Currently translated at 69.3% (43 of 62 strings)

Translated using Weblate (Spanish)

Currently translated at 6.0% (48 of 790 strings)

Translated using Weblate (Spanish)

Currently translated at 88.0% (22 of 25 strings)

Translated using Weblate (Spanish)

Currently translated at 9.8% (46 of 469 strings)

Translated using Weblate (Spanish)

Currently translated at 95.4% (21 of 22 strings)

Translated using Weblate (Spanish)

Currently translated at 98.3% (120 of 122 strings)

Co-authored-by: Francesc Domene <fdomenef@gmail.com>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: José María Díaz <jdiaz.bb@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-camera/es/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-cameras/es/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-global/es/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-groups/es/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-validation/es/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-classificationmodel/es/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-events/es/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-explore/es/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-exports/es/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-facelibrary/es/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-live/es/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/es/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-system/es/
Translation: Frigate NVR/Config - Cameras
Translation: Frigate NVR/Config - Global
Translation: Frigate NVR/Config - Groups
Translation: Frigate NVR/Config - Validation
Translation: Frigate NVR/components-camera
Translation: Frigate NVR/views-classificationmodel
Translation: Frigate NVR/views-events
Translation: Frigate NVR/views-explore
Translation: Frigate NVR/views-exports
Translation: Frigate NVR/views-facelibrary
Translation: Frigate NVR/views-live
Translation: Frigate NVR/views-settings
Translation: Frigate NVR/views-system
2026-04-04 08:08:35 -05:00
95f08db494 Translated using Weblate (Dutch)
Currently translated at 15.3% (72 of 469 strings)

Translated using Weblate (Dutch)

Currently translated at 91.2% (157 of 172 strings)

Translated using Weblate (Dutch)

Currently translated at 100.0% (122 of 122 strings)

Translated using Weblate (Dutch)

Currently translated at 100.0% (25 of 25 strings)

Translated using Weblate (Dutch)

Currently translated at 10.1% (80 of 788 strings)

Translated using Weblate (Dutch)

Currently translated at 100.0% (22 of 22 strings)

Translated using Weblate (Dutch)

Currently translated at 99.1% (122 of 123 strings)

Translated using Weblate (Dutch)

Currently translated at 69.4% (713 of 1026 strings)

Translated using Weblate (Dutch)

Currently translated at 15.4% (72 of 467 strings)

Translated using Weblate (Dutch)

Currently translated at 8.6% (68 of 788 strings)

Translated using Weblate (Dutch)

Currently translated at 86.0% (148 of 172 strings)

Translated using Weblate (Dutch)

Currently translated at 52.0% (13 of 25 strings)

Translated using Weblate (Dutch)

Currently translated at 8.5% (67 of 788 strings)

Translated using Weblate (Dutch)

Currently translated at 86.3% (19 of 22 strings)

Translated using Weblate (Dutch)

Currently translated at 69.3% (43 of 62 strings)

Translated using Weblate (Dutch)

Currently translated at 81.8% (18 of 22 strings)

Translated using Weblate (Dutch)

Currently translated at 40.0% (10 of 25 strings)

Translated using Weblate (Dutch)

Currently translated at 100.0% (23 of 23 strings)

Translated using Weblate (Dutch)

Currently translated at 100.0% (98 of 98 strings)

Translated using Weblate (Dutch)

Currently translated at 8.2% (65 of 788 strings)

Translated using Weblate (Dutch)

Currently translated at 84.8% (146 of 172 strings)

Translated using Weblate (Dutch)

Currently translated at 98.3% (120 of 122 strings)

Translated using Weblate (Dutch)

Currently translated at 69.7% (705 of 1011 strings)

Translated using Weblate (Dutch)

Currently translated at 94.3% (218 of 231 strings)

Translated using Weblate (Dutch)

Currently translated at 5.2% (59 of 1117 strings)

Co-authored-by: Anonymous <noreply@weblate.org>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Marijn <168113859+Marijn0@users.noreply.github.com>
Co-authored-by: Mark Holtkamp <markholtkamp85@gmail.com>
Co-authored-by: Paul Bröerken <broerken@me.com>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/common/nl/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-cameras/nl/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-global/nl/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-groups/nl/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-validation/nl/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/objects/nl/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-classificationmodel/nl/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-events/nl/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-exports/nl/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-live/nl/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/nl/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-system/nl/
Translation: Frigate NVR/Config - Cameras
Translation: Frigate NVR/Config - Global
Translation: Frigate NVR/Config - Groups
Translation: Frigate NVR/Config - Validation
Translation: Frigate NVR/common
Translation: Frigate NVR/objects
Translation: Frigate NVR/views-classificationmodel
Translation: Frigate NVR/views-events
Translation: Frigate NVR/views-exports
Translation: Frigate NVR/views-live
Translation: Frigate NVR/views-settings
Translation: Frigate NVR/views-system
2026-04-04 08:08:35 -05:00
d5972e2ea7 Translated using Weblate (Indonesian)
Currently translated at 53.2% (65 of 122 strings)

Translated using Weblate (Indonesian)

Currently translated at 53.2% (65 of 122 strings)

Co-authored-by: Catto <sisharyadi@gmail.com>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: ariska <ariska@databisnis.id>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-classificationmodel/id/
Translation: Frigate NVR/views-classificationmodel
2026-04-04 08:08:35 -05:00
3e502ee084 Translated using Weblate (Arabic)
Currently translated at 48.8% (84 of 172 strings)

Translated using Weblate (Arabic)

Currently translated at 4.0% (1 of 25 strings)

Translated using Weblate (Arabic)

Currently translated at 0.2% (1 of 469 strings)

Co-authored-by: Ammar Nafie <ymmar83@gmail.com>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: MAATECH <hmmdcool@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-cameras/ar/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-groups/ar/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-system/ar/
Translation: Frigate NVR/Config - Cameras
Translation: Frigate NVR/Config - Groups
Translation: Frigate NVR/views-system
2026-04-04 08:08:35 -05:00
ecae4e36cd Translated using Weblate (Italian)
Currently translated at 100.0% (142 of 142 strings)

Translated using Weblate (Italian)

Currently translated at 100.0% (58 of 58 strings)

Translated using Weblate (Italian)

Currently translated at 100.0% (99 of 99 strings)

Translated using Weblate (Italian)

Currently translated at 100.0% (129 of 129 strings)

Translated using Weblate (Italian)

Currently translated at 100.0% (123 of 123 strings)

Translated using Weblate (Italian)

Currently translated at 100.0% (47 of 47 strings)

Translated using Weblate (Italian)

Currently translated at 100.0% (23 of 23 strings)

Translated using Weblate (Italian)

Currently translated at 98.9% (98 of 99 strings)

Translated using Weblate (Italian)

Currently translated at 2.6% (21 of 790 strings)

Translated using Weblate (Italian)

Currently translated at 2.6% (21 of 790 strings)

Translated using Weblate (Italian)

Currently translated at 100.0% (235 of 235 strings)

Translated using Weblate (Italian)

Currently translated at 93.0% (120 of 129 strings)

Translated using Weblate (Italian)

Currently translated at 100.0% (25 of 25 strings)

Translated using Weblate (Italian)

Currently translated at 27.2% (6 of 22 strings)

Translated using Weblate (Italian)

Currently translated at 60.7% (651 of 1071 strings)

Translated using Weblate (Italian)

Currently translated at 2.7% (13 of 469 strings)

Translated using Weblate (Italian)

Currently translated at 1.2% (6 of 469 strings)

Translated using Weblate (Italian)

Currently translated at 100.0% (23 of 23 strings)

Translated using Weblate (Italian)

Currently translated at 0.3% (3 of 790 strings)

Translated using Weblate (Italian)

Currently translated at 76.0% (19 of 25 strings)

Translated using Weblate (Italian)

Currently translated at 98.9% (98 of 99 strings)

Translated using Weblate (Italian)

Currently translated at 27.2% (6 of 22 strings)

Translated using Weblate (Italian)

Currently translated at 98.3% (120 of 122 strings)

Co-authored-by: AlessioCappe <alessio_cappe@hotmail.it>
Co-authored-by: Evion58 <enniocianciolo058@duck.com>
Co-authored-by: Gringo <ita.translations@tiscali.it>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/common/it/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-camera/it/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-cameras/it/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-global/it/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-groups/it/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-validation/it/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/objects/it/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-classificationmodel/it/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-explore/it/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-exports/it/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-facelibrary/it/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-live/it/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/it/
Translation: Frigate NVR/Config - Cameras
Translation: Frigate NVR/Config - Global
Translation: Frigate NVR/Config - Groups
Translation: Frigate NVR/Config - Validation
Translation: Frigate NVR/common
Translation: Frigate NVR/components-camera
Translation: Frigate NVR/objects
Translation: Frigate NVR/views-classificationmodel
Translation: Frigate NVR/views-explore
Translation: Frigate NVR/views-exports
Translation: Frigate NVR/views-facelibrary
Translation: Frigate NVR/views-live
Translation: Frigate NVR/views-settings
2026-04-04 08:08:35 -05:00
985b834a51 Translated using Weblate (Polish)
Currently translated at 2.2% (18 of 790 strings)

Translated using Weblate (Polish)

Currently translated at 22.8% (107 of 469 strings)

Translated using Weblate (Polish)

Currently translated at 2.2% (18 of 790 strings)

Translated using Weblate (Polish)

Currently translated at 100.0% (47 of 47 strings)

Translated using Weblate (Polish)

Currently translated at 98.3% (120 of 122 strings)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Mateusz Paś <piciuok@gmail.com>
Co-authored-by: Szymon Woźniak <swozniak6@gmail.com>
Co-authored-by: Wojciech Niziński <niziak-weblate@spox.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-camera/pl/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-cameras/pl/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-global/pl/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-classificationmodel/pl/
Translation: Frigate NVR/Config - Cameras
Translation: Frigate NVR/Config - Global
Translation: Frigate NVR/components-camera
Translation: Frigate NVR/views-classificationmodel
2026-04-04 08:08:35 -05:00
5098df10cc Translated using Weblate (Hebrew)
Currently translated at 98.3% (120 of 122 strings)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Ronen Atsil <atsil55@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-classificationmodel/he/
Translation: Frigate NVR/views-classificationmodel
2026-04-04 08:08:35 -05:00
91af284677 Translated using Weblate (Hungarian)
Currently translated at 33.6% (41 of 122 strings)

Translated using Weblate (Hungarian)

Currently translated at 33.6% (41 of 122 strings)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Zrinyi Patrik <patrikzrinyi404@gmail.com>
Co-authored-by: ugfus1630 <katona.ta@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-classificationmodel/hu/
Translation: Frigate NVR/views-classificationmodel
2026-04-04 08:08:35 -05:00
1e2c8af3dc Translated using Weblate (Croatian)
Currently translated at 98.3% (120 of 122 strings)

Translated using Weblate (Croatian)

Currently translated at 98.3% (120 of 122 strings)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Zoran Ivancevic <zolakt@gmail.com>
Co-authored-by: stipe-jurkovic <sjurko00@fesb.hr>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-classificationmodel/hr/
Translation: Frigate NVR/views-classificationmodel
2026-04-04 08:08:35 -05:00
ba7725b9bf Translated using Weblate (Icelandic)
Currently translated at 1.3% (1 of 74 strings)

Translated using Weblate (Icelandic)

Currently translated at 16.6% (1 of 6 strings)

Translated using Weblate (Icelandic)

Currently translated at 1.7% (1 of 58 strings)

Translated using Weblate (Icelandic)

Currently translated at 10.0% (1 of 10 strings)

Translated using Weblate (Icelandic)

Currently translated at 50.0% (1 of 2 strings)

Translated using Weblate (Icelandic)

Currently translated at 50.0% (1 of 2 strings)

Translated using Weblate (Icelandic)

Currently translated at 10.0% (1 of 10 strings)

Translated using Weblate (Icelandic)

Currently translated at 1.6% (1 of 62 strings)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Hosted Weblate user 145663 <marel@snorl.net>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-auth/is/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-dialog/is/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-filter/is/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-icons/is/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-input/is/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-configeditor/is/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-events/is/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-recording/is/
Translation: Frigate NVR/components-auth
Translation: Frigate NVR/components-dialog
Translation: Frigate NVR/components-filter
Translation: Frigate NVR/components-icons
Translation: Frigate NVR/components-input
Translation: Frigate NVR/views-configeditor
Translation: Frigate NVR/views-events
Translation: Frigate NVR/views-recording
2026-04-04 08:08:35 -05:00
cf457f67bd Translated using Weblate (Vietnamese)
Currently translated at 31.9% (39 of 122 strings)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: John Nguyen <thongnguyen.uit@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-classificationmodel/vi/
Translation: Frigate NVR/views-classificationmodel
2026-04-04 08:08:35 -05:00
0fa6053839 Translated using Weblate (Portuguese)
Currently translated at 27.8% (34 of 122 strings)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: fabiovalverde <fabio@rvalverde.com>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-classificationmodel/pt/
Translation: Frigate NVR/views-classificationmodel
2026-04-04 08:08:35 -05:00
287ea3f4f0 Translated using Weblate (Czech)
Currently translated at 44.2% (54 of 122 strings)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: lukascissa <lukas@cissa.cz>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-classificationmodel/cs/
Translation: Frigate NVR/views-classificationmodel
2026-04-04 08:08:35 -05:00
a16c5731da Translated using Weblate (Catalan)
Currently translated at 100.0% (1071 of 1071 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (1068 of 1068 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (1065 of 1065 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (1065 of 1065 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (174 of 174 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (790 of 790 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (469 of 469 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (1053 of 1053 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (469 of 469 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (790 of 790 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (99 of 99 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (1047 of 1047 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (172 of 172 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (58 of 58 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (129 of 129 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (47 of 47 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (142 of 142 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (235 of 235 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (62 of 62 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (98 of 98 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (1026 of 1026 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (467 of 467 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (23 of 23 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (788 of 788 strings)

Translated using Weblate (Catalan)

Currently translated at 98.3% (120 of 122 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (467 of 467 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (788 of 788 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (1011 of 1011 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (123 of 123 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (469 of 469 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (1011 of 1011 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (1117 of 1117 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (1005 of 1005 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (231 of 231 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (467 of 467 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (1003 of 1003 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (1111 of 1111 strings)

Co-authored-by: Eduardo Pastor Fernández <123eduardoneko123@gmail.com>
Co-authored-by: Gerard Ricart Castells <gerard.ricart@gmail.com>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/common/ca/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-camera/ca/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-cameras/ca/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-global/ca/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/objects/ca/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-classificationmodel/ca/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-events/ca/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-explore/ca/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-exports/ca/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-facelibrary/ca/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-live/ca/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/ca/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-system/ca/
Translation: Frigate NVR/Config - Cameras
Translation: Frigate NVR/Config - Global
Translation: Frigate NVR/common
Translation: Frigate NVR/components-camera
Translation: Frigate NVR/objects
Translation: Frigate NVR/views-classificationmodel
Translation: Frigate NVR/views-events
Translation: Frigate NVR/views-explore
Translation: Frigate NVR/views-exports
Translation: Frigate NVR/views-facelibrary
Translation: Frigate NVR/views-live
Translation: Frigate NVR/views-settings
Translation: Frigate NVR/views-system
2026-04-04 08:08:35 -05:00
Hosted WeblateJosh HawkinsYusuke, Hirota <hirota.yusuke@jp.fujitsu.com>gon 360sotohiyhi264
aec7e7443a Translated using Weblate (Japanese)
Currently translated at 100.0% (6 of 6 strings)

Translated using Weblate (Japanese)

Currently translated at 52.1% (12 of 23 strings)

Translated using Weblate (Japanese)

Currently translated at 64.0% (16 of 25 strings)

Translated using Weblate (Japanese)

Currently translated at 83.1% (143 of 172 strings)

Translated using Weblate (Japanese)

Currently translated at 1.6% (13 of 788 strings)

Translated using Weblate (Japanese)

Currently translated at 98.3% (120 of 122 strings)

Translated using Weblate (Japanese)

Currently translated at 98.3% (120 of 122 strings)

Translated using Weblate (Japanese)

Currently translated at 60.0% (15 of 25 strings)

Translated using Weblate (Japanese)

Currently translated at 64.8% (656 of 1011 strings)

Translated using Weblate (Japanese)

Currently translated at 1.7% (8 of 469 strings)

Translated using Weblate (Japanese)

Currently translated at 18.1% (4 of 22 strings)

Translated using Weblate (Japanese)

Currently translated at 83.6% (143 of 171 strings)

Translated using Weblate (Japanese)

Currently translated at 1.0% (12 of 1117 strings)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Yusuke, Hirota <hirota.yusuke@jp.fujitsu.com>
Co-authored-by: gon 360 <gon360@gmail.com>
Co-authored-by: sotohi <c6h4ohcooc6h5@gmail.com>
Co-authored-by: yhi264 <yhiraki@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-cameras/ja/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-global/ja/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-groups/ja/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-validation/ja/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-classificationmodel/ja/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-exports/ja/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-recording/ja/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/ja/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-system/ja/
Translation: Frigate NVR/Config - Cameras
Translation: Frigate NVR/Config - Global
Translation: Frigate NVR/Config - Groups
Translation: Frigate NVR/Config - Validation
Translation: Frigate NVR/views-classificationmodel
Translation: Frigate NVR/views-exports
Translation: Frigate NVR/views-recording
Translation: Frigate NVR/views-settings
Translation: Frigate NVR/views-system
2026-04-04 08:08:35 -05:00
32a7adaa23 Translated using Weblate (Ukrainian)
Currently translated at 98.3% (120 of 122 strings)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Максим Горпиніч <gorpinicmaksim2005ukr@protonmail.com>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-classificationmodel/uk/
Translation: Frigate NVR/views-classificationmodel
2026-04-04 08:08:35 -05:00
b3dce759d9 Translated using Weblate (Romanian)
Currently translated at 100.0% (1071 of 1071 strings)

Translated using Weblate (Romanian)

Currently translated at 100.0% (1068 of 1068 strings)

Translated using Weblate (Romanian)

Currently translated at 100.0% (1065 of 1065 strings)

Translated using Weblate (Romanian)

Currently translated at 100.0% (174 of 174 strings)

Translated using Weblate (Romanian)

Currently translated at 100.0% (469 of 469 strings)

Translated using Weblate (Romanian)

Currently translated at 100.0% (1053 of 1053 strings)

Translated using Weblate (Romanian)

Currently translated at 100.0% (790 of 790 strings)

Translated using Weblate (Romanian)

Currently translated at 100.0% (142 of 142 strings)

Translated using Weblate (Romanian)

Currently translated at 100.0% (1049 of 1049 strings)

Translated using Weblate (Romanian)

Currently translated at 100.0% (469 of 469 strings)

Translated using Weblate (Romanian)

Currently translated at 100.0% (129 of 129 strings)

Translated using Weblate (Romanian)

Currently translated at 100.0% (235 of 235 strings)

Translated using Weblate (Romanian)

Currently translated at 100.0% (99 of 99 strings)

Translated using Weblate (Romanian)

Currently translated at 100.0% (47 of 47 strings)

Translated using Weblate (Romanian)

Currently translated at 100.0% (58 of 58 strings)

Translated using Weblate (Romanian)

Currently translated at 100.0% (62 of 62 strings)

Translated using Weblate (Romanian)

Currently translated at 100.0% (172 of 172 strings)

Translated using Weblate (Romanian)

Currently translated at 100.0% (23 of 23 strings)

Translated using Weblate (Romanian)

Currently translated at 100.0% (790 of 790 strings)

Translated using Weblate (Romanian)

Currently translated at 98.3% (120 of 122 strings)

Translated using Weblate (Romanian)

Currently translated at 100.0% (123 of 123 strings)

Translated using Weblate (Romanian)

Currently translated at 100.0% (231 of 231 strings)

Translated using Weblate (Romanian)

Currently translated at 100.0% (788 of 788 strings)

Translated using Weblate (Romanian)

Currently translated at 100.0% (1011 of 1011 strings)

Translated using Weblate (Romanian)

Currently translated at 100.0% (467 of 467 strings)

Translated using Weblate (Romanian)

Currently translated at 100.0% (467 of 467 strings)

Translated using Weblate (Romanian)

Currently translated at 100.0% (1111 of 1111 strings)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: lukasig <lukasig@hotmail.com>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/common/ro/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-camera/ro/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-cameras/ro/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-global/ro/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/objects/ro/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-classificationmodel/ro/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-events/ro/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-explore/ro/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-exports/ro/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-facelibrary/ro/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-live/ro/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/ro/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-system/ro/
Translation: Frigate NVR/Config - Cameras
Translation: Frigate NVR/Config - Global
Translation: Frigate NVR/common
Translation: Frigate NVR/components-camera
Translation: Frigate NVR/objects
Translation: Frigate NVR/views-classificationmodel
Translation: Frigate NVR/views-events
Translation: Frigate NVR/views-explore
Translation: Frigate NVR/views-exports
Translation: Frigate NVR/views-facelibrary
Translation: Frigate NVR/views-live
Translation: Frigate NVR/views-settings
Translation: Frigate NVR/views-system
2026-04-04 08:08:35 -05:00
c65e6d84e9 Translated using Weblate (Russian)
Currently translated at 5.1% (41 of 790 strings)

Translated using Weblate (Russian)

Currently translated at 11.5% (54 of 469 strings)

Translated using Weblate (Russian)

Currently translated at 2.3% (11 of 469 strings)

Translated using Weblate (Russian)

Currently translated at 0.2% (2 of 790 strings)

Translated using Weblate (Russian)

Currently translated at 98.3% (120 of 122 strings)

Co-authored-by: Evgeny N. <isobago@gmail.com>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Артём Владимиров <artyomka71@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-cameras/ru/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-global/ru/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-classificationmodel/ru/
Translation: Frigate NVR/Config - Cameras
Translation: Frigate NVR/Config - Global
Translation: Frigate NVR/views-classificationmodel
2026-04-04 08:08:35 -05:00
41cfd23255 Translated using Weblate (Estonian)
Currently translated at 0.4% (2 of 467 strings)

Translated using Weblate (Estonian)

Currently translated at 86.7% (85 of 98 strings)

Translated using Weblate (Estonian)

Currently translated at 100.0% (123 of 123 strings)

Translated using Weblate (Estonian)

Currently translated at 100.0% (235 of 235 strings)

Translated using Weblate (Estonian)

Currently translated at 100.0% (47 of 47 strings)

Translated using Weblate (Estonian)

Currently translated at 100.0% (23 of 23 strings)

Translated using Weblate (Estonian)

Currently translated at 100.0% (231 of 231 strings)

Translated using Weblate (Estonian)

Currently translated at 19.0% (191 of 1005 strings)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Priit Jõerüüt <jrthwlate@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/common/et/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-camera/et/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-cameras/et/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/objects/et/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-exports/et/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-live/et/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/et/
Translation: Frigate NVR/Config - Cameras
Translation: Frigate NVR/common
Translation: Frigate NVR/components-camera
Translation: Frigate NVR/objects
Translation: Frigate NVR/views-exports
Translation: Frigate NVR/views-live
Translation: Frigate NVR/views-settings
2026-04-04 08:08:35 -05:00
75e074fb4f Translated using Weblate (Danish)
Currently translated at 98.3% (120 of 122 strings)

Co-authored-by: Bjorn Jorgensen <github@bjornz.dk>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-classificationmodel/da/
Translation: Frigate NVR/views-classificationmodel
2026-04-04 08:08:35 -05:00
56fbc4c185 Translated using Weblate (German)
Currently translated at 100.0% (1065 of 1065 strings)

Translated using Weblate (German)

Currently translated at 100.0% (174 of 174 strings)

Translated using Weblate (German)

Currently translated at 99.4% (173 of 174 strings)

Translated using Weblate (German)

Currently translated at 100.0% (1053 of 1053 strings)

Translated using Weblate (German)

Currently translated at 100.0% (1053 of 1053 strings)

Translated using Weblate (German)

Currently translated at 100.0% (469 of 469 strings)

Translated using Weblate (German)

Currently translated at 100.0% (99 of 99 strings)

Translated using Weblate (German)

Currently translated at 100.0% (123 of 123 strings)

Translated using Weblate (German)

Currently translated at 100.0% (790 of 790 strings)

Translated using Weblate (German)

Currently translated at 100.0% (790 of 790 strings)

Translated using Weblate (German)

Currently translated at 100.0% (790 of 790 strings)

Translated using Weblate (German)

Currently translated at 100.0% (172 of 172 strings)

Translated using Weblate (German)

Currently translated at 100.0% (129 of 129 strings)

Translated using Weblate (German)

Currently translated at 100.0% (58 of 58 strings)

Translated using Weblate (German)

Currently translated at 83.2% (656 of 788 strings)

Translated using Weblate (German)

Currently translated at 73.7% (757 of 1026 strings)

Translated using Weblate (German)

Currently translated at 100.0% (467 of 467 strings)

Translated using Weblate (German)

Currently translated at 99.4% (171 of 172 strings)

Translated using Weblate (German)

Currently translated at 100.0% (47 of 47 strings)

Translated using Weblate (German)

Currently translated at 100.0% (142 of 142 strings)

Translated using Weblate (German)

Currently translated at 100.0% (122 of 122 strings)

Translated using Weblate (German)

Currently translated at 100.0% (23 of 23 strings)

Translated using Weblate (German)

Currently translated at 100.0% (235 of 235 strings)

Translated using Weblate (German)

Currently translated at 100.0% (98 of 98 strings)

Translated using Weblate (German)

Currently translated at 100.0% (62 of 62 strings)

Translated using Weblate (German)

Currently translated at 98.3% (120 of 122 strings)

Translated using Weblate (German)

Currently translated at 99.1% (122 of 123 strings)

Translated using Weblate (German)

Currently translated at 72.8% (737 of 1011 strings)

Translated using Weblate (German)

Currently translated at 70.2% (328 of 467 strings)

Translated using Weblate (German)

Currently translated at 100.0% (231 of 231 strings)

Translated using Weblate (German)

Currently translated at 58.8% (464 of 788 strings)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Ninja110292 <ninja110292@users.noreply.hosted.weblate.org>
Co-authored-by: PhillyMay <mein.alias@outlook.com>
Co-authored-by: Sebastian Sie <sebastian.neuplanitz@googlemail.com>
Co-authored-by: jmtatsch <julian@tatsch.it>
Co-authored-by: mvdberge <micha.vordemberge@christmann.info>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/common/de/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-camera/de/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-cameras/de/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-global/de/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/objects/de/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-classificationmodel/de/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-events/de/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-explore/de/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-exports/de/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-facelibrary/de/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-live/de/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/de/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-system/de/
Translation: Frigate NVR/Config - Cameras
Translation: Frigate NVR/Config - Global
Translation: Frigate NVR/common
Translation: Frigate NVR/components-camera
Translation: Frigate NVR/objects
Translation: Frigate NVR/views-classificationmodel
Translation: Frigate NVR/views-events
Translation: Frigate NVR/views-explore
Translation: Frigate NVR/views-exports
Translation: Frigate NVR/views-facelibrary
Translation: Frigate NVR/views-live
Translation: Frigate NVR/views-settings
Translation: Frigate NVR/views-system
2026-04-04 08:08:35 -05:00
a6015631d4 Translated using Weblate (Portuguese (Brazil))
Currently translated at 93.1% (54 of 58 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 80.9% (115 of 142 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 67.7% (42 of 62 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 96.0% (24 of 25 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 44.1% (57 of 129 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (98 of 98 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (23 of 23 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 44.9% (461 of 1026 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 77.3% (133 of 172 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 4.6% (37 of 788 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 5.1% (24 of 467 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (22 of 22 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (58 of 58 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 45.9% (56 of 122 strings)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Marcelo Popper Costa <marcelo_popper@hotmail.com>
Co-authored-by: Tiago Krüger <tiagokruger404@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-dialog/pt_BR/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-cameras/pt_BR/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-global/pt_BR/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-groups/pt_BR/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-validation/pt_BR/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-classificationmodel/pt_BR/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-events/pt_BR/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-explore/pt_BR/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-exports/pt_BR/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-facelibrary/pt_BR/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-live/pt_BR/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/pt_BR/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-system/pt_BR/
Translation: Frigate NVR/Config - Cameras
Translation: Frigate NVR/Config - Global
Translation: Frigate NVR/Config - Groups
Translation: Frigate NVR/Config - Validation
Translation: Frigate NVR/components-dialog
Translation: Frigate NVR/views-classificationmodel
Translation: Frigate NVR/views-events
Translation: Frigate NVR/views-explore
Translation: Frigate NVR/views-exports
Translation: Frigate NVR/views-facelibrary
Translation: Frigate NVR/views-live
Translation: Frigate NVR/views-settings
Translation: Frigate NVR/views-system
2026-04-04 08:08:35 -05:00
99076cfe51 Translated using Weblate (Lithuanian)
Currently translated at 98.3% (120 of 122 strings)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: MaBeniu <runnerm@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-classificationmodel/lt/
Translation: Frigate NVR/views-classificationmodel
2026-04-04 08:08:35 -05:00
75d654b6d5 Translated using Weblate (Turkish)
Currently translated at 18.1% (4 of 22 strings)

Translated using Weblate (Turkish)

Currently translated at 0.2% (2 of 788 strings)

Translated using Weblate (Turkish)

Currently translated at 93.1% (54 of 58 strings)

Translated using Weblate (Turkish)

Currently translated at 0.2% (1 of 467 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (98 of 98 strings)

Translated using Weblate (Turkish)

Currently translated at 98.3% (120 of 122 strings)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Serhat Karaman <serhatkaramanworkmail@gmail.com>
Co-authored-by: m.a.tecik <matmakif38@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-cameras/tr/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-global/tr/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-validation/tr/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-classificationmodel/tr/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-facelibrary/tr/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-live/tr/
Translation: Frigate NVR/Config - Cameras
Translation: Frigate NVR/Config - Global
Translation: Frigate NVR/Config - Validation
Translation: Frigate NVR/views-classificationmodel
Translation: Frigate NVR/views-facelibrary
Translation: Frigate NVR/views-live
2026-04-04 08:08:35 -05:00
Josh HawkinsandGitHub e24eb676a9 GenAI tweaks (#22756)
* add DictAsYamlField for genai provider and runtime options

* regenerate config translations

* chat tweaks

- add page title
- scroll if near bottom
- add tool call group that dynamically updates as tool calls are made
- add bouncing loading indicator and other UI polish

* tool call grouping
2026-04-04 06:54:51 -06:00
Nicolas MowenandGitHub 9cb76d0bd9 Refactor genai (#22752)
CI / AMD64 Build (push) Waiting to run
CI / ARM Build (push) Waiting to run
CI / Jetson Jetpack 6 (push) Waiting to run
CI / AMD64 Extra Build (push) Blocked by required conditions
CI / ARM Extra Build (push) Blocked by required conditions
CI / Synaptics Build (push) Blocked by required conditions
CI / Assemble and push default build (push) Blocked by required conditions
* Switch to a feature-based roles so it is easier to choose models for different tasks

* Fallback and try llama-swap format

* List models supported by provider

* Cleanup

* Add frontend

* Improve model loading

* Make it possible to update genai without restarting

* Cleanup

* Cleanup

* Mypy
2026-04-03 17:13:52 -06:00
Josh HawkinsandGitHub bb77a01779 Settings tweaks (#22750)
* add ability to order subfields with dot notation

* put review genai enabled at the top of the genai subsection

* fix genai summary title truncation issue in detail stream
2026-04-03 17:46:43 -05:00
Nicolas MowenandGitHub 68dfb157ea Auto llama.cpp context (#22737)
CI / AMD64 Build (push) Waiting to run
CI / ARM Build (push) Waiting to run
CI / Jetson Jetpack 6 (push) Waiting to run
CI / AMD64 Extra Build (push) Blocked by required conditions
CI / ARM Extra Build (push) Blocked by required conditions
CI / Synaptics Build (push) Blocked by required conditions
CI / Assemble and push default build (push) Blocked by required conditions
* Add model probing

* Include aliases

* Pull correctly

* Correctly query specific model props

* Debug log

* Update model list
2026-04-02 20:13:34 -05:00
Josh HawkinsandGitHub 520d9eeb7f remove direct go2rtc API proxy in favor of frigate API endpoints (#22735)
CI / AMD64 Build (push) Waiting to run
CI / ARM Build (push) Waiting to run
CI / Jetson Jetpack 6 (push) Waiting to run
CI / AMD64 Extra Build (push) Blocked by required conditions
CI / ARM Extra Build (push) Blocked by required conditions
CI / Synaptics Build (push) Blocked by required conditions
CI / Assemble and push default build (push) Blocked by required conditions
2026-04-02 11:15:27 -06:00
Josh HawkinsandGitHub 5059311c9d Mask/zone editor fixes (#22732)
* add guards to reject missing sub commands

* mask/zone bugfixes

- fix websocket crash when creating a new mask or zone before a name is assigned
- fix deleted masks and zones not disappearing from the list until navigating away
- fix deleting profile override not reverting to the base mask in the list
- fix inertia defaulting to nan

* disable save button on invalid form state

* fix validation for speed estimation

* ensure polygon is closed before allowing save

* require all masks and zones to be on the base config

* clarify dialog message and tooltip when removing an override

* clarify docs
2026-04-02 08:15:51 -06:00
Josh HawkinsandGitHub adc8c2a6e8 Settings UI tweaks (#22722)
CI / AMD64 Build (push) Has been cancelled
CI / ARM Build (push) Has been cancelled
CI / Jetson Jetpack 6 (push) Has been cancelled
CI / AMD64 Extra Build (push) Has been cancelled
CI / ARM Extra Build (push) Has been cancelled
CI / Synaptics Build (push) Has been cancelled
CI / Assemble and push default build (push) Has been cancelled
* set edgetpu for multi-instance

* improve error messages when mixing/matching detectors

* allow custom add button text via uiSchema

* clarify language in docs for configuring detectors via the UI
2026-04-01 09:23:42 -06:00
Josh HawkinsandGitHub f1983b25ca Ensure environment vars are correctly substituted when dynamically changing go2rtc streams (#22723) 2026-04-01 08:06:25 -05:00
Nicolas MowenandGitHub e1245cb93d Improve profile state management and add recap tool (#22715)
CI / AMD64 Build (push) Waiting to run
CI / ARM Build (push) Waiting to run
CI / Jetson Jetpack 6 (push) Waiting to run
CI / AMD64 Extra Build (push) Blocked by required conditions
CI / ARM Extra Build (push) Blocked by required conditions
CI / Synaptics Build (push) Blocked by required conditions
CI / Assemble and push default build (push) Blocked by required conditions
* Improve profile information

* Add chat tools

* Add quick links to new chats

* Improve usefulness

* Cleanup

* fix
2026-03-31 19:09:32 -05:00
Josh HawkinsandGitHub b821420dee Miscellaneous improvements (#22714)
* scrub genai API keys and onvif credentials from config endpoint

* enforce camera access in thumbnail tracked-object fallback

The /events/{id}/thumbnail endpoint called require_camera_access when
loading persisted events but skipped the check in the tracked-object
fallback path for in-progress events. A restricted viewer could
retrieve thumbnails from cameras they should not have access to.

* block filter and attach flags in custom ffmpeg export args

The ffmpeg argument blocklist missed -filter_complex, -lavfi, -vf,
-af, -filter, and -attach. These flags can read arbitrary files via
source filters like movie= and amovie=, bypassing the existing -i
block. A user with camera access could exploit this through the
custom export endpoint.

* enforce camera access on VLM monitor endpoint

POST /vlm/monitor allowed any authenticated user to start VLM
monitoring on any camera without checking camera access. A viewer
restricted to specific cameras could monitor cameras they should
not have access to.

* enforce camera access in chat start_camera_watch tool

The start_camera_watch tool called via POST /chat/completion did not
validate camera access, allowing a restricted viewer to start VLM
monitoring on cameras outside their allowed set through the chat
interface.

* restrict review summary endpoint to admin role

* fix require_role call passing string instead of list

* fix section config uiSchema merge replacing base entries

mergeSectionConfig was replacing the entire base uiSchema when a
level override (global/camera) also defined one, causing base-level
ui:after/ui:before directives to be silently dropped. This broke
the SemanticSearchReindex button which was defined in base uiSchema.
2026-03-31 13:45:04 -05:00
Josh HawkinsandGitHub 4695e10341 await config refresh before clearing pending form data (#22707)
CI / AMD64 Build (push) Waiting to run
CI / ARM Build (push) Waiting to run
CI / Jetson Jetpack 6 (push) Waiting to run
CI / AMD64 Extra Build (push) Blocked by required conditions
CI / Synaptics Build (push) Blocked by required conditions
CI / Assemble and push default build (push) Blocked by required conditions
CI / ARM Extra Build (push) Blocked by required conditions
2026-03-30 12:24:53 -06:00
Josh HawkinsandGitHub 5a5d23b503 Docs refactor (#22703)
CI / AMD64 Build (push) Waiting to run
CI / ARM Build (push) Waiting to run
CI / Jetson Jetpack 6 (push) Waiting to run
CI / AMD64 Extra Build (push) Blocked by required conditions
CI / ARM Extra Build (push) Blocked by required conditions
CI / Synaptics Build (push) Blocked by required conditions
CI / Assemble and push default build (push) Blocked by required conditions
* add generation script

a script to read yaml code blocks from docs markdown files and generate corresponding "Frigate UI" tab instructions based on the json schema, i18n, section configs (hidden fields), and nav mappings

* first pass

* components

* add to gitignore

* second pass

* fix broken anchors

* fixes

* clean up tabs

* version bump

* tweaks

* remove role mapping config from ui
2026-03-30 10:36:45 -06:00
Josh HawkinsandGitHub a5e3dfd107 Add config validators (#22704)
* add validator for detect width and height

require both or neither

* coerce semantic search model string to enum

Built-in model names (jinav1, jinav2) get converted to the enum, genai provider names that don't match stay as plain strings and follow the existing validation path

* formatting
2026-03-30 08:34:54 -05:00
Nicolas MowenandGitHub f0a6626c6a Fix EU DST bug (#22698)
CI / AMD64 Build (push) Waiting to run
CI / ARM Build (push) Waiting to run
CI / Jetson Jetpack 6 (push) Waiting to run
CI / AMD64 Extra Build (push) Blocked by required conditions
CI / ARM Extra Build (push) Blocked by required conditions
CI / Synaptics Build (push) Blocked by required conditions
CI / Assemble and push default build (push) Blocked by required conditions
2026-03-29 18:38:11 -06:00
Josh HawkinsandGitHub 953d244c52 Add UI config messages framework (#22692)
* add config messages to sections and fields

* add alert variants

* add messages to types

* add detect fps, review, and audio messages

* add a basic set of messages

* remove emptySelectionHintKey from switches widget

use the new messages framework and revert the changes made in #22664
2026-03-29 15:25:40 -06:00
Josh HawkinsandGitHub 257dae11c1 Fix browser time format handling (#22694)
* implement hook to return resolved "24hour" | "12hour" string

delegate to existing use24HourTime(), which correctly detects the browser's locale preference via Intl.DateTimeFormat

* update frontend to use use24HourTime(config) or useTimeFormat(config) instead of directly comparing config.ui.time_format
2026-03-29 13:03:07 -06:00
Josh HawkinsandGitHub f44f485f48 Improve metrics UI performance (#22691)
* embed cpu/mem stats into detectors, cameras, and processes

so history consumers don't need the full cpu_usages dict

* support dot-notation for nested keys

to avoid returning large objects when only specific subfields are needed

* fix setLastUpdated being called inside useMemo

this triggered a setState-during-render warning, so moved to a useEffect

* frontend types

* frontend

hide instead of unmount all graphs - re-rendering is much more expensive and disruptive than the amount of dom memory required

keep track of visited tabs to keep them mounted rather than re-mounting or mounting all tabs

add isActive prop to all charts to re-trigger animation when switching metrics tabs

fix chart data padding bug where the loop used number of series rather than number of data points

fix bug where only a shallow copy of the array was used for mutation

fix missing key prop causing console logs

* add isactive after rebase

* formatting

* skip None values in filtered output for dot notation
2026-03-29 11:58:47 -06:00
Josh HawkinsandGitHub f002513d36 send MQTT snapshot when object enters required zone (#22690)
When mqtt.required_zones is configured, the initial mqtt snapshot on
object creation is always blocked because zone evaluation hasn't run
yet (entered_zones is empty). Later, the snapshot is only re-sent if
a better thumbnail is found, so if the first frame was already the
best capture the snapshot is silently lost.

Add a new_zone_entered flag to TrackedObject that triggers an mqtt
snapshot publish as soon as zone entry is confirmed, closing the gap
between object detection and zone evaluation.

Closes blakeblackshear/frigate#21027
2026-03-29 12:33:57 -05:00
Josh HawkinsandGitHub b04b1d0dc8 fix json serialization error for license plate box coordinates (#22689) 2026-03-29 11:30:39 -06:00
Nicolas MowenandGitHub decc8aa391 Incrase frequency of secondary pipeline updates (#22673)
* Incrase frequency of secondary pipeline updates when an object needs it

* Handle buffer timestamps correctly

* Consider LP that are not sub label
2026-03-29 12:12:01 -05:00
Nicolas MowenandGitHub 831cfc2444 Refactor Intel Stats (#22674)
* Improve Intel stats collection

* Update handling of stats to be simpler

* Simplify handling

* More accurately label Intel stats

* Cleanup

* Remove
2026-03-29 12:09:02 -05:00
Nicolas MowenandGitHub 29ca18c24c Add warm-up to onnx as some GPUs require kernel compilation before accepting inferences (#22685)
CI / AMD64 Build (push) Waiting to run
CI / ARM Build (push) Waiting to run
CI / Jetson Jetpack 6 (push) Waiting to run
CI / AMD64 Extra Build (push) Blocked by required conditions
CI / ARM Extra Build (push) Blocked by required conditions
CI / Synaptics Build (push) Blocked by required conditions
CI / Assemble and push default build (push) Blocked by required conditions
2026-03-29 11:19:46 -05:00
GuoQing LiuandGitHub 148e11afc5 fix: fix classification none label i18n issue (#22680) 2026-03-29 05:51:29 -06:00
Josh HawkinsandGitHub c35cee2d2f Review labels widget (#22664)
CI / AMD64 Build (push) Has been cancelled
CI / ARM Build (push) Has been cancelled
CI / Jetson Jetpack 6 (push) Has been cancelled
CI / AMD64 Extra Build (push) Has been cancelled
CI / ARM Extra Build (push) Has been cancelled
CI / Synaptics Build (push) Has been cancelled
CI / Assemble and push default build (push) Has been cancelled
* add review labels widget

* register widget and add to review section

* i18n

* add border to switches widget

* padding tweaks

* don't show audio labels if audio is not enabled

* add docs links

* ability to add custom labels to review

* add hint for empty selection in review labels and SwitchesWidget

* language consistency
2026-03-27 08:45:50 -06:00
Nicolas MowenandGitHub 1a01513223 Improve chat features (#22663)
* Improve notification messaging

* Improve wake behavior when a zone is not specified

* Fix prompt ordering for generate calls
2026-03-27 08:48:50 -05:00
GuoQing LiuandGitHub 06ad72860c feat: add axera npu load (#22662) 2026-03-27 05:07:07 -06:00
688 changed files with 42891 additions and 3953 deletions
+1 -1
View File
@@ -26,7 +26,7 @@ _Please read the [contributing guidelines](https://github.com/blakeblackshear/fr
- This PR fixes or closes issue: fixes #
- This PR is related to issue:
- Link to discussion with maintainers (**required** for large/pinned features):
- Link to discussion with maintainers (**required** for any large or "planned" features):
## For new features
+2 -2
View File
@@ -13,10 +13,10 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Check PR description against template
uses: actions/github-script@v7
uses: actions/github-script@v9
with:
script: |
const maintainers = ['blakeblackshear', 'NickM-27', 'hawkeye217', 'dependabot[bot]'];
const maintainers = ['blakeblackshear', 'NickM-27', 'hawkeye217', 'dependabot[bot]', 'weblate'];
const author = context.payload.pull_request.user.login;
if (maintainers.includes(author)) {
+31
View File
@@ -50,6 +50,37 @@ jobs:
# run: npm run test
# working-directory: ./web
web_e2e:
name: Web - E2E Tests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
with:
persist-credentials: false
- uses: actions/setup-node@v6
with:
node-version: 20.x
- run: npm install
working-directory: ./web
- name: Install Playwright Chromium
run: npx playwright install chromium --with-deps
working-directory: ./web
- name: Build web for E2E
run: npm run e2e:build
working-directory: ./web
- name: Run E2E tests
run: npm run e2e
working-directory: ./web
- name: Upload test artifacts
uses: actions/upload-artifact@v7
if: failure()
with:
name: playwright-report
path: |
web/test-results/
web/playwright-report/
retention-days: 7
python_checks:
runs-on: ubuntu-latest
name: Python Checks
+3 -3
View File
@@ -18,9 +18,9 @@ jobs:
close-issue-message: ""
days-before-stale: 30
days-before-close: 3
exempt-draft-pr: true
exempt-issue-labels: "pinned,security"
exempt-pr-labels: "pinned,security,dependencies"
exempt-draft-pr: false
exempt-issue-labels: "planned,security"
exempt-pr-labels: "planned,security,dependencies"
operations-per-run: 120
- name: Print outputs
env:
+1 -1
View File
@@ -12,7 +12,7 @@ If you've found a bug and want to fix it, go for it. Link to the relevant issue
Every new feature adds scope that the maintainers must test, maintain, and support long-term. Before writing code for a new feature:
1. **Check for existing discussion.** Search [feature requests](https://github.com/blakeblackshear/frigate/issues) and [discussions](https://github.com/blakeblackshear/frigate/discussions) to see if it's been proposed or discussed. Pinned feature requests are on our radar — we plan to get to them, but we don't maintain a public roadmap or timeline. Check in with us first if you have interest in contributing to one.
1. **Check for existing discussion.** Search [feature requests](https://github.com/blakeblackshear/frigate/issues) and [discussions](https://github.com/blakeblackshear/frigate/discussions) to see if it's been proposed or discussed. Feature requests tagged with "planned" are on our radar — we plan to get to them, but we don't maintain a public roadmap or timeline. Check in with us first if you have interest in contributing to one.
2. **Start a discussion or feature request first.** This helps ensure your idea aligns with Frigate's direction before you invest time building it. Community interest in a feature request helps us gauge demand, though a great idea is a great idea even without a crowd behind it.
3. **Be open to "no".** We try to be thoughtful about what we take on, and sometimes that means saying no to good code if the feature isn't the right fit for the project. These calls are sometimes subjective, and we won't always get them right. We're happy to discuss and reconsider.
+2
View File
@@ -14,6 +14,8 @@ services:
dockerfile: docker/main/Dockerfile
# Use target devcontainer-trt for TensorRT dev
target: devcontainer
cache_from:
- ghcr.io/blakeblackshear/frigate:cache-amd64
## Uncomment this block for nvidia gpu support
# deploy:
# resources:
+9
View File
@@ -52,6 +52,14 @@ RUN --mount=type=tmpfs,target=/tmp --mount=type=tmpfs,target=/var/cache/apt \
--mount=type=cache,target=/root/.ccache \
/deps/build_sqlite_vec.sh
# Build intel-media-driver from source against bookworm's system libva so it
# works with Debian 12's glibc/libstdc++ (pre-built noble/trixie packages
# require glibc 2.38 which is not available on bookworm).
FROM base AS intel-media-driver
ARG DEBIAN_FRONTEND
RUN --mount=type=bind,source=docker/main/build_intel_media_driver.sh,target=/deps/build_intel_media_driver.sh \
/deps/build_intel_media_driver.sh
FROM scratch AS go2rtc
ARG TARGETARCH
WORKDIR /rootfs/usr/local/go2rtc/bin
@@ -200,6 +208,7 @@ RUN --mount=type=bind,source=docker/main/install_hailort.sh,target=/deps/install
FROM scratch AS deps-rootfs
COPY --from=nginx /usr/local/nginx/ /usr/local/nginx/
COPY --from=sqlite-vec /usr/local/lib/ /usr/local/lib/
COPY --from=intel-media-driver /rootfs/ /
COPY --from=go2rtc /rootfs/ /
COPY --from=libusb-build /usr/local/lib /usr/local/lib
COPY --from=tempio /rootfs/ /
+48
View File
@@ -0,0 +1,48 @@
#!/bin/bash
set -euxo pipefail
# Intel media driver is x86_64-only. Create empty rootfs on other arches so
# the downstream COPY --from has a valid source.
if [ "$(uname -m)" != "x86_64" ]; then
mkdir -p /rootfs
exit 0
fi
MEDIA_DRIVER_VERSION="intel-media-25.2.6"
GMMLIB_VERSION="intel-gmmlib-22.7.2"
apt-get -qq update
apt-get -qq install -y wget gnupg ca-certificates cmake g++ make pkg-config
# Use Intel's jammy repo for newer libva-dev (2.22) which provides the
# VVC/VVC-decode headers required by media-driver 25.x
wget -qO - https://repositories.intel.com/gpu/intel-graphics.key | gpg --yes --dearmor --output /usr/share/keyrings/intel-graphics.gpg
echo "deb [arch=amd64 signed-by=/usr/share/keyrings/intel-graphics.gpg] https://repositories.intel.com/gpu/ubuntu jammy client" > /etc/apt/sources.list.d/intel-gpu-jammy.list
apt-get -qq update
apt-get -qq install -y libva-dev
# Build gmmlib (required by media-driver)
wget -qO gmmlib.tar.gz "https://github.com/intel/gmmlib/archive/refs/tags/${GMMLIB_VERSION}.tar.gz"
mkdir /tmp/gmmlib
tar -xf gmmlib.tar.gz -C /tmp/gmmlib --strip-components 1
cmake -S /tmp/gmmlib -B /tmp/gmmlib/build -DCMAKE_BUILD_TYPE=Release
make -C /tmp/gmmlib/build -j"$(nproc)"
make -C /tmp/gmmlib/build install
# Build intel-media-driver
wget -qO media-driver.tar.gz "https://github.com/intel/media-driver/archive/refs/tags/${MEDIA_DRIVER_VERSION}.tar.gz"
mkdir /tmp/media-driver
tar -xf media-driver.tar.gz -C /tmp/media-driver --strip-components 1
cmake -S /tmp/media-driver -B /tmp/media-driver/build \
-DCMAKE_BUILD_TYPE=Release \
-DENABLE_KERNELS=ON \
-DENABLE_NONFREE_KERNELS=ON \
-DCMAKE_INSTALL_PREFIX=/usr \
-DCMAKE_INSTALL_LIBDIR=/usr/lib/x86_64-linux-gnu \
-DCMAKE_C_FLAGS="-Wno-error" \
-DCMAKE_CXX_FLAGS="-Wno-error"
make -C /tmp/media-driver/build -j"$(nproc)"
# Install driver to rootfs for COPY --from
make -C /tmp/media-driver/build install DESTDIR=/rootfs
+29 -16
View File
@@ -87,38 +87,47 @@ if [[ "${TARGETARCH}" == "amd64" ]]; then
# intel packages use zst compression so we need to update dpkg
apt-get install -y dpkg
# use intel apt intel packages
# use intel apt repo for libmfx1 (legacy QSV, pre-Gen12)
wget -qO - https://repositories.intel.com/gpu/intel-graphics.key | gpg --yes --dearmor --output /usr/share/keyrings/intel-graphics.gpg
echo "deb [arch=amd64 signed-by=/usr/share/keyrings/intel-graphics.gpg] https://repositories.intel.com/gpu/ubuntu jammy client" | tee /etc/apt/sources.list.d/intel-gpu-jammy.list
apt-get -qq update
apt-get -qq install --no-install-recommends --no-install-suggests -y \
intel-media-va-driver-non-free libmfx1 libmfxgen1 libvpl2
# intel-media-va-driver-non-free is built from source in the
# intel-media-driver Dockerfile stage for Battlemage (Xe2) support
apt-get -qq install --no-install-recommends --no-install-suggests -y \
libmfx1
rm -f /usr/share/keyrings/intel-graphics.gpg
rm -f /etc/apt/sources.list.d/intel-gpu-jammy.list
# upgrade libva2, oneVPL runtime, and libvpl2 from trixie for Battlemage support
echo "deb http://deb.debian.org/debian trixie main" > /etc/apt/sources.list.d/trixie.list
apt-get -qq update
apt-get -qq install -y -t trixie libva2 libva-drm2 libzstd1
apt-get -qq install -y -t trixie libmfx-gen1.2 libvpl2
rm -f /etc/apt/sources.list.d/trixie.list
apt-get -qq update
apt-get -qq install -y ocl-icd-libopencl1
# install libtbb12 for NPU support
apt-get -qq install -y libtbb12
rm -f /usr/share/keyrings/intel-graphics.gpg
rm -f /etc/apt/sources.list.d/intel-gpu-jammy.list
# install legacy and standard intel icd and level-zero-gpu
# install legacy and standard intel compute packages
# see https://github.com/intel/compute-runtime/blob/master/LEGACY_PLATFORMS.md for more info
# needed core package
wget https://github.com/intel/compute-runtime/releases/download/25.13.33276.19/libigdgmm12_22.7.0_amd64.deb
dpkg -i libigdgmm12_22.7.0_amd64.deb
rm libigdgmm12_22.7.0_amd64.deb
wget https://github.com/intel/compute-runtime/releases/download/26.14.37833.4/libigdgmm12_22.9.0_amd64.deb
dpkg -i libigdgmm12_22.9.0_amd64.deb
rm libigdgmm12_22.9.0_amd64.deb
# legacy packages
# legacy compute-runtime packages
wget https://github.com/intel/compute-runtime/releases/download/24.35.30872.36/intel-opencl-icd-legacy1_24.35.30872.36_amd64.deb
wget https://github.com/intel/compute-runtime/releases/download/24.35.30872.36/intel-level-zero-gpu-legacy1_1.5.30872.36_amd64.deb
wget https://github.com/intel/intel-graphics-compiler/releases/download/igc-1.0.17537.24/intel-igc-opencl_1.0.17537.24_amd64.deb
wget https://github.com/intel/intel-graphics-compiler/releases/download/igc-1.0.17537.24/intel-igc-core_1.0.17537.24_amd64.deb
# standard packages
wget https://github.com/intel/compute-runtime/releases/download/25.13.33276.19/intel-opencl-icd_25.13.33276.19_amd64.deb
wget https://github.com/intel/compute-runtime/releases/download/25.13.33276.19/intel-level-zero-gpu_1.6.33276.19_amd64.deb
wget https://github.com/intel/intel-graphics-compiler/releases/download/v2.10.10/intel-igc-opencl-2_2.10.10+18926_amd64.deb
wget https://github.com/intel/intel-graphics-compiler/releases/download/v2.10.10/intel-igc-core-2_2.10.10+18926_amd64.deb
# standard compute-runtime packages
wget https://github.com/intel/compute-runtime/releases/download/26.14.37833.4/intel-opencl-icd_26.14.37833.4-0_amd64.deb
wget https://github.com/intel/compute-runtime/releases/download/26.14.37833.4/libze-intel-gpu1_26.14.37833.4-0_amd64.deb
wget https://github.com/intel/intel-graphics-compiler/releases/download/v2.32.7/intel-igc-opencl-2_2.32.7+21184_amd64.deb
wget https://github.com/intel/intel-graphics-compiler/releases/download/v2.32.7/intel-igc-core-2_2.32.7+21184_amd64.deb
# npu packages
wget https://github.com/oneapi-src/level-zero/releases/download/v1.28.2/level-zero_1.28.2+u22.04_amd64.deb
wget https://github.com/intel/linux-npu-driver/releases/download/v1.19.0/intel-driver-compiler-npu_1.19.0.20250707-16111289554_ubuntu22.04_amd64.deb
@@ -128,6 +137,10 @@ if [[ "${TARGETARCH}" == "amd64" ]]; then
dpkg -i *.deb
rm *.deb
apt-get -qq install -f -y
# Battlemage uses the xe kernel driver, but the VA-API driver is still iHD.
# The oneVPL runtime may look for a driver named after the kernel module.
ln -sf /usr/lib/x86_64-linux-gnu/dri/iHD_drv_video.so /usr/lib/x86_64-linux-gnu/dri/xe_drv_video.so
fi
if [[ "${TARGETARCH}" == "arm64" ]]; then
+3 -3
View File
@@ -5,13 +5,13 @@ aiohttp == 3.12.*
starlette == 0.47.*
starlette-context == 0.4.*
fastapi[standard-no-fastapi-cloud-cli] == 0.116.*
uvicorn == 0.35.*
uvicorn == 0.46.*
slowapi == 0.1.*
joserfc == 1.2.*
cryptography == 44.0.*
pathvalidate == 3.3.*
markupsafe == 3.0.*
python-multipart == 0.0.20
python-multipart == 0.0.26
# Classification Model Training
tensorflow == 2.19.* ; platform_machine == 'aarch64'
tensorflow-cpu == 2.19.* ; platform_machine == 'x86_64'
@@ -42,7 +42,7 @@ opencv-python-headless == 4.11.0.*
opencv-contrib-python == 4.11.0.*
scipy == 1.16.*
# OpenVino & ONNX
openvino == 2025.3.*
openvino == 2025.4.*
onnxruntime == 1.22.*
# Embeddings
transformers == 4.45.*
@@ -9,6 +9,7 @@ from typing import Any
from ruamel.yaml import YAML
sys.path.insert(0, "/opt/frigate")
from frigate.config.env import substitute_frigate_vars
from frigate.const import (
BIRDSEYE_PIPE,
DEFAULT_FFMPEG_VERSION,
@@ -47,14 +48,6 @@ ALLOW_ARBITRARY_EXEC = allow_arbitrary_exec is not None and str(
allow_arbitrary_exec
).lower() in ("true", "1", "yes")
FRIGATE_ENV_VARS = {k: v for k, v in os.environ.items() if k.startswith("FRIGATE_")}
# read docker secret files as env vars too
if os.path.isdir("/run/secrets"):
for secret_file in os.listdir("/run/secrets"):
if secret_file.startswith("FRIGATE_"):
FRIGATE_ENV_VARS[secret_file] = (
Path(os.path.join("/run/secrets", secret_file)).read_text().strip()
)
config_file = find_config_file()
@@ -103,13 +96,13 @@ if go2rtc_config["webrtc"].get("candidates") is None:
go2rtc_config["webrtc"]["candidates"] = default_candidates
if go2rtc_config.get("rtsp", {}).get("username") is not None:
go2rtc_config["rtsp"]["username"] = go2rtc_config["rtsp"]["username"].format(
**FRIGATE_ENV_VARS
go2rtc_config["rtsp"]["username"] = substitute_frigate_vars(
go2rtc_config["rtsp"]["username"]
)
if go2rtc_config.get("rtsp", {}).get("password") is not None:
go2rtc_config["rtsp"]["password"] = go2rtc_config["rtsp"]["password"].format(
**FRIGATE_ENV_VARS
go2rtc_config["rtsp"]["password"] = substitute_frigate_vars(
go2rtc_config["rtsp"]["password"]
)
# ensure ffmpeg path is set correctly
@@ -145,7 +138,7 @@ for name in list(go2rtc_config.get("streams", {})):
if isinstance(stream, str):
try:
formatted_stream = stream.format(**FRIGATE_ENV_VARS)
formatted_stream = substitute_frigate_vars(stream)
if not ALLOW_ARBITRARY_EXEC and is_restricted_source(formatted_stream):
print(
f"[ERROR] Stream '{name}' uses a restricted source (echo/expr/exec) which is disabled by default for security. "
@@ -164,7 +157,7 @@ for name in list(go2rtc_config.get("streams", {})):
filtered_streams = []
for i, stream_item in enumerate(stream):
try:
formatted_stream = stream_item.format(**FRIGATE_ENV_VARS)
formatted_stream = substitute_frigate_vars(stream_item)
if not ALLOW_ARBITRARY_EXEC and is_restricted_source(formatted_stream):
print(
f"[ERROR] Stream '{name}' item {i + 1} uses a restricted source (echo/expr/exec) which is disabled by default for security. "
@@ -227,16 +227,6 @@ http {
include proxy.conf;
}
# frontend uses this to fetch the version
location /api/go2rtc/api {
include auth_request.conf;
limit_except GET {
deny all;
}
proxy_pass http://go2rtc/api;
include proxy.conf;
}
# integration uses this to add webrtc candidate
location /api/go2rtc/webrtc {
include auth_request.conf;
+6 -3
View File
@@ -32,11 +32,14 @@ RUN echo /opt/rocm/lib|tee /opt/rocm-dist/etc/ld.so.conf.d/rocm.conf
FROM deps AS deps-prelim
COPY docker/rocm/debian-backports.sources /etc/apt/sources.list.d/debian-backports.sources
RUN apt-get update && \
# install_deps.sh upgraded libstdc++6 from trixie for Battlemage; the matching
# -dev package must also come from trixie or apt refuses to satisfy it.
RUN echo "deb http://deb.debian.org/debian trixie main" > /etc/apt/sources.list.d/trixie.list && \
apt-get update && \
apt-get install -y libnuma1 && \
apt-get install -qq -y -t bookworm-backports mesa-va-drivers mesa-vulkan-drivers && \
# Install C++ standard library headers for HIPRTC kernel compilation fallback
apt-get install -qq -y libstdc++-12-dev && \
apt-get install -qq -y -t trixie libstdc++-14-dev && \
rm -f /etc/apt/sources.list.d/trixie.list && \
rm -rf /var/lib/apt/lists/*
WORKDIR /opt/frigate
+1
View File
@@ -7,6 +7,7 @@
# Generated files
.docusaurus
.cache-loader
docs/integrations/api/
# Misc
.DS_Store
+115 -5
View File
@@ -4,12 +4,29 @@ title: Advanced Options
sidebar_label: Advanced Options
---
import ConfigTabs from "@site/src/components/ConfigTabs";
import TabItem from "@theme/TabItem";
import NavPath from "@site/src/components/NavPath";
### Logging
#### Frigate `logger`
Change the default log level for troubleshooting purposes.
<ConfigTabs>
<TabItem value="ui">
Navigate to <NavPath path="Settings > System > Logging" />.
| Field | Description |
| ------------------------- | ------------------------------------------------------- |
| **Logging level** | The default log level for all modules (default: `info`) |
| **Per-process log level** | Override the log level for specific modules |
</TabItem>
<TabItem value="yaml">
```yaml
logger:
# Optional: default log level (default: shown below)
@@ -19,6 +36,9 @@ logger:
frigate.mqtt: error
```
</TabItem>
</ConfigTabs>
Available log levels are: `debug`, `info`, `warning`, `error`, `critical`
Examples of available modules are:
@@ -48,7 +68,20 @@ This section can be used to set environment variables for those unable to modify
Variables prefixed with `FRIGATE_` can be referenced in config fields that support environment variable substitution (such as MQTT host and credentials, camera stream URLs, and ONVIF host and credentials) using the `{FRIGATE_VARIABLE_NAME}` syntax.
Example:
<ConfigTabs>
<TabItem value="ui">
Navigate to <NavPath path="Settings > System > Environment variables" /> to add or edit environment variables.
| Field | Description |
| --------- | --------------------------------------------------------- |
| **Key** | The environment variable name (e.g., `FRIGATE_MQTT_USER`) |
| **Value** | The value for the variable |
Variables defined here can be referenced elsewhere in your configuration using the `{FRIGATE_VARIABLE_NAME}` syntax.
</TabItem>
<TabItem value="yaml">
```yaml
environment_vars:
@@ -61,10 +94,27 @@ mqtt:
password: "{FRIGATE_MQTT_PASSWORD}"
```
</TabItem>
</ConfigTabs>
#### TensorFlow Thread Configuration
If you encounter thread creation errors during classification model training, you can limit TensorFlow's thread usage:
<ConfigTabs>
<TabItem value="ui">
Navigate to <NavPath path="Settings > System > Environment variables" /> and add the following variables:
| Variable | Description |
| --------------------------------- | ---------------------------------------------- |
| `TF_INTRA_OP_PARALLELISM_THREADS` | Threads within operations (`0` = use default) |
| `TF_INTER_OP_PARALLELISM_THREADS` | Threads between operations (`0` = use default) |
| `TF_DATASET_THREAD_POOL_SIZE` | Data pipeline threads (`0` = use default) |
</TabItem>
<TabItem value="yaml">
```yaml
environment_vars:
TF_INTRA_OP_PARALLELISM_THREADS: "2" # Threads within operations (0 = use default)
@@ -72,19 +122,35 @@ environment_vars:
TF_DATASET_THREAD_POOL_SIZE: "2" # Data pipeline threads (0 = use default)
```
</TabItem>
</ConfigTabs>
### `database`
Tracked object and recording information is managed in a sqlite database at `/config/frigate.db`. If that database is deleted, recordings will be orphaned and will need to be cleaned up manually. They also won't show up in the Media Browser within Home Assistant.
If you are storing your database on a network share (SMB, NFS, etc), you may get a `database is locked` error message on startup. You can customize the location of the database in the config if necessary.
If you are storing your database on a network share (SMB, NFS, etc), you may get a `database is locked` error message on startup. You can customize the location of the database if necessary.
This may need to be in a custom location if network storage is used for the media folder.
<ConfigTabs>
<TabItem value="ui">
Navigate to <NavPath path="Settings > System > Database" />.
- Set **Database path** to the custom path for the Frigate database file (default: `/config/frigate.db`)
</TabItem>
<TabItem value="yaml">
```yaml
database:
path: /path/to/frigate.db
```
</TabItem>
</ConfigTabs>
### `model`
If using a custom model, the width and height will need to be specified.
@@ -103,6 +169,22 @@ Custom models may also require different input tensor formats. The colorspace co
| "nhwc" |
| "nchw" |
<ConfigTabs>
<TabItem value="ui">
Navigate to <NavPath path="Settings > System > Detection model" /> to configure the model path, dimensions, and input format.
| Field | Description |
| --------------------------------------------- | ------------------------------------ |
| **Custom object detector model path** | Path to the custom model file |
| **Object detection model input width** | Model input width (default: 320) |
| **Object detection model input height** | Model input height (default: 320) |
| **Advanced > Model Input Tensor Shape** | Input tensor shape: `nhwc` or `nchw` |
| **Advanced > Model Input Pixel Color Format** | Pixel format: `rgb`, `bgr`, or `yuv` |
</TabItem>
<TabItem value="yaml">
```yaml
# Optional: model config
model:
@@ -113,6 +195,9 @@ model:
input_pixel_format: "bgr"
```
</TabItem>
</ConfigTabs>
#### `labelmap`
:::warning
@@ -163,7 +248,15 @@ services:
### Enabling IPv6
IPv6 is disabled by default, to enable IPv6 modify your Frigate configuration as follows:
IPv6 is disabled by default. Enable it in the Frigate configuration.
<ConfigTabs>
<TabItem value="ui">
Navigate to <NavPath path="Settings > System > Networking" /> and expand **IPv6 configuration**, then enable **Enable IPv6**.
</TabItem>
<TabItem value="yaml">
```yaml
networking:
@@ -171,11 +264,25 @@ networking:
enabled: True
```
</TabItem>
</ConfigTabs>
### Listen on different ports
You can change the ports Nginx uses for listening using Frigate's configuration file. The internal port (unauthenticated) and external port (authenticated) can be changed independently. You can also specify an IP address using the format `ip:port` if you wish to bind the port to a specific interface. This may be useful for example to prevent exposing the internal port outside the container.
You can change the ports Nginx uses for listening. The internal port (unauthenticated) and external port (authenticated) can be changed independently. You can also specify an IP address using the format `ip:port` if you wish to bind the port to a specific interface. This may be useful for example to prevent exposing the internal port outside the container.
For example:
<ConfigTabs>
<TabItem value="ui">
Navigate to <NavPath path="Settings > System > Networking" /> to configure the listen ports.
| Field | Description |
| ----------------- | --------------------------------------------------------- |
| **Internal port** | The unauthenticated listen address/port (default: `5000`) |
| **External port** | The authenticated listen address/port (default: `8971`) |
</TabItem>
<TabItem value="yaml">
```yaml
networking:
@@ -184,6 +291,9 @@ networking:
external: 8971
```
</TabItem>
</ConfigTabs>
:::warning
This setting is for advanced users. For the majority of use cases it's recommended to change the `ports` section of your Docker compose file or use the Docker `run` `--publish` option instead, e.g. `-p 443:8971`. Changing Frigate's ports may break some integrations.
+73 -8
View File
@@ -3,6 +3,10 @@ id: audio_detectors
title: Audio Detectors
---
import ConfigTabs from "@site/src/components/ConfigTabs";
import TabItem from "@theme/TabItem";
import NavPath from "@site/src/components/NavPath";
Frigate provides a builtin audio detector which runs on the CPU. Compared to object detection in images, audio detection is a relatively lightweight operation so the only option is to run the detection on a CPU.
## Configuration
@@ -11,7 +15,17 @@ Audio events work by detecting a type of audio and creating an event, the event
### Enabling Audio Events
Audio events can be enabled for all cameras or only for specific cameras.
Audio events can be enabled globally or for specific cameras.
<ConfigTabs>
<TabItem value="ui">
**Global:** Navigate to <NavPath path="Settings > Global configuration > Audio events" /> and set **Enable audio detection** to on.
**Per-camera:** Navigate to <NavPath path="Settings > Camera configuration > Audio events" /> and set **Enable audio detection** to on for the desired camera.
</TabItem>
<TabItem value="yaml">
```yaml
@@ -26,6 +40,9 @@ cameras:
enabled: True # <- enable audio events for the front_camera
```
</TabItem>
</ConfigTabs>
If you are using multiple streams then you must set the `audio` role on the stream that is going to be used for audio detection, this can be any stream but the stream must have audio included.
:::note
@@ -34,6 +51,14 @@ The ffmpeg process for capturing audio will be a separate connection to the came
:::
<ConfigTabs>
<TabItem value="ui">
Navigate to <NavPath path="Settings > Camera configuration > FFmpeg" /> and add an input with the `audio` role pointing to a stream that includes audio.
</TabItem>
<TabItem value="yaml">
```yaml
cameras:
front_camera:
@@ -48,6 +73,9 @@ cameras:
- detect
```
</TabItem>
</ConfigTabs>
### Configuring Minimum Volume
The audio detector uses volume levels in the same way that motion in a camera feed is used for object detection. This means that Frigate will not run audio detection unless the audio volume is above the configured level in order to reduce resource usage. Audio levels can vary widely between camera models so it is important to run tests to see what volume levels are. The Debug view in the Frigate UI has an Audio tab for cameras that have the `audio` role assigned where a graph and the current levels are is displayed. The `min_volume` parameter should be set to the minimum the `RMS` level required to run audio detection.
@@ -62,6 +90,17 @@ Volume is considered motion for recordings, this means when the `record -> retai
The included audio model has over [500 different types](https://github.com/blakeblackshear/frigate/blob/dev/audio-labelmap.txt) of audio that can be detected, many of which are not practical. By default `bark`, `fire_alarm`, `scream`, `speech`, and `yell` are enabled but these can be customized.
<ConfigTabs>
<TabItem value="ui">
Navigate to <NavPath path="Settings > Global configuration > Audio events" />.
- Set **Enable audio detection** to on
- Set **Listen types** to include the audio types you want to detect
</TabItem>
<TabItem value="yaml">
```yaml
audio:
enabled: True
@@ -73,15 +112,38 @@ audio:
- yell
```
</TabItem>
</ConfigTabs>
### Audio Transcription
Frigate supports fully local audio transcription using either `sherpa-onnx` or OpenAIs open-source Whisper models via `faster-whisper`. The goal of this feature is to support Semantic Search for `speech` audio events. Frigate is not intended to act as a continuous, fully-automatic speech transcription service — automatically transcribing all speech (or queuing many audio events for transcription) requires substantial CPU (or GPU) resources and is impractical on most systems. For this reason, transcriptions for events are initiated manually from the UI or the API rather than being run continuously in the background.
Frigate supports fully local audio transcription using either `sherpa-onnx` or OpenAI's open-source Whisper models via `faster-whisper`. The goal of this feature is to support Semantic Search for `speech` audio events. Frigate is not intended to act as a continuous, fully-automatic speech transcription service — automatically transcribing all speech (or queuing many audio events for transcription) requires substantial CPU (or GPU) resources and is impractical on most systems. For this reason, transcriptions for events are initiated manually from the UI or the API rather than being run continuously in the background.
:::info
Audio transcription requires a one-time internet connection to download the Whisper or Sherpa-ONNX model on first use. Once cached, transcription runs fully offline. See [Network Requirements](/frigate/network_requirements#one-time-model-downloads) for details.
:::
Transcription accuracy also depends heavily on the quality of your camera's microphone and recording conditions. Many cameras use inexpensive microphones, and distance to the speaker, low audio bitrate, or background noise can significantly reduce transcription quality. If you need higher accuracy, more robust long-running queues, or large-scale automatic transcription, consider using the HTTP API in combination with an automation platform and a cloud transcription service.
#### Configuration
To enable transcription, enable it in your config. Note that audio detection must also be enabled as described above in order to use audio transcription features.
To enable transcription, configure it globally and optionally disable for specific cameras. Audio detection must also be enabled as described above.
<ConfigTabs>
<TabItem value="ui">
**Global:** Navigate to <NavPath path="Settings > Enrichments > Audio transcription" />.
- Set **Enable audio transcription** to on
- Set **Transcription device** to the desired device
- Set **Model size** to the desired size
**Per-camera:** Navigate to <NavPath path="Settings > Camera configuration > Audio transcription" /> to enable or disable transcription for a specific camera.
</TabItem>
<TabItem value="yaml">
```yaml
audio_transcription:
@@ -100,6 +162,9 @@ cameras:
enabled: False
```
</TabItem>
</ConfigTabs>
:::note
Audio detection must be enabled and configured as described above in order to use audio transcription features.
@@ -146,7 +211,7 @@ If you have CUDA hardware, you can experiment with the `large` `whisper` model o
Any `speech` events in Explore can be transcribed and/or translated through the Transcribe button in the Tracked Object Details pane.
In order to use transcription and translation for past events, you must enable audio detection and define `speech` as an audio type to listen for in your config. To have `speech` events translated into the language of your choice, set the `language` config parameter with the correct [language code](https://github.com/openai/whisper/blob/main/whisper/tokenizer.py#L10).
In order to use transcription and translation for past events, you must enable audio detection and define `speech` as an audio type to listen for. To have `speech` events translated into the language of your choice, set the `language` config parameter with the correct [language code](https://github.com/openai/whisper/blob/main/whisper/tokenizer.py#L10).
The transcribed/translated speech will appear in the description box in the Tracked Object Details pane. If Semantic Search is enabled, embeddings are generated for the transcription text and are fully searchable using the description search type.
@@ -162,16 +227,16 @@ Recorded `speech` events will always use a `whisper` model, regardless of the `m
1. Why doesn't Frigate automatically transcribe all `speech` events?
Frigate does not implement a queue mechanism for speech transcription, and adding one is not trivial. A proper queue would need backpressure, prioritization, memory/disk buffering, retry logic, crash recovery, and safeguards to prevent unbounded growth when events outpace processing. Thats a significant amount of complexity for a feature that, in most real-world environments, would mostly just churn through low-value noise.
Frigate does not implement a queue mechanism for speech transcription, and adding one is not trivial. A proper queue would need backpressure, prioritization, memory/disk buffering, retry logic, crash recovery, and safeguards to prevent unbounded growth when events outpace processing. That's a significant amount of complexity for a feature that, in most real-world environments, would mostly just churn through low-value noise.
Because transcription is **serialized (one event at a time)** and speech events can be generated far faster than they can be processed, an auto-transcribe toggle would very quickly create an ever-growing backlog and degrade core functionality. For the amount of engineering and risk involved, it adds **very little practical value** for the majority of deployments, which are often on low-powered, edge hardware.
If you hear speech thats actually important and worth saving/indexing for the future, **just press the transcribe button in Explore** on that specific `speech` event - that keeps things explicit, reliable, and under your control.
If you hear speech that's actually important and worth saving/indexing for the future, **just press the transcribe button in Explore** on that specific `speech` event - that keeps things explicit, reliable, and under your control.
Other options are being considered for future versions of Frigate to add transcription options that support external `whisper` Docker containers. A single transcription service could then be shared by Frigate and other applications (for example, Home Assistant Voice), and run on more powerful machines when available.
2. Why don't you save live transcription text and use that for `speech` events?
Theres no guarantee that a `speech` event is even created from the exact audio that went through the transcription model. Live transcription and `speech` event creation are **separate, asynchronous processes**. Even when both are correctly configured, trying to align the **precise start and end time of a speech event** with whatever audio the model happened to be processing at that moment is unreliable.
There's no guarantee that a `speech` event is even created from the exact audio that went through the transcription model. Live transcription and `speech` event creation are **separate, asynchronous processes**. Even when both are correctly configured, trying to align the **precise start and end time of a speech event** with whatever audio the model happened to be processing at that moment is unreliable.
Automatically persisting that data would often result in **misaligned, partial, or irrelevant transcripts**, while still incurring all of the CPU, storage, and privacy costs of transcription. Thats why Frigate treats transcription as an **explicit, user-initiated action** rather than an automatic side-effect of every `speech` event.
Automatically persisting that data would often result in **misaligned, partial, or irrelevant transcripts**, while still incurring all of the CPU, storage, and privacy costs of transcription. That's why Frigate treats transcription as an **explicit, user-initiated action** rather than an automatic side-effect of every `speech` event.
+110 -7
View File
@@ -3,6 +3,10 @@ id: authentication
title: Authentication
---
import ConfigTabs from "@site/src/components/ConfigTabs";
import TabItem from "@theme/TabItem";
import NavPath from "@site/src/components/NavPath";
# Authentication
Frigate stores user information in its database. Password hashes are generated using industry standard PBKDF2-SHA256 with 600,000 iterations. Upon successful login, a JWT token is issued with an expiration date and set as a cookie. The cookie is refreshed as needed automatically. This JWT token can also be passed in the Authorization header as a bearer token.
@@ -22,13 +26,26 @@ On startup, an admin user and password are generated and printed in the logs. It
## Resetting admin password
In the event that you are locked out of your instance, you can tell Frigate to reset the admin password and print it in the logs on next startup using the `reset_admin_password` setting in your config file.
In the event that you are locked out of your instance, you can tell Frigate to reset the admin password and print it in the logs on next startup.
<ConfigTabs>
<TabItem value="ui">
Navigate to <NavPath path="Settings > System > Authentication" />.
- Set **Reset admin password** to on to reset the admin password and print it in the logs on next startup
</TabItem>
<TabItem value="yaml">
```yaml
auth:
reset_admin_password: true
```
</TabItem>
</ConfigTabs>
## Password guidance
Constructing secure passwords and managing them properly is important. Frigate requires a minimum length of 12 characters. For guidance on password standards see [NIST SP 800-63B](https://pages.nist.gov/800-63-3/sp800-63b.html). To learn what makes a password truly secure, read this [article](https://medium.com/peerio/how-to-build-a-billion-dollar-password-3d92568d9277).
@@ -47,7 +64,20 @@ Restarting Frigate will reset the rate limits.
If you are running Frigate behind a proxy, you will want to set `trusted_proxies` or these rate limits will apply to the upstream proxy IP address. This means that a brute force attack will rate limit login attempts from other devices and could temporarily lock you out of your instance. In order to ensure rate limits only apply to the actual IP address where the requests are coming from, you will need to list the upstream networks that you want to trust. These trusted proxies are checked against the `X-Forwarded-For` header when looking for the IP address where the request originated.
If you are running a reverse proxy in the same Docker Compose file as Frigate, here is an example of how your auth config might look:
If you are running a reverse proxy in the same Docker Compose file as Frigate, configure rate limiting and trusted proxies as follows:
<ConfigTabs>
<TabItem value="ui">
Navigate to <NavPath path="Settings > System > Authentication" />.
| Field | Description |
| ----------------------- | ------------------------------------------------------------------------------------------------------------------------- |
| **Failed login limits** | Rate limit string for login failures (e.g., `1/second;5/minute;20/hour`) |
| **Trusted proxies** | List of upstream network CIDRs to trust for `X-Forwarded-For` (e.g., `172.18.0.0/16` for internal Docker Compose network) |
</TabItem>
<TabItem value="yaml">
```yaml
auth:
@@ -56,6 +86,9 @@ auth:
- 172.18.0.0/16 # <---- this is the subnet for the internal Docker Compose network
```
</TabItem>
</ConfigTabs>
## Session Length
The default session length for user authentication in Frigate is 24 hours. This setting determines how long a user's authenticated session remains active before a token refresh is required — otherwise, the user will need to log in again.
@@ -67,11 +100,24 @@ The default value of `86400` will expire the authentication session after 24 hou
- `0`: Setting the session length to 0 will require a user to log in every time they access the application or after a very short, immediate timeout.
- `604800`: Setting the session length to 604800 will require a user to log in if the token is not refreshed for 7 days.
<ConfigTabs>
<TabItem value="ui">
Navigate to <NavPath path="Settings > System > Authentication" />.
- Set **Session length** to the duration in seconds before the authentication session expires (default: 86400 / 24 hours)
</TabItem>
<TabItem value="yaml">
```yaml
auth:
session_length: 86400
```
</TabItem>
</ConfigTabs>
## JWT Token Secret
The JWT token secret needs to be kept secure. Anyone with this secret can generate valid JWT tokens to authenticate with Frigate. This should be a cryptographically random string of at least 64 characters.
@@ -99,7 +145,18 @@ Frigate can be configured to leverage features of common upstream authentication
If you are leveraging the authentication of an upstream proxy, you likely want to disable Frigate's authentication as there is no correspondence between users in Frigate's database and users authenticated via the proxy. Optionally, if communication between the reverse proxy and Frigate is over an untrusted network, you should set an `auth_secret` in the `proxy` config and configure the proxy to send the secret value as a header named `X-Proxy-Secret`. Assuming this is an untrusted network, you will also want to [configure a real TLS certificate](tls.md) to ensure the traffic can't simply be sniffed to steal the secret.
Here is an example of how to disable Frigate's authentication and also ensure the requests come only from your known proxy.
To disable Frigate's authentication and ensure requests come only from your known proxy:
<ConfigTabs>
<TabItem value="ui">
1. Navigate to <NavPath path="Settings > System > Authentication" />.
- Set **Enable authentication** to off
2. Navigate to <NavPath path="Settings > System > Proxy" />.
- Set **Proxy secret** to `<some random long string>`
</TabItem>
<TabItem value="yaml">
```yaml
auth:
@@ -109,6 +166,9 @@ proxy:
auth_secret: <some random long string>
```
</TabItem>
</ConfigTabs>
You can use the following code to generate a random secret.
```shell
@@ -119,6 +179,20 @@ python3 -c 'import secrets; print(secrets.token_hex(64))'
If you have disabled Frigate's authentication and your proxy supports passing a header with authenticated usernames and/or roles, you can use the `header_map` config to specify the header name so it is passed to Frigate. For example, the following will map the `X-Forwarded-User` and `X-Forwarded-Groups` values. Header names are not case sensitive. Multiple values can be included in the role header. Frigate expects that the character separating the roles is a comma, but this can be specified using the `separator` config entry.
<ConfigTabs>
<TabItem value="ui">
Navigate to <NavPath path="Settings > System > Proxy" /> and configure the header mapping and separator settings.
| Field | Description |
| -------------------------------- | ---------------------------------------------------------------------------------------------------- |
| **Separator character** | Character separating multiple roles in the role header (default: comma). Authentik uses a pipe `\|`. |
| **Header mapping > User header** | Header name for the authenticated username (e.g., `x-forwarded-user`) |
| **Header mapping > Role header** | Header name for the authenticated role/groups (e.g., `x-forwarded-groups`) |
</TabItem>
<TabItem value="yaml">
```yaml
proxy:
...
@@ -128,19 +202,37 @@ proxy:
role: x-forwarded-groups
```
</TabItem>
</ConfigTabs>
Frigate supports `admin`, `viewer`, and custom roles (see below). When using port `8971`, Frigate validates these headers and subsequent requests use the headers `remote-user` and `remote-role` for authorization.
A default role can be provided. Any value in the mapped `role` header will override the default.
<ConfigTabs>
<TabItem value="ui">
Navigate to <NavPath path="Settings > System > Proxy" /> and set the default role.
| Field | Description |
| ---------------- | ------------------------------------------------------------- |
| **Default role** | Fallback role when no role header is present (e.g., `viewer`) |
</TabItem>
<TabItem value="yaml">
```yaml
proxy:
...
default_role: viewer
```
</TabItem>
</ConfigTabs>
## Role mapping
In some environments, upstream identity providers (OIDC, SAML, LDAP, etc.) do not pass a Frigate-compatible role directly, but instead pass one or more group claims. To handle this, Frigate supports a `role_map` that translates upstream group names into Frigates internal roles (`admin`, `viewer`, or custom).
In some environments, upstream identity providers (OIDC, SAML, LDAP, etc.) do not pass a Frigate-compatible role directly, but instead pass one or more group claims. To handle this, Frigate supports a `role_map` that translates upstream group names into Frigate's internal roles (`admin`, `viewer`, or custom). This is configurable via YAML in the configuration file:
```yaml
proxy:
@@ -175,7 +267,7 @@ In this example:
**Authenticated Port (8971)**
- Header mapping is **fully supported**.
- The `remote-role` header determines the users privileges:
- The `remote-role` header determines the user's privileges:
- **admin** → Full access (user management, configuration changes).
- **viewer** → Read-only access.
- **Custom roles** → Read-only access limited to the cameras defined in `auth.roles[role]`.
@@ -232,6 +324,14 @@ The viewer role provides read-only access to all cameras in the UI and API. Cust
### Role Configuration Example
<ConfigTabs>
<TabItem value="ui">
Navigate to <NavPath path="Settings > Users > Roles" /> to define custom roles and assign which cameras each role can access.
</TabItem>
<TabItem value="yaml">
```yaml {11-16}
cameras:
front_door:
@@ -251,13 +351,16 @@ auth:
- side_yard
```
</TabItem>
</ConfigTabs>
If you want to provide access to all cameras to a specific user, just use the **viewer** role.
### Managing User Roles
1. Log in as an **admin** user via port `8971` (preferred), or unauthenticated via port `5000`.
2. Navigate to **Settings**.
3. In the **Users** section, edit a users role by selecting from available roles (admin, viewer, or custom).
3. In the **Users** section, edit a user's role by selecting from available roles (admin, viewer, or custom).
4. In the **Roles** section, add/edit/delete custom roles (select cameras via switches). Deleting a role auto-reassigns users to "viewer".
### Role Enforcement
@@ -277,7 +380,7 @@ To use role-based access control, you must connect to Frigate via the **authenti
1. Log in as an **admin** user via port `8971`.
2. Navigate to **Settings > Users**.
3. Edit a users role by selecting **admin** or **viewer**.
3. Edit a user's role by selecting **admin** or **viewer**.
## API Authentication Guide
+41 -2
View File
@@ -3,6 +3,10 @@ id: autotracking
title: Camera Autotracking
---
import ConfigTabs from "@site/src/components/ConfigTabs";
import TabItem from "@theme/TabItem";
import NavPath from "@site/src/components/NavPath";
An ONVIF-capable, PTZ (pan-tilt-zoom) camera that supports relative movement within the field of view (FOV) can be configured to automatically track moving objects and keep them in the center of the frame.
![Autotracking example with zooming](/img/frigate-autotracking-example.gif)
@@ -29,12 +33,44 @@ A growing list of cameras and brands that have been reported by users to work wi
First, set up a PTZ preset in your camera's firmware and give it a name. If you're unsure how to do this, consult the documentation for your camera manufacturer's firmware. Some tutorials for common brands: [Amcrest](https://www.youtube.com/watch?v=lJlE9-krmrM), [Reolink](https://www.youtube.com/watch?v=VAnxHUY5i5w), [Dahua](https://www.youtube.com/watch?v=7sNbc5U-k54).
Edit your Frigate configuration file and enter the ONVIF parameters for your camera. Specify the object types to track, a required zone the object must enter to begin autotracking, and the camera preset name you configured in your camera's firmware to return to when tracking has ended. Optionally, specify a delay in seconds before Frigate returns the camera to the preset.
Configure the ONVIF connection and autotracking parameters for your camera. Specify the object types to track, a required zone the object must enter to begin autotracking, and the camera preset name you configured in your camera's firmware to return to when tracking has ended. Optionally, specify a delay in seconds before Frigate returns the camera to the preset.
An [ONVIF connection](cameras.md) is required for autotracking to function. Also, a [motion mask](masks.md) over your camera's timestamp and any overlay text is recommended to ensure they are completely excluded from scene change calculations when the camera is moving.
Note that `autotracking` is disabled by default but can be enabled in the configuration or by MQTT.
<ConfigTabs>
<TabItem value="ui">
Navigate to <NavPath path="Settings > Camera configuration > ONVIF" /> for the desired camera.
**ONVIF Connection**
| Field | Description |
| ---------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **ONVIF host** | Host of the camera being connected to. HTTP is assumed by default; prefix with `https://` for HTTPS. |
| **ONVIF port** | ONVIF port for device (default: 8000) |
| **ONVIF username** | Username for login. Some devices require admin to access ONVIF. |
| **ONVIF password** | Password for login |
| **Disable TLS verify** | Skip TLS verification and disable digest auth for ONVIF (default: false) |
| **ONVIF profile** | ONVIF media profile to use for PTZ control, matched by token or name. If not set, the first profile with valid PTZ configuration is selected automatically. |
**Autotracking**
| Field | Description |
| ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
| **Enable Autotracking** | Enable or disable object autotracking (default: false) |
| **Calibrate on start** | Calibrate the camera on startup by measuring PTZ motor speed (default: false) |
| **Zoom mode** | Zoom mode during autotracking: `disabled`, `absolute`, or `relative` (default: disabled) |
| **Zoom Factor** | Controls zoom behavior on tracked objects, between 0.1 and 0.75. Lower keeps more scene visible; higher zooms in more (default: 0.3) |
| **Tracked objects** | List of object types to track (default: person) |
| **Required Zones** | Zones an object must enter to begin autotracking |
| **Return Preset** | Name of ONVIF preset in camera firmware to return to when tracking ends (default: home) |
| **Return timeout** | Seconds to delay before returning to preset (default: 10) |
</TabItem>
<TabItem value="yaml">
```yaml
cameras:
ptzcamera:
@@ -92,13 +128,16 @@ cameras:
movement_weights: []
```
</TabItem>
</ConfigTabs>
## Calibration
PTZ motors operate at different speeds. Performing a calibration will direct Frigate to measure this speed over a variety of movements and use those measurements to better predict the amount of movement necessary to keep autotracked objects in the center of the frame.
Calibration is optional, but will greatly assist Frigate in autotracking objects that move across the camera's field of view more quickly.
To begin calibration, set the `calibrate_on_startup` for your camera to `True` and restart Frigate. Frigate will then make a series of small and large movements with your camera. Don't move the PTZ manually while calibration is in progress. Once complete, camera motion will stop and your config file will be automatically updated with a `movement_weights` parameter to be used in movement calculations. You should not modify this parameter manually.
To begin calibration, set `calibrate_on_startup` for your camera to `True` and restart Frigate. Frigate will then make a series of small and large movements with your camera. Don't move the PTZ manually while calibration is in progress. Once complete, camera motion will stop and your config file will be automatically updated with a `movement_weights` parameter to be used in movement calculations. You should not modify this parameter manually.
After calibration has ended, your PTZ will be moved to the preset specified by `return_preset`.
+25 -1
View File
@@ -3,8 +3,18 @@ id: bird_classification
title: Bird Classification
---
import ConfigTabs from "@site/src/components/ConfigTabs";
import TabItem from "@theme/TabItem";
import NavPath from "@site/src/components/NavPath";
Bird classification identifies known birds using a quantized Tensorflow model. When a known bird is recognized, its common name will be added as a `sub_label`. This information is included in the UI, filters, as well as in notifications.
:::info
Bird classification requires a one-time internet connection to download the classification model and label map from GitHub. Once cached, models work fully offline. See [Network Requirements](/frigate/network_requirements#one-time-model-downloads) for details.
:::
## Minimum System Requirements
Bird classification runs a lightweight tflite model on the CPU, there are no significantly different system requirements than running Frigate itself.
@@ -15,7 +25,18 @@ The classification model used is the MobileNet INat Bird Classification, [availa
## Configuration
Bird classification is disabled by default, it must be enabled in your config file before it can be used. Bird classification is a global configuration setting.
Bird classification is disabled by default and must be enabled before it can be used. Bird classification is a global configuration setting.
<ConfigTabs>
<TabItem value="ui">
Navigate to <NavPath path="Settings > Enrichments > Object classification" />.
- Set **Bird classification config > Bird classification** to on
- Set **Bird classification config > Minimum score** to the desired confidence score (default: 0.9)
</TabItem>
<TabItem value="yaml">
```yaml
classification:
@@ -23,6 +44,9 @@ classification:
enabled: true
```
</TabItem>
</ConfigTabs>
## Advanced Configuration
Fine-tune bird classification with these optional parameters:
+96 -5
View File
@@ -1,5 +1,9 @@
# Birdseye
import ConfigTabs from "@site/src/components/ConfigTabs";
import TabItem from "@theme/TabItem";
import NavPath from "@site/src/components/NavPath";
In addition to Frigate's Live camera dashboard, Birdseye allows a portable heads-up view of your cameras to see what is going on around your property / space without having to watch all cameras that may have nothing happening. Birdseye allows specific modes that intelligently show and disappear based on what you care about.
Birdseye can be viewed by adding the "Birdseye" camera to a Camera Group in the Web UI. Add a Camera Group by pressing the "+" icon on the Live page, and choose "Birdseye" as one of the cameras.
@@ -22,7 +26,22 @@ A custom icon can be added to the birdseye background by providing a 180x180 ima
### Birdseye view override at camera level
If you want to include a camera in Birdseye view only for specific circumstances, or just don't include it at all, the Birdseye setting can be set at the camera level.
To include a camera in Birdseye view only for specific circumstances, or exclude it entirely, configure Birdseye at the camera level.
<ConfigTabs>
<TabItem value="ui">
**Global settings:** Navigate to <NavPath path="Settings > System > Birdseye" /> to configure the default Birdseye behavior for all cameras.
**Per-camera overrides:** Navigate to <NavPath path="Settings > Camera configuration > Birdseye" /> to override the mode or disable Birdseye for a specific camera.
| Field | Description |
|-------|-------------|
| **Enable Birdseye** | Whether this camera appears in Birdseye view |
| **Tracking mode** | When to show the camera: `continuous`, `motion`, or `objects` |
</TabItem>
<TabItem value="yaml">
```yaml {8-10,12-14}
# Include all cameras by default in Birdseye view
@@ -41,9 +60,24 @@ cameras:
enabled: False
```
</TabItem>
</ConfigTabs>
### Birdseye Inactivity
By default birdseye shows all cameras that have had the configured activity in the last 30 seconds, this can be configured:
By default birdseye shows all cameras that have had the configured activity in the last 30 seconds. This threshold can be configured.
<ConfigTabs>
<TabItem value="ui">
Navigate to <NavPath path="Settings > System > Birdseye" />.
| Field | Description |
|-------|-------------|
| **Inactivity threshold** | Seconds of inactivity before a camera is hidden from Birdseye (default: 30) |
</TabItem>
<TabItem value="yaml">
```yaml
birdseye:
@@ -52,12 +86,28 @@ birdseye:
inactivity_threshold: 15
```
</TabItem>
</ConfigTabs>
## Birdseye Layout
### Birdseye Dimensions
The resolution and aspect ratio of birdseye can be configured. Resolution will increase the quality but does not affect the layout. Changing the aspect ratio of birdseye does affect how cameras are laid out.
<ConfigTabs>
<TabItem value="ui">
Navigate to <NavPath path="Settings > System > Birdseye" />.
| Field | Description |
|-------|-------------|
| **Width** | Birdseye output width in pixels (default: 1280) |
| **Height** | Birdseye output height in pixels (default: 720) |
</TabItem>
<TabItem value="yaml">
```yaml
birdseye:
enabled: True
@@ -65,10 +115,20 @@ birdseye:
height: 720
```
</TabItem>
</ConfigTabs>
### Sorting cameras in the Birdseye view
It is possible to override the order of cameras that are being shown in the Birdseye view.
The order needs to be set at the camera level.
It is possible to override the order of cameras that are being shown in the Birdseye view. The order is set at the camera level.
<ConfigTabs>
<TabItem value="ui">
Navigate to <NavPath path="Settings > Camera configuration > Birdseye" /> for each camera and set the **Position** field to control the display order.
</TabItem>
<TabItem value="yaml">
```yaml
# Include all cameras by default in Birdseye view
@@ -87,13 +147,26 @@ cameras:
order: 2
```
</TabItem>
</ConfigTabs>
_Note_: Cameras are sorted by default using their name to ensure a constant view inside Birdseye.
### Birdseye Cameras
It is possible to limit the number of cameras shown on birdseye at one time. When this is enabled, birdseye will show the cameras with most recent activity. There is a cooldown to ensure that cameras do not switch too frequently.
For example, this can be configured to only show the most recently active camera.
<ConfigTabs>
<TabItem value="ui">
Navigate to <NavPath path="Settings > System > Birdseye" />.
| Field | Description |
|-------|-------------|
| **Layout > Max cameras** | Maximum number of cameras shown at once (e.g., `1` for only the most active camera) |
</TabItem>
<TabItem value="yaml">
```yaml {3-4}
birdseye:
@@ -102,13 +175,31 @@ birdseye:
max_cameras: 1
```
</TabItem>
</ConfigTabs>
### Birdseye Scaling
By default birdseye tries to fit 2 cameras in each row and then double in size until a suitable layout is found. The scaling can be configured with a value between 1.0 and 5.0 depending on use case.
<ConfigTabs>
<TabItem value="ui">
Navigate to <NavPath path="Settings > System > Birdseye" />.
| Field | Description |
|-------|-------------|
| **Layout > Scaling factor** | Camera scaling factor between 1.0 and 5.0 (default: 2.0) |
</TabItem>
<TabItem value="yaml">
```yaml {3-4}
birdseye:
enabled: True
layout:
scaling_factor: 3.0
```
</TabItem>
</ConfigTabs>
+63 -6
View File
@@ -3,6 +3,10 @@ id: cameras
title: Camera Configuration
---
import ConfigTabs from "@site/src/components/ConfigTabs";
import TabItem from "@theme/TabItem";
import NavPath from "@site/src/components/NavPath";
## Setting Up Camera Inputs
Several inputs can be configured for each camera and the role of each input can be mixed and matched based on your needs. This allows you to use a lower resolution stream for object detection, but create recordings from a higher resolution stream, or vice versa.
@@ -17,6 +21,25 @@ Each role can only be assigned to one input per camera. The options for roles ar
| `record` | Saves segments of the video feed based on configuration settings. [docs](record.md) |
| `audio` | Feed for audio based detection. [docs](audio_detectors.md) |
<ConfigTabs>
<TabItem value="ui">
Navigate to <NavPath path="Settings > Camera configuration > FFmpeg" />.
| Field | Description |
| ----------------- | ------------------------------------------------------------------- |
| **Camera inputs** | List of input stream definitions (paths and roles) for this camera. |
Navigate to <NavPath path="Settings > Camera configuration > Object detection" />.
| Field | Description |
| ----------------- | ------------------------------------------------------------------------------------------------------ |
| **Detect width** | Width (pixels) of frames used for the detect stream; leave empty to use the native stream resolution. |
| **Detect height** | Height (pixels) of frames used for the detect stream; leave empty to use the native stream resolution. |
</TabItem>
<TabItem value="yaml">
```yaml
mqtt:
host: mqtt.server.com
@@ -36,7 +59,18 @@ cameras:
height: 720 # <- optional, by default Frigate tries to automatically detect resolution
```
Additional cameras are simply added to the config under the `cameras` entry.
</TabItem>
</ConfigTabs>
Additional cameras are simply added under the camera configuration section.
<ConfigTabs>
<TabItem value="ui">
Navigate to <NavPath path="Settings > Camera configuration > Management" /> and use the add camera button to configure each additional camera.
</TabItem>
<TabItem value="yaml">
```yaml
mqtt: ...
@@ -46,6 +80,9 @@ cameras:
side: ...
```
</TabItem>
</ConfigTabs>
:::note
If you only define one stream in your `inputs` and do not assign a `detect` role to it, Frigate will automatically assign it the `detect` role. Frigate will always decode a stream to support motion detection, Birdseye, the API image endpoints, and other features, even if you have disabled object detection with `enabled: False` in your config's `detect` section.
@@ -64,7 +101,19 @@ Not every PTZ supports ONVIF, which is the standard protocol Frigate uses to com
:::
Add the onvif section to your camera in your configuration file:
Configure the ONVIF connection for your camera to enable PTZ controls.
<ConfigTabs>
<TabItem value="ui">
1. Navigate to <NavPath path="Settings > Camera configuration > ONVIF" /> and select your camera.
- Set **ONVIF host** to your camera's IP address, e.g.: `10.0.10.10`
- Set **ONVIF port** to your camera's ONVIF port, e.g.: `8000`
- Set **ONVIF username** to your camera's ONVIF username, e.g.: `admin`
- Set **ONVIF password** to your camera's ONVIF password, e.g.: `password`
</TabItem>
<TabItem value="yaml">
```yaml {4-8}
cameras:
@@ -77,6 +126,9 @@ cameras:
password: password
```
</TabItem>
</ConfigTabs>
If the ONVIF connection is successful, PTZ controls will be available in the camera's WebUI.
:::note
@@ -130,13 +182,15 @@ The FeatureList on the [ONVIF Conformant Products Database](https://www.onvif.or
## Setting up camera groups
:::tip
Camera groups let you organize cameras together with a shared name and icon, making it easier to review and filter them. A default group for all cameras is always available.
It is recommended to set up camera groups using the UI.
<ConfigTabs>
<TabItem value="ui">
:::
On the Live dashboard, press the **+** icon in the main navigation to add a new camera group. Configure the group name, select which cameras to include, choose an icon, and set the display order.
Cameras can be grouped together and assigned a name and icon, this allows them to be reviewed and filtered together. There will always be the default group for all cameras.
</TabItem>
<TabItem value="yaml">
```yaml
camera_groups:
@@ -148,6 +202,9 @@ camera_groups:
order: 0
```
</TabItem>
</ConfigTabs>
## Two-Way Audio
See the guide [here](/configuration/live/#two-way-talk)
@@ -3,13 +3,23 @@ id: object_classification
title: Object Classification
---
import ConfigTabs from "@site/src/components/ConfigTabs";
import TabItem from "@theme/TabItem";
import NavPath from "@site/src/components/NavPath";
Object classification allows you to train a custom MobileNetV2 classification model to run on tracked objects (persons, cars, animals, etc.) to identify a finer category or attribute for that object. Classification results are visible in the Tracked Object Details pane in Explore, through the `frigate/tracked_object_details` MQTT topic, in Home Assistant sensors via the official Frigate integration, or through the event endpoints in the HTTP API.
:::info
Training a custom object classification model requires a one-time internet connection to download MobileNetV2 base weights. Once trained, the model runs fully offline. See [Network Requirements](/frigate/network_requirements#one-time-model-downloads) for details.
:::
## Minimum System Requirements
Object classification models are lightweight and run very fast on CPU.
Training the model does briefly use a high amount of system resources for about 13 minutes per training run. On lower-power devices, training may take longer.
Training the model does briefly use a high amount of system resources for about 1-3 minutes per training run. On lower-power devices, training may take longer.
A CPU with AVX + AVX2 instructions is required for training and inference.
@@ -27,7 +37,7 @@ For object classification:
### Classification Type
- **Sub label**:
- Applied to the objects `sub_label` field.
- Applied to the object's `sub_label` field.
- Ideal for a single, more specific identity or type.
- Example: `cat``Leo`, `Charlie`, `None`.
@@ -55,7 +65,7 @@ This two-step verification prevents false positives by requiring consistent pred
### Sub label
- **Known pet vs unknown**: For `dog` objects, set sub label to your pets name (e.g., `buddy`) or `none` for others.
- **Known pet vs unknown**: For `dog` objects, set sub label to your pet's name (e.g., `buddy`) or `none` for others.
- **Mail truck vs normal car**: For `car`, classify as `mail_truck` vs `car` to filter important arrivals.
- **Delivery vs non-delivery person**: For `person`, classify `delivery` vs `visitor` based on uniform/props.
@@ -68,7 +78,27 @@ This two-step verification prevents false positives by requiring consistent pred
## Configuration
Object classification is configured as a custom classification model. Each model has its own name and settings. You must list which object labels should be classified.
Object classification is configured as a custom classification model. Each model has its own name and settings. Specify which object labels should be classified.
<ConfigTabs>
<TabItem value="ui">
Navigate to the **Classification** page from the main navigation sidebar, then click **Add Classification**.
In the **Create New Classification** dialog:
| Field | Description |
| ----------------------- | ------------------------------------------------------------- |
| **Name** | A name for your classification model (e.g., `dog`) |
| **Type** | Select **Object** for object classification |
| **Object Label** | The object label to classify (e.g., `dog`, `person`, `car`) |
| **Classification Type** | Whether to assign results as a **Sub Label** or **Attribute** |
| **Classes** | The class names the model will learn to distinguish between |
The `threshold` (default: `0.8`) can be adjusted in the YAML configuration.
</TabItem>
<TabItem value="yaml">
```yaml
classification:
@@ -82,6 +112,9 @@ classification:
An optional config, `save_attempts`, can be set as a key under the model name. This defines the number of classification attempts to save in the Recent Classifications tab. For object classification models, the default is 200.
</TabItem>
</ConfigTabs>
## Training the model
Creating and training the model is done within the Frigate UI using the `Classification` page. The process consists of two steps:
@@ -104,18 +137,18 @@ If examples for some of your classes do not appear in the grid, you can continue
:::tip Diversity matters far more than volume
Selecting dozens of nearly identical images is one of the fastest ways to degrade model performance. MobileNetV2 can overfit quickly when trained on homogeneous data — the model learns what *that exact moment* looked like rather than what actually defines the class. **This is why Frigate does not implement bulk training in the UI.**
Selecting dozens of nearly identical images is one of the fastest ways to degrade model performance. MobileNetV2 can overfit quickly when trained on homogeneous data — the model learns what _that exact moment_ looked like rather than what actually defines the class. **This is why Frigate does not implement bulk training in the UI.**
For more detail, see [Frigate Tip: Best Practices for Training Face and Custom Classification Models](https://github.com/blakeblackshear/frigate/discussions/21374).
:::
- **Start small and iterate**: Begin with a small, representative set of images per class. Models often begin working well with surprisingly few examples and improve naturally over time.
- **Favor hard examples**: When images appear in the Recent Classifications tab, prioritize images scoring below 90100% or those captured under new lighting, weather, or distance conditions.
- **Favor hard examples**: When images appear in the Recent Classifications tab, prioritize images scoring below 90-100% or those captured under new lighting, weather, or distance conditions.
- **Avoid bulk training similar images**: Training large batches of images that already score 100% (or close) adds little new information and increases the risk of overfitting.
- **The wizard is just the starting point**: You dont need to find and label every class upfront. Missing classes will naturally appear in Recent Classifications, and those images tend to be more valuable because they represent new conditions and edge cases.
- **The wizard is just the starting point**: You don't need to find and label every class upfront. Missing classes will naturally appear in Recent Classifications, and those images tend to be more valuable because they represent new conditions and edge cases.
- **Problem framing**: Keep classes visually distinct and relevant to the chosen object types.
- **Preprocessing**: Ensure examples reflect object crops similar to Frigates boxes; keep the subject centered.
- **Preprocessing**: Ensure examples reflect object crops similar to Frigate's boxes; keep the subject centered.
- **Labels**: Keep label names short and consistent; include a `none` class if you plan to ignore uncertain predictions for sub labels.
- **Threshold**: Tune `threshold` per model to reduce false assignments. Start at `0.8` and adjust based on validation.
@@ -125,6 +158,17 @@ To troubleshoot issues with object classification models, enable debug logging t
Enable debug logs for classification models by adding `frigate.data_processing.real_time.custom_classification: debug` to your `logger` configuration. These logs are verbose, so only keep this enabled when necessary. Restart Frigate after this change.
<ConfigTabs>
<TabItem value="ui">
Navigate to <NavPath path="Settings > System > Logging" />.
- Set **Logging level** to `debug`
- Set **Per-process log level > `frigate.data_processing.real_time.custom_classification`** to `debug` for verbose classification logging
</TabItem>
<TabItem value="yaml">
```yaml
logger:
default: info
@@ -133,6 +177,9 @@ logger:
frigate.data_processing.real_time.custom_classification: debug
```
</TabItem>
</ConfigTabs>
The debug logs will show:
- Classification probabilities for each attempt
@@ -3,13 +3,23 @@ id: state_classification
title: State Classification
---
import ConfigTabs from "@site/src/components/ConfigTabs";
import TabItem from "@theme/TabItem";
import NavPath from "@site/src/components/NavPath";
State classification allows you to train a custom MobileNetV2 classification model on a fixed region of your camera frame(s) to determine a current state. The model can be configured to run on a schedule and/or when motion is detected in that region. Classification results are available through the `frigate/<camera_name>/classification/<model_name>` MQTT topic and in Home Assistant sensors via the official Frigate integration.
:::info
Training a custom state classification model requires a one-time internet connection to download MobileNetV2 base weights. Once trained, the model runs fully offline. See [Network Requirements](/frigate/network_requirements#one-time-model-downloads) for details.
:::
## Minimum System Requirements
State classification models are lightweight and run very fast on CPU.
Training the model does briefly use a high amount of system resources for about 13 minutes per training run. On lower-power devices, training may take longer.
Training the model does briefly use a high amount of system resources for about 1-3 minutes per training run. On lower-power devices, training may take longer.
A CPU with AVX + AVX2 instructions is required for training and inference.
@@ -33,7 +43,25 @@ For state classification:
## Configuration
State classification is configured as a custom classification model. Each model has its own name and settings. You must provide at least one camera crop under `state_config.cameras`.
State classification is configured as a custom classification model. Each model has its own name and settings. Provide at least one camera crop under `state_config.cameras`.
<ConfigTabs>
<TabItem value="ui">
Navigate to the **Classification** page from the main navigation sidebar, select the **States** tab, then click **Add Classification**.
In the **Create New Classification** dialog:
| Field | Description |
| ----------- | ------------------------------------------------------------------------------------ |
| **Name** | A name for your state classification model (e.g., `front_door`) |
| **Type** | Select **State** for state classification |
| **Classes** | The state names the model will learn to distinguish between (e.g., `open`, `closed`) |
After creating the model, the wizard will guide you through selecting the camera crop area and assigning training examples. The `threshold` (default: `0.8`), `motion`, and `interval` settings can be adjusted in the YAML configuration.
</TabItem>
<TabItem value="yaml">
```yaml
classification:
@@ -50,6 +78,9 @@ classification:
An optional config, `save_attempts`, can be set as a key under the model name. This defines the number of classification attempts to save in the Recent Classifications tab. For state classification models, the default is 100.
</TabItem>
</ConfigTabs>
## Training the model
Creating and training the model is done within the Frigate UI using the `Classification` page. The process consists of three steps:
@@ -72,7 +103,7 @@ Once some images are assigned, training will begin automatically.
:::tip Diversity matters far more than volume
Selecting dozens of nearly identical images is one of the fastest ways to degrade model performance. MobileNetV2 can overfit quickly when trained on homogeneous data — the model learns what *that exact moment* looked like rather than what actually defines the state. This often leads to models that work perfectly under the original conditions but become unstable when day turns to night, weather changes, or seasonal lighting shifts. **This is why Frigate does not implement bulk training in the UI.**
Selecting dozens of nearly identical images is one of the fastest ways to degrade model performance. MobileNetV2 can overfit quickly when trained on homogeneous data — the model learns what _that exact moment_ looked like rather than what actually defines the state. This often leads to models that work perfectly under the original conditions but become unstable when day turns to night, weather changes, or seasonal lighting shifts. **This is why Frigate does not implement bulk training in the UI.**
For more detail, see [Frigate Tip: Best Practices for Training Face and Custom Classification Models](https://github.com/blakeblackshear/frigate/discussions/21374).
@@ -82,7 +113,7 @@ For more detail, see [Frigate Tip: Best Practices for Training Face and Custom C
- **Problem framing**: Keep classes visually distinct and state-focused (e.g., `open`, `closed`, `unknown`). Avoid combining object identity with state in a single model unless necessary.
- **Data collection**: Use the model's Recent Classifications tab to gather balanced examples across times of day and weather.
- **When to train**: Focus on cases where the model is entirely incorrect or flips between states when it should not. There's no need to train additional images when the model is already working consistently.
- **Favor hard examples**: When images appear in the Recent Classifications tab, prioritize images scoring below 90100% or those captured under new conditions (e.g., first snow of the year, seasonal changes, objects temporarily in view, insects at night). These represent scenarios different from the default state and help prevent overfitting.
- **Favor hard examples**: When images appear in the Recent Classifications tab, prioritize images scoring below 90-100% or those captured under new conditions (e.g., first snow of the year, seasonal changes, objects temporarily in view, insects at night). These represent scenarios different from the default state and help prevent overfitting.
- **Avoid bulk training similar images**: Training large batches of images that already score 100% (or close) adds little new information and increases the risk of overfitting.
- **The wizard is just the starting point**: You don't need to find and label every state upfront. Missing states will naturally appear in Recent Classifications, and those images tend to be more valuable because they represent new conditions and edge cases.
@@ -92,6 +123,17 @@ To troubleshoot issues with state classification models, enable debug logging to
Enable debug logs for classification models by adding `frigate.data_processing.real_time.custom_classification: debug` to your `logger` configuration. These logs are verbose, so only keep this enabled when necessary. Restart Frigate after this change.
<ConfigTabs>
<TabItem value="ui">
Navigate to <NavPath path="Settings > System > Logging" />.
- Set **Logging level** to `debug`
- Set **Per-process log level > `frigate.data_processing.real_time.custom_classification`** to `debug` for verbose classification logging
</TabItem>
<TabItem value="yaml">
```yaml
logger:
default: info
@@ -100,6 +142,9 @@ logger:
frigate.data_processing.real_time.custom_classification: debug
```
</TabItem>
</ConfigTabs>
The debug logs will show:
- Classification probabilities for each attempt
+83 -22
View File
@@ -3,8 +3,18 @@ id: face_recognition
title: Face Recognition
---
import ConfigTabs from "@site/src/components/ConfigTabs";
import TabItem from "@theme/TabItem";
import NavPath from "@site/src/components/NavPath";
Face recognition identifies known individuals by matching detected faces with previously learned facial data. When a known `person` is recognized, their name will be added as a `sub_label`. This information is included in the UI, filters, as well as in notifications.
:::info
Face recognition requires a one-time internet connection to download detection and embedding models from GitHub. Once cached, models work fully offline. See [Network Requirements](/frigate/network_requirements#one-time-model-downloads) for details.
:::
## Model Requirements
### Face Detection
@@ -40,50 +50,101 @@ The `large` model is optimized for accuracy, an integrated or discrete GPU / NPU
## Configuration
Face recognition is disabled by default, face recognition must be enabled in the UI or in your config file before it can be used. Face recognition is a global configuration setting.
Face recognition is disabled by default and must be enabled before it can be used. Face recognition is a global configuration setting.
<ConfigTabs>
<TabItem value="ui">
Navigate to <NavPath path="Settings > Enrichments > Face recognition" />.
- Set **Enable face recognition** to on
</TabItem>
<TabItem value="yaml">
```yaml
face_recognition:
enabled: true
```
</TabItem>
</ConfigTabs>
Like the other real-time processors in Frigate, face recognition runs on the camera stream defined by the `detect` role in your config. To ensure optimal performance, select a suitable resolution for this stream in your camera's firmware that fits your specific scene and requirements.
## Advanced Configuration
Fine-tune face recognition with these optional parameters at the global level of your config. The only optional parameters that can be set at the camera level are `enabled` and `min_area`.
Fine-tune face recognition with these optional parameters. The only optional parameters that can be set at the camera level are `enabled` and `min_area`.
### Detection
- `detection_threshold`: Face detection confidence score required before recognition runs:
<ConfigTabs>
<TabItem value="ui">
Navigate to <NavPath path="Settings > Enrichments > Face recognition" />.
- **Detection threshold**: Face detection confidence score required before recognition runs. This field only applies to the standalone face detection model; `min_score` should be used to filter for models that have face detection built in.
- Default: `0.7`
- Note: This is field only applies to the standalone face detection model, `min_score` should be used to filter for models that have face detection built in.
- `min_area`: Defines the minimum size (in pixels) a face must be before recognition runs.
- Default: `500` pixels.
- Depending on the resolution of your camera's `detect` stream, you can increase this value to ignore small or distant faces.
- **Minimum face area**: Minimum size (in pixels) a face must be before recognition runs. Depending on the resolution of your camera's `detect` stream, you can increase this value to ignore small or distant faces.
- Default: `500` pixels
</TabItem>
<TabItem value="yaml">
```yaml
face_recognition:
enabled: true
detection_threshold: 0.7
min_area: 500
```
</TabItem>
</ConfigTabs>
### Recognition
- `model_size`: Which model size to use, options are `small` or `large`
- `unknown_score`: Min score to mark a person as a potential match, matches at or below this will be marked as unknown.
- Default: `0.8`.
- `recognition_threshold`: Recognition confidence score required to add the face to the object as a sub label.
- Default: `0.9`.
- `min_faces`: Min face recognitions for the sub label to be applied to the person object.
<ConfigTabs>
<TabItem value="ui">
Navigate to <NavPath path="Settings > Enrichments > Face recognition" />.
- **Model size**: Which model size to use, options are `small` or `large`.
- **Unknown score threshold**: Min score to mark a person as a potential match; matches at or below this will be marked as unknown.
- Default: `0.8`
- **Recognition threshold**: Recognition confidence score required to add the face to the object as a sub label.
- Default: `0.9`
- **Minimum faces**: Min face recognitions for the sub label to be applied to the person object.
- Default: `1`
- `save_attempts`: Number of images of recognized faces to save for training.
- Default: `200`.
- `blur_confidence_filter`: Enables a filter that calculates how blurry the face is and adjusts the confidence based on this.
- Default: `True`.
- `device`: Target a specific device to run the face recognition model on (multi-GPU installation).
- Default: `None`.
- Note: This setting is only applicable when using the `large` model. See [onnxruntime's provider options](https://onnxruntime.ai/docs/execution-providers/)
- **Save attempts**: Number of images of recognized faces to save for training.
- Default: `200`
- **Blur confidence filter**: Enables a filter that calculates how blurry the face is and adjusts the confidence based on this.
- Default: `True`
- **Device**: Target a specific device to run the face recognition model on (multi-GPU installation). This setting is only applicable when using the `large` model. See [onnxruntime's provider options](https://onnxruntime.ai/docs/execution-providers/).
- Default: `None`
</TabItem>
<TabItem value="yaml">
```yaml
face_recognition:
enabled: true
model_size: small
unknown_score: 0.8
recognition_threshold: 0.9
min_faces: 1
save_attempts: 200
blur_confidence_filter: true
device: None
```
</TabItem>
</ConfigTabs>
## Usage
Follow these steps to begin:
1. **Enable face recognition** in your configuration file and restart Frigate.
1. **Enable face recognition** in your configuration and restart Frigate.
2. **Upload one face** using the **Add Face** button's wizard in the Face Library section of the Frigate UI. Read below for the best practices on expanding your training set.
3. When Frigate detects and attempts to recognize a face, it will appear in the **Train** tab of the Face Library, along with its associated recognition confidence.
4. From the **Train** tab, you can **assign the face** to a new or existing person to improve recognition accuracy for the future.
@@ -110,7 +171,7 @@ When choosing images to include in the face training set it is recommended to al
- If it is difficult to make out details in a persons face it will not be helpful in training.
- Avoid images with extreme under/over-exposure.
- Avoid blurry / pixelated images.
- Avoid training on infrared (gray-scale). The models are trained on color images and will be able to extract features from gray-scale images.
- Avoid training on infrared (gray-scale). The models are trained on color images and will not be able to extract features from gray-scale images.
- Using images of people wearing hats / sunglasses may confuse the model.
- Do not upload too many similar images at the same time, it is recommended to train no more than 4-6 similar images for each person to avoid over-fitting.
+30 -2
View File
@@ -3,6 +3,10 @@ id: ffmpeg_presets
title: FFmpeg presets
---
import ConfigTabs from "@site/src/components/ConfigTabs";
import TabItem from "@theme/TabItem";
import NavPath from "@site/src/components/NavPath";
Some presets of FFmpeg args are provided by default to make the configuration easier. All presets can be seen in [this file](https://github.com/blakeblackshear/frigate/blob/master/frigate/ffmpeg_presets.py).
### Hwaccel Presets
@@ -21,7 +25,31 @@ See [the hwaccel docs](/configuration/hardware_acceleration_video.md) for more i
| preset-nvidia | Nvidia GPU | |
| preset-jetson-h264 | Nvidia Jetson with h264 stream | |
| preset-jetson-h265 | Nvidia Jetson with h265 stream | |
| preset-rkmpp | Rockchip MPP | Use image with \*-rk suffix and privileged mode |
| preset-rkmpp | Rockchip MPP | Use image with \*-rk suffix and privileged mode |
Select the appropriate hwaccel preset for your hardware.
<ConfigTabs>
<TabItem value="ui">
1. Navigate to <NavPath path="Settings > Global configuration > FFmpeg" /> and set **Hardware acceleration arguments** to the appropriate preset for your hardware.
2. To override for a specific camera, navigate to <NavPath path="Settings > Camera configuration > FFmpeg" /> and set **Hardware acceleration arguments** for that camera.
</TabItem>
<TabItem value="yaml">
```yaml
ffmpeg:
hwaccel_args: preset-vaapi
cameras:
front_door:
ffmpeg:
hwaccel_args: preset-nvidia
```
</TabItem>
</ConfigTabs>
### Input Args Presets
@@ -72,7 +100,7 @@ Output args presets help make the config more readable and handle use cases for
| Preset | Usage | Other Notes |
| -------------------------------- | --------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| preset-record-generic | Record WITHOUT audio | If your camera doesnt have audio, or if you dont want to record audio, use this option |
| preset-record-generic | Record WITHOUT audio | If your camera doesn't have audio, or if you don't want to record audio, use this option |
| preset-record-generic-audio-copy | Record WITH original audio | Use this to enable audio in recordings |
| preset-record-generic-audio-aac | Record WITH transcoded aac audio | This is the default when no option is specified. Use it to transcode audio to AAC. If the source is already in AAC format, use preset-record-generic-audio-copy instead to avoid unnecessary re-encoding |
| preset-record-mjpeg | Record an mjpeg stream | Recommend restreaming mjpeg stream instead |
+114 -2
View File
@@ -3,6 +3,10 @@ id: genai_config
title: Configuring Generative AI
---
import ConfigTabs from "@site/src/components/ConfigTabs";
import TabItem from "@theme/TabItem";
import NavPath from "@site/src/components/NavPath";
## Configuration
A Generative AI provider can be configured in the global config, which will make the Generative AI features available for use. There are currently 4 native providers available to integrate with Frigate. Other providers that support the OpenAI standard API can also be used. See the OpenAI-Compatible section below.
@@ -25,11 +29,11 @@ You must use a vision-capable model with Frigate. The following models are recom
| Model | Notes |
| ------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `qwen3-vl` | Strong visual and situational understanding, strong ability to identify smaller objects and interactions with object. |
| `qwen3-vl` | Strong visual and situational understanding, enhanced ability to identify smaller objects and interactions with object. |
| `qwen3.5` | Strong situational understanding, but missing DeepStack from qwen3-vl leading to worse performance for identifying objects in people's hand and other small details. |
| `gemma4` | Strong situational understanding, sometimes resorts to more vague terms like 'interacts' instead of assigning a specific action. |
| `Intern3.5VL` | Relatively fast with good vision comprehension |
| `gemma3` | Slower model with good vision and temporal understanding |
| `qwen2.5-vl` | Fast but capable model with good vision comprehension |
:::info
@@ -69,6 +73,18 @@ You must use a vision capable model with Frigate. The llama.cpp server supports
All llama.cpp native options can be passed through `provider_options`, including `temperature`, `top_k`, `top_p`, `min_p`, `repeat_penalty`, `repeat_last_n`, `seed`, `grammar`, and more. See the [llama.cpp server documentation](https://github.com/ggml-org/llama.cpp/blob/master/tools/server/README.md) for a complete list of available parameters.
<ConfigTabs>
<TabItem value="ui">
1. Navigate to <NavPath path="Settings > Enrichments > Generative AI" />.
- Set **Provider** to `llamacpp`
- Set **Base URL** to your llama.cpp server address (e.g., `http://localhost:8080`)
- Set **Model** to the name of your model
- Under **Provider Options**, set `context_size` to tell Frigate your context size so it can send the appropriate amount of information
</TabItem>
<TabItem value="yaml">
```yaml
genai:
provider: llamacpp
@@ -78,6 +94,9 @@ genai:
context_size: 16000 # Tell Frigate your context size so it can send the appropriate amount of information.
```
</TabItem>
</ConfigTabs>
### Ollama
[Ollama](https://ollama.com/) allows you to self-host large language models and keep everything running locally. It is highly recommended to host this server on a machine with an Nvidia graphics card, or on a Apple silicon Mac for best performance.
@@ -96,6 +115,18 @@ Note that Frigate will not automatically download the model you specify in your
#### Configuration
<ConfigTabs>
<TabItem value="ui">
1. Navigate to <NavPath path="Settings > Enrichments > Generative AI" />.
- Set **Provider** to `ollama`
- Set **Base URL** to your Ollama server address (e.g., `http://localhost:11434`)
- Set **Model** to the model tag (e.g., `qwen3-vl:4b`)
- Under **Provider Options**, set `keep_alive` (e.g., `-1`) and `options.num_ctx` to match your desired context size
</TabItem>
<TabItem value="yaml">
```yaml
genai:
provider: ollama
@@ -107,6 +138,9 @@ genai:
num_ctx: 8192 # make sure the context matches other services that are using ollama
```
</TabItem>
</ConfigTabs>
### OpenAI-Compatible
Frigate supports any provider that implements the OpenAI API standard. This includes self-hosted solutions like [vLLM](https://docs.vllm.ai/), [LocalAI](https://localai.io/), and other OpenAI-compatible servers.
@@ -130,6 +164,18 @@ This ensures Frigate uses the correct context window size when generating prompt
#### Configuration
<ConfigTabs>
<TabItem value="ui">
1. Navigate to <NavPath path="Settings > Enrichments > Generative AI" />.
- Set **Provider** to `openai`
- Set **Base URL** to your server address (e.g., `http://your-server:port`)
- Set **API key** if required by your server
- Set **Model** to the model name
</TabItem>
<TabItem value="yaml">
```yaml
genai:
provider: openai
@@ -138,18 +184,38 @@ genai:
model: your-model-name
```
</TabItem>
</ConfigTabs>
To use a different OpenAI-compatible API endpoint, set the `OPENAI_BASE_URL` environment variable to your provider's API URL.
## Cloud Providers
Cloud providers run on remote infrastructure and require an API key for authentication. These services handle all model inference on their servers.
:::info
Cloud Generative AI providers require an active internet connection to send images and prompts for processing. Local providers like llama.cpp and Ollama (with local models) do not require internet. See [Network Requirements](/frigate/network_requirements#generative-ai) for details.
:::
### Ollama Cloud
Ollama also supports [cloud models](https://ollama.com/cloud), where your local Ollama instance handles requests from Frigate, but model inference is performed in the cloud. Set up Ollama locally, sign in with your Ollama account, and specify the cloud model name in your Frigate config. For more details, see the Ollama cloud model [docs](https://docs.ollama.com/cloud).
#### Configuration
<ConfigTabs>
<TabItem value="ui">
1. Navigate to <NavPath path="Settings > Enrichments > Generative AI" />.
- Set **Provider** to `ollama`
- Set **Base URL** to your local Ollama address (e.g., `http://localhost:11434`)
- Set **Model** to the cloud model name
</TabItem>
<TabItem value="yaml">
```yaml
genai:
provider: ollama
@@ -157,6 +223,9 @@ genai:
model: cloud-model-name
```
</TabItem>
</ConfigTabs>
### Google Gemini
Google Gemini has a [free tier](https://ai.google.dev/pricing) for the API, however the limits may not be sufficient for standard Frigate usage. Choose a plan appropriate for your installation.
@@ -176,6 +245,17 @@ To start using Gemini, you must first get an API key from [Google AI Studio](htt
#### Configuration
<ConfigTabs>
<TabItem value="ui">
1. Navigate to <NavPath path="Settings > Enrichments > Generative AI" />.
- Set **Provider** to `gemini`
- Set **API key** to your Gemini API key (or use an environment variable such as `{FRIGATE_GEMINI_API_KEY}`)
- Set **Model** to the desired model (e.g., `gemini-2.5-flash`)
</TabItem>
<TabItem value="yaml">
```yaml
genai:
provider: gemini
@@ -183,6 +263,9 @@ genai:
model: gemini-2.5-flash
```
</TabItem>
</ConfigTabs>
:::note
To use a different Gemini-compatible API endpoint, set the `provider_options` with the `base_url` key to your provider's API URL. For example:
@@ -213,6 +296,17 @@ To start using OpenAI, you must first [create an API key](https://platform.opena
#### Configuration
<ConfigTabs>
<TabItem value="ui">
1. Navigate to <NavPath path="Settings > Enrichments > Generative AI" />.
- Set **Provider** to `openai`
- Set **API key** to your OpenAI API key (or use an environment variable such as `{FRIGATE_OPENAI_API_KEY}`)
- Set **Model** to the desired model (e.g., `gpt-4o`)
</TabItem>
<TabItem value="yaml">
```yaml
genai:
provider: openai
@@ -220,6 +314,9 @@ genai:
model: gpt-4o
```
</TabItem>
</ConfigTabs>
:::note
To use a different OpenAI-compatible API endpoint, set the `OPENAI_BASE_URL` environment variable to your provider's API URL.
@@ -257,6 +354,18 @@ To start using Azure OpenAI, you must first [create a resource](https://learn.mi
#### Configuration
<ConfigTabs>
<TabItem value="ui">
1. Navigate to <NavPath path="Settings > Enrichments > Generative AI" />.
- Set **Provider** to `azure_openai`
- Set **Base URL** to your Azure resource URL including the `api-version` parameter (e.g., `https://instance.cognitiveservices.azure.com/openai/responses?api-version=2025-04-01-preview`)
- Set **Model** to your deployed model name (e.g., `gpt-5-mini`)
- Set **API key** to your Azure OpenAI API key (or use an environment variable such as `{FRIGATE_OPENAI_API_KEY}`)
</TabItem>
<TabItem value="yaml">
```yaml
genai:
provider: azure_openai
@@ -264,3 +373,6 @@ genai:
model: gpt-5-mini
api_key: "{FRIGATE_OPENAI_API_KEY}"
```
</TabItem>
</ConfigTabs>
+40 -4
View File
@@ -3,6 +3,10 @@ id: genai_objects
title: Object Descriptions
---
import ConfigTabs from "@site/src/components/ConfigTabs";
import TabItem from "@theme/TabItem";
import NavPath from "@site/src/components/NavPath";
Generative AI can be used to automatically generate descriptive text based on the thumbnails of your tracked objects. This helps with [Semantic Search](/configuration/semantic_search) in Frigate to provide more context about your tracked objects. Descriptions are accessed via the _Explore_ view in the Frigate UI by clicking on a tracked object's thumbnail.
Requests for a description are sent off automatically to your AI provider at the end of the tracked object's lifecycle, or can optionally be sent earlier after a number of significantly changed frames, for example in use in more real-time notifications. Descriptions can also be regenerated manually via the Frigate UI. Note that if you are manually entering a description for tracked objects prior to its end, this will be overwritten by the generated response.
@@ -15,9 +19,9 @@ Generative AI object descriptions can also be toggled dynamically for a camera v
## Usage and Best Practices
Frigate's thumbnail search excels at identifying specific details about tracked objects for example, using an "image caption" approach to find a "person wearing a yellow vest," "a white dog running across the lawn," or "a red car on a residential street." To enhance this further, Frigates default prompts are designed to ask your AI provider about the intent behind the object's actions, rather than just describing its appearance.
Frigate's thumbnail search excels at identifying specific details about tracked objects -- for example, using an "image caption" approach to find a "person wearing a yellow vest," "a white dog running across the lawn," or "a red car on a residential street." To enhance this further, Frigate's default prompts are designed to ask your AI provider about the intent behind the object's actions, rather than just describing its appearance.
While generating simple descriptions of detected objects is useful, understanding intent provides a deeper layer of insight. Instead of just recognizing "what" is in a scene, Frigates default prompts aim to infer "why" it might be there or "what" it could do next. Descriptions tell you whats happening, but intent gives context. For instance, a person walking toward a door might seem like a visitor, but if theyre moving quickly after hours, you can infer a potential break-in attempt. Detecting a person loitering near a door at night can trigger an alert sooner than simply noting "a person standing by the door," helping you respond based on the situations context.
While generating simple descriptions of detected objects is useful, understanding intent provides a deeper layer of insight. Instead of just recognizing "what" is in a scene, Frigate's default prompts aim to infer "why" it might be there or "what" it could do next. Descriptions tell you what's happening, but intent gives context. For instance, a person walking toward a door might seem like a visitor, but if they're moving quickly after hours, you can infer a potential break-in attempt. Detecting a person loitering near a door at night can trigger an alert sooner than simply noting "a person standing by the door," helping you respond based on the situation's context.
## Custom Prompts
@@ -33,7 +37,18 @@ Prompts can use variable replacements `{label}`, `{sub_label}`, and `{camera}` t
:::
You are also able to define custom prompts in your configuration.
You can define custom prompts at the global level and per-object type. To configure custom prompts:
<ConfigTabs>
<TabItem value="ui">
1. Navigate to <NavPath path="Settings > Global configuration > Objects" />.
- Expand the **GenAI object config** section
- Set **Caption prompt** to your custom prompt text
- Under **Object prompts**, add entries keyed by object type (e.g., `person`, `car`) with custom prompts for each
</TabItem>
<TabItem value="yaml">
```yaml
genai:
@@ -49,7 +64,25 @@ objects:
car: "Observe the primary vehicle in these images. Focus on its movement, direction, or purpose (e.g., parking, approaching, circling). If it's a delivery vehicle, mention the company."
```
Prompts can also be overridden at the camera level to provide a more detailed prompt to the model about your specific camera, if you desire.
</TabItem>
</ConfigTabs>
Prompts can also be overridden at the camera level to provide a more detailed prompt to the model about your specific camera. To configure camera-level overrides:
<ConfigTabs>
<TabItem value="ui">
1. Navigate to <NavPath path="Settings > Camera configuration > Objects" /> for the desired camera.
- Expand the **GenAI object config** section
- Set **Enable GenAI** to on
- Set **Use snapshots** to on if desired
- Set **Caption prompt** to a camera-specific prompt
- Under **Object prompts**, add entries keyed by object type with camera-specific prompts
- Set **GenAI objects** to the list of object types that should receive descriptions (e.g., `person`, `cat`)
- Set **Required zones** to limit descriptions to objects in specific zones (e.g., `steps`)
</TabItem>
<TabItem value="yaml">
```yaml
cameras:
@@ -69,6 +102,9 @@ cameras:
- steps
```
</TabItem>
</ConfigTabs>
### Experiment with prompts
Many providers also have a public facing chat interface for their models. Download a couple of different thumbnails or snapshots from Frigate and try new things in the playground to get descriptions to your liking before updating the prompt in Frigate.
@@ -3,6 +3,10 @@ id: genai_review
title: Review Summaries
---
import ConfigTabs from "@site/src/components/ConfigTabs";
import TabItem from "@theme/TabItem";
import NavPath from "@site/src/components/NavPath";
Generative AI can be used to automatically generate structured summaries of review items. These summaries will show up in Frigate's native notifications as well as in the UI. Generative AI can also be used to take a collection of summaries over a period of time and provide a report, which may be useful to get a quick report of everything that happened while out for some amount of time.
Requests for a summary are requested automatically to your AI provider for alert review items when the activity has ended, they can also be optionally enabled for detections as well.
@@ -28,6 +32,30 @@ This will show in multiple places in the UI to give additional context about eac
Each installation and even camera can have different parameters for what is considered suspicious activity. Frigate allows the `activity_context_prompt` to be defined globally and at the camera level, which allows you to define more specifically what should be considered normal activity. It is important that this is not overly specific as it can sway the output of the response.
To configure the activity context prompt:
<ConfigTabs>
<TabItem value="ui">
Navigate to <NavPath path="Settings > Global configuration > Review" />.
- Set **GenAI config > Activity context prompt** to your custom activity context text
</TabItem>
<TabItem value="yaml">
```yaml
review:
genai:
activity_context_prompt: |
### Normal Activity Indicators (Level 0)
- Known/verified people in any zone at any time
...
```
</TabItem>
</ConfigTabs>
<details>
<summary>Default Activity Context Prompt</summary>
@@ -74,7 +102,18 @@ review:
### Image Source
By default, review summaries use preview images (cached preview frames) which have a lower resolution but use fewer tokens per image. For better image quality and more detailed analysis, you can configure Frigate to extract frames directly from recordings at a higher resolution:
By default, review summaries use preview images (cached preview frames) which have a lower resolution but use fewer tokens per image. For better image quality and more detailed analysis, configure Frigate to extract frames directly from recordings at a higher resolution.
<ConfigTabs>
<TabItem value="ui">
Navigate to <NavPath path="Settings > Global configuration > Review" />.
- Set **GenAI config > Enable GenAI descriptions** to on
- Set **GenAI config > Review image source** to `recordings` (default is `preview`)
</TabItem>
<TabItem value="yaml">
```yaml
review:
@@ -84,6 +123,9 @@ review:
image_source: recordings # Options: "preview" (default) or "recordings"
```
</TabItem>
</ConfigTabs>
When using `recordings`, frames are extracted at 480px height while maintaining the camera's original aspect ratio, providing better detail for the LLM while being mindful of context window size. This is particularly useful for scenarios where fine details matter, such as identifying license plates, reading text, or analyzing distant objects.
The number of frames sent to the LLM is dynamically calculated based on:
@@ -103,7 +145,17 @@ If recordings are not available for a given time period, the system will automat
### Additional Concerns
Along with the concern of suspicious activity or immediate threat, you may have concerns such as animals in your garden or a gate being left open. These concerns can be configured so that the review summaries will make note of them if the activity requires additional review. For example:
Along with the concern of suspicious activity or immediate threat, you may have concerns such as animals in your garden or a gate being left open. Configure these concerns so that review summaries will make note of them if the activity requires additional review.
<ConfigTabs>
<TabItem value="ui">
Navigate to <NavPath path="Settings > Global configuration > Review" />.
- Set **GenAI config > Additional concerns** to a list of your concerns (e.g., `animals in the garden`)
</TabItem>
<TabItem value="yaml">
```yaml {4,5}
review:
@@ -113,9 +165,22 @@ review:
- animals in the garden
```
</TabItem>
</ConfigTabs>
### Preferred Language
By default, review summaries are generated in English. You can configure Frigate to generate summaries in your preferred language by setting the `preferred_language` option:
By default, review summaries are generated in English. Configure Frigate to generate summaries in your preferred language by setting the `preferred_language` option.
<ConfigTabs>
<TabItem value="ui">
Navigate to <NavPath path="Settings > Global configuration > Review" />.
- Set **GenAI config > Preferred language** to the desired language (e.g., `Spanish`)
</TabItem>
<TabItem value="yaml">
```yaml {4}
review:
@@ -124,6 +189,9 @@ review:
preferred_language: Spanish
```
</TabItem>
</ConfigTabs>
## Review Reports
Along with individual review item summaries, Generative AI can also produce a single report of review items from all cameras marked "suspicious" over a specified time period (for example, a daily summary of suspicious activity while you're on vacation).
@@ -4,6 +4,9 @@ title: Video Decoding
---
import CommunityBadge from '@site/src/components/CommunityBadge';
import ConfigTabs from "@site/src/components/ConfigTabs";
import TabItem from "@theme/TabItem";
import NavPath from "@site/src/components/NavPath";
# Video Decoding
@@ -56,13 +59,14 @@ Frigate can utilize most Intel integrated GPUs and Arc GPUs to accelerate video
**Recommended hwaccel Preset**
| CPU Generation | Intel Driver | Recommended Preset | Notes |
| -------------- | ------------ | ------------------- | ------------------------------------------- |
| gen1 - gen5 | i965 | preset-vaapi | qsv is not supported, may not support H.265 |
| gen6 - gen7 | iHD | preset-vaapi | qsv is not supported |
| gen8 - gen12 | iHD | preset-vaapi | preset-intel-qsv-\* can also be used |
| gen13+ | iHD / Xe | preset-intel-qsv-\* | |
| Intel Arc GPU | iHD / Xe | preset-intel-qsv-\* | |
| CPU Generation | Intel Driver | Recommended Preset | Notes |
| ------------------ | ------------ | ------------------- | ------------------------------------------- |
| gen1 - gen5 | i965 | preset-vaapi | qsv is not supported, may not support H.265 |
| gen6 - gen7 | iHD | preset-vaapi | qsv is not supported |
| gen8 - gen12 | iHD | preset-vaapi | preset-intel-qsv-\* can also be used |
| gen13+ | iHD / Xe | preset-intel-qsv-\* | |
| Intel Arc A-series | iHD / Xe | preset-intel-qsv-\* | |
| Intel Arc B-series | iHD / Xe | preset-intel-qsv-\* | Requires host kernel 6.12+ |
:::
@@ -78,27 +82,60 @@ See [The Intel Docs](https://www.intel.com/content/www/us/en/support/articles/00
VAAPI supports automatic profile selection so it will work automatically with both H.264 and H.265 streams.
<ConfigTabs>
<TabItem value="ui">
Navigate to <NavPath path="Settings > Global configuration > FFmpeg" /> and set **Hardware acceleration arguments** to `VAAPI (Intel/AMD GPU)`. For per-camera overrides, navigate to <NavPath path="Settings > Camera configuration > FFmpeg" />.
</TabItem>
<TabItem value="yaml">
```yaml
ffmpeg:
hwaccel_args: preset-vaapi
```
</TabItem>
</ConfigTabs>
### Via Quicksync
#### H.264 streams
<ConfigTabs>
<TabItem value="ui">
Navigate to <NavPath path="Settings > Global configuration > FFmpeg" /> and set **Hardware acceleration arguments** to `Intel QuickSync (H.264)`. For per-camera overrides, navigate to <NavPath path="Settings > Camera configuration > FFmpeg" />.
</TabItem>
<TabItem value="yaml">
```yaml
ffmpeg:
hwaccel_args: preset-intel-qsv-h264
```
</TabItem>
</ConfigTabs>
#### H.265 streams
<ConfigTabs>
<TabItem value="ui">
Navigate to <NavPath path="Settings > Global configuration > FFmpeg" /> and set **Hardware acceleration arguments** to `Intel QuickSync (H.265)`. For per-camera overrides, navigate to <NavPath path="Settings > Camera configuration > FFmpeg" />.
</TabItem>
<TabItem value="yaml">
```yaml
ffmpeg:
hwaccel_args: preset-intel-qsv-h265
```
</TabItem>
</ConfigTabs>
### Configuring Intel GPU Stats in Docker
Additional configuration is needed for the Docker container to be able to access the `intel_gpu_top` command for GPU stats. There are two options:
@@ -196,11 +233,22 @@ You need to change the driver to `radeonsi` by adding the following environment
VAAPI supports automatic profile selection so it will work automatically with both H.264 and H.265 streams.
<ConfigTabs>
<TabItem value="ui">
Navigate to <NavPath path="Settings > Global configuration > FFmpeg" /> and set **Hardware acceleration arguments** to `VAAPI (Intel/AMD GPU)`. For per-camera overrides, navigate to <NavPath path="Settings > Camera configuration > FFmpeg" />.
</TabItem>
<TabItem value="yaml">
```yaml
ffmpeg:
hwaccel_args: preset-vaapi
```
</TabItem>
</ConfigTabs>
## NVIDIA GPUs
While older GPUs may work, it is recommended to use modern, supported GPUs. NVIDIA provides a [matrix of supported GPUs and features](https://developer.nvidia.com/video-encode-and-decode-gpu-support-matrix-new). If your card is on the list and supports CUVID/NVDEC, it will most likely work with Frigate for decoding. However, you must also use [a driver version that will work with FFmpeg](https://github.com/FFmpeg/nv-codec-headers/blob/master/README). Older driver versions may be missing symbols and fail to work, and older cards are not supported by newer driver versions. The only way around this is to [provide your own FFmpeg](/configuration/advanced#custom-ffmpeg-build) that will work with your driver version, but this is unsupported and may not work well if at all.
@@ -244,11 +292,22 @@ docker run -d \
Using `preset-nvidia` ffmpeg will automatically select the necessary profile for the incoming video, and will log an error if the profile is not supported by your GPU.
<ConfigTabs>
<TabItem value="ui">
Navigate to <NavPath path="Settings > Global configuration > FFmpeg" /> and set **Hardware acceleration arguments** to `NVIDIA GPU`. For per-camera overrides, navigate to <NavPath path="Settings > Camera configuration > FFmpeg" />.
</TabItem>
<TabItem value="yaml">
```yaml
ffmpeg:
hwaccel_args: preset-nvidia
```
</TabItem>
</ConfigTabs>
If everything is working correctly, you should see a significant improvement in performance.
Verify that hardware decoding is working by running `nvidia-smi`, which should show `ffmpeg`
processes:
@@ -296,6 +355,14 @@ These instructions were originally based on the [Jellyfin documentation](https:/
Ensure you increase the allocated RAM for your GPU to at least 128 (`raspi-config` > Performance Options > GPU Memory).
If you are using the HA App, you may need to use the full access variant and turn off _Protection mode_ for hardware acceleration.
<ConfigTabs>
<TabItem value="ui">
Navigate to <NavPath path="Settings > Global configuration > FFmpeg" /> and set **Hardware acceleration arguments** to `Raspberry Pi (H.264)` (for H.264 streams) or `Raspberry Pi (H.265)` (for H.265/HEVC streams). For per-camera overrides, navigate to <NavPath path="Settings > Camera configuration > FFmpeg" />.
</TabItem>
<TabItem value="yaml">
```yaml
# if you want to decode a h264 stream
ffmpeg:
@@ -306,6 +373,9 @@ ffmpeg:
hwaccel_args: preset-rpi-64-h265
```
</TabItem>
</ConfigTabs>
:::note
If running Frigate through Docker, you either need to run in privileged mode or
@@ -405,11 +475,22 @@ A list of supported codecs (you can use `ffmpeg -decoders | grep nvmpi` in the c
For example, for H264 video, you'll select `preset-jetson-h264`.
<ConfigTabs>
<TabItem value="ui">
Navigate to <NavPath path="Settings > Global configuration > FFmpeg" /> and set **Hardware acceleration arguments** to `NVIDIA Jetson (H.264)` (or `NVIDIA Jetson (H.265)` for HEVC streams). For per-camera overrides, navigate to <NavPath path="Settings > Camera configuration > FFmpeg" />.
</TabItem>
<TabItem value="yaml">
```yaml
ffmpeg:
hwaccel_args: preset-jetson-h264
```
</TabItem>
</ConfigTabs>
If everything is working correctly, you should see a significant reduction in ffmpeg CPU load and power consumption.
Verify that hardware decoding is working by running `jtop` (`sudo pip3 install -U jetson-stats`), which should show
that NVDEC/NVDEC1 are in use.
@@ -424,13 +505,24 @@ Make sure to follow the [Rockchip specific installation instructions](/frigate/i
### Configuration
Add one of the following FFmpeg presets to your `config.yml` to enable hardware video processing:
Set the FFmpeg hwaccel preset to enable hardware video processing.
<ConfigTabs>
<TabItem value="ui">
Navigate to <NavPath path="Settings > Global configuration > FFmpeg" /> and set **Hardware acceleration arguments** to `Rockchip RKMPP`. For per-camera overrides, navigate to <NavPath path="Settings > Camera configuration > FFmpeg" />.
</TabItem>
<TabItem value="yaml">
```yaml
ffmpeg:
hwaccel_args: preset-rkmpp
```
</TabItem>
</ConfigTabs>
:::note
Make sure that your SoC supports hardware acceleration for your input stream. For example, if your camera streams with h265 encoding and a 4k resolution, your SoC must be able to de- and encode h265 with a 4k resolution or higher. If you are unsure whether your SoC meets the requirements, take a look at the datasheet.
@@ -480,7 +572,15 @@ Make sure to follow the [Synaptics specific installation instructions](/frigate/
### Configuration
Add one of the following FFmpeg presets to your `config.yml` to enable hardware video processing:
Set the FFmpeg hwaccel args to enable hardware video processing.
<ConfigTabs>
<TabItem value="ui">
Navigate to <NavPath path="Settings > Global configuration > FFmpeg" /> and configure the hardware acceleration args and input args manually for Synaptics hardware. For per-camera overrides, navigate to <NavPath path="Settings > Camera configuration > FFmpeg" />.
</TabItem>
<TabItem value="yaml">
```yaml {2}
ffmpeg:
@@ -490,6 +590,9 @@ output_args:
record: preset-record-generic-audio-aac
```
</TabItem>
</ConfigTabs>
:::warning
Make sure that your SoC supports hardware acceleration for your input stream and your input stream is h264 encoding. For example, if your camera streams with h264 encoding, your SoC must be able to de- and encode with it. If you are unsure whether your SoC meets the requirements, take a look at the datasheet.
+72 -9
View File
@@ -3,13 +3,24 @@ id: index
title: Frigate Configuration
---
For Home Assistant App installations, the config file should be at `/addon_configs/<addon_directory>/config.yml`, where `<addon_directory>` is specific to the variant of the Frigate App you are running. See the list of directories [here](#accessing-app-config-dir).
import ConfigTabs from "@site/src/components/ConfigTabs";
import TabItem from "@theme/TabItem";
import NavPath from "@site/src/components/NavPath";
For all other installation types, the config file should be mapped to `/config/config.yml` inside the container.
Frigate can be configured through the **Settings UI** or by editing the YAML configuration file directly. The Settings UI is the recommended approach — it provides validation and a guided experience for all configuration options.
It is recommended to start with a minimal configuration and add to it as described in [the getting started guide](../guides/getting_started.md).
## Configuration File Location
For users who prefer to edit the YAML configuration file directly:
- **Home Assistant App:** `/addon_configs/<addon_directory>/config.yml` — see [directory list](#accessing-app-config-dir)
- **All other installations:** Map to `/config/config.yml` inside the container
It can be named `config.yml` or `config.yaml`, but if both files exist `config.yml` will be preferred and `config.yaml` will be ignored.
It is recommended to start with a minimal configuration and add to it as described in [this guide](../guides/getting_started.md) and use the built in configuration editor in Frigate's UI which supports validation.
A minimal starting configuration:
```yaml
mqtt:
@@ -38,7 +49,7 @@ When running Frigate through the HA App, the Frigate `/config` directory is mapp
**Whenever you see `/config` in the documentation, it refers to this directory.**
If for example you are running the standard App variant and use the [VS Code App](https://github.com/hassio-addons/addon-vscode) to browse your files, you can click _File_ > _Open folder..._ and navigate to `/addon_configs/ccab4aaf_frigate` to access the Frigate `/config` directory and edit the `config.yaml` file. You can also use the built-in file editor in the Frigate UI to edit the configuration file.
If for example you are running the standard App variant and use the [VS Code App](https://github.com/hassio-addons/addon-vscode) to browse your files, you can click _File_ > _Open folder..._ and navigate to `/addon_configs/ccab4aaf_frigate` to access the Frigate `/config` directory and edit the `config.yaml` file. You can also use the built-in config editor in the Frigate UI.
## VS Code Configuration Schema
@@ -81,7 +92,7 @@ genai:
## Common configuration examples
Here are some common starter configuration examples. Refer to the [reference config](./reference.md) for detailed information about all the config values.
Here are some common starter configuration examples. These can be configured through the Settings UI or via YAML. Refer to the [reference config](./reference.md) for detailed information about all config values.
### Raspberry Pi Home Assistant App with USB Coral
@@ -94,6 +105,20 @@ Here are some common starter configuration examples. Refer to the [reference con
- Save snapshots for 30 days
- Motion mask for the camera timestamp
<ConfigTabs>
<TabItem value="ui">
1. Navigate to <NavPath path="Settings > System > MQTT" /> and configure the MQTT connection to your Home Assistant Mosquitto broker
2. Navigate to <NavPath path="Settings > Global configuration > FFmpeg" /> and set **Hardware acceleration arguments** to `Raspberry Pi (H.264)`
3. Navigate to <NavPath path="Settings > System > Detector hardware" /> and add a detector with **Type** `EdgeTPU` and **Device** `usb`
4. Navigate to <NavPath path="Settings > Global configuration > Recording" /> and set **Enable recording** to on, **Motion retention > Retention days** to `7`, **Alert retention > Event retention > Retention days** to `30`, **Alert retention > Event retention > Retention mode** to `motion`, **Detection retention > Event retention > Retention days** to `30`, **Detection retention > Event retention > Retention mode** to `motion`
5. Navigate to <NavPath path="Settings > Global configuration > Snapshots" /> and set **Enable snapshots** to on, **Snapshot retention > Default retention** to `30`
6. Navigate to <NavPath path="Settings > Camera configuration > Management" /> and add your camera with the appropriate RTSP stream URL
7. Navigate to <NavPath path="Settings > Camera configuration > Masks / Zones" /> to add a motion mask for the camera timestamp
</TabItem>
<TabItem value="yaml">
```yaml
mqtt:
host: core-mosquitto
@@ -145,10 +170,13 @@ cameras:
coordinates: "0.000,0.427,0.002,0.000,0.999,0.000,0.999,0.781,0.885,0.456,0.700,0.424,0.701,0.311,0.507,0.294,0.453,0.347,0.451,0.400"
```
</TabItem>
</ConfigTabs>
### Standalone Intel Mini PC with USB Coral
- Single camera with 720p, 5fps stream for detect
- MQTT disabled (not integrated with home assistant)
- MQTT disabled (not integrated with Home Assistant)
- VAAPI hardware acceleration for decoding video
- USB Coral detector
- Save all video with any detectable motion for 7 days regardless of whether any objects were detected or not
@@ -156,6 +184,20 @@ cameras:
- Save snapshots for 30 days
- Motion mask for the camera timestamp
<ConfigTabs>
<TabItem value="ui">
1. Navigate to <NavPath path="Settings > System > MQTT" /> and set **Enable MQTT** to off
2. Navigate to <NavPath path="Settings > Global configuration > FFmpeg" /> and set **Hardware acceleration arguments** to `VAAPI (Intel/AMD GPU)`
3. Navigate to <NavPath path="Settings > System > Detector hardware" /> and add a detector with **Type** `EdgeTPU` and **Device** `usb`
4. Navigate to <NavPath path="Settings > Global configuration > Recording" /> and set **Enable recording** to on, **Motion retention > Retention days** to `7`, **Alert retention > Event retention > Retention days** to `30`, **Alert retention > Event retention > Retention mode** to `motion`, **Detection retention > Event retention > Retention days** to `30`, **Detection retention > Event retention > Retention mode** to `motion`
5. Navigate to <NavPath path="Settings > Global configuration > Snapshots" /> and set **Enable snapshots** to on, **Snapshot retention > Default retention** to `30`
6. Navigate to <NavPath path="Settings > Camera configuration > Management" /> and add your camera with the appropriate RTSP stream URL
7. Navigate to <NavPath path="Settings > Camera configuration > Masks / Zones" /> to add a motion mask for the camera timestamp
</TabItem>
<TabItem value="yaml">
```yaml
mqtt:
enabled: False
@@ -205,17 +247,35 @@ cameras:
coordinates: "0.000,0.427,0.002,0.000,0.999,0.000,0.999,0.781,0.885,0.456,0.700,0.424,0.701,0.311,0.507,0.294,0.453,0.347,0.451,0.400"
```
### Home Assistant integrated Intel Mini PC with OpenVino
</TabItem>
</ConfigTabs>
### Home Assistant integrated Intel Mini PC with OpenVINO
- Single camera with 720p, 5fps stream for detect
- MQTT connected to same mqtt server as home assistant
- MQTT connected to same MQTT server as Home Assistant
- VAAPI hardware acceleration for decoding video
- OpenVino detector
- OpenVINO detector
- Save all video with any detectable motion for 7 days regardless of whether any objects were detected or not
- Continue to keep all video if it qualified as an alert or detection for 30 days
- Save snapshots for 30 days
- Motion mask for the camera timestamp
<ConfigTabs>
<TabItem value="ui">
1. Navigate to <NavPath path="Settings > System > MQTT" /> and configure the connection to your MQTT broker
2. Navigate to <NavPath path="Settings > Global configuration > FFmpeg" /> and set **Hardware acceleration arguments** to `VAAPI (Intel/AMD GPU)`
3. Navigate to <NavPath path="Settings > System > Detector hardware" /> and add a detector with **Type** `openvino` and **Device** `AUTO`
4. Navigate to <NavPath path="Settings > System > Detection model" /> and configure the OpenVINO model path and settings
5. Navigate to <NavPath path="Settings > Global configuration > Recording" /> and set **Enable recording** to on, **Motion retention > Retention days** to `7`, **Alert retention > Event retention > Retention days** to `30`, **Alert retention > Event retention > Retention mode** to `motion`, **Detection retention > Event retention > Retention days** to `30`, **Detection retention > Event retention > Retention mode** to `motion`
6. Navigate to <NavPath path="Settings > Global configuration > Snapshots" /> and set **Enable snapshots** to on, **Snapshot retention > Default retention** to `30`
7. Navigate to <NavPath path="Settings > Camera configuration > Management" /> and add your camera with the appropriate RTSP stream URL
8. Navigate to <NavPath path="Settings > Camera configuration > Masks / Zones" /> to add a motion mask for the camera timestamp
</TabItem>
<TabItem value="yaml">
```yaml
mqtt:
host: 192.168.X.X # <---- same mqtt broker that home assistant uses
@@ -274,3 +334,6 @@ cameras:
enabled: true
coordinates: "0.000,0.427,0.002,0.000,0.999,0.000,0.999,0.781,0.885,0.456,0.700,0.424,0.701,0.311,0.507,0.294,0.453,0.347,0.451,0.400"
```
</TabItem>
</ConfigTabs>
@@ -3,10 +3,20 @@ id: license_plate_recognition
title: License Plate Recognition (LPR)
---
import ConfigTabs from "@site/src/components/ConfigTabs";
import TabItem from "@theme/TabItem";
import NavPath from "@site/src/components/NavPath";
Frigate can recognize license plates on vehicles and automatically add the detected characters to the `recognized_license_plate` field or a [known](#matching) name as a `sub_label` to tracked objects of type `car` or `motorcycle`. A common use case may be to read the license plates of cars pulling into a driveway or cars passing by on a street.
LPR works best when the license plate is clearly visible to the camera. For moving vehicles, Frigate continuously refines the recognition process, keeping the most confident result. When a vehicle becomes stationary, LPR continues to run for a short time after to attempt recognition.
:::info
License plate recognition requires a one-time internet connection to download OCR and detection models from GitHub. Once cached, models work fully offline. See [Network Requirements](/frigate/network_requirements#one-time-model-downloads) for details.
:::
When a plate is recognized, the details are:
- Added as a `sub_label` (if [known](#matching)) or the `recognized_license_plate` field (if unknown) to a tracked object.
@@ -34,14 +44,35 @@ License plate recognition works by running AI models locally on your system. The
## Configuration
License plate recognition is disabled by default. Enable it in your config file:
License plate recognition is disabled by default and must be enabled before it can be used.
<ConfigTabs>
<TabItem value="ui">
Navigate to <NavPath path="Settings > Enrichments > License plate recognition" />.
- Set **Enable LPR** to on
</TabItem>
<TabItem value="yaml">
```yaml
lpr:
enabled: True
```
Like other enrichments in Frigate, LPR **must be enabled globally** to use the feature. You should disable it for specific cameras at the camera level if you don't want to run LPR on cars on those cameras:
</TabItem>
</ConfigTabs>
Like other enrichments in Frigate, LPR **must be enabled globally** to use the feature. Disable it for specific cameras at the camera level if you don't want to run LPR on cars on those cameras.
<ConfigTabs>
<TabItem value="ui">
Navigate to <NavPath path="Settings > Camera configuration > License plate recognition" /> for the desired camera and disable the **Enable LPR** toggle.
</TabItem>
<TabItem value="yaml">
```yaml {4,5}
cameras:
@@ -51,65 +82,144 @@ cameras:
enabled: False
```
</TabItem>
</ConfigTabs>
For non-dedicated LPR cameras, ensure that your camera is configured to detect objects of type `car` or `motorcycle`, and that a car or motorcycle is actually being detected by Frigate. Otherwise, LPR will not run.
Like the other real-time processors in Frigate, license plate recognition runs on the camera stream defined by the `detect` role in your config. To ensure optimal performance, select a suitable resolution for this stream in your camera's firmware that fits your specific scene and requirements.
## Advanced Configuration
Fine-tune the LPR feature using these optional parameters at the global level of your config. The only optional parameters that can be set at the camera level are `enabled`, `min_area`, and `enhancement`.
Fine-tune the LPR feature using these optional parameters. The only optional parameters that can be set at the camera level are `enabled`, `min_area`, and `enhancement`.
### Detection
- **`detection_threshold`**: License plate object detection confidence score required before recognition runs.
<ConfigTabs>
<TabItem value="ui">
Navigate to <NavPath path="Settings > Enrichments > License plate recognition" />.
- **Detection threshold**: License plate object detection confidence score required before recognition runs. This field only applies to the standalone license plate detection model; `threshold` and `min_score` object filters should be used for models like Frigate+ that have license plate detection built in.
- Default: `0.7`
- Note: This is field only applies to the standalone license plate detection model, `threshold` and `min_score` object filters should be used for models like Frigate+ that have license plate detection built in.
- **`min_area`**: Defines the minimum area (in pixels) a license plate must be before recognition runs.
- Default: `1000` pixels. Note: this is intentionally set very low as it is an _area_ measurement (length x width). For reference, 1000 pixels represents a ~32x32 pixel square in your camera image.
- Depending on the resolution of your camera's `detect` stream, you can increase this value to ignore small or distant plates.
- **`device`**: Device to use to run license plate detection _and_ recognition models.
- **Minimum plate area**: Minimum area (in pixels) a license plate must be before recognition runs. This is an _area_ measurement (length x width). For reference, 1000 pixels represents a ~32x32 pixel square in your camera image. Depending on the resolution of your camera's `detect` stream, you can increase this value to ignore small or distant plates.
- Default: `1000` pixels
- **Device**: Device to use to run license plate detection _and_ recognition models. Auto-selected by Frigate and can be `CPU`, `GPU`, or the GPU's device number. For users without a model that detects license plates natively, using a GPU may increase performance of the YOLOv9 license plate detector model. See the [Hardware Accelerated Enrichments](/configuration/hardware_acceleration_enrichments.md) documentation.
- Default: `None`
- This is auto-selected by Frigate and can be `CPU`, `GPU`, or the GPU's device number. For users without a model that detects license plates natively, using a GPU may increase performance of the YOLOv9 license plate detector model. See the [Hardware Accelerated Enrichments](/configuration/hardware_acceleration_enrichments.md) documentation. However, for users who run a model that detects `license_plate` natively, there is little to no performance gain reported with running LPR on GPU compared to the CPU.
- **`model_size`**: The size of the model used to identify regions of text on plates.
- **Model size**: The size of the model used to identify regions of text on plates. The `small` model is fast and identifies groups of Latin and Chinese characters. The `large` model identifies Latin characters only, and uses an enhanced text detector to find characters on multi-line plates. If your country or region does not use multi-line plates, you should use the `small` model.
- Default: `small`
- This can be `small` or `large`.
- The `small` model is fast and identifies groups of Latin and Chinese characters.
- The `large` model identifies Latin characters only, and uses an enhanced text detector to find characters on multi-line plates. It is significantly slower than the `small` model.
- If your country or region does not use multi-line plates, you should use the `small` model as performance is much better for single-line plates.
</TabItem>
<TabItem value="yaml">
```yaml
lpr:
enabled: True
detection_threshold: 0.7
min_area: 1000
device: CPU
model_size: small
```
</TabItem>
</ConfigTabs>
### Recognition
- **`recognition_threshold`**: Recognition confidence score required to add the plate to the object as a `recognized_license_plate` and/or `sub_label`.
- Default: `0.9`.
- **`min_plate_length`**: Specifies the minimum number of characters a detected license plate must have to be added as a `recognized_license_plate` and/or `sub_label` to an object.
- Use this to filter out short, incomplete, or incorrect detections.
- **`format`**: A regular expression defining the expected format of detected plates. Plates that do not match this format will be discarded.
- `"^[A-Z]{1,3} [A-Z]{1,2} [0-9]{1,4}$"` matches plates like "B AB 1234" or "M X 7"
- `"^[A-Z]{2}[0-9]{2} [A-Z]{3}$"` matches plates like "AB12 XYZ" or "XY68 ABC"
- Websites like https://regex101.com/ can help test regular expressions for your plates.
<ConfigTabs>
<TabItem value="ui">
Navigate to <NavPath path="Settings > Enrichments > License plate recognition" />.
- **Recognition threshold**: Recognition confidence score required to add the plate to the object as a `recognized_license_plate` and/or `sub_label`.
- Default: `0.9`
- **Min plate length**: Minimum number of characters a detected license plate must have to be added as a `recognized_license_plate` and/or `sub_label`. Use this to filter out short, incomplete, or incorrect detections.
- **Plate format regex**: A regular expression defining the expected format of detected plates. Plates that do not match this format will be discarded. Websites like https://regex101.com/ can help test regular expressions for your plates.
</TabItem>
<TabItem value="yaml">
```yaml
lpr:
enabled: True
recognition_threshold: 0.9
min_plate_length: 4
format: "^[A-Z]{2}[0-9]{2} [A-Z]{3}$"
```
</TabItem>
</ConfigTabs>
### Matching
- **`known_plates`**: List of strings or regular expressions that assign custom a `sub_label` to `car` and `motorcycle` objects when a recognized plate matches a known value.
- These labels appear in the UI, filters, and notifications.
- Unknown plates are still saved but are added to the `recognized_license_plate` field rather than the `sub_label`.
- **`match_distance`**: Allows for minor variations (missing/incorrect characters) when matching a detected plate to a known plate.
- For example, setting `match_distance: 1` allows a plate `ABCDE` to match `ABCBE` or `ABCD`.
- This parameter will _not_ operate on known plates that are defined as regular expressions. You should define the full string of your plate in `known_plates` in order to use `match_distance`.
<ConfigTabs>
<TabItem value="ui">
Navigate to <NavPath path="Settings > Enrichments > License plate recognition" />.
- **Known plates**: Assign custom `sub_label` values to `car` and `motorcycle` objects when a recognized plate matches a known value. These labels appear in the UI, filters, and notifications. Unknown plates are still saved but are added to the `recognized_license_plate` field rather than the `sub_label`.
- **Match distance**: Allows for minor variations (missing/incorrect characters) when matching a detected plate to a known plate. For example, setting to `1` allows a plate `ABCDE` to match `ABCBE` or `ABCD`. This parameter will _not_ operate on known plates that are defined as regular expressions.
</TabItem>
<TabItem value="yaml">
```yaml
lpr:
enabled: True
match_distance: 1
known_plates:
Wife's Car:
- "ABC-1234"
Johnny:
- "J*N-*234"
```
</TabItem>
</ConfigTabs>
### Image Enhancement
- **`enhancement`**: A value between 0 and 10 that adjusts the level of image enhancement applied to captured license plates before they are processed for recognition. This preprocessing step can sometimes improve accuracy but may also have the opposite effect.
<ConfigTabs>
<TabItem value="ui">
Navigate to <NavPath path="Settings > Enrichments > License plate recognition" />.
- **Enhancement level**: A value between 0 and 10 that adjusts the level of image enhancement applied to captured license plates before they are processed for recognition. Higher values increase contrast, sharpen details, and reduce noise, but excessive enhancement can blur or distort characters. This setting is best adjusted at the camera level if running LPR on multiple cameras.
- Default: `0` (no enhancement)
- Higher values increase contrast, sharpen details, and reduce noise, but excessive enhancement can blur or distort characters, actually making them much harder for Frigate to recognize.
- This setting is best adjusted at the camera level if running LPR on multiple cameras.
- If Frigate is already recognizing plates correctly, leave this setting at the default of `0`. However, if you're experiencing frequent character issues or incomplete plates and you can already easily read the plates yourself, try increasing the value gradually, starting at 5 and adjusting as needed. You should see how different enhancement levels affect your plates. Use the `debug_save_plates` configuration option (see below).
</TabItem>
<TabItem value="yaml">
```yaml
lpr:
enabled: True
enhancement: 1
```
</TabItem>
</ConfigTabs>
If Frigate is already recognizing plates correctly, leave enhancement at the default of `0`. However, if you're experiencing frequent character issues or incomplete plates and you can already easily read the plates yourself, try increasing the value gradually, starting at 3 and adjusting as needed. Use the `debug_save_plates` configuration option (see below) to see how different enhancement levels affect your plates.
### Normalization Rules
- **`replace_rules`**: List of regex replacement rules to normalize detected plates. These rules are applied sequentially and are applied _before_ the `format` regex, if specified. Each rule must have a `pattern` (which can be a string or a regex) and `replacement` (a string, which also supports [backrefs](https://docs.python.org/3/library/re.html#re.sub) like `\1`). These rules are useful for dealing with common OCR issues like noise characters, separators, or confusions (e.g., 'O'→'0').
<ConfigTabs>
<TabItem value="ui">
These rules must be defined at the global level of your `lpr` config.
Navigate to <NavPath path="Settings > Enrichments > License plate recognition" />.
Under **Replacement rules**, add regex rules to normalize detected plate strings before matching. Rules fire in order. For example:
| Pattern | Replacement | Description |
| ---------------- | ----------- | -------------------------------------------------- |
| `[%#*?]` | _(empty)_ | Remove noise symbols |
| `[= ]` | `-` | Normalize `=` or space to dash |
| `O` | `0` | Swap `O` to `0` (common OCR error) |
| `I` | `1` | Swap `I` to `1` |
| `(\w{3})(\w{3})` | `\1-\2` | Split 6 chars into groups (e.g., ABC123 → ABC-123) |
</TabItem>
<TabItem value="yaml">
```yaml
lpr:
@@ -126,6 +236,11 @@ lpr:
replacement: '\1-\2'
```
</TabItem>
</ConfigTabs>
These rules must be defined at the global level of your `lpr` config.
- Rules fire in order: In the example above: clean noise first, then separators, then swaps, then splits.
- Backrefs (`\1`, `\2`) allow dynamic replacements (e.g., capture groups).
- Any changes made by the rules are printed to the LPR debug log.
@@ -133,13 +248,50 @@ lpr:
### Debugging
- **`debug_save_plates`**: Set to `True` to save captured text on plates for debugging. These images are stored in `/media/frigate/clips/lpr`, organized into subdirectories by `<camera>/<event_id>`, and named based on the capture timestamp.
- These saved images are not full plates but rather the specific areas of text detected on the plates. It is normal for the text detection model to sometimes find multiple areas of text on the plate. Use them to analyze what text Frigate recognized and how image enhancement affects detection.
- **Note:** Frigate does **not** automatically delete these debug images. Once LPR is functioning correctly, you should disable this option and manually remove the saved files to free up storage.
<ConfigTabs>
<TabItem value="ui">
Navigate to <NavPath path="Settings > Enrichments > License plate recognition" />.
- **Save debug plates**: Set to on to save captured text on plates for debugging. These images are stored in `/media/frigate/clips/lpr`, organized into subdirectories by `<camera>/<event_id>`, and named based on the capture timestamp.
</TabItem>
<TabItem value="yaml">
```yaml
lpr:
enabled: True
debug_save_plates: True
```
</TabItem>
</ConfigTabs>
The saved images are not full plates but rather the specific areas of text detected on the plates. It is normal for the text detection model to sometimes find multiple areas of text on the plate. Use them to analyze what text Frigate recognized and how image enhancement affects detection.
**Note:** Frigate does **not** automatically delete these debug images. Once LPR is functioning correctly, you should disable this option and manually remove the saved files to free up storage.
## Configuration Examples
These configuration parameters are available at the global level of your config. The only optional parameters that should be set at the camera level are `enabled`, `min_area`, and `enhancement`.
These configuration parameters are available at the global level. The only optional parameters that should be set at the camera level are `enabled`, `min_area`, and `enhancement`.
<ConfigTabs>
<TabItem value="ui">
Navigate to <NavPath path="Settings > Enrichments > License plate recognition" />.
| Field | Description |
| ------------------------------ | ----------------------------------------------------------------------------------------------------- |
| **Enable LPR** | Set to on |
| **Minimum plate area** | Set to `1500` — ignore plates with an area (length x width) smaller than 1500 pixels |
| **Min plate length** | Set to `4` — only recognize plates with 4 or more characters |
| **Known plates > Wife's Car** | `ABC-1234`, `ABC-I234` (accounts for potential confusion between the number one and capital letter I) |
| **Known plates > Johnny** | `J*N-*234` (matches JHN-1234 and JMN-I234; `*` matches any number of characters) |
| **Known plates > Sally** | `[S5]LL 1234` (matches both SLL 1234 and 5LL 1234) |
| **Known plates > Work Trucks** | `EMP-[0-9]{3}[A-Z]` (matches plates like EMP-123A, EMP-456Z) |
</TabItem>
<TabItem value="yaml">
```yaml
lpr:
@@ -158,28 +310,21 @@ lpr:
- "EMP-[0-9]{3}[A-Z]" # Matches plates like EMP-123A, EMP-456Z
```
```yaml
lpr:
enabled: True
min_area: 4000 # Run recognition on larger plates only (4000 pixels represents a 63x63 pixel square in your image)
recognition_threshold: 0.85
format: "^[A-Z]{2} [A-Z][0-9]{4}$" # Only recognize plates that are two letters, followed by a space, followed by a single letter and 4 numbers
match_distance: 1 # Allow one character variation in plate matching
replace_rules:
- pattern: "O"
replacement: "0" # Replace the letter O with the number 0 in every plate
known_plates:
Delivery Van:
- "RJ K5678"
- "UP A1234"
Supervisor:
- "MN D3163"
```
</TabItem>
</ConfigTabs>
:::note
If a camera is configured to detect `car` or `motorcycle` but you don't want Frigate to run LPR for that camera, disable LPR at the camera level:
<ConfigTabs>
<TabItem value="ui">
Navigate to <NavPath path="Settings > Camera configuration > License plate recognition" /> for the desired camera and disable the **Enable LPR** toggle.
</TabItem>
<TabItem value="yaml">
```yaml
cameras:
side_yard:
@@ -188,13 +333,16 @@ cameras:
...
```
</TabItem>
</ConfigTabs>
:::
## Dedicated LPR Cameras
Dedicated LPR cameras are single-purpose cameras with powerful optical zoom to capture license plates on distant vehicles, often with fine-tuned settings to capture plates at night.
To mark a camera as a dedicated LPR camera, add `type: "lpr"` the camera configuration.
To mark a camera as a dedicated LPR camera, set `type: "lpr"` in the camera configuration.
:::note
@@ -210,6 +358,55 @@ Users running a Frigate+ model (or any model that natively detects `license_plat
An example configuration for a dedicated LPR camera using a `license_plate`-detecting model:
<ConfigTabs>
<TabItem value="ui">
Navigate to <NavPath path="Settings > Enrichments > License plate recognition" /> and set **Enable LPR** to on. Set **Device** to `CPU` (can also be `GPU` if available).
Navigate to <NavPath path="Settings > Camera configuration > FFmpeg" /> and add your camera streams.
Navigate to <NavPath path="Settings > Camera configuration > Object detection" />.
| Field | Description |
| --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------ |
| **Enable object detection** | Set to on |
| **Detect FPS** | Set to `5`. Increase to `10` if vehicles move quickly across your frame. Higher than 10 is unnecessary and is not recommended. |
| **Minimum initialization frames** | Set to `2` |
| **Detect width** | Set to `1920` |
| **Detect height** | Set to `1080` |
Navigate to <NavPath path="Settings > Camera configuration > Objects" />.
| Field | Description |
| ---------------------------------------------- | ------------------- |
| **Objects to track** | Add `license_plate` |
| **Object filters > License Plate > Threshold** | Set to `0.7` |
Navigate to <NavPath path="Settings > Camera configuration > Motion detection" />.
| Field | Description |
| -------------------- | --------------------------------------------------------------------- |
| **Motion threshold** | Set to `30` |
| **Contour area** | Set to `60`. Use an increased value to tune out small motion changes. |
| **Improve contrast** | Set to off |
Also add a motion mask over your camera's timestamp so it is not incorrectly detected as a license plate.
Navigate to <NavPath path="Settings > Camera configuration > Recording" />.
| Field | Description |
| -------------------- | -------------------------------------------------------- |
| **Enable recording** | Set to on. Disable recording if you only want snapshots. |
Navigate to <NavPath path="Settings > Camera configuration > Snapshots" />.
| Field | Description |
| -------------------- | ----------- |
| **Enable snapshots** | Set to on |
</TabItem>
<TabItem value="yaml">
```yaml
# LPR global configuration
lpr:
@@ -248,6 +445,9 @@ cameras:
- license_plate
```
</TabItem>
</ConfigTabs>
With this setup:
- License plates are treated as normal objects in Frigate.
@@ -259,10 +459,65 @@ With this setup:
### Using the Secondary LPR Pipeline (Without Frigate+)
If you are not running a Frigate+ model, you can use Frigates built-in secondary dedicated LPR pipeline. In this mode, Frigate bypasses the standard object detection pipeline and runs a local license plate detector model on the full frame whenever motion activity occurs.
If you are not running a Frigate+ model, you can use Frigate's built-in secondary dedicated LPR pipeline. In this mode, Frigate bypasses the standard object detection pipeline and runs a local license plate detector model on the full frame whenever motion activity occurs.
An example configuration for a dedicated LPR camera using the secondary pipeline:
<ConfigTabs>
<TabItem value="ui">
Navigate to <NavPath path="Settings > Enrichments > License plate recognition" /> and set **Enable LPR** to on. Set **Device** to `CPU` (can also be `GPU` if available and the correct Docker image is used). Set **Detection threshold** to `0.7` (change if necessary).
Navigate to <NavPath path="Settings > Camera configuration > License plate recognition" /> for your dedicated LPR camera.
| Field | Description |
| --------------------- | -------------------------------------------------------------------------------- |
| **Enable LPR** | Set to on |
| **Enhancement level** | Set to `3` (optional — enhances the image before trying to recognize characters) |
Navigate to <NavPath path="Settings > Camera configuration > FFmpeg" /> and add your camera streams.
Navigate to <NavPath path="Settings > Camera configuration > Object detection" />.
| Field | Description |
| --------------------------- | ---------------------------------------------------------------------------------------------------------------------------- |
| **Enable object detection** | Set to off — disables Frigate's standard object detection pipeline |
| **Detect FPS** | Set to `5`. Increase if necessary, though high values may slow down Frigate's enrichments pipeline and use considerable CPU. |
| **Detect width** | Set to `1920` (recommended value, but depends on your camera) |
| **Detect height** | Set to `1080` (recommended value, but depends on your camera) |
Navigate to <NavPath path="Settings > Camera configuration > Objects" />.
| Field | Description |
| -------------------- | -------------------------------------------------------------------------------------- |
| **Objects to track** | Set to an empty list — required when not using a Frigate+ model for dedicated LPR mode |
Navigate to <NavPath path="Settings > Camera configuration > Motion detection" />.
| Field | Description |
| -------------------- | --------------------------------------------------------------------- |
| **Motion threshold** | Set to `30` |
| **Contour area** | Set to `60`. Use an increased value to tune out small motion changes. |
| **Improve contrast** | Set to off |
Navigate to <NavPath path="Settings > Camera configuration > Masks / Zones" /> and add a motion mask over your camera's timestamp so it is not incorrectly detected as a license plate.
Navigate to <NavPath path="Settings > Camera configuration > Recording" />.
| Field | Description |
| -------------------- | -------------------------------------------------------- |
| **Enable recording** | Set to on. Disable recording if you only want snapshots. |
Navigate to <NavPath path="Settings > Camera configuration > Review" />.
| Field | Description |
| ----------------------------------------- | --------------- |
| **Detections config > Enable detections** | Set to on |
| **Detections config > Retain > Default** | Set to `7` days |
</TabItem>
<TabItem value="yaml">
```yaml
# LPR global configuration
lpr:
@@ -299,6 +554,9 @@ cameras:
default: 7
```
</TabItem>
</ConfigTabs>
With this setup:
- The standard object detection pipeline is bypassed. Any detected license plates on dedicated LPR cameras are treated similarly to manual events in Frigate. You must **not** specify `license_plate` as an object to track.
@@ -377,12 +635,27 @@ Start with ["Why isn't my license plate being detected and recognized?"](#why-is
1. Start with a simplified LPR config.
- Remove or comment out everything in your LPR config, including `min_area`, `min_plate_length`, `format`, `known_plates`, or `enhancement` values so that the only values left are `enabled` and `debug_save_plates`. This will run LPR with Frigate's default values.
```yaml
lpr:
enabled: true
device: CPU
debug_save_plates: true
```
<ConfigTabs>
<TabItem value="ui">
Navigate to <NavPath path="Settings > Enrichments > License plate recognition" />.
- Set **Enable LPR** to on
- Set **Device** to `CPU`
- Set **Save debug plates** to on
</TabItem>
<TabItem value="yaml">
```yaml
lpr:
enabled: true
device: CPU
debug_save_plates: true
```
</TabItem>
</ConfigTabs>
2. Enable debug logs to see exactly what Frigate is doing.
- Enable debug logs for LPR by adding `frigate.data_processing.common.license_plate: debug` to your `logger` configuration. These logs are _very_ verbose, so only keep this enabled when necessary. Restart Frigate after this change.
@@ -391,7 +664,7 @@ Start with ["Why isn't my license plate being detected and recognized?"](#why-is
logger:
default: info
logs:
# highlight-next-line
# highlight-next-line
frigate.data_processing.common.license_plate: debug
```
+60 -6
View File
@@ -3,6 +3,10 @@ id: live
title: Live View
---
import ConfigTabs from "@site/src/components/ConfigTabs";
import TabItem from "@theme/TabItem";
import NavPath from "@site/src/components/NavPath";
Frigate intelligently displays your camera streams on the Live view dashboard. By default, Frigate employs "smart streaming" where camera images update once per minute when no detectable activity is occurring to conserve bandwidth and resources. As soon as any motion or active objects are detected, cameras seamlessly switch to a live stream.
### Live View technologies
@@ -17,6 +21,12 @@ The jsmpeg live view will use more browser and client GPU resources. Using go2rt
| mse | native | native | yes (depends on audio codec) | yes | iPhone requires iOS 17.1+, Firefox is h.264 only. This is Frigate's default when go2rtc is configured. |
| webrtc | native | native | yes (depends on audio codec) | yes | Requires extra configuration. Frigate attempts to use WebRTC when MSE fails or when using a camera's two-way talk feature. |
:::info
WebRTC may use an external STUN server for NAT traversal. MSE and HLS streaming do not require any internet access. See [Network Requirements](/frigate/network_requirements#webrtc-stun) for details.
:::
### Camera Settings Recommendations
If you are using go2rtc, you should adjust the following settings in your camera's firmware for the best experience with Live view:
@@ -63,19 +73,26 @@ go2rtc:
### Setting Streams For Live UI
You can configure Frigate to allow manual selection of the stream you want to view in the Live UI. For example, you may want to view your camera's substream on mobile devices, but the full resolution stream on desktop devices. Setting the `live -> streams` list will populate a dropdown in the UI's Live view that allows you to choose between the streams. This stream setting is _per device_ and is saved in your browser's local storage.
You can configure Frigate to allow manual selection of the stream you want to view in the Live UI. For example, you may want to view your camera's substream on mobile devices, but the full resolution stream on desktop devices. Setting the streams list will populate a dropdown in the UI's Live view that allows you to choose between the streams. This stream setting is _per device_ and is saved in your browser's local storage.
Additionally, when creating and editing camera groups in the UI, you can choose the stream you want to use for your camera group's Live dashboard.
:::note
Frigate's default dashboard ("All Cameras") will always use the first entry you've defined in `streams:` when playing live streams from your cameras.
Frigate's default dashboard ("All Cameras") will always use the first entry you've defined in streams when playing live streams from your cameras.
:::
Configure the `streams` option with a "friendly name" for your stream followed by the go2rtc stream name.
Configure a "friendly name" for your stream followed by the go2rtc stream name. Using Frigate's internal version of go2rtc is required to use this feature. You cannot specify paths in the streams configuration, only go2rtc stream names.
Using Frigate's internal version of go2rtc is required to use this feature. You cannot specify paths in the `streams` configuration, only go2rtc stream names.
<ConfigTabs>
<TabItem value="ui">
1. Navigate to <NavPath path="Settings > Camera configuration > Live playback" />, then select your camera.
- Under **Live stream names**, add entries mapping a friendly name to each go2rtc stream name (e.g., `Main Stream` mapped to `test_cam`, `Sub Stream` mapped to `test_cam_sub`).
</TabItem>
<TabItem value="yaml">
```yaml {3,6,8,25-29}
go2rtc:
@@ -109,6 +126,9 @@ cameras:
Special Stream: test_cam_another_sub
```
</TabItem>
</ConfigTabs>
### WebRTC extra configuration:
WebRTC works by creating a TCP or UDP connection on port `8555`. However, it requires additional configuration:
@@ -185,7 +205,7 @@ To prevent go2rtc from blocking other applications from accessing your camera's
Frigate provides a dialog in the Camera Group Edit pane with several options for streaming on a camera group's dashboard. These settings are _per device_ and are saved in your device's local storage.
- Stream selection using the `live -> streams` configuration option (see _Setting Streams For Live UI_ above)
- Stream selection using the streams configuration option (see _Setting Streams For Live UI_ above)
- Streaming type:
- _No streaming_: Camera images will only update once per minute and no live streaming will occur.
- _Smart Streaming_ (default, recommended setting): Smart streaming will update your camera image once per minute when no detectable activity is occurring to conserve bandwidth and resources, since a static picture is the same as a streaming image with no motion or objects. When motion or objects are detected, the image seamlessly switches to a live stream.
@@ -203,6 +223,40 @@ Use a camera group if you want to change any of these settings from the defaults
:::
### jsmpeg Stream Quality
The jsmpeg live view resolution and encoding quality can be adjusted globally or per camera. These settings only affect the jsmpeg player and do not apply when go2rtc is used for live view.
<ConfigTabs>
<TabItem value="ui">
Navigate to <NavPath path="Settings > Global configuration > Live playback" /> for global defaults, or <NavPath path="Settings > Camera configuration > Live playback" /> and select a camera for per-camera overrides.
| Field | Description |
| ---------------- | --------------------------------------------------------------------------------------------------- |
| **Live height** | Height in pixels for the jsmpeg live stream; must be less than or equal to the detect stream height |
| **Live quality** | Encoding quality for the jsmpeg stream (1 = highest, 31 = lowest) |
</TabItem>
<TabItem value="yaml">
```yaml
# Global defaults
live:
height: 720
quality: 8
# Per-camera override
cameras:
front_door:
live:
height: 480
quality: 4
```
</TabItem>
</ConfigTabs>
### Disabling cameras
Cameras can be temporarily disabled through the Frigate UI and through [MQTT](/integrations/mqtt#frigatecamera_nameenabledset) to conserve system resources. When disabled, Frigate's ffmpeg processes are terminated — recording stops, object detection is paused, and the Live dashboard displays a blank image with a disabled message. Review items, tracked objects, and historical footage for disabled cameras can still be accessed via the UI.
@@ -276,7 +330,7 @@ When your browser runs into problems playing back your camera streams, it will l
4. Look for messages prefixed with the camera name.
These logs help identify if the issue is player-specific (MSE vs. WebRTC) or related to camera configuration (e.g., go2rtc streams, codecs). If you see frequent errors:
- Verify your camera's H.264/AAC settings (see [Frigate's camera settings recommendations](#camera_settings_recommendations)).
- Verify your camera's H.264/AAC settings (see [Frigate's camera settings recommendations](#camera-settings-recommendations)).
- Check go2rtc configuration for transcoding (e.g., audio to AAC/OPUS).
- Test with a different stream via the UI dropdown (if `live -> streams` is configured).
- For WebRTC-specific issues, ensure port 8555 is forwarded and candidates are set (see (WebRTC Extra Configuration)(#webrtc-extra-configuration)).
+15 -10
View File
@@ -3,6 +3,10 @@ id: masks
title: Masks
---
import ConfigTabs from "@site/src/components/ConfigTabs";
import TabItem from "@theme/TabItem";
import NavPath from "@site/src/components/NavPath";
## Motion masks
Motion masks are used to prevent unwanted types of motion from triggering detection. Try watching the Debug feed (Settings --> Debug) with `Motion Boxes` enabled to see what may be regularly detected as motion. For example, you want to mask out your timestamp, the sky, rooftops, etc. Keep in mind that this mask only prevents motion from being detected and does not prevent objects from being detected if object detection was started due to motion in unmasked areas. Motion is also used during object tracking to refine the object detection area in the next frame. _Over-masking will make it more difficult for objects to be tracked._
@@ -17,17 +21,15 @@ Object filter masks can be used to filter out stubborn false positives in fixed
![object mask](/img/bottom-center-mask.jpg)
## Using the mask creator
## Creating masks
To create a poly mask:
<ConfigTabs>
<TabItem value="ui">
1. Visit the Web UI
2. Click/tap the gear icon and open "Settings"
3. Select "Mask / zone editor"
4. At the top right, select the camera you wish to create a mask or zone for
5. Click the plus icon under the type of mask or zone you would like to create
6. Click on the camera's latest image to create the points for a masked area. Click the first point again to close the polygon.
7. When you've finished creating your mask, press Save.
Navigate to <NavPath path="Settings > Camera configuration > Masks / Zones" /> and select a camera. Use the mask editor to draw motion masks and object filter masks directly on the camera feed. Each mask can be given a friendly name and toggled on or off.
</TabItem>
<TabItem value="yaml">
Your config file will be updated with the relative coordinates of the mask/zone:
@@ -59,7 +61,7 @@ motion:
coordinates: "0.000,0.427,0.002,0.000,0.999,0.000,0.999,0.781,0.885,0.456"
```
Object filter masks can also be created through the UI or manually in the config. They are configured under the object filters section for each object type:
Object filter masks are configured under the object filters section for each object type:
```yaml
objects:
@@ -78,6 +80,9 @@ objects:
coordinates: "0.000,0.700,1.000,0.700,1.000,1.000,0.000,1.000"
```
</TabItem>
</ConfigTabs>
## Enabling/Disabling Masks
Both motion masks and object filter masks can be toggled on or off without removing them from the configuration. Disabled masks are completely ignored at runtime - they will not affect motion detection or object filtering. This is useful for temporarily disabling a mask during certain seasons or times of day without modifying the configuration.
+30 -3
View File
@@ -3,19 +3,42 @@ id: metrics
title: Metrics
---
import ConfigTabs from "@site/src/components/ConfigTabs";
import TabItem from "@theme/TabItem";
import NavPath from "@site/src/components/NavPath";
# Metrics
Frigate exposes Prometheus metrics at the `/api/metrics` endpoint that can be used to monitor the performance and health of your Frigate instance.
## Enabling Telemetry
Prometheus metrics are exposed via the telemetry configuration. Enable or configure telemetry to control metric availability.
<ConfigTabs>
<TabItem value="ui">
Navigate to <NavPath path="Settings > System > Telemetry" /> to configure metrics and telemetry settings.
</TabItem>
<TabItem value="yaml">
Metrics are available at `/api/metrics` by default. No additional Frigate configuration is required to expose them.
</TabItem>
</ConfigTabs>
## Available Metrics
### System Metrics
- `frigate_cpu_usage_percent{pid="", name="", process="", type="", cmdline=""}` - Process CPU usage percentage
- `frigate_mem_usage_percent{pid="", name="", process="", type="", cmdline=""}` - Process memory usage percentage
- `frigate_gpu_usage_percent{gpu_name=""}` - GPU utilization percentage
- `frigate_gpu_mem_usage_percent{gpu_name=""}` - GPU memory usage percentage
### Camera Metrics
- `frigate_camera_fps{camera_name=""}` - Frames per second being consumed from your camera
- `frigate_detection_fps{camera_name=""}` - Number of times detection is run per second
- `frigate_process_fps{camera_name=""}` - Frames per second being processed
@@ -25,21 +48,25 @@ Frigate exposes Prometheus metrics at the `/api/metrics` endpoint that can be us
- `frigate_audio_rms{camera_name=""}` - Audio RMS for camera
### Detector Metrics
- `frigate_detector_inference_speed_seconds{name=""}` - Time spent running object detection in seconds
- `frigate_detection_start{name=""}` - Detector start time (unix timestamp)
### Storage Metrics
- `frigate_storage_free_bytes{storage=""}` - Storage free bytes
- `frigate_storage_total_bytes{storage=""}` - Storage total bytes
- `frigate_storage_used_bytes{storage=""}` - Storage used bytes
- `frigate_storage_mount_type{mount_type="", storage=""}` - Storage mount type info
### Service Metrics
- `frigate_service_uptime_seconds` - Uptime in seconds
- `frigate_service_last_updated_timestamp` - Stats recorded time (unix timestamp)
- `frigate_device_temperature{device=""}` - Device Temperature
### Event Metrics
- `frigate_camera_events{camera="", label=""}` - Count of camera events since exporter started
## Configuring Prometheus
@@ -48,10 +75,10 @@ To scrape metrics from Frigate, add the following to your Prometheus configurati
```yaml
scrape_configs:
- job_name: 'frigate'
metrics_path: '/api/metrics'
- job_name: "frigate"
metrics_path: "/api/metrics"
static_configs:
- targets: ['frigate:5000']
- targets: ["frigate:5000"]
scrape_interval: 15s
```
+73 -1
View File
@@ -3,6 +3,10 @@ id: motion_detection
title: Motion Detection
---
import ConfigTabs from "@site/src/components/ConfigTabs";
import TabItem from "@theme/TabItem";
import NavPath from "@site/src/components/NavPath";
# Tuning Motion Detection
Frigate uses motion detection as a first line check to see if there is anything happening in the frame worth checking with object detection.
@@ -21,7 +25,7 @@ First, mask areas with regular motion not caused by the objects you want to dete
## Prepare For Testing
The easiest way to tune motion detection is to use the Frigate UI under Settings > Motion Tuner. This screen allows the changing of motion detection values live to easily see the immediate effect on what is detected as motion.
The recommended way to tune motion detection is to use the built-in Motion Tuner. Navigate to <NavPath path="Settings > Camera configuration > Motion tuner" /> and select the camera you want to tune. This screen lets you adjust motion detection values live and immediately see the effect on what is detected as motion, making it the fastest way to find optimal settings for each camera.
## Tuning Motion Detection During The Day
@@ -37,6 +41,20 @@ Remember that motion detection is just used to determine when object detection s
The threshold value dictates how much of a change in a pixels luminance is required to be considered motion.
<ConfigTabs>
<TabItem value="ui">
Navigate to <NavPath path="Settings > Global configuration > Motion detection" /> to set the threshold globally.
To override for a specific camera, navigate to <NavPath path="Settings > Camera configuration > Motion detection" /> and select the camera, or use the <NavPath path="Settings > Camera configuration > Motion tuner" /> to adjust it live.
| Field | Description |
| -------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Motion threshold** | The threshold passed to cv2.threshold to determine if a pixel is different enough to be counted as motion. Increasing this value will make motion detection less sensitive and decreasing it will make motion detection more sensitive. The value should be between 1 and 255. (default: 30) |
</TabItem>
<TabItem value="yaml">
```yaml
motion:
# Optional: The threshold passed to cv2.threshold to determine if a pixel is different enough to be counted as motion. (default: shown below)
@@ -45,12 +63,29 @@ motion:
threshold: 30
```
</TabItem>
</ConfigTabs>
Lower values mean motion detection is more sensitive to changes in color, making it more likely for example to detect motion when a brown dogs blends in with a brown fence or a person wearing a red shirt blends in with a red car. If the threshold is too low however, it may detect things like grass blowing in the wind, shadows, etc. to be detected as motion.
Watching the motion boxes in the debug view, increase the threshold until you only see motion that is visible to the eye. Once this is done, it is important to test and ensure that desired motion is still detected.
### Contour Area
<ConfigTabs>
<TabItem value="ui">
Navigate to <NavPath path="Settings > Global configuration > Motion detection" /> to set the contour area globally.
To override for a specific camera, navigate to <NavPath path="Settings > Camera configuration > Motion detection" /> and select the camera, or use the <NavPath path="Settings > Camera configuration > Motion tuner" /> to adjust it live.
| Field | Description |
| ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Contour area** | Minimum size in pixels in the resized motion image that counts as motion. Increasing this value will prevent smaller areas of motion from being detected. Decreasing will make motion detection more sensitive to smaller moving objects. As a rule of thumb: 10 = high sensitivity, 30 = medium sensitivity, 50 = low sensitivity. (default: 10) |
</TabItem>
<TabItem value="yaml">
```yaml
motion:
# Optional: Minimum size in pixels in the resized motion image that counts as motion (default: shown below)
@@ -63,6 +98,9 @@ motion:
contour_area: 10
```
</TabItem>
</ConfigTabs>
Once the threshold calculation is run, the pixels that have changed are grouped together. The contour area value is used to decide which groups of changed pixels qualify as motion. Smaller values are more sensitive meaning people that are far away, small animals, etc. are more likely to be detected as motion, but it also means that small changes in shadows, leaves, etc. are detected as motion. Higher values are less sensitive meaning these things won't be detected as motion but with the risk that desired motion won't be detected until closer to the camera.
Watching the motion boxes in the debug view, adjust the contour area until there are no motion boxes smaller than the smallest you'd expect frigate to detect something moving.
@@ -81,6 +119,20 @@ However, if the preferred day settings do not work well at night it is recommend
### Lightning Threshold
<ConfigTabs>
<TabItem value="ui">
Navigate to <NavPath path="Settings > Global configuration > Motion detection" /> and expand the advanced fields to find the lightning threshold setting.
To override for a specific camera, navigate to <NavPath path="Settings > Camera configuration > Motion detection" /> and select the camera.
| Field | Description |
| ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Lightning threshold** | The percentage of the image used to detect lightning or other substantial changes where motion detection needs to recalibrate. Increasing this value will make motion detection more likely to consider lightning or IR mode changes as valid motion. Decreasing this value will make motion detection more likely to ignore large amounts of motion such as a person approaching a doorbell camera. (default: 0.8) |
</TabItem>
<TabItem value="yaml">
```yaml
motion:
# Optional: The percentage of the image used to detect lightning or
@@ -94,6 +146,9 @@ motion:
lightning_threshold: 0.8
```
</TabItem>
</ConfigTabs>
Large changes in motion like PTZ moves and camera switches between Color and IR mode should result in a pause in object detection. `lightning_threshold` defines the percentage of the image used to detect these substantial changes. Increasing this value makes motion detection more likely to treat large changes (like IR mode switches) as valid motion. Decreasing it makes motion detection more likely to ignore large amounts of motion, such as a person approaching a doorbell camera.
Note that `lightning_threshold` does **not** stop motion-based recordings from being saved — it only prevents additional motion analysis after the threshold is exceeded, reducing false positive object detections during high-motion periods (e.g. storms or PTZ sweeps) without interfering with recordings.
@@ -106,6 +161,20 @@ Some cameras, like doorbell cameras, may have missed detections when someone wal
### Skip Motion On Large Scene Changes
<ConfigTabs>
<TabItem value="ui">
Navigate to <NavPath path="Settings > Global configuration > Motion detection" /> and expand the advanced fields to find the skip motion threshold setting.
To override for a specific camera, navigate to <NavPath path="Settings > Camera configuration > Motion detection" /> and select the camera.
| Field | Description |
| ------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Skip motion threshold** | Fraction of the frame that must change in a single update before Frigate will completely ignore any motion in that frame. Values range between 0.0 and 1.0; leave unset (null) to disable. For example, setting this to 0.7 causes Frigate to skip reporting motion boxes when more than 70% of the image appears to change (e.g. during lightning storms, IR/color mode switches, or other sudden lighting events). |
</TabItem>
<TabItem value="yaml">
```yaml
motion:
# Optional: Fraction of the frame that must change in a single update
@@ -118,6 +187,9 @@ motion:
skip_motion_threshold: 0.7
```
</TabItem>
</ConfigTabs>
This option is handy when you want to prevent large transient changes from triggering recordings or object detection. It differs from `lightning_threshold` because it completely suppresses motion instead of just forcing a recalibration.
:::warning
+42 -2
View File
@@ -3,10 +3,20 @@ id: notifications
title: Notifications
---
import ConfigTabs from "@site/src/components/ConfigTabs";
import TabItem from "@theme/TabItem";
import NavPath from "@site/src/components/NavPath";
# Notifications
Frigate offers native notifications using the [WebPush Protocol](https://web.dev/articles/push-notifications-web-push-protocol) which uses the [VAPID spec](https://tools.ietf.org/html/draft-thomson-webpush-vapid) to deliver notifications to web apps using encryption.
:::info
Push notifications require internet access from the Frigate server to the browser vendor's push service (e.g., Google FCM, Mozilla autopush). See [Network Requirements](/frigate/network_requirements#push-notifications) for details.
:::
## Setting up Notifications
In order to use notifications the following requirements must be met:
@@ -18,15 +28,27 @@ In order to use notifications the following requirements must be met:
### Configuration
To configure notifications, go to the Frigate WebUI -> Settings -> Notifications and enable, then fill out the fields and save.
Enable notifications and fill out the required fields.
Optionally, you can change the default cooldown period for notifications through the `cooldown` parameter in your config file. This parameter can also be overridden at the camera level.
Optionally, change the default cooldown period for notifications. The cooldown can also be overridden at the camera level.
Notifications will be prevented if either:
- The global cooldown period hasn't elapsed since any camera's last notification
- The camera-specific cooldown period hasn't elapsed for the specific camera
#### Global notifications
<ConfigTabs>
<TabItem value="ui">
1. Navigate to <NavPath path="Settings > Notifications > Notifications" />.
- Set **Email** to your email address
- Enable notifications for the desired cameras
</TabItem>
<TabItem value="yaml">
```yaml
notifications:
enabled: True
@@ -34,6 +56,21 @@ notifications:
cooldown: 10 # wait 10 seconds before sending another notification from any camera
```
</TabItem>
</ConfigTabs>
#### Per-camera notifications
<ConfigTabs>
<TabItem value="ui">
1. Navigate to <NavPath path="Settings > Camera configuration > Notifications" /> and select the desired camera.
- Set **Enable notifications** to on
- Set **Cooldown period** to the desired number of seconds to wait before sending another notification from this camera (e.g. `30`)
</TabItem>
<TabItem value="yaml">
```yaml
cameras:
doorbell:
@@ -43,6 +80,9 @@ cameras:
cooldown: 30 # wait 30 seconds before sending another notification from the doorbell camera
```
</TabItem>
</ConfigTabs>
### Registration
Once notifications are enabled, press the `Register for Notifications` button on all devices that you would like to receive notifications on. This will register the background worker. After this Frigate must be restarted and then notifications will begin to be sent.
File diff suppressed because it is too large Load Diff
+96 -2
View File
@@ -3,11 +3,15 @@ id: object_filters
title: Filters
---
import ConfigTabs from "@site/src/components/ConfigTabs";
import TabItem from "@theme/TabItem";
import NavPath from "@site/src/components/NavPath";
There are several types of object filters that can be used to reduce false positive rates.
## Object Scores
For object filters in your configuration, any single detection below `min_score` will be ignored as a false positive. `threshold` is based on the median of the history of scores (padded to 3 values) for a tracked object. Consider the following frames when `min_score` is set to 0.6 and threshold is set to 0.85:
For object filters, any single detection below `min_score` will be ignored as a false positive. `threshold` is based on the median of the history of scores (padded to 3 values) for a tracked object. Consider the following frames when `min_score` is set to 0.6 and threshold is set to 0.85:
| Frame | Current Score | Score History | Computed Score | Detected Object |
| ----- | ------------- | --------------------------------- | -------------- | --------------- |
@@ -20,6 +24,12 @@ For object filters in your configuration, any single detection below `min_score`
In frame 2, the score is below the `min_score` value, so Frigate ignores it and it becomes a 0.0. The computed score is the median of the score history (padding to at least 3 values), and only when that computed score crosses the `threshold` is the object marked as a true positive. That happens in frame 4 in the example.
The **top score** is the highest computed score the tracked object has ever reached during its lifetime. Because the computed score rises and falls as new frames come in, the top score can be thought of as the peak confidence Frigate had in the object. In Frigate's UI (such as the Tracking Details pane in Explore), you may see all three values:
- **Score** — the raw detector score for that single frame.
- **Computed Score** — the median of the most recent score history at that moment. This is the value compared against `threshold`.
- **Top Score** — the highest computed score reached so far for the tracked object.
### Minimum Score
Any detection below `min_score` will be immediately thrown out and never tracked because it is considered a false positive. If `min_score` is too low then false positives may be detected and tracked which can confuse the object tracker and may lead to wasted resources. If `min_score` is too high then lower scoring true positives like objects that are further away or partially occluded may be thrown out which can also confuse the tracker and cause valid tracked objects to be lost or disjointed.
@@ -28,6 +38,46 @@ Any detection below `min_score` will be immediately thrown out and never tracked
`threshold` is used to determine that the object is a true positive. Once an object is detected with a score >= `threshold` object is considered a true positive. If `threshold` is too low then some higher scoring false positives may create an tracked object. If `threshold` is too high then true positive tracked objects may be missed due to the object never scoring high enough.
## Configuring Object Scores
<ConfigTabs>
<TabItem value="ui">
Navigate to <NavPath path="Settings > Global configuration > Objects" /> to set score filters globally.
| Field | Description |
| --------------------------------------- | ---------------------------------------------------------------- |
| **Object filters > Person > Min Score** | Minimum score for a single detection to initiate tracking |
| **Object filters > Person > Threshold** | Minimum computed (median) score to be considered a true positive |
To override score filters for a specific camera, navigate to <NavPath path="Settings > Camera configuration > Objects" /> and select the camera.
</TabItem>
<TabItem value="yaml">
```yaml
objects:
filters:
person:
min_score: 0.5
threshold: 0.7
```
To override at the camera level:
```yaml
cameras:
front_door:
objects:
filters:
person:
min_score: 0.5
threshold: 0.7
```
</TabItem>
</ConfigTabs>
## Object Shape
False positives can also be reduced by filtering a detection based on its shape.
@@ -46,6 +96,50 @@ Conceptually, a ratio of 1 is a square, 0.5 is a "tall skinny" box, and 2 is a "
:::
### Configuring Shape Filters
<ConfigTabs>
<TabItem value="ui">
Navigate to <NavPath path="Settings > Global configuration > Objects" /> to set shape filters globally.
| Field | Description |
| --------------------------------------- | ------------------------------------------------------------------------ |
| **Object filters > Person > Min Area** | Minimum bounding box area in pixels (or decimal for percentage of frame) |
| **Object filters > Person > Max Area** | Maximum bounding box area in pixels (or decimal for percentage of frame) |
| **Object filters > Person > Min Ratio** | Minimum width/height ratio of the bounding box |
| **Object filters > Person > Max Ratio** | Maximum width/height ratio of the bounding box |
To override shape filters for a specific camera, navigate to <NavPath path="Settings > Camera configuration > Objects" /> and select the camera.
</TabItem>
<TabItem value="yaml">
```yaml
objects:
filters:
person:
min_area: 5000
max_area: 100000
min_ratio: 0.5
max_ratio: 2.0
```
To override at the camera level:
```yaml
cameras:
front_door:
objects:
filters:
person:
min_area: 5000
max_area: 100000
```
</TabItem>
</ConfigTabs>
## Other Tools
### Zones
@@ -54,4 +148,4 @@ Conceptually, a ratio of 1 is a square, 0.5 is a "tall skinny" box, and 2 is a "
### Object Masks
[Object Filter Masks](/configuration/masks) are a last resort but can be useful when false positives are in the relatively same place but can not be filtered due to their size or shape.
[Object Filter Masks](/configuration/masks) are a last resort but can be useful when false positives are in the relatively same place but can not be filtered due to their size or shape. Object filter masks can be configured in <NavPath path="Settings > Camera configuration > Masks / Zones" />.
+133 -1
View File
@@ -3,6 +3,9 @@ id: objects
title: Available Objects
---
import ConfigTabs from "@site/src/components/ConfigTabs";
import TabItem from "@theme/TabItem";
import NavPath from "@site/src/components/NavPath";
import labels from "../../../labelmap.txt";
Frigate includes the object labels listed below from the Google Coral test data.
@@ -10,7 +13,7 @@ Frigate includes the object labels listed below from the Google Coral test data.
Please note:
- `car` is listed twice because `truck` has been renamed to `car` by default. These object types are frequently confused.
- `person` is the only tracked object by default. See the [full configuration reference](reference.md) for an example of expanding the list of tracked objects.
- `person` is the only tracked object by default. To track additional objects, configure them in the objects settings.
<ul>
{labels.split("\n").map((label) => (
@@ -18,6 +21,135 @@ Please note:
))}
</ul>
## Configuring Tracked Objects
By default, Frigate only tracks `person`. To track additional object types, add them to the tracked objects list.
<ConfigTabs>
<TabItem value="ui">
1. Navigate to <NavPath path="Settings > Global configuration > Objects" />.
- Add the desired object types to the **Objects to track** list (e.g., `person`, `car`, `dog`)
To override the tracked objects list for a specific camera:
1. Navigate to <NavPath path="Settings > Camera configuration > Objects" />.
- Add the desired object types to the **Objects to track** list
</TabItem>
<TabItem value="yaml">
```yaml
objects:
track:
- person
- car
- dog
```
To override at the camera level:
```yaml
cameras:
front_door:
objects:
track:
- person
- car
```
</TabItem>
</ConfigTabs>
## Filtering Objects
Object filters help reduce false positives by constraining the size, shape, and confidence thresholds for each object type. Filters can be configured globally or per camera.
<ConfigTabs>
<TabItem value="ui">
Navigate to <NavPath path="Settings > Global configuration > Objects" />.
| Field | Description |
| --------------------------------------- | ------------------------------------------------------------------------ |
| **Object filters > Person > Min Area** | Minimum bounding box area in pixels (or decimal for percentage of frame) |
| **Object filters > Person > Max Area** | Maximum bounding box area in pixels (or decimal for percentage of frame) |
| **Object filters > Person > Min Ratio** | Minimum width/height ratio of the bounding box |
| **Object filters > Person > Max Ratio** | Maximum width/height ratio of the bounding box |
| **Object filters > Person > Min Score** | Minimum score for the object to initiate tracking |
| **Object filters > Person > Threshold** | Minimum computed score to be considered a true positive |
To override filters for a specific camera, navigate to <NavPath path="Settings > Camera configuration > Objects" />.
</TabItem>
<TabItem value="yaml">
```yaml
objects:
filters:
person:
min_area: 5000
max_area: 100000
min_ratio: 0.5
max_ratio: 2.0
min_score: 0.5
threshold: 0.7
```
To override at the camera level:
```yaml
cameras:
front_door:
objects:
filters:
person:
min_area: 5000
threshold: 0.7
```
</TabItem>
</ConfigTabs>
## Object Filter Masks
Object filter masks prevent specific object types from being detected in certain areas of the camera frame. These masks check the bottom center of the bounding box. A global mask applies to all object types, while per-object masks apply only to the specified type.
<ConfigTabs>
<TabItem value="ui">
Navigate to <NavPath path="Settings > Camera configuration > Masks / Zones" /> and select a camera. Use the mask editor to draw object filter masks directly on the camera feed. Global object masks and per-object masks can both be configured from this view.
</TabItem>
<TabItem value="yaml">
```yaml
objects:
# Global mask applied to all object types
mask:
mask1:
friendly_name: "Object filter mask area"
enabled: true
coordinates: "0.000,0.000,0.781,0.000,0.781,0.278,0.000,0.278"
# Per-object mask
filters:
person:
mask:
mask1:
friendly_name: "Person filter mask"
enabled: true
coordinates: "0.000,0.000,0.781,0.000,0.781,0.278,0.000,0.278"
```
</TabItem>
</ConfigTabs>
:::note
The global mask is combined with any object-specific mask. Both are checked based on the bottom center of the bounding box.
:::
## Custom Models
Models for both CPU and EdgeTPU (Coral) are bundled in the image. You can use your own models with volume mounts:
+33 -12
View File
@@ -3,6 +3,10 @@ id: profiles
title: Profiles
---
import ConfigTabs from "@site/src/components/ConfigTabs";
import TabItem from "@theme/TabItem";
import NavPath from "@site/src/components/NavPath";
Profiles allow you to define named sets of camera configuration overrides that can be activated and deactivated at runtime without restarting Frigate. This is useful for scenarios like switching between "Home" and "Away" modes, daytime and nighttime configurations, or any situation where you want to quickly change how multiple cameras behave.
## How Profiles Work
@@ -16,7 +20,7 @@ When a profile is activated, Frigate merges each camera's profile overrides on t
:::info
Profile changes are applied in-memory and take effect immediately — no restart is required. The active profile is persisted across Frigate restarts (stored in the `/config/.active_profile` file).
Profile changes are applied in-memory and take effect immediately — no restart is required. The active profile is persisted across Frigate restarts (stored in the `/config/.profiles` file).
:::
@@ -24,16 +28,18 @@ Profile changes are applied in-memory and take effect immediately — no restart
The easiest way to define profiles is to use the Frigate UI. Profiles can also be configured manually in your configuration file.
### Using the UI
### Creating and Managing Profiles
To create and manage profiles from the UI, open **Settings**. From there you can:
<ConfigTabs>
<TabItem value="ui">
1. **Create a profile** — Navigate to **Profiles**. Click the **Add Profile** button, enter a name (and optionally a profile ID).
2. **Configure overrides** — Navigate to a camera configuration section (e.g. Motion detection, Record, Notifications). In the top right, two buttons will appear - choose a camera and a profile from the profile selector to edit overrides for that camera and section. Only the fields you change will be stored as overrides — fields that require a restart are hidden since profiles are applied at runtime. You can click the **Remove Profile Override** button
3. **Activate a profile** — Use the **Profiles** option in Frigate's main menu to choose a profile. Alternatively, in Settings, navigate to **Profiles**, then choose a profile in the Active Profile dropdown to activate it. The active profile is also shown in the status bar at the bottom of the screen on desktop browsers.
4. **Delete a profile** — Navigate to **Profiles**, then click the trash icon for a profile. This removes the profile definition and all camera overrides associated with it.
1. **Create a profile** — Navigate to <NavPath path="Settings > Camera configuration > Profiles" />. Click the **Add Profile** button, enter a name (and optionally a profile ID).
2. **Configure overrides** — Navigate to a camera configuration section (e.g. Motion detection, Record, Notifications). In the top right, two buttons will appear - choose a camera and a profile from the profile selector to edit overrides for that camera and section. Only the fields you change will be stored as overrides — fields that require a restart are hidden since profiles are applied at runtime. You can click the **Remove Profile Override** button to clear overrides.
3. **Activate a profile** — Use the **Profiles** option in Frigate's main menu to choose a profile. Alternatively, in Settings, navigate to <NavPath path="Settings > Camera configuration > Profiles" />, then choose a profile in the Active Profile dropdown to activate it. The active profile is also shown in the status bar at the bottom of the screen on desktop browsers.
4. **Delete a profile** — Navigate to <NavPath path="Settings > Camera configuration > Profiles" />, then click the trash icon for a profile. This removes the profile definition and all camera overrides associated with it.
### Defining Profiles in YAML
</TabItem>
<TabItem value="yaml">
First, define your profiles at the top level of your Frigate config. Every profile name referenced by a camera must be defined here.
@@ -47,8 +53,6 @@ profiles:
friendly_name: Night Mode
```
### Camera Profile Overrides
Under each camera, add a `profiles` section with overrides for each profile. You only need to include the settings you want to change.
```yaml
@@ -91,6 +95,9 @@ cameras:
- person
```
</TabItem>
</ConfigTabs>
### Supported Override Sections
The following camera configuration sections can be overridden in a profile:
@@ -113,7 +120,7 @@ The following camera configuration sections can be overridden in a profile:
:::note
Only the fields you explicitly set in a profile override are applied. All other fields retain their base configuration values. For zones, profile zones are merged with the camera's base zones — any zone defined in the profile will override or add to the base zones.
Only the fields you explicitly set in a profile override are applied. All other fields retain their base configuration values. For masks and zones, profile zones **override** the camera's base masks and zones. If configuring profiles via YAML, you should not define masks or zones in profiles that are not defined in the base config.
:::
@@ -123,7 +130,18 @@ Profiles can be activated and deactivated from the Frigate UI. Open the Settings
## Example: Home / Away Setup
A common use case is having different detection and notification settings based on whether you are home or away.
A common use case is having different detection and notification settings based on whether you are home or away. This example below is for a system with two cameras, `front_door` and `indoor_cam`.
<ConfigTabs>
<TabItem value="ui">
1. Navigate to <NavPath path="Settings > Camera configuration > Profiles" /> and create two profiles: **Home** and **Away**.
2. From to the Camera configuration section in Settings, choose the **front_door** camera, and select the **Away** profile from the profile dropdown. Then, enable notifications from the Notifications pane, and set alert labels to `person` and `car` from the Review pane. Then, from the profile dropdown choose **Home** profile, then navigate to Notifications to disable notifications.
3. For the **indoor_cam** camera, perform similar steps - configure the **Away** profile to enable the camera, detection, and recording. Configure the **Home** profile to disable the camera entirely for privacy.
4. Activate the desired profile from <NavPath path="Settings > Camera configuration > Profiles" /> or from the **Profiles** option in Frigate's main menu.
</TabItem>
<TabItem value="yaml">
```yaml
profiles:
@@ -181,6 +199,9 @@ cameras:
enabled: false
```
</TabItem>
</ConfigTabs>
In this example:
- **Away profile**: The front door camera enables notifications and tracks specific alert labels. The indoor camera is fully enabled with detection and recording.
+204 -24
View File
@@ -3,7 +3,11 @@ id: record
title: Recording
---
Recordings can be enabled and are stored at `/media/frigate/recordings`. The folder structure for the recordings is `YYYY-MM-DD/HH/<camera_name>/MM.SS.mp4` in **UTC time**. These recordings are written directly from your camera stream without re-encoding. Each camera supports a configurable retention policy in the config. Frigate chooses the largest matching retention value between the recording retention and the tracked object retention when determining if a recording should be removed.
import ConfigTabs from "@site/src/components/ConfigTabs";
import TabItem from "@theme/TabItem";
import NavPath from "@site/src/components/NavPath";
Recordings can be enabled and are stored at `/media/frigate/recordings`. The folder structure for the recordings is `YYYY-MM-DD/HH/<camera_name>/MM.SS.mp4` in **UTC time**. These recordings are written directly from your camera stream without re-encoding. Each camera supports a configurable retention policy. Frigate chooses the largest matching retention value between the recording retention and the tracked object retention when determining if a recording should be removed.
New recording segments are written from the camera stream to cache, they are only moved to disk if they match the setup recording retention policy.
@@ -13,7 +17,23 @@ H265 recordings can be viewed in Chrome 108+, Edge and Safari only. All other br
### Most conservative: Ensure all video is saved
For users deploying Frigate in environments where it is important to have contiguous video stored even if there was no detectable motion, the following config will store all video for 3 days. After 3 days, only video containing motion will be saved for 7 days. After 7 days, only video containing motion and overlapping with alerts or detections will be retained until 30 days have passed.
For users deploying Frigate in environments where it is important to have contiguous video stored even if there was no detectable motion, the following configuration will store all video for 3 days. After 3 days, only video containing motion will be saved for 7 days. After 7 days, only video containing motion and overlapping with alerts or detections will be retained until 30 days have passed.
<ConfigTabs>
<TabItem value="ui">
Navigate to <NavPath path="Settings > Global configuration > Recording" />.
- Set **Enable recording** to on
- Set **Continuous retention > Retention days** to `3`
- Set **Motion retention > Retention days** to `7`
- Set **Alert retention > Event retention > Retention days** to `30`
- Set **Alert retention > Event retention > Retention mode** to `all`
- Set **Detection retention > Event retention > Retention days** to `30`
- Set **Detection retention > Event retention > Retention mode** to `all`
</TabItem>
<TabItem value="yaml">
```yaml
record:
@@ -32,9 +52,27 @@ record:
mode: all
```
</TabItem>
</ConfigTabs>
### Reduced storage: Only saving video when motion is detected
In order to reduce storage requirements, you can adjust your config to only retain video where motion / activity was detected.
To reduce storage requirements, configure recording to only retain video where motion or activity was detected.
<ConfigTabs>
<TabItem value="ui">
Navigate to <NavPath path="Settings > Global configuration > Recording" />.
- Set **Enable recording** to on
- Set **Motion retention > Retention days** to `3`
- Set **Alert retention > Event retention > Retention days** to `30`
- Set **Alert retention > Event retention > Retention mode** to `motion`
- Set **Detection retention > Event retention > Retention days** to `30`
- Set **Detection retention > Event retention > Retention mode** to `motion`
</TabItem>
<TabItem value="yaml">
```yaml
record:
@@ -51,9 +89,25 @@ record:
mode: motion
```
</TabItem>
</ConfigTabs>
### Minimum: Alerts only
If you only want to retain video that occurs during activity caused by tracked object(s), this config will discard video unless an alert is ongoing.
If you only want to retain video that occurs during activity caused by tracked object(s), this configuration will discard video unless an alert is ongoing.
<ConfigTabs>
<TabItem value="ui">
Navigate to <NavPath path="Settings > Global configuration > Recording" />.
- Set **Enable recording** to on
- Set **Continuous retention > Retention days** to `0`
- Set **Alert retention > Event retention > Retention days** to `30`
- Set **Alert retention > Event retention > Retention mode** to `motion`
</TabItem>
<TabItem value="yaml">
```yaml
record:
@@ -66,6 +120,79 @@ record:
mode: motion
```
</TabItem>
</ConfigTabs>
## Pre-capture and Post-capture
The `pre_capture` and `post_capture` settings control how many seconds of video are included before and after an alert or detection. These can be configured independently for alerts and detections, and can be set globally or overridden per camera.
<ConfigTabs>
<TabItem value="ui">
Navigate to <NavPath path="Settings > Global configuration > Recording" /> for global defaults, or <NavPath path="Settings > Camera configuration > (select camera) > Recording" /> to override for a specific camera.
| Field | Description |
| ---------------------------------------------- | ---------------------------------------------------- |
| **Alert retention > Pre-capture seconds** | Seconds of video to include before an alert event |
| **Alert retention > Post-capture seconds** | Seconds of video to include after an alert event |
| **Detection retention > Pre-capture seconds** | Seconds of video to include before a detection event |
| **Detection retention > Post-capture seconds** | Seconds of video to include after a detection event |
</TabItem>
<TabItem value="yaml">
```yaml
record:
enabled: True
alerts:
pre_capture: 5 # seconds before the alert to include
post_capture: 5 # seconds after the alert to include
detections:
pre_capture: 5 # seconds before the detection to include
post_capture: 5 # seconds after the detection to include
```
</TabItem>
</ConfigTabs>
- **Default**: 5 seconds for both pre and post capture.
- **Pre-capture maximum**: 60 seconds.
- These settings apply per review category (alerts and detections), not per object type.
### How pre/post capture interacts with retention mode
The `pre_capture` and `post_capture` values define the **time window** around a review item, but only recording segments that also match the configured **retention mode** are actually kept on disk.
- **`mode: all`** — Retains every segment within the capture window, regardless of whether motion was detected.
- **`mode: motion`** (default) — Only retains segments within the capture window that contain motion. This includes segments with active tracked objects, since object motion implies motion. Segments without any motion are discarded even if they fall within the pre/post capture range.
- **`mode: active_objects`** — Only retains segments within the capture window where tracked objects were actively moving. Segments with general motion but no active objects are discarded.
This means that with the default `motion` mode, you may see less footage than the configured pre/post capture duration if parts of the capture window had no motion.
To guarantee the full pre/post capture duration is always retained:
```yaml
record:
enabled: True
alerts:
pre_capture: 10
post_capture: 10
retain:
days: 30
mode: all # retains all segments within the capture window
```
:::note
Because recording segments are written in 10 second chunks, pre-capture timing depends on segment boundaries. The actual pre-capture footage may be slightly shorter or longer than the exact configured value.
:::
### Where to view pre/post capture footage
Pre and post capture footage is included in the **recording timeline**, visible in the History view. Note that pre/post capture settings only affect which recording segments are **retained on disk** — they do not change the start and end points shown in the UI. The History view will still center on the review item's actual time range, but you can scrub backward and forward through the retained pre/post capture footage on the timeline. The Explore view shows object-specific clips that are trimmed to when the tracked object was actually visible, so pre/post capture time will not be reflected there.
## Will Frigate delete old recordings if my storage runs out?
As of Frigate 0.12 if there is less than an hour left of storage, the oldest 2 hours of recordings will be deleted.
@@ -82,7 +209,21 @@ Retention configs support decimals meaning they can be configured to retain `0.5
### Continuous and Motion Recording
The number of days to retain continuous and motion recordings can be set via the following config where X is a number, by default continuous recording is disabled.
The number of days to retain continuous and motion recordings can be configured. By default, continuous recording is disabled.
<ConfigTabs>
<TabItem value="ui">
Navigate to <NavPath path="Settings > Global configuration > Recording" />.
| Field | Description |
| ----------------------------------------- | -------------------------------------------- |
| **Enable recording** | Enable or disable recording for all cameras |
| **Continuous retention > Retention days** | Number of days to keep continuous recordings |
| **Motion retention > Retention days** | Number of days to keep motion recordings |
</TabItem>
<TabItem value="yaml">
```yaml
record:
@@ -93,11 +234,28 @@ record:
days: 2 # <- number of days to keep motion recordings
```
Continuous recording supports different retention modes [which are described below](#what-do-the-different-retain-modes-mean)
</TabItem>
</ConfigTabs>
Continuous recording supports different retention modes [which are described below](#configuring-recording-retention).
### Object Recording
The number of days to record review items can be specified for review items classified as alerts as well as tracked objects.
The number of days to retain recordings for review items can be specified for items classified as alerts as well as tracked objects.
<ConfigTabs>
<TabItem value="ui">
Navigate to <NavPath path="Settings > Global configuration > Recording" />.
| Field | Description |
| ---------------------------------------------------------- | ------------------------------------------- |
| **Enable recording** | Enable or disable recording for all cameras |
| **Alert retention > Event retention > Retention days** | Number of days to keep alert recordings |
| **Detection retention > Event retention > Retention days** | Number of days to keep detection recordings |
</TabItem>
<TabItem value="yaml">
```yaml
record:
@@ -110,9 +268,10 @@ record:
days: 10 # <- number of days to keep detections recordings
```
This configuration will retain recording segments that overlap with alerts and detections for 10 days. Because multiple tracked objects can reference the same recording segments, this avoids storing duplicate footage for overlapping tracked objects and reduces overall storage needs.
</TabItem>
</ConfigTabs>
**WARNING**: Recordings still must be enabled in the config. If a camera has recordings disabled in the config, enabling via the methods listed above will have no effect.
This configuration will retain recording segments that overlap with alerts and detections for 10 days. Because multiple tracked objects can reference the same recording segments, this avoids storing duplicate footage for overlapping tracked objects and reduces overall storage needs.
## Can I have "continuous" recordings, but only at certain times?
@@ -122,31 +281,52 @@ Using Frigate UI, Home Assistant, or MQTT, cameras can be automated to only reco
Footage can be exported from Frigate by right-clicking (desktop) or long pressing (mobile) on a review item in the Review pane or by clicking the Export button in the History view. Exported footage is then organized and searchable through the Export view, accessible from the main navigation bar.
### Time-lapse export
### Custom export with FFmpeg arguments
Time lapse exporting is available only via the [HTTP API](../integrations/api/export-recording-export-camera-name-start-start-time-end-end-time-post.api.mdx).
For advanced use cases, the [custom export HTTP API](../integrations/api/export-recording-custom-export-custom-camera-name-start-start-time-end-end-time-post.api.mdx) lets you pass custom FFmpeg arguments when exporting a recording:
When exporting a time-lapse the default speed-up is 25x with 30 FPS. This means that every 25 seconds of (real-time) recording is condensed into 1 second of time-lapse video (always without audio) with a smoothness of 30 FPS.
To configure the speed-up factor, the frame rate and further custom settings, the configuration parameter `timelapse_args` can be used. The below configuration example would change the time-lapse speed to 60x (for fitting 1 hour of recording into 1 minute of time-lapse) with 25 FPS:
```yaml {3-4}
record:
enabled: True
export:
timelapse_args: "-vf setpts=PTS/60 -r 25"
```
POST /export/custom/{camera_name}/start/{start_time}/end/{end_time}
```
:::tip
The request body accepts `ffmpeg_input_args` and `ffmpeg_output_args` to control encoding, frame rate, filters, and other FFmpeg options. If neither is provided, Frigate defaults to time-lapse output settings (25x speed, 30 FPS).
When using `hwaccel_args`, hardware encoding is used for timelapse generation. This setting can be overridden for a specific camera (e.g., when camera resolution exceeds hardware encoder limits); set `cameras.<camera>.record.export.hwaccel_args` with the appropriate settings. Using an unrecognized value or empty string will fall back to software encoding (libx264).
The following example exports a time-lapse at 60x speed with 25 FPS:
```json
{
"name": "Front Door Time-lapse",
"ffmpeg_output_args": "-vf setpts=PTS/60 -r 25"
}
```
#### CPU fallback
If hardware acceleration is configured and the export fails (e.g., the GPU is unavailable), set `cpu_fallback: true` in the request body to automatically retry using software encoding.
```json
{
"name": "My Export",
"ffmpeg_output_args": "-c:v libx264 -crf 23",
"cpu_fallback": true
}
```
:::note
Non-admin users are restricted from using FFmpeg arguments that can access the filesystem (e.g., `-filter_complex`, file paths, and protocol references). Admin users have full control over FFmpeg arguments.
:::
:::tip
The encoder determines its own behavior so the resulting file size may be undesirably large.
To reduce the output file size the ffmpeg parameter `-qp n` can be utilized (where `n` stands for the value of the quantisation parameter). The value can be adjusted to get an acceptable tradeoff between quality and file size for the given scenario.
When `hwaccel_args` is configured, hardware encoding is used for exports. This can be overridden per camera (e.g., when camera resolution exceeds hardware encoder limits) by setting a camera-level `hwaccel_args`. Using an unrecognized value or empty string falls back to software encoding (libx264).
:::
:::tip
To reduce output file size, add the FFmpeg parameter `-qp n` to `ffmpeg_output_args` (where `n` is the quantization parameter). Adjust the value to balance quality and file size for your scenario.
:::
+28
View File
@@ -3,6 +3,10 @@ id: restream
title: Restream
---
import ConfigTabs from "@site/src/components/ConfigTabs";
import TabItem from "@theme/TabItem";
import NavPath from "@site/src/components/NavPath";
## RTSP
Frigate can restream your video feed as an RTSP feed for other applications such as Home Assistant to utilize it at `rtsp://<frigate_host>:8554/<camera_name>`. Port 8554 must be open. [This allows you to use a video feed for detection in Frigate and Home Assistant live view at the same time without having to make two separate connections to the camera](#reduce-connections-to-camera). The video feed is copied from the original video feed directly to avoid re-encoding. This feed does not include any annotation by Frigate.
@@ -52,6 +56,16 @@ Some cameras only support one active connection or you may just want to have a s
One connection is made to the camera. One for the restream, `detect` and `record` connect to the restream.
Configure the go2rtc stream and point the camera inputs at the local restream.
<ConfigTabs>
<TabItem value="ui">
Navigate to <NavPath path="Settings > System > go2rtc streams" /> and add stream entries for each camera. Then navigate to <NavPath path="Settings > Camera configuration > FFmpeg" /> for each camera and set the input paths to use the local restream URL (`rtsp://127.0.0.1:8554/<camera_name>`).
</TabItem>
<TabItem value="yaml">
```yaml
go2rtc:
streams:
@@ -87,10 +101,21 @@ cameras:
- audio # <- only necessary if audio detection is enabled
```
</TabItem>
</ConfigTabs>
### With Sub Stream
Two connections are made to the camera. One for the sub stream, one for the restream, `record` connects to the restream.
<ConfigTabs>
<TabItem value="ui">
Navigate to <NavPath path="Settings > System > go2rtc streams" /> and add stream entries for each camera and its sub stream. Then navigate to <NavPath path="Settings > Camera configuration > FFmpeg" /> for each camera and configure separate inputs for the main and sub streams using the local restream URLs.
</TabItem>
<TabItem value="yaml">
```yaml
go2rtc:
streams:
@@ -138,6 +163,9 @@ cameras:
- detect
```
</TabItem>
</ConfigTabs>
## Handling Complex Passwords
go2rtc expects URL-encoded passwords in the config, [urlencoder.org](https://urlencoder.org) can be used for this purpose.
+46 -4
View File
@@ -3,6 +3,10 @@ id: review
title: Review
---
import ConfigTabs from "@site/src/components/ConfigTabs";
import TabItem from "@theme/TabItem";
import NavPath from "@site/src/components/NavPath";
The Review page of the Frigate UI is for quickly reviewing historical footage of interest from your cameras. _Review items_ are indicated on a vertical timeline and displayed as a grid of previews - bandwidth-optimized, low frame rate, low resolution videos. Hovering over or swiping a preview plays the video and marks it as reviewed. If more in-depth analysis is required, the preview can be clicked/tapped and the full frame rate, full resolution recording is displayed.
Review items are filterable by date, object type, and camera.
@@ -23,7 +27,7 @@ Not every segment of video captured by Frigate may be of the same level of inter
:::note
Alerts and detections categorize the tracked objects in review items, but Frigate must first detect those objects with your configured object detector (Coral, OpenVINO, etc). By default, the object tracker only detects `person`. Setting `labels` for `alerts` and `detections` does not automatically enable detection of new objects. To detect more than `person`, you should add the following to your config:
Alerts and detections categorize the tracked objects in review items, but Frigate must first detect those objects with your configured object detector (Coral, OpenVINO, etc). By default, the object tracker only detects `person`. Setting `labels` for `alerts` and `detections` does not automatically enable detection of new objects. To detect more than `person`, you should add more labels via <NavPath path="Settings > Global configuration > Objects" /> or <NavPath path="Settings > Camera configuration > Objects" /> and select your camera. Alternatively, add the following to your config:
```yaml
objects:
@@ -38,7 +42,17 @@ See the [objects documentation](objects.md) for the list of objects that Frigate
## Restricting alerts to specific labels
By default a review item will only be marked as an alert if a person or car is detected. This can be configured to include any object or audio label using the following config:
By default a review item will only be marked as an alert if a person or car is detected. Configure the alert labels to include any object or audio label.
<ConfigTabs>
<TabItem value="ui">
Navigate to <NavPath path="Settings > Global configuration > Review" /> or <NavPath path="Settings > Camera configuration > Review" /> and select your camera.
Expand **Alerts config** and configure which labels and zones should generate alerts.
</TabItem>
<TabItem value="yaml">
```yaml
# can be overridden at the camera level
@@ -52,10 +66,23 @@ review:
- speech
```
</TabItem>
</ConfigTabs>
## Restricting detections to specific labels
By default all detections that do not qualify as an alert qualify as a detection. However, detections can further be filtered to only include certain labels or certain zones.
<ConfigTabs>
<TabItem value="ui">
Navigate to <NavPath path="Settings > Global configuration > Review" /> or <NavPath path="Settings > Camera configuration > Review" /> and select your camera.
Expand **Detections config** and configure which labels should qualify as detections.
</TabItem>
<TabItem value="yaml">
```yaml
# can be overridden at the camera level
review:
@@ -65,11 +92,23 @@ review:
- dog
```
</TabItem>
</ConfigTabs>
## Excluding a camera from alerts or detections
To exclude a specific camera from alerts or detections, simply provide an empty list to the alerts or detections field _at the camera level_.
To exclude a specific camera from alerts or detections, provide an empty list to the alerts or detections labels field at the camera level.
For example, to exclude objects on the camera _gatecamera_ from any detections, include this in your config:
For example, to exclude objects on the camera _gatecamera_ from any detections:
<ConfigTabs>
<TabItem value="ui">
1. Navigate to <NavPath path="Settings > Camera configuration > Review" /> and select the **gatecamera** camera.
- Expand **Detections config** and turn off all of the object label switches.
</TabItem>
<TabItem value="yaml">
```yaml {3-5}
cameras:
@@ -79,6 +118,9 @@ cameras:
labels: []
```
</TabItem>
</ConfigTabs>
## Restricting review items to specific zones
By default a review item will be created if any `review -> alerts -> labels` and `review -> detections -> labels` are detected anywhere in the camera frame. You will likely want to configure review items to only be created when the object enters an area of interest, [see the zone docs for more information](./zones.md#restricting-alerts-and-detections-to-specific-zones)
+102 -15
View File
@@ -3,12 +3,22 @@ id: semantic_search
title: Semantic Search
---
import ConfigTabs from "@site/src/components/ConfigTabs";
import TabItem from "@theme/TabItem";
import NavPath from "@site/src/components/NavPath";
Semantic Search in Frigate allows you to find tracked objects within your review items using either the image itself, a user-defined text description, or an automatically generated one. This feature works by creating _embeddings_ — numerical vector representations — for both the images and text descriptions of your tracked objects. By comparing these embeddings, Frigate assesses their similarities to deliver relevant search results.
Frigate uses models from [Jina AI](https://huggingface.co/jinaai) to create and save embeddings to Frigate's database. All of this runs locally.
Semantic Search is accessed via the _Explore_ view in the Frigate UI.
:::info
Semantic search requires a one-time internet connection to download embedding models from HuggingFace. Once cached, models work fully offline. See [Network Requirements](/frigate/network_requirements#one-time-model-downloads) for details.
:::
## Minimum System Requirements
Semantic Search works by running a large AI model locally on your system. Small or underpowered systems like a Raspberry Pi will not run Semantic Search reliably or at all.
@@ -19,7 +29,17 @@ For best performance, 16GB or more of RAM and a dedicated GPU are recommended.
## Configuration
Semantic Search is disabled by default, and must be enabled in your config file or in the UI's Enrichments Settings page before it can be used. Semantic Search is a global configuration setting.
Semantic Search is disabled by default and must be enabled before it can be used. Semantic Search is a global configuration setting.
<ConfigTabs>
<TabItem value="ui">
Navigate to <NavPath path="Settings > Enrichments > Semantic search" />.
- Set **Enable semantic search** to on
</TabItem>
<TabItem value="yaml">
```yaml
semantic_search:
@@ -27,6 +47,9 @@ semantic_search:
reindex: False
```
</TabItem>
</ConfigTabs>
:::tip
The embeddings database can be re-indexed from the existing tracked objects in your database by pressing the "Reindex" button in the Enrichments Settings in the UI or by adding `reindex: True` to your `semantic_search` configuration and restarting Frigate. Depending on the number of tracked objects you have, it can take a long while to complete and may max out your CPU while indexing.
@@ -41,7 +64,20 @@ The [V1 model from Jina](https://huggingface.co/jinaai/jina-clip-v1) has a visio
The V1 text model is used to embed tracked object descriptions and perform searches against them. Descriptions can be created, viewed, and modified on the Explore page when clicking on thumbnail of a tracked object. See [the object description docs](/configuration/genai/objects.md) for more information on how to automatically generate tracked object descriptions.
Differently weighted versions of the Jina models are available and can be selected by setting the `model_size` config option as `small` or `large`:
Differently weighted versions of the Jina models are available and can be selected by setting the model size.
<ConfigTabs>
<TabItem value="ui">
Navigate to <NavPath path="Settings > Enrichments > Semantic search" />.
| Field | Description |
| ------------------------------------------------ | -------------------------------------------------------------------------- |
| **Semantic search model or GenAI provider name** | Select `jinav1` to use the Jina AI CLIP V1 model |
| **Model size** | `small` (quantized, CPU-friendly) or `large` (full model, GPU-accelerated) |
</TabItem>
<TabItem value="yaml">
```yaml
semantic_search:
@@ -50,6 +86,9 @@ semantic_search:
model_size: small
```
</TabItem>
</ConfigTabs>
- Configuring the `large` model employs the full Jina model and will automatically run on the GPU if applicable.
- Configuring the `small` model employs a quantized version of the Jina model that uses less RAM and runs on CPU with a very negligible difference in embedding quality.
@@ -59,7 +98,20 @@ Frigate also supports the [V2 model from Jina](https://huggingface.co/jinaai/jin
V2 offers only a 3% performance improvement over V1 in both text-image and text-text retrieval tasks, an upgrade that is unlikely to yield noticeable real-world benefits. Additionally, V2 has _significantly_ higher RAM and GPU requirements, leading to increased inference time and memory usage. If you plan to use V2, ensure your system has ample RAM and a discrete GPU. CPU inference (with the `small` model) using V2 is not recommended.
To use the V2 model, update the `model` parameter in your config:
To use the V2 model, set the model to `jinav2`.
<ConfigTabs>
<TabItem value="ui">
Navigate to <NavPath path="Settings > Enrichments > Semantic search" />.
| Field | Description |
| ------------------------------------------------ | ----------------------------------------------------- |
| **Semantic search model or GenAI provider name** | Select `jinav2` to use the Jina AI CLIP V2 model |
| **Model size** | `large` is recommended for V2 (requires discrete GPU) |
</TabItem>
<TabItem value="yaml">
```yaml
semantic_search:
@@ -68,6 +120,9 @@ semantic_search:
model_size: large
```
</TabItem>
</ConfigTabs>
For most users, especially native English speakers, the V1 model remains the recommended choice.
:::note
@@ -82,9 +137,23 @@ Frigate can use a GenAI provider for semantic search embeddings when that provid
To use llama.cpp for semantic search:
1. Configure a GenAI provider in your config with `embeddings` in its `roles`.
2. Set `semantic_search.model` to the GenAI config key (e.g. `default`).
3. Start the llama.cpp server with `--embeddings` and `--mmproj` for image support:
1. Configure a GenAI provider with `embeddings` in its `roles`.
2. Set the semantic search model to the GenAI config key (e.g. `default`).
3. Start the llama.cpp server with `--embeddings` and `--mmproj` for image support.
<ConfigTabs>
<TabItem value="ui">
Navigate to <NavPath path="Settings > Enrichments > Semantic search" />.
| Field | Description |
| ------------------------------------------------ | ---------------------------------------------------------------------------------------------- |
| **Semantic search model or GenAI provider name** | Set to the GenAI config key (e.g. `default`) to use a configured GenAI provider for embeddings |
The GenAI provider must also be configured with the `embeddings` role under <NavPath path="Settings > Enrichments > Generative AI" />.
</TabItem>
<TabItem value="yaml">
```yaml
genai:
@@ -102,6 +171,9 @@ semantic_search:
model: default
```
</TabItem>
</ConfigTabs>
The llama.cpp server must be started with `--embeddings` for the embeddings API, and a multi-modal embeddings model. See the [llama.cpp server documentation](https://github.com/ggml-org/llama.cpp/blob/master/tools/server/README.md) for details.
:::note
@@ -114,6 +186,19 @@ Switching between Jina models and a GenAI provider requires reindexing. Embeddin
The CLIP models are downloaded in ONNX format, and the `large` model can be accelerated using GPU hardware, when available. This depends on the Docker build that is used. You can also target a specific device in a multi-GPU installation.
<ConfigTabs>
<TabItem value="ui">
Navigate to <NavPath path="Settings > Enrichments > Semantic search" />.
| Field | Description |
| -------------- | ---------------------------------------------------------------------- |
| **Model size** | Set to `large` to enable GPU acceleration |
| **Device** | (Optional) Specify a GPU device index in a multi-GPU system (e.g. `0`) |
</TabItem>
<TabItem value="yaml">
```yaml
semantic_search:
enabled: True
@@ -122,6 +207,9 @@ semantic_search:
device: 0
```
</TabItem>
</ConfigTabs>
:::info
If the correct build is used for your GPU / NPU and the `large` model is configured, then the GPU will be detected and used automatically.
@@ -153,16 +241,15 @@ Semantic Search must be enabled to use Triggers.
### Configuration
Triggers are defined within the `semantic_search` configuration for each camera in your Frigate configuration file or through the UI. Each trigger consists of a `friendly_name`, a `type` (either `thumbnail` or `description`), a `data` field (the reference image event ID or text), a `threshold` for similarity matching, and a list of `actions` to perform when the trigger fires - `notification`, `sub_label`, and `attribute`.
Triggers are defined within the `semantic_search` configuration for each camera. Each trigger consists of a `friendly_name`, a `type` (either `thumbnail` or `description`), a `data` field (the reference image event ID or text), a `threshold` for similarity matching, and a list of `actions` to perform when the trigger fires - `notification`, `sub_label`, and `attribute`.
Triggers are best configured through the Frigate UI.
#### Managing Triggers in the UI
1. Navigate to the **Settings** page and select the **Triggers** tab.
2. Choose a camera from the dropdown menu to view or manage its triggers.
3. Click **Add Trigger** to create a new trigger or use the pencil icon to edit an existing one.
4. In the **Create Trigger** wizard:
1. Navigate to <NavPath path="Settings > Enrichments > Triggers" /> and select a camera from the dropdown menu.
2. Click **Add Trigger** to create a new trigger or use the pencil icon to edit an existing one.
3. In the **Create Trigger** wizard:
- Enter a **Name** for the trigger (e.g., "Red Car Alert").
- Enter a descriptive **Friendly Name** for the trigger (e.g., "Red car on the driveway camera").
- Select the **Type** (`Thumbnail` or `Description`).
@@ -173,14 +260,14 @@ Triggers are best configured through the Frigate UI.
If native webpush notifications are enabled, check the `Send Notification` box to send a notification.
Check the `Add Sub Label` box to add the trigger's friendly name as a sub label to any triggering tracked objects.
Check the `Add Attribute` box to add the trigger's internal ID (e.g., "red_car_alert") to a data attribute on the tracked object that can be processed via the API or MQTT.
5. Save the trigger to update the configuration and store the embedding in the database.
4. Save the trigger to update the configuration and store the embedding in the database.
When a trigger fires, the UI highlights the trigger with a blue dot for 3 seconds for easy identification. Additionally, the UI will show the last date/time and tracked object ID that activated your trigger. The last triggered timestamp is not saved to the database or persisted through restarts of Frigate.
### Usage and Best Practices
1. **Thumbnail Triggers**: Select a representative image (event ID) from the Explore page that closely matches the object you want to detect. For best results, choose images where the object is prominent and fills most of the frame.
2. **Description Triggers**: Write concise, specific text descriptions (e.g., "Person in a red jacket") that align with the tracked objects description. Avoid vague terms to improve matching accuracy.
2. **Description Triggers**: Write concise, specific text descriptions (e.g., "Person in a red jacket") that align with the tracked object's description. Avoid vague terms to improve matching accuracy.
3. **Threshold Tuning**: Adjust the threshold to balance sensitivity and specificity. A higher threshold (e.g., 0.8) requires closer matches, reducing false positives but potentially missing similar objects. A lower threshold (e.g., 0.6) is more inclusive but may trigger more often.
4. **Using Explore**: Use the context menu or right-click / long-press on a tracked object in the Grid View in Explore to quickly add a trigger based on the tracked object's thumbnail.
5. **Editing triggers**: For the best experience, triggers should be edited via the UI. However, Frigate will ensure triggers edited in the config will be synced with triggers created and edited in the UI.
@@ -195,6 +282,6 @@ When a trigger fires, the UI highlights the trigger with a blue dot for 3 second
#### Why can't I create a trigger on thumbnails for some text, like "person with a blue shirt" and have it trigger when a person with a blue shirt is detected?
TL;DR: Text-to-image triggers arent supported because CLIP can confuse similar images and give inconsistent scores, making automation unreliable. The same wordimage pair can give different scores and the score ranges can be too close together to set a clear cutoff.
TL;DR: Text-to-image triggers aren't supported because CLIP can confuse similar images and give inconsistent scores, making automation unreliable. The same word-image pair can give different scores and the score ranges can be too close together to set a clear cutoff.
Text-to-image triggers are not supported due to fundamental limitations of CLIP-based similarity search. While CLIP works well for exploratory, manual queries, it is unreliable for automated triggers based on a threshold. Issues include embedding drift (the same textimage pair can yield different cosine distances over time), lack of true semantic grounding (visually similar but incorrect matches), and unstable thresholding (distance distributions are dataset-dependent and often too tightly clustered to separate relevant from irrelevant results). Instead, it is recommended to set up a workflow with thumbnail triggers: first use text search to manually select 35 representative reference tracked objects, then configure thumbnail triggers based on that visual similarity. This provides robust automation without the semantic ambiguity of text to image matching.
Text-to-image triggers are not supported due to fundamental limitations of CLIP-based similarity search. While CLIP works well for exploratory, manual queries, it is unreliable for automated triggers based on a threshold. Issues include embedding drift (the same text-image pair can yield different cosine distances over time), lack of true semantic grounding (visually similar but incorrect matches), and unstable thresholding (distance distributions are dataset-dependent and often too tightly clustered to separate relevant from irrelevant results). Instead, it is recommended to set up a workflow with thumbnail triggers: first use text search to manually select 3-5 representative reference tracked objects, then configure thumbnail triggers based on that visual similarity. This provides robust automation without the semantic ambiguity of text to image matching.
+118 -3
View File
@@ -3,19 +3,134 @@ id: snapshots
title: Snapshots
---
import ConfigTabs from "@site/src/components/ConfigTabs";
import TabItem from "@theme/TabItem";
import NavPath from "@site/src/components/NavPath";
Frigate can save a snapshot image to `/media/frigate/clips` for each object that is detected named as `<camera>-<id>-clean.webp`. They are also accessible [via the api](../integrations/api/event-snapshot-events-event-id-snapshot-jpg-get.api.mdx)
Snapshots are accessible in the UI in the Explore pane. This allows for quick submission to the Frigate+ service.
To only save snapshots for objects that enter a specific zone, [see the zone docs](./zones.md#restricting-snapshots-to-specific-zones)
Snapshots sent via MQTT are configured in the [config file](/configuration) under `cameras -> your_camera -> mqtt`
Snapshots sent via MQTT are configured separately under the camera MQTT settings, not here.
## Enabling Snapshots
Enable snapshot saving and configure the default settings that apply to all cameras.
<ConfigTabs>
<TabItem value="ui">
Navigate to <NavPath path="Settings > Global configuration > Snapshots" />.
- Set **Enable snapshots** to on
</TabItem>
<TabItem value="yaml">
```yaml
snapshots:
enabled: True
```
</TabItem>
</ConfigTabs>
To override snapshot settings for a specific camera:
<ConfigTabs>
<TabItem value="ui">
Navigate to <NavPath path="Settings > Camera configuration > Snapshots" /> and select your camera.
- Set **Enable snapshots** to on
</TabItem>
<TabItem value="yaml">
```yaml
cameras:
front_door:
snapshots:
enabled: True
```
</TabItem>
</ConfigTabs>
## Snapshot Options
Configure how snapshots are rendered and stored. These settings control the defaults applied when snapshots are requested via the API.
<ConfigTabs>
<TabItem value="ui">
Navigate to <NavPath path="Settings > Global configuration > Snapshots" />.
| Field | Description |
| ------------------------ | ------------------------------------------------------------------------------ |
| **Enable snapshots** | Enable or disable saving snapshots for tracked objects |
| **Timestamp overlay** | Overlay a timestamp on snapshots from API |
| **Bounding box overlay** | Draw bounding boxes for tracked objects on snapshots from API |
| **Crop snapshot** | Crop snapshots from API to the detected object's bounding box |
| **Snapshot height** | Height in pixels to resize snapshots to; leave empty to preserve original size |
| **Snapshot quality** | Encode quality for saved snapshots (0-100) |
| **Required zones** | Zones an object must enter for a snapshot to be saved |
</TabItem>
<TabItem value="yaml">
```yaml
snapshots:
enabled: True
timestamp: False
bounding_box: True
crop: False
height: 175
required_zones: []
quality: 60
```
</TabItem>
</ConfigTabs>
## Snapshot Retention
Configure how long snapshots are retained on disk. Per-object retention overrides allow different retention periods for specific object types.
<ConfigTabs>
<TabItem value="ui">
Navigate to <NavPath path="Settings > Global configuration > Snapshots" />.
| Field | Description |
| -------------------------------------------------- | ----------------------------------------------------------------------------------- |
| **Snapshot retention > Default retention** | Number of days to retain snapshots (default: 10) |
| **Snapshot retention > Retention mode** | Retention mode: `all`, `motion`, or `active_objects` |
| **Snapshot retention > Object retention > Person** | Per-object overrides for retention days (e.g., keep `person` snapshots for 15 days) |
</TabItem>
<TabItem value="yaml">
```yaml
snapshots:
enabled: True
retain:
default: 10
mode: motion
objects:
person: 15
```
</TabItem>
</ConfigTabs>
## Frame Selection
Frigate does not save every frame. It picks a single "best" frame for each tracked object based on detection confidence, object size, and the presence of key attributes like faces or license plates. Frames where the object touches the edge of the frame are deprioritized. That best frame is written to disk once tracking ends.
MQTT snapshots are published more frequently — each time a better thumbnail frame is found during tracking, or when the current best image is older than `best_image_timeout` (default: 60s). These use their own annotation settings configured under `cameras -> your_camera -> mqtt`.
MQTT snapshots are published more frequently — each time a better thumbnail frame is found during tracking, or when the current best image is older than `best_image_timeout` (default: 60s). These use their own annotation settings configured under the camera MQTT settings.
## Rendering
@@ -28,4 +143,4 @@ Frigate stores a single clean snapshot on disk:
| `/api/events/<id>/snapshot-clean.webp` | Returns the same stored snapshot without annotations |
| [Frigate+](/plus/first_model) submission | Uses the same stored clean snapshot |
MQTT snapshots are configured separately under `cameras -> your_camera -> mqtt` and are unrelated to the stored event snapshot.
MQTT snapshots are configured separately under the camera MQTT settings and are unrelated to the stored event snapshot.
+19 -7
View File
@@ -1,14 +1,29 @@
# Stationary Objects
import ConfigTabs from "@site/src/components/ConfigTabs";
import TabItem from "@theme/TabItem";
import NavPath from "@site/src/components/NavPath";
An object is considered stationary when it is being tracked and has been in a very similar position for a certain number of frames. This number is defined in the configuration under `detect -> stationary -> threshold`, and is 10x the frame rate (or 10 seconds) by default. Once an object is considered stationary, it will remain stationary until motion occurs within the object at which point object detection will start running again. If the object changes location, it will be considered active.
## Why does it matter if an object is stationary?
Once an object becomes stationary, object detection will not be continually run on that object. This serves to reduce resource usage and redundant detections when there has been no motion near the tracked object. This also means that Frigate is contextually aware, and can for example [filter out recording segments](record.md#what-do-the-different-retain-modes-mean) to only when the object is considered active. Motion alone does not determine if an object is "active" for active_objects segment retention. Lighting changes for a parked car won't make an object active.
Once an object becomes stationary, object detection will not be continually run on that object. This serves to reduce resource usage and redundant detections when there has been no motion near the tracked object. This also means that Frigate is contextually aware, and can for example [filter out recording segments](record.md#configuring-recording-retention) to only when the object is considered active. Motion alone does not determine if an object is "active" for active_objects segment retention. Lighting changes for a parked car won't make an object active.
## Tuning stationary behavior
The default config is:
Configure how Frigate handles stationary objects.
<ConfigTabs>
<TabItem value="ui">
Navigate to <NavPath path="Settings > Global configuration > Object detection" />.
- Set **Stationary objects config > Stationary interval** to the frequency for running detection on stationary objects (default: 50). Once stationary, detection runs every nth frame to verify the object is still present. There is no way to disable stationary object tracking with this value.
- Set **Stationary objects config > Stationary threshold** to the number of frames an object must remain relatively still before it is considered stationary (default: 50)
</TabItem>
<TabItem value="yaml">
```yaml
detect:
@@ -17,11 +32,8 @@ detect:
threshold: 50
```
`interval` is defined as the frequency for running detection on stationary objects. This means that by default once an object is considered stationary, detection will not be run on it until motion is detected or until the interval (every 50th frame by default). With `interval >= 1`, every nth frames detection will be run to make sure the object is still there.
NOTE: There is no way to disable stationary object tracking with this value.
`threshold` is the number of frames an object needs to remain relatively still before it is considered stationary.
</TabItem>
</ConfigTabs>
## Why does Frigate track stationary objects?
+18 -1
View File
@@ -3,19 +3,36 @@ id: tls
title: TLS
---
import ConfigTabs from "@site/src/components/ConfigTabs";
import TabItem from "@theme/TabItem";
import NavPath from "@site/src/components/NavPath";
# TLS
Frigate's integrated NGINX server supports TLS certificates. By default Frigate will generate a self signed certificate that will be used for port 8971. Frigate is designed to make it easy to use whatever tool you prefer to manage certificates.
Frigate is often running behind a reverse proxy that manages TLS certificates for multiple services. You will likely need to set your reverse proxy to allow self signed certificates or you can disable TLS in Frigate's config. However, if you are running on a dedicated device that's separate from your proxy or if you expose Frigate directly to the internet, you may want to configure TLS with valid certificates.
In many deployments, TLS will be unnecessary. It can be disabled in the config with the following yaml:
In many deployments, TLS will be unnecessary. Disable it as follows:
<ConfigTabs>
<TabItem value="ui">
Navigate to <NavPath path="Settings > System > TLS" />.
- Set **Enable TLS** to off if running behind a reverse proxy that handles TLS (default: on)
</TabItem>
<TabItem value="yaml">
```yaml
tls:
enabled: False
```
</TabItem>
</ConfigTabs>
## Certificates
TLS certificates can be mounted at `/etc/letsencrypt/live/frigate` using a bind mount or docker volume.
+183 -7
View File
@@ -3,6 +3,10 @@ id: zones
title: Zones
---
import ConfigTabs from "@site/src/components/ConfigTabs";
import TabItem from "@theme/TabItem";
import NavPath from "@site/src/components/NavPath";
Zones allow you to define a specific area of the frame and apply additional filters for object types so you can determine whether or not an object is within a particular area. Presence in a zone is evaluated based on the bottom center of the bounding box for the object. It does not matter how much of the bounding box overlaps with the zone.
For example, the cat in this image is currently in Zone 1, but **not** Zone 2.
@@ -16,11 +20,51 @@ Zones can be toggled on or off without removing them from the configuration. Dis
During testing, enable the Zones option for the Debug view of your camera (Settings --> Debug) so you can adjust as needed. The zone line will increase in thickness when any object enters the zone.
To create a zone, follow [the steps for a "Motion mask"](masks.md), but use the section of the web UI for creating a zone instead.
## Creating a Zone
<ConfigTabs>
<TabItem value="ui">
1. Navigate to <NavPath path="Settings > Camera configuration > Masks / Zones" /> and select the desired camera.
2. Under the **Zones** section, click the plus icon to add a new zone.
3. Click on the camera's latest image to create the points for the zone boundary. Click the first point again to close the polygon.
4. Configure zone options such as **Friendly name**, **Objects**, **Loitering time**, and **Inertia** in the zone editor.
5. Press **Save** when finished.
</TabItem>
<TabItem value="yaml">
Follow [the steps for creating a mask](masks.md), but use the zone section of the web UI instead. Alternatively, define zones directly in your configuration file:
```yaml
cameras:
name_of_your_camera:
zones:
entire_yard:
friendly_name: Entire yard
coordinates: 0.123,0.456,0.789,0.012,...
```
</TabItem>
</ConfigTabs>
### Restricting alerts and detections to specific zones
Often you will only want alerts to be created when an object enters areas of interest. This is done using zones along with setting required_zones. Let's say you only want to have an alert created when an object enters your entire_yard zone, the config would be:
Often you will only want alerts to be created when an object enters areas of interest. This is done by combining zones with required zones for review items.
To create an alert only when an object enters the `entire_yard` zone:
<ConfigTabs>
<TabItem value="ui">
Navigate to <NavPath path="Settings > Camera configuration > Review" />.
| Field | Description |
| ---------------------------------- | ----------------------------------------------------------------------------------------- |
| **Alerts config > Required zones** | Zones that an object must enter to be considered an alert; leave empty to allow any zone. |
</TabItem>
<TabItem value="yaml">
```yaml {6,8}
cameras:
@@ -35,7 +79,23 @@ cameras:
coordinates: ...
```
You may also want to filter detections to only be created when an object enters a secondary area of interest. This is done using zones along with setting required_zones. Let's say you want alerts when an object enters the inner area of the yard but detections when an object enters the edge of the yard, the config would be
</TabItem>
</ConfigTabs>
You may also want to filter detections to only be created when an object enters a secondary area of interest. For example, to trigger alerts when an object enters the inner area of the yard but detections when an object enters the edge of the yard:
<ConfigTabs>
<TabItem value="ui">
Navigate to <NavPath path="Settings > Camera configuration > Review" />.
| Field | Description |
| -------------------------------------- | -------------------------------------------------------------------------------------------- |
| **Alerts config > Required zones** | Zones that an object must enter to be considered an alert; leave empty to allow any zone. |
| **Detections config > Required zones** | Zones that an object must enter to be considered a detection; leave empty to allow any zone. |
</TabItem>
<TabItem value="yaml">
```yaml
cameras:
@@ -56,8 +116,22 @@ cameras:
coordinates: ...
```
</TabItem>
</ConfigTabs>
### Restricting snapshots to specific zones
To only save snapshots when an object enters a specific zone:
<ConfigTabs>
<TabItem value="ui">
1. Navigate to <NavPath path="Settings > Camera configuration > Snapshots" /> and select your camera.
- Set **Required zones** to `entire_yard`
</TabItem>
<TabItem value="yaml">
```yaml
cameras:
name_of_your_camera:
@@ -70,9 +144,24 @@ cameras:
coordinates: ...
```
</TabItem>
</ConfigTabs>
### Restricting zones to specific objects
Sometimes you want to limit a zone to specific object types to have more granular control of when alerts, detections, and snapshots are saved. The following example will limit one zone to person objects and the other to cars.
Sometimes you want to limit a zone to specific object types to have more granular control of when alerts, detections, and snapshots are saved. The following example limits one zone to person objects and the other to cars.
<ConfigTabs>
<TabItem value="ui">
1. Navigate to <NavPath path="Settings > Camera configuration > Masks / Zones" /> and select the desired camera.
2. Create a zone named `entire_yard` covering everywhere you want to track a person.
- Under **Objects**, add `person`
3. Create a second zone named `front_yard_street` covering just the street.
- Under **Objects**, add `car`
</TabItem>
<TabItem value="yaml">
```yaml
cameras:
@@ -88,6 +177,9 @@ cameras:
- car
```
</TabItem>
</ConfigTabs>
Only car objects can trigger the `front_yard_street` zone and only person can trigger the `entire_yard`. Objects will be tracked for any `person` that enter anywhere in the yard, and for cars only if they enter the street.
### Zone Loitering
@@ -103,6 +195,17 @@ When using loitering zones, a review item will behave in the following way:
:::
<ConfigTabs>
<TabItem value="ui">
1. Navigate to <NavPath path="Settings > Camera configuration > Masks / Zones" /> and select the desired camera.
2. Edit or create the zone (e.g., `sidewalk`).
- Set **Loitering time** to the desired number of seconds (e.g., `4`)
- Under **Objects**, add the relevant object types (e.g., `person`)
</TabItem>
<TabItem value="yaml">
```yaml
cameras:
name_of_your_camera:
@@ -114,9 +217,22 @@ cameras:
- person
```
</TabItem>
</ConfigTabs>
### Zone Inertia
Sometimes an objects bounding box may be slightly incorrect and the bottom center of the bounding box is inside the zone while the object is not actually in the zone. Zone inertia helps guard against this by requiring an object's bounding box to be within the zone for multiple consecutive frames. This value can be configured:
Sometimes an objects bounding box may be slightly incorrect and the bottom center of the bounding box is inside the zone while the object is not actually in the zone. Zone inertia helps guard against this by requiring an object's bounding box to be within the zone for multiple consecutive frames.
<ConfigTabs>
<TabItem value="ui">
1. Navigate to <NavPath path="Settings > Camera configuration > Masks / Zones" /> and select the desired camera.
2. Edit or create the zone (e.g., `front_yard`).
- Set **Inertia** to the desired number of consecutive frames (e.g., `3`)
</TabItem>
<TabItem value="yaml">
```yaml
cameras:
@@ -129,8 +245,21 @@ cameras:
- person
```
</TabItem>
</ConfigTabs>
There may also be cases where you expect an object to quickly enter and exit a zone, like when a car is pulling into the driveway, and you may want to have the object be considered present in the zone immediately:
<ConfigTabs>
<TabItem value="ui">
1. Navigate to <NavPath path="Settings > Camera configuration > Masks / Zones" /> and select the desired camera.
2. Edit or create the zone (e.g., `driveway_entrance`).
- Set **Inertia** to `1`
</TabItem>
<TabItem value="yaml">
```yaml
cameras:
name_of_your_camera:
@@ -142,6 +271,9 @@ cameras:
- car
```
</TabItem>
</ConfigTabs>
### Speed Estimation
Frigate can be configured to estimate the speed of objects moving through a zone. This works by combining data from Frigate's object tracker and "real world" distance measurements of the edges of the zone. The recommended use case for this feature is to track the speed of vehicles on a road as they move through the zone.
@@ -152,7 +284,19 @@ Your zone must be defined with exactly 4 points and should be aligned to the gro
Speed estimation requires a minimum number of frames for your object to be tracked before a valid estimate can be calculated, so create your zone away from places where objects enter and exit for the best results. The object's bounding box must be stable and remain a constant size as it enters and exits the zone. _Your zone should not take up the full frame, and the zone does **not** need to be the same size or larger than the objects passing through it._ An object's speed is tracked while it passes through the zone and then saved to Frigate's database.
Accurate real-world distance measurements are required to estimate speeds. These distances can be specified in your zone config through the `distances` field.
Accurate real-world distance measurements are required to estimate speeds. These distances can be specified through the `distances` field. Each number represents the real-world distance between consecutive points in the `coordinates` list. The fastest and most accurate way to configure this is through the Zone Editor in the Frigate UI.
<ConfigTabs>
<TabItem value="ui">
1. Navigate to <NavPath path="Settings > Camera configuration > Masks / Zones" /> and select the desired camera.
2. Create or edit a zone with exactly 4 points aligned to the ground plane.
3. In the zone editor, enter the real-world **Distances** between each pair of consecutive points.
- For example, if the distance between the first and second points is 10 meters, between the second and third is 12 meters, etc.
4. Distances are measured in meters (metric) or feet (imperial), depending on the **Unit system** setting.
</TabItem>
<TabItem value="yaml">
```yaml
cameras:
@@ -163,16 +307,34 @@ cameras:
distances: 10,12,11,13.5 # in meters or feet
```
Each number in the `distance` field represents the real-world distance between the points in the `coordinates` list. So in the example above, the distance between the first two points ([0.033,0.306] and [0.324,0.138]) is 10. The distance between the second and third set of points ([0.324,0.138] and [0.439,0.185]) is 12, and so on. The fastest and most accurate way to configure this is through the Zone Editor in the Frigate UI.
So in the example above, the distance between the first two points ([0.033,0.306] and [0.324,0.138]) is 10. The distance between the second and third set of points ([0.324,0.138] and [0.439,0.185]) is 12, and so on.
</TabItem>
</ConfigTabs>
The `distance` values are measured in meters (metric) or feet (imperial), depending on how `unit_system` is configured in your `ui` config:
<ConfigTabs>
<TabItem value="ui">
Navigate to <NavPath path="Settings > System > UI" />.
| Field | Description |
| --------------- | -------------------------------------------------------------------- |
| **Unit system** | Set to `metric` (kilometers per hour) or `imperial` (miles per hour) |
</TabItem>
<TabItem value="yaml">
```yaml
ui:
# can be "metric" or "imperial", default is metric
unit_system: metric
```
</TabItem>
</ConfigTabs>
The average speed of your object as it moved through your zone is saved in Frigate's database and can be seen in the UI in the Tracked Object Details pane in Explore. Current estimated speed can also be seen on the debug view as the third value in the object label (see the caveats below). Current estimated speed, average estimated speed, and velocity angle (the angle of the direction the object is moving relative to the frame) of tracked objects is also sent through the `events` MQTT topic. See the [MQTT docs](../integrations/mqtt.md#frigateevents).
These speed values are output as a number in miles per hour (mph) or kilometers per hour (kph). For miles per hour, set `unit_system` to `imperial`. For kilometers per hour, set `unit_system` to `metric`.
@@ -191,6 +353,17 @@ These speed values are output as a number in miles per hour (mph) or kilometers
Zones can be configured with a minimum speed requirement, meaning an object must be moving at or above this speed to be considered inside the zone. Zone `distances` must be defined as described above.
<ConfigTabs>
<TabItem value="ui">
1. Navigate to <NavPath path="Settings > Camera configuration > Masks / Zones" /> and select the desired camera.
2. Edit or create the zone with distances configured.
- Set **Speed threshold** to the desired minimum speed (e.g., `20`)
- The unit is kph or mph, depending on the **Unit system** setting
</TabItem>
<TabItem value="yaml">
```yaml
cameras:
name_of_your_camera:
@@ -202,3 +375,6 @@ cameras:
# highlight-next-line
speed_threshold: 20 # unit is in kph or mph, depending on how unit_system is set (see above)
```
</TabItem>
</ConfigTabs>
+1 -1
View File
@@ -34,7 +34,7 @@ For the Dahua/Loryta 5442 camera, I use the following settings:
- Encode Mode: H.264
- Resolution: 2688\*1520
- Frame Rate(FPS): 15
- I Frame Interval: 30 (15 can also be used to prioritize streaming performance - see the [camera settings recommendations](/configuration/live#camera_settings_recommendations) for more info)
- I Frame Interval: 30 (15 can also be used to prioritize streaming performance - see the [camera settings recommendations](/configuration/live#camera-settings-recommendations) for more info)
**Sub Stream (Detection)**
+3 -9
View File
@@ -95,7 +95,7 @@ Frigate supports multiple different detectors that work on different types of ha
**Rockchip** <CommunityBadge />
- [RKNN](#rockchip-platform): RKNN models can run on Rockchip devices with included NPUs to provide efficient object detection.
- [Supports limited model architectures](../../configuration/object_detectors#choosing-a-model)
- [Supports limited model architectures](../../configuration/object_detectors#rockchip-supported-models)
- Runs best with tiny or small size models
- Runs efficiently on low power hardware
@@ -146,17 +146,11 @@ A single Coral can handle many cameras using the default model and will be suffi
The OpenVINO detector type is able to run on:
- 6th Gen Intel Platforms and newer that have an iGPU
- x86 hosts with an Intel Arc GPU
- x86 hosts with an Intel Arc GPU (including Arc A-series and B-series Battlemage)
- Intel NPUs
- Most modern AMD CPUs (though this is officially not supported by Intel)
- x86 & Arm64 hosts via CPU (generally not recommended)
:::note
Intel B-series (Battlemage) GPUs are not officially supported with Frigate 0.17, though a user has [provided steps to rebuild the Frigate container](https://github.com/blakeblackshear/frigate/discussions/21257) with support for them.
:::
More information is available [in the detector docs](/configuration/object_detectors#openvino-detector)
Inference speeds vary greatly depending on the CPU or GPU used, some known examples of GPU inference times are below:
@@ -263,7 +257,7 @@ Inference speeds may vary depending on the host platform. The above data was mea
### Nvidia Jetson
Jetson devices are supported via the TensorRT or ONNX detectors when running Jetpack 6. It will [make use of the Jetson's hardware media engine](/configuration/hardware_acceleration_video#nvidia-jetson-orin-agx-orin-nx-orin-nano-xavier-agx-xavier-nx-tx2-tx1-nano) when configured with the [appropriate presets](/configuration/ffmpeg_presets#hwaccel-presets), and will make use of the Jetson's GPU and DLA for object detection when configured with the [TensorRT detector](/configuration/object_detectors#nvidia-tensorrt-detector).
Jetson devices are supported via the TensorRT or ONNX detectors when running Jetpack 6. It will [make use of the Jetson's hardware media engine](/configuration/hardware_acceleration_video#nvidia-jetson) when configured with the [appropriate presets](/configuration/ffmpeg_presets#hwaccel-presets), and will make use of the Jetson's GPU and DLA for object detection when configured with the [TensorRT detector](/configuration/object_detectors#nvidia-tensorrt-detector).
Inference speed will vary depending on the YOLO model, jetson platform and jetson nvpmodel (GPU/DLA/EMC clock speed). It is typically 20-40 ms for most models. The DLA is more efficient than the GPU, but not faster, so using the DLA will reduce power consumption but will slightly increase inference time.
+3 -2
View File
@@ -271,7 +271,7 @@ If you are using `docker run`, add this option to your command `--device /dev/ha
#### Configuration
Finally, configure [hardware object detection](/configuration/object_detectors#hailo-8l) to complete the setup.
Finally, configure [hardware object detection](/configuration/object_detectors#hailo-8) to complete the setup.
### MemryX MX3
@@ -482,7 +482,8 @@ services:
- /dev/apex_0:/dev/apex_0 # Passes a PCIe Coral, follow driver instructions here https://github.com/jnicolson/gasket-builder
- /dev/video11:/dev/video11 # For Raspberry Pi 4B
- /dev/dri/renderD128:/dev/dri/renderD128 # AMD / Intel GPU, needs to be updated for your hardware
- /dev/accel:/dev/accel # Intel NPU
- /dev/kfd:/dev/kfd # AMD Kernel Fusion Driver for ROCm
- /dev/accel:/dev/accel # AMD / Intel NPU
volumes:
- /etc/localtime:/etc/localtime:ro
- /path/to/your/config:/config
+155
View File
@@ -0,0 +1,155 @@
---
id: network_requirements
title: Network Requirements
---
# Network Requirements
Frigate is designed to run locally and does not require a persistent internet connection for core functionality. However, certain features need internet access for initial setup or ongoing operation. This page describes what connects to the internet, when, and how to control it.
## How Frigate Uses the Internet
Frigate's internet usage falls into three categories:
1. **One-time model downloads** — ML models are downloaded the first time a feature is enabled, then cached locally. No internet is needed on subsequent startups.
2. **Optional cloud services** — Features like Frigate+ and Generative AI connect to external APIs only when explicitly configured.
3. **Build-time dependencies** — Components bundled into the Docker image during the build process. These require no internet at runtime.
:::tip
After initial setup, Frigate can run fully offline as long as all required models have been downloaded and no cloud-dependent features are enabled.
:::
## One-Time Model Downloads
The following models are downloaded automatically the first time their associated feature is enabled. Once cached in `/config/model_cache/`, they do not require internet again.
| Feature | Models Downloaded | Source |
| --------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------- | -------------------- |
| [Semantic search](/configuration/semantic_search) | Jina CLIP v1 or v2 (ONNX) + tokenizer | HuggingFace |
| [Face recognition](/configuration/face_recognition) | FaceNet, ArcFace, face detection model | GitHub |
| [License plate recognition](/configuration/license_plate_recognition) | PaddleOCR (detection, classification, recognition) + YOLOv9 plate detector | GitHub |
| [Bird classification](/configuration/bird_classification) | MobileNetV2 bird model + label map | GitHub |
| [Custom classification](/configuration/custom_classification/state_classification) (training) | MobileNetV2 ImageNet base weights (via Keras) | Google storage |
| [Audio transcription](/configuration/advanced) | Whisper or Sherpa-ONNX streaming model | HuggingFace / OpenAI |
### Hardware-Specific Detector Models
If you are using one of the following hardware detectors and have not provided your own model file, a default model will be downloaded on first startup:
| Detector | Model Downloaded | Source |
| ------------------------------------------------------------------ | -------------------- | ------------------------ |
| [Rockchip RKNN](/configuration/object_detectors#rockchip-platform) | RKNN detection model | GitHub |
| [Hailo 8 / 8L](/configuration/object_detectors#hailo-8) | YOLOv6n (.hef) | Hailo Model Zoo (AWS S3) |
| [AXERA AXEngine](/configuration/object_detectors) | Detection model | HuggingFace |
:::note
The default CPU, EdgeTPU, and OpenVINO object detection models are bundled into the Docker image and do not require any download at runtime.
:::
### Preventing Model Downloads
If you have already downloaded all required models and want to prevent Frigate from attempting any outbound connections to HuggingFace or the Transformers library, set the following environment variables on your Frigate container:
```yaml
environment:
HF_HUB_OFFLINE: "1"
TRANSFORMERS_OFFLINE: "1"
```
:::warning
Setting these variables without having the correct model files already cached in `/config/model_cache/` will cause failures. Only use these after a successful initial setup with internet access.
:::
### Mirror Support
If your Frigate instance has restricted internet access, you can point model downloads at internal mirrors using environment variables:
| Environment Variable | Default | Used By |
| ----------------------------------- | ----------------------------------- | --------------------------------------------- |
| `HF_ENDPOINT` | `https://huggingface.co` | Semantic search, Sherpa-ONNX, AXEngine models |
| `GITHUB_ENDPOINT` | `https://github.com` | Face recognition, LPR, RKNN models |
| `GITHUB_RAW_ENDPOINT` | `https://raw.githubusercontent.com` | Bird classification |
| `TF_KERAS_MOBILENET_V2_WEIGHTS_URL` | Google storage (Keras default) | Custom classification training |
## Optional Cloud Services
These features connect to external services during normal operation and require internet whenever they are active.
### Frigate+
When a Frigate+ API key is configured, Frigate communicates with `https://api.frigate.video` to download models, upload snapshots for training, submit annotations, and report false positives. Remove the API key to disable all Frigate+ network activity.
See [Frigate+](/integrations/plus) for details.
### Generative AI
When a Generative AI provider is configured, Frigate sends images and prompts to the configured provider for event descriptions, chat, and camera monitoring. Available providers:
| Provider | Internet Required |
| ------------- | ---------------------------------------------------------------- |
| OpenAI | Yes — connects to OpenAI API (or custom base URL) |
| Google Gemini | Yes — connects to Google Generative AI API |
| Azure OpenAI | Yes — connects to your Azure endpoint |
| Ollama | Depends — typically local (`localhost:11434`), but can be remote |
| llama.cpp | No — runs entirely locally |
Disable Generative AI by removing the `genai` configuration from your cameras. See [Generative AI](/configuration/genai/genai_config) for details.
### Version Check
Frigate checks GitHub for the latest release version on startup by querying `https://api.github.com`. This can be disabled:
```yaml
telemetry:
version_check: false
```
### Push Notifications
When [notifications](/configuration/notifications) are enabled and users have registered for push notifications in the web UI, Frigate sends push messages through the browser vendor's push service (e.g., Google FCM, Mozilla autopush). This requires internet access from the Frigate server to these push endpoints.
### MQTT
If an [MQTT broker](/integrations/mqtt) is configured, Frigate maintains a connection to the broker's host and port. This is typically a local network connection, but will require internet if you use a cloud-hosted MQTT broker.
### DeepStack / CodeProject.AI
When using the [DeepStack detector plugin](/configuration/object_detectors), Frigate sends images to the configured API endpoint for inference. This is typically local but depends on where the service is hosted.
## WebRTC (STUN)
For [WebRTC live streaming](/configuration/live), Frigate uses STUN for NAT traversal:
- **go2rtc** defaults to a local STUN listener (`stun:8555`) — no internet required.
- **The web UI's WebRTC player** includes a fallback to Google's public STUN server (`stun:stun.l.google.com:19302`), which requires internet.
## Home Assistant Supervisor
When running as a Home Assistant add-on, the go2rtc startup script queries the local Supervisor API (`http://supervisor/`) to discover the host IP address and WebRTC port. This is a local network call to the Home Assistant host, not an internet connection.
## What Does NOT Require Internet
- **Object detection** — CPU, EdgeTPU, OpenVINO, and other bundled detector models are included in the Docker image.
- **Recording and playback** — All video is stored and served locally.
- **Live streaming** — Camera streams are pulled over your local network. MSE and HLS streaming work without any external connections.
- **The web interface** — Fully self-contained with no external fonts, scripts, analytics, or CDN dependencies. All translations are bundled locally.
- **Custom classification inference** — After training, custom models run entirely locally.
- **Audio detection** — The YAMNet audio classification model is bundled in the Docker image.
## Running Frigate Offline
To run Frigate in an air-gapped or offline environment:
1. **Pre-download models** — Start Frigate with internet access once with all desired features enabled. Models will be cached in `/config/model_cache/`.
2. **Disable version check** — Set `telemetry.version_check: false` in your configuration.
3. **Block outbound model requests** — Set the `HF_HUB_OFFLINE=1` and `TRANSFORMERS_OFFLINE=1` environment variables to prevent HuggingFace and Transformers from attempting any network requests.
4. **Avoid cloud features** — Do not configure Frigate+, Generative AI providers that require internet, or cloud MQTT brokers.
5. **Use local model mirrors** — If limited internet is available, set the `HF_ENDPOINT`, `GITHUB_ENDPOINT`, and `GITHUB_RAW_ENDPOINT` environment variables to point to local mirrors.
After these steps, Frigate will operate with no outbound internet connections.
+8 -7
View File
@@ -5,7 +5,7 @@ title: Updating
# Updating Frigate
The current stable version of Frigate is **0.17.0**. The release notes and any breaking changes for this version can be found on the [Frigate GitHub releases page](https://github.com/blakeblackshear/frigate/releases/tag/v0.17.0).
The current stable version of Frigate is **0.18.0**. The release notes and any breaking changes for this version can be found on the [Frigate GitHub releases page](https://github.com/blakeblackshear/frigate/releases/tag/v0.18.0).
Keeping Frigate up to date ensures you benefit from the latest features, performance improvements, and bug fixes. The update process varies slightly depending on your installation method (Docker, Home Assistant App, etc.). Below are instructions for the most common setups.
@@ -31,21 +31,21 @@ If youre running Frigate via Docker (recommended method), follow these steps:
2. **Update and Pull the Latest Image**:
- If using Docker Compose:
- Edit your `docker-compose.yml` file to specify the desired version tag (e.g., `0.17.0` instead of `0.16.4`). For example:
- Edit your `docker-compose.yml` file to specify the desired version tag (e.g., `0.18.0` instead of `0.17.1`). For example:
```yaml
services:
frigate:
image: ghcr.io/blakeblackshear/frigate:0.17.0
image: ghcr.io/blakeblackshear/frigate:0.18.0
```
- Then pull the image:
```bash
docker pull ghcr.io/blakeblackshear/frigate:0.17.0
docker pull ghcr.io/blakeblackshear/frigate:0.18.0
```
- **Note for `stable` Tag Users**: If your `docker-compose.yml` uses the `stable` tag (e.g., `ghcr.io/blakeblackshear/frigate:stable`), you dont need to update the tag manually. The `stable` tag always points to the latest stable release after pulling.
- If using `docker run`:
- Pull the image with the appropriate tag (e.g., `0.17.0`, `0.17.0-tensorrt`, or `stable`):
- Pull the image with the appropriate tag (e.g., `0.18.0`, `0.18.0-tensorrt`, or `stable`):
```bash
docker pull ghcr.io/blakeblackshear/frigate:0.17.0
docker pull ghcr.io/blakeblackshear/frigate:0.18.0
```
3. **Start the Container**:
@@ -77,6 +77,7 @@ For users running Frigate as a Home Assistant App:
- If an update is available, youll see an "Update" button.
2. **Update the App**:
- Make a backup of the current version of the app.
- Click the "Update" button next to the Frigate app.
- Wait for the process to complete. Home Assistant will handle downloading and installing the new version.
@@ -99,7 +100,7 @@ If an update causes issues:
1. Stop Frigate.
2. Restore your backed-up config file and database.
3. Revert to the previous image version:
- For Docker: Specify an older tag (e.g., `ghcr.io/blakeblackshear/frigate:0.16.4`) in your `docker run` command.
- For Docker: Specify an older tag (e.g., `ghcr.io/blakeblackshear/frigate:0.17.1`) in your `docker run` command.
- For Docker Compose: Edit your `docker-compose.yml`, specify the older version tag (e.g., `ghcr.io/blakeblackshear/frigate:0.16.4`), and re-run `docker compose up -d`.
- For Home Assistant: Restore from the app/addon backup you took before you updated.
4. Verify the old version is running again.
+1 -1
View File
@@ -17,7 +17,7 @@ First, you will want to configure go2rtc to connect to your camera stream by add
For the best experience, you should set the stream name under `go2rtc` to match the name of your camera so that Frigate will automatically map it and be able to use better live view options for the camera.
See [the live view docs](../configuration/live.md#setting-stream-for-live-ui) for more information.
See [the live view docs](../configuration/live.md#setting-streams-for-live-ui) for more information.
:::
+76 -13
View File
@@ -3,6 +3,10 @@ id: getting_started
title: Getting started
---
import ConfigTabs from "@site/src/components/ConfigTabs";
import TabItem from "@theme/TabItem";
import NavPath from "@site/src/components/NavPath";
# Getting Started
:::tip
@@ -85,7 +89,7 @@ This section shows how to create a minimal directory structure for a Docker inst
### Setup directories
Frigate will create a config file if one does not exist on the initial startup. The following directory structure is the bare minimum to get started. Once Frigate is running, you can use the built-in config editor which supports config validation.
Frigate will create a config file if one does not exist on the initial startup. The following directory structure is the bare minimum to get started.
```
.
@@ -128,7 +132,7 @@ services:
- "8554:8554" # RTSP feeds
```
Now you should be able to start Frigate by running `docker compose up -d` from within the folder containing `docker-compose.yml`. On startup, an admin user and password will be created and outputted in the logs. You can see this by running `docker logs frigate`. Frigate should now be accessible at `https://server_ip:8971` where you can login with the `admin` user and finish the configuration using the built-in configuration editor.
Now you should be able to start Frigate by running `docker compose up -d` from within the folder containing `docker-compose.yml`. On startup, an admin user and password will be created and outputted in the logs. You can see this by running `docker logs frigate`. Frigate should now be accessible at `https://server_ip:8971` where you can login with the `admin` user and finish configuration using the Settings UI.
## Configuring Frigate
@@ -140,15 +144,15 @@ At this point you should be able to start Frigate and a basic config will be cre
### Step 2: Add a camera
You can click the `Add Camera` button to use the camera setup wizard to get your first camera added into Frigate.
Click the **Add Camera** button in <NavPath path="Settings > Camera configuration > Management" /> to use the camera setup wizard to get your first camera added into Frigate.
### Step 3: Configure hardware acceleration (recommended)
Now that you have a working camera configuration, you want to setup hardware acceleration to minimize the CPU required to decode your video streams. See the [hardware acceleration](../configuration/hardware_acceleration_video.md) config reference for examples applicable to your hardware.
Now that you have a working camera configuration, set up hardware acceleration to minimize the CPU required to decode your video streams. See the [hardware acceleration](../configuration/hardware_acceleration_video.md) docs for examples applicable to your hardware.
Here is an example configuration with hardware acceleration configured to work with most Intel processors with an integrated GPU using the [preset](../configuration/ffmpeg_presets.md):
:::note
`docker-compose.yml` (after modifying, you will need to run `docker compose up -d` to apply changes)
Hardware acceleration requires passing the appropriate device to the Docker container. For Intel and AMD GPUs, add the device to your `docker-compose.yml`:
```yaml {4,5}
services:
@@ -159,7 +163,17 @@ services:
...
```
`config.yml`
After modifying, run `docker compose up -d` to apply changes.
:::
<ConfigTabs>
<TabItem value="ui">
Navigate to <NavPath path="Settings > Global configuration > FFmpeg" /> and set **Hardware acceleration arguments** to the appropriate preset for your hardware (e.g., `VAAPI (Intel/AMD GPU)` for most Intel processors).
</TabItem>
<TabItem value="yaml">
```yaml
mqtt: ...
@@ -173,6 +187,9 @@ cameras:
detect: ...
```
</TabItem>
</ConfigTabs>
### Step 4: Configure detectors
By default, Frigate will use a single CPU detector.
@@ -184,6 +201,24 @@ In many cases, the integrated graphics on Intel CPUs provides sufficient perform
You need to refer to **Configure hardware acceleration** above to enable the container to use the GPU.
<ConfigTabs>
<TabItem value="ui">
1. Navigate to <NavPath path="Settings > System > Detector hardware" /> and add a detector with **Type** `OpenVINO` and **Device** `GPU`
2. Navigate to <NavPath path="Settings > System > Detection model" /> and configure the model settings for OpenVINO:
| Field | Value |
| ---------------------------------------- | ------------------------------------------ |
| **Object detection model input width** | `300` |
| **Object detection model input height** | `300` |
| **Model Input Tensor Shape** | `nhwc` |
| **Model Input Pixel Color Format** | `bgr` |
| **Custom object detector model path** | `/openvino-model/ssdlite_mobilenet_v2.xml` |
| **Label map for custom object detector** | `/openvino-model/coco_91cl_bkgr.txt` |
</TabItem>
<TabItem value="yaml">
```yaml {3-6,9-15,20-21}
mqtt: ...
@@ -209,6 +244,9 @@ cameras:
...
```
</TabItem>
</ConfigTabs>
</details>
If you have a USB Coral, you will need to add a detectors section to your config.
@@ -216,7 +254,9 @@ If you have a USB Coral, you will need to add a detectors section to your config
<details>
<summary>Use USB Coral detector</summary>
`docker-compose.yml` (after modifying, you will need to run `docker compose up -d` to apply changes)
:::note
You need to pass the USB Coral device to the Docker container. Add the following to your `docker-compose.yml` and run `docker compose up -d`:
```yaml {4-6}
services:
@@ -228,6 +268,16 @@ services:
...
```
:::
<ConfigTabs>
<TabItem value="ui">
Navigate to <NavPath path="Settings > System > Detector hardware" /> and add a detector with **Type** `EdgeTPU` and **Device** `usb`.
</TabItem>
<TabItem value="yaml">
```yaml {3-6,11-12}
mqtt: ...
@@ -244,17 +294,20 @@ cameras:
...
```
</TabItem>
</ConfigTabs>
</details>
More details on available detectors can be found [here](../configuration/object_detectors.md).
Restart Frigate and you should start seeing detections for `person`. If you want to track other objects, they will need to be added according to the [configuration file reference](../configuration/reference.md).
Restart Frigate and you should start seeing detections for `person`. If you want to track other objects, they can be configured in <NavPath path="Settings > Global configuration > Objects" /> or via the [configuration file reference](../configuration/reference.md).
### Step 5: Setup motion masks
Now that you have optimized your configuration for decoding the video stream, you will want to check to see where to implement motion masks. To do this, navigate to the camera in the UI, select "Debug" at the top, and enable "Motion boxes" in the options below the video feed. Watch for areas that continuously trigger unwanted motion to be detected. Common areas to mask include camera timestamps and trees that frequently blow in the wind. The goal is to avoid wasting object detection cycles looking at these areas.
Now that you have optimized your configuration for decoding the video stream, you will want to check to see where to implement motion masks. Click on the camera from the main dashboard, then select the gear icon in the top right, enable Debug View, and finally enable the switch for Motion Boxes. Watch for areas that continuously trigger unwanted motion to be detected. Common areas to mask include camera timestamps and trees that frequently blow in the wind. The goal is to avoid wasting object detection cycles looking at these areas.
Now that you know where you need to mask, use the "Mask & Zone creator" in the options pane to generate the coordinates needed for your config file. More information about masks can be found [here](../configuration/masks.md).
Use the mask editor to draw polygon masks directly on the camera feed. Navigate to <NavPath path="Settings > Camera configuration > Masks / Zones" /> and set up a motion mask over the area. More information about masks can be found [here](../configuration/masks.md).
:::warning
@@ -262,7 +315,7 @@ Note that motion masks should not be used to mark out areas where you do not wan
:::
Your configuration should look similar to this now.
If you are using YAML to configure Frigate instead of the UI, your configuration should look similar to this now:
```yaml {16-18}
mqtt:
@@ -292,7 +345,14 @@ cameras:
In order to review activity in the Frigate UI, recordings need to be enabled.
To enable recording video, add the `record` role to a stream and enable it in the config. If record is disabled in the config, it won't be possible to enable it in the UI.
<ConfigTabs>
<TabItem value="ui">
1. If you have separate streams for detect and record, navigate to <NavPath path="Settings > Camera configuration > FFmpeg" />, select your camera, and add a second input with the `record` role pointing to your high-resolution stream
2. Navigate to <NavPath path="Settings > Global configuration > Recording" /> (or <NavPath path="Settings > Camera configuration > Recording" /> for a specific camera) and set **Enable recording** to on
</TabItem>
<TabItem value="yaml">
```yaml {16-17}
mqtt: ...
@@ -315,6 +375,9 @@ cameras:
motion: ...
```
</TabItem>
</ConfigTabs>
If you don't have separate streams for detect and record, you would just add the record role to the list on the first input.
:::note
+6
View File
@@ -5,6 +5,12 @@ title: MQTT
These are the MQTT messages generated by Frigate. The default topic_prefix is `frigate`, but can be changed in the config file.
:::info
MQTT requires a network connection to your broker. This is typically local, but will require internet if using a cloud-hosted MQTT broker. See [Network Requirements](/frigate/network_requirements#mqtt) for details.
:::
## General Frigate Topics
### `frigate/available`
+6
View File
@@ -5,6 +5,12 @@ title: Frigate+
For more information about how to use Frigate+ to improve your model, see the [Frigate+ docs](/plus/).
:::info
Frigate+ requires an active internet connection to communicate with `https://api.frigate.video` for model downloads, image uploads, and annotations. See [Network Requirements](/frigate/network_requirements#frigate) for details.
:::
## Setup
### Create an account
@@ -17,6 +17,10 @@ Please use your own knowledge to assess and vet them before you install anything
The [Advanced Camera Card](https://card.camera/#/README) is a Home Assistant dashboard card with deep Frigate integration.
## [cctvQL](https://github.com/arunrajiah/cctvql)
[cctvQL](https://github.com/arunrajiah/cctvql) is a natural language query layer for Frigate and other CCTV systems. It connects to Frigate's REST API and MQTT broker to let you ask conversational questions about cameras and events (e.g. "Was there motion at the front door last night?"), with support for real-time event streaming, anomaly detection, PTZ control, alert rules, and a Home Assistant custom component.
## [Double Take](https://github.com/skrashevich/double-take)
[Double Take](https://github.com/skrashevich/double-take) provides an unified UI and API for processing and training images for facial recognition.
@@ -35,6 +39,10 @@ This is a fork (with fixed errors and new features) of [original Double Take](ht
[Frigate telegram](https://github.com/OldTyT/frigate-telegram) makes it possible to send events from Frigate to Telegram. Events are sent as a message with a text description, video, and thumbnail.
## [kiosk-monitor](https://github.com/extremeshok/kiosk-monitor)
[kiosk-monitor](https://github.com/extremeshok/kiosk-monitor) is a Raspberry Pi watchdog that runs Chromium fullscreen on a Frigate dashboard (optionally with VLC on a second monitor for an RTSP camera stream), auto-restarts on frozen screens or unreachable URLs, and ships a Birdseye-aware Chromium helper that auto-sizes the grid to the display.
## [Periscope](https://github.com/maksz42/periscope)
[Periscope](https://github.com/maksz42/periscope) is a lightweight Android app that turns old devices into live viewers for Frigate. It works on Android 2.2 and above, including Android TV. It supports authentication and HTTPS.
+14
View File
@@ -110,3 +110,17 @@ No. Frigate uses the TCP protocol to connect to your camera's RTSP URL. VLC auto
TCP ensures that all data packets arrive in the correct order. This is crucial for video recording, decoding, and stream processing, which is why Frigate enforces a TCP connection. UDP is faster but less reliable, as it does not guarantee packet delivery or order, and VLC does not have the same requirements as Frigate.
You can still configure Frigate to use UDP by using ffmpeg input args or the preset `preset-rtsp-udp`. See the [ffmpeg presets](/configuration/ffmpeg_presets) documentation.
### Frigate is slow to start up with a "probing detect stream" message in the logs
When `detect.width` and `detect.height` are not set, Frigate probes each camera's detect stream on startup (and when saving the config) to auto-detect its resolution. For RTSP streams Frigate probes with ffprobe and automatically retries over TCP if UDP doesn't respond, with a 5 second timeout per attempt. A camera that cannot be reached over either transport will add up to ~10 seconds to startup before Frigate falls through with default dimensions, which may show up as width `0` and height `0` in Camera Probe Info under System Metrics.
To skip the probe entirely and make startup instant, set `detect.width` and `detect.height` explicitly in your camera config:
```yaml
cameras:
my_camera:
detect:
width: 1280
height: 720
```
+82
View File
@@ -80,3 +80,85 @@ Some users found that mounting a drive via `fstab` with the `sync` option caused
#### Copy Times < 1 second
If the storage is working quickly then this error may be caused by CPU load on the machine being too high for Frigate to have the resources to keep up. Try temporarily shutting down other services to see if the issue improves.
## I see the message: WARNING : Too many unprocessed recording segments in cache for camera. This likely indicates an issue with the detect stream...
This warning means that the detect stream for the affected camera has fallen behind or stopped processing frames. Frigate's recording cache holds segments waiting to be analyzed by the detector — when more than 6 segments pile up without being processed, Frigate discards the oldest ones to prevent the cache from filling up.
:::warning
This error is a **symptom**, not the root cause. The actual cause is always logged **before** these messages start appearing. You must review the full logs from Frigate startup through the first occurrence of this warning to identify the real issue.
:::
### Step 1: Get the full logs
Collect complete Frigate logs from startup through the first occurrence of the error. Look for errors or warnings that appear **before** the "Too many unprocessed" messages begin — that is where the root cause will be found.
### Step 2: Check the cache directory
Exec into the Frigate container and inspect the recording cache:
```
docker exec -it frigate ls -la /tmp/cache
```
Each camera should have a small number of `.mp4` segment files. If one camera has significantly more files than others, that camera is the source of the problem. A problem with a single camera can cascade and cause all cameras to show this error.
### Step 3: Verify segment duration
Recording segments should be approximately 10 seconds long. Run `ffprobe` on segments in the cache to check:
```
docker exec -it frigate ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1 /tmp/cache/<camera>@<segment>.mp4
```
If segments are only ~1 second instead of ~10 seconds, the camera is sending corrupt timestamp data, causing segments to be split too frequently and filling the cache 10x faster than expected.
**Common causes of short segments:**
- **"Smart Codec" or "Smart+" enabled on the camera** — These features dynamically change encoding parameters mid-stream, which corrupts timestamps. Disable them in your camera's settings.
- **Changing codec, bitrate, or resolution mid-stream** — Any encoding changes during an active stream can cause unpredictable segment splitting.
- **Camera firmware bugs** — Check for firmware updates from your camera manufacturer.
### Step 4: Check for a stuck detector
If the detect stream is not processing frames, segments will accumulate. Common causes:
- **Detection resolution too high** — Use a substream for detection, not the full resolution main stream.
- **Detection FPS too high** — 5 fps is the recommended maximum for detection.
- **Model too large** — Use smaller model variants (e.g., YOLO `s` or `t` size, not `e` or `x`). Use 320x320 input size rather than 640x640 unless you have a powerful dedicated detector.
- **Virtualization** — Running Frigate in a VM (especially Proxmox) can cause the detector to hang or stall. This is a known issue with GPU/TPU passthrough in virtualized environments and is not something Frigate can fix. Running Frigate in Docker on bare metal is recommended.
### Step 5: Check for GPU hangs
On the host machine, check `dmesg` for GPU-related errors:
```
dmesg | grep -i -E "gpu|drm|reset|hang"
```
Messages like `trying reset from guc_exec_queue_timedout_job` or similar GPU reset/hang messages indicate a driver or hardware issue. Ensure your kernel and GPU drivers (especially Intel) are up to date.
### Step 6: Verify hardware acceleration configuration
An incorrect `hwaccel_args` preset can cause ffmpeg to fail silently or consume excessive CPU, starving the detector of resources.
- After upgrading Frigate, verify your preset matches your hardware (e.g., `preset-intel-qsv-h264` instead of the deprecated `preset-vaapi`).
- For h265 cameras, use the corresponding h265 preset (e.g., `preset-intel-qsv-h265`).
- Note that `hwaccel_args` are only relevant for the detect stream — Frigate does not decode the record stream.
### Step 7: Verify go2rtc stream configuration
Ensure that the ffmpeg source names in your go2rtc configuration match the correct camera stream. A misconfigured stream name (e.g., copying a config from one camera to another without updating the stream reference) will cause the wrong stream to be used or the stream to fail entirely.
### Step 8: Check system resources
If none of the above apply, the issue may be a general resource constraint. Monitor the following on your host:
- **CPU usage** — An overloaded CPU can prevent the detector from keeping up.
- **RAM and swap** — Excessive swapping dramatically slows all I/O operations.
- **Disk I/O** — Use `iotop` or `iostat` to check for saturation.
- **Storage space** — Verify you have free space on the Frigate storage volume (check the Storage page in the Frigate UI).
Try temporarily disabling resource-intensive features like `genai` and `face_recognition` to see if the issue resolves. This can help isolate whether the detector is being starved of resources.
+3 -3
View File
@@ -10897,9 +10897,9 @@
"license": "MIT"
},
"node_modules/express/node_modules/path-to-regexp": {
"version": "0.1.12",
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz",
"integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==",
"version": "0.1.13",
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.13.tgz",
"integrity": "sha512-A/AGNMFN3c8bOlvV9RreMdrv7jsmF9XIfDeCd87+I8RNg6s78BhJxMu69NEMHBSJFxKidViTEdruRwEk/WIKqA==",
"license": "MIT"
},
"node_modules/express/node_modules/range-parser": {
+184
View File
@@ -0,0 +1,184 @@
# Documentation Scripts
## generate_ui_tabs.py
Automatically generates "Frigate UI" tab content for documentation files based on the YAML config examples already in the docs.
Instead of manually writing UI instructions for every YAML block, this script reads three data sources from the codebase and generates the UI tabs:
1. **JSON Schema** (from Pydantic config models) -- field names, types, defaults
2. **i18n translation files** -- the exact labels shown in the Settings UI
3. **Section mappings** (from Settings.tsx) -- config key to UI navigation path
### Prerequisites
Run from the repository root. The script imports Frigate's Python config models directly, so the `frigate` package must be importable:
```bash
# From repo root -- no extra install needed if your environment can import frigate
python3 docs/scripts/generate_ui_tabs.py --help
```
### Usage
#### Preview (default)
Shows what would be generated for each bare YAML block, without modifying any files:
```bash
# Single file
python3 docs/scripts/generate_ui_tabs.py docs/docs/configuration/record.md
# All config docs
python3 docs/scripts/generate_ui_tabs.py docs/docs/configuration/
```
#### Inject
Wraps bare YAML blocks with `<ConfigTabs>` and inserts the generated UI tab. Also adds the required imports (`ConfigTabs`, `TabItem`, `NavPath`) after the frontmatter if missing.
Already-wrapped blocks are skipped (idempotent).
```bash
python3 docs/scripts/generate_ui_tabs.py --inject docs/docs/configuration/record.md
```
#### Check
Compares existing UI tabs against what the script would generate from the current schema and i18n files. Prints a unified diff for each drifted block and exits with code 1 if any drift is found.
Use this in CI to catch stale docs after schema or i18n changes.
```bash
python3 docs/scripts/generate_ui_tabs.py --check docs/docs/configuration/
```
#### Regenerate
Replaces the UI tab content in existing `<ConfigTabs>` blocks with freshly generated content. The YAML tab is preserved exactly as-is. Only blocks that have actually changed are rewritten.
```bash
# Preview changes without writing
python3 docs/scripts/generate_ui_tabs.py --regenerate --dry-run docs/docs/configuration/
# Apply changes
python3 docs/scripts/generate_ui_tabs.py --regenerate docs/docs/configuration/
```
#### Output to directory (`--outdir`)
Write generated files to a separate directory instead of modifying the originals. The source directory structure is mirrored. Files without changes are copied as-is so the output is a complete snapshot suitable for diffing.
Works with `--inject` and `--regenerate`.
```bash
# Generate into a named directory
python3 docs/scripts/generate_ui_tabs.py --inject --outdir /tmp/generated docs/docs/configuration/
# Then diff original vs generated
diff -rq docs/docs/configuration/ /tmp/generated/
# Or let an AI agent compare them
diff -ru docs/docs/configuration/record.md /tmp/generated/record.md
```
This is useful for AI agents that need to review the generated output before applying it, or for previewing what `--inject` or `--regenerate` would do across an entire directory.
#### Verbose mode
Add `-v` to any mode for detailed diagnostics (skipped blocks, reasons, unchanged blocks):
```bash
python3 docs/scripts/generate_ui_tabs.py -v docs/docs/configuration/
```
### Typical workflow
```bash
# 1. Preview what would be generated (output to temp dir, originals untouched)
python3 docs/scripts/generate_ui_tabs.py --inject --outdir /tmp/ui-preview docs/docs/configuration/
# Compare: diff -ru docs/docs/configuration/ /tmp/ui-preview/
# 2. Apply: inject UI tabs into the actual docs
python3 docs/scripts/generate_ui_tabs.py --inject docs/docs/configuration/
# 3. Review and hand-edit where needed (the script gets you 90% there)
# 4. Later, after schema or i18n changes, check for drift
python3 docs/scripts/generate_ui_tabs.py --check docs/docs/configuration/
# 5. If drifted, preview then regenerate
python3 docs/scripts/generate_ui_tabs.py --regenerate --outdir /tmp/ui-regen docs/docs/configuration/
# Compare: diff -ru docs/docs/configuration/ /tmp/ui-regen/
# 6. Apply regeneration
python3 docs/scripts/generate_ui_tabs.py --regenerate docs/docs/configuration/
```
### How it decides what to generate
The script detects two patterns from the YAML block content:
**Pattern A -- Field table.** When the YAML has inline comments (e.g., `# <- description`), the script generates a markdown table with field names and descriptions:
```markdown
Navigate to <NavPath path="Settings > Global configuration > Recording" />.
| Field | Description |
|-------|-------------|
| **Continuous retention > Retention days** | Days to retain recordings. |
| **Motion retention > Retention days** | Days to retain recordings. |
```
**Pattern B -- Set instructions.** When the YAML has concrete values without comments, the script generates step-by-step instructions:
```markdown
Navigate to <NavPath path="Settings > Global configuration > Recording" />.
- Set **Enable recording** to on
- Set **Continuous retention > Retention days** to `3`
- Set **Alert retention > Event retention > Retention days** to `30`
- Set **Alert retention > Event retention > Retention mode** to `all`
```
**Camera-level config** is auto-detected when the YAML is nested under `cameras:`. The output uses a generic camera reference rather than the example camera name from the YAML:
```markdown
1. Navigate to <NavPath path="Settings > Camera configuration > Recording" /> and select your camera.
- Set **Enable recording** to on
- Set **Continuous retention > Retention days** to `5`
```
### What gets skipped
- YAML blocks already inside `<ConfigTabs>` (for `--inject`)
- YAML blocks whose top-level key is not a known config section (e.g., `go2rtc`, `docker-compose`, `scrape_configs`)
- Fields listed in `hiddenFields` in the section configs (e.g., `enabled_in_config`)
### File structure
```
docs/scripts/
├── generate_ui_tabs.py # CLI entry point
├── README.md # This file
└── lib/
├── __init__.py
├── schema_loader.py # Loads JSON schema from Pydantic models
├── i18n_loader.py # Loads i18n translation JSON files
├── section_config_parser.py # Parses TS section configs (hiddenFields, etc.)
├── yaml_extractor.py # Extracts YAML blocks and ConfigTabs from markdown
├── ui_generator.py # Generates UI tab markdown content
└── nav_map.py # Maps config sections to Settings UI nav paths
```
### Data sources
| Source | Path | What it provides |
|--------|------|------------------|
| Pydantic models | `frigate/config/` | Field names, types, defaults, nesting |
| JSON schema | Generated from Pydantic at runtime | Full schema with `$defs` and `$ref` |
| i18n (global) | `web/public/locales/en/config/global.json` | Field labels for global settings |
| i18n (cameras) | `web/public/locales/en/config/cameras.json` | Field labels for camera settings |
| i18n (menu) | `web/public/locales/en/views/settings.json` | Sidebar menu labels |
| Section configs | `web/src/components/config-form/section-configs/*.ts` | Hidden fields, advanced fields, field order |
| Navigation map | Hardcoded from `web/src/pages/Settings.tsx` | Config section to UI path mapping |
+660
View File
@@ -0,0 +1,660 @@
#!/usr/bin/env python3
"""Generate Frigate UI tab content for documentation files.
This script reads YAML code blocks from documentation markdown files and
generates corresponding "Frigate UI" tab instructions based on:
- JSON Schema (from Pydantic config models)
- i18n translation files (for UI field labels)
- Section configs (for hidden/advanced field info)
- Navigation mappings (for Settings UI paths)
Usage:
# Preview generated UI tabs for a single file
python docs/scripts/generate_ui_tabs.py docs/docs/configuration/record.md
# Preview all config docs
python docs/scripts/generate_ui_tabs.py docs/docs/configuration/
# Inject UI tabs into files (wraps bare YAML blocks with ConfigTabs)
python docs/scripts/generate_ui_tabs.py --inject docs/docs/configuration/record.md
# Regenerate existing UI tabs from current schema/i18n
python docs/scripts/generate_ui_tabs.py --regenerate docs/docs/configuration/
# Check for drift between existing UI tabs and what would be generated
python docs/scripts/generate_ui_tabs.py --check docs/docs/configuration/
# Write generated files to a temp directory for comparison (originals unchanged)
python docs/scripts/generate_ui_tabs.py --inject --outdir /tmp/generated docs/docs/configuration/
# Show detailed warnings and diagnostics
python docs/scripts/generate_ui_tabs.py --verbose docs/docs/configuration/
"""
import argparse
import difflib
import shutil
import sys
import tempfile
from pathlib import Path
# Ensure frigate package is importable
sys.path.insert(0, str(Path(__file__).resolve().parents[1].parent))
from lib.i18n_loader import load_i18n
from lib.nav_map import ALL_CONFIG_SECTIONS
from lib.schema_loader import load_schema
from lib.section_config_parser import load_section_configs
from lib.ui_generator import generate_ui_content, wrap_with_config_tabs
from lib.yaml_extractor import (
extract_config_tabs_blocks,
extract_yaml_blocks,
)
def process_file(
filepath: Path,
schema: dict,
i18n: dict,
section_configs: dict,
inject: bool = False,
verbose: bool = False,
outpath: Path | None = None,
) -> dict:
"""Process a single markdown file for initial injection of bare YAML blocks.
Args:
outpath: If set, write the result here instead of modifying filepath.
Returns:
Stats dict with counts of blocks found, generated, skipped, etc.
"""
content = filepath.read_text()
blocks = extract_yaml_blocks(content)
stats = {
"file": str(filepath),
"total_blocks": len(blocks),
"config_blocks": 0,
"already_wrapped": 0,
"generated": 0,
"skipped": 0,
"warnings": [],
}
if not blocks:
return stats
# For injection, we need to track replacements
replacements: list[tuple[int, int, str]] = []
for block in blocks:
# Skip non-config YAML blocks
if block.section_key is None or (
block.section_key not in ALL_CONFIG_SECTIONS
and not block.is_camera_level
):
stats["skipped"] += 1
if verbose and block.config_keys:
stats["warnings"].append(
f" Line {block.line_start}: Skipped block with keys "
f"{block.config_keys} (not a known config section)"
)
continue
stats["config_blocks"] += 1
# Skip already-wrapped blocks
if block.inside_config_tabs:
stats["already_wrapped"] += 1
if verbose:
stats["warnings"].append(
f" Line {block.line_start}: Already inside ConfigTabs, skipping"
)
continue
# Generate UI content
ui_content = generate_ui_content(
block, schema, i18n, section_configs
)
if ui_content is None:
stats["skipped"] += 1
if verbose:
stats["warnings"].append(
f" Line {block.line_start}: Could not generate UI content "
f"for section '{block.section_key}'"
)
continue
stats["generated"] += 1
if inject:
full_block = wrap_with_config_tabs(
ui_content, block.raw, block.highlight
)
replacements.append((block.line_start, block.line_end, full_block))
else:
# Preview mode: print to stdout
print(f"\n{'='*60}")
print(f"File: {filepath}")
print(f"Line {block.line_start}: section={block.section_key}, "
f"camera={block.is_camera_level}")
print(f"{'='*60}")
print()
print("--- Generated UI tab ---")
print(ui_content)
print()
print("--- Would produce ---")
print(wrap_with_config_tabs(ui_content, block.raw, block.highlight))
print()
# Apply injections in reverse order (to preserve line numbers)
if inject and replacements:
lines = content.split("\n")
for start, end, replacement in reversed(replacements):
# start/end are 1-based line numbers
# The YAML block spans from the ``` line before start to the ``` line at end
# We need to replace from the opening ``` to the closing ```
block_start = start - 2 # 0-based index of ```yaml line
block_end = end - 1 # 0-based index of closing ``` line
replacement_lines = replacement.split("\n")
lines[block_start : block_end + 1] = replacement_lines
new_content = "\n".join(lines)
# Ensure imports are present
new_content = _ensure_imports(new_content)
target = outpath or filepath
target.parent.mkdir(parents=True, exist_ok=True)
target.write_text(new_content)
print(f" Injected {len(replacements)} ConfigTabs block(s) into {target}")
elif outpath is not None:
# No changes but outdir requested -- copy original so the output
# directory contains a complete set of files for diffing.
outpath.parent.mkdir(parents=True, exist_ok=True)
shutil.copy2(filepath, outpath)
return stats
def regenerate_file(
filepath: Path,
schema: dict,
i18n: dict,
section_configs: dict,
dry_run: bool = False,
verbose: bool = False,
outpath: Path | None = None,
) -> dict:
"""Regenerate UI tabs in existing ConfigTabs blocks.
Strips the current UI tab content and regenerates it from the YAML tab
using the current schema and i18n data.
Args:
outpath: If set, write the result here instead of modifying filepath.
Returns:
Stats dict
"""
content = filepath.read_text()
tab_blocks = extract_config_tabs_blocks(content)
stats = {
"file": str(filepath),
"total_blocks": len(tab_blocks),
"regenerated": 0,
"unchanged": 0,
"skipped": 0,
"warnings": [],
}
if not tab_blocks:
return stats
replacements: list[tuple[int, int, str]] = []
for tab_block in tab_blocks:
yaml_block = tab_block.yaml_block
# Skip non-config blocks
if yaml_block.section_key is None or (
yaml_block.section_key not in ALL_CONFIG_SECTIONS
and not yaml_block.is_camera_level
):
stats["skipped"] += 1
if verbose:
stats["warnings"].append(
f" Line {tab_block.line_start}: Skipped (not a config section)"
)
continue
# Generate fresh UI content
new_ui = generate_ui_content(
yaml_block, schema, i18n, section_configs
)
if new_ui is None:
stats["skipped"] += 1
if verbose:
stats["warnings"].append(
f" Line {tab_block.line_start}: Could not regenerate "
f"for section '{yaml_block.section_key}'"
)
continue
# Compare with existing
existing_ui = tab_block.ui_content
if _normalize_whitespace(new_ui) == _normalize_whitespace(existing_ui):
stats["unchanged"] += 1
if verbose:
stats["warnings"].append(
f" Line {tab_block.line_start}: Unchanged"
)
continue
stats["regenerated"] += 1
new_full = wrap_with_config_tabs(
new_ui, yaml_block.raw, yaml_block.highlight
)
replacements.append(
(tab_block.line_start, tab_block.line_end, new_full)
)
if dry_run or verbose:
print(f"\n{'='*60}")
print(f"File: {filepath}, line {tab_block.line_start}")
print(f"Section: {yaml_block.section_key}")
print(f"{'='*60}")
_print_diff(existing_ui, new_ui, filepath, tab_block.line_start)
# Apply replacements
if not dry_run and replacements:
lines = content.split("\n")
for start, end, replacement in reversed(replacements):
block_start = start - 1 # 0-based index of <ConfigTabs> line
block_end = end - 1 # 0-based index of </ConfigTabs> line
replacement_lines = replacement.split("\n")
lines[block_start : block_end + 1] = replacement_lines
new_content = "\n".join(lines)
target = outpath or filepath
target.parent.mkdir(parents=True, exist_ok=True)
target.write_text(new_content)
print(
f" Regenerated {len(replacements)} ConfigTabs block(s) in {target}",
file=sys.stderr,
)
elif outpath is not None:
outpath.parent.mkdir(parents=True, exist_ok=True)
shutil.copy2(filepath, outpath)
return stats
def check_file(
filepath: Path,
schema: dict,
i18n: dict,
section_configs: dict,
verbose: bool = False,
) -> dict:
"""Check for drift between existing UI tabs and what would be generated.
Returns:
Stats dict with drift info. Non-zero "drifted" means the file is stale.
"""
content = filepath.read_text()
tab_blocks = extract_config_tabs_blocks(content)
stats = {
"file": str(filepath),
"total_blocks": len(tab_blocks),
"up_to_date": 0,
"drifted": 0,
"skipped": 0,
"warnings": [],
}
if not tab_blocks:
return stats
for tab_block in tab_blocks:
yaml_block = tab_block.yaml_block
if yaml_block.section_key is None or (
yaml_block.section_key not in ALL_CONFIG_SECTIONS
and not yaml_block.is_camera_level
):
stats["skipped"] += 1
continue
new_ui = generate_ui_content(
yaml_block, schema, i18n, section_configs
)
if new_ui is None:
stats["skipped"] += 1
continue
existing_ui = tab_block.ui_content
if _normalize_whitespace(new_ui) == _normalize_whitespace(existing_ui):
stats["up_to_date"] += 1
else:
stats["drifted"] += 1
print(f"\n{'='*60}")
print(f"DRIFT: {filepath}, line {tab_block.line_start}")
print(f"Section: {yaml_block.section_key}")
print(f"{'='*60}")
_print_diff(existing_ui, new_ui, filepath, tab_block.line_start)
return stats
def _normalize_whitespace(text: str) -> str:
"""Normalize whitespace for comparison (strip lines, collapse blanks)."""
lines = [line.rstrip() for line in text.strip().splitlines()]
# Collapse multiple blank lines into one
result: list[str] = []
prev_blank = False
for line in lines:
if line == "":
if not prev_blank:
result.append(line)
prev_blank = True
else:
result.append(line)
prev_blank = False
return "\n".join(result)
def _print_diff(existing: str, generated: str, filepath: Path, line: int):
"""Print a unified diff between existing and generated UI content."""
existing_lines = existing.strip().splitlines(keepends=True)
generated_lines = generated.strip().splitlines(keepends=True)
diff = difflib.unified_diff(
existing_lines,
generated_lines,
fromfile=f"{filepath}:{line} (existing)",
tofile=f"{filepath}:{line} (generated)",
lineterm="",
)
diff_text = "\n".join(diff)
if diff_text:
print(diff_text)
else:
print(" (whitespace-only difference)")
def _ensure_imports(content: str) -> str:
"""Ensure ConfigTabs/TabItem/NavPath imports are present in the file."""
lines = content.split("\n")
needed_imports = []
if "<ConfigTabs>" in content and 'import ConfigTabs' not in content:
needed_imports.append(
'import ConfigTabs from "@site/src/components/ConfigTabs";'
)
if "<TabItem" in content and 'import TabItem' not in content:
needed_imports.append('import TabItem from "@theme/TabItem";')
if "<NavPath" in content and 'import NavPath' not in content:
needed_imports.append(
'import NavPath from "@site/src/components/NavPath";'
)
if not needed_imports:
return content
# Insert imports after frontmatter (---)
insert_idx = 0
frontmatter_count = 0
for i, line in enumerate(lines):
if line.strip() == "---":
frontmatter_count += 1
if frontmatter_count == 2:
insert_idx = i + 1
break
# Add blank line before imports if needed
import_block = [""] + needed_imports + [""]
lines[insert_idx:insert_idx] = import_block
return "\n".join(lines)
def main():
parser = argparse.ArgumentParser(
description="Generate Frigate UI tab content for documentation files"
)
parser.add_argument(
"paths",
nargs="+",
type=Path,
help="Markdown file(s) or directory to process",
)
mode_group = parser.add_mutually_exclusive_group()
mode_group.add_argument(
"--inject",
action="store_true",
help="Inject generated content into files (wraps bare YAML blocks)",
)
mode_group.add_argument(
"--regenerate",
action="store_true",
help="Regenerate UI tabs in existing ConfigTabs from current schema/i18n",
)
mode_group.add_argument(
"--check",
action="store_true",
help="Check for drift between existing UI tabs and current schema/i18n (exit 1 if drifted)",
)
parser.add_argument(
"--outdir",
type=Path,
default=None,
help="Write output files to this directory instead of modifying originals. "
"Mirrors the source directory structure. Use with --inject or --regenerate.",
)
parser.add_argument(
"--dry-run",
action="store_true",
help="With --regenerate, show diffs but don't write files",
)
parser.add_argument(
"--verbose", "-v",
action="store_true",
help="Show detailed warnings and diagnostics",
)
args = parser.parse_args()
# Collect files and determine base directory for relative path computation
files: list[Path] = []
base_dirs: list[Path] = []
for p in args.paths:
if p.is_dir():
files.extend(sorted(p.glob("**/*.md")))
base_dirs.append(p.resolve())
elif p.is_file():
files.append(p)
base_dirs.append(p.resolve().parent)
else:
print(f"Warning: {p} not found, skipping", file=sys.stderr)
if not files:
print("No markdown files found", file=sys.stderr)
sys.exit(1)
# Use the first input path's directory as the base for relative paths
base_dir = base_dirs[0] if base_dirs else Path.cwd()
# Resolve outdir: create a temp directory if --outdir is given without a path
outdir: Path | None = args.outdir
created_tmpdir = False
if outdir is not None:
if str(outdir) == "auto":
outdir = Path(tempfile.mkdtemp(prefix="frigate-ui-tabs-"))
created_tmpdir = True
outdir.mkdir(parents=True, exist_ok=True)
# Build file->outpath mapping
file_outpaths: dict[Path, Path | None] = {}
for f in files:
if outdir is not None:
try:
rel = f.resolve().relative_to(base_dir)
except ValueError:
rel = Path(f.name)
file_outpaths[f] = outdir / rel
else:
file_outpaths[f] = None
# Load data sources
print("Loading schema from Pydantic models...", file=sys.stderr)
schema = load_schema()
print("Loading i18n translations...", file=sys.stderr)
i18n = load_i18n()
print("Loading section configs...", file=sys.stderr)
section_configs = load_section_configs()
print(f"Processing {len(files)} file(s)...\n", file=sys.stderr)
if args.check:
_run_check(files, schema, i18n, section_configs, args.verbose)
elif args.regenerate:
_run_regenerate(
files, schema, i18n, section_configs,
args.dry_run, args.verbose, file_outpaths,
)
else:
_run_inject(
files, schema, i18n, section_configs,
args.inject, args.verbose, file_outpaths,
)
if outdir is not None:
print(f"\nOutput written to: {outdir}", file=sys.stderr)
def _run_inject(files, schema, i18n, section_configs, inject, verbose, file_outpaths):
"""Run default mode: preview or inject bare YAML blocks."""
total_stats = {
"files": 0,
"total_blocks": 0,
"config_blocks": 0,
"already_wrapped": 0,
"generated": 0,
"skipped": 0,
}
for filepath in files:
stats = process_file(
filepath, schema, i18n, section_configs,
inject=inject, verbose=verbose,
outpath=file_outpaths.get(filepath),
)
total_stats["files"] += 1
for key in ["total_blocks", "config_blocks", "already_wrapped",
"generated", "skipped"]:
total_stats[key] += stats[key]
if verbose and stats["warnings"]:
print(f"\n{filepath}:", file=sys.stderr)
for w in stats["warnings"]:
print(w, file=sys.stderr)
print("\n" + "=" * 60, file=sys.stderr)
print("Summary:", file=sys.stderr)
print(f" Files processed: {total_stats['files']}", file=sys.stderr)
print(f" Total YAML blocks: {total_stats['total_blocks']}", file=sys.stderr)
print(f" Config blocks: {total_stats['config_blocks']}", file=sys.stderr)
print(f" Already wrapped: {total_stats['already_wrapped']}", file=sys.stderr)
print(f" Generated: {total_stats['generated']}", file=sys.stderr)
print(f" Skipped: {total_stats['skipped']}", file=sys.stderr)
print("=" * 60, file=sys.stderr)
def _run_regenerate(files, schema, i18n, section_configs, dry_run, verbose, file_outpaths):
"""Run regenerate mode: update existing ConfigTabs blocks."""
total_stats = {
"files": 0,
"total_blocks": 0,
"regenerated": 0,
"unchanged": 0,
"skipped": 0,
}
for filepath in files:
stats = regenerate_file(
filepath, schema, i18n, section_configs,
dry_run=dry_run, verbose=verbose,
outpath=file_outpaths.get(filepath),
)
total_stats["files"] += 1
for key in ["total_blocks", "regenerated", "unchanged", "skipped"]:
total_stats[key] += stats[key]
if verbose and stats["warnings"]:
print(f"\n{filepath}:", file=sys.stderr)
for w in stats["warnings"]:
print(w, file=sys.stderr)
action = "Would regenerate" if dry_run else "Regenerated"
print("\n" + "=" * 60, file=sys.stderr)
print("Summary:", file=sys.stderr)
print(f" Files processed: {total_stats['files']}", file=sys.stderr)
print(f" ConfigTabs blocks: {total_stats['total_blocks']}", file=sys.stderr)
print(f" {action}: {total_stats['regenerated']}", file=sys.stderr)
print(f" Unchanged: {total_stats['unchanged']}", file=sys.stderr)
print(f" Skipped: {total_stats['skipped']}", file=sys.stderr)
print("=" * 60, file=sys.stderr)
def _run_check(files, schema, i18n, section_configs, verbose):
"""Run check mode: detect drift without modifying files."""
total_stats = {
"files": 0,
"total_blocks": 0,
"up_to_date": 0,
"drifted": 0,
"skipped": 0,
}
for filepath in files:
stats = check_file(
filepath, schema, i18n, section_configs, verbose=verbose,
)
total_stats["files"] += 1
for key in ["total_blocks", "up_to_date", "drifted", "skipped"]:
total_stats[key] += stats[key]
print("\n" + "=" * 60, file=sys.stderr)
print("Summary:", file=sys.stderr)
print(f" Files processed: {total_stats['files']}", file=sys.stderr)
print(f" ConfigTabs blocks: {total_stats['total_blocks']}", file=sys.stderr)
print(f" Up to date: {total_stats['up_to_date']}", file=sys.stderr)
print(f" Drifted: {total_stats['drifted']}", file=sys.stderr)
print(f" Skipped: {total_stats['skipped']}", file=sys.stderr)
print("=" * 60, file=sys.stderr)
if total_stats["drifted"] > 0:
print(
f"\n{total_stats['drifted']} block(s) have drifted from schema/i18n. "
"Run with --regenerate to update.",
file=sys.stderr,
)
sys.exit(1)
else:
print("\nAll UI tabs are up to date.", file=sys.stderr)
if __name__ == "__main__":
main()
View File
+139
View File
@@ -0,0 +1,139 @@
"""Load i18n translation files for Settings UI field labels."""
import json
from pathlib import Path
from typing import Any
# Base path for locale files
WEB_LOCALES = Path(__file__).resolve().parents[3] / "web" / "public" / "locales" / "en"
def load_i18n() -> dict[str, Any]:
"""Load and merge all relevant i18n files.
Returns:
Dict with keys: "global", "cameras", "settings_menu"
"""
global_path = WEB_LOCALES / "config" / "global.json"
cameras_path = WEB_LOCALES / "config" / "cameras.json"
settings_path = WEB_LOCALES / "views" / "settings.json"
result: dict[str, Any] = {}
with open(global_path) as f:
result["global"] = json.load(f)
with open(cameras_path) as f:
result["cameras"] = json.load(f)
with open(settings_path) as f:
settings = json.load(f)
result["settings_menu"] = settings.get("menu", {})
# Build a unified enum value → label lookup from all known sources.
# Merges multiple maps so callers don't need to know which file
# a particular enum lives in.
value_labels: dict[str, str] = {}
config_form = settings.get("configForm", {})
# FFmpeg preset labels (preset-vaapi → "VAAPI (Intel/AMD GPU)")
value_labels.update(
config_form.get("ffmpegArgs", {}).get("presetLabels", {})
)
# Timestamp position (tl → "Top left")
value_labels.update(settings.get("timestampPosition", {}))
# Input role options (detect → "Detect")
value_labels.update(
config_form.get("inputRoles", {}).get("options", {})
)
# GenAI role options (vision → "Vision")
value_labels.update(
config_form.get("genaiRoles", {}).get("options", {})
)
result["value_labels"] = value_labels
return result
def get_field_label(
i18n: dict[str, Any],
section_key: str,
field_path: list[str],
level: str = "global",
) -> str | None:
"""Look up the UI label for a field.
Args:
i18n: Loaded i18n data from load_i18n()
section_key: Config section (e.g., "record")
field_path: Path within section (e.g., ["continuous", "days"])
level: "global" or "cameras"
Returns:
The label string, or None if not found.
"""
source = i18n.get(level, {})
node = source.get(section_key, {})
for key in field_path:
if not isinstance(node, dict):
return None
node = node.get(key, {})
if isinstance(node, dict):
return node.get("label")
return None
def get_field_description(
i18n: dict[str, Any],
section_key: str,
field_path: list[str],
level: str = "global",
) -> str | None:
"""Look up the UI description for a field."""
source = i18n.get(level, {})
node = source.get(section_key, {})
for key in field_path:
if not isinstance(node, dict):
return None
node = node.get(key, {})
if isinstance(node, dict):
return node.get("description")
return None
def get_value_label(
i18n: dict[str, Any],
value: str,
) -> str | None:
"""Look up the display label for an enum/option value.
Args:
i18n: Loaded i18n data from load_i18n()
value: The raw config value (e.g., "preset-vaapi", "tl")
Returns:
The human-readable label (e.g., "VAAPI (Intel/AMD GPU)"), or None.
"""
return i18n.get("value_labels", {}).get(value)
def get_section_label(
i18n: dict[str, Any],
section_key: str,
level: str = "global",
) -> str | None:
"""Get the top-level label for a config section."""
source = i18n.get(level, {})
section = source.get(section_key, {})
if isinstance(section, dict):
return section.get("label")
return None
+120
View File
@@ -0,0 +1,120 @@
"""Map config section keys to Settings UI navigation paths."""
# Derived from web/src/pages/Settings.tsx section mappings
# and web/public/locales/en/views/settings.json menu labels.
#
# Format: section_key -> (group_label, page_label)
# Navigation path: "Settings > {group_label} > {page_label}"
GLOBAL_NAV: dict[str, tuple[str, str]] = {
"detect": ("Global configuration", "Object detection"),
"ffmpeg": ("Global configuration", "FFmpeg"),
"record": ("Global configuration", "Recording"),
"snapshots": ("Global configuration", "Snapshots"),
"motion": ("Global configuration", "Motion detection"),
"objects": ("Global configuration", "Objects"),
"review": ("Global configuration", "Review"),
"audio": ("Global configuration", "Audio events"),
"live": ("Global configuration", "Live playback"),
"timestamp_style": ("Global configuration", "Timestamp style"),
"notifications": ("Notifications", "Notifications"),
}
CAMERA_NAV: dict[str, tuple[str, str]] = {
"detect": ("Camera configuration", "Object detection"),
"ffmpeg": ("Camera configuration", "FFmpeg"),
"record": ("Camera configuration", "Recording"),
"snapshots": ("Camera configuration", "Snapshots"),
"motion": ("Camera configuration", "Motion detection"),
"objects": ("Camera configuration", "Objects"),
"review": ("Camera configuration", "Review"),
"audio": ("Camera configuration", "Audio events"),
"audio_transcription": ("Camera configuration", "Audio transcription"),
"notifications": ("Camera configuration", "Notifications"),
"live": ("Camera configuration", "Live playback"),
"birdseye": ("Camera configuration", "Birdseye"),
"face_recognition": ("Camera configuration", "Face recognition"),
"lpr": ("Camera configuration", "License plate recognition"),
"mqtt": ("Camera configuration", "MQTT"),
"onvif": ("Camera configuration", "ONVIF"),
"ui": ("Camera configuration", "Camera UI"),
"timestamp_style": ("Camera configuration", "Timestamp style"),
}
ENRICHMENT_NAV: dict[str, tuple[str, str]] = {
"semantic_search": ("Enrichments", "Semantic search"),
"genai": ("Enrichments", "Generative AI"),
"face_recognition": ("Enrichments", "Face recognition"),
"lpr": ("Enrichments", "License plate recognition"),
"classification": ("Enrichments", "Object classification"),
"audio_transcription": ("Enrichments", "Audio transcription"),
}
SYSTEM_NAV: dict[str, tuple[str, str]] = {
"go2rtc_streams": ("System", "go2rtc streams"),
"database": ("System", "Database"),
"mqtt": ("System", "MQTT"),
"tls": ("System", "TLS"),
"auth": ("System", "Authentication"),
"networking": ("System", "Networking"),
"proxy": ("System", "Proxy"),
"ui": ("System", "UI"),
"logger": ("System", "Logging"),
"environment_vars": ("System", "Environment variables"),
"telemetry": ("System", "Telemetry"),
"birdseye": ("System", "Birdseye"),
"detectors": ("System", "Detector hardware"),
"model": ("System", "Detection model"),
}
# All known top-level config section keys
ALL_CONFIG_SECTIONS = (
set(GLOBAL_NAV)
| set(CAMERA_NAV)
| set(ENRICHMENT_NAV)
| set(SYSTEM_NAV)
| {"cameras"}
)
def get_nav_path(section_key: str, level: str = "global") -> str | None:
"""Get the full navigation path for a config section.
Args:
section_key: Config section key (e.g., "record")
level: "global", "camera", "enrichment", or "system"
Returns:
NavPath string like "Settings > Global configuration > Recording",
or None if not found.
"""
nav_tables = {
"global": GLOBAL_NAV,
"camera": CAMERA_NAV,
"enrichment": ENRICHMENT_NAV,
"system": SYSTEM_NAV,
}
table = nav_tables.get(level)
if table is None:
return None
entry = table.get(section_key)
if entry is None:
return None
group, page = entry
return f"Settings > {group} > {page}"
def detect_level(section_key: str) -> str:
"""Detect whether a config section is global, camera, enrichment, or system."""
if section_key in SYSTEM_NAV:
return "system"
if section_key in ENRICHMENT_NAV:
return "enrichment"
if section_key in GLOBAL_NAV:
return "global"
if section_key in CAMERA_NAV:
return "camera"
return "global"
+88
View File
@@ -0,0 +1,88 @@
"""Load JSON schema from Frigate's Pydantic config models."""
from typing import Any
def load_schema() -> dict[str, Any]:
"""Generate and return the full JSON schema for FrigateConfig."""
from frigate.config.config import FrigateConfig
from frigate.util.schema import get_config_schema
return get_config_schema(FrigateConfig)
def resolve_ref(schema: dict[str, Any], ref: str) -> dict[str, Any]:
"""Resolve a $ref pointer within the schema."""
# ref format: "#/$defs/RecordConfig"
parts = ref.lstrip("#/").split("/")
node = schema
for part in parts:
node = node[part]
return node
def resolve_schema_node(
schema: dict[str, Any], node: dict[str, Any]
) -> dict[str, Any]:
"""Resolve a schema node, following $ref and allOf if present."""
if "$ref" in node:
node = resolve_ref(schema, node["$ref"])
if "allOf" in node:
merged: dict[str, Any] = {}
for item in node["allOf"]:
resolved = resolve_schema_node(schema, item)
merged.update(resolved)
return merged
return node
def get_section_schema(
schema: dict[str, Any], section_key: str
) -> dict[str, Any] | None:
"""Get the resolved schema for a top-level config section."""
props = schema.get("properties", {})
if section_key not in props:
return None
return resolve_schema_node(schema, props[section_key])
def get_field_info(
schema: dict[str, Any], section_key: str, field_path: list[str]
) -> dict[str, Any] | None:
"""Get schema info for a specific field path within a section.
Args:
schema: Full JSON schema
section_key: Top-level section (e.g., "record")
field_path: List of nested keys (e.g., ["continuous", "days"])
Returns:
Resolved schema node for the field, or None if not found.
"""
section = get_section_schema(schema, section_key)
if section is None:
return None
node = section
for key in field_path:
props = node.get("properties", {})
if key not in props:
return None
node = resolve_schema_node(schema, props[key])
return node
def is_boolean_field(field_schema: dict[str, Any]) -> bool:
"""Check if a schema node represents a boolean field."""
return field_schema.get("type") == "boolean"
def is_enum_field(field_schema: dict[str, Any]) -> bool:
"""Check if a schema node is an enum."""
return "enum" in field_schema
def is_object_field(field_schema: dict[str, Any]) -> bool:
"""Check if a schema node is an object with properties."""
return field_schema.get("type") == "object" or "properties" in field_schema
+130
View File
@@ -0,0 +1,130 @@
"""Parse TypeScript section config files for hidden/advanced field info."""
import json
import re
from pathlib import Path
from typing import Any
SECTION_CONFIGS_DIR = (
Path(__file__).resolve().parents[3]
/ "web"
/ "src"
/ "components"
/ "config-form"
/ "section-configs"
)
def _extract_string_array(text: str, field_name: str) -> list[str]:
"""Extract a string array value from TypeScript object literal text."""
pattern = rf"{field_name}\s*:\s*\[(.*?)\]"
match = re.search(pattern, text, re.DOTALL)
if not match:
return []
content = match.group(1)
return re.findall(r'"([^"]*)"', content)
def _parse_section_file(filepath: Path) -> dict[str, Any]:
"""Parse a single section config .ts file."""
text = filepath.read_text()
# Extract base block
base_match = re.search(r"base\s*:\s*\{(.*?)\n \}", text, re.DOTALL)
base_text = base_match.group(1) if base_match else ""
# Extract global block
global_match = re.search(r"global\s*:\s*\{(.*?)\n \}", text, re.DOTALL)
global_text = global_match.group(1) if global_match else ""
# Extract camera block
camera_match = re.search(r"camera\s*:\s*\{(.*?)\n \}", text, re.DOTALL)
camera_text = camera_match.group(1) if camera_match else ""
result: dict[str, Any] = {
"fieldOrder": _extract_string_array(base_text, "fieldOrder"),
"hiddenFields": _extract_string_array(base_text, "hiddenFields"),
"advancedFields": _extract_string_array(base_text, "advancedFields"),
}
# Merge global-level hidden fields
global_hidden = _extract_string_array(global_text, "hiddenFields")
if global_hidden:
result["globalHiddenFields"] = global_hidden
# Merge camera-level hidden fields
camera_hidden = _extract_string_array(camera_text, "hiddenFields")
if camera_hidden:
result["cameraHiddenFields"] = camera_hidden
return result
def load_section_configs() -> dict[str, dict[str, Any]]:
"""Load all section configs from TypeScript files.
Returns:
Dict mapping section name to parsed config.
"""
# Read sectionConfigs.ts to get the mapping of section keys to filenames
registry_path = SECTION_CONFIGS_DIR.parent / "sectionConfigs.ts"
registry_text = registry_path.read_text()
configs: dict[str, dict[str, Any]] = {}
for ts_file in SECTION_CONFIGS_DIR.glob("*.ts"):
if ts_file.name == "types.ts":
continue
section_name = ts_file.stem
configs[section_name] = _parse_section_file(ts_file)
# Map section config keys from the registry (handles renames like
# "timestamp_style: timestampStyle")
key_map: dict[str, str] = {}
for match in re.finditer(
r"(\w+)(?:\s*:\s*\w+)?\s*,", registry_text[registry_text.find("{") :]
):
key = match.group(1)
key_map[key] = key
# Handle explicit key mappings like `timestamp_style: timestampStyle`
for match in re.finditer(r"(\w+)\s*:\s*(\w+)\s*,", registry_text):
key_map[match.group(1)] = match.group(2)
return configs
def get_hidden_fields(
configs: dict[str, dict[str, Any]],
section_key: str,
level: str = "global",
) -> set[str]:
"""Get the set of hidden fields for a section at a given level.
Args:
configs: Loaded section configs
section_key: Config section name (e.g., "record")
level: "global" or "camera"
Returns:
Set of hidden field paths (e.g., {"enabled_in_config", "sync_recordings"})
"""
config = configs.get(section_key, {})
hidden = set(config.get("hiddenFields", []))
if level == "global":
hidden.update(config.get("globalHiddenFields", []))
elif level == "camera":
hidden.update(config.get("cameraHiddenFields", []))
return hidden
def get_advanced_fields(
configs: dict[str, dict[str, Any]],
section_key: str,
) -> set[str]:
"""Get the set of advanced fields for a section."""
config = configs.get(section_key, {})
return set(config.get("advancedFields", []))
+283
View File
@@ -0,0 +1,283 @@
"""Generate UI tab markdown content from parsed YAML blocks."""
from typing import Any
from .i18n_loader import get_field_description, get_field_label, get_value_label
from .nav_map import ALL_CONFIG_SECTIONS, detect_level, get_nav_path
from .schema_loader import is_boolean_field, is_object_field
from .section_config_parser import get_hidden_fields
from .yaml_extractor import YamlBlock, get_leaf_paths
def _format_value(
value: object,
field_schema: dict[str, Any] | None,
i18n: dict[str, Any] | None = None,
) -> str:
"""Format a YAML value for UI display.
Looks up i18n labels for enum/option values when available.
"""
if field_schema and is_boolean_field(field_schema):
return "on" if value else "off"
if isinstance(value, bool):
return "on" if value else "off"
if isinstance(value, list):
if len(value) == 0:
return "an empty list"
items = []
for v in value:
label = get_value_label(i18n, str(v)) if i18n else None
items.append(f"`{label}`" if label else f"`{v}`")
return ", ".join(items)
if value is None:
return "empty"
# Try i18n label for the raw value (enum translations)
if i18n and isinstance(value, str):
label = get_value_label(i18n, value)
if label:
return f"`{label}`"
return f"`{value}`"
def _build_field_label(
i18n: dict[str, Any],
section_key: str,
field_path: list[str],
level: str,
) -> str:
"""Build the display label for a field using i18n labels.
For a path like ["continuous", "days"], produces
"Continuous retention > Retention days" using the actual i18n labels.
"""
parts: list[str] = []
for depth in range(len(field_path)):
sub_path = field_path[: depth + 1]
label = get_field_label(i18n, section_key, sub_path, level)
if label:
parts.append(label)
else:
# Fallback to title-cased field name
parts.append(field_path[depth].replace("_", " ").title())
return " > ".join(parts)
def _is_hidden(
field_key: str,
full_path: list[str],
hidden_fields: set[str],
) -> bool:
"""Check if a field should be hidden from UI output."""
# Check exact match
if field_key in hidden_fields:
return True
# Check dotted path match (e.g., "alerts.enabled_in_config")
dotted = ".".join(str(p) for p in full_path)
if dotted in hidden_fields:
return True
# Check wildcard patterns (e.g., "filters.*.mask")
for pattern in hidden_fields:
if "*" in pattern:
parts = pattern.split(".")
if len(parts) == len(full_path):
match = all(
p == "*" or p == fp for p, fp in zip(parts, full_path)
)
if match:
return True
return False
def generate_ui_content(
block: YamlBlock,
schema: dict[str, Any],
i18n: dict[str, Any],
section_configs: dict[str, dict[str, Any]],
) -> str | None:
"""Generate UI tab markdown content for a YAML block.
Args:
block: Parsed YAML block from a doc file
schema: Full JSON schema
i18n: Loaded i18n translations
section_configs: Parsed section config data
Returns:
Generated markdown string for the UI tab, or None if the block
can't be converted (not a config block, etc.)
"""
if block.section_key is None:
return None
# Determine which config data to walk
if block.is_camera_level:
# Camera-level: unwrap cameras.{name}.{section}
cam_data = block.parsed.get("cameras", {})
cam_name = block.camera_name or next(iter(cam_data), None)
if not cam_name:
return None
inner = cam_data.get(cam_name, {})
if not isinstance(inner, dict):
return None
level = "camera"
else:
inner = block.parsed
# Determine level from section key
level = detect_level(block.section_key)
# Collect sections to process (may span multiple top-level keys)
sections_to_process: list[tuple[str, dict]] = []
for key in inner:
if key in ALL_CONFIG_SECTIONS or key == block.section_key:
val = inner[key]
if isinstance(val, dict):
sections_to_process.append((key, val))
else:
# Simple scalar at section level (e.g., record.enabled = True)
sections_to_process.append((key, {key: val}))
# If inner is the section itself (e.g., parsed = {"record": {...}})
if not sections_to_process and block.section_key in inner:
section_data = inner[block.section_key]
if isinstance(section_data, dict):
sections_to_process = [(block.section_key, section_data)]
if not sections_to_process:
# Try treating the whole inner dict as the section data
sections_to_process = [(block.section_key, inner)]
# Choose pattern based on whether YAML has comments (descriptive) or values
use_table = block.has_comments
lines: list[str] = []
step_num = 1
for section_key, section_data in sections_to_process:
# Get navigation path
i18n_level = "cameras" if level == "camera" else "global"
nav_path = get_nav_path(section_key, level)
if nav_path is None:
# Try global as fallback
nav_path = get_nav_path(section_key, "global")
if nav_path is None:
continue
# Get hidden fields for this section
hidden = get_hidden_fields(section_configs, section_key, level)
# Get leaf paths from the YAML data
leaves = get_leaf_paths(section_data)
# Filter out hidden fields
visible_leaves: list[tuple[tuple[str, ...], object]] = []
for path, value in leaves:
path_list = list(path)
if not _is_hidden(path_list[-1], path_list, hidden):
visible_leaves.append((path, value))
if not visible_leaves:
continue
if use_table:
# Pattern A: Field table with descriptions
lines.append(
f'Navigate to <NavPath path="{nav_path}" />.'
)
lines.append("")
lines.append("| Field | Description |")
lines.append("|-------|-------------|")
for path, _value in visible_leaves:
path_list = list(path)
label = _build_field_label(
i18n, section_key, path_list, i18n_level
)
desc = get_field_description(
i18n, section_key, path_list, i18n_level
)
if not desc:
desc = ""
lines.append(f"| **{label}** | {desc} |")
else:
# Pattern B: Set instructions
multi_section = len(sections_to_process) > 1
if multi_section:
camera_note = ""
if block.is_camera_level:
camera_note = (
" and select your camera"
)
lines.append(
f'{step_num}. Navigate to <NavPath path="{nav_path}" />{camera_note}.'
)
else:
if block.is_camera_level:
lines.append(
f'1. Navigate to <NavPath path="{nav_path}" /> and select your camera.'
)
else:
lines.append(
f'Navigate to <NavPath path="{nav_path}" />.'
)
lines.append("")
from .schema_loader import get_field_info
for path, value in visible_leaves:
path_list = list(path)
label = _build_field_label(
i18n, section_key, path_list, i18n_level
)
field_info = get_field_info(schema, section_key, path_list)
formatted = _format_value(value, field_info, i18n)
if multi_section or block.is_camera_level:
lines.append(f" - Set **{label}** to {formatted}")
else:
lines.append(f"- Set **{label}** to {formatted}")
step_num += 1
if not lines:
return None
return "\n".join(lines)
def wrap_with_config_tabs(ui_content: str, yaml_raw: str, highlight: str | None = None) -> str:
"""Wrap UI content and YAML in ConfigTabs markup.
Args:
ui_content: Generated UI tab markdown
yaml_raw: Original YAML text
highlight: Optional highlight spec (e.g., "{3-4}")
Returns:
Full ConfigTabs MDX block
"""
highlight_str = f" {highlight}" if highlight else ""
return f"""<ConfigTabs>
<TabItem value="ui">
{ui_content}
</TabItem>
<TabItem value="yaml">
```yaml{highlight_str}
{yaml_raw}
```
</TabItem>
</ConfigTabs>"""
+283
View File
@@ -0,0 +1,283 @@
"""Extract YAML code blocks from markdown documentation files."""
import re
from dataclasses import dataclass, field
import yaml
@dataclass
class YamlBlock:
"""A YAML code block extracted from a markdown file."""
raw: str # Original YAML text
parsed: dict # Parsed YAML content
line_start: int # Line number in the markdown file (1-based)
line_end: int # End line number
highlight: str | None = None # Highlight spec (e.g., "{3-4}")
has_comments: bool = False # Whether the YAML has inline comments
inside_config_tabs: bool = False # Already wrapped in ConfigTabs
section_key: str | None = None # Detected top-level config section
is_camera_level: bool = False # Whether this is camera-level config
camera_name: str | None = None # Camera name if camera-level
config_keys: list[str] = field(
default_factory=list
) # Top-level keys in the YAML
def extract_yaml_blocks(content: str) -> list[YamlBlock]:
"""Extract all YAML fenced code blocks from markdown content.
Args:
content: Markdown file content
Returns:
List of YamlBlock instances
"""
blocks: list[YamlBlock] = []
lines = content.split("\n")
i = 0
in_config_tabs = False
while i < len(lines):
line = lines[i]
# Track ConfigTabs context
if "<ConfigTabs>" in line:
in_config_tabs = True
elif "</ConfigTabs>" in line:
in_config_tabs = False
# Look for YAML fence opening
fence_match = re.match(r"^```yaml\s*(\{[^}]*\})?\s*$", line)
if fence_match:
highlight = fence_match.group(1)
start_line = i + 1 # 1-based
yaml_lines: list[str] = []
i += 1
# Collect until closing fence
while i < len(lines) and not lines[i].startswith("```"):
yaml_lines.append(lines[i])
i += 1
end_line = i + 1 # 1-based, inclusive of closing fence
raw = "\n".join(yaml_lines)
# Check for inline comments
has_comments = any(
re.search(r"#\s*(<-|[A-Za-z])", yl) for yl in yaml_lines
)
# Parse YAML
try:
parsed = yaml.safe_load(raw)
except yaml.YAMLError:
i += 1
continue
if not isinstance(parsed, dict):
i += 1
continue
# Detect config section and level
config_keys = list(parsed.keys())
section_key = None
is_camera = False
camera_name = None
if "cameras" in parsed and isinstance(parsed["cameras"], dict):
is_camera = True
cam_entries = parsed["cameras"]
if len(cam_entries) == 1:
camera_name = list(cam_entries.keys())[0]
inner = cam_entries[camera_name]
if isinstance(inner, dict):
inner_keys = list(inner.keys())
if len(inner_keys) >= 1:
section_key = inner_keys[0]
elif len(config_keys) >= 1:
section_key = config_keys[0]
blocks.append(
YamlBlock(
raw=raw,
parsed=parsed,
line_start=start_line,
line_end=end_line,
highlight=highlight,
has_comments=has_comments,
inside_config_tabs=in_config_tabs,
section_key=section_key,
is_camera_level=is_camera,
camera_name=camera_name,
config_keys=config_keys,
)
)
i += 1
return blocks
@dataclass
class ConfigTabsBlock:
"""An existing ConfigTabs block in a markdown file."""
line_start: int # 1-based line of <ConfigTabs>
line_end: int # 1-based line of </ConfigTabs>
ui_content: str # Content inside the UI TabItem
yaml_block: YamlBlock # The YAML block inside the YAML TabItem
raw_text: str # Full raw text of the ConfigTabs block
def extract_config_tabs_blocks(content: str) -> list[ConfigTabsBlock]:
"""Extract existing ConfigTabs blocks from markdown content.
Parses the structure:
<ConfigTabs>
<TabItem value="ui">
...ui content...
</TabItem>
<TabItem value="yaml">
```yaml
...yaml...
```
</TabItem>
</ConfigTabs>
Returns:
List of ConfigTabsBlock instances
"""
blocks: list[ConfigTabsBlock] = []
lines = content.split("\n")
i = 0
while i < len(lines):
if "<ConfigTabs>" not in lines[i]:
i += 1
continue
block_start = i # 0-based
# Find </ConfigTabs>
j = i + 1
while j < len(lines) and "</ConfigTabs>" not in lines[j]:
j += 1
if j >= len(lines):
i += 1
continue
block_end = j # 0-based, line with </ConfigTabs>
block_text = "\n".join(lines[block_start : block_end + 1])
# Extract UI content (between <TabItem value="ui"> and </TabItem>)
ui_match = re.search(
r'<TabItem\s+value="ui">\s*\n(.*?)\n\s*</TabItem>',
block_text,
re.DOTALL,
)
ui_content = ui_match.group(1).strip() if ui_match else ""
# Extract YAML block from inside the yaml TabItem
yaml_tab_match = re.search(
r'<TabItem\s+value="yaml">\s*\n(.*?)\n\s*</TabItem>',
block_text,
re.DOTALL,
)
yaml_block = None
if yaml_tab_match:
yaml_tab_text = yaml_tab_match.group(1)
fence_match = re.search(
r"```yaml\s*(\{[^}]*\})?\s*\n(.*?)\n```",
yaml_tab_text,
re.DOTALL,
)
if fence_match:
highlight = fence_match.group(1)
yaml_raw = fence_match.group(2)
has_comments = bool(
re.search(r"#\s*(<-|[A-Za-z])", yaml_raw)
)
try:
parsed = yaml.safe_load(yaml_raw)
except yaml.YAMLError:
parsed = {}
if isinstance(parsed, dict):
config_keys = list(parsed.keys())
section_key = None
is_camera = False
camera_name = None
if "cameras" in parsed and isinstance(
parsed["cameras"], dict
):
is_camera = True
cam_entries = parsed["cameras"]
if len(cam_entries) == 1:
camera_name = list(cam_entries.keys())[0]
inner = cam_entries[camera_name]
if isinstance(inner, dict):
inner_keys = list(inner.keys())
if len(inner_keys) >= 1:
section_key = inner_keys[0]
elif len(config_keys) >= 1:
section_key = config_keys[0]
yaml_block = YamlBlock(
raw=yaml_raw,
parsed=parsed,
line_start=block_start + 1,
line_end=block_end + 1,
highlight=highlight,
has_comments=has_comments,
inside_config_tabs=True,
section_key=section_key,
is_camera_level=is_camera,
camera_name=camera_name,
config_keys=config_keys,
)
if yaml_block:
blocks.append(
ConfigTabsBlock(
line_start=block_start + 1, # 1-based
line_end=block_end + 1, # 1-based
ui_content=ui_content,
yaml_block=yaml_block,
raw_text=block_text,
)
)
i = j + 1
return blocks
def get_leaf_paths(
data: dict, prefix: tuple[str, ...] = ()
) -> list[tuple[tuple[str, ...], object]]:
"""Walk a parsed YAML dict and return all leaf key paths with values.
Args:
data: Parsed YAML dict
prefix: Current key path prefix
Returns:
List of (key_path_tuple, value) pairs.
e.g., [( ("record", "continuous", "days"), 3 ), ...]
"""
results: list[tuple[tuple[str, ...], object]] = []
for key, value in data.items():
path = prefix + (str(key),)
if isinstance(value, dict):
results.extend(get_leaf_paths(value, path))
else:
results.append((path, value))
return results
+1
View File
@@ -12,6 +12,7 @@ const sidebars: SidebarsConfig = {
"frigate/updating",
"frigate/camera_setup",
"frigate/video_pipeline",
"frigate/network_requirements",
"frigate/glossary",
],
Guides: [
+34
View File
@@ -0,0 +1,34 @@
import React, { Children, cloneElement } from "react";
import Tabs from "@theme/Tabs";
import TabItem from "@theme/TabItem";
export default function ConfigTabs({ children }) {
const wrapped = Children.map(children, (child) => {
if (child?.props?.value === "ui") {
return cloneElement(child, {
className: "config-tab-ui",
});
}
if (child?.props?.value === "yaml") {
return cloneElement(child, {
className: "config-tab-yaml",
});
}
return child;
});
return (
<div className="config-tabs-wrapper">
<Tabs
groupId="config-method"
defaultValue="ui"
values={[
{ label: "Frigate UI", value: "ui" },
{ label: "YAML", value: "yaml" },
]}
>
{wrapped}
</Tabs>
</div>
);
}
+30
View File
@@ -0,0 +1,30 @@
import React from "react";
export default function NavPath({ path }) {
const segments = path.split(" > ");
return (
<span
style={{
display: "inline",
fontSize: "inherit",
lineHeight: "inherit",
}}
>
{segments.map((seg, i) => (
<span key={i}>
{i > 0 && (
<span
style={{
margin: "0 4px",
color: "var(--ifm-color-emphasis-800)",
}}
>
</span>
)}
<strong>{seg}</strong>
</span>
))}
</span>
);
}
+46
View File
@@ -241,4 +241,50 @@
margin: 0 calc(-1 * var(--ifm-pre-padding));
padding: 0 var(--ifm-pre-padding);
border-left: 3px solid #ff000080;
}
/* ConfigTabs wrapper */
.config-tabs-wrapper {
border: 1px solid var(--ifm-color-emphasis-300);
border-radius: 8px;
overflow: hidden;
margin-bottom: 16px;
}
.config-tabs-wrapper .tabs-container {
margin-bottom: 0 !important;
}
.config-tabs-wrapper .tabs {
background: var(--ifm-color-emphasis-100);
border-bottom: 1px solid var(--ifm-color-emphasis-300);
margin-bottom: 0;
padding: 0 12px;
}
.config-tabs-wrapper .tabs__item {
padding: 8px 16px;
border-radius: 0;
}
.config-tabs-wrapper .tabs__item--active {
border-bottom-color: var(--ifm-color-primary);
}
.config-tabs-wrapper .config-tab-ui {
padding: 4px 16px 16px;
}
.config-tabs-wrapper .config-tab-ui > :last-child {
margin-bottom: 0;
}
.config-tabs-wrapper div[class*="codeBlockContainer"] {
border-top-left-radius: 0;
border-top-right-radius: 0;
margin: 0;
}
.config-tabs-wrapper .tabs-container > .margin-top--md:has(.config-tab-yaml:not([hidden])) {
margin-top: 0 !important;
}
+299 -63
View File
@@ -2724,6 +2724,135 @@ paths:
application/json:
schema:
$ref: "#/components/schemas/HTTPValidationError"
/exports/batch:
post:
tags:
- Export
summary: Start recording export batch
description: >-
Starts recording exports for a batch of items, each with its own camera
and time range. Optionally assigns them to a new or existing export case.
When neither export_case_id nor new_case_name is provided, exports are
added as uncategorized. Attaching to an existing case is admin-only.
operationId: export_recordings_batch_exports_batch_post
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/BatchExportBody"
responses:
"202":
description: Successful Response
content:
application/json:
schema:
$ref: "#/components/schemas/BatchExportResponse"
"400":
description: Bad Request
content:
application/json:
schema:
$ref: "#/components/schemas/GenericResponse"
"403":
description: Forbidden
content:
application/json:
schema:
$ref: "#/components/schemas/GenericResponse"
"404":
description: Not Found
content:
application/json:
schema:
$ref: "#/components/schemas/GenericResponse"
"503":
description: Service Unavailable
content:
application/json:
schema:
$ref: "#/components/schemas/GenericResponse"
"422":
description: Validation Error
content:
application/json:
schema:
$ref: "#/components/schemas/HTTPValidationError"
/exports/delete:
post:
tags:
- Export
summary: Bulk delete exports
description: >-
Deletes one or more exports by ID. All IDs must exist and none can be
in-progress. Admin-only.
operationId: bulk_delete_exports_exports_delete_post
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/ExportBulkDeleteBody"
responses:
"200":
description: Successful Response
content:
application/json:
schema:
$ref: "#/components/schemas/GenericResponse"
"400":
description: Bad Request - one or more exports are in-progress
content:
application/json:
schema:
$ref: "#/components/schemas/GenericResponse"
"404":
description: Not Found - one or more export IDs do not exist
content:
application/json:
schema:
$ref: "#/components/schemas/GenericResponse"
"422":
description: Validation Error
content:
application/json:
schema:
$ref: "#/components/schemas/HTTPValidationError"
/exports/reassign:
post:
tags:
- Export
summary: Bulk reassign exports to a case
description: >-
Assigns or unassigns one or more exports to/from a case. All IDs must
exist. Pass export_case_id as null to unassign (move to uncategorized).
Admin-only.
operationId: bulk_reassign_exports_exports_reassign_post
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/ExportBulkReassignBody"
responses:
"200":
description: Successful Response
content:
application/json:
schema:
$ref: "#/components/schemas/GenericResponse"
"404":
description: Not Found - one or more export IDs or the target case do not exist
content:
application/json:
schema:
$ref: "#/components/schemas/GenericResponse"
"422":
description: Validation Error
content:
application/json:
schema:
$ref: "#/components/schemas/HTTPValidationError"
/cases:
get:
tags:
@@ -2853,39 +2982,6 @@ paths:
application/json:
schema:
$ref: "#/components/schemas/HTTPValidationError"
"/export/{export_id}/case":
patch:
tags:
- Export
summary: Assign export to case
description: "Assigns an export to a case, or unassigns it if export_case_id is null."
operationId: assign_export_case_export__export_id__case_patch
parameters:
- name: export_id
in: path
required: true
schema:
type: string
title: Export Id
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/ExportCaseAssignBody"
responses:
"200":
description: Successful Response
content:
application/json:
schema:
$ref: "#/components/schemas/GenericResponse"
"422":
description: Validation Error
content:
application/json:
schema:
$ref: "#/components/schemas/HTTPValidationError"
"/export/{camera_name}/start/{start_time}/end/{end_time}":
post:
tags:
@@ -2973,32 +3069,6 @@ paths:
application/json:
schema:
$ref: "#/components/schemas/HTTPValidationError"
"/export/{event_id}":
delete:
tags:
- Export
summary: Delete export
operationId: export_delete_export__event_id__delete
parameters:
- name: event_id
in: path
required: true
schema:
type: string
title: Event Id
responses:
"200":
description: Successful Response
content:
application/json:
schema:
$ref: "#/components/schemas/GenericResponse"
"422":
description: Validation Error
content:
application/json:
schema:
$ref: "#/components/schemas/HTTPValidationError"
"/export/custom/{camera_name}/start/{start_time}/end/{end_time}":
post:
tags:
@@ -6501,6 +6571,149 @@ components:
required:
- recognizedLicensePlate
title: EventsLPRBody
BatchExportBody:
properties:
items:
items:
$ref: "#/components/schemas/BatchExportItem"
type: array
minItems: 1
maxItems: 50
title: Items
description: List of export items. Each item has its own camera and time range.
export_case_id:
anyOf:
- type: string
maxLength: 30
- type: "null"
title: Export case ID
description: Existing export case ID to assign all exports to. Attaching to an existing case is temporarily admin-only until case-level ACLs exist.
new_case_name:
anyOf:
- type: string
maxLength: 100
- type: "null"
title: New case name
description: Name of a new export case to create when export_case_id is omitted
new_case_description:
anyOf:
- type: string
- type: "null"
title: New case description
description: Optional description for a newly created export case
type: object
required:
- items
title: BatchExportBody
BatchExportItem:
properties:
camera:
type: string
title: Camera name
start_time:
type: number
title: Start time
end_time:
type: number
title: End time
image_path:
anyOf:
- type: string
- type: "null"
title: Existing thumbnail path
description: Optional existing image to use as the export thumbnail
friendly_name:
anyOf:
- type: string
maxLength: 256
- type: "null"
title: Friendly name
description: Optional friendly name for this specific export item
client_item_id:
anyOf:
- type: string
maxLength: 128
- type: "null"
title: Client item ID
description: Optional opaque client identifier echoed back in results
type: object
required:
- camera
- start_time
- end_time
title: BatchExportItem
BatchExportResponse:
properties:
export_case_id:
anyOf:
- type: string
- type: "null"
title: Export Case Id
description: Export case ID associated with the batch
export_ids:
items:
type: string
type: array
title: Export Ids
description: Export IDs successfully queued
results:
items:
$ref: "#/components/schemas/BatchExportResultModel"
type: array
title: Results
description: Per-item batch export results
type: object
required:
- export_ids
- results
title: BatchExportResponse
description: Response model for starting an export batch.
BatchExportResultModel:
properties:
camera:
type: string
title: Camera
description: Camera name for this export attempt
export_id:
anyOf:
- type: string
- type: "null"
title: Export Id
description: The export ID when the export was successfully queued
success:
type: boolean
title: Success
description: Whether the export was successfully queued
status:
anyOf:
- type: string
- type: "null"
title: Status
description: Queue status for this camera export
error:
anyOf:
- type: string
- type: "null"
title: Error
description: Validation or queueing error for this item, if any
item_index:
anyOf:
- type: integer
- type: "null"
title: Item Index
description: Zero-based index of this result within the request items list
client_item_id:
anyOf:
- type: string
- type: "null"
title: Client Item Id
description: Opaque client-supplied item identifier echoed from the request
type: object
required:
- camera
- success
title: BatchExportResultModel
description: Per-item result for a batch export request.
EventsSubLabelBody:
properties:
subLabel:
@@ -6523,18 +6736,41 @@ components:
required:
- subLabel
title: EventsSubLabelBody
ExportCaseAssignBody:
ExportBulkDeleteBody:
properties:
ids:
items:
type: string
minLength: 1
type: array
minItems: 1
title: Ids
type: object
required:
- ids
title: ExportBulkDeleteBody
description: Request body for bulk deleting exports.
ExportBulkReassignBody:
properties:
ids:
items:
type: string
minLength: 1
type: array
minItems: 1
title: Ids
export_case_id:
anyOf:
- type: string
maxLength: 30
- type: "null"
title: Export Case Id
description: "Case ID to assign to the export, or null to unassign"
description: "Case ID to assign to, or null to unassign from current case"
type: object
title: ExportCaseAssignBody
description: Request body for assigning or unassigning an export to a case.
required:
- ids
title: ExportBulkReassignBody
description: Request body for bulk reassigning exports to a case.
ExportCaseCreateBody:
properties:
name:
+24
View File
@@ -125,6 +125,16 @@ def metrics(request: Request):
return Response(content=content, media_type=content_type)
@router.get(
"/genai/models",
dependencies=[Depends(allow_any_authenticated())],
summary="List available GenAI models",
description="Returns available models for each configured GenAI provider.",
)
def genai_models(request: Request):
return JSONResponse(content=request.app.genai_manager.list_models())
@router.get("/config", dependencies=[Depends(allow_any_authenticated())])
def config(request: Request):
config_obj: FrigateConfig = request.app.frigate_config
@@ -142,9 +152,20 @@ def config(request: Request):
# remove the proxy secret
config["proxy"].pop("auth_secret", None)
# remove genai api keys
for genai_name, genai_cfg in config.get("genai", {}).items():
if isinstance(genai_cfg, dict):
genai_cfg.pop("api_key", None)
for camera_name, camera in request.app.frigate_config.cameras.items():
camera_dict = config["cameras"][camera_name]
# remove onvif credentials
onvif_dict = camera_dict.get("onvif", {})
if onvif_dict:
onvif_dict.pop("user", None)
onvif_dict.pop("password", None)
# clean paths
for input in camera_dict.get("ffmpeg", {}).get("inputs", []):
input["path"] = clean_camera_user_pass(input["path"])
@@ -673,6 +694,9 @@ def config_set(request: Request, body: AppConfigSetBody):
if request.app.stats_emitter is not None:
request.app.stats_emitter.config = config
if request.app.dispatcher is not None:
request.app.dispatcher.config = config
if body.update_topic:
if body.update_topic.startswith("config/cameras/"):
_, _, camera, field = body.update_topic.split("/")
+5
View File
@@ -64,6 +64,7 @@ def require_admin_by_default():
"/logout",
# Authenticated user endpoints (allow_any_authenticated)
"/profile",
"/profiles",
# Public info endpoints (allow_public)
"/",
"/version",
@@ -87,7 +88,9 @@ def require_admin_by_default():
"/go2rtc/streams",
"/event_ids",
"/events",
"/cases",
"/exports",
"/jobs/export",
}
# Path prefixes that should be exempt (for paths with parameters)
@@ -100,7 +103,9 @@ def require_admin_by_default():
"/go2rtc/streams/", # /go2rtc/streams/{camera}
"/users/", # /users/{username}/password (has own auth)
"/preview/", # /preview/{file}/thumbnail.jpg
"/cases/", # /cases/{case_id}
"/exports/", # /exports/{export_id}
"/jobs/export/", # /jobs/export/{export_id}
"/vod/", # /vod/{camera_name}/...
"/notifications/", # /notifications/pubkey, /notifications/register
)
+14 -1
View File
@@ -30,6 +30,7 @@ from frigate.config.camera.updater import (
CameraConfigUpdateEnum,
CameraConfigUpdateTopic,
)
from frigate.config.env import substitute_frigate_vars
from frigate.util.builtin import clean_camera_user_pass
from frigate.util.camera_cleanup import cleanup_camera_db, cleanup_camera_files
from frigate.util.config import find_config_file
@@ -124,7 +125,10 @@ def go2rtc_add_stream(request: Request, stream_name: str, src: str = ""):
try:
params = {"name": stream_name}
if src:
params["src"] = src
try:
params["src"] = substitute_frigate_vars(src)
except KeyError:
params["src"] = src
r = requests.put(
"http://127.0.0.1:1984/api/streams",
@@ -1220,6 +1224,15 @@ def camera_set(
status_code=400,
)
if not sub_command and feature in _SUB_COMMAND_FEATURES:
return JSONResponse(
content={
"success": False,
"message": f"Feature '{feature}' requires a sub-command (e.g. mask or zone name)",
},
status_code=400,
)
if camera_name == "*":
cameras = list(frigate_config.cameras.keys())
elif camera_name not in frigate_config.cameras:
+557 -106
View File
@@ -3,9 +3,11 @@
import base64
import json
import logging
import operator
import time
from datetime import datetime
from typing import Any, Dict, Generator, List, Optional
from functools import reduce
from typing import Any, Dict, List, Optional
import cv2
from fastapi import APIRouter, Body, Depends, Request
@@ -15,6 +17,15 @@ from pydantic import BaseModel
from frigate.api.auth import (
allow_any_authenticated,
get_allowed_cameras_for_filter,
require_camera_access,
)
from frigate.api.chat_util import (
chunk_content,
distance_to_score,
format_events_with_local_time,
fuse_scores,
hydrate_event,
parse_iso_to_timestamp,
)
from frigate.api.defs.query.events_query_parameters import EventsQueryParams
from frigate.api.defs.request.chat_body import ChatCompletionRequest
@@ -25,61 +36,20 @@ from frigate.api.defs.response.chat_response import (
)
from frigate.api.defs.tags import Tags
from frigate.api.event import events
from frigate.config import FrigateConfig
from frigate.genai.utils import build_assistant_message_for_conversation
from frigate.jobs.vlm_watch import (
get_vlm_watch_job,
start_vlm_watch_job,
stop_vlm_watch_job,
)
from frigate.models import Event
logger = logging.getLogger(__name__)
router = APIRouter(tags=[Tags.chat])
def _chunk_content(content: str, chunk_size: int = 80) -> Generator[str, None, None]:
"""Yield content in word-aware chunks for streaming."""
if not content:
return
words = content.split(" ")
current: List[str] = []
current_len = 0
for w in words:
current.append(w)
current_len += len(w) + 1
if current_len >= chunk_size:
yield " ".join(current) + " "
current = []
current_len = 0
if current:
yield " ".join(current)
def _format_events_with_local_time(
events_list: List[Dict[str, Any]],
) -> List[Dict[str, Any]]:
"""Add human-readable local start/end times to each event for the LLM."""
result = []
for evt in events_list:
if not isinstance(evt, dict):
result.append(evt)
continue
copy_evt = dict(evt)
try:
start_ts = evt.get("start_time")
end_ts = evt.get("end_time")
if start_ts is not None:
dt_start = datetime.fromtimestamp(start_ts)
copy_evt["start_time_local"] = dt_start.strftime("%Y-%m-%d %I:%M:%S %p")
if end_ts is not None:
dt_end = datetime.fromtimestamp(end_ts)
copy_evt["end_time_local"] = dt_end.strftime("%Y-%m-%d %I:%M:%S %p")
except (TypeError, ValueError, OSError):
pass
result.append(copy_evt)
return result
class ToolExecuteRequest(BaseModel):
"""Request model for tool execution."""
@@ -157,6 +127,76 @@ def get_tool_definitions() -> List[Dict[str, Any]]:
"required": [],
},
},
{
"type": "function",
"function": {
"name": "find_similar_objects",
"description": (
"Find tracked objects that are visually and semantically similar "
"to a specific past event. Use this when the user references a "
"particular object they have seen and wants to find other "
"sightings of the same or similar one ('that green car', 'the "
"person in the red jacket', 'the package that was delivered'). "
"Prefer this over search_objects whenever the user's intent is "
"'find more like this specific one.' Use search_objects first "
"only if you need to locate the anchor event. Requires semantic "
"search to be enabled."
),
"parameters": {
"type": "object",
"properties": {
"event_id": {
"type": "string",
"description": "The id of the anchor event to find similar objects to.",
},
"after": {
"type": "string",
"description": "Start time in ISO 8601 format (e.g., '2024-01-01T00:00:00Z').",
},
"before": {
"type": "string",
"description": "End time in ISO 8601 format (e.g., '2024-01-01T23:59:59Z').",
},
"cameras": {
"type": "array",
"items": {"type": "string"},
"description": "Optional list of cameras to restrict to. Defaults to all.",
},
"labels": {
"type": "array",
"items": {"type": "string"},
"description": "Optional list of labels to restrict to. Defaults to the anchor event's label.",
},
"sub_labels": {
"type": "array",
"items": {"type": "string"},
"description": "Optional list of sub_labels (names) to restrict to.",
},
"zones": {
"type": "array",
"items": {"type": "string"},
"description": "Optional list of zones. An event matches if any of its zones overlap.",
},
"similarity_mode": {
"type": "string",
"enum": ["visual", "semantic", "fused"],
"description": "Which similarity signal(s) to use. 'fused' (default) combines visual and semantic.",
"default": "fused",
},
"min_score": {
"type": "number",
"description": "Drop matches with a similarity score below this threshold (0.0-1.0).",
},
"limit": {
"type": "integer",
"description": "Maximum number of matches to return (default: 10).",
"default": 10,
},
},
"required": ["event_id"],
},
},
},
{
"type": "function",
"function": {
@@ -293,6 +333,60 @@ def get_tool_definitions() -> List[Dict[str, Any]]:
},
},
},
{
"type": "function",
"function": {
"name": "get_profile_status",
"description": (
"Get the current profile status including the active profile and "
"timestamps of when each profile was last activated. Use this to "
"determine time periods for recap requests — e.g. when the user asks "
"'what happened while I was away?', call this first to find the relevant "
"time window based on profile activation history."
),
"parameters": {
"type": "object",
"properties": {},
"required": [],
},
},
},
{
"type": "function",
"function": {
"name": "get_recap",
"description": (
"Get a recap of all activity (alerts and detections) for a given time period. "
"Use this after calling get_profile_status to retrieve what happened during "
"a specific window — e.g. 'what happened while I was away?'. Returns a "
"chronological list of activity with camera, objects, zones, and GenAI-generated "
"descriptions when available. Summarize the results for the user."
),
"parameters": {
"type": "object",
"properties": {
"after": {
"type": "string",
"description": "Start of the time period in ISO 8601 format (e.g. '2025-03-15T08:00:00').",
},
"before": {
"type": "string",
"description": "End of the time period in ISO 8601 format (e.g. '2025-03-15T17:00:00').",
},
"cameras": {
"type": "string",
"description": "Comma-separated camera IDs to include, or 'all' for all cameras. Default is 'all'.",
},
"severity": {
"type": "string",
"enum": ["alert", "detection"],
"description": "Filter by severity level. Omit to include both alerts and detections.",
},
},
"required": ["after", "before"],
},
},
},
]
@@ -308,9 +402,38 @@ def get_tools() -> JSONResponse:
return JSONResponse(content={"tools": tools})
def _resolve_zones(
zones: List[str],
config: FrigateConfig,
target_cameras: List[str],
) -> List[str]:
"""Map zone names to their canonical config keys, case-insensitively.
LLMs frequently echo a user's casing ("Front Yard") instead of the
configured key ("front_yard"). The downstream zone filter is a SQLite GLOB
over the JSON-encoded zones column, which is case-sensitive so an
unnormalized name silently returns zero matches. Build a lookup over the
relevant cameras' configured zones and substitute when we find a match;
unknown names pass through so behavior matches what the model asked for.
"""
if not zones:
return zones
lookup: Dict[str, str] = {}
for camera_id in target_cameras:
camera_config = config.cameras.get(camera_id)
if camera_config is None:
continue
for zone_name in camera_config.zones.keys():
lookup.setdefault(zone_name.lower(), zone_name)
return [lookup.get(z.lower(), z) for z in zones]
async def _execute_search_objects(
arguments: Dict[str, Any],
allowed_cameras: List[str],
config: FrigateConfig,
) -> JSONResponse:
"""
Execute the search_objects tool.
@@ -344,6 +467,11 @@ async def _execute_search_objects(
# Convert zones array to comma-separated string if provided
zones = arguments.get("zones")
if isinstance(zones, list):
camera_arg = arguments.get("camera")
target_cameras = (
[camera_arg] if camera_arg and camera_arg != "all" else allowed_cameras
)
zones = _resolve_zones(zones, config, target_cameras)
zones = ",".join(zones)
elif zones is None:
zones = "all"
@@ -352,7 +480,7 @@ async def _execute_search_objects(
query_params = EventsQueryParams(
cameras=arguments.get("camera", "all"),
labels=arguments.get("label", "all"),
sub_labels=arguments.get("sub_label", "all").lower(),
sub_labels=arguments.get("sub_label", "all"), # case-insensitive on the backend
zones=zones,
zone=zones,
after=after,
@@ -379,6 +507,171 @@ async def _execute_search_objects(
)
async def _execute_find_similar_objects(
request: Request,
arguments: Dict[str, Any],
allowed_cameras: List[str],
) -> Dict[str, Any]:
"""Execute the find_similar_objects tool.
Returns a plain dict (not JSONResponse) so the chat loop can embed it
directly in tool-result messages.
"""
# 1. Semantic search enabled?
config = request.app.frigate_config
if not getattr(config.semantic_search, "enabled", False):
return {
"error": "semantic_search_disabled",
"message": (
"Semantic search must be enabled to find similar objects. "
"Enable it in the Frigate config under semantic_search."
),
}
context = request.app.embeddings
if context is None:
return {
"error": "semantic_search_disabled",
"message": "Embeddings context is not available.",
}
# 2. Anchor lookup.
event_id = arguments.get("event_id")
if not event_id:
return {"error": "missing_event_id", "message": "event_id is required."}
try:
anchor = Event.get(Event.id == event_id)
except Event.DoesNotExist:
return {
"error": "anchor_not_found",
"message": f"Could not find event {event_id}.",
}
# 3. Parse params.
after = parse_iso_to_timestamp(arguments.get("after"))
before = parse_iso_to_timestamp(arguments.get("before"))
cameras = arguments.get("cameras")
if cameras:
# Respect RBAC: intersect with the user's allowed cameras.
cameras = [c for c in cameras if c in allowed_cameras]
else:
cameras = list(allowed_cameras) if allowed_cameras else None
labels = arguments.get("labels") or [anchor.label]
sub_labels = arguments.get("sub_labels")
zones = arguments.get("zones")
if zones:
zones = _resolve_zones(
zones, request.app.frigate_config, cameras or list(allowed_cameras)
)
similarity_mode = arguments.get("similarity_mode", "fused")
if similarity_mode not in ("visual", "semantic", "fused"):
similarity_mode = "fused"
min_score = arguments.get("min_score")
limit = int(arguments.get("limit", 10))
limit = max(1, min(limit, 50))
# 4. Run similarity searches. We deliberately do NOT pass event_ids into
# the vec queries — the IN filter on sqlite-vec is broken in the installed
# version (see frigate/embeddings/__init__.py). Mirror the pattern used by
# frigate/api/event.py events_search: fetch top-k globally, then intersect
# with the structured filters via Peewee.
visual_distances: Dict[str, float] = {}
description_distances: Dict[str, float] = {}
try:
if similarity_mode in ("visual", "fused"):
rows = context.search_thumbnail(anchor)
visual_distances = {row[0]: row[1] for row in rows}
if similarity_mode in ("semantic", "fused"):
query_text = (
(anchor.data or {}).get("description")
or anchor.sub_label
or anchor.label
)
rows = context.search_description(query_text)
description_distances = {row[0]: row[1] for row in rows}
except Exception:
logger.exception("Similarity search failed")
return {
"error": "similarity_search_failed",
"message": "Failed to run similarity search.",
}
vec_ids = set(visual_distances) | set(description_distances)
vec_ids.discard(anchor.id)
# vec layer returns up to k=100 per modality; flag when we hit that ceiling
# so the LLM can mention there may be more matches beyond what we saw.
candidate_truncated = (
len(visual_distances) >= 100 or len(description_distances) >= 100
)
if not vec_ids:
return {
"anchor": hydrate_event(anchor),
"results": [],
"similarity_mode": similarity_mode,
"candidate_truncated": candidate_truncated,
}
# 5. Apply structured filters, intersected with vec hits.
clauses = [Event.id.in_(list(vec_ids))]
if after is not None:
clauses.append(Event.start_time >= after)
if before is not None:
clauses.append(Event.start_time <= before)
if cameras:
clauses.append(Event.camera.in_(cameras))
if labels:
clauses.append(Event.label.in_(labels))
if sub_labels:
clauses.append(Event.sub_label.in_(sub_labels))
if zones:
# Mirror the pattern used by frigate/api/event.py for JSON-array zone match.
zone_clauses = [Event.zones.cast("text") % f'*"{zone}"*' for zone in zones]
clauses.append(reduce(operator.or_, zone_clauses))
eligible = {e.id: e for e in Event.select().where(reduce(operator.and_, clauses))}
# 6. Fuse and rank.
scored: List[tuple[str, float]] = []
for eid in eligible:
v_score = (
distance_to_score(visual_distances[eid], context.thumb_stats)
if eid in visual_distances
else None
)
d_score = (
distance_to_score(description_distances[eid], context.desc_stats)
if eid in description_distances
else None
)
fused = fuse_scores(v_score, d_score)
if fused is None:
continue
if min_score is not None and fused < min_score:
continue
scored.append((eid, fused))
scored.sort(key=lambda pair: pair[1], reverse=True)
scored = scored[:limit]
results = [hydrate_event(eligible[eid], score=score) for eid, score in scored]
return {
"anchor": hydrate_event(anchor),
"results": results,
"similarity_mode": similarity_mode,
"candidate_truncated": candidate_truncated,
}
@router.post(
"/chat/execute",
dependencies=[Depends(allow_any_authenticated())],
@@ -402,7 +695,16 @@ async def execute_tool(
logger.debug(f"Executing tool: {tool_name} with arguments: {arguments}")
if tool_name == "search_objects":
return await _execute_search_objects(arguments, allowed_cameras)
return await _execute_search_objects(
arguments, allowed_cameras, request.app.frigate_config
)
if tool_name == "find_similar_objects":
result = await _execute_find_similar_objects(
request, arguments, allowed_cameras
)
status_code = 200 if "error" not in result else 400
return JSONResponse(content=result, status_code=status_code)
if tool_name == "set_camera_state":
result = await _execute_set_camera_state(request, arguments)
@@ -465,45 +767,14 @@ async def _execute_get_live_context(
"detections": list(tracked_objects_dict.values()),
}
# Grab live frame and handle based on provider configuration
# Grab live frame when the chat model supports vision
image_url = await _get_live_frame_image_url(request, camera, allowed_cameras)
if image_url:
genai_manager = request.app.genai_manager
if genai_manager.tool_client is genai_manager.vision_client:
# Same provider handles both roles — pass image URL so it can
# be injected as a user message (images can't be in tool results)
chat_client = request.app.genai_manager.chat_client
if chat_client is not None and chat_client.supports_vision:
# Pass image URL so it can be injected as a user message
# (images can't be in tool results)
result["_image_url"] = image_url
elif genai_manager.vision_client is not None:
# Separate vision provider — have it describe the image,
# providing detection context so it knows what to focus on
frame_bytes = _decode_data_url(image_url)
if frame_bytes:
detections = result.get("detections", [])
if detections:
detection_lines = []
for d in detections:
parts = [d.get("label", "unknown")]
if d.get("sub_label"):
parts.append(f"({d['sub_label']})")
if d.get("zones"):
parts.append(f"in {', '.join(d['zones'])}")
detection_lines.append(" ".join(parts))
context = (
"The following objects are currently being tracked: "
+ "; ".join(detection_lines)
+ "."
)
else:
context = "No objects are currently being tracked."
description = genai_manager.vision_client._send(
f"Describe what you see in this security camera image. "
f"{context} Focus on the scene, any visible activity, "
f"and details about the tracked objects.",
[frame_bytes],
)
if description:
result["image_description"] = description
return result
@@ -554,17 +825,6 @@ async def _get_live_frame_image_url(
return None
def _decode_data_url(data_url: str) -> Optional[bytes]:
"""Decode a base64 data URL to raw bytes."""
try:
# Format: data:image/jpeg;base64,<data>
_, encoded = data_url.split(",", 1)
return base64.b64decode(encoded)
except (ValueError, Exception) as e:
logger.debug("Failed to decode data URL: %s", e)
return None
async def _execute_set_camera_state(
request: Request,
arguments: Dict[str, Any],
@@ -617,7 +877,9 @@ async def _execute_tool_internal(
This is used by the chat completion endpoint to execute tools.
"""
if tool_name == "search_objects":
response = await _execute_search_objects(arguments, allowed_cameras)
response = await _execute_search_objects(
arguments, allowed_cameras, request.app.frigate_config
)
try:
if hasattr(response, "body"):
body_str = response.body.decode("utf-8")
@@ -629,6 +891,8 @@ async def _execute_tool_internal(
except (json.JSONDecodeError, AttributeError) as e:
logger.warning(f"Failed to extract tool result: {e}")
return {"error": "Failed to parse tool result"}
elif tool_name == "find_similar_objects":
return await _execute_find_similar_objects(request, arguments, allowed_cameras)
elif tool_name == "set_camera_state":
return await _execute_set_camera_state(request, arguments)
elif tool_name == "get_live_context":
@@ -645,10 +909,15 @@ async def _execute_tool_internal(
return await _execute_start_camera_watch(request, arguments)
elif tool_name == "stop_camera_watch":
return _execute_stop_camera_watch()
elif tool_name == "get_profile_status":
return _execute_get_profile_status(request)
elif tool_name == "get_recap":
return _execute_get_recap(arguments, allowed_cameras)
else:
logger.error(
"Tool call failed: unknown tool %r. Expected one of: search_objects, get_live_context, "
"start_camera_watch, stop_camera_watch. Arguments received: %s",
"Tool call failed: unknown tool %r. Expected one of: search_objects, find_similar_objects, "
"get_live_context, start_camera_watch, stop_camera_watch, get_profile_status, get_recap. "
"Arguments received: %s",
tool_name,
json.dumps(arguments),
)
@@ -672,10 +941,15 @@ async def _execute_start_camera_watch(
if camera not in config.cameras:
return {"error": f"Camera '{camera}' not found."}
await require_camera_access(camera, request=request)
if zones:
zones = _resolve_zones(zones, config, [camera])
genai_manager = request.app.genai_manager
vision_client = genai_manager.vision_client or genai_manager.tool_client
if vision_client is None:
return {"error": "No vision/GenAI provider configured."}
chat_client = genai_manager.chat_client
if chat_client is None or not chat_client.supports_vision:
return {"error": "VLM watch requires a chat model with vision support."}
try:
job_id = start_vlm_watch_job(
@@ -710,6 +984,168 @@ def _execute_stop_camera_watch() -> Dict[str, Any]:
return {"success": False, "message": "No active watch job to cancel."}
def _execute_get_profile_status(request: Request) -> Dict[str, Any]:
"""Return profile status including active profile and activation timestamps."""
profile_manager = getattr(request.app, "profile_manager", None)
if profile_manager is None:
return {"error": "Profile manager is not available."}
info = profile_manager.get_profile_info()
# Convert timestamps to human-readable local times inline
last_activated = {}
for name, ts in info.get("last_activated", {}).items():
try:
dt = datetime.fromtimestamp(ts)
last_activated[name] = dt.strftime("%Y-%m-%d %I:%M:%S %p")
except (TypeError, ValueError, OSError):
last_activated[name] = str(ts)
return {
"active_profile": info.get("active_profile"),
"profiles": info.get("profiles", []),
"last_activated": last_activated,
}
def _execute_get_recap(
arguments: Dict[str, Any],
allowed_cameras: List[str],
) -> Dict[str, Any]:
"""Fetch review segments with GenAI metadata for a time period."""
from functools import reduce
from peewee import operator
from frigate.models import ReviewSegment
after_str = arguments.get("after")
before_str = arguments.get("before")
def _parse_as_local_timestamp(s: str):
s = s.replace("Z", "").strip()[:19]
dt = datetime.strptime(s, "%Y-%m-%dT%H:%M:%S")
return time.mktime(dt.timetuple())
try:
after = _parse_as_local_timestamp(after_str)
except (ValueError, AttributeError, TypeError):
return {"error": f"Invalid 'after' timestamp: {after_str}"}
try:
before = _parse_as_local_timestamp(before_str)
except (ValueError, AttributeError, TypeError):
return {"error": f"Invalid 'before' timestamp: {before_str}"}
cameras = arguments.get("cameras", "all")
if cameras != "all":
requested = set(cameras.split(","))
camera_list = list(requested.intersection(allowed_cameras))
if not camera_list:
return {"events": [], "message": "No accessible cameras matched."}
else:
camera_list = allowed_cameras
clauses = [
(ReviewSegment.start_time < before)
& ((ReviewSegment.end_time.is_null(True)) | (ReviewSegment.end_time > after)),
(ReviewSegment.camera << camera_list),
]
severity_filter = arguments.get("severity")
if severity_filter:
clauses.append(ReviewSegment.severity == severity_filter)
try:
rows = (
ReviewSegment.select(
ReviewSegment.camera,
ReviewSegment.start_time,
ReviewSegment.end_time,
ReviewSegment.severity,
ReviewSegment.data,
)
.where(reduce(operator.and_, clauses))
.order_by(ReviewSegment.start_time.asc())
.limit(100)
.dicts()
.iterator()
)
events: List[Dict[str, Any]] = []
for row in rows:
data = row.get("data") or {}
if isinstance(data, str):
try:
data = json.loads(data)
except json.JSONDecodeError:
data = {}
camera = row["camera"]
event: Dict[str, Any] = {
"camera": camera.replace("_", " ").title(),
"severity": row.get("severity", "detection"),
}
# Include GenAI metadata when available
metadata = data.get("metadata")
if metadata and isinstance(metadata, dict):
if metadata.get("title"):
event["title"] = metadata["title"]
if metadata.get("scene"):
event["description"] = metadata["scene"]
threat = metadata.get("potential_threat_level")
if threat is not None:
threat_labels = {
0: "normal",
1: "needs_review",
2: "security_concern",
}
event["threat_level"] = threat_labels.get(threat, str(threat))
# Only include objects/zones/audio when there's no GenAI description
# to keep the payload concise — the description already covers these
if "description" not in event:
objects = data.get("objects", [])
if objects:
event["objects"] = objects
zones = data.get("zones", [])
if zones:
event["zones"] = zones
audio = data.get("audio", [])
if audio:
event["audio"] = audio
start_ts = row.get("start_time")
end_ts = row.get("end_time")
if start_ts is not None:
try:
event["time"] = datetime.fromtimestamp(start_ts).strftime(
"%I:%M %p"
)
except (TypeError, ValueError, OSError):
pass
if end_ts is not None and start_ts is not None:
try:
event["duration_seconds"] = round(end_ts - start_ts)
except (TypeError, ValueError):
pass
events.append(event)
if not events:
return {
"events": [],
"message": "No activity was found during this time period.",
}
return {"events": events}
except Exception as e:
logger.error("Error executing get_recap: %s", e, exc_info=True)
return {"error": "Failed to fetch recap data."}
async def _execute_pending_tools(
pending_tool_calls: List[Dict[str, Any]],
request: Request,
@@ -746,7 +1182,7 @@ async def _execute_pending_tools(
json.dumps(tool_args),
)
if tool_name == "search_objects" and isinstance(tool_result, list):
tool_result = _format_events_with_local_time(tool_result)
tool_result = format_events_with_local_time(tool_result)
_keys = {
"id",
"camera",
@@ -847,7 +1283,7 @@ async def chat_completion(
6. Repeats until final answer
7. Returns response to user
"""
genai_client = request.app.genai_manager.tool_client
genai_client = request.app.genai_manager.chat_client
if not genai_client:
return JSONResponse(
content={
@@ -899,7 +1335,9 @@ Do not start your response with phrases like "I will check...", "Let me see...",
Always present times to the user in the server's local timezone. When tool results include start_time_local and end_time_local, use those exact strings when listing or describing detection times—do not convert or invent timestamps. Do not use UTC or ISO format with Z for the user-facing answer unless the tool result only provides Unix timestamps without local time fields.
When users ask about "today", "yesterday", "this week", etc., use the current date above as reference.
When searching for objects or events, use ISO 8601 format for dates (e.g., {current_date_str}T00:00:00Z for the start of today).
Always be accurate with time calculations based on the current date provided.{cameras_section}"""
Always be accurate with time calculations based on the current date provided.
When a user refers to a specific object they have seen or describe with identifying details ("that green car", "the person in the red jacket", "a package left today"), prefer the find_similar_objects tool over search_objects. Use search_objects first only to locate the anchor event, then pass its id to find_similar_objects. For generic queries like "show me all cars today", keep using search_objects. If a user message begins with [attached_event:<id>], treat that event id as the anchor for any similarity or "tell me more" request in the same message and call find_similar_objects with that id.{cameras_section}"""
conversation.append(
{
@@ -937,6 +1375,9 @@ Always be accurate with time calculations based on the current date provided.{ca
async def stream_body_llm():
nonlocal conversation, stream_tool_calls, stream_iterations
while stream_iterations < max_iterations:
if await request.is_disconnected():
logger.debug("Client disconnected, stopping chat stream")
return
logger.debug(
f"Streaming LLM (iteration {stream_iterations + 1}/{max_iterations}) "
f"with {len(conversation)} message(s)"
@@ -946,6 +1387,9 @@ Always be accurate with time calculations based on the current date provided.{ca
tools=tools if tools else None,
tool_choice="auto",
):
if await request.is_disconnected():
logger.debug("Client disconnected, stopping chat stream")
return
kind, value = event
if kind == "content_delta":
yield (
@@ -975,6 +1419,11 @@ Always be accurate with time calculations based on the current date provided.{ca
msg.get("content"), pending
)
)
if await request.is_disconnected():
logger.debug(
"Client disconnected before tool execution"
)
return
(
executed_calls,
tool_results,
@@ -1059,7 +1508,7 @@ Always be accurate with time calculations based on the current date provided.{ca
+ b"\n"
)
# Stream content in word-sized chunks for smooth UX
for part in _chunk_content(final_content):
for part in chunk_content(final_content):
yield (
json.dumps({"type": "content", "delta": part}).encode(
"utf-8"
@@ -1156,12 +1605,14 @@ async def start_vlm_monitor(
status_code=404,
)
vision_client = genai_manager.vision_client or genai_manager.tool_client
if vision_client is None:
await require_camera_access(body.camera, request=request)
chat_client = genai_manager.chat_client
if chat_client is None or not chat_client.supports_vision:
return JSONResponse(
content={
"success": False,
"message": "No vision/GenAI provider configured.",
"message": "VLM watch requires a chat model with vision support.",
},
status_code=400,
)
+135
View File
@@ -0,0 +1,135 @@
"""Pure, stateless helpers used by the chat tool dispatchers.
These were extracted from frigate/api/chat.py to keep that module focused on
route handlers, tool dispatchers, and streaming loop internals. Nothing in
this file touches the FastAPI request, the embeddings context, or the chat
loop state all inputs and outputs are plain data.
"""
import logging
import math
import time
from datetime import datetime
from typing import Any, Dict, Generator, List, Optional
from frigate.embeddings.util import ZScoreNormalization
from frigate.models import Event
logger = logging.getLogger(__name__)
# Similarity fusion weights for find_similar_objects.
# Visual dominates because the feature's primary use case is "same specific object."
# If these change, update the test in test_chat_find_similar_objects.py.
VISUAL_WEIGHT = 0.65
DESCRIPTION_WEIGHT = 0.35
def chunk_content(content: str, chunk_size: int = 80) -> Generator[str, None, None]:
"""Yield content in word-aware chunks for streaming."""
if not content:
return
words = content.split(" ")
current: List[str] = []
current_len = 0
for w in words:
current.append(w)
current_len += len(w) + 1
if current_len >= chunk_size:
yield " ".join(current) + " "
current = []
current_len = 0
if current:
yield " ".join(current)
def format_events_with_local_time(
events_list: List[Dict[str, Any]],
) -> List[Dict[str, Any]]:
"""Add human-readable local start/end times to each event for the LLM."""
result = []
for evt in events_list:
if not isinstance(evt, dict):
result.append(evt)
continue
copy_evt = dict(evt)
try:
start_ts = evt.get("start_time")
end_ts = evt.get("end_time")
if start_ts is not None:
dt_start = datetime.fromtimestamp(start_ts)
copy_evt["start_time_local"] = dt_start.strftime("%Y-%m-%d %I:%M:%S %p")
if end_ts is not None:
dt_end = datetime.fromtimestamp(end_ts)
copy_evt["end_time_local"] = dt_end.strftime("%Y-%m-%d %I:%M:%S %p")
except (TypeError, ValueError, OSError):
pass
result.append(copy_evt)
return result
def distance_to_score(distance: float, stats: ZScoreNormalization) -> float:
"""Convert a cosine distance to a [0, 1] similarity score.
Uses the existing ZScoreNormalization stats maintained by EmbeddingsContext
to normalize across deployments, then a bounded sigmoid. Lower distance ->
higher score. If stats are uninitialized (stddev == 0), returns a neutral
0.5 so the fallback ordering by raw distance still dominates.
"""
if stats.stddev == 0:
return 0.5
z = (distance - stats.mean) / stats.stddev
# Sigmoid on -z so that small distance (good) -> high score.
return 1.0 / (1.0 + math.exp(z))
def fuse_scores(
visual_score: Optional[float],
description_score: Optional[float],
) -> Optional[float]:
"""Weighted fusion of visual and description similarity scores.
If one side is missing (e.g., no description embedding for this event),
the other side's score is returned alone with no penalty. If both are
missing, returns None and the caller should drop the event.
"""
if visual_score is None and description_score is None:
return None
if visual_score is None:
return description_score
if description_score is None:
return visual_score
return VISUAL_WEIGHT * visual_score + DESCRIPTION_WEIGHT * description_score
def parse_iso_to_timestamp(value: Optional[str]) -> Optional[float]:
"""Parse an ISO-8601 string as server-local time -> unix timestamp.
Mirrors the parsing _execute_search_objects uses so both tools accept the
same format from the LLM.
"""
if value is None:
return None
try:
s = value.replace("Z", "").strip()[:19]
dt = datetime.strptime(s, "%Y-%m-%dT%H:%M:%S")
return time.mktime(dt.timetuple())
except (ValueError, AttributeError, TypeError):
logger.warning("Invalid timestamp format: %s", value)
return None
def hydrate_event(event: Event, score: Optional[float] = None) -> Dict[str, Any]:
"""Convert an Event row into the dict shape returned by find_similar_objects."""
data: Dict[str, Any] = {
"id": event.id,
"camera": event.camera,
"label": event.label,
"sub_label": event.sub_label,
"start_time": event.start_time,
"end_time": event.end_time,
"zones": event.zones,
}
if score is not None:
data["score"] = score
return data
@@ -0,0 +1,65 @@
from typing import List, Optional
from pydantic import BaseModel, Field, model_validator
MAX_BATCH_EXPORT_ITEMS = 50
class BatchExportItem(BaseModel):
camera: str = Field(title="Camera name")
start_time: float = Field(title="Start time")
end_time: float = Field(title="End time")
image_path: Optional[str] = Field(
default=None,
title="Existing thumbnail path",
description="Optional existing image to use as the export thumbnail",
)
friendly_name: Optional[str] = Field(
default=None,
title="Friendly name",
max_length=256,
description="Optional friendly name for this specific export item",
)
client_item_id: Optional[str] = Field(
default=None,
title="Client item ID",
max_length=128,
description="Optional opaque client identifier echoed back in results",
)
class BatchExportBody(BaseModel):
items: List[BatchExportItem] = Field(
title="Items",
min_length=1,
max_length=MAX_BATCH_EXPORT_ITEMS,
description="List of export items. Each item has its own camera and time range.",
)
export_case_id: Optional[str] = Field(
default=None,
title="Export case ID",
max_length=30,
description=(
"Existing export case ID to assign all exports to. Attaching to an "
"existing case is temporarily admin-only until case-level ACLs exist."
),
)
new_case_name: Optional[str] = Field(
default=None,
title="New case name",
max_length=100,
description="Name of a new export case to create when export_case_id is omitted",
)
new_case_description: Optional[str] = Field(
default=None,
title="New case description",
description="Optional description for a newly created export case",
)
@model_validator(mode="after")
def validate_case_target(self) -> "BatchExportBody":
for item in self.items:
if item.end_time <= item.start_time:
raise ValueError("end_time must be after start_time")
return self
@@ -0,0 +1,24 @@
"""Request bodies for bulk export operations."""
from typing import Optional
from pydantic import BaseModel, Field, conlist, constr
class ExportBulkDeleteBody(BaseModel):
"""Request body for bulk deleting exports."""
# List of export IDs with at least one element and each element with at least one char
ids: conlist(constr(min_length=1), min_length=1)
class ExportBulkReassignBody(BaseModel):
"""Request body for bulk reassigning exports to a case."""
# List of export IDs with at least one element and each element with at least one char
ids: conlist(constr(min_length=1), min_length=1)
export_case_id: Optional[str] = Field(
default=None,
max_length=30,
description="Case ID to assign to, or null to unassign from current case",
)
@@ -23,13 +23,3 @@ class ExportCaseUpdateBody(BaseModel):
description: Optional[str] = Field(
default=None, description="Updated description of the export case"
)
class ExportCaseAssignBody(BaseModel):
"""Request body for assigning or unassigning an export to a case."""
export_case_id: Optional[str] = Field(
default=None,
max_length=30,
description="Case ID to assign to the export, or null to unassign",
)
+91 -1
View File
@@ -1,4 +1,4 @@
from typing import List, Optional
from typing import Any, List, Optional
from pydantic import BaseModel, Field
@@ -28,6 +28,96 @@ class StartExportResponse(BaseModel):
export_id: Optional[str] = Field(
default=None, description="The export ID if successfully started"
)
status: Optional[str] = Field(
default=None,
description="Queue status for the export job",
)
class BatchExportResultModel(BaseModel):
"""Per-item result for a batch export request."""
camera: str = Field(description="Camera name for this export attempt")
export_id: Optional[str] = Field(
default=None,
description="The export ID when the export was successfully queued",
)
success: bool = Field(description="Whether the export was successfully queued")
status: Optional[str] = Field(
default=None,
description="Queue status for this camera export",
)
error: Optional[str] = Field(
default=None,
description="Validation or queueing error for this item, if any",
)
item_index: Optional[int] = Field(
default=None,
description="Zero-based index of this result within the request items list",
)
client_item_id: Optional[str] = Field(
default=None,
description="Opaque client-supplied item identifier echoed from the request",
)
class BatchExportResponse(BaseModel):
"""Response model for starting an export batch."""
export_case_id: Optional[str] = Field(
default=None,
description="Export case ID associated with the batch",
)
export_ids: List[str] = Field(description="Export IDs successfully queued")
results: List[BatchExportResultModel] = Field(
description="Per-item batch export results"
)
class ExportJobModel(BaseModel):
"""Model representing a queued or running export job."""
id: str = Field(description="Unique identifier for the export job")
job_type: str = Field(description="Job type")
status: str = Field(description="Current job status")
camera: str = Field(description="Camera associated with this export job")
name: Optional[str] = Field(
default=None,
description="Friendly name for the export",
)
export_case_id: Optional[str] = Field(
default=None,
description="ID of the export case this export belongs to",
)
request_start_time: float = Field(description="Requested export start time")
request_end_time: float = Field(description="Requested export end time")
start_time: Optional[float] = Field(
default=None,
description="Unix timestamp when execution started",
)
end_time: Optional[float] = Field(
default=None,
description="Unix timestamp when execution completed",
)
error_message: Optional[str] = Field(
default=None,
description="Error message for failed jobs",
)
results: Optional[dict[str, Any]] = Field(
default=None,
description="Result metadata for completed jobs",
)
current_step: str = Field(
default="queued",
description="Current execution step (queued, preparing, encoding, encoding_retry, finalizing)",
)
progress_percent: float = Field(
default=0.0,
description="Progress percentage of the current step (0.0 - 100.0)",
)
ExportJobsResponse = List[ExportJobModel]
ExportsResponse = List[ExportModel]
+29 -10
View File
@@ -199,13 +199,18 @@ def events(
sub_label_clauses.append((Event.sub_label.is_null()))
for label in filtered_sub_labels:
lowered = label.lower()
sub_label_clauses.append(
(Event.sub_label.cast("text") == label)
) # include exact matches
(fn.LOWER(Event.sub_label.cast("text")) == lowered)
) # include exact matches (case-insensitive)
# include this label when part of a list
sub_label_clauses.append((Event.sub_label.cast("text") % f"*{label},*"))
sub_label_clauses.append((Event.sub_label.cast("text") % f"*, {label}*"))
# include this label when part of a list (LIKE is case-insensitive in sqlite for ASCII)
sub_label_clauses.append(
(fn.LOWER(Event.sub_label.cast("text")) % f"*{lowered},*")
)
sub_label_clauses.append(
(fn.LOWER(Event.sub_label.cast("text")) % f"*, {lowered}*")
)
sub_label_clause = reduce(operator.or_, sub_label_clauses)
clauses.append((sub_label_clause))
@@ -609,13 +614,18 @@ def events_search(
sub_label_clauses.append((Event.sub_label.is_null()))
for label in filtered_sub_labels:
lowered = label.lower()
sub_label_clauses.append(
(Event.sub_label.cast("text") == label)
) # include exact matches
(fn.LOWER(Event.sub_label.cast("text")) == lowered)
) # include exact matches (case-insensitive)
# include this label when part of a list
sub_label_clauses.append((Event.sub_label.cast("text") % f"*{label},*"))
sub_label_clauses.append((Event.sub_label.cast("text") % f"*, {label}*"))
# include this label when part of a list (LIKE is case-insensitive in sqlite for ASCII)
sub_label_clauses.append(
(fn.LOWER(Event.sub_label.cast("text")) % f"*{lowered},*")
)
sub_label_clauses.append(
(fn.LOWER(Event.sub_label.cast("text")) % f"*, {lowered}*")
)
event_filters.append((reduce(operator.or_, sub_label_clauses)))
@@ -744,6 +754,15 @@ def events_search(
status_code=404,
)
if search_event.camera not in allowed_cameras:
return JSONResponse(
content={
"success": False,
"message": "Event not found",
},
status_code=404,
)
thumb_result = context.search_thumbnail(search_event)
thumb_ids = {result[0]: result[1] for result in thumb_result}
search_results = {
+789 -278
View File
File diff suppressed because it is too large Load Diff
+20 -9
View File
@@ -896,6 +896,7 @@ async def event_thumbnail(
if event_id in camera_state.tracked_objects:
tracked_obj = camera_state.tracked_objects.get(event_id)
if tracked_obj is not None:
await require_camera_access(camera_state.name, request=request)
thumbnail_bytes = tracked_obj.get_thumbnail(extension.value)
except Exception:
return JSONResponse(
@@ -1066,7 +1067,7 @@ def grid_snapshot(
@router.delete(
"/{camera_name}/region_grid", dependencies=[Depends(require_role("admin"))]
"/{camera_name}/region_grid", dependencies=[Depends(require_role(["admin"]))]
)
def clear_region_grid(request: Request, camera_name: str):
"""Clear the region grid for a camera."""
@@ -1367,12 +1368,17 @@ def preview_gif(
file_start = f"preview_{camera_name}-"
start_file = f"{file_start}{start_ts}.{PREVIEW_FRAME_TYPE}"
end_file = f"{file_start}{end_ts}.{PREVIEW_FRAME_TYPE}"
camera_files = [
entry.name
for entry in os.scandir(preview_dir)
if entry.name.startswith(file_start)
]
camera_files.sort()
selected_previews = []
for file in sorted(os.listdir(preview_dir)):
if not file.startswith(file_start):
continue
for file in camera_files:
if file < start_file:
continue
@@ -1549,12 +1555,17 @@ def preview_mp4(
file_start = f"preview_{camera_name}-"
start_file = f"{file_start}{start_ts}.{PREVIEW_FRAME_TYPE}"
end_file = f"{file_start}{end_ts}.{PREVIEW_FRAME_TYPE}"
camera_files = [
entry.name
for entry in os.scandir(preview_dir)
if entry.name.startswith(file_start)
]
camera_files.sort()
selected_previews = []
for file in sorted(os.listdir(preview_dir)):
if not file.startswith(file_start):
continue
for file in camera_files:
if file < start_file:
continue
+9 -4
View File
@@ -148,12 +148,17 @@ def get_preview_frames_from_cache(camera_name: str, start_ts: float, end_ts: flo
file_start = f"preview_{camera_name}-"
start_file = f"{file_start}{start_ts}.{PREVIEW_FRAME_TYPE}"
end_file = f"{file_start}{end_ts}.{PREVIEW_FRAME_TYPE}"
camera_files = [
entry.name
for entry in os.scandir(preview_dir)
if entry.name.startswith(file_start)
]
camera_files.sort()
selected_previews = []
for file in sorted(os.listdir(preview_dir)):
if not file.startswith(file_start):
continue
for file in camera_files:
if file < start_file:
continue
+1 -1
View File
@@ -35,7 +35,7 @@ logger = logging.getLogger(__name__)
router = APIRouter(tags=[Tags.recordings])
@router.get("/recordings/storage", dependencies=[Depends(allow_any_authenticated())])
@router.get("/recordings/storage", dependencies=[Depends(require_role(["admin"]))])
def get_recordings_storage_usage(request: Request):
recording_stats = request.app.stats_emitter.get_latest_stats()["service"][
"storage"
+2 -2
View File
@@ -742,11 +742,11 @@ async def set_not_reviewed(
@router.post(
"/review/summarize/start/{start_ts}/end/{end_ts}",
dependencies=[Depends(allow_any_authenticated())],
dependencies=[Depends(require_role(["admin"]))],
description="Use GenAI to summarize review items over a period of time.",
)
def generate_review_summary(request: Request, start_ts: float, end_ts: float):
if not request.app.genai_manager.vision_client:
if not request.app.genai_manager.description_client:
return JSONResponse(
content=(
{
+6 -16
View File
@@ -52,6 +52,7 @@ from frigate.embeddings import EmbeddingProcess, EmbeddingsContext
from frigate.events.audio import AudioProcessor
from frigate.events.cleanup import EventCleanup
from frigate.events.maintainer import EventProcessor
from frigate.jobs.export import reap_stale_exports
from frigate.jobs.motion_search import stop_all_motion_search_jobs
from frigate.log import _stop_logging
from frigate.models import (
@@ -188,17 +189,6 @@ class FrigateApp:
except PermissionError:
logger.error("Unable to write to /config to save DB state")
def cleanup_timeline_db(db: SqliteExtDatabase) -> None:
db.execute_sql(
"DELETE FROM timeline WHERE source_id NOT IN (SELECT id FROM event);"
)
try:
with open(f"{CONFIG_DIR}/.timeline", "w") as f:
f.write(str(datetime.datetime.now().timestamp()))
except PermissionError:
logger.error("Unable to write to /config to save DB state")
# Migrate DB schema
migrate_db = SqliteExtDatabase(self.config.database.path)
@@ -215,11 +205,6 @@ class FrigateApp:
router.run()
# this is a temporary check to clean up user DB from beta
# will be removed before final release
if not os.path.exists(f"{CONFIG_DIR}/.timeline"):
cleanup_timeline_db(migrate_db)
# check if vacuum needs to be run
if os.path.exists(f"{CONFIG_DIR}/.vacuum"):
with open(f"{CONFIG_DIR}/.vacuum") as f:
@@ -611,6 +596,11 @@ class FrigateApp:
# Clean up any stale replay camera artifacts (filesystem + DB)
cleanup_replay_cameras()
# Reap any Export rows still marked in_progress from a previous
# session (crash, kill, broken migration). Runs synchronously before
# uvicorn binds so no API request can observe a stale row.
reap_stale_exports()
self.init_inter_process_communicator()
self.start_detectors()
self.init_dispatcher()
+56 -5
View File
@@ -54,6 +54,28 @@ class CameraState:
self.ptz_autotracker_thread = ptz_autotracker_thread
self.prev_enabled = self.camera_config.enabled
# Minimum object area thresholds for fast-tracking updates to secondary
# face/LPR pipelines when using a model without built-in detection.
self.face_recognition_min_obj_area: int = 0
self.lpr_min_obj_area: int = 0
if (
self.camera_config.face_recognition.enabled
and "face" not in config.objects.all_objects
):
# A face is roughly 1/8 of person box area; use a conservative
# multiplier so fast-tracking starts slightly before the optimal zone
self.face_recognition_min_obj_area = (
self.camera_config.face_recognition.min_area * 6
)
if (
self.camera_config.lpr.enabled
and "license_plate" not in self.camera_config.objects.track
):
# A plate is a smaller fraction of a vehicle box; use ~20x multiplier
self.lpr_min_obj_area = self.camera_config.lpr.min_area * 20
def get_current_frame(self, draw_options: dict[str, Any] = {}) -> np.ndarray:
with self.current_frame_lock:
frame_copy = np.copy(self._current_frame)
@@ -372,13 +394,30 @@ class CameraState:
updated_obj.last_updated = frame_time
# if it has been more than 5 seconds since the last thumb update
# and the last update is greater than the last publish or
# the object has changed significantly or
# the object moved enough to update the path
# Determine the staleness threshold for publishing updates.
# Fast-track to 1s for objects in the optimal size range for
# secondary face/LPR recognition that don't yet have a sub_label.
obj_area = updated_obj.obj_data.get("area", 0)
obj_label = updated_obj.obj_data.get("label")
publish_threshold = 5
if (
obj_label == "person"
and self.face_recognition_min_obj_area > 0
and obj_area >= self.face_recognition_min_obj_area
and updated_obj.obj_data.get("sub_label") is None
) or (
obj_label in ("car", "motorcycle")
and self.lpr_min_obj_area > 0
and obj_area >= self.lpr_min_obj_area
and updated_obj.obj_data.get("sub_label") is None
and updated_obj.obj_data.get("recognized_license_plate") is None
):
publish_threshold = 1
if (
(
frame_time - updated_obj.last_published > 5
frame_time - updated_obj.last_published > publish_threshold
and updated_obj.last_updated > updated_obj.last_published
)
or significant_update
@@ -389,6 +428,18 @@ class CameraState:
c(self.name, updated_obj, frame_name)
updated_obj.last_published = frame_time
# send MQTT snapshot when object first enters a required zone,
# since the initial snapshot at creation time is blocked before
# zone evaluation has run
if updated_obj.new_zone_entered and not updated_obj.false_positive:
mqtt_required = self.camera_config.mqtt.required_zones
if mqtt_required and set(updated_obj.entered_zones) & set(
mqtt_required
):
object_type = updated_obj.obj_data["label"]
self.send_mqtt_snapshot(updated_obj, object_type)
updated_obj.new_zone_entered = False
for id in removed_ids:
# publish events to mqtt
removed_obj = tracked_objects[id]
+11
View File
@@ -118,10 +118,21 @@ class Dispatcher:
try:
if command_type == "set":
# Commands that require a sub-command (mask/zone name)
sub_command_required = {
"motion_mask",
"object_mask",
"zone",
}
if sub_command:
self._camera_settings_handlers[command](
camera_name, sub_command, payload
)
elif command in sub_command_required:
logger.error(
"Command %s requires a sub-command (mask/zone name)",
command,
)
else:
self._camera_settings_handlers[command](camera_name, payload)
elif command_type == "ptz":
+10 -2
View File
@@ -542,13 +542,21 @@ class WebPushClient(Communicator):
self.check_registrations()
reasoning: str = payload.get("reasoning", "")
text: str = payload.get("message") or payload.get("reasoning", "")
title = f"{camera_name}: Monitoring Alert"
message = (reasoning[:197] + "...") if len(reasoning) > 200 else reasoning
message = (text[:197] + "...") if len(text) > 200 else text
logger.debug(f"Sending camera monitoring push notification for {camera_name}")
for user in self.web_pushers:
if not self._user_has_camera_access(user, camera):
logger.debug(
"Skipping notification for user %s - no access to camera %s",
user,
camera,
)
continue
self.send_push_notification(
user=user,
payload=payload,
+9 -1
View File
@@ -1,6 +1,6 @@
from typing import Optional
from pydantic import Field
from pydantic import Field, model_validator
from ..base import FrigateBaseModel
@@ -88,3 +88,11 @@ class DetectConfig(FrigateBaseModel):
title="Annotation offset",
description="Milliseconds to shift detect annotations to better align timeline bounding boxes with recordings; can be positive or negative.",
)
@model_validator(mode="after")
def validate_dimensions(self) -> "DetectConfig":
if (self.width is None) != (self.height is None):
raise ValueError(
"detect -> both width and height must be specified together, or both omitted"
)
return self
+7 -7
View File
@@ -18,8 +18,8 @@ class GenAIProviderEnum(str, Enum):
class GenAIRoleEnum(str, Enum):
tools = "tools"
vision = "vision"
chat = "chat"
descriptions = "descriptions"
embeddings = "embeddings"
@@ -49,21 +49,21 @@ class GenAIConfig(FrigateBaseModel):
roles: list[GenAIRoleEnum] = Field(
default_factory=lambda: [
GenAIRoleEnum.embeddings,
GenAIRoleEnum.vision,
GenAIRoleEnum.tools,
GenAIRoleEnum.descriptions,
GenAIRoleEnum.chat,
],
title="Roles",
description="GenAI roles (tools, vision, embeddings); one provider per role.",
description="GenAI roles (chat, descriptions, embeddings); one provider per role.",
)
provider_options: dict[str, Any] = Field(
default={},
title="Provider options",
description="Additional provider-specific options to pass to the GenAI client.",
json_schema_extra={"additionalProperties": {"type": "string"}},
json_schema_extra={"additionalProperties": {}},
)
runtime_options: dict[str, Any] = Field(
default={},
title="Runtime options",
description="Runtime options passed to the provider for each inference call.",
json_schema_extra={"additionalProperties": {"type": "string"}},
json_schema_extra={"additionalProperties": {}},
)
+6
View File
@@ -92,6 +92,12 @@ class RecordExportConfig(FrigateBaseModel):
title="Export hwaccel args",
description="Hardware acceleration args to use for export/transcode operations.",
)
max_concurrent: int = Field(
default=3,
ge=1,
title="Maximum concurrent exports",
description="Maximum number of export jobs to process at the same time.",
)
class RecordConfig(FrigateBaseModel):
+1 -1
View File
@@ -188,7 +188,7 @@ class ReviewConfig(FrigateBaseModel):
detections: DetectionsConfig = Field(
default_factory=DetectionsConfig,
title="Detections config",
description="Settings for creating detection events (non-alert) and how long to keep them.",
description="Settings for which tracked objects generate detections (non-alert) and how detections are retained.",
)
genai: GenAIReviewConfig = Field(
default_factory=GenAIReviewConfig,
+2
View File
@@ -20,6 +20,7 @@ class CameraConfigUpdateEnum(str, Enum):
ffmpeg = "ffmpeg"
live = "live"
motion = "motion" # includes motion and motion masks
mqtt = "mqtt"
notifications = "notifications"
objects = "objects"
object_genai = "object_genai"
@@ -33,6 +34,7 @@ class CameraConfigUpdateEnum(str, Enum):
lpr = "lpr"
snapshots = "snapshots"
timestamp_style = "timestamp_style"
ui = "ui"
zones = "zones"
+12 -1
View File
@@ -1,7 +1,7 @@
from enum import Enum
from typing import Dict, List, Optional, Union
from pydantic import ConfigDict, Field
from pydantic import ConfigDict, Field, field_validator
from .base import FrigateBaseModel
@@ -178,6 +178,17 @@ class SemanticSearchConfig(FrigateBaseModel):
title="Semantic search model or GenAI provider name",
description="The embeddings model to use for semantic search (for example 'jinav1'), or the name of a GenAI provider with the embeddings role.",
)
@field_validator("model", mode="before")
@classmethod
def coerce_model_enum(cls, v):
if isinstance(v, str):
try:
return SemanticSearchModelEnum(v)
except ValueError:
return v
return v
model_size: str = Field(
default="small",
title="Model size",

Some files were not shown because too many files have changed in this diff Show More