From f14777723b34b665ca22815c152e3b9ec809bdb3 Mon Sep 17 00:00:00 2001 From: George Tsiamasiotis Date: Mon, 23 Sep 2024 09:56:18 +0300 Subject: [PATCH] Moved FrigateApp.init_config() into FrigateConfig.load() --- frigate/app.py | 43 +++++++++--------------------- frigate/config.py | 59 ++++++++++++++++++++++++++++++++++++++--- frigate/util/builtin.py | 31 ---------------------- 3 files changed, 68 insertions(+), 65 deletions(-) diff --git a/frigate/app.py b/frigate/app.py index f6479d9ad..94cc3c112 100644 --- a/frigate/app.py +++ b/frigate/app.py @@ -7,7 +7,6 @@ import secrets import shutil import signal import sys -import traceback from multiprocessing import Queue from multiprocessing.synchronize import Event as MpEvent from types import FrameType @@ -70,8 +69,7 @@ from frigate.stats.util import stats_init from frigate.storage import StorageMaintainer from frigate.timeline import TimelineProcessor from frigate.types import CameraMetricsTypes, PTZMetricsTypes -from frigate.util.builtin import empty_and_close_queue, save_default_config -from frigate.util.config import migrate_frigate_config +from frigate.util.builtin import empty_and_close_queue from frigate.util.object import get_camera_regions_grid from frigate.version import VERSION from frigate.video import capture_camera, track_camera @@ -113,24 +111,7 @@ class FrigateApp: else: logger.debug(f"Skipping directory: {d}") - def init_config(self) -> None: - config_file = os.environ.get("CONFIG_FILE", "/config/config.yml") - - # Check if we can use .yaml instead of .yml - config_file_yaml = config_file.replace(".yml", ".yaml") - if os.path.isfile(config_file_yaml): - config_file = config_file_yaml - - if not os.path.isfile(config_file): - print("No config file found, saving default config") - config_file = config_file_yaml - save_default_config(config_file) - - # check if the config file needs to be migrated - migrate_frigate_config(config_file) - - self.config = FrigateConfig.parse_file(config_file, plus_api=self.plus_api) - + def init_camera_metrics(self) -> None: for camera_name in self.config.cameras.keys(): # create camera_metrics self.camera_metrics[camera_name] = { @@ -671,24 +652,20 @@ class FrigateApp: try: self.ensure_dirs() try: - self.init_config() - except Exception as e: + self.config = FrigateConfig.load(plus_api=self.plus_api) + except ValidationError as e: print("*************************************************************") print("*************************************************************") print("*** Your config file is not valid! ***") print("*** Please check the docs at ***") - print("*** https://docs.frigate.video/configuration/index ***") + print("*** https://docs.frigate.video/configuration/ ***") print("*************************************************************") print("*************************************************************") print("*** Config Validation Errors ***") print("*************************************************************") - if isinstance(e, ValidationError): - for error in e.errors(): - location = ".".join(str(item) for item in error["loc"]) - print(f"{location}: {error['msg']}") - else: - print(e) - print(traceback.format_exc()) + for error in e.errors(): + location = ".".join(str(item) for item in error["loc"]) + print(f"{location}: {error['msg']}") print("*************************************************************") print("*** End Config Validation Errors ***") print("*************************************************************") @@ -698,6 +675,8 @@ class FrigateApp: print("*** Your config file is valid. ***") print("*************************************************************") sys.exit(0) + + self.init_camera_metrics() self.set_environment_vars() self.set_log_levels() self.init_queues() @@ -711,9 +690,11 @@ class FrigateApp: self.check_db_data_migrations() self.init_inter_process_communicator() self.init_dispatcher() + except Exception as e: print(e) sys.exit(1) + self.start_detectors() self.start_video_output_processor() self.start_ptz_autotracker() diff --git a/frigate/config.py b/frigate/config.py index e9ffde35a..8b663f5b7 100644 --- a/frigate/config.py +++ b/frigate/config.py @@ -51,7 +51,11 @@ from frigate.util.builtin import ( generate_color_palette, get_ffmpeg_arg_list, ) -from frigate.util.config import StreamInfoRetriever, get_relative_coordinates +from frigate.util.config import ( + StreamInfoRetriever, + get_relative_coordinates, + migrate_frigate_config, +) from frigate.util.image import create_mask from frigate.util.services import auto_detect_hwaccel @@ -59,6 +63,25 @@ logger = logging.getLogger(__name__) yaml = YAML() +DEFAULT_CONFIG_FILES = ["/config/config.yaml", "/config/config.yml"] +DEFAULT_CONFIG = """ +mqtt: + enabled: False + +cameras: + name_of_your_camera: # <------ Name the camera + enabled: True + ffmpeg: + inputs: + - path: rtsp://10.0.10.10:554/rtsp # <----- The stream you want to use for detection + roles: + - detect + detect: + enabled: False # <---- disable detection until you have a working camera feed + width: 1280 + height: 720 +""" + # TODO: Identify what the default format to display timestamps is DEFAULT_TIME_FORMAT = "%m/%d/%Y %H:%M:%S" # German Style: @@ -1743,8 +1766,38 @@ class FrigateConfig(FrigateBaseModel): return v @classmethod - def parse_file(cls, config_path, **kwargs): - with open(config_path) as f: + def load(cls, **kwargs): + config_path = os.environ.get("CONFIG_FILE") + + # No explicit configuration file, try to find one in the default paths. + if config_path is None: + for path in DEFAULT_CONFIG_FILES: + if os.path.isfile(path): + config_path = path + break + + # No configuration file found, create one. + new_config = False + if config_path is None: + logger.info("No config file found, saving default config") + config_path = DEFAULT_CONFIG_FILES[-1] + new_config = True + else: + # Check if the config file needs to be migrated. + migrate_frigate_config(config_path) + + # Finally, load the resulting configuration file. + with open(config_path, "a+") as f: + # Only write the default config if the opened file is non-empty. This can happen as + # a race condition. It's extremely unlikely, but eh. Might as well check it. + if new_config and f.tell() == 0: + f.write(DEFAULT_CONFIG) + logger.info( + "Created default config file, see the getting started docs \ + for configuration https://docs.frigate.video/guides/getting_started" + ) + + f.seek(0) return FrigateConfig.parse(f, **kwargs) @classmethod diff --git a/frigate/util/builtin.py b/frigate/util/builtin.py index e50882e10..164c34091 100644 --- a/frigate/util/builtin.py +++ b/frigate/util/builtin.py @@ -258,37 +258,6 @@ def find_by_key(dictionary, target_key): return None -def save_default_config(location: str) -> None: - try: - with open(location, "w") as f: - f.write( - """ -mqtt: - enabled: False - -cameras: - name_of_your_camera: # <------ Name the camera - enabled: True - ffmpeg: - inputs: - - path: rtsp://10.0.10.10:554/rtsp # <----- The stream you want to use for detection - roles: - - detect - detect: - enabled: False # <---- disable detection until you have a working camera feed - width: 1280 - height: 720 - """ - ) - except PermissionError: - logger.error("Unable to write default config to /config") - return - - logger.info( - "Created default config file, see the getting started docs for configuration https://docs.frigate.video/guides/getting_started" - ) - - def get_tomorrow_at_time(hour: int) -> datetime.datetime: """Returns the datetime of the following day at 2am.""" try: