Dynamic Config Updates (#18353)

* Create classes to handle publishing and subscribing config updates

* Cleanup

* Use config updater

* Update handling for enabled config

* Cleanup

* Recording config updates

* Birdseye config updates

* Handle notifications

* handle review

* Update motion
This commit is contained in:
Nicolas Mowen
2025-08-16 10:20:33 -05:00
committed by Blake Blackshear
parent b7dbcce6e5
commit dc187eee1c
13 changed files with 316 additions and 236 deletions
-17
View File
@@ -15,7 +15,6 @@ from typing import Any, Optional
import cv2
import numpy as np
from frigate.comms.config_updater import ConfigSubscriber
from frigate.config import BirdseyeModeEnum, FfmpegConfig, FrigateConfig
from frigate.const import BASE_DIR, BIRDSEYE_PIPE, INSTALL_DIR
from frigate.util.image import (
@@ -754,7 +753,6 @@ class Birdseye:
"birdseye", self.converter, websocket_server, stop_event
)
self.birdseye_manager = BirdsEyeFrameManager(config, stop_event)
self.birdseye_subscriber = ConfigSubscriber("config/birdseye/")
self.frame_manager = SharedMemoryFrameManager()
self.stop_event = stop_event
@@ -791,20 +789,6 @@ class Birdseye:
frame_time: float,
frame: np.ndarray,
) -> None:
# check if there is an updated config
while True:
(
updated_birdseye_topic,
updated_birdseye_config,
) = self.birdseye_subscriber.check_for_update()
if not updated_birdseye_topic:
break
if updated_birdseye_config:
camera_name = updated_birdseye_topic.rpartition("/")[-1]
self.config.cameras[camera_name].birdseye = updated_birdseye_config
if self.birdseye_manager.update(
camera,
len([o for o in current_tracked_objects if not o["stationary"]]),
@@ -815,6 +799,5 @@ class Birdseye:
self.__send_new_frame()
def stop(self) -> None:
self.birdseye_subscriber.stop()
self.converter.join()
self.broadcaster.join()
+14 -15
View File
@@ -17,10 +17,13 @@ from ws4py.server.wsgirefserver import (
)
from ws4py.server.wsgiutils import WebSocketWSGIApplication
from frigate.comms.config_updater import ConfigSubscriber
from frigate.comms.detections_updater import DetectionSubscriber, DetectionTypeEnum
from frigate.comms.ws import WebSocket
from frigate.config import FrigateConfig
from frigate.config.camera.updater import (
CameraConfigUpdateEnum,
CameraConfigUpdateSubscriber,
)
from frigate.const import CACHE_DIR, CLIPS_DIR
from frigate.output.birdseye import Birdseye
from frigate.output.camera import JsmpegCamera
@@ -99,7 +102,14 @@ def output_frames(
websocket_thread = threading.Thread(target=websocket_server.serve_forever)
detection_subscriber = DetectionSubscriber(DetectionTypeEnum.video)
config_enabled_subscriber = ConfigSubscriber("config/enabled/")
config_subscriber = CameraConfigUpdateSubscriber(
config.cameras,
[
CameraConfigUpdateEnum.birdseye,
CameraConfigUpdateEnum.enabled,
CameraConfigUpdateEnum.record,
],
)
jsmpeg_cameras: dict[str, JsmpegCamera] = {}
birdseye: Birdseye | None = None
@@ -125,18 +135,7 @@ def output_frames(
while not stop_event.is_set():
# check if there is an updated config
while True:
(
updated_enabled_topic,
updated_enabled_config,
) = config_enabled_subscriber.check_for_update()
if not updated_enabled_topic:
break
if updated_enabled_config:
camera_name = updated_enabled_topic.rpartition("/")[-1]
config.cameras[camera_name].enabled = updated_enabled_config.enabled
config_subscriber.check_for_updates()
(topic, data) = detection_subscriber.check_for_update(timeout=1)
now = datetime.datetime.now().timestamp()
@@ -240,7 +239,7 @@ def output_frames(
if birdseye is not None:
birdseye.stop()
config_enabled_subscriber.stop()
config_subscriber.stop()
websocket_server.manager.close_all()
websocket_server.manager.stop()
websocket_server.manager.join()
-10
View File
@@ -13,7 +13,6 @@ from typing import Any
import cv2
import numpy as np
from frigate.comms.config_updater import ConfigSubscriber
from frigate.comms.inter_process import InterProcessRequestor
from frigate.config import CameraConfig, RecordQualityEnum
from frigate.const import CACHE_DIR, CLIPS_DIR, INSERT_PREVIEW, PREVIEW_FRAME_TYPE
@@ -174,9 +173,6 @@ class PreviewRecorder:
# create communication for finished previews
self.requestor = InterProcessRequestor()
self.config_subscriber = ConfigSubscriber(
f"config/record/{self.config.name}", True
)
y, u1, u2, v1, v2 = get_yuv_crop(
self.config.frame_shape_yuv,
@@ -323,12 +319,6 @@ class PreviewRecorder:
) -> None:
self.offline = False
# check for updated record config
_, updated_record_config = self.config_subscriber.check_for_update()
if updated_record_config:
self.config.record = updated_record_config
# always write the first frame
if self.start_time == 0:
self.start_time = frame_time