diff --git a/frigate/config.py b/frigate/config.py index 986ba1241..d464bb970 100644 --- a/frigate/config.py +++ b/frigate/config.py @@ -794,6 +794,21 @@ class FrigateConfig(FrigateBaseModel): config.cameras[name] = camera_config + # check runtime config + for name, camera in config.cameras.items(): + assigned_roles = list( + set([r for i in camera.ffmpeg.inputs for r in i.roles]) + ) + if camera.record.enabled and not "record" in assigned_roles: + raise ValueError( + f"Camera {name} has record enabled, but record is not assigned to an input." + ) + + if camera.rtmp.enabled and not "rtmp" in assigned_roles: + raise ValueError( + f"Camera {name} has rtmp enabled, but rtmp is not assigned to an input." + ) + return config @validator("cameras") @@ -804,23 +819,6 @@ class FrigateConfig(FrigateBaseModel): raise ValueError("Zones cannot share names with cameras") return v - @validator("cameras") - def ensure_cameras_are_not_missing_roles(cls, v: Dict[str, CameraConfig]): - for name, camera in v.items(): - assigned_roles = list( - set([r for i in camera.ffmpeg.inputs for r in i.roles]) - ) - if camera.record.enabled and not "record" in assigned_roles: - raise ValueError( - f"Camera {name} has record enabled, but record is not assigned to an input." - ) - - if camera.rtmp.enabled and not "rtmp" in assigned_roles: - raise ValueError( - f"Camera {name} has rtmp enabled, but rtmp is not assigned to an input." - ) - return v - @classmethod def parse_file(cls, config_file): with open(config_file) as f: diff --git a/frigate/test/test_config.py b/frigate/test/test_config.py index 523291cf8..92b30d542 100644 --- a/frigate/test/test_config.py +++ b/frigate/test/test_config.py @@ -702,7 +702,11 @@ class TestConfig(unittest.TestCase): "inputs": [ { "path": "rtsp://10.0.0.1:554/video", - "roles": ["detect", "clips"], + "roles": ["detect"], + }, + { + "path": "rtsp://10.0.0.1:554/video2", + "roles": ["clips"], }, ] }, @@ -717,6 +721,37 @@ class TestConfig(unittest.TestCase): self.assertRaises(ValidationError, lambda: FrigateConfig(**config)) + def test_fails_on_missing_role(self): + + config = { + "mqtt": {"host": "mqtt"}, + "cameras": { + "back": { + "ffmpeg": { + "inputs": [ + { + "path": "rtsp://10.0.0.1:554/video", + "roles": ["detect"], + }, + { + "path": "rtsp://10.0.0.1:554/video2", + "roles": ["record"], + }, + ] + }, + "detect": { + "height": 1080, + "width": 1920, + "fps": 5, + }, + "rtmp": {"enabled": True}, + } + }, + } + + frigate_config = FrigateConfig(**config) + self.assertRaises(ValueError, lambda: frigate_config.runtime_config) + def test_global_detect(self): config = { @@ -958,6 +993,34 @@ class TestConfig(unittest.TestCase): runtime_config = frigate_config.runtime_config assert runtime_config.cameras["back"].rtmp.enabled + def test_global_rtmp_default(self): + + config = { + "mqtt": {"host": "mqtt"}, + "rtmp": {"enabled": False}, + "cameras": { + "back": { + "ffmpeg": { + "inputs": [ + { + "path": "rtsp://10.0.0.1:554/video", + "roles": ["detect"], + }, + { + "path": "rtsp://10.0.0.1:554/video2", + "roles": ["record"], + }, + ] + }, + } + }, + } + frigate_config = FrigateConfig(**config) + assert config == frigate_config.dict(exclude_unset=True) + + runtime_config = frigate_config.runtime_config + assert not runtime_config.cameras["back"].rtmp.enabled + def test_global_live(self): config = {