Use dataclasses for config handling
Use config data classes to eliminate some of the boilerplate associated
with setting up the configuration. In particular, using dataclasses
removes a lot of the boilerplate around assigning properties to the
object and allows these to be easily immutable by freezing them. In the
case of simple, non-nested dataclasses, this also provides more
convenient `asdict` helpers.
To set this up, where previously the objects would be parsed from the
config via the `__init__` method, create a `build` classmethod that does
this and calls the dataclass initializer.
Some of the objects are mutated at runtime, in particular some of the
zones are mutated to set the color (this might be able to be refactored
out) and some of the camera functionality can be enabled/disabled. Some
of the configs with `enabled` properties don't seem to have mqtt hooks
to be able to toggle this, in particular, the clips, snapshots, and
detect can be toggled but rtmp and record configs do not, but all of
these configs are still not frozen in case there is some other
functionality I am missing.
There are a couple other minor fixes here, one that was introduced
by me recently where `max_seconds` was not defined, the other to
properly `get()` the message payload when handling publishing mqtt
messages sent via websocket.
2021-05-23 00:28:15 +02:00
from __future__ import annotations
2020-11-03 15:15:58 +01:00
import json
2020-12-21 15:03:27 +01:00
import logging
2020-11-03 15:15:58 +01:00
import os
2024-09-15 17:01:15 +02:00
import shutil
2021-08-16 15:02:04 +02:00
from enum import Enum
2023-11-02 11:35:30 +01:00
from pathlib import Path
2024-03-01 00:10:13 +01:00
from typing import Any , Dict , List , Optional , Tuple , Union
2020-11-03 15:15:58 +01:00
import numpy as np
2024-03-01 00:10:13 +01:00
from pydantic import (
BaseModel ,
ConfigDict ,
Field ,
TypeAdapter ,
ValidationInfo ,
field_serializer ,
field_validator ,
)
2021-06-24 07:45:27 +02:00
from pydantic . fields import PrivateAttr
2020-11-01 13:17:44 +01:00
2023-07-17 13:07:15 +02:00
from frigate . const import (
2023-09-30 14:38:15 +02:00
ALL_ATTRIBUTE_LABELS ,
2023-07-17 13:07:15 +02:00
AUDIO_MIN_CONFIDENCE ,
CACHE_DIR ,
2023-11-05 21:30:29 +01:00
CACHE_SEGMENT_FORMAT ,
2023-07-17 13:07:15 +02:00
DEFAULT_DB_PATH ,
2024-07-02 00:08:14 +02:00
FREQUENCY_STATS_POINTS ,
2023-11-18 22:37:06 +01:00
MAX_PRE_CAPTURE ,
2023-07-17 13:07:15 +02:00
REGEX_CAMERA_NAME ,
YAML_EXT ,
)
2023-05-29 12:31:17 +02:00
from frigate . detectors import DetectorConfig , ModelConfig
2023-04-24 14:24:28 +02:00
from frigate . detectors . detector_config import BaseDetectorConfig
2022-11-29 04:48:11 +01:00
from frigate . ffmpeg_presets import (
2022-12-30 17:56:52 +01:00
parse_preset_hardware_acceleration_decode ,
parse_preset_hardware_acceleration_scale ,
2022-11-29 04:48:11 +01:00
parse_preset_input ,
parse_preset_output_record ,
)
2023-05-29 12:31:17 +02:00
from frigate . plus import PlusApi
2023-07-06 16:28:50 +02:00
from frigate . util . builtin import (
2023-05-29 12:31:17 +02:00
deep_merge ,
escape_special_characters ,
2024-07-07 20:53:00 +02:00
generate_color_palette ,
2023-05-29 12:31:17 +02:00
get_ffmpeg_arg_list ,
load_config_with_no_duplicates ,
2022-12-15 14:12:52 +01:00
)
2024-05-29 15:41:41 +02:00
from frigate . util . config import StreamInfoRetriever , get_relative_coordinates
2023-07-06 16:28:50 +02:00
from frigate . util . image import create_mask
2024-05-29 15:41:41 +02:00
from frigate . util . services import auto_detect_hwaccel
2022-12-15 14:12:52 +01:00
2020-12-21 15:03:27 +01:00
logger = logging . getLogger ( __name__ )
2021-06-15 22:19:49 +02:00
# TODO: Identify what the default format to display timestamps is
DEFAULT_TIME_FORMAT = " % m/ %d / % Y % H: % M: % S "
# German Style:
# DEFAULT_TIME_FORMAT = "%d.%m.%Y %H:%M:%S"
2021-01-16 14:39:08 +01:00
2021-06-24 07:45:27 +02:00
FRIGATE_ENV_VARS = { k : v for k , v in os . environ . items ( ) if k . startswith ( " FRIGATE_ " ) }
2023-11-02 11:35:30 +01:00
# read docker secret files as env vars too
2024-02-29 00:18:34 +01:00
if os . path . isdir ( " /run/secrets " ) and os . access ( " /run/secrets " , os . R_OK ) :
2023-11-02 11:35:30 +01:00
for secret_file in os . listdir ( " /run/secrets " ) :
if secret_file . startswith ( " FRIGATE_ " ) :
2024-07-12 15:36:15 +02:00
FRIGATE_ENV_VARS [ secret_file ] = (
Path ( os . path . join ( " /run/secrets " , secret_file ) ) . read_text ( ) . strip ( )
)
2021-06-24 07:45:27 +02:00
2021-06-15 22:19:49 +02:00
DEFAULT_TRACKED_OBJECTS = [ " person " ]
2024-02-21 00:26:09 +01:00
DEFAULT_ALERT_OBJECTS = [ " person " , " car " ]
2023-09-21 12:23:26 +02:00
DEFAULT_LISTEN_AUDIO = [ " bark " , " fire_alarm " , " scream " , " speech " , " yell " ]
2021-08-16 14:39:20 +02:00
DEFAULT_DETECTORS = { " cpu " : { " type " : " cpu " } }
2023-07-14 13:56:03 +02:00
DEFAULT_DETECT_DIMENSIONS = { " width " : 1280 , " height " : 720 }
2023-09-21 14:20:05 +02:00
DEFAULT_TIME_LAPSE_FFMPEG_ARGS = " -vf setpts=0.04*PTS -r 30 "
Use dataclasses for config handling
Use config data classes to eliminate some of the boilerplate associated
with setting up the configuration. In particular, using dataclasses
removes a lot of the boilerplate around assigning properties to the
object and allows these to be easily immutable by freezing them. In the
case of simple, non-nested dataclasses, this also provides more
convenient `asdict` helpers.
To set this up, where previously the objects would be parsed from the
config via the `__init__` method, create a `build` classmethod that does
this and calls the dataclass initializer.
Some of the objects are mutated at runtime, in particular some of the
zones are mutated to set the color (this might be able to be refactored
out) and some of the camera functionality can be enabled/disabled. Some
of the configs with `enabled` properties don't seem to have mqtt hooks
to be able to toggle this, in particular, the clips, snapshots, and
detect can be toggled but rtmp and record configs do not, but all of
these configs are still not frozen in case there is some other
functionality I am missing.
There are a couple other minor fixes here, one that was introduced
by me recently where `max_seconds` was not defined, the other to
properly `get()` the message payload when handling publishing mqtt
messages sent via websocket.
2021-05-23 00:28:15 +02:00
2024-05-29 15:41:41 +02:00
# stream info handler
stream_info_retriever = StreamInfoRetriever ( )
Use dataclasses for config handling
Use config data classes to eliminate some of the boilerplate associated
with setting up the configuration. In particular, using dataclasses
removes a lot of the boilerplate around assigning properties to the
object and allows these to be easily immutable by freezing them. In the
case of simple, non-nested dataclasses, this also provides more
convenient `asdict` helpers.
To set this up, where previously the objects would be parsed from the
config via the `__init__` method, create a `build` classmethod that does
this and calls the dataclass initializer.
Some of the objects are mutated at runtime, in particular some of the
zones are mutated to set the color (this might be able to be refactored
out) and some of the camera functionality can be enabled/disabled. Some
of the configs with `enabled` properties don't seem to have mqtt hooks
to be able to toggle this, in particular, the clips, snapshots, and
detect can be toggled but rtmp and record configs do not, but all of
these configs are still not frozen in case there is some other
functionality I am missing.
There are a couple other minor fixes here, one that was introduced
by me recently where `max_seconds` was not defined, the other to
properly `get()` the message payload when handling publishing mqtt
messages sent via websocket.
2021-05-23 00:28:15 +02:00
2021-09-04 23:56:01 +02:00
class FrigateBaseModel ( BaseModel ) :
2024-03-01 00:10:13 +01:00
model_config = ConfigDict ( extra = " forbid " , protected_namespaces = ( ) )
2021-09-04 23:56:01 +02:00
2023-01-14 00:27:16 +01:00
class LiveModeEnum ( str , Enum ) :
jsmpeg = " jsmpeg "
mse = " mse "
webrtc = " webrtc "
2023-02-26 16:37:18 +01:00
class TimeFormatEnum ( str , Enum ) :
browser = " browser "
hours12 = " 12hour "
hours24 = " 24hour "
2023-02-22 14:54:16 +01:00
class DateTimeStyleEnum ( str , Enum ) :
full = " full "
long = " long "
medium = " medium "
short = " short "
2022-02-27 15:04:12 +01:00
class UIConfig ( FrigateBaseModel ) :
2024-03-01 00:10:13 +01:00
timezone : Optional [ str ] = Field ( default = None , title = " Override UI timezone. " )
2023-02-26 16:37:18 +01:00
time_format : TimeFormatEnum = Field (
default = TimeFormatEnum . browser , title = " Override UI time format. "
)
2023-02-22 14:54:16 +01:00
date_style : DateTimeStyleEnum = Field (
default = DateTimeStyleEnum . short , title = " Override UI dateStyle. "
)
time_style : DateTimeStyleEnum = Field (
default = DateTimeStyleEnum . medium , title = " Override UI timeStyle. "
)
strftime_fmt : Optional [ str ] = Field (
default = None , title = " Override date and time format using strftime syntax. "
)
2021-06-24 07:45:27 +02:00
2022-04-16 15:42:44 +02:00
2024-06-02 14:48:28 +02:00
class TlsConfig ( FrigateBaseModel ) :
2024-06-29 15:18:40 +02:00
enabled : bool = Field ( default = True , title = " Enable TLS for port 8971 " )
2024-06-02 14:48:28 +02:00
2024-05-18 18:36:13 +02:00
class HeaderMappingConfig ( FrigateBaseModel ) :
user : str = Field (
default = None , title = " Header name from upstream proxy to identify user. "
)
2024-06-15 01:02:13 +02:00
class ProxyConfig ( FrigateBaseModel ) :
header_map : HeaderMappingConfig = Field (
default_factory = HeaderMappingConfig ,
title = " Header mapping definitions for proxy user passing. " ,
)
logout_url : Optional [ str ] = Field (
default = None , title = " Redirect url for logging out with proxy. "
)
auth_secret : Optional [ str ] = Field (
default = None ,
title = " Secret value for proxy authentication. " ,
)
2024-05-18 18:36:13 +02:00
class AuthConfig ( FrigateBaseModel ) :
2024-06-15 01:02:13 +02:00
enabled : bool = Field ( default = True , title = " Enable authentication " )
2024-05-18 18:36:13 +02:00
reset_admin_password : bool = Field (
default = False , title = " Reset the admin password on startup "
)
cookie_name : str = Field (
default = " frigate_token " , title = " Name for jwt token cookie " , pattern = r " ^[a-z]_*$ "
)
2024-05-18 21:53:49 +02:00
cookie_secure : bool = Field ( default = False , title = " Set secure flag on cookie " )
2024-05-18 18:36:13 +02:00
session_length : int = Field (
default = 86400 , title = " Session length for jwt session tokens " , ge = 60
)
refresh_time : int = Field (
default = 43200 ,
title = " Refresh the session if it is going to expire in this many seconds " ,
ge = 30 ,
)
failed_login_rate_limit : Optional [ str ] = Field (
default = None ,
title = " Rate limits for failed login attempts. " ,
)
trusted_proxies : List [ str ] = Field (
default = [ ] ,
title = " Trusted proxies for determining IP address to rate limit " ,
)
# As of Feb 2023, OWASP recommends 600000 iterations for PBKDF2-SHA256
hash_iterations : int = Field ( default = 600000 , title = " Password hash iterations " )
2024-07-22 22:39:15 +02:00
class NotificationConfig ( FrigateBaseModel ) :
enabled : bool = Field ( default = False , title = " Enable notifications " )
email : Optional [ str ] = Field ( default = None , title = " Email required for push. " )
2024-09-10 19:24:44 +02:00
enabled_in_config : Optional [ bool ] = Field (
default = None , title = " Keep track of original state of notifications. "
)
2024-07-22 22:39:15 +02:00
2023-06-11 15:26:34 +02:00
class StatsConfig ( FrigateBaseModel ) :
amd_gpu_stats : bool = Field ( default = True , title = " Enable AMD GPU stats. " )
intel_gpu_stats : bool = Field ( default = True , title = " Enable Intel GPU stats. " )
network_bandwidth : bool = Field (
default = False , title = " Enable network bandwidth for ffmpeg processes. "
)
2023-01-26 01:36:26 +01:00
class TelemetryConfig ( FrigateBaseModel ) :
2023-06-11 14:34:03 +02:00
network_interfaces : List [ str ] = Field (
2023-09-21 12:26:22 +02:00
default = [ ] ,
2023-06-11 14:34:03 +02:00
title = " Enabled network interfaces for bandwidth calculation. " ,
)
2023-06-11 15:26:34 +02:00
stats : StatsConfig = Field (
default_factory = StatsConfig , title = " System Stats Configuration "
)
2023-01-26 01:36:26 +01:00
version_check : bool = Field ( default = True , title = " Enable latest version check. " )
2021-09-04 23:56:01 +02:00
class MqttConfig ( FrigateBaseModel ) :
2022-11-24 03:03:20 +01:00
enabled : bool = Field ( title = " Enable MQTT Communication. " , default = True )
2023-01-04 02:24:53 +01:00
host : str = Field ( default = " " , title = " MQTT Host " )
2021-06-24 07:45:27 +02:00
port : int = Field ( default = 1883 , title = " MQTT Port " )
topic_prefix : str = Field ( default = " frigate " , title = " MQTT Topic Prefix " )
client_id : str = Field ( default = " frigate " , title = " MQTT Client ID " )
2024-07-02 00:08:14 +02:00
stats_interval : int = Field (
default = 60 , ge = FREQUENCY_STATS_POINTS , title = " MQTT Camera Stats Interval "
)
2024-03-01 00:10:13 +01:00
user : Optional [ str ] = Field ( None , title = " MQTT Username " )
password : Optional [ str ] = Field ( None , title = " MQTT Password " , validate_default = True )
tls_ca_certs : Optional [ str ] = Field ( None , title = " MQTT TLS CA Certificates " )
tls_client_cert : Optional [ str ] = Field ( None , title = " MQTT TLS Client Certificate " )
tls_client_key : Optional [ str ] = Field ( None , title = " MQTT TLS Client Key " )
tls_insecure : Optional [ bool ] = Field ( None , title = " MQTT TLS Insecure " )
@field_validator ( " password " )
def user_requires_pass ( cls , v , info : ValidationInfo ) :
if ( v is None ) != ( info . data [ " user " ] is None ) :
2021-06-24 07:45:27 +02:00
raise ValueError ( " Password must be provided with username. " )
2021-06-24 22:53:01 +02:00
return v
2021-06-24 07:45:27 +02:00
2023-09-27 13:19:10 +02:00
class ZoomingModeEnum ( str , Enum ) :
disabled = " disabled "
absolute = " absolute "
relative = " relative "
2023-07-08 14:04:47 +02:00
class PtzAutotrackConfig ( FrigateBaseModel ) :
enabled : bool = Field ( default = False , title = " Enable PTZ object autotracking. " )
2023-09-27 13:19:10 +02:00
calibrate_on_startup : bool = Field (
default = False , title = " Perform a camera calibration when Frigate starts. "
)
zooming : ZoomingModeEnum = Field (
default = ZoomingModeEnum . disabled , title = " Autotracker zooming mode. "
)
2023-09-29 01:21:37 +02:00
zoom_factor : float = Field (
default = 0.3 ,
title = " Zooming factor (0.1-0.75). " ,
ge = 0.1 ,
le = 0.75 ,
)
2023-07-08 14:04:47 +02:00
track : List [ str ] = Field ( default = DEFAULT_TRACKED_OBJECTS , title = " Objects to track. " )
required_zones : List [ str ] = Field (
default_factory = list ,
title = " List of required zones to be entered in order to begin autotracking. " ,
)
return_preset : str = Field (
default = " home " ,
title = " Name of camera preset to return to when object tracking is over. " ,
)
timeout : int = Field (
default = 10 , title = " Seconds to delay before returning to preset. "
)
2023-11-01 12:12:43 +01:00
movement_weights : Optional [ Union [ str , List [ str ] ] ] = Field (
2023-09-27 13:19:10 +02:00
default = [ ] ,
title = " Internal value used for PTZ movements based on the speed of your camera ' s motor. " ,
)
2023-11-16 02:25:48 +01:00
enabled_in_config : Optional [ bool ] = Field (
2024-03-01 00:10:13 +01:00
None , title = " Keep track of original state of autotracking. "
2023-11-16 02:25:48 +01:00
)
2023-09-27 13:19:10 +02:00
2024-03-01 00:10:13 +01:00
@field_validator ( " movement_weights " , mode = " before " )
@classmethod
2023-09-27 13:19:10 +02:00
def validate_weights ( cls , v ) :
if v is None :
return None
if isinstance ( v , str ) :
2024-03-01 00:10:13 +01:00
weights = list ( map ( str , map ( float , v . split ( " , " ) ) ) )
2023-09-27 13:19:10 +02:00
elif isinstance ( v , list ) :
2024-03-01 00:10:13 +01:00
weights = [ str ( float ( val ) ) for val in v ]
2023-09-27 13:19:10 +02:00
else :
raise ValueError ( " Invalid type for movement_weights " )
2023-10-22 18:59:13 +02:00
if len ( weights ) != 5 :
raise ValueError ( " movement_weights must have exactly 5 floats " )
2023-09-27 13:19:10 +02:00
return weights
2023-07-08 14:04:47 +02:00
2023-04-26 13:08:53 +02:00
class OnvifConfig ( FrigateBaseModel ) :
host : str = Field ( default = " " , title = " Onvif Host " )
port : int = Field ( default = 8000 , title = " Onvif Port " )
2024-03-01 00:10:13 +01:00
user : Optional [ str ] = Field ( None , title = " Onvif Username " )
password : Optional [ str ] = Field ( None , title = " Onvif Password " )
2023-07-08 14:04:47 +02:00
autotracking : PtzAutotrackConfig = Field (
default_factory = PtzAutotrackConfig ,
title = " PTZ auto tracking config. " ,
)
2024-07-09 21:00:47 +02:00
ignore_time_mismatch : bool = Field (
default = False ,
title = " Onvif Ignore Time Synchronization Mismatch Between Camera and Server " ,
)
2023-04-26 13:08:53 +02:00
2021-12-11 16:22:44 +01:00
class RetainModeEnum ( str , Enum ) :
all = " all "
motion = " motion "
active_objects = " active_objects "
2024-09-02 15:22:53 +02:00
class RecordRetainConfig ( FrigateBaseModel ) :
days : float = Field ( default = 0 , title = " Default retention period. " )
mode : RetainModeEnum = Field ( default = RetainModeEnum . all , title = " Retain mode. " )
Use dataclasses for config handling
Use config data classes to eliminate some of the boilerplate associated
with setting up the configuration. In particular, using dataclasses
removes a lot of the boilerplate around assigning properties to the
object and allows these to be easily immutable by freezing them. In the
case of simple, non-nested dataclasses, this also provides more
convenient `asdict` helpers.
To set this up, where previously the objects would be parsed from the
config via the `__init__` method, create a `build` classmethod that does
this and calls the dataclass initializer.
Some of the objects are mutated at runtime, in particular some of the
zones are mutated to set the color (this might be able to be refactored
out) and some of the camera functionality can be enabled/disabled. Some
of the configs with `enabled` properties don't seem to have mqtt hooks
to be able to toggle this, in particular, the clips, snapshots, and
detect can be toggled but rtmp and record configs do not, but all of
these configs are still not frozen in case there is some other
functionality I am missing.
There are a couple other minor fixes here, one that was introduced
by me recently where `max_seconds` was not defined, the other to
properly `get()` the message payload when handling publishing mqtt
messages sent via websocket.
2021-05-23 00:28:15 +02:00
2020-11-23 15:25:46 +01:00
2024-09-03 16:49:50 +02:00
class ReviewRetainConfig ( FrigateBaseModel ) :
days : float = Field ( default = 10 , title = " Default retention period. " )
mode : RetainModeEnum = Field ( default = RetainModeEnum . motion , title = " Retain mode. " )
2021-09-08 15:02:26 +02:00
class EventsConfig ( FrigateBaseModel ) :
2023-11-18 22:37:06 +01:00
pre_capture : int = Field (
default = 5 , title = " Seconds to retain before event starts. " , le = MAX_PRE_CAPTURE
)
2021-09-08 15:02:26 +02:00
post_capture : int = Field ( default = 5 , title = " Seconds to retain after event ends. " )
2024-09-03 16:49:50 +02:00
retain : ReviewRetainConfig = Field (
default_factory = ReviewRetainConfig , title = " Event retention settings. "
2021-06-24 07:45:27 +02:00
)
Use dataclasses for config handling
Use config data classes to eliminate some of the boilerplate associated
with setting up the configuration. In particular, using dataclasses
removes a lot of the boilerplate around assigning properties to the
object and allows these to be easily immutable by freezing them. In the
case of simple, non-nested dataclasses, this also provides more
convenient `asdict` helpers.
To set this up, where previously the objects would be parsed from the
config via the `__init__` method, create a `build` classmethod that does
this and calls the dataclass initializer.
Some of the objects are mutated at runtime, in particular some of the
zones are mutated to set the color (this might be able to be refactored
out) and some of the camera functionality can be enabled/disabled. Some
of the configs with `enabled` properties don't seem to have mqtt hooks
to be able to toggle this, in particular, the clips, snapshots, and
detect can be toggled but rtmp and record configs do not, but all of
these configs are still not frozen in case there is some other
functionality I am missing.
There are a couple other minor fixes here, one that was introduced
by me recently where `max_seconds` was not defined, the other to
properly `get()` the message payload when handling publishing mqtt
messages sent via websocket.
2021-05-23 00:28:15 +02:00
2023-09-21 14:20:05 +02:00
class RecordExportConfig ( FrigateBaseModel ) :
timelapse_args : str = Field (
default = DEFAULT_TIME_LAPSE_FFMPEG_ARGS , title = " Timelapse Args "
)
2023-12-03 15:16:01 +01:00
class RecordQualityEnum ( str , Enum ) :
very_low = " very_low "
low = " low "
medium = " medium "
high = " high "
very_high = " very_high "
class RecordPreviewConfig ( FrigateBaseModel ) :
quality : RecordQualityEnum = Field (
default = RecordQualityEnum . medium , title = " Quality of recording preview. "
)
2021-09-04 23:56:01 +02:00
class RecordConfig ( FrigateBaseModel ) :
2021-07-09 22:14:16 +02:00
enabled : bool = Field ( default = False , title = " Enable record on all cameras. " )
2023-11-18 13:06:00 +01:00
sync_recordings : bool = Field (
default = False , title = " Sync recordings with disk on startup and once a day. "
2023-07-15 15:38:21 +02:00
)
2022-02-05 15:51:18 +01:00
expire_interval : int = Field (
default = 60 ,
title = " Number of minutes to wait between cleanup runs. " ,
)
2021-12-11 16:22:44 +01:00
retain : RecordRetainConfig = Field (
default_factory = RecordRetainConfig , title = " Record retention settings. "
)
2024-09-02 15:22:53 +02:00
detections : EventsConfig = Field (
default_factory = EventsConfig , title = " Detection specific retention settings. "
)
alerts : EventsConfig = Field (
default_factory = EventsConfig , title = " Alert specific retention settings. "
2021-07-09 22:14:16 +02:00
)
2023-09-21 14:20:05 +02:00
export : RecordExportConfig = Field (
default_factory = RecordExportConfig , title = " Recording Export Config "
)
2023-12-03 15:16:01 +01:00
preview : RecordPreviewConfig = Field (
default_factory = RecordPreviewConfig , title = " Recording Preview Config "
)
2023-05-15 14:36:26 +02:00
enabled_in_config : Optional [ bool ] = Field (
2024-03-01 00:10:13 +01:00
None , title = " Keep track of original state of recording. "
2023-05-15 14:36:26 +02:00
)
2021-07-09 22:14:16 +02:00
2021-09-04 23:56:01 +02:00
class MotionConfig ( FrigateBaseModel ) :
2024-02-19 14:26:59 +01:00
enabled : bool = Field ( default = True , title = " Enable motion on all cameras. " )
2021-06-24 07:45:27 +02:00
threshold : int = Field (
2023-06-30 14:27:31 +02:00
default = 30 ,
2021-06-24 07:45:27 +02:00
title = " Motion detection threshold (1-255). " ,
ge = 1 ,
le = 255 ,
)
2023-06-11 15:45:11 +02:00
lightning_threshold : float = Field (
default = 0.8 , title = " Lightning detection threshold (0.3-1.0). " , ge = 0.3 , le = 1.0
)
improve_contrast : bool = Field ( default = True , title = " Improve Contrast " )
2023-06-18 18:56:41 +02:00
contour_area : Optional [ int ] = Field ( default = 10 , title = " Contour Area " )
2021-06-24 07:45:27 +02:00
delta_alpha : float = Field ( default = 0.2 , title = " Delta Alpha " )
2023-06-21 15:38:51 +02:00
frame_alpha : float = Field ( default = 0.01 , title = " Frame Alpha " )
2023-06-18 18:56:41 +02:00
frame_height : Optional [ int ] = Field ( default = 100 , title = " Frame Height " )
2021-06-24 07:45:27 +02:00
mask : Union [ str , List [ str ] ] = Field (
default = " " , title = " Coordinates polygon for the motion mask. "
)
2022-05-15 14:03:33 +02:00
mqtt_off_delay : int = Field (
default = 30 ,
title = " Delay for updating MQTT with no motion detected. " ,
)
2024-02-19 14:26:59 +01:00
enabled_in_config : Optional [ bool ] = Field (
2024-03-01 00:10:13 +01:00
None , title = " Keep track of original state of motion detection. "
2024-02-19 14:26:59 +01:00
)
2024-03-01 00:10:13 +01:00
raw_mask : Union [ str , List [ str ] ] = " "
@field_serializer ( " mask " , when_used = " json " )
def serialize_mask ( self , value : Any , info ) :
return self . raw_mask
@field_serializer ( " raw_mask " , when_used = " json " )
def serialize_raw_mask ( self , value : Any , info ) :
return None
Use dataclasses for config handling
Use config data classes to eliminate some of the boilerplate associated
with setting up the configuration. In particular, using dataclasses
removes a lot of the boilerplate around assigning properties to the
object and allows these to be easily immutable by freezing them. In the
case of simple, non-nested dataclasses, this also provides more
convenient `asdict` helpers.
To set this up, where previously the objects would be parsed from the
config via the `__init__` method, create a `build` classmethod that does
this and calls the dataclass initializer.
Some of the objects are mutated at runtime, in particular some of the
zones are mutated to set the color (this might be able to be refactored
out) and some of the camera functionality can be enabled/disabled. Some
of the configs with `enabled` properties don't seem to have mqtt hooks
to be able to toggle this, in particular, the clips, snapshots, and
detect can be toggled but rtmp and record configs do not, but all of
these configs are still not frozen in case there is some other
functionality I am missing.
There are a couple other minor fixes here, one that was introduced
by me recently where `max_seconds` was not defined, the other to
properly `get()` the message payload when handling publishing mqtt
messages sent via websocket.
2021-05-23 00:28:15 +02:00
2021-06-24 07:45:27 +02:00
class RuntimeMotionConfig ( MotionConfig ) :
raw_mask : Union [ str , List [ str ] ] = " "
mask : np . ndarray = None
Use dataclasses for config handling
Use config data classes to eliminate some of the boilerplate associated
with setting up the configuration. In particular, using dataclasses
removes a lot of the boilerplate around assigning properties to the
object and allows these to be easily immutable by freezing them. In the
case of simple, non-nested dataclasses, this also provides more
convenient `asdict` helpers.
To set this up, where previously the objects would be parsed from the
config via the `__init__` method, create a `build` classmethod that does
this and calls the dataclass initializer.
Some of the objects are mutated at runtime, in particular some of the
zones are mutated to set the color (this might be able to be refactored
out) and some of the camera functionality can be enabled/disabled. Some
of the configs with `enabled` properties don't seem to have mqtt hooks
to be able to toggle this, in particular, the clips, snapshots, and
detect can be toggled but rtmp and record configs do not, but all of
these configs are still not frozen in case there is some other
functionality I am missing.
There are a couple other minor fixes here, one that was introduced
by me recently where `max_seconds` was not defined, the other to
properly `get()` the message payload when handling publishing mqtt
messages sent via websocket.
2021-05-23 00:28:15 +02:00
2021-06-24 07:45:27 +02:00
def __init__ ( self , * * config ) :
frame_shape = config . get ( " frame_shape " , ( 1 , 1 ) )
2020-11-01 13:17:44 +01:00
2024-04-18 18:35:16 +02:00
mask = get_relative_coordinates ( config . get ( " mask " , " " ) , frame_shape )
2021-06-24 07:45:27 +02:00
config [ " raw_mask " ] = mask
Use dataclasses for config handling
Use config data classes to eliminate some of the boilerplate associated
with setting up the configuration. In particular, using dataclasses
removes a lot of the boilerplate around assigning properties to the
object and allows these to be easily immutable by freezing them. In the
case of simple, non-nested dataclasses, this also provides more
convenient `asdict` helpers.
To set this up, where previously the objects would be parsed from the
config via the `__init__` method, create a `build` classmethod that does
this and calls the dataclass initializer.
Some of the objects are mutated at runtime, in particular some of the
zones are mutated to set the color (this might be able to be refactored
out) and some of the camera functionality can be enabled/disabled. Some
of the configs with `enabled` properties don't seem to have mqtt hooks
to be able to toggle this, in particular, the clips, snapshots, and
detect can be toggled but rtmp and record configs do not, but all of
these configs are still not frozen in case there is some other
functionality I am missing.
There are a couple other minor fixes here, one that was introduced
by me recently where `max_seconds` was not defined, the other to
properly `get()` the message payload when handling publishing mqtt
messages sent via websocket.
2021-05-23 00:28:15 +02:00
2021-06-24 07:45:27 +02:00
if mask :
config [ " mask " ] = create_mask ( frame_shape , mask )
else :
empty_mask = np . zeros ( frame_shape , np . uint8 )
empty_mask [ : ] = 255
config [ " mask " ] = empty_mask
Use dataclasses for config handling
Use config data classes to eliminate some of the boilerplate associated
with setting up the configuration. In particular, using dataclasses
removes a lot of the boilerplate around assigning properties to the
object and allows these to be easily immutable by freezing them. In the
case of simple, non-nested dataclasses, this also provides more
convenient `asdict` helpers.
To set this up, where previously the objects would be parsed from the
config via the `__init__` method, create a `build` classmethod that does
this and calls the dataclass initializer.
Some of the objects are mutated at runtime, in particular some of the
zones are mutated to set the color (this might be able to be refactored
out) and some of the camera functionality can be enabled/disabled. Some
of the configs with `enabled` properties don't seem to have mqtt hooks
to be able to toggle this, in particular, the clips, snapshots, and
detect can be toggled but rtmp and record configs do not, but all of
these configs are still not frozen in case there is some other
functionality I am missing.
There are a couple other minor fixes here, one that was introduced
by me recently where `max_seconds` was not defined, the other to
properly `get()` the message payload when handling publishing mqtt
messages sent via websocket.
2021-05-23 00:28:15 +02:00
2021-06-24 07:45:27 +02:00
super ( ) . __init__ ( * * config )
Use dataclasses for config handling
Use config data classes to eliminate some of the boilerplate associated
with setting up the configuration. In particular, using dataclasses
removes a lot of the boilerplate around assigning properties to the
object and allows these to be easily immutable by freezing them. In the
case of simple, non-nested dataclasses, this also provides more
convenient `asdict` helpers.
To set this up, where previously the objects would be parsed from the
config via the `__init__` method, create a `build` classmethod that does
this and calls the dataclass initializer.
Some of the objects are mutated at runtime, in particular some of the
zones are mutated to set the color (this might be able to be refactored
out) and some of the camera functionality can be enabled/disabled. Some
of the configs with `enabled` properties don't seem to have mqtt hooks
to be able to toggle this, in particular, the clips, snapshots, and
detect can be toggled but rtmp and record configs do not, but all of
these configs are still not frozen in case there is some other
functionality I am missing.
There are a couple other minor fixes here, one that was introduced
by me recently where `max_seconds` was not defined, the other to
properly `get()` the message payload when handling publishing mqtt
messages sent via websocket.
2021-05-23 00:28:15 +02:00
2021-06-24 07:45:27 +02:00
def dict ( self , * * kwargs ) :
2024-03-01 00:10:13 +01:00
ret = super ( ) . model_dump ( * * kwargs )
2021-06-24 07:45:27 +02:00
if " mask " in ret :
ret [ " mask " ] = ret [ " raw_mask " ]
ret . pop ( " raw_mask " )
return ret
Use dataclasses for config handling
Use config data classes to eliminate some of the boilerplate associated
with setting up the configuration. In particular, using dataclasses
removes a lot of the boilerplate around assigning properties to the
object and allows these to be easily immutable by freezing them. In the
case of simple, non-nested dataclasses, this also provides more
convenient `asdict` helpers.
To set this up, where previously the objects would be parsed from the
config via the `__init__` method, create a `build` classmethod that does
this and calls the dataclass initializer.
Some of the objects are mutated at runtime, in particular some of the
zones are mutated to set the color (this might be able to be refactored
out) and some of the camera functionality can be enabled/disabled. Some
of the configs with `enabled` properties don't seem to have mqtt hooks
to be able to toggle this, in particular, the clips, snapshots, and
detect can be toggled but rtmp and record configs do not, but all of
these configs are still not frozen in case there is some other
functionality I am missing.
There are a couple other minor fixes here, one that was introduced
by me recently where `max_seconds` was not defined, the other to
properly `get()` the message payload when handling publishing mqtt
messages sent via websocket.
2021-05-23 00:28:15 +02:00
2024-03-01 00:10:13 +01:00
@field_serializer ( " mask " , when_used = " json " )
def serialize_mask ( self , value : Any , info ) :
return self . raw_mask
@field_serializer ( " raw_mask " , when_used = " json " )
def serialize_raw_mask ( self , value : Any , info ) :
return None
model_config = ConfigDict ( arbitrary_types_allowed = True , extra = " ignore " )
Use dataclasses for config handling
Use config data classes to eliminate some of the boilerplate associated
with setting up the configuration. In particular, using dataclasses
removes a lot of the boilerplate around assigning properties to the
object and allows these to be easily immutable by freezing them. In the
case of simple, non-nested dataclasses, this also provides more
convenient `asdict` helpers.
To set this up, where previously the objects would be parsed from the
config via the `__init__` method, create a `build` classmethod that does
this and calls the dataclass initializer.
Some of the objects are mutated at runtime, in particular some of the
zones are mutated to set the color (this might be able to be refactored
out) and some of the camera functionality can be enabled/disabled. Some
of the configs with `enabled` properties don't seem to have mqtt hooks
to be able to toggle this, in particular, the clips, snapshots, and
detect can be toggled but rtmp and record configs do not, but all of
these configs are still not frozen in case there is some other
functionality I am missing.
There are a couple other minor fixes here, one that was introduced
by me recently where `max_seconds` was not defined, the other to
properly `get()` the message payload when handling publishing mqtt
messages sent via websocket.
2021-05-23 00:28:15 +02:00
2022-02-13 15:58:44 +01:00
class StationaryMaxFramesConfig ( FrigateBaseModel ) :
2024-03-01 00:10:13 +01:00
default : Optional [ int ] = Field ( None , title = " Default max frames. " , ge = 1 )
2022-02-13 15:58:44 +01:00
objects : Dict [ str , int ] = Field (
default_factory = dict , title = " Object specific max frames. "
)
class StationaryConfig ( FrigateBaseModel ) :
interval : Optional [ int ] = Field (
2024-03-01 00:10:13 +01:00
None ,
2022-02-13 15:58:44 +01:00
title = " Frame interval for checking stationary objects. " ,
2023-06-16 14:32:43 +02:00
gt = 0 ,
2022-02-13 15:58:44 +01:00
)
threshold : Optional [ int ] = Field (
2024-03-01 00:10:13 +01:00
None ,
2022-02-13 15:58:44 +01:00
title = " Number of frames without a position change for an object to be considered stationary " ,
ge = 1 ,
)
max_frames : StationaryMaxFramesConfig = Field (
default_factory = StationaryMaxFramesConfig ,
title = " Max frames for stationary objects. " ,
)
2021-09-04 23:56:01 +02:00
class DetectConfig ( FrigateBaseModel ) :
2024-03-01 00:10:13 +01:00
height : Optional [ int ] = Field (
None , title = " Height of the stream for the detect role. "
)
width : Optional [ int ] = Field ( None , title = " Width of the stream for the detect role. " )
2021-08-28 15:51:29 +02:00
fps : int = Field (
default = 5 , title = " Number of frames per second to process through detection. "
)
2021-06-24 07:45:27 +02:00
enabled : bool = Field ( default = True , title = " Detection Enabled. " )
2023-10-31 01:26:31 +01:00
min_initialized : Optional [ int ] = Field (
2024-03-01 00:10:13 +01:00
None ,
title = " Minimum number of consecutive hits for an object to be initialized by the tracker. " ,
2023-10-31 01:26:31 +01:00
)
2021-06-26 16:57:32 +02:00
max_disappeared : Optional [ int ] = Field (
2024-03-01 00:10:13 +01:00
None ,
2024-03-30 11:51:41 +01:00
title = " Maximum number of frames the object can disappear before detection ends. " ,
2021-06-24 07:45:27 +02:00
)
2022-02-13 15:58:44 +01:00
stationary : StationaryConfig = Field (
default_factory = StationaryConfig ,
title = " Stationary objects config. " ,
2022-02-08 14:40:45 +01:00
)
2023-04-28 13:02:06 +02:00
annotation_offset : int = Field (
default = 0 , title = " Milliseconds to offset detect annotations by. "
)
Use dataclasses for config handling
Use config data classes to eliminate some of the boilerplate associated
with setting up the configuration. In particular, using dataclasses
removes a lot of the boilerplate around assigning properties to the
object and allows these to be easily immutable by freezing them. In the
case of simple, non-nested dataclasses, this also provides more
convenient `asdict` helpers.
To set this up, where previously the objects would be parsed from the
config via the `__init__` method, create a `build` classmethod that does
this and calls the dataclass initializer.
Some of the objects are mutated at runtime, in particular some of the
zones are mutated to set the color (this might be able to be refactored
out) and some of the camera functionality can be enabled/disabled. Some
of the configs with `enabled` properties don't seem to have mqtt hooks
to be able to toggle this, in particular, the clips, snapshots, and
detect can be toggled but rtmp and record configs do not, but all of
these configs are still not frozen in case there is some other
functionality I am missing.
There are a couple other minor fixes here, one that was introduced
by me recently where `max_seconds` was not defined, the other to
properly `get()` the message payload when handling publishing mqtt
messages sent via websocket.
2021-05-23 00:28:15 +02:00
2021-09-04 23:56:01 +02:00
class FilterConfig ( FrigateBaseModel ) :
2021-06-24 07:45:27 +02:00
min_area : int = Field (
default = 0 , title = " Minimum area of bounding box for object to be counted. "
)
max_area : int = Field (
default = 24000000 , title = " Maximum area of bounding box for object to be counted. "
)
2022-04-10 15:25:18 +02:00
min_ratio : float = Field (
default = 0 ,
title = " Minimum ratio of bounding box ' s width/height for object to be counted. " ,
)
max_ratio : float = Field (
default = 24000000 ,
title = " Maximum ratio of bounding box ' s width/height for object to be counted. " ,
)
2021-06-24 07:45:27 +02:00
threshold : float = Field (
default = 0.7 ,
title = " Average detection confidence threshold for object to be counted. " ,
)
min_score : float = Field (
default = 0.5 , title = " Minimum detection confidence for object to be counted. "
)
mask : Optional [ Union [ str , List [ str ] ] ] = Field (
2024-03-01 00:10:13 +01:00
None ,
2021-06-24 07:45:27 +02:00
title = " Detection area polygon mask for this filter configuration. " ,
)
2024-03-01 00:10:13 +01:00
raw_mask : Union [ str , List [ str ] ] = " "
@field_serializer ( " mask " , when_used = " json " )
def serialize_mask ( self , value : Any , info ) :
return self . raw_mask
@field_serializer ( " raw_mask " , when_used = " json " )
def serialize_raw_mask ( self , value : Any , info ) :
return None
Use dataclasses for config handling
Use config data classes to eliminate some of the boilerplate associated
with setting up the configuration. In particular, using dataclasses
removes a lot of the boilerplate around assigning properties to the
object and allows these to be easily immutable by freezing them. In the
case of simple, non-nested dataclasses, this also provides more
convenient `asdict` helpers.
To set this up, where previously the objects would be parsed from the
config via the `__init__` method, create a `build` classmethod that does
this and calls the dataclass initializer.
Some of the objects are mutated at runtime, in particular some of the
zones are mutated to set the color (this might be able to be refactored
out) and some of the camera functionality can be enabled/disabled. Some
of the configs with `enabled` properties don't seem to have mqtt hooks
to be able to toggle this, in particular, the clips, snapshots, and
detect can be toggled but rtmp and record configs do not, but all of
these configs are still not frozen in case there is some other
functionality I am missing.
There are a couple other minor fixes here, one that was introduced
by me recently where `max_seconds` was not defined, the other to
properly `get()` the message payload when handling publishing mqtt
messages sent via websocket.
2021-05-23 00:28:15 +02:00
2023-07-17 13:07:15 +02:00
class AudioFilterConfig ( FrigateBaseModel ) :
threshold : float = Field (
default = 0.8 ,
ge = AUDIO_MIN_CONFIDENCE ,
lt = 1.0 ,
title = " Minimum detection confidence threshold for audio to be counted. " ,
)
2021-06-24 07:45:27 +02:00
class RuntimeFilterConfig ( FilterConfig ) :
2024-03-01 00:10:13 +01:00
mask : Optional [ np . ndarray ] = None
raw_mask : Optional [ Union [ str , List [ str ] ] ] = None
Use dataclasses for config handling
Use config data classes to eliminate some of the boilerplate associated
with setting up the configuration. In particular, using dataclasses
removes a lot of the boilerplate around assigning properties to the
object and allows these to be easily immutable by freezing them. In the
case of simple, non-nested dataclasses, this also provides more
convenient `asdict` helpers.
To set this up, where previously the objects would be parsed from the
config via the `__init__` method, create a `build` classmethod that does
this and calls the dataclass initializer.
Some of the objects are mutated at runtime, in particular some of the
zones are mutated to set the color (this might be able to be refactored
out) and some of the camera functionality can be enabled/disabled. Some
of the configs with `enabled` properties don't seem to have mqtt hooks
to be able to toggle this, in particular, the clips, snapshots, and
detect can be toggled but rtmp and record configs do not, but all of
these configs are still not frozen in case there is some other
functionality I am missing.
There are a couple other minor fixes here, one that was introduced
by me recently where `max_seconds` was not defined, the other to
properly `get()` the message payload when handling publishing mqtt
messages sent via websocket.
2021-05-23 00:28:15 +02:00
2021-06-24 07:45:27 +02:00
def __init__ ( self , * * config ) :
2024-04-10 00:51:38 +02:00
frame_shape = config . get ( " frame_shape " , ( 1 , 1 ) )
2024-04-18 18:35:16 +02:00
mask = get_relative_coordinates ( config . get ( " mask " ) , frame_shape )
2024-04-10 00:51:38 +02:00
2021-06-24 07:45:27 +02:00
config [ " raw_mask " ] = mask
Use dataclasses for config handling
Use config data classes to eliminate some of the boilerplate associated
with setting up the configuration. In particular, using dataclasses
removes a lot of the boilerplate around assigning properties to the
object and allows these to be easily immutable by freezing them. In the
case of simple, non-nested dataclasses, this also provides more
convenient `asdict` helpers.
To set this up, where previously the objects would be parsed from the
config via the `__init__` method, create a `build` classmethod that does
this and calls the dataclass initializer.
Some of the objects are mutated at runtime, in particular some of the
zones are mutated to set the color (this might be able to be refactored
out) and some of the camera functionality can be enabled/disabled. Some
of the configs with `enabled` properties don't seem to have mqtt hooks
to be able to toggle this, in particular, the clips, snapshots, and
detect can be toggled but rtmp and record configs do not, but all of
these configs are still not frozen in case there is some other
functionality I am missing.
There are a couple other minor fixes here, one that was introduced
by me recently where `max_seconds` was not defined, the other to
properly `get()` the message payload when handling publishing mqtt
messages sent via websocket.
2021-05-23 00:28:15 +02:00
2021-06-24 07:45:27 +02:00
if mask is not None :
2024-04-10 00:51:38 +02:00
config [ " mask " ] = create_mask ( frame_shape , mask )
Use dataclasses for config handling
Use config data classes to eliminate some of the boilerplate associated
with setting up the configuration. In particular, using dataclasses
removes a lot of the boilerplate around assigning properties to the
object and allows these to be easily immutable by freezing them. In the
case of simple, non-nested dataclasses, this also provides more
convenient `asdict` helpers.
To set this up, where previously the objects would be parsed from the
config via the `__init__` method, create a `build` classmethod that does
this and calls the dataclass initializer.
Some of the objects are mutated at runtime, in particular some of the
zones are mutated to set the color (this might be able to be refactored
out) and some of the camera functionality can be enabled/disabled. Some
of the configs with `enabled` properties don't seem to have mqtt hooks
to be able to toggle this, in particular, the clips, snapshots, and
detect can be toggled but rtmp and record configs do not, but all of
these configs are still not frozen in case there is some other
functionality I am missing.
There are a couple other minor fixes here, one that was introduced
by me recently where `max_seconds` was not defined, the other to
properly `get()` the message payload when handling publishing mqtt
messages sent via websocket.
2021-05-23 00:28:15 +02:00
2021-06-24 07:45:27 +02:00
super ( ) . __init__ ( * * config )
Use dataclasses for config handling
Use config data classes to eliminate some of the boilerplate associated
with setting up the configuration. In particular, using dataclasses
removes a lot of the boilerplate around assigning properties to the
object and allows these to be easily immutable by freezing them. In the
case of simple, non-nested dataclasses, this also provides more
convenient `asdict` helpers.
To set this up, where previously the objects would be parsed from the
config via the `__init__` method, create a `build` classmethod that does
this and calls the dataclass initializer.
Some of the objects are mutated at runtime, in particular some of the
zones are mutated to set the color (this might be able to be refactored
out) and some of the camera functionality can be enabled/disabled. Some
of the configs with `enabled` properties don't seem to have mqtt hooks
to be able to toggle this, in particular, the clips, snapshots, and
detect can be toggled but rtmp and record configs do not, but all of
these configs are still not frozen in case there is some other
functionality I am missing.
There are a couple other minor fixes here, one that was introduced
by me recently where `max_seconds` was not defined, the other to
properly `get()` the message payload when handling publishing mqtt
messages sent via websocket.
2021-05-23 00:28:15 +02:00
2021-06-24 07:45:27 +02:00
def dict ( self , * * kwargs ) :
2024-03-01 00:10:13 +01:00
ret = super ( ) . model_dump ( * * kwargs )
2021-06-24 07:45:27 +02:00
if " mask " in ret :
ret [ " mask " ] = ret [ " raw_mask " ]
ret . pop ( " raw_mask " )
return ret
Use dataclasses for config handling
Use config data classes to eliminate some of the boilerplate associated
with setting up the configuration. In particular, using dataclasses
removes a lot of the boilerplate around assigning properties to the
object and allows these to be easily immutable by freezing them. In the
case of simple, non-nested dataclasses, this also provides more
convenient `asdict` helpers.
To set this up, where previously the objects would be parsed from the
config via the `__init__` method, create a `build` classmethod that does
this and calls the dataclass initializer.
Some of the objects are mutated at runtime, in particular some of the
zones are mutated to set the color (this might be able to be refactored
out) and some of the camera functionality can be enabled/disabled. Some
of the configs with `enabled` properties don't seem to have mqtt hooks
to be able to toggle this, in particular, the clips, snapshots, and
detect can be toggled but rtmp and record configs do not, but all of
these configs are still not frozen in case there is some other
functionality I am missing.
There are a couple other minor fixes here, one that was introduced
by me recently where `max_seconds` was not defined, the other to
properly `get()` the message payload when handling publishing mqtt
messages sent via websocket.
2021-05-23 00:28:15 +02:00
2024-03-01 00:10:13 +01:00
model_config = ConfigDict ( arbitrary_types_allowed = True , extra = " ignore " )
Use dataclasses for config handling
Use config data classes to eliminate some of the boilerplate associated
with setting up the configuration. In particular, using dataclasses
removes a lot of the boilerplate around assigning properties to the
object and allows these to be easily immutable by freezing them. In the
case of simple, non-nested dataclasses, this also provides more
convenient `asdict` helpers.
To set this up, where previously the objects would be parsed from the
config via the `__init__` method, create a `build` classmethod that does
this and calls the dataclass initializer.
Some of the objects are mutated at runtime, in particular some of the
zones are mutated to set the color (this might be able to be refactored
out) and some of the camera functionality can be enabled/disabled. Some
of the configs with `enabled` properties don't seem to have mqtt hooks
to be able to toggle this, in particular, the clips, snapshots, and
detect can be toggled but rtmp and record configs do not, but all of
these configs are still not frozen in case there is some other
functionality I am missing.
There are a couple other minor fixes here, one that was introduced
by me recently where `max_seconds` was not defined, the other to
properly `get()` the message payload when handling publishing mqtt
messages sent via websocket.
2021-05-23 00:28:15 +02:00
2021-09-04 23:56:01 +02:00
# this uses the base model because the color is an extra attribute
2021-06-24 07:45:27 +02:00
class ZoneConfig ( BaseModel ) :
filters : Dict [ str , FilterConfig ] = Field (
default_factory = dict , title = " Zone filters. "
)
coordinates : Union [ str , List [ str ] ] = Field (
title = " Coordinates polygon for the defined zone. "
)
2023-06-11 15:00:53 +02:00
inertia : int = Field (
default = 3 ,
title = " Number of consecutive frames required for object to be considered present in the zone. " ,
gt = 0 ,
)
2024-03-19 21:58:04 +01:00
loitering_time : int = Field (
default = 0 ,
ge = 0 ,
title = " Number of seconds that an object must loiter to be considered in the zone. " ,
)
2024-05-01 16:08:10 +02:00
objects : Union [ str , List [ str ] ] = Field (
2021-07-07 14:31:42 +02:00
default_factory = list ,
title = " List of objects that can trigger the zone. " ,
)
2021-06-24 07:45:27 +02:00
_color : Optional [ Tuple [ int , int , int ] ] = PrivateAttr ( )
_contour : np . ndarray = PrivateAttr ( )
@property
def color ( self ) - > Tuple [ int , int , int ] :
return self . _color
@property
def contour ( self ) - > np . ndarray :
return self . _contour
2024-04-19 13:34:07 +02:00
@field_validator ( " objects " , mode = " before " )
@classmethod
def validate_objects ( cls , v ) :
if isinstance ( v , str ) and " , " not in v :
return [ v ]
return v
2021-06-24 07:45:27 +02:00
def __init__ ( self , * * config ) :
super ( ) . __init__ ( * * config )
self . _color = config . get ( " color " , ( 0 , 0 , 0 ) )
2024-04-10 00:51:38 +02:00
self . _contour = config . get ( " contour " , np . array ( [ ] ) )
def generate_contour ( self , frame_shape : tuple [ int , int ] ) :
coordinates = self . coordinates
Use dataclasses for config handling
Use config data classes to eliminate some of the boilerplate associated
with setting up the configuration. In particular, using dataclasses
removes a lot of the boilerplate around assigning properties to the
object and allows these to be easily immutable by freezing them. In the
case of simple, non-nested dataclasses, this also provides more
convenient `asdict` helpers.
To set this up, where previously the objects would be parsed from the
config via the `__init__` method, create a `build` classmethod that does
this and calls the dataclass initializer.
Some of the objects are mutated at runtime, in particular some of the
zones are mutated to set the color (this might be able to be refactored
out) and some of the camera functionality can be enabled/disabled. Some
of the configs with `enabled` properties don't seem to have mqtt hooks
to be able to toggle this, in particular, the clips, snapshots, and
detect can be toggled but rtmp and record configs do not, but all of
these configs are still not frozen in case there is some other
functionality I am missing.
There are a couple other minor fixes here, one that was introduced
by me recently where `max_seconds` was not defined, the other to
properly `get()` the message payload when handling publishing mqtt
messages sent via websocket.
2021-05-23 00:28:15 +02:00
2024-04-10 00:51:38 +02:00
# masks and zones are saved as relative coordinates
# we know if any points are > 1 then it is using the
# old native resolution coordinates
Use dataclasses for config handling
Use config data classes to eliminate some of the boilerplate associated
with setting up the configuration. In particular, using dataclasses
removes a lot of the boilerplate around assigning properties to the
object and allows these to be easily immutable by freezing them. In the
case of simple, non-nested dataclasses, this also provides more
convenient `asdict` helpers.
To set this up, where previously the objects would be parsed from the
config via the `__init__` method, create a `build` classmethod that does
this and calls the dataclass initializer.
Some of the objects are mutated at runtime, in particular some of the
zones are mutated to set the color (this might be able to be refactored
out) and some of the camera functionality can be enabled/disabled. Some
of the configs with `enabled` properties don't seem to have mqtt hooks
to be able to toggle this, in particular, the clips, snapshots, and
detect can be toggled but rtmp and record configs do not, but all of
these configs are still not frozen in case there is some other
functionality I am missing.
There are a couple other minor fixes here, one that was introduced
by me recently where `max_seconds` was not defined, the other to
properly `get()` the message payload when handling publishing mqtt
messages sent via websocket.
2021-05-23 00:28:15 +02:00
if isinstance ( coordinates , list ) :
2024-04-10 00:51:38 +02:00
explicit = any ( p . split ( " , " ) [ 0 ] > " 1.0 " for p in coordinates )
2024-05-08 16:46:31 +02:00
try :
self . _contour = np . array (
[
(
[ int ( p . split ( " , " ) [ 0 ] ) , int ( p . split ( " , " ) [ 1 ] ) ]
if explicit
else [
int ( float ( p . split ( " , " ) [ 0 ] ) * frame_shape [ 1 ] ) ,
int ( float ( p . split ( " , " ) [ 1 ] ) * frame_shape [ 0 ] ) ,
]
)
for p in coordinates
]
)
except ValueError :
raise ValueError (
f " Invalid coordinates found in configuration file. Coordinates must be relative (between 0-1): { coordinates } "
)
2024-04-10 00:51:38 +02:00
if explicit :
self . coordinates = " , " . join (
[
f ' { round ( int ( p . split ( " , " ) [ 0 ] ) / frame_shape [ 1 ] , 3 ) } , { round ( int ( p . split ( " , " ) [ 1 ] ) / frame_shape [ 0 ] , 3 ) } '
for p in coordinates
]
)
Use dataclasses for config handling
Use config data classes to eliminate some of the boilerplate associated
with setting up the configuration. In particular, using dataclasses
removes a lot of the boilerplate around assigning properties to the
object and allows these to be easily immutable by freezing them. In the
case of simple, non-nested dataclasses, this also provides more
convenient `asdict` helpers.
To set this up, where previously the objects would be parsed from the
config via the `__init__` method, create a `build` classmethod that does
this and calls the dataclass initializer.
Some of the objects are mutated at runtime, in particular some of the
zones are mutated to set the color (this might be able to be refactored
out) and some of the camera functionality can be enabled/disabled. Some
of the configs with `enabled` properties don't seem to have mqtt hooks
to be able to toggle this, in particular, the clips, snapshots, and
detect can be toggled but rtmp and record configs do not, but all of
these configs are still not frozen in case there is some other
functionality I am missing.
There are a couple other minor fixes here, one that was introduced
by me recently where `max_seconds` was not defined, the other to
properly `get()` the message payload when handling publishing mqtt
messages sent via websocket.
2021-05-23 00:28:15 +02:00
elif isinstance ( coordinates , str ) :
points = coordinates . split ( " , " )
2024-04-10 00:51:38 +02:00
explicit = any ( p > " 1.0 " for p in points )
2024-05-08 16:46:31 +02:00
try :
self . _contour = np . array (
[
(
[ int ( points [ i ] ) , int ( points [ i + 1 ] ) ]
if explicit
else [
int ( float ( points [ i ] ) * frame_shape [ 1 ] ) ,
int ( float ( points [ i + 1 ] ) * frame_shape [ 0 ] ) ,
]
)
for i in range ( 0 , len ( points ) , 2 )
]
)
except ValueError :
raise ValueError (
f " Invalid coordinates found in configuration file. Coordinates must be relative (between 0-1): { coordinates } "
)
2024-04-10 00:51:38 +02:00
if explicit :
self . coordinates = " , " . join (
[
f " { round ( int ( points [ i ] ) / frame_shape [ 1 ] , 3 ) } , { round ( int ( points [ i + 1 ] ) / frame_shape [ 0 ] , 3 ) } "
for i in range ( 0 , len ( points ) , 2 )
]
)
Use dataclasses for config handling
Use config data classes to eliminate some of the boilerplate associated
with setting up the configuration. In particular, using dataclasses
removes a lot of the boilerplate around assigning properties to the
object and allows these to be easily immutable by freezing them. In the
case of simple, non-nested dataclasses, this also provides more
convenient `asdict` helpers.
To set this up, where previously the objects would be parsed from the
config via the `__init__` method, create a `build` classmethod that does
this and calls the dataclass initializer.
Some of the objects are mutated at runtime, in particular some of the
zones are mutated to set the color (this might be able to be refactored
out) and some of the camera functionality can be enabled/disabled. Some
of the configs with `enabled` properties don't seem to have mqtt hooks
to be able to toggle this, in particular, the clips, snapshots, and
detect can be toggled but rtmp and record configs do not, but all of
these configs are still not frozen in case there is some other
functionality I am missing.
There are a couple other minor fixes here, one that was introduced
by me recently where `max_seconds` was not defined, the other to
properly `get()` the message payload when handling publishing mqtt
messages sent via websocket.
2021-05-23 00:28:15 +02:00
else :
2021-06-24 07:45:27 +02:00
self . _contour = np . array ( [ ] )
Use dataclasses for config handling
Use config data classes to eliminate some of the boilerplate associated
with setting up the configuration. In particular, using dataclasses
removes a lot of the boilerplate around assigning properties to the
object and allows these to be easily immutable by freezing them. In the
case of simple, non-nested dataclasses, this also provides more
convenient `asdict` helpers.
To set this up, where previously the objects would be parsed from the
config via the `__init__` method, create a `build` classmethod that does
this and calls the dataclass initializer.
Some of the objects are mutated at runtime, in particular some of the
zones are mutated to set the color (this might be able to be refactored
out) and some of the camera functionality can be enabled/disabled. Some
of the configs with `enabled` properties don't seem to have mqtt hooks
to be able to toggle this, in particular, the clips, snapshots, and
detect can be toggled but rtmp and record configs do not, but all of
these configs are still not frozen in case there is some other
functionality I am missing.
There are a couple other minor fixes here, one that was introduced
by me recently where `max_seconds` was not defined, the other to
properly `get()` the message payload when handling publishing mqtt
messages sent via websocket.
2021-05-23 00:28:15 +02:00
2021-09-04 23:56:01 +02:00
class ObjectConfig ( FrigateBaseModel ) :
2021-06-24 07:45:27 +02:00
track : List [ str ] = Field ( default = DEFAULT_TRACKED_OBJECTS , title = " Objects to track. " )
2023-09-30 14:38:15 +02:00
filters : Dict [ str , FilterConfig ] = Field ( default = { } , title = " Object filters. " )
2021-06-24 07:45:27 +02:00
mask : Union [ str , List [ str ] ] = Field ( default = " " , title = " Object mask. " )
Use dataclasses for config handling
Use config data classes to eliminate some of the boilerplate associated
with setting up the configuration. In particular, using dataclasses
removes a lot of the boilerplate around assigning properties to the
object and allows these to be easily immutable by freezing them. In the
case of simple, non-nested dataclasses, this also provides more
convenient `asdict` helpers.
To set this up, where previously the objects would be parsed from the
config via the `__init__` method, create a `build` classmethod that does
this and calls the dataclass initializer.
Some of the objects are mutated at runtime, in particular some of the
zones are mutated to set the color (this might be able to be refactored
out) and some of the camera functionality can be enabled/disabled. Some
of the configs with `enabled` properties don't seem to have mqtt hooks
to be able to toggle this, in particular, the clips, snapshots, and
detect can be toggled but rtmp and record configs do not, but all of
these configs are still not frozen in case there is some other
functionality I am missing.
There are a couple other minor fixes here, one that was introduced
by me recently where `max_seconds` was not defined, the other to
properly `get()` the message payload when handling publishing mqtt
messages sent via websocket.
2021-05-23 00:28:15 +02:00
2024-04-13 14:08:20 +02:00
class AlertsConfig ( FrigateBaseModel ) :
""" Configure alerts """
labels : List [ str ] = Field (
default = DEFAULT_ALERT_OBJECTS , title = " Labels to create alerts for. "
)
2024-05-01 16:08:10 +02:00
required_zones : Union [ str , List [ str ] ] = Field (
2024-04-13 14:08:20 +02:00
default_factory = list ,
title = " List of required zones to be entered in order to save the event as an alert. " ,
)
2024-04-19 13:34:07 +02:00
@field_validator ( " required_zones " , mode = " before " )
@classmethod
def validate_required_zones ( cls , v ) :
if isinstance ( v , str ) and " , " not in v :
return [ v ]
return v
2024-04-13 14:08:20 +02:00
class DetectionsConfig ( FrigateBaseModel ) :
""" Configure detections """
labels : Optional [ List [ str ] ] = Field (
default = None , title = " Labels to create detections for. "
)
2024-05-01 16:08:10 +02:00
required_zones : Union [ str , List [ str ] ] = Field (
2024-04-13 14:08:20 +02:00
default_factory = list ,
title = " List of required zones to be entered in order to save the event as a detection. " ,
)
2024-04-19 13:34:07 +02:00
@field_validator ( " required_zones " , mode = " before " )
@classmethod
def validate_required_zones ( cls , v ) :
if isinstance ( v , str ) and " , " not in v :
return [ v ]
return v
2024-04-13 14:08:20 +02:00
class ReviewConfig ( FrigateBaseModel ) :
""" Configure reviews """
alerts : AlertsConfig = Field (
default_factory = AlertsConfig , title = " Review alerts config. "
)
detections : DetectionsConfig = Field (
default_factory = DetectionsConfig , title = " Review detections config. "
)
2024-06-21 23:30:19 +02:00
class SemanticSearchConfig ( FrigateBaseModel ) :
2024-08-04 05:06:20 +02:00
enabled : bool = Field ( default = False , title = " Enable semantic search. " )
2024-06-21 23:30:19 +02:00
reindex : Optional [ bool ] = Field (
default = False , title = " Reindex all detections on startup. "
)
class GenAIProviderEnum ( str , Enum ) :
openai = " openai "
gemini = " gemini "
ollama = " ollama "
class GenAIConfig ( FrigateBaseModel ) :
enabled : bool = Field ( default = False , title = " Enable GenAI. " )
provider : GenAIProviderEnum = Field (
default = GenAIProviderEnum . openai , title = " GenAI provider. "
)
base_url : Optional [ str ] = Field ( None , title = " Provider base url. " )
api_key : Optional [ str ] = Field ( None , title = " Provider API key. " )
model : str = Field ( default = " gpt-4o " , title = " GenAI model. " )
prompt : str = Field (
default = " Describe the {label} in the sequence of images with as much detail as possible. Do not describe the background. " ,
title = " Default caption prompt. " ,
)
object_prompts : Dict [ str , str ] = Field ( default = { } , title = " Object specific prompts. " )
2024-09-16 16:46:11 +02:00
# uses BaseModel because some global attributes are not available at the camera level
class GenAICameraConfig ( BaseModel ) :
2024-06-21 23:30:19 +02:00
enabled : bool = Field ( default = False , title = " Enable GenAI for camera. " )
2024-09-16 16:46:11 +02:00
prompt : str = Field (
default = " Describe the {label} in the sequence of images with as much detail as possible. Do not describe the background. " ,
title = " Default caption prompt. " ,
)
object_prompts : Dict [ str , str ] = Field ( default = { } , title = " Object specific prompts. " )
2024-06-21 23:30:19 +02:00
2023-07-01 15:18:33 +02:00
class AudioConfig ( FrigateBaseModel ) :
enabled : bool = Field ( default = False , title = " Enable audio events. " )
max_not_heard : int = Field (
default = 30 , title = " Seconds of not hearing the type of audio to end the event. "
)
2023-07-08 14:16:24 +02:00
min_volume : int = Field (
default = 500 , title = " Min volume required to run audio detection. "
)
2023-07-01 15:18:33 +02:00
listen : List [ str ] = Field (
default = DEFAULT_LISTEN_AUDIO , title = " Audio to listen for. "
)
2024-03-01 00:10:13 +01:00
filters : Optional [ Dict [ str , AudioFilterConfig ] ] = Field (
None , title = " Audio filters. "
)
2023-07-01 15:18:33 +02:00
enabled_in_config : Optional [ bool ] = Field (
2024-03-01 00:10:13 +01:00
None , title = " Keep track of original state of audio detection. "
2023-07-01 15:18:33 +02:00
)
2023-09-01 14:00:11 +02:00
num_threads : int = Field ( default = 2 , title = " Number of detection threads " , ge = 1 )
2023-07-01 15:18:33 +02:00
2021-06-24 07:45:27 +02:00
class BirdseyeModeEnum ( str , Enum ) :
objects = " objects "
motion = " motion "
continuous = " continuous "
2021-06-11 14:26:35 +02:00
2023-10-26 13:20:55 +02:00
@classmethod
def get_index ( cls , type ) :
return list ( cls ) . index ( type )
@classmethod
def get ( cls , index ) :
return list ( cls ) [ index ]
2021-06-11 14:26:35 +02:00
2024-02-10 18:55:13 +01:00
class BirdseyeLayoutConfig ( FrigateBaseModel ) :
scaling_factor : float = Field (
default = 2.0 , title = " Birdseye Scaling Factor " , ge = 1.0 , le = 5.0
)
max_cameras : Optional [ int ] = Field ( default = None , title = " Max cameras " )
2021-09-04 23:56:01 +02:00
class BirdseyeConfig ( FrigateBaseModel ) :
2021-06-24 07:45:27 +02:00
enabled : bool = Field ( default = True , title = " Enable birdseye view. " )
2023-01-17 00:50:35 +01:00
restream : bool = Field ( default = False , title = " Restream birdseye via RTSP. " )
2021-06-24 07:45:27 +02:00
width : int = Field ( default = 1280 , title = " Birdseye width. " )
height : int = Field ( default = 720 , title = " Birdseye height. " )
2021-07-02 14:50:09 +02:00
quality : int = Field (
default = 8 ,
title = " Encoding quality. " ,
ge = 1 ,
le = 31 ,
)
2024-02-10 18:55:13 +01:00
inactivity_threshold : int = Field (
default = 30 , title = " Birdseye Inactivity Threshold " , gt = 0
)
2021-06-24 07:45:27 +02:00
mode : BirdseyeModeEnum = Field (
default = BirdseyeModeEnum . objects , title = " Tracking mode. "
)
2024-02-10 18:55:13 +01:00
layout : BirdseyeLayoutConfig = Field (
default_factory = BirdseyeLayoutConfig , title = " Birdseye Layout Config "
)
2021-06-11 14:26:35 +02:00
2022-04-16 15:44:04 +02:00
# uses BaseModel because some global attributes are not available at the camera level
class BirdseyeCameraConfig ( BaseModel ) :
2022-04-15 13:59:30 +02:00
enabled : bool = Field ( default = True , title = " Enable birdseye view for camera. " )
2023-04-27 02:29:01 +02:00
order : int = Field ( default = 0 , title = " Position of the camera in the birdseye view. " )
2022-04-15 13:59:30 +02:00
mode : BirdseyeModeEnum = Field (
default = BirdseyeModeEnum . objects , title = " Tracking mode for camera. "
)
2023-03-17 23:14:57 +01:00
# Note: Setting threads to less than 2 caused several issues with recording segments
# https://github.com/blakeblackshear/frigate/issues/5659
FFMPEG_GLOBAL_ARGS_DEFAULT = [ " -hide_banner " , " -loglevel " , " warning " , " -threads " , " 2 " ]
2022-12-16 14:41:03 +01:00
FFMPEG_INPUT_ARGS_DEFAULT = " preset-rtsp-generic "
2023-03-17 23:14:57 +01:00
DETECT_FFMPEG_OUTPUT_ARGS_DEFAULT = [
" -threads " ,
" 2 " ,
" -f " ,
" rawvideo " ,
" -pix_fmt " ,
" yuv420p " ,
]
2022-12-16 14:41:03 +01:00
RECORD_FFMPEG_OUTPUT_ARGS_DEFAULT = " preset-record-generic "
2020-11-01 13:17:44 +01:00
Use dataclasses for config handling
Use config data classes to eliminate some of the boilerplate associated
with setting up the configuration. In particular, using dataclasses
removes a lot of the boilerplate around assigning properties to the
object and allows these to be easily immutable by freezing them. In the
case of simple, non-nested dataclasses, this also provides more
convenient `asdict` helpers.
To set this up, where previously the objects would be parsed from the
config via the `__init__` method, create a `build` classmethod that does
this and calls the dataclass initializer.
Some of the objects are mutated at runtime, in particular some of the
zones are mutated to set the color (this might be able to be refactored
out) and some of the camera functionality can be enabled/disabled. Some
of the configs with `enabled` properties don't seem to have mqtt hooks
to be able to toggle this, in particular, the clips, snapshots, and
detect can be toggled but rtmp and record configs do not, but all of
these configs are still not frozen in case there is some other
functionality I am missing.
There are a couple other minor fixes here, one that was introduced
by me recently where `max_seconds` was not defined, the other to
properly `get()` the message payload when handling publishing mqtt
messages sent via websocket.
2021-05-23 00:28:15 +02:00
2021-09-04 23:56:01 +02:00
class FfmpegOutputArgsConfig ( FrigateBaseModel ) :
2021-06-24 22:45:15 +02:00
detect : Union [ str , List [ str ] ] = Field (
2021-06-24 07:45:27 +02:00
default = DETECT_FFMPEG_OUTPUT_ARGS_DEFAULT ,
title = " Detect role FFmpeg output arguments. " ,
)
2021-06-24 22:45:15 +02:00
record : Union [ str , List [ str ] ] = Field (
2021-06-24 07:45:27 +02:00
default = RECORD_FFMPEG_OUTPUT_ARGS_DEFAULT ,
title = " Record role FFmpeg output arguments. " ,
)
2024-02-28 04:41:36 +01:00
_force_record_hvc1 : bool = PrivateAttr ( default = False )
Use dataclasses for config handling
Use config data classes to eliminate some of the boilerplate associated
with setting up the configuration. In particular, using dataclasses
removes a lot of the boilerplate around assigning properties to the
object and allows these to be easily immutable by freezing them. In the
case of simple, non-nested dataclasses, this also provides more
convenient `asdict` helpers.
To set this up, where previously the objects would be parsed from the
config via the `__init__` method, create a `build` classmethod that does
this and calls the dataclass initializer.
Some of the objects are mutated at runtime, in particular some of the
zones are mutated to set the color (this might be able to be refactored
out) and some of the camera functionality can be enabled/disabled. Some
of the configs with `enabled` properties don't seem to have mqtt hooks
to be able to toggle this, in particular, the clips, snapshots, and
detect can be toggled but rtmp and record configs do not, but all of
these configs are still not frozen in case there is some other
functionality I am missing.
There are a couple other minor fixes here, one that was introduced
by me recently where `max_seconds` was not defined, the other to
properly `get()` the message payload when handling publishing mqtt
messages sent via websocket.
2021-05-23 00:28:15 +02:00
2021-09-04 23:56:01 +02:00
class FfmpegConfig ( FrigateBaseModel ) :
2024-09-13 22:14:51 +02:00
path : str = Field ( default = " default " , title = " FFmpeg path " )
2021-06-24 07:45:27 +02:00
global_args : Union [ str , List [ str ] ] = Field (
default = FFMPEG_GLOBAL_ARGS_DEFAULT , title = " Global FFmpeg arguments. "
)
hwaccel_args : Union [ str , List [ str ] ] = Field (
2024-01-01 16:36:40 +01:00
default = " auto " , title = " FFmpeg hardware acceleration arguments. "
2021-06-24 07:45:27 +02:00
)
input_args : Union [ str , List [ str ] ] = Field (
default = FFMPEG_INPUT_ARGS_DEFAULT , title = " FFmpeg input arguments. "
)
output_args : FfmpegOutputArgsConfig = Field (
default_factory = FfmpegOutputArgsConfig ,
title = " FFmpeg output arguments per role. " ,
)
2023-06-30 14:14:39 +02:00
retry_interval : float = Field (
default = 10.0 ,
title = " Time in seconds to wait before FFmpeg retries connecting to the camera. " ,
)
2021-06-24 07:45:27 +02:00
2024-09-13 22:14:51 +02:00
@property
def ffmpeg_path ( self ) - > str :
if self . path == " default " :
2024-09-15 17:01:15 +02:00
if shutil . which ( " ffmpeg " ) is None :
2024-09-15 19:42:52 +02:00
return " /usr/lib/ffmpeg/6.0/bin/ffmpeg "
2024-09-13 22:14:51 +02:00
else :
return " ffmpeg "
2024-09-15 19:42:52 +02:00
elif self . path == " 6.0 " :
return " /usr/lib/ffmpeg/6.0/bin/ffmpeg "
2024-09-13 22:14:51 +02:00
elif self . path == " 5.0 " :
return " /usr/lib/ffmpeg/5.0/bin/ffmpeg "
else :
return f " { self . path } /bin/ffmpeg "
@property
def ffprobe_path ( self ) - > str :
if self . path == " default " :
if int ( os . getenv ( " LIBAVFORMAT_VERSION_MAJOR " , " 59 " ) ) > = 59 :
2024-09-15 19:42:52 +02:00
return " /usr/lib/ffmpeg/6.0/bin/ffprobe "
2024-09-13 22:14:51 +02:00
else :
return " ffprobe "
2024-09-15 19:42:52 +02:00
elif self . path == " 6.0 " :
return " /usr/lib/ffmpeg/6.0/bin/ffprobe "
2024-09-13 22:14:51 +02:00
elif self . path == " 5.0 " :
return " /usr/lib/ffmpeg/5.0/bin/ffprobe "
else :
return f " { self . path } /bin/ffprobe "
Use dataclasses for config handling
Use config data classes to eliminate some of the boilerplate associated
with setting up the configuration. In particular, using dataclasses
removes a lot of the boilerplate around assigning properties to the
object and allows these to be easily immutable by freezing them. In the
case of simple, non-nested dataclasses, this also provides more
convenient `asdict` helpers.
To set this up, where previously the objects would be parsed from the
config via the `__init__` method, create a `build` classmethod that does
this and calls the dataclass initializer.
Some of the objects are mutated at runtime, in particular some of the
zones are mutated to set the color (this might be able to be refactored
out) and some of the camera functionality can be enabled/disabled. Some
of the configs with `enabled` properties don't seem to have mqtt hooks
to be able to toggle this, in particular, the clips, snapshots, and
detect can be toggled but rtmp and record configs do not, but all of
these configs are still not frozen in case there is some other
functionality I am missing.
There are a couple other minor fixes here, one that was introduced
by me recently where `max_seconds` was not defined, the other to
properly `get()` the message payload when handling publishing mqtt
messages sent via websocket.
2021-05-23 00:28:15 +02:00
2021-08-28 15:16:25 +02:00
class CameraRoleEnum ( str , Enum ) :
2023-07-01 15:18:33 +02:00
audio = " audio "
2021-08-28 15:16:25 +02:00
record = " record "
detect = " detect "
2021-09-04 23:56:01 +02:00
class CameraInput ( FrigateBaseModel ) :
2021-06-24 07:45:27 +02:00
path : str = Field ( title = " Camera input path. " )
2021-08-28 15:16:25 +02:00
roles : List [ CameraRoleEnum ] = Field ( title = " Roles assigned to this input. " )
2021-06-24 22:45:15 +02:00
global_args : Union [ str , List [ str ] ] = Field (
2021-06-24 07:45:27 +02:00
default_factory = list , title = " FFmpeg global arguments. "
)
2021-06-24 22:45:15 +02:00
hwaccel_args : Union [ str , List [ str ] ] = Field (
2021-06-24 07:45:27 +02:00
default_factory = list , title = " FFmpeg hardware acceleration arguments. "
)
2021-06-24 22:45:15 +02:00
input_args : Union [ str , List [ str ] ] = Field (
default_factory = list , title = " FFmpeg input arguments. "
)
2021-06-24 07:45:27 +02:00
Use dataclasses for config handling
Use config data classes to eliminate some of the boilerplate associated
with setting up the configuration. In particular, using dataclasses
removes a lot of the boilerplate around assigning properties to the
object and allows these to be easily immutable by freezing them. In the
case of simple, non-nested dataclasses, this also provides more
convenient `asdict` helpers.
To set this up, where previously the objects would be parsed from the
config via the `__init__` method, create a `build` classmethod that does
this and calls the dataclass initializer.
Some of the objects are mutated at runtime, in particular some of the
zones are mutated to set the color (this might be able to be refactored
out) and some of the camera functionality can be enabled/disabled. Some
of the configs with `enabled` properties don't seem to have mqtt hooks
to be able to toggle this, in particular, the clips, snapshots, and
detect can be toggled but rtmp and record configs do not, but all of
these configs are still not frozen in case there is some other
functionality I am missing.
There are a couple other minor fixes here, one that was introduced
by me recently where `max_seconds` was not defined, the other to
properly `get()` the message payload when handling publishing mqtt
messages sent via websocket.
2021-05-23 00:28:15 +02:00
2021-06-24 07:45:27 +02:00
class CameraFfmpegConfig ( FfmpegConfig ) :
inputs : List [ CameraInput ] = Field ( title = " Camera inputs. " )
2020-11-01 13:17:44 +01:00
2024-03-01 00:10:13 +01:00
@field_validator ( " inputs " )
@classmethod
2021-06-24 07:45:27 +02:00
def validate_roles ( cls , v ) :
roles = [ role for i in v for role in i . roles ]
roles_set = set ( roles )
2020-11-03 15:15:58 +01:00
2021-06-24 07:45:27 +02:00
if len ( roles ) > len ( roles_set ) :
raise ValueError ( " Each input role may only be used once. " )
Use dataclasses for config handling
Use config data classes to eliminate some of the boilerplate associated
with setting up the configuration. In particular, using dataclasses
removes a lot of the boilerplate around assigning properties to the
object and allows these to be easily immutable by freezing them. In the
case of simple, non-nested dataclasses, this also provides more
convenient `asdict` helpers.
To set this up, where previously the objects would be parsed from the
config via the `__init__` method, create a `build` classmethod that does
this and calls the dataclass initializer.
Some of the objects are mutated at runtime, in particular some of the
zones are mutated to set the color (this might be able to be refactored
out) and some of the camera functionality can be enabled/disabled. Some
of the configs with `enabled` properties don't seem to have mqtt hooks
to be able to toggle this, in particular, the clips, snapshots, and
detect can be toggled but rtmp and record configs do not, but all of
these configs are still not frozen in case there is some other
functionality I am missing.
There are a couple other minor fixes here, one that was introduced
by me recently where `max_seconds` was not defined, the other to
properly `get()` the message payload when handling publishing mqtt
messages sent via websocket.
2021-05-23 00:28:15 +02:00
2023-05-29 12:31:17 +02:00
if " detect " not in roles :
2021-06-24 07:45:27 +02:00
raise ValueError ( " The detect role is required. " )
2021-02-17 14:23:32 +01:00
2021-06-24 07:45:27 +02:00
return v
Use dataclasses for config handling
Use config data classes to eliminate some of the boilerplate associated
with setting up the configuration. In particular, using dataclasses
removes a lot of the boilerplate around assigning properties to the
object and allows these to be easily immutable by freezing them. In the
case of simple, non-nested dataclasses, this also provides more
convenient `asdict` helpers.
To set this up, where previously the objects would be parsed from the
config via the `__init__` method, create a `build` classmethod that does
this and calls the dataclass initializer.
Some of the objects are mutated at runtime, in particular some of the
zones are mutated to set the color (this might be able to be refactored
out) and some of the camera functionality can be enabled/disabled. Some
of the configs with `enabled` properties don't seem to have mqtt hooks
to be able to toggle this, in particular, the clips, snapshots, and
detect can be toggled but rtmp and record configs do not, but all of
these configs are still not frozen in case there is some other
functionality I am missing.
There are a couple other minor fixes here, one that was introduced
by me recently where `max_seconds` was not defined, the other to
properly `get()` the message payload when handling publishing mqtt
messages sent via websocket.
2021-05-23 00:28:15 +02:00
2020-11-08 23:05:15 +01:00
2024-09-02 15:22:53 +02:00
class RetainConfig ( FrigateBaseModel ) :
default : float = Field ( default = 10 , title = " Default retention period. " )
mode : RetainModeEnum = Field ( default = RetainModeEnum . motion , title = " Retain mode. " )
objects : Dict [ str , float ] = Field (
default_factory = dict , title = " Object retention period. "
)
2021-09-04 23:56:01 +02:00
class SnapshotsConfig ( FrigateBaseModel ) :
2021-06-24 07:45:27 +02:00
enabled : bool = Field ( default = False , title = " Snapshots enabled. " )
clean_copy : bool = Field (
default = True , title = " Create a clean copy of the snapshot image. "
)
timestamp : bool = Field (
default = False , title = " Add a timestamp overlay on the snapshot. "
)
bounding_box : bool = Field (
default = True , title = " Add a bounding box overlay on the snapshot. "
)
crop : bool = Field ( default = False , title = " Crop the snapshot to the detected object. " )
required_zones : List [ str ] = Field (
default_factory = list ,
title = " List of required zones to be entered in order to save a snapshot. " ,
)
2024-03-01 00:10:13 +01:00
height : Optional [ int ] = Field ( None , title = " Snapshot image height. " )
2021-06-24 07:45:27 +02:00
retain : RetainConfig = Field (
default_factory = RetainConfig , title = " Snapshot retention. "
)
2021-07-02 14:47:03 +02:00
quality : int = Field (
default = 70 ,
title = " Quality of the encoded jpeg (0-100). " ,
ge = 0 ,
le = 100 ,
)
2021-02-17 14:23:32 +01:00
2021-06-15 22:19:49 +02:00
2021-09-04 23:56:01 +02:00
class ColorConfig ( FrigateBaseModel ) :
2021-09-04 23:39:56 +02:00
red : int = Field ( default = 255 , ge = 0 , le = 255 , title = " Red " )
green : int = Field ( default = 255 , ge = 0 , le = 255 , title = " Green " )
blue : int = Field ( default = 255 , ge = 0 , le = 255 , title = " Blue " )
2021-06-15 22:19:49 +02:00
2021-09-04 23:34:48 +02:00
class TimestampPositionEnum ( str , Enum ) :
tl = " tl "
tr = " tr "
bl = " bl "
br = " br "
class TimestampEffectEnum ( str , Enum ) :
solid = " solid "
shadow = " shadow "
2021-09-04 23:56:01 +02:00
class TimestampStyleConfig ( FrigateBaseModel ) :
2021-09-04 23:34:48 +02:00
position : TimestampPositionEnum = Field (
default = TimestampPositionEnum . tl , title = " Timestamp position. "
)
2021-06-24 07:45:27 +02:00
format : str = Field ( default = DEFAULT_TIME_FORMAT , title = " Timestamp format. " )
color : ColorConfig = Field ( default_factory = ColorConfig , title = " Timestamp color. " )
thickness : int = Field ( default = 2 , title = " Timestamp thickness. " )
2024-03-01 00:10:13 +01:00
effect : Optional [ TimestampEffectEnum ] = Field ( None , title = " Timestamp effect. " )
2021-06-15 22:19:49 +02:00
Use dataclasses for config handling
Use config data classes to eliminate some of the boilerplate associated
with setting up the configuration. In particular, using dataclasses
removes a lot of the boilerplate around assigning properties to the
object and allows these to be easily immutable by freezing them. In the
case of simple, non-nested dataclasses, this also provides more
convenient `asdict` helpers.
To set this up, where previously the objects would be parsed from the
config via the `__init__` method, create a `build` classmethod that does
this and calls the dataclass initializer.
Some of the objects are mutated at runtime, in particular some of the
zones are mutated to set the color (this might be able to be refactored
out) and some of the camera functionality can be enabled/disabled. Some
of the configs with `enabled` properties don't seem to have mqtt hooks
to be able to toggle this, in particular, the clips, snapshots, and
detect can be toggled but rtmp and record configs do not, but all of
these configs are still not frozen in case there is some other
functionality I am missing.
There are a couple other minor fixes here, one that was introduced
by me recently where `max_seconds` was not defined, the other to
properly `get()` the message payload when handling publishing mqtt
messages sent via websocket.
2021-05-23 00:28:15 +02:00
2021-09-04 23:56:01 +02:00
class CameraMqttConfig ( FrigateBaseModel ) :
2021-06-24 07:45:27 +02:00
enabled : bool = Field ( default = True , title = " Send image over MQTT. " )
timestamp : bool = Field ( default = True , title = " Add timestamp to MQTT image. " )
bounding_box : bool = Field ( default = True , title = " Add bounding box to MQTT image. " )
crop : bool = Field ( default = True , title = " Crop MQTT image to detected object. " )
height : int = Field ( default = 270 , title = " MQTT image height. " )
required_zones : List [ str ] = Field (
default_factory = list ,
title = " List of required zones to be entered in order to send the image. " ,
)
2021-07-02 14:47:03 +02:00
quality : int = Field (
default = 70 ,
title = " Quality of the encoded jpeg (0-100). " ,
ge = 0 ,
le = 100 ,
)
2021-02-05 04:44:44 +01:00
2020-11-29 22:55:53 +01:00
2023-01-17 00:50:35 +01:00
class CameraLiveConfig ( FrigateBaseModel ) :
stream_name : str = Field ( default = " " , title = " Name of restream to use as live view. " )
height : int = Field ( default = 720 , title = " Live camera view height " )
quality : int = Field ( default = 8 , ge = 1 , le = 31 , title = " Live camera view quality " )
2022-11-02 12:36:09 +01:00
2023-01-17 00:50:35 +01:00
class RestreamConfig ( BaseModel ) :
2024-03-01 00:10:13 +01:00
model_config = ConfigDict ( extra = " allow " )
2021-02-17 14:23:32 +01:00
2021-06-23 15:09:15 +02:00
2022-04-15 14:23:02 +02:00
class CameraUiConfig ( FrigateBaseModel ) :
order : int = Field ( default = 0 , title = " Order of camera in UI. " )
2022-04-16 15:42:44 +02:00
dashboard : bool = Field (
default = True , title = " Show this camera in Frigate dashboard UI. "
)
2022-04-15 14:23:02 +02:00
2021-09-04 23:56:01 +02:00
class CameraConfig ( FrigateBaseModel ) :
2024-03-01 00:10:13 +01:00
name : Optional [ str ] = Field ( None , title = " Camera name. " , pattern = REGEX_CAMERA_NAME )
2022-11-02 12:41:44 +01:00
enabled : bool = Field ( default = True , title = " Enable camera. " )
2021-06-24 07:45:27 +02:00
ffmpeg : CameraFfmpegConfig = Field ( title = " FFmpeg configuration for the camera. " )
best_image_timeout : int = Field (
default = 60 ,
title = " How long to wait for the image with the highest confidence score. " ,
)
2023-11-01 14:08:59 +01:00
webui_url : Optional [ str ] = Field (
2024-03-01 00:10:13 +01:00
None ,
2023-11-01 14:08:59 +01:00
title = " URL to visit the camera directly from system page " ,
)
2021-06-24 07:45:27 +02:00
zones : Dict [ str , ZoneConfig ] = Field (
default_factory = dict , title = " Zone configuration. "
)
record : RecordConfig = Field (
default_factory = RecordConfig , title = " Record configuration. "
)
2023-01-17 00:50:35 +01:00
live : CameraLiveConfig = Field (
default_factory = CameraLiveConfig , title = " Live playback settings. "
2021-08-28 16:14:00 +02:00
)
snapshots : SnapshotsConfig = Field (
default_factory = SnapshotsConfig , title = " Snapshot configuration. "
2021-06-24 07:45:27 +02:00
)
mqtt : CameraMqttConfig = Field (
default_factory = CameraMqttConfig , title = " MQTT configuration. "
)
objects : ObjectConfig = Field (
default_factory = ObjectConfig , title = " Object configuration. "
)
2024-04-13 14:08:20 +02:00
review : ReviewConfig = Field (
default_factory = ReviewConfig , title = " Review configuration. "
)
2024-06-21 23:30:19 +02:00
genai : GenAICameraConfig = Field (
default_factory = GenAICameraConfig , title = " Generative AI configuration. "
)
2023-07-01 15:18:33 +02:00
audio : AudioConfig = Field (
default_factory = AudioConfig , title = " Audio events configuration. "
)
2024-03-01 00:10:13 +01:00
motion : Optional [ MotionConfig ] = Field (
None , title = " Motion detection configuration. "
)
2021-08-28 16:14:00 +02:00
detect : DetectConfig = Field (
default_factory = DetectConfig , title = " Object detection configuration. "
)
2023-04-26 13:08:53 +02:00
onvif : OnvifConfig = Field (
default_factory = OnvifConfig , title = " Camera Onvif Configuration. "
)
2022-04-15 14:23:02 +02:00
ui : CameraUiConfig = Field (
default_factory = CameraUiConfig , title = " Camera UI Modifications. "
)
2022-04-15 13:59:30 +02:00
birdseye : BirdseyeCameraConfig = Field (
default_factory = BirdseyeCameraConfig , title = " Birdseye camera configuration. "
)
2021-06-24 23:02:46 +02:00
timestamp_style : TimestampStyleConfig = Field (
default_factory = TimestampStyleConfig , title = " Timestamp style configuration. "
2021-06-24 07:45:27 +02:00
)
2021-11-08 14:32:29 +01:00
_ffmpeg_cmds : List [ Dict [ str , List [ str ] ] ] = PrivateAttr ( )
2021-06-24 07:45:27 +02:00
def __init__ ( self , * * config ) :
# Set zone colors
if " zones " in config :
2024-07-07 20:53:00 +02:00
colors = generate_color_palette ( len ( config [ " zones " ] ) )
2021-06-24 07:45:27 +02:00
config [ " zones " ] = {
2024-07-07 20:53:00 +02:00
name : { * * z , " color " : color }
for ( name , z ) , color in zip ( config [ " zones " ] . items ( ) , colors )
2021-06-24 07:45:27 +02:00
}
2021-10-16 14:46:39 +02:00
# add roles to the input if there is only one
if len ( config [ " ffmpeg " ] [ " inputs " ] ) == 1 :
2023-07-01 15:18:33 +02:00
has_audio = " audio " in config [ " ffmpeg " ] [ " inputs " ] [ 0 ] . get ( " roles " , [ ] )
2022-11-02 12:36:09 +01:00
config [ " ffmpeg " ] [ " inputs " ] [ 0 ] [ " roles " ] = [
" record " ,
" detect " ,
]
2023-07-01 15:18:33 +02:00
if has_audio :
config [ " ffmpeg " ] [ " inputs " ] [ 0 ] [ " roles " ] . append ( " audio " )
2021-06-24 07:45:27 +02:00
super ( ) . __init__ ( * * config )
Use dataclasses for config handling
Use config data classes to eliminate some of the boilerplate associated
with setting up the configuration. In particular, using dataclasses
removes a lot of the boilerplate around assigning properties to the
object and allows these to be easily immutable by freezing them. In the
case of simple, non-nested dataclasses, this also provides more
convenient `asdict` helpers.
To set this up, where previously the objects would be parsed from the
config via the `__init__` method, create a `build` classmethod that does
this and calls the dataclass initializer.
Some of the objects are mutated at runtime, in particular some of the
zones are mutated to set the color (this might be able to be refactored
out) and some of the camera functionality can be enabled/disabled. Some
of the configs with `enabled` properties don't seem to have mqtt hooks
to be able to toggle this, in particular, the clips, snapshots, and
detect can be toggled but rtmp and record configs do not, but all of
these configs are still not frozen in case there is some other
functionality I am missing.
There are a couple other minor fixes here, one that was introduced
by me recently where `max_seconds` was not defined, the other to
properly `get()` the message payload when handling publishing mqtt
messages sent via websocket.
2021-05-23 00:28:15 +02:00
@property
def frame_shape ( self ) - > Tuple [ int , int ] :
2021-08-14 21:18:35 +02:00
return self . detect . height , self . detect . width
Use dataclasses for config handling
Use config data classes to eliminate some of the boilerplate associated
with setting up the configuration. In particular, using dataclasses
removes a lot of the boilerplate around assigning properties to the
object and allows these to be easily immutable by freezing them. In the
case of simple, non-nested dataclasses, this also provides more
convenient `asdict` helpers.
To set this up, where previously the objects would be parsed from the
config via the `__init__` method, create a `build` classmethod that does
this and calls the dataclass initializer.
Some of the objects are mutated at runtime, in particular some of the
zones are mutated to set the color (this might be able to be refactored
out) and some of the camera functionality can be enabled/disabled. Some
of the configs with `enabled` properties don't seem to have mqtt hooks
to be able to toggle this, in particular, the clips, snapshots, and
detect can be toggled but rtmp and record configs do not, but all of
these configs are still not frozen in case there is some other
functionality I am missing.
There are a couple other minor fixes here, one that was introduced
by me recently where `max_seconds` was not defined, the other to
properly `get()` the message payload when handling publishing mqtt
messages sent via websocket.
2021-05-23 00:28:15 +02:00
@property
def frame_shape_yuv ( self ) - > Tuple [ int , int ] :
2021-08-14 21:18:35 +02:00
return self . detect . height * 3 / / 2 , self . detect . width
Use dataclasses for config handling
Use config data classes to eliminate some of the boilerplate associated
with setting up the configuration. In particular, using dataclasses
removes a lot of the boilerplate around assigning properties to the
object and allows these to be easily immutable by freezing them. In the
case of simple, non-nested dataclasses, this also provides more
convenient `asdict` helpers.
To set this up, where previously the objects would be parsed from the
config via the `__init__` method, create a `build` classmethod that does
this and calls the dataclass initializer.
Some of the objects are mutated at runtime, in particular some of the
zones are mutated to set the color (this might be able to be refactored
out) and some of the camera functionality can be enabled/disabled. Some
of the configs with `enabled` properties don't seem to have mqtt hooks
to be able to toggle this, in particular, the clips, snapshots, and
detect can be toggled but rtmp and record configs do not, but all of
these configs are still not frozen in case there is some other
functionality I am missing.
There are a couple other minor fixes here, one that was introduced
by me recently where `max_seconds` was not defined, the other to
properly `get()` the message payload when handling publishing mqtt
messages sent via websocket.
2021-05-23 00:28:15 +02:00
@property
def ffmpeg_cmds ( self ) - > List [ Dict [ str , List [ str ] ] ] :
2021-11-08 14:32:29 +01:00
return self . _ffmpeg_cmds
2021-11-09 02:05:39 +01:00
def create_ffmpeg_cmds ( self ) :
2022-01-14 14:31:25 +01:00
if " _ffmpeg_cmds " in self :
return
Use dataclasses for config handling
Use config data classes to eliminate some of the boilerplate associated
with setting up the configuration. In particular, using dataclasses
removes a lot of the boilerplate around assigning properties to the
object and allows these to be easily immutable by freezing them. In the
case of simple, non-nested dataclasses, this also provides more
convenient `asdict` helpers.
To set this up, where previously the objects would be parsed from the
config via the `__init__` method, create a `build` classmethod that does
this and calls the dataclass initializer.
Some of the objects are mutated at runtime, in particular some of the
zones are mutated to set the color (this might be able to be refactored
out) and some of the camera functionality can be enabled/disabled. Some
of the configs with `enabled` properties don't seem to have mqtt hooks
to be able to toggle this, in particular, the clips, snapshots, and
detect can be toggled but rtmp and record configs do not, but all of
these configs are still not frozen in case there is some other
functionality I am missing.
There are a couple other minor fixes here, one that was introduced
by me recently where `max_seconds` was not defined, the other to
properly `get()` the message payload when handling publishing mqtt
messages sent via websocket.
2021-05-23 00:28:15 +02:00
ffmpeg_cmds = [ ]
for ffmpeg_input in self . ffmpeg . inputs :
2020-12-07 15:07:35 +01:00
ffmpeg_cmd = self . _get_ffmpeg_cmd ( ffmpeg_input )
if ffmpeg_cmd is None :
continue
Use dataclasses for config handling
Use config data classes to eliminate some of the boilerplate associated
with setting up the configuration. In particular, using dataclasses
removes a lot of the boilerplate around assigning properties to the
object and allows these to be easily immutable by freezing them. In the
case of simple, non-nested dataclasses, this also provides more
convenient `asdict` helpers.
To set this up, where previously the objects would be parsed from the
config via the `__init__` method, create a `build` classmethod that does
this and calls the dataclass initializer.
Some of the objects are mutated at runtime, in particular some of the
zones are mutated to set the color (this might be able to be refactored
out) and some of the camera functionality can be enabled/disabled. Some
of the configs with `enabled` properties don't seem to have mqtt hooks
to be able to toggle this, in particular, the clips, snapshots, and
detect can be toggled but rtmp and record configs do not, but all of
these configs are still not frozen in case there is some other
functionality I am missing.
There are a couple other minor fixes here, one that was introduced
by me recently where `max_seconds` was not defined, the other to
properly `get()` the message payload when handling publishing mqtt
messages sent via websocket.
2021-05-23 00:28:15 +02:00
ffmpeg_cmds . append ( { " roles " : ffmpeg_input . roles , " cmd " : ffmpeg_cmd } )
2021-11-09 01:20:47 +01:00
self . _ffmpeg_cmds = ffmpeg_cmds
Use dataclasses for config handling
Use config data classes to eliminate some of the boilerplate associated
with setting up the configuration. In particular, using dataclasses
removes a lot of the boilerplate around assigning properties to the
object and allows these to be easily immutable by freezing them. In the
case of simple, non-nested dataclasses, this also provides more
convenient `asdict` helpers.
To set this up, where previously the objects would be parsed from the
config via the `__init__` method, create a `build` classmethod that does
this and calls the dataclass initializer.
Some of the objects are mutated at runtime, in particular some of the
zones are mutated to set the color (this might be able to be refactored
out) and some of the camera functionality can be enabled/disabled. Some
of the configs with `enabled` properties don't seem to have mqtt hooks
to be able to toggle this, in particular, the clips, snapshots, and
detect can be toggled but rtmp and record configs do not, but all of
these configs are still not frozen in case there is some other
functionality I am missing.
There are a couple other minor fixes here, one that was introduced
by me recently where `max_seconds` was not defined, the other to
properly `get()` the message payload when handling publishing mqtt
messages sent via websocket.
2021-05-23 00:28:15 +02:00
2021-06-24 07:45:27 +02:00
def _get_ffmpeg_cmd ( self , ffmpeg_input : CameraInput ) :
2020-11-29 22:55:53 +01:00
ffmpeg_output_args = [ ]
2021-02-17 14:23:32 +01:00
if " detect " in ffmpeg_input . roles :
2022-11-29 04:48:11 +01:00
detect_args = get_ffmpeg_arg_list ( self . ffmpeg . output_args . detect )
2022-12-30 17:56:52 +01:00
scale_detect_args = parse_preset_hardware_acceleration_scale (
ffmpeg_input . hwaccel_args or self . ffmpeg . hwaccel_args ,
detect_args ,
self . detect . fps ,
self . detect . width ,
self . detect . height ,
2021-08-14 21:18:35 +02:00
)
2022-12-30 17:56:52 +01:00
ffmpeg_output_args = scale_detect_args + ffmpeg_output_args + [ " pipe: " ]
2022-11-29 04:48:11 +01:00
2021-08-15 15:30:27 +02:00
if " record " in ffmpeg_input . roles and self . record . enabled :
2022-11-29 04:48:11 +01:00
record_args = get_ffmpeg_arg_list (
2024-02-28 04:41:36 +01:00
parse_preset_output_record (
self . ffmpeg . output_args . record ,
self . ffmpeg . output_args . _force_record_hvc1 ,
)
2022-11-29 04:48:11 +01:00
or self . ffmpeg . output_args . record
2021-06-24 22:45:15 +02:00
)
2021-10-16 17:36:13 +02:00
2021-06-24 22:45:15 +02:00
ffmpeg_output_args = (
record_args
2023-11-05 21:30:29 +01:00
+ [ f " { os . path . join ( CACHE_DIR , self . name ) } @ { CACHE_SEGMENT_FORMAT } .mp4 " ]
2021-02-17 14:23:32 +01:00
+ ffmpeg_output_args
)
2021-01-09 18:26:46 +01:00
2024-09-17 17:41:46 +02:00
# if there aren't any outputs enabled for this input
2020-12-07 15:07:35 +01:00
if len ( ffmpeg_output_args ) == 0 :
return None
2022-11-29 04:48:11 +01:00
global_args = get_ffmpeg_arg_list (
ffmpeg_input . global_args or self . ffmpeg . global_args
2021-06-24 22:45:15 +02:00
)
2024-02-15 01:24:36 +01:00
camera_arg = (
self . ffmpeg . hwaccel_args if self . ffmpeg . hwaccel_args != " auto " else None
)
2022-11-29 04:48:11 +01:00
hwaccel_args = get_ffmpeg_arg_list (
2023-07-26 12:50:41 +02:00
parse_preset_hardware_acceleration_decode (
ffmpeg_input . hwaccel_args ,
self . detect . fps ,
self . detect . width ,
self . detect . height ,
)
2022-12-30 17:56:52 +01:00
or ffmpeg_input . hwaccel_args
2023-07-26 12:50:41 +02:00
or parse_preset_hardware_acceleration_decode (
2024-02-15 01:24:36 +01:00
camera_arg ,
2023-07-26 12:50:41 +02:00
self . detect . fps ,
self . detect . width ,
self . detect . height ,
)
2024-02-15 01:24:36 +01:00
or camera_arg
or [ ]
2021-06-24 22:45:15 +02:00
)
2022-11-29 04:48:11 +01:00
input_args = get_ffmpeg_arg_list (
2022-12-30 17:56:52 +01:00
parse_preset_input ( ffmpeg_input . input_args , self . detect . fps )
or ffmpeg_input . input_args
2022-11-29 04:48:11 +01:00
or parse_preset_input ( self . ffmpeg . input_args , self . detect . fps )
or self . ffmpeg . input_args
2021-06-24 22:45:15 +02:00
)
2021-02-17 14:23:32 +01:00
cmd = (
2024-09-13 22:14:51 +02:00
[ self . ffmpeg . ffmpeg_path ]
2021-06-24 22:45:15 +02:00
+ global_args
2024-09-14 20:22:03 +02:00
+ ( hwaccel_args if " detect " in ffmpeg_input . roles else [ ] )
2021-06-24 22:45:15 +02:00
+ input_args
2022-11-02 13:00:54 +01:00
+ [ " -i " , escape_special_characters ( ffmpeg_input . path ) ]
2021-02-17 14:23:32 +01:00
+ ffmpeg_output_args
)
2021-01-09 18:26:46 +01:00
2021-02-17 14:23:32 +01:00
return [ part for part in cmd if part != " " ]
2021-01-09 18:26:46 +01:00
Use dataclasses for config handling
Use config data classes to eliminate some of the boilerplate associated
with setting up the configuration. In particular, using dataclasses
removes a lot of the boilerplate around assigning properties to the
object and allows these to be easily immutable by freezing them. In the
case of simple, non-nested dataclasses, this also provides more
convenient `asdict` helpers.
To set this up, where previously the objects would be parsed from the
config via the `__init__` method, create a `build` classmethod that does
this and calls the dataclass initializer.
Some of the objects are mutated at runtime, in particular some of the
zones are mutated to set the color (this might be able to be refactored
out) and some of the camera functionality can be enabled/disabled. Some
of the configs with `enabled` properties don't seem to have mqtt hooks
to be able to toggle this, in particular, the clips, snapshots, and
detect can be toggled but rtmp and record configs do not, but all of
these configs are still not frozen in case there is some other
functionality I am missing.
There are a couple other minor fixes here, one that was introduced
by me recently where `max_seconds` was not defined, the other to
properly `get()` the message payload when handling publishing mqtt
messages sent via websocket.
2021-05-23 00:28:15 +02:00
2021-09-04 23:56:01 +02:00
class DatabaseConfig ( FrigateBaseModel ) :
2023-04-23 18:35:40 +02:00
path : str = Field ( default = DEFAULT_DB_PATH , title = " Database path. " )
Use dataclasses for config handling
Use config data classes to eliminate some of the boilerplate associated
with setting up the configuration. In particular, using dataclasses
removes a lot of the boilerplate around assigning properties to the
object and allows these to be easily immutable by freezing them. In the
case of simple, non-nested dataclasses, this also provides more
convenient `asdict` helpers.
To set this up, where previously the objects would be parsed from the
config via the `__init__` method, create a `build` classmethod that does
this and calls the dataclass initializer.
Some of the objects are mutated at runtime, in particular some of the
zones are mutated to set the color (this might be able to be refactored
out) and some of the camera functionality can be enabled/disabled. Some
of the configs with `enabled` properties don't seem to have mqtt hooks
to be able to toggle this, in particular, the clips, snapshots, and
detect can be toggled but rtmp and record configs do not, but all of
these configs are still not frozen in case there is some other
functionality I am missing.
There are a couple other minor fixes here, one that was introduced
by me recently where `max_seconds` was not defined, the other to
properly `get()` the message payload when handling publishing mqtt
messages sent via websocket.
2021-05-23 00:28:15 +02:00
2021-06-24 07:45:27 +02:00
class LogLevelEnum ( str , Enum ) :
debug = " debug "
info = " info "
warning = " warning "
error = " error "
critical = " critical "
Use dataclasses for config handling
Use config data classes to eliminate some of the boilerplate associated
with setting up the configuration. In particular, using dataclasses
removes a lot of the boilerplate around assigning properties to the
object and allows these to be easily immutable by freezing them. In the
case of simple, non-nested dataclasses, this also provides more
convenient `asdict` helpers.
To set this up, where previously the objects would be parsed from the
config via the `__init__` method, create a `build` classmethod that does
this and calls the dataclass initializer.
Some of the objects are mutated at runtime, in particular some of the
zones are mutated to set the color (this might be able to be refactored
out) and some of the camera functionality can be enabled/disabled. Some
of the configs with `enabled` properties don't seem to have mqtt hooks
to be able to toggle this, in particular, the clips, snapshots, and
detect can be toggled but rtmp and record configs do not, but all of
these configs are still not frozen in case there is some other
functionality I am missing.
There are a couple other minor fixes here, one that was introduced
by me recently where `max_seconds` was not defined, the other to
properly `get()` the message payload when handling publishing mqtt
messages sent via websocket.
2021-05-23 00:28:15 +02:00
2021-09-04 23:56:01 +02:00
class LoggerConfig ( FrigateBaseModel ) :
2021-06-24 07:45:27 +02:00
default : LogLevelEnum = Field (
default = LogLevelEnum . info , title = " Default logging level. "
)
logs : Dict [ str , LogLevelEnum ] = Field (
default_factory = dict , title = " Log level for specified processes. "
)
Use dataclasses for config handling
Use config data classes to eliminate some of the boilerplate associated
with setting up the configuration. In particular, using dataclasses
removes a lot of the boilerplate around assigning properties to the
object and allows these to be easily immutable by freezing them. In the
case of simple, non-nested dataclasses, this also provides more
convenient `asdict` helpers.
To set this up, where previously the objects would be parsed from the
config via the `__init__` method, create a `build` classmethod that does
this and calls the dataclass initializer.
Some of the objects are mutated at runtime, in particular some of the
zones are mutated to set the color (this might be able to be refactored
out) and some of the camera functionality can be enabled/disabled. Some
of the configs with `enabled` properties don't seem to have mqtt hooks
to be able to toggle this, in particular, the clips, snapshots, and
detect can be toggled but rtmp and record configs do not, but all of
these configs are still not frozen in case there is some other
functionality I am missing.
There are a couple other minor fixes here, one that was introduced
by me recently where `max_seconds` was not defined, the other to
properly `get()` the message payload when handling publishing mqtt
messages sent via websocket.
2021-05-23 00:28:15 +02:00
2024-03-05 00:18:30 +01:00
class CameraGroupConfig ( FrigateBaseModel ) :
""" Represents a group of cameras. """
2024-05-29 16:19:05 +02:00
cameras : Union [ str , List [ str ] ] = Field (
2024-03-05 00:18:30 +01:00
default_factory = list , title = " List of cameras in this group. "
)
icon : str = Field ( default = " generic " , title = " Icon that represents camera group. " )
order : int = Field ( default = 0 , title = " Sort order for group. " )
2024-05-29 16:19:05 +02:00
@field_validator ( " cameras " , mode = " before " )
@classmethod
def validate_cameras ( cls , v ) :
if isinstance ( v , str ) and " , " not in v :
return [ v ]
return v
2024-03-05 00:18:30 +01:00
2022-11-09 02:47:45 +01:00
def verify_config_roles ( camera_config : CameraConfig ) - > None :
""" Verify that roles are setup in the config correctly. """
assigned_roles = list (
set ( [ r for i in camera_config . ffmpeg . inputs for r in i . roles ] )
)
2023-05-29 12:31:17 +02:00
if camera_config . record . enabled and " record " not in assigned_roles :
2022-11-09 02:47:45 +01:00
raise ValueError (
f " Camera { camera_config . name } has record enabled, but record is not assigned to an input. "
)
2023-07-01 15:18:33 +02:00
if camera_config . audio . enabled and " audio " not in assigned_roles :
raise ValueError (
f " Camera { camera_config . name } has audio events enabled, but audio is not assigned to an input. "
)
2023-01-17 00:50:35 +01:00
def verify_valid_live_stream_name (
frigate_config : FrigateConfig , camera_config : CameraConfig
2023-04-24 14:24:28 +02:00
) - > ValueError | None :
2023-01-17 00:50:35 +01:00
""" Verify that a restream exists to use for live view. """
if (
camera_config . live . stream_name
2024-03-01 00:10:13 +01:00
not in frigate_config . go2rtc . model_dump ( ) . get ( " streams " , { } ) . keys ( )
2023-01-17 00:50:35 +01:00
) :
return ValueError (
f " No restream with name { camera_config . live . stream_name } exists for camera { camera_config . name } . "
2022-11-09 02:47:45 +01:00
)
def verify_recording_retention ( camera_config : CameraConfig ) - > None :
""" Verify that recording retention modes are ranked correctly. """
rank_map = {
RetainModeEnum . all : 0 ,
RetainModeEnum . motion : 1 ,
RetainModeEnum . active_objects : 2 ,
}
if (
camera_config . record . retain . days != 0
and rank_map [ camera_config . record . retain . mode ]
2024-09-02 15:22:53 +02:00
> rank_map [ camera_config . record . alerts . retain . mode ]
) :
logger . warning (
f " { camera_config . name } : Recording retention is configured for { camera_config . record . retain . mode } and alert retention is configured for { camera_config . record . alerts . retain . mode } . The more restrictive retention policy will be applied. "
)
if (
camera_config . record . retain . days != 0
and rank_map [ camera_config . record . retain . mode ]
> rank_map [ camera_config . record . detections . retain . mode ]
2022-11-09 02:47:45 +01:00
) :
logger . warning (
2024-09-02 15:22:53 +02:00
f " { camera_config . name } : Recording retention is configured for { camera_config . record . retain . mode } and detection retention is configured for { camera_config . record . detections . retain . mode } . The more restrictive retention policy will be applied. "
2022-11-09 02:47:45 +01:00
)
2022-12-09 04:03:54 +01:00
def verify_recording_segments_setup_with_reasonable_time (
camera_config : CameraConfig ,
) - > None :
""" Verify that recording segments are setup and segment time is not greater than 60. """
record_args : list [ str ] = get_ffmpeg_arg_list (
camera_config . ffmpeg . output_args . record
)
2022-12-09 15:35:28 +01:00
if record_args [ 0 ] . startswith ( " preset " ) :
return
2022-12-09 04:03:54 +01:00
seg_arg_index = record_args . index ( " -segment_time " )
if seg_arg_index < 0 :
raise ValueError (
f " Camera { camera_config . name } has no segment_time in recording output args, segment args are required for record. "
)
if int ( record_args [ seg_arg_index + 1 ] ) > 60 :
raise ValueError (
f " Camera { camera_config . name } has invalid segment_time output arg, segment_time must be 60 or less. "
)
2022-11-09 02:47:45 +01:00
def verify_zone_objects_are_tracked ( camera_config : CameraConfig ) - > None :
""" Verify that user has not entered zone objects that are not in the tracking config. """
for zone_name , zone in camera_config . zones . items ( ) :
for obj in zone . objects :
if obj not in camera_config . objects . track :
raise ValueError (
f " Zone { zone_name } is configured to track { obj } but that object type is not added to objects -> track. "
)
2024-04-18 18:35:16 +02:00
def verify_required_zones_exist ( camera_config : CameraConfig ) - > None :
for det_zone in camera_config . review . detections . required_zones :
if det_zone not in camera_config . zones . keys ( ) :
raise ValueError (
f " Camera { camera_config . name } has a required zone for detections { det_zone } that is not defined. "
)
for det_zone in camera_config . review . alerts . required_zones :
if det_zone not in camera_config . zones . keys ( ) :
raise ValueError (
f " Camera { camera_config . name } has a required zone for alerts { det_zone } that is not defined. "
)
2023-07-08 14:04:47 +02:00
def verify_autotrack_zones ( camera_config : CameraConfig ) - > ValueError | None :
""" Verify that required_zones are specified when autotracking is enabled. """
if (
camera_config . onvif . autotracking . enabled
and not camera_config . onvif . autotracking . required_zones
) :
raise ValueError (
f " Camera { camera_config . name } has autotracking enabled, required_zones must be set to at least one of the camera ' s zones. "
)
2024-02-19 14:26:59 +01:00
def verify_motion_and_detect ( camera_config : CameraConfig ) - > ValueError | None :
""" Verify that required_zones are specified when autotracking is enabled. """
if camera_config . detect . enabled and not camera_config . motion . enabled :
raise ValueError (
f " Camera { camera_config . name } has motion detection disabled and object detection enabled but object detection requires motion detection. "
)
2021-09-04 23:56:01 +02:00
class FrigateConfig ( FrigateBaseModel ) :
2024-05-18 18:36:13 +02:00
mqtt : MqttConfig = Field ( title = " MQTT configuration. " )
2021-06-24 07:45:27 +02:00
database : DatabaseConfig = Field (
default_factory = DatabaseConfig , title = " Database configuration. "
)
2024-06-02 14:48:28 +02:00
tls : TlsConfig = Field ( default_factory = TlsConfig , title = " TLS configuration. " )
2024-06-15 01:02:13 +02:00
proxy : ProxyConfig = Field (
default_factory = ProxyConfig , title = " Proxy configuration. "
)
2024-05-18 18:36:13 +02:00
auth : AuthConfig = Field ( default_factory = AuthConfig , title = " Auth configuration. " )
2021-06-24 07:45:27 +02:00
environment_vars : Dict [ str , str ] = Field (
default_factory = dict , title = " Frigate environment variables. "
)
2022-02-27 15:04:12 +01:00
ui : UIConfig = Field ( default_factory = UIConfig , title = " UI configuration. " )
2024-07-22 22:39:15 +02:00
notifications : NotificationConfig = Field (
default_factory = NotificationConfig , title = " Notification Config "
)
2023-01-26 01:36:26 +01:00
telemetry : TelemetryConfig = Field (
default_factory = TelemetryConfig , title = " Telemetry configuration. "
)
2021-06-24 07:45:27 +02:00
model : ModelConfig = Field (
default_factory = ModelConfig , title = " Detection model configuration. "
)
2023-04-24 14:24:28 +02:00
detectors : Dict [ str , BaseDetectorConfig ] = Field (
2022-12-15 14:12:52 +01:00
default = DEFAULT_DETECTORS ,
2021-06-24 07:45:27 +02:00
title = " Detector hardware configuration. " ,
)
logger : LoggerConfig = Field (
default_factory = LoggerConfig , title = " Logging configuration. "
)
record : RecordConfig = Field (
default_factory = RecordConfig , title = " Global record configuration. "
)
snapshots : SnapshotsConfig = Field (
default_factory = SnapshotsConfig , title = " Global snapshots configuration. "
)
2023-01-17 00:50:35 +01:00
live : CameraLiveConfig = Field (
default_factory = CameraLiveConfig , title = " Live playback settings. "
)
go2rtc : RestreamConfig = Field (
2022-11-02 12:36:09 +01:00
default_factory = RestreamConfig , title = " Global restream configuration. "
)
2021-06-24 07:45:27 +02:00
birdseye : BirdseyeConfig = Field (
default_factory = BirdseyeConfig , title = " Birdseye configuration. "
)
ffmpeg : FfmpegConfig = Field (
default_factory = FfmpegConfig , title = " Global FFmpeg configuration. "
)
objects : ObjectConfig = Field (
default_factory = ObjectConfig , title = " Global object configuration. "
)
2024-04-13 14:08:20 +02:00
review : ReviewConfig = Field (
default_factory = ReviewConfig , title = " Review configuration. "
)
2024-06-21 23:30:19 +02:00
semantic_search : SemanticSearchConfig = Field (
default_factory = SemanticSearchConfig , title = " Semantic search configuration. "
)
genai : GenAIConfig = Field (
default_factory = GenAIConfig , title = " Generative AI configuration. "
)
2023-07-01 15:18:33 +02:00
audio : AudioConfig = Field (
default_factory = AudioConfig , title = " Global Audio events configuration. "
)
2021-06-24 07:45:27 +02:00
motion : Optional [ MotionConfig ] = Field (
2024-03-01 00:10:13 +01:00
None , title = " Global motion detection configuration. "
2021-06-24 07:45:27 +02:00
)
2021-08-28 16:14:00 +02:00
detect : DetectConfig = Field (
default_factory = DetectConfig , title = " Global object tracking configuration. "
2021-06-24 07:45:27 +02:00
)
cameras : Dict [ str , CameraConfig ] = Field ( title = " Camera configuration. " )
2024-03-05 00:18:30 +01:00
camera_groups : Dict [ str , CameraGroupConfig ] = Field (
2024-03-05 13:02:34 +01:00
default_factory = dict , title = " Camera group configuration "
2024-03-05 00:18:30 +01:00
)
2021-09-03 14:03:36 +02:00
timestamp_style : TimestampStyleConfig = Field (
default_factory = TimestampStyleConfig ,
title = " Global timestamp style configuration. " ,
)
2024-09-02 15:22:53 +02:00
version : Optional [ str ] = Field ( default = None , title = " Current config version. " )
Use dataclasses for config handling
Use config data classes to eliminate some of the boilerplate associated
with setting up the configuration. In particular, using dataclasses
removes a lot of the boilerplate around assigning properties to the
object and allows these to be easily immutable by freezing them. In the
case of simple, non-nested dataclasses, this also provides more
convenient `asdict` helpers.
To set this up, where previously the objects would be parsed from the
config via the `__init__` method, create a `build` classmethod that does
this and calls the dataclass initializer.
Some of the objects are mutated at runtime, in particular some of the
zones are mutated to set the color (this might be able to be refactored
out) and some of the camera functionality can be enabled/disabled. Some
of the configs with `enabled` properties don't seem to have mqtt hooks
to be able to toggle this, in particular, the clips, snapshots, and
detect can be toggled but rtmp and record configs do not, but all of
these configs are still not frozen in case there is some other
functionality I am missing.
There are a couple other minor fixes here, one that was introduced
by me recently where `max_seconds` was not defined, the other to
properly `get()` the message payload when handling publishing mqtt
messages sent via websocket.
2021-05-23 00:28:15 +02:00
2023-04-30 20:32:36 +02:00
def runtime_config ( self , plus_api : PlusApi = None ) - > FrigateConfig :
2021-06-24 07:45:27 +02:00
""" Merge camera config with globals. """
2024-03-01 00:10:13 +01:00
config = self . model_copy ( deep = True )
2021-06-24 22:53:01 +02:00
2024-06-15 01:02:13 +02:00
# Proxy secret substitution
if config . proxy . auth_secret :
config . proxy . auth_secret = config . proxy . auth_secret . format (
* * FRIGATE_ENV_VARS
)
2023-01-08 00:10:48 +01:00
# MQTT user/password substitutions
if config . mqtt . user or config . mqtt . password :
config . mqtt . user = config . mqtt . user . format ( * * FRIGATE_ENV_VARS )
2021-06-24 22:53:01 +02:00
config . mqtt . password = config . mqtt . password . format ( * * FRIGATE_ENV_VARS )
2024-09-10 19:24:44 +02:00
# set notifications state
config . notifications . enabled_in_config = config . notifications . enabled
2024-06-21 23:30:19 +02:00
# GenAI substitution
if config . genai . api_key :
config . genai . api_key = config . genai . api_key . format ( * * FRIGATE_ENV_VARS )
2023-09-30 14:38:15 +02:00
# set default min_score for object attributes
for attribute in ALL_ATTRIBUTE_LABELS :
if not config . objects . filters . get ( attribute ) :
config . objects . filters [ attribute ] = FilterConfig ( min_score = 0.7 )
elif config . objects . filters [ attribute ] . min_score == 0.5 :
config . objects . filters [ attribute ] . min_score = 0.7
2024-01-01 16:36:40 +01:00
# auto detect hwaccel args
if config . ffmpeg . hwaccel_args == " auto " :
config . ffmpeg . hwaccel_args = auto_detect_hwaccel ( )
2022-11-02 12:41:44 +01:00
# Global config to propagate down to camera level
2024-03-01 00:10:13 +01:00
global_config = config . model_dump (
2021-06-24 07:45:27 +02:00
include = {
2023-07-01 15:18:33 +02:00
" audio " : . . . ,
2022-04-15 13:59:30 +02:00
" birdseye " : . . . ,
2021-06-24 07:45:27 +02:00
" record " : . . . ,
" snapshots " : . . . ,
2023-01-17 00:50:35 +01:00
" live " : . . . ,
2021-06-24 07:45:27 +02:00
" objects " : . . . ,
2024-04-13 14:08:20 +02:00
" review " : . . . ,
2024-09-16 16:46:11 +02:00
" genai " : . . . ,
2021-06-24 07:45:27 +02:00
" motion " : . . . ,
" detect " : . . . ,
" ffmpeg " : . . . ,
2021-09-03 14:03:36 +02:00
" timestamp_style " : . . . ,
2021-06-24 07:45:27 +02:00
} ,
exclude_unset = True ,
)
Use dataclasses for config handling
Use config data classes to eliminate some of the boilerplate associated
with setting up the configuration. In particular, using dataclasses
removes a lot of the boilerplate around assigning properties to the
object and allows these to be easily immutable by freezing them. In the
case of simple, non-nested dataclasses, this also provides more
convenient `asdict` helpers.
To set this up, where previously the objects would be parsed from the
config via the `__init__` method, create a `build` classmethod that does
this and calls the dataclass initializer.
Some of the objects are mutated at runtime, in particular some of the
zones are mutated to set the color (this might be able to be refactored
out) and some of the camera functionality can be enabled/disabled. Some
of the configs with `enabled` properties don't seem to have mqtt hooks
to be able to toggle this, in particular, the clips, snapshots, and
detect can be toggled but rtmp and record configs do not, but all of
these configs are still not frozen in case there is some other
functionality I am missing.
There are a couple other minor fixes here, one that was introduced
by me recently where `max_seconds` was not defined, the other to
properly `get()` the message payload when handling publishing mqtt
messages sent via websocket.
2021-05-23 00:28:15 +02:00
2021-06-24 07:45:27 +02:00
for name , camera in config . cameras . items ( ) :
2024-03-01 00:10:13 +01:00
merged_config = deep_merge (
2024-04-17 14:02:59 +02:00
camera . model_dump ( exclude_unset = True ) , global_config
2024-03-01 00:10:13 +01:00
)
camera_config : CameraConfig = CameraConfig . model_validate (
2021-07-09 22:14:16 +02:00
{ " name " : name , * * merged_config }
)
2021-06-24 07:45:27 +02:00
2024-02-01 13:44:10 +01:00
if camera_config . ffmpeg . hwaccel_args == " auto " :
camera_config . ffmpeg . hwaccel_args = config . ffmpeg . hwaccel_args
2024-02-28 04:41:36 +01:00
for input in camera_config . ffmpeg . inputs :
2024-03-05 15:11:08 +01:00
need_record_fourcc = False and " record " in input . roles
2024-02-28 04:41:36 +01:00
need_detect_dimensions = " detect " in input . roles and (
camera_config . detect . height is None
or camera_config . detect . width is None
)
if need_detect_dimensions or need_record_fourcc :
stream_info = { " width " : 0 , " height " : 0 , " fourcc " : None }
try :
2024-09-13 22:14:51 +02:00
stream_info = stream_info_retriever . get_stream_info (
config . ffmpeg , input . path
)
2024-02-28 04:41:36 +01:00
except Exception :
logger . warn (
f " Error detecting stream parameters automatically for { input . path } Applying default values. "
2023-07-14 13:56:03 +02:00
)
2024-02-28 04:41:36 +01:00
stream_info = { " width " : 0 , " height " : 0 , " fourcc " : None }
if need_detect_dimensions :
camera_config . detect . width = (
stream_info [ " width " ]
if stream_info . get ( " width " )
else DEFAULT_DETECT_DIMENSIONS [ " width " ]
)
camera_config . detect . height = (
stream_info [ " height " ]
if stream_info . get ( " height " )
else DEFAULT_DETECT_DIMENSIONS [ " height " ]
)
if need_record_fourcc :
# Apple only supports HEVC if it is hvc1 (vs. hev1)
camera_config . ffmpeg . output_args . _force_record_hvc1 = (
stream_info [ " fourcc " ] == " hevc "
if stream_info . get ( " hevc " )
else False
)
2023-07-14 13:56:03 +02:00
2024-05-20 05:36:41 +02:00
# Warn if detect fps > 10
if camera_config . detect . fps > 10 :
logger . warning (
f " { camera_config . name } detect fps is set to { camera_config . detect . fps } . This does NOT need to match your camera ' s frame rate. High values could lead to reduced performance. Recommended value is 5. "
)
2023-10-31 01:26:31 +01:00
# Default min_initialized configuration
2024-03-01 00:10:13 +01:00
min_initialized = int ( camera_config . detect . fps / 2 )
2023-10-31 01:26:31 +01:00
if camera_config . detect . min_initialized is None :
camera_config . detect . min_initialized = min_initialized
2021-08-28 16:14:00 +02:00
# Default max_disappeared configuration
2021-08-28 15:51:29 +02:00
max_disappeared = camera_config . detect . fps * 5
if camera_config . detect . max_disappeared is None :
camera_config . detect . max_disappeared = max_disappeared
2022-02-11 14:12:51 +01:00
# Default stationary_threshold configuration
2022-02-11 14:30:47 +01:00
stationary_threshold = camera_config . detect . fps * 10
2022-02-13 15:58:44 +01:00
if camera_config . detect . stationary . threshold is None :
camera_config . detect . stationary . threshold = stationary_threshold
2023-06-16 14:32:43 +02:00
# default to the stationary_threshold if not defined
if camera_config . detect . stationary . interval is None :
camera_config . detect . stationary . interval = stationary_threshold
2022-02-11 14:12:51 +01:00
2021-06-24 22:53:01 +02:00
# FFMPEG input substitution
for input in camera_config . ffmpeg . inputs :
input . path = input . path . format ( * * FRIGATE_ENV_VARS )
2023-04-26 13:08:53 +02:00
# ONVIF substitution
if camera_config . onvif . user or camera_config . onvif . password :
camera_config . onvif . user = camera_config . onvif . user . format (
* * FRIGATE_ENV_VARS
)
camera_config . onvif . password = camera_config . onvif . password . format (
* * FRIGATE_ENV_VARS
)
2023-07-01 15:18:33 +02:00
# set config pre-value
camera_config . audio . enabled_in_config = camera_config . audio . enabled
2024-02-19 14:26:59 +01:00
camera_config . record . enabled_in_config = camera_config . record . enabled
2023-11-16 02:25:48 +01:00
camera_config . onvif . autotracking . enabled_in_config = (
camera_config . onvif . autotracking . enabled
)
2023-04-26 13:08:53 +02:00
2021-06-24 07:45:27 +02:00
# Add default filters
object_keys = camera_config . objects . track
if camera_config . objects . filters is None :
camera_config . objects . filters = { }
object_keys = object_keys - camera_config . objects . filters . keys ( )
for key in object_keys :
camera_config . objects . filters [ key ] = FilterConfig ( )
# Apply global object masks and convert masks to numpy array
for object , filter in camera_config . objects . filters . items ( ) :
if camera_config . objects . mask :
filter_mask = [ ]
if filter . mask is not None :
filter_mask = (
filter . mask
if isinstance ( filter . mask , list )
else [ filter . mask ]
)
object_mask = (
2024-04-18 18:35:16 +02:00
get_relative_coordinates (
(
camera_config . objects . mask
if isinstance ( camera_config . objects . mask , list )
else [ camera_config . objects . mask ]
) ,
camera_config . frame_shape ,
)
or [ ]
2021-06-24 07:45:27 +02:00
)
filter . mask = filter_mask + object_mask
# Set runtime filter to create masks
camera_config . objects . filters [ object ] = RuntimeFilterConfig (
frame_shape = camera_config . frame_shape ,
2024-04-17 14:02:59 +02:00
* * filter . model_dump ( exclude_unset = True ) ,
2021-06-24 07:45:27 +02:00
)
Use dataclasses for config handling
Use config data classes to eliminate some of the boilerplate associated
with setting up the configuration. In particular, using dataclasses
removes a lot of the boilerplate around assigning properties to the
object and allows these to be easily immutable by freezing them. In the
case of simple, non-nested dataclasses, this also provides more
convenient `asdict` helpers.
To set this up, where previously the objects would be parsed from the
config via the `__init__` method, create a `build` classmethod that does
this and calls the dataclass initializer.
Some of the objects are mutated at runtime, in particular some of the
zones are mutated to set the color (this might be able to be refactored
out) and some of the camera functionality can be enabled/disabled. Some
of the configs with `enabled` properties don't seem to have mqtt hooks
to be able to toggle this, in particular, the clips, snapshots, and
detect can be toggled but rtmp and record configs do not, but all of
these configs are still not frozen in case there is some other
functionality I am missing.
There are a couple other minor fixes here, one that was introduced
by me recently where `max_seconds` was not defined, the other to
properly `get()` the message payload when handling publishing mqtt
messages sent via websocket.
2021-05-23 00:28:15 +02:00
2021-06-24 07:45:27 +02:00
# Convert motion configuration
if camera_config . motion is None :
camera_config . motion = RuntimeMotionConfig (
frame_shape = camera_config . frame_shape
)
else :
camera_config . motion = RuntimeMotionConfig (
frame_shape = camera_config . frame_shape ,
raw_mask = camera_config . motion . mask ,
2024-04-17 14:02:59 +02:00
* * camera_config . motion . model_dump ( exclude_unset = True ) ,
2021-06-24 07:45:27 +02:00
)
2024-02-19 14:26:59 +01:00
camera_config . motion . enabled_in_config = camera_config . motion . enabled
Use dataclasses for config handling
Use config data classes to eliminate some of the boilerplate associated
with setting up the configuration. In particular, using dataclasses
removes a lot of the boilerplate around assigning properties to the
object and allows these to be easily immutable by freezing them. In the
case of simple, non-nested dataclasses, this also provides more
convenient `asdict` helpers.
To set this up, where previously the objects would be parsed from the
config via the `__init__` method, create a `build` classmethod that does
this and calls the dataclass initializer.
Some of the objects are mutated at runtime, in particular some of the
zones are mutated to set the color (this might be able to be refactored
out) and some of the camera functionality can be enabled/disabled. Some
of the configs with `enabled` properties don't seem to have mqtt hooks
to be able to toggle this, in particular, the clips, snapshots, and
detect can be toggled but rtmp and record configs do not, but all of
these configs are still not frozen in case there is some other
functionality I am missing.
There are a couple other minor fixes here, one that was introduced
by me recently where `max_seconds` was not defined, the other to
properly `get()` the message payload when handling publishing mqtt
messages sent via websocket.
2021-05-23 00:28:15 +02:00
2024-04-10 00:51:38 +02:00
# generate zone contours
if len ( camera_config . zones ) > 0 :
for zone in camera_config . zones . values ( ) :
zone . generate_contour ( camera_config . frame_shape )
2023-01-17 00:50:35 +01:00
# Set live view stream if none is set
if not camera_config . live . stream_name :
camera_config . live . stream_name = name
2022-11-09 02:47:45 +01:00
verify_config_roles ( camera_config )
2023-01-17 00:50:35 +01:00
verify_valid_live_stream_name ( config , camera_config )
2022-11-09 02:47:45 +01:00
verify_recording_retention ( camera_config )
2022-12-09 04:03:54 +01:00
verify_recording_segments_setup_with_reasonable_time ( camera_config )
2022-11-09 02:47:45 +01:00
verify_zone_objects_are_tracked ( camera_config )
2024-04-18 18:35:16 +02:00
verify_required_zones_exist ( camera_config )
2023-07-08 14:04:47 +02:00
verify_autotrack_zones ( camera_config )
2024-02-19 14:26:59 +01:00
verify_motion_and_detect ( camera_config )
2021-10-24 20:33:13 +02:00
2022-11-02 12:41:44 +01:00
# generate the ffmpeg commands
2022-01-14 14:31:25 +01:00
camera_config . create_ffmpeg_cmds ( )
2021-10-24 20:33:13 +02:00
config . cameras [ name ] = camera_config
2022-12-15 14:12:52 +01:00
2023-01-07 02:31:54 +01:00
# get list of unique enabled labels for tracking
enabled_labels = set ( config . objects . track )
for _ , camera in config . cameras . items ( ) :
enabled_labels . update ( camera . objects . track )
2023-01-07 19:05:11 +01:00
config . model . create_colormap ( sorted ( enabled_labels ) )
2023-04-30 20:32:36 +02:00
config . model . check_and_load_plus_model ( plus_api )
2023-01-07 02:31:54 +01:00
2022-12-15 14:12:52 +01:00
for key , detector in config . detectors . items ( ) :
2024-03-01 00:10:13 +01:00
adapter = TypeAdapter ( DetectorConfig )
model_dict = (
2024-05-04 17:15:03 +02:00
detector
if isinstance ( detector , dict )
else detector . model_dump ( warnings = " none " )
2024-03-01 00:10:13 +01:00
)
detector_config : DetectorConfig = adapter . validate_python ( model_dict )
2022-12-15 14:12:52 +01:00
if detector_config . model is None :
2024-05-04 17:15:03 +02:00
detector_config . model = config . model . model_copy ( )
2022-12-15 14:12:52 +01:00
else :
2024-05-04 17:15:03 +02:00
path = detector_config . model . path
detector_config . model = config . model . model_copy ( )
detector_config . model . path = path
if " path " not in model_dict or len ( model_dict . keys ( ) ) > 1 :
2022-12-15 14:12:52 +01:00
logger . warning (
" Customizing more than a detector model path is unsupported. "
)
2024-05-04 17:15:03 +02:00
2022-12-15 14:12:52 +01:00
merged_model = deep_merge (
2024-05-04 17:15:03 +02:00
detector_config . model . model_dump ( exclude_unset = True , warnings = " none " ) ,
config . model . model_dump ( exclude_unset = True , warnings = " none " ) ,
2022-12-15 14:12:52 +01:00
)
2023-04-24 14:24:28 +02:00
2023-05-29 12:31:17 +02:00
if " path " not in merged_model :
2023-04-24 14:24:28 +02:00
if detector_config . type == " cpu " :
merged_model [ " path " ] = " /cpu_model.tflite "
elif detector_config . type == " edgetpu " :
merged_model [ " path " ] = " /edgetpu_model.tflite "
2024-03-01 00:10:13 +01:00
detector_config . model = ModelConfig . model_validate ( merged_model )
2023-04-30 20:32:36 +02:00
detector_config . model . check_and_load_plus_model (
plus_api , detector_config . type
)
2023-04-24 14:24:28 +02:00
detector_config . model . compute_model_hash ( )
2022-12-15 14:12:52 +01:00
config . detectors [ key ] = detector_config
2020-11-03 15:15:58 +01:00
return config
2024-03-01 00:10:13 +01:00
@field_validator ( " cameras " )
@classmethod
2021-06-24 07:45:27 +02:00
def ensure_zones_and_cameras_have_different_names ( cls , v : Dict [ str , CameraConfig ] ) :
zones = [ zone for camera in v . values ( ) for zone in camera . zones . keys ( ) ]
for zone in zones :
if zone in v . keys ( ) :
raise ValueError ( " Zones cannot share names with cameras " )
return v
@classmethod
def parse_file ( cls , config_file ) :
2020-11-03 15:15:58 +01:00
with open ( config_file ) as f :
raw_config = f . read ( )
2021-01-09 18:26:46 +01:00
2021-12-12 16:27:05 +01:00
if config_file . endswith ( YAML_EXT ) :
2022-11-09 02:47:45 +01:00
config = load_config_with_no_duplicates ( raw_config )
2020-11-03 15:15:58 +01:00
elif config_file . endswith ( " .json " ) :
config = json . loads ( raw_config )
2021-01-09 18:26:46 +01:00
2024-03-01 00:10:13 +01:00
return cls . model_validate ( config )
2022-12-07 14:36:56 +01:00
@classmethod
def parse_raw ( cls , raw_config ) :
config = load_config_with_no_duplicates ( raw_config )
2024-03-01 00:10:13 +01:00
return cls . model_validate ( config )