mirror of
https://github.com/blakeblackshear/frigate.git
synced 2024-11-21 19:07:46 +01:00
disallow extra keys in config
This commit is contained in:
parent
8109445fdd
commit
e8eb3125a5
@ -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."
|
||||
|
@ -962,7 +962,7 @@ class TestConfig(unittest.TestCase):
|
||||
|
||||
config = {
|
||||
"mqtt": {"host": "mqtt"},
|
||||
"timestamp_style": {"position": "bl", "scale": 1.5},
|
||||
"timestamp_style": {"position": "bl"},
|
||||
"cameras": {
|
||||
"back": {
|
||||
"ffmpeg": {
|
||||
@ -981,7 +981,6 @@ class TestConfig(unittest.TestCase):
|
||||
|
||||
runtime_config = frigate_config.runtime_config
|
||||
assert runtime_config.cameras["back"].timestamp_style.position == "bl"
|
||||
assert runtime_config.cameras["back"].timestamp_style.scale == 1.5
|
||||
|
||||
def test_default_timestamp_style(self):
|
||||
|
||||
@ -1005,14 +1004,13 @@ class TestConfig(unittest.TestCase):
|
||||
|
||||
runtime_config = frigate_config.runtime_config
|
||||
assert runtime_config.cameras["back"].timestamp_style.position == "tl"
|
||||
assert runtime_config.cameras["back"].timestamp_style.scale == 1.0
|
||||
|
||||
def test_global_timestamp_style_merge(self):
|
||||
|
||||
config = {
|
||||
"mqtt": {"host": "mqtt"},
|
||||
"rtmp": {"enabled": False},
|
||||
"timestamp_style": {"position": "br", "scale": 2.0},
|
||||
"timestamp_style": {"position": "br", "thickness": 2},
|
||||
"cameras": {
|
||||
"back": {
|
||||
"ffmpeg": {
|
||||
@ -1023,7 +1021,7 @@ class TestConfig(unittest.TestCase):
|
||||
},
|
||||
]
|
||||
},
|
||||
"timestamp_style": {"position": "bl", "scale": 1.5},
|
||||
"timestamp_style": {"position": "bl", "thickness": 4},
|
||||
}
|
||||
},
|
||||
}
|
||||
@ -1032,7 +1030,7 @@ class TestConfig(unittest.TestCase):
|
||||
|
||||
runtime_config = frigate_config.runtime_config
|
||||
assert runtime_config.cameras["back"].timestamp_style.position == "bl"
|
||||
assert runtime_config.cameras["back"].timestamp_style.scale == 1.5
|
||||
assert runtime_config.cameras["back"].timestamp_style.thickness == 4
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
Loading…
Reference in New Issue
Block a user