From 0a3988ba73e6a129002d8ac7e77925e6e6da943c Mon Sep 17 00:00:00 2001 From: Nicolas Mowen Date: Mon, 26 Aug 2024 08:06:10 -0600 Subject: [PATCH] Handle migration automatically --- frigate/config.py | 2 +- frigate/events/maintainer.py | 7 +-- frigate/record/maintainer.py | 5 +- frigate/test/test_config.py | 8 +-- frigate/util/config.py | 100 ++++++++++++++++++++++++++++++++++- 5 files changed, 107 insertions(+), 15 deletions(-) diff --git a/frigate/config.py b/frigate/config.py index a6593e6ee..20433e644 100644 --- a/frigate/config.py +++ b/frigate/config.py @@ -1437,7 +1437,7 @@ class FrigateConfig(FrigateBaseModel): default_factory=TimestampStyleConfig, title="Global timestamp style configuration.", ) - version: Optional[float] = Field(default=None, title="Current config version.") + version: Optional[str] = Field(default=None, title="Current config version.") def runtime_config(self, plus_api: PlusApi = None) -> FrigateConfig: """Merge camera config with globals.""" diff --git a/frigate/events/maintainer.py b/frigate/events/maintainer.py index e83194ede..2753300ef 100644 --- a/frigate/events/maintainer.py +++ b/frigate/events/maintainer.py @@ -128,16 +128,13 @@ class EventProcessor(threading.Thread): if should_update_db(self.events_in_process[event_data["id"]], event_data): updated_db = True camera_config = self.config.cameras[camera] - event_config: EventsConfig = camera_config.record.events width = camera_config.detect.width height = camera_config.detect.height first_detector = list(self.config.detectors.values())[0] - start_time = event_data["start_time"] - event_config.pre_capture + start_time = event_data["start_time"] end_time = ( - None - if event_data["end_time"] is None - else event_data["end_time"] + event_config.post_capture + None if event_data["end_time"] is None else event_data["end_time"] ) # score of the snapshot score = ( diff --git a/frigate/record/maintainer.py b/frigate/record/maintainer.py index cf5dccc93..e06660223 100644 --- a/frigate/record/maintainer.py +++ b/frigate/record/maintainer.py @@ -268,7 +268,10 @@ class RecordingMaintainer(threading.Thread): # if it doesn't overlap with an event, go ahead and drop the segment # if it ends more than the configured pre_capture for the camera else: - pre_capture = max(record_config.alerts.pre_capture, record_config.detections.pre_capture) + pre_capture = max( + record_config.alerts.pre_capture, + record_config.detections.pre_capture, + ) camera_info = self.object_recordings_info[camera] most_recently_processed_frame_time = ( camera_info[-1][0] if len(camera_info) > 0 else 0 diff --git a/frigate/test/test_config.py b/frigate/test/test_config.py index 28851da71..7f35bf78e 100644 --- a/frigate/test/test_config.py +++ b/frigate/test/test_config.py @@ -555,9 +555,7 @@ class TestConfig(unittest.TestCase): def test_inherit_clips_retention(self): config = { "mqtt": {"host": "mqtt"}, - "record": { - "alerts": {"retain": {"days": 20 }} - }, + "record": {"alerts": {"retain": {"days": 20}}}, "cameras": { "back": { "ffmpeg": { @@ -577,9 +575,7 @@ class TestConfig(unittest.TestCase): assert config == frigate_config.model_dump(exclude_unset=True) runtime_config = frigate_config.runtime_config() - assert ( - runtime_config.cameras["back"].record.alerts.retain.days == 20 - ) + assert runtime_config.cameras["back"].record.alerts.retain.days == 20 def test_roles_listed_twice_throws_error(self): config = { diff --git a/frigate/util/config.py b/frigate/util/config.py index 11524b871..24c533aa6 100644 --- a/frigate/util/config.py +++ b/frigate/util/config.py @@ -56,7 +56,11 @@ def migrate_frigate_config(config_file: str): ) if previous_version < "0.14.1-0": - logger.info(f"Migrating frigate config from {previous_version} to 0.14...") + logger.info(f"Migrating frigate config from {previous_version} to 0.14.1-0...") + new_config = migrate_0141_0(config) + with open(config_file, "w") as f: + yaml.dump(new_config, f) + previous_version = "0.14.1-0" logger.info("Finished frigate config migration...") @@ -144,7 +148,99 @@ def migrate_014(config: dict[str, dict[str, any]]) -> dict[str, dict[str, any]]: new_config["cameras"][name] = camera_config - new_config["version"] = 0.14 + new_config["version"] = "0.14" + return new_config + + +def migrate_0141_0(config: dict[str, dict[str, any]]) -> dict[str, dict[str, any]]: + """Handle migrating frigate config to 0.14.1-0""" + new_config = config.copy() + + # migrate record.events to record.alerts and record.detections + global_record_events = config.get("record", {}).get("events") + if global_record_events: + alerts_retention = {"retain": {}} + detections_retention = {"retain": {}} + + if global_record_events["pre_capture"]: + alerts_retention["pre_capture"] = global_record_events["pre_capture"] + + if global_record_events["post_capture"]: + alerts_retention["post_capture"] = global_record_events["post_capture"] + + if global_record_events["retain"]["default"]: + alerts_retention["retain"]["days"] = global_record_events["retain"][ + "default" + ] + + # decide logical detections retention based on current detections config + if not config.get("review", {}).get("alerts", {}).get( + "required_zones" + ) or config.get("review", {}).get("detections"): + if global_record_events["pre_capture"]: + detections_retention["pre_capture"] = global_record_events[ + "pre_capture" + ] + + if global_record_events["post_capture"]: + detections_retention["post_capture"] = global_record_events[ + "post_capture" + ] + + if global_record_events["retain"]["default"]: + detections_retention["retain"]["days"] = global_record_events["retain"][ + "default" + ] + else: + detections_retention["retain"]["days"] = 0 + + new_config["record"]["alerts"] = alerts_retention + new_config["record"]["detections"] = detections_retention + + del new_config["record"]["events"] + + for name, camera in config.get("cameras", {}).items(): + camera_config: dict[str, dict[str, any]] = camera.copy() + + record_events = camera_config.get("record", {}).get("events") + if record_events: + alerts_retention = {"retain": {}} + detections_retention = {"retain": {}} + + if record_events["pre_capture"]: + alerts_retention["pre_capture"] = record_events["pre_capture"] + + if record_events["post_capture"]: + alerts_retention["post_capture"] = record_events["post_capture"] + + if record_events["retain"]["default"]: + alerts_retention["retain"]["days"] = record_events["retain"]["default"] + + # decide logical detections retention based on current detections config + if not camera_config.get("review", {}).get("alerts", {}).get( + "required_zones" + ) or camera_config.get("review", {}).get("detections"): + if record_events["pre_capture"]: + detections_retention["pre_capture"] = record_events["pre_capture"] + + if record_events["post_capture"]: + detections_retention["post_capture"] = record_events["post_capture"] + + if record_events["retain"]["default"]: + detections_retention["retain"]["days"] = record_events["retain"][ + "default" + ] + else: + detections_retention["retain"]["days"] = 0 + + new_config["record"]["alerts"] = alerts_retention + new_config["record"]["detections"] = detections_retention + + del new_config["record"]["events"] + + new_config["cameras"][name] = camera_config + + new_config["version"] = "0.14.1-0" return new_config