|  | @@ -9,7 +9,7 @@ from typing import Dict, List, Optional, Tuple, Union
 | 
	
		
			
				|  |  |  import matplotlib.pyplot as plt
 | 
	
		
			
				|  |  |  import numpy as np
 | 
	
		
			
				|  |  |  import yaml
 | 
	
		
			
				|  |  | -from pydantic import BaseModel, Field, validator
 | 
	
		
			
				|  |  | +from pydantic import BaseModel, Extra, Field, validator
 | 
	
		
			
				|  |  |  from pydantic.fields import PrivateAttr
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  from frigate.const import BASE_DIR, CACHE_DIR, RECORD_DIR
 | 
	
	
		
			
				|  | @@ -29,18 +29,23 @@ DEFAULT_TRACKED_OBJECTS = ["person"]
 | 
	
		
			
				|  |  |  DEFAULT_DETECTORS = {"cpu": {"type": "cpu"}}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +class FrigateBaseModel(BaseModel):
 | 
	
		
			
				|  |  | +    class Config:
 | 
	
		
			
				|  |  | +        extra = Extra.forbid
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  class DetectorTypeEnum(str, Enum):
 | 
	
		
			
				|  |  |      edgetpu = "edgetpu"
 | 
	
		
			
				|  |  |      cpu = "cpu"
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -class DetectorConfig(BaseModel):
 | 
	
		
			
				|  |  | +class DetectorConfig(FrigateBaseModel):
 | 
	
		
			
				|  |  |      type: DetectorTypeEnum = Field(default=DetectorTypeEnum.cpu, title="Detector Type")
 | 
	
		
			
				|  |  |      device: str = Field(default="usb", title="Device Type")
 | 
	
		
			
				|  |  |      num_threads: int = Field(default=3, title="Number of detection threads")
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -class MqttConfig(BaseModel):
 | 
	
		
			
				|  |  | +class MqttConfig(FrigateBaseModel):
 | 
	
		
			
				|  |  |      host: str = Field(title="MQTT Host")
 | 
	
		
			
				|  |  |      port: int = Field(default=1883, title="MQTT Port")
 | 
	
		
			
				|  |  |      topic_prefix: str = Field(default="frigate", title="MQTT Topic Prefix")
 | 
	
	
		
			
				|  | @@ -60,7 +65,7 @@ class MqttConfig(BaseModel):
 | 
	
		
			
				|  |  |          return v
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -class RetainConfig(BaseModel):
 | 
	
		
			
				|  |  | +class RetainConfig(FrigateBaseModel):
 | 
	
		
			
				|  |  |      default: int = Field(default=10, title="Default retention period.")
 | 
	
		
			
				|  |  |      objects: Dict[str, int] = Field(
 | 
	
		
			
				|  |  |          default_factory=dict, title="Object retention period."
 | 
	
	
		
			
				|  | @@ -68,7 +73,7 @@ class RetainConfig(BaseModel):
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  # DEPRECATED: Will eventually be removed
 | 
	
		
			
				|  |  | -class ClipsConfig(BaseModel):
 | 
	
		
			
				|  |  | +class ClipsConfig(FrigateBaseModel):
 | 
	
		
			
				|  |  |      enabled: bool = Field(default=False, title="Save clips.")
 | 
	
		
			
				|  |  |      max_seconds: int = Field(default=300, title="Maximum clip duration.")
 | 
	
		
			
				|  |  |      pre_capture: int = Field(default=5, title="Seconds to capture before event starts.")
 | 
	
	
		
			
				|  | @@ -85,7 +90,7 @@ class ClipsConfig(BaseModel):
 | 
	
		
			
				|  |  |      )
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -class RecordConfig(BaseModel):
 | 
	
		
			
				|  |  | +class RecordConfig(FrigateBaseModel):
 | 
	
		
			
				|  |  |      enabled: bool = Field(default=False, title="Enable record on all cameras.")
 | 
	
		
			
				|  |  |      retain_days: int = Field(default=0, title="Recording retention period in days.")
 | 
	
		
			
				|  |  |      events: ClipsConfig = Field(
 | 
	
	
		
			
				|  | @@ -93,7 +98,7 @@ class RecordConfig(BaseModel):
 | 
	
		
			
				|  |  |      )
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -class MotionConfig(BaseModel):
 | 
	
		
			
				|  |  | +class MotionConfig(FrigateBaseModel):
 | 
	
		
			
				|  |  |      threshold: int = Field(
 | 
	
		
			
				|  |  |          default=25,
 | 
	
		
			
				|  |  |          title="Motion detection threshold (1-255).",
 | 
	
	
		
			
				|  | @@ -146,9 +151,10 @@ class RuntimeMotionConfig(MotionConfig):
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      class Config:
 | 
	
		
			
				|  |  |          arbitrary_types_allowed = True
 | 
	
		
			
				|  |  | +        extra = Extra.ignore
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -class DetectConfig(BaseModel):
 | 
	
		
			
				|  |  | +class DetectConfig(FrigateBaseModel):
 | 
	
		
			
				|  |  |      height: int = Field(default=720, title="Height of the stream for the detect role.")
 | 
	
		
			
				|  |  |      width: int = Field(default=1280, title="Width of the stream for the detect role.")
 | 
	
		
			
				|  |  |      fps: int = Field(
 | 
	
	
		
			
				|  | @@ -160,7 +166,7 @@ class DetectConfig(BaseModel):
 | 
	
		
			
				|  |  |      )
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -class FilterConfig(BaseModel):
 | 
	
		
			
				|  |  | +class FilterConfig(FrigateBaseModel):
 | 
	
		
			
				|  |  |      min_area: int = Field(
 | 
	
		
			
				|  |  |          default=0, title="Minimum area of bounding box for object to be counted."
 | 
	
		
			
				|  |  |      )
 | 
	
	
		
			
				|  | @@ -201,8 +207,10 @@ class RuntimeFilterConfig(FilterConfig):
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      class Config:
 | 
	
		
			
				|  |  |          arbitrary_types_allowed = True
 | 
	
		
			
				|  |  | +        extra = Extra.ignore
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +# this uses the base model because the color is an extra attribute
 | 
	
		
			
				|  |  |  class ZoneConfig(BaseModel):
 | 
	
		
			
				|  |  |      filters: Dict[str, FilterConfig] = Field(
 | 
	
		
			
				|  |  |          default_factory=dict, title="Zone filters."
 | 
	
	
		
			
				|  | @@ -244,7 +252,7 @@ class ZoneConfig(BaseModel):
 | 
	
		
			
				|  |  |              self._contour = np.array([])
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -class ObjectConfig(BaseModel):
 | 
	
		
			
				|  |  | +class ObjectConfig(FrigateBaseModel):
 | 
	
		
			
				|  |  |      track: List[str] = Field(default=DEFAULT_TRACKED_OBJECTS, title="Objects to track.")
 | 
	
		
			
				|  |  |      filters: Optional[Dict[str, FilterConfig]] = Field(title="Object filters.")
 | 
	
		
			
				|  |  |      mask: Union[str, List[str]] = Field(default="", title="Object mask.")
 | 
	
	
		
			
				|  | @@ -256,7 +264,7 @@ class BirdseyeModeEnum(str, Enum):
 | 
	
		
			
				|  |  |      continuous = "continuous"
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -class BirdseyeConfig(BaseModel):
 | 
	
		
			
				|  |  | +class BirdseyeConfig(FrigateBaseModel):
 | 
	
		
			
				|  |  |      enabled: bool = Field(default=True, title="Enable birdseye view.")
 | 
	
		
			
				|  |  |      width: int = Field(default=1280, title="Birdseye width.")
 | 
	
		
			
				|  |  |      height: int = Field(default=720, title="Birdseye height.")
 | 
	
	
		
			
				|  | @@ -303,7 +311,7 @@ RECORD_FFMPEG_OUTPUT_ARGS_DEFAULT = [
 | 
	
		
			
				|  |  |  ]
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -class FfmpegOutputArgsConfig(BaseModel):
 | 
	
		
			
				|  |  | +class FfmpegOutputArgsConfig(FrigateBaseModel):
 | 
	
		
			
				|  |  |      detect: Union[str, List[str]] = Field(
 | 
	
		
			
				|  |  |          default=DETECT_FFMPEG_OUTPUT_ARGS_DEFAULT,
 | 
	
		
			
				|  |  |          title="Detect role FFmpeg output arguments.",
 | 
	
	
		
			
				|  | @@ -318,7 +326,7 @@ class FfmpegOutputArgsConfig(BaseModel):
 | 
	
		
			
				|  |  |      )
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -class FfmpegConfig(BaseModel):
 | 
	
		
			
				|  |  | +class FfmpegConfig(FrigateBaseModel):
 | 
	
		
			
				|  |  |      global_args: Union[str, List[str]] = Field(
 | 
	
		
			
				|  |  |          default=FFMPEG_GLOBAL_ARGS_DEFAULT, title="Global FFmpeg arguments."
 | 
	
		
			
				|  |  |      )
 | 
	
	
		
			
				|  | @@ -340,7 +348,7 @@ class CameraRoleEnum(str, Enum):
 | 
	
		
			
				|  |  |      detect = "detect"
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -class CameraInput(BaseModel):
 | 
	
		
			
				|  |  | +class CameraInput(FrigateBaseModel):
 | 
	
		
			
				|  |  |      path: str = Field(title="Camera input path.")
 | 
	
		
			
				|  |  |      roles: List[CameraRoleEnum] = Field(title="Roles assigned to this input.")
 | 
	
		
			
				|  |  |      global_args: Union[str, List[str]] = Field(
 | 
	
	
		
			
				|  | @@ -371,7 +379,7 @@ class CameraFfmpegConfig(FfmpegConfig):
 | 
	
		
			
				|  |  |          return v
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -class SnapshotsConfig(BaseModel):
 | 
	
		
			
				|  |  | +class SnapshotsConfig(FrigateBaseModel):
 | 
	
		
			
				|  |  |      enabled: bool = Field(default=False, title="Snapshots enabled.")
 | 
	
		
			
				|  |  |      clean_copy: bool = Field(
 | 
	
		
			
				|  |  |          default=True, title="Create a clean copy of the snapshot image."
 | 
	
	
		
			
				|  | @@ -399,7 +407,7 @@ class SnapshotsConfig(BaseModel):
 | 
	
		
			
				|  |  |      )
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -class ColorConfig(BaseModel):
 | 
	
		
			
				|  |  | +class ColorConfig(FrigateBaseModel):
 | 
	
		
			
				|  |  |      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")
 | 
	
	
		
			
				|  | @@ -417,7 +425,7 @@ class TimestampEffectEnum(str, Enum):
 | 
	
		
			
				|  |  |      shadow = "shadow"
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -class TimestampStyleConfig(BaseModel):
 | 
	
		
			
				|  |  | +class TimestampStyleConfig(FrigateBaseModel):
 | 
	
		
			
				|  |  |      position: TimestampPositionEnum = Field(
 | 
	
		
			
				|  |  |          default=TimestampPositionEnum.tl, title="Timestamp position."
 | 
	
		
			
				|  |  |      )
 | 
	
	
		
			
				|  | @@ -427,7 +435,7 @@ class TimestampStyleConfig(BaseModel):
 | 
	
		
			
				|  |  |      effect: Optional[TimestampEffectEnum] = Field(title="Timestamp effect.")
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -class CameraMqttConfig(BaseModel):
 | 
	
		
			
				|  |  | +class CameraMqttConfig(FrigateBaseModel):
 | 
	
		
			
				|  |  |      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.")
 | 
	
	
		
			
				|  | @@ -445,16 +453,16 @@ class CameraMqttConfig(BaseModel):
 | 
	
		
			
				|  |  |      )
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -class RtmpConfig(BaseModel):
 | 
	
		
			
				|  |  | +class RtmpConfig(FrigateBaseModel):
 | 
	
		
			
				|  |  |      enabled: bool = Field(default=True, title="RTMP restreaming enabled.")
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -class CameraLiveConfig(BaseModel):
 | 
	
		
			
				|  |  | +class CameraLiveConfig(FrigateBaseModel):
 | 
	
		
			
				|  |  |      height: int = Field(default=720, title="Live camera view height")
 | 
	
		
			
				|  |  |      quality: int = Field(default=8, ge=1, le=31, title="Live camera view quality")
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -class CameraConfig(BaseModel):
 | 
	
		
			
				|  |  | +class CameraConfig(FrigateBaseModel):
 | 
	
		
			
				|  |  |      name: Optional[str] = Field(title="Camera name.")
 | 
	
		
			
				|  |  |      ffmpeg: CameraFfmpegConfig = Field(title="FFmpeg configuration for the camera.")
 | 
	
		
			
				|  |  |      best_image_timeout: int = Field(
 | 
	
	
		
			
				|  | @@ -590,13 +598,13 @@ class CameraConfig(BaseModel):
 | 
	
		
			
				|  |  |          return [part for part in cmd if part != ""]
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -class DatabaseConfig(BaseModel):
 | 
	
		
			
				|  |  | +class DatabaseConfig(FrigateBaseModel):
 | 
	
		
			
				|  |  |      path: str = Field(
 | 
	
		
			
				|  |  |          default=os.path.join(BASE_DIR, "frigate.db"), title="Database path."
 | 
	
		
			
				|  |  |      )
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -class ModelConfig(BaseModel):
 | 
	
		
			
				|  |  | +class ModelConfig(FrigateBaseModel):
 | 
	
		
			
				|  |  |      width: int = Field(default=320, title="Object detection model input width.")
 | 
	
		
			
				|  |  |      height: int = Field(default=320, title="Object detection model input height.")
 | 
	
		
			
				|  |  |      labelmap: Dict[int, str] = Field(
 | 
	
	
		
			
				|  | @@ -636,7 +644,7 @@ class LogLevelEnum(str, Enum):
 | 
	
		
			
				|  |  |      critical = "critical"
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -class LoggerConfig(BaseModel):
 | 
	
		
			
				|  |  | +class LoggerConfig(FrigateBaseModel):
 | 
	
		
			
				|  |  |      default: LogLevelEnum = Field(
 | 
	
		
			
				|  |  |          default=LogLevelEnum.info, title="Default logging level."
 | 
	
		
			
				|  |  |      )
 | 
	
	
		
			
				|  | @@ -645,7 +653,7 @@ class LoggerConfig(BaseModel):
 | 
	
		
			
				|  |  |      )
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -class FrigateConfig(BaseModel):
 | 
	
		
			
				|  |  | +class FrigateConfig(FrigateBaseModel):
 | 
	
		
			
				|  |  |      mqtt: MqttConfig = Field(title="MQTT Configuration.")
 | 
	
		
			
				|  |  |      database: DatabaseConfig = Field(
 | 
	
		
			
				|  |  |          default_factory=DatabaseConfig, title="Database configuration."
 |