From 9bf98f908d5c5b1c9b4a91075a357d095fdae8ce Mon Sep 17 00:00:00 2001 From: Blake Blackshear Date: Sun, 30 Apr 2023 13:32:36 -0500 Subject: [PATCH] add plus integration for models (#6328) --- docs/docs/integrations/plus.md | 30 +++++++-- frigate/app.py | 15 +++-- frigate/config.py | 8 ++- frigate/const.py | 1 + frigate/detectors/detector_config.py | 44 +++++++++++++ frigate/http.py | 5 ++ frigate/plus.py | 23 ++++++- frigate/test/test_config.py | 97 ++++++++++++++-------------- frigate/test/test_http.py | 6 +- 9 files changed, 166 insertions(+), 63 deletions(-) diff --git a/docs/docs/integrations/plus.md b/docs/docs/integrations/plus.md index 4bab29ef3..7ffce4941 100644 --- a/docs/docs/integrations/plus.md +++ b/docs/docs/integrations/plus.md @@ -5,13 +5,11 @@ title: Frigate+ :::info -Frigate+ is under active development and currently only offers the ability to submit your examples with annotations. Models will be available after enough examples are submitted to train a robust model. It is free to create an account and upload your examples. +Frigate+ is under active development. Models are available as a part of an invitation only beta. It is free to create an account and upload/annotate your examples. ::: -Frigate+ offers models trained from scratch and specifically designed for the way Frigate NVR analyzes video footage. They offer higher accuracy with less resources. By uploading your own labeled examples, your model can be uniquely tuned for accuracy in your specific conditions. After tuning, performance is evaluated against a broad dataset and real world examples submitted by other Frigate+ users to prevent overfitting. - -Custom models also include a more relevant set of objects for security cameras such as person, face, car, license plate, delivery truck, package, dog, cat, deer, and more. Interested in detecting an object unique to you? Upload examples to incorporate your own objects without worrying that you are reducing the accuracy of other object types in the model. +Frigate+ offers models trained from scratch and specifically designed for the way Frigate NVR analyzes video footage. They offer higher accuracy with less resources and include a more relevant set of objects for security cameras. By uploading your own labeled examples, your model can be uniquely tuned for accuracy in your specific conditions. After tuning, performance is evaluated against a broad dataset and real world examples submitted by other Frigate+ users to prevent overfitting. ## Setup @@ -35,7 +33,7 @@ You cannot use the `environment_vars` section of your configuration file to set ::: -### Submit examples +## Submit examples Once your API key is configured, you can submit examples directly from the events page in Frigate using the `SEND TO FRIGATE+` button. @@ -52,3 +50,25 @@ Snapshots must be enabled to be able to submit examples to Frigate+ You can view all of your submitted images at [https://plus.frigate.video](https://plus.frigate.video). Annotations can be added by clicking an image. ![Annotate](/img/annotate.png) + +## Use Models + +Models available in Frigate+ can be used with a special model path. No other information needs to be configured for Frigate+ models because it fetches the remaining config from Frigate+ automatically. + +```yaml +model: + path: plus://e63b7345cc83a84ed79dedfc99c16616 +``` + +Models are downloaded into the `/config/model_cache` folder and only downloaded if needed. + +You can override the labelmap for Frigate+ models like this: + +```yaml +model: + path: plus://e63b7345cc83a84ed79dedfc99c16616 + labelmap: + 3: animal + 4: animal + 5: animal +``` diff --git a/frigate/app.py b/frigate/app.py index 095a51e36..a07a4465f 100644 --- a/frigate/app.py +++ b/frigate/app.py @@ -18,7 +18,14 @@ from frigate.comms.dispatcher import Communicator, Dispatcher from frigate.comms.mqtt import MqttClient from frigate.comms.ws import WebSocketClient from frigate.config import FrigateConfig -from frigate.const import CACHE_DIR, CLIPS_DIR, CONFIG_DIR, DEFAULT_DB_PATH, RECORD_DIR +from frigate.const import ( + CACHE_DIR, + CLIPS_DIR, + CONFIG_DIR, + DEFAULT_DB_PATH, + MODEL_CACHE_DIR, + RECORD_DIR, +) from frigate.object_detection import ObjectDetectProcess from frigate.events import EventCleanup, EventProcessor from frigate.http import create_app @@ -57,7 +64,7 @@ class FrigateApp: os.environ[key] = value def ensure_dirs(self) -> None: - for d in [CONFIG_DIR, RECORD_DIR, CLIPS_DIR, CACHE_DIR]: + for d in [CONFIG_DIR, RECORD_DIR, CLIPS_DIR, CACHE_DIR, MODEL_CACHE_DIR]: if not os.path.exists(d) and not os.path.islink(d): logger.info(f"Creating directory: {d}") os.makedirs(d) @@ -81,7 +88,7 @@ class FrigateApp: config_file = config_file_yaml user_config = FrigateConfig.parse_file(config_file) - self.config = user_config.runtime_config + self.config = user_config.runtime_config(self.plus_api) for camera_name in self.config.cameras.keys(): # create camera_metrics @@ -379,6 +386,7 @@ class FrigateApp: self.init_logger() logger.info(f"Starting Frigate ({VERSION})") try: + self.ensure_dirs() try: self.init_config() except Exception as e: @@ -399,7 +407,6 @@ class FrigateApp: self.log_process.terminate() sys.exit(1) self.set_environment_vars() - self.ensure_dirs() self.set_log_levels() self.init_queues() self.init_database() diff --git a/frigate/config.py b/frigate/config.py index 85685e8e9..dc66e7896 100644 --- a/frigate/config.py +++ b/frigate/config.py @@ -19,6 +19,7 @@ from frigate.const import ( YAML_EXT, ) from frigate.detectors.detector_config import BaseDetectorConfig +from frigate.plus import PlusApi from frigate.util import ( create_mask, deep_merge, @@ -906,8 +907,7 @@ class FrigateConfig(FrigateBaseModel): title="Global timestamp style configuration.", ) - @property - def runtime_config(self) -> FrigateConfig: + def runtime_config(self, plus_api: PlusApi = None) -> FrigateConfig: """Merge camera config with globals.""" config = self.copy(deep=True) @@ -1031,6 +1031,7 @@ class FrigateConfig(FrigateBaseModel): enabled_labels.update(camera.objects.track) config.model.create_colormap(sorted(enabled_labels)) + config.model.check_and_load_plus_model(plus_api) for key, detector in config.detectors.items(): detector_config: DetectorConfig = parse_obj_as(DetectorConfig, detector) @@ -1063,6 +1064,9 @@ class FrigateConfig(FrigateBaseModel): merged_model["path"] = "/edgetpu_model.tflite" detector_config.model = ModelConfig.parse_obj(merged_model) + detector_config.model.check_and_load_plus_model( + plus_api, detector_config.type + ) detector_config.model.compute_model_hash() config.detectors[key] = detector_config diff --git a/frigate/const.py b/frigate/const.py index 8e1e42bb9..cfcdc2a53 100644 --- a/frigate/const.py +++ b/frigate/const.py @@ -1,5 +1,6 @@ CONFIG_DIR = "/config" DEFAULT_DB_PATH = f"{CONFIG_DIR}/frigate.db" +MODEL_CACHE_DIR = f"{CONFIG_DIR}/model_cache" BASE_DIR = "/media/frigate" CLIPS_DIR = f"{BASE_DIR}/clips" RECORD_DIR = f"{BASE_DIR}/recordings" diff --git a/frigate/detectors/detector_config.py b/frigate/detectors/detector_config.py index 46f92e6ab..16ffe5fd4 100644 --- a/frigate/detectors/detector_config.py +++ b/frigate/detectors/detector_config.py @@ -1,11 +1,16 @@ import hashlib +import json import logging from enum import Enum +import os from typing import Dict, List, Optional, Tuple, Union, Literal + +import requests import matplotlib.pyplot as plt from pydantic import BaseModel, Extra, Field, validator from pydantic.fields import PrivateAttr +from frigate.plus import PlusApi from frigate.util import load_labels @@ -73,6 +78,45 @@ class ModelConfig(BaseModel): } self._colormap = {} + def check_and_load_plus_model( + self, plus_api: PlusApi, detector: str = None + ) -> None: + if not self.path or not self.path.startswith("plus://"): + return + + model_id = self.path[7:] + self.path = f"/config/model_cache/{model_id}" + model_info_path = f"{self.path}.json" + + # download the model if it doesn't exist + if not os.path.isfile(self.path): + download_url = plus_api.get_model_download_url(model_id) + r = requests.get(download_url) + with open(self.path, "wb") as f: + f.write(r.content) + + # download the model info if it doesn't exist + if not os.path.isfile(model_info_path): + model_info = plus_api.get_model_info(model_id) + with open(model_info_path, "w") as f: + json.dump(model_info, f) + else: + with open(model_info_path, "r") as f: + model_info = json.load(f) + + if detector and detector not in model_info["supportedDetectors"]: + raise ValueError(f"Model does not support detector type of {detector}") + + self.width = model_info["width"] + self.height = model_info["height"] + self.input_tensor = model_info["inputShape"] + self.input_pixel_format = model_info["pixelFormat"] + self.model_type = model_info["type"] + self._merged_labelmap = { + **{int(key): val for key, val in model_info["labelMap"].items()}, + **self.labelmap, + } + def compute_model_hash(self) -> None: with open(self.path, "rb") as f: file_hash = hashlib.md5() diff --git a/frigate/http.py b/frigate/http.py index 198b2be16..706487e8f 100644 --- a/frigate/http.py +++ b/frigate/http.py @@ -866,6 +866,11 @@ def config(): config["plus"] = {"enabled": current_app.plus_api.is_active()} + for detector, detector_config in config["detectors"].items(): + detector_config["model"]["labelmap"] = current_app.frigate_config.detectors[ + detector + ].model.merged_labelmap + return jsonify(config) diff --git a/frigate/plus.py b/frigate/plus.py index 4b59b961e..7ba67a62d 100644 --- a/frigate/plus.py +++ b/frigate/plus.py @@ -3,7 +3,7 @@ import json import logging import os import re -from typing import List +from typing import Any, Dict, List import requests from frigate.const import PLUS_ENV_VAR, PLUS_API_HOST from requests.models import Response @@ -187,3 +187,24 @@ class PlusApi: if not r.ok: raise Exception(r.text) + + def get_model_download_url( + self, + model_id: str, + ) -> str: + r = self._get(f"model/{model_id}/signed_url") + + if not r.ok: + raise Exception(r.text) + + presigned_url = r.json() + + return str(presigned_url.get("url")) + + def get_model_info(self, model_id: str) -> Any: + r = self._get(f"model/{model_id}") + + if not r.ok: + raise Exception(r.text) + + return r.json() diff --git a/frigate/test/test_config.py b/frigate/test/test_config.py index b978453c1..a40093139 100644 --- a/frigate/test/test_config.py +++ b/frigate/test/test_config.py @@ -34,7 +34,7 @@ class TestConfig(unittest.TestCase): frigate_config = FrigateConfig(**self.minimal) assert self.minimal == frigate_config.dict(exclude_unset=True) - runtime_config = frigate_config.runtime_config + runtime_config = frigate_config.runtime_config() assert "cpu" in runtime_config.detectors.keys() assert runtime_config.detectors["cpu"].type == DetectorTypeEnum.cpu assert runtime_config.detectors["cpu"].model.width == 320 @@ -59,7 +59,7 @@ class TestConfig(unittest.TestCase): } frigate_config = FrigateConfig(**(deep_merge(config, self.minimal))) - runtime_config = frigate_config.runtime_config + runtime_config = frigate_config.runtime_config() assert "cpu" in runtime_config.detectors.keys() assert "edgetpu" in runtime_config.detectors.keys() @@ -125,7 +125,7 @@ class TestConfig(unittest.TestCase): frigate_config = FrigateConfig(**config) assert config == frigate_config.dict(exclude_unset=True) - runtime_config = frigate_config.runtime_config + runtime_config = frigate_config.runtime_config() assert "dog" in runtime_config.cameras["back"].objects.track def test_override_birdseye(self): @@ -151,7 +151,7 @@ class TestConfig(unittest.TestCase): frigate_config = FrigateConfig(**config) assert config == frigate_config.dict(exclude_unset=True) - runtime_config = frigate_config.runtime_config + runtime_config = frigate_config.runtime_config() assert not runtime_config.cameras["back"].birdseye.enabled assert runtime_config.cameras["back"].birdseye.mode is BirdseyeModeEnum.motion @@ -177,7 +177,7 @@ class TestConfig(unittest.TestCase): frigate_config = FrigateConfig(**config) assert config == frigate_config.dict(exclude_unset=True) - runtime_config = frigate_config.runtime_config + runtime_config = frigate_config.runtime_config() assert runtime_config.cameras["back"].birdseye.enabled def test_inherit_birdseye(self): @@ -202,7 +202,7 @@ class TestConfig(unittest.TestCase): frigate_config = FrigateConfig(**config) assert config == frigate_config.dict(exclude_unset=True) - runtime_config = frigate_config.runtime_config + runtime_config = frigate_config.runtime_config() assert runtime_config.cameras["back"].birdseye.enabled assert ( runtime_config.cameras["back"].birdseye.mode is BirdseyeModeEnum.continuous @@ -231,7 +231,7 @@ class TestConfig(unittest.TestCase): frigate_config = FrigateConfig(**config) assert config == frigate_config.dict(exclude_unset=True) - runtime_config = frigate_config.runtime_config + runtime_config = frigate_config.runtime_config() assert "cat" in runtime_config.cameras["back"].objects.track def test_default_object_filters(self): @@ -256,7 +256,7 @@ class TestConfig(unittest.TestCase): frigate_config = FrigateConfig(**config) assert config == frigate_config.dict(exclude_unset=True) - runtime_config = frigate_config.runtime_config + runtime_config = frigate_config.runtime_config() assert "dog" in runtime_config.cameras["back"].objects.filters def test_inherit_object_filters(self): @@ -284,7 +284,7 @@ class TestConfig(unittest.TestCase): frigate_config = FrigateConfig(**config) assert config == frigate_config.dict(exclude_unset=True) - runtime_config = frigate_config.runtime_config + runtime_config = frigate_config.runtime_config() assert "dog" in runtime_config.cameras["back"].objects.filters assert runtime_config.cameras["back"].objects.filters["dog"].threshold == 0.7 @@ -313,7 +313,7 @@ class TestConfig(unittest.TestCase): frigate_config = FrigateConfig(**config) assert config == frigate_config.dict(exclude_unset=True) - runtime_config = frigate_config.runtime_config + runtime_config = frigate_config.runtime_config() assert "dog" in runtime_config.cameras["back"].objects.filters assert runtime_config.cameras["back"].objects.filters["dog"].threshold == 0.7 @@ -343,7 +343,7 @@ class TestConfig(unittest.TestCase): frigate_config = FrigateConfig(**config) assert config == frigate_config.dict(exclude_unset=True) - runtime_config = frigate_config.runtime_config + runtime_config = frigate_config.runtime_config() back_camera = runtime_config.cameras["back"] assert "dog" in back_camera.objects.filters assert len(back_camera.objects.filters["dog"].raw_mask) == 2 @@ -374,7 +374,7 @@ class TestConfig(unittest.TestCase): frigate_config = FrigateConfig(**config) assert config == frigate_config.dict(exclude_unset=True) - runtime_config = frigate_config.runtime_config + runtime_config = frigate_config.runtime_config() assert "-rtsp_transport" in runtime_config.cameras["back"].ffmpeg_cmds[0]["cmd"] def test_ffmpeg_params_global(self): @@ -403,7 +403,7 @@ class TestConfig(unittest.TestCase): frigate_config = FrigateConfig(**config) assert config == frigate_config.dict(exclude_unset=True) - runtime_config = frigate_config.runtime_config + runtime_config = frigate_config.runtime_config() assert "-re" in runtime_config.cameras["back"].ffmpeg_cmds[0]["cmd"] def test_ffmpeg_params_camera(self): @@ -433,7 +433,7 @@ class TestConfig(unittest.TestCase): frigate_config = FrigateConfig(**config) assert config == frigate_config.dict(exclude_unset=True) - runtime_config = frigate_config.runtime_config + runtime_config = frigate_config.runtime_config() assert "-re" in runtime_config.cameras["back"].ffmpeg_cmds[0]["cmd"] assert "test" not in runtime_config.cameras["back"].ffmpeg_cmds[0]["cmd"] @@ -468,7 +468,7 @@ class TestConfig(unittest.TestCase): frigate_config = FrigateConfig(**config) assert config == frigate_config.dict(exclude_unset=True) - runtime_config = frigate_config.runtime_config + runtime_config = frigate_config.runtime_config() assert "-re" in runtime_config.cameras["back"].ffmpeg_cmds[0]["cmd"] assert "test" in runtime_config.cameras["back"].ffmpeg_cmds[0]["cmd"] assert "test2" not in runtime_config.cameras["back"].ffmpeg_cmds[0]["cmd"] @@ -498,7 +498,7 @@ class TestConfig(unittest.TestCase): frigate_config = FrigateConfig(**config) assert config == frigate_config.dict(exclude_unset=True) - runtime_config = frigate_config.runtime_config + runtime_config = frigate_config.runtime_config() assert ( runtime_config.cameras["back"].record.events.retain.objects["person"] == 30 ) @@ -576,7 +576,7 @@ class TestConfig(unittest.TestCase): frigate_config = FrigateConfig(**config) assert config == frigate_config.dict(exclude_unset=True) - runtime_config = frigate_config.runtime_config + runtime_config = frigate_config.runtime_config() assert isinstance( runtime_config.cameras["back"].zones["test"].contour, np.ndarray ) @@ -608,7 +608,7 @@ class TestConfig(unittest.TestCase): frigate_config = FrigateConfig(**config) assert config == frigate_config.dict(exclude_unset=True) - runtime_config = frigate_config.runtime_config + runtime_config = frigate_config.runtime_config() back_camera = runtime_config.cameras["back"] assert back_camera.record.events.objects is None assert back_camera.record.events.retain.objects["person"] == 30 @@ -639,7 +639,7 @@ class TestConfig(unittest.TestCase): frigate_config = FrigateConfig(**config) assert config == frigate_config.dict(exclude_unset=True) - runtime_config = frigate_config.runtime_config + runtime_config = frigate_config.runtime_config() ffmpeg_cmds = runtime_config.cameras["back"].ffmpeg_cmds assert len(ffmpeg_cmds) == 1 assert not "clips" in ffmpeg_cmds[0]["roles"] @@ -670,7 +670,7 @@ class TestConfig(unittest.TestCase): frigate_config = FrigateConfig(**config) assert config == frigate_config.dict(exclude_unset=True) - runtime_config = frigate_config.runtime_config + runtime_config = frigate_config.runtime_config() assert runtime_config.cameras["back"].detect.max_disappeared == 5 * 5 def test_motion_frame_height_wont_go_below_120(self): @@ -698,7 +698,7 @@ class TestConfig(unittest.TestCase): frigate_config = FrigateConfig(**config) assert config == frigate_config.dict(exclude_unset=True) - runtime_config = frigate_config.runtime_config + runtime_config = frigate_config.runtime_config() assert runtime_config.cameras["back"].motion.frame_height == 50 def test_motion_contour_area_dynamic(self): @@ -726,7 +726,7 @@ class TestConfig(unittest.TestCase): frigate_config = FrigateConfig(**config) assert config == frigate_config.dict(exclude_unset=True) - runtime_config = frigate_config.runtime_config + runtime_config = frigate_config.runtime_config() assert round(runtime_config.cameras["back"].motion.contour_area) == 30 def test_merge_labelmap(self): @@ -755,7 +755,7 @@ class TestConfig(unittest.TestCase): frigate_config = FrigateConfig(**config) assert config == frigate_config.dict(exclude_unset=True) - runtime_config = frigate_config.runtime_config + runtime_config = frigate_config.runtime_config() assert runtime_config.model.merged_labelmap[7] == "truck" def test_default_labelmap_empty(self): @@ -783,7 +783,7 @@ class TestConfig(unittest.TestCase): frigate_config = FrigateConfig(**config) assert config == frigate_config.dict(exclude_unset=True) - runtime_config = frigate_config.runtime_config + runtime_config = frigate_config.runtime_config() assert runtime_config.model.merged_labelmap[0] == "person" def test_default_labelmap(self): @@ -812,7 +812,7 @@ class TestConfig(unittest.TestCase): frigate_config = FrigateConfig(**config) assert config == frigate_config.dict(exclude_unset=True) - runtime_config = frigate_config.runtime_config + runtime_config = frigate_config.runtime_config() assert runtime_config.model.merged_labelmap[0] == "person" def test_fails_on_invalid_role(self): @@ -871,7 +871,7 @@ class TestConfig(unittest.TestCase): } frigate_config = FrigateConfig(**config) - self.assertRaises(ValueError, lambda: frigate_config.runtime_config) + self.assertRaises(ValueError, lambda: frigate_config.runtime_config()) def test_works_on_missing_role_multiple_cams(self): config = { @@ -919,7 +919,7 @@ class TestConfig(unittest.TestCase): } frigate_config = FrigateConfig(**config) - runtime_config = frigate_config.runtime_config + runtime_config = frigate_config.runtime_config() def test_global_detect(self): config = { @@ -946,7 +946,7 @@ class TestConfig(unittest.TestCase): frigate_config = FrigateConfig(**config) assert config == frigate_config.dict(exclude_unset=True) - runtime_config = frigate_config.runtime_config + runtime_config = frigate_config.runtime_config() assert runtime_config.cameras["back"].detect.max_disappeared == 1 assert runtime_config.cameras["back"].detect.height == 1080 @@ -969,7 +969,7 @@ class TestConfig(unittest.TestCase): frigate_config = FrigateConfig(**config) assert config == frigate_config.dict(exclude_unset=True) - runtime_config = frigate_config.runtime_config + runtime_config = frigate_config.runtime_config() assert runtime_config.cameras["back"].detect.max_disappeared == 25 assert runtime_config.cameras["back"].detect.height == 720 @@ -998,7 +998,7 @@ class TestConfig(unittest.TestCase): frigate_config = FrigateConfig(**config) assert config == frigate_config.dict(exclude_unset=True) - runtime_config = frigate_config.runtime_config + runtime_config = frigate_config.runtime_config() assert runtime_config.cameras["back"].detect.max_disappeared == 1 assert runtime_config.cameras["back"].detect.height == 1080 assert runtime_config.cameras["back"].detect.width == 1920 @@ -1026,7 +1026,7 @@ class TestConfig(unittest.TestCase): frigate_config = FrigateConfig(**config) assert config == frigate_config.dict(exclude_unset=True) - runtime_config = frigate_config.runtime_config + runtime_config = frigate_config.runtime_config() assert runtime_config.cameras["back"].snapshots.enabled assert runtime_config.cameras["back"].snapshots.height == 100 @@ -1049,7 +1049,7 @@ class TestConfig(unittest.TestCase): frigate_config = FrigateConfig(**config) assert config == frigate_config.dict(exclude_unset=True) - runtime_config = frigate_config.runtime_config + runtime_config = frigate_config.runtime_config() assert runtime_config.cameras["back"].snapshots.bounding_box assert runtime_config.cameras["back"].snapshots.quality == 70 @@ -1077,7 +1077,7 @@ class TestConfig(unittest.TestCase): frigate_config = FrigateConfig(**config) assert config == frigate_config.dict(exclude_unset=True) - runtime_config = frigate_config.runtime_config + runtime_config = frigate_config.runtime_config() assert runtime_config.cameras["back"].snapshots.bounding_box == False assert runtime_config.cameras["back"].snapshots.height == 150 assert runtime_config.cameras["back"].snapshots.enabled @@ -1101,7 +1101,7 @@ class TestConfig(unittest.TestCase): frigate_config = FrigateConfig(**config) assert config == frigate_config.dict(exclude_unset=True) - runtime_config = frigate_config.runtime_config + runtime_config = frigate_config.runtime_config() assert not runtime_config.cameras["back"].rtmp.enabled def test_default_not_rtmp(self): @@ -1123,7 +1123,7 @@ class TestConfig(unittest.TestCase): frigate_config = FrigateConfig(**config) assert config == frigate_config.dict(exclude_unset=True) - runtime_config = frigate_config.runtime_config + runtime_config = frigate_config.runtime_config() assert not runtime_config.cameras["back"].rtmp.enabled def test_global_rtmp_merge(self): @@ -1149,7 +1149,7 @@ class TestConfig(unittest.TestCase): frigate_config = FrigateConfig(**config) assert config == frigate_config.dict(exclude_unset=True) - runtime_config = frigate_config.runtime_config + runtime_config = frigate_config.runtime_config() assert runtime_config.cameras["back"].rtmp.enabled def test_global_rtmp_default(self): @@ -1175,7 +1175,7 @@ class TestConfig(unittest.TestCase): frigate_config = FrigateConfig(**config) assert config == frigate_config.dict(exclude_unset=True) - runtime_config = frigate_config.runtime_config + runtime_config = frigate_config.runtime_config() assert not runtime_config.cameras["back"].rtmp.enabled def test_global_jsmpeg(self): @@ -1198,7 +1198,7 @@ class TestConfig(unittest.TestCase): frigate_config = FrigateConfig(**config) assert config == frigate_config.dict(exclude_unset=True) - runtime_config = frigate_config.runtime_config + runtime_config = frigate_config.runtime_config() assert runtime_config.cameras["back"].live.quality == 4 def test_default_live(self): @@ -1220,7 +1220,7 @@ class TestConfig(unittest.TestCase): frigate_config = FrigateConfig(**config) assert config == frigate_config.dict(exclude_unset=True) - runtime_config = frigate_config.runtime_config + runtime_config = frigate_config.runtime_config() assert runtime_config.cameras["back"].live.quality == 8 def test_global_live_merge(self): @@ -1246,7 +1246,7 @@ class TestConfig(unittest.TestCase): frigate_config = FrigateConfig(**config) assert config == frigate_config.dict(exclude_unset=True) - runtime_config = frigate_config.runtime_config + runtime_config = frigate_config.runtime_config() assert runtime_config.cameras["back"].live.quality == 7 assert runtime_config.cameras["back"].live.height == 480 @@ -1270,7 +1270,7 @@ class TestConfig(unittest.TestCase): frigate_config = FrigateConfig(**config) assert config == frigate_config.dict(exclude_unset=True) - runtime_config = frigate_config.runtime_config + runtime_config = frigate_config.runtime_config() assert runtime_config.cameras["back"].timestamp_style.position == "bl" def test_default_timestamp_style(self): @@ -1292,7 +1292,7 @@ class TestConfig(unittest.TestCase): frigate_config = FrigateConfig(**config) assert config == frigate_config.dict(exclude_unset=True) - runtime_config = frigate_config.runtime_config + runtime_config = frigate_config.runtime_config() assert runtime_config.cameras["back"].timestamp_style.position == "tl" def test_global_timestamp_style_merge(self): @@ -1317,7 +1317,7 @@ class TestConfig(unittest.TestCase): frigate_config = FrigateConfig(**config) assert config == frigate_config.dict(exclude_unset=True) - runtime_config = frigate_config.runtime_config + runtime_config = frigate_config.runtime_config() assert runtime_config.cameras["back"].timestamp_style.position == "bl" assert runtime_config.cameras["back"].timestamp_style.thickness == 4 @@ -1341,7 +1341,7 @@ class TestConfig(unittest.TestCase): frigate_config = FrigateConfig(**config) assert config == frigate_config.dict(exclude_unset=True) - runtime_config = frigate_config.runtime_config + runtime_config = frigate_config.runtime_config() assert runtime_config.cameras["back"].snapshots.retain.default == 1.5 def test_fails_on_bad_camera_name(self): @@ -1365,7 +1365,7 @@ class TestConfig(unittest.TestCase): frigate_config = FrigateConfig(**config) self.assertRaises( - ValidationError, lambda: frigate_config.runtime_config.cameras + ValidationError, lambda: frigate_config.runtime_config().cameras ) def test_fails_on_bad_segment_time(self): @@ -1392,7 +1392,8 @@ class TestConfig(unittest.TestCase): frigate_config = FrigateConfig(**config) self.assertRaises( - ValueError, lambda: frigate_config.runtime_config.ffmpeg.output_args.record + ValueError, + lambda: frigate_config.runtime_config().ffmpeg.output_args.record, ) def test_fails_zone_defines_untracked_object(self): @@ -1421,7 +1422,7 @@ class TestConfig(unittest.TestCase): frigate_config = FrigateConfig(**config) - self.assertRaises(ValueError, lambda: frigate_config.runtime_config.cameras) + self.assertRaises(ValueError, lambda: frigate_config.runtime_config().cameras) def test_fails_duplicate_keys(self): raw_config = """ @@ -1465,7 +1466,7 @@ class TestConfig(unittest.TestCase): frigate_config = FrigateConfig(**config) assert config == frigate_config.dict(exclude_unset=True) - runtime_config = frigate_config.runtime_config + runtime_config = frigate_config.runtime_config() assert "dog" in runtime_config.cameras["back"].objects.filters assert runtime_config.cameras["back"].objects.filters["dog"].min_ratio == 0.2 assert runtime_config.cameras["back"].objects.filters["dog"].max_ratio == 10.1 diff --git a/frigate/test/test_http.py b/frigate/test/test_http.py index bc08ec010..2c0e58df2 100644 --- a/frigate/test/test_http.py +++ b/frigate/test/test_http.py @@ -292,7 +292,7 @@ class TestHttp(unittest.TestCase): def test_config(self): app = create_app( - FrigateConfig(**self.minimal_config).runtime_config, + FrigateConfig(**self.minimal_config).runtime_config(), self.db, None, None, @@ -308,7 +308,7 @@ class TestHttp(unittest.TestCase): def test_recordings(self): app = create_app( - FrigateConfig(**self.minimal_config).runtime_config, + FrigateConfig(**self.minimal_config).runtime_config(), self.db, None, None, @@ -327,7 +327,7 @@ class TestHttp(unittest.TestCase): @patch("frigate.http.stats_snapshot") def test_stats(self, mock_stats): app = create_app( - FrigateConfig(**self.minimal_config).runtime_config, + FrigateConfig(**self.minimal_config).runtime_config(), self.db, None, None,