From eb1709fa49bf2b94ddbbe342c136d6574beea7d5 Mon Sep 17 00:00:00 2001 From: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com> Date: Fri, 22 May 2026 09:11:43 -0500 Subject: [PATCH] add refresh topic for camera maintainer recycle action MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The maintainer's recycle branch is doing an action (recycle the camera) in response to a section-level signal. Introduce a CameraConfigUpdateEnum.refresh case as an explicit action signal — the maintainer subscribes to refresh instead of detect, parallel with add and remove. Publishers fire refresh alongside detect when a recycle is needed; section-level subscribers keep their existing topic. Since no main-process subscriber listens for detect anymore, the refresh handler calls recreate_ffmpeg_cmds() explicitly so the shared CameraConfig's ffmpeg_cmds is rebuilt before the new subprocesses spawn. --- frigate/api/app.py | 10 +++++++++- frigate/camera/maintainer.py | 8 ++++++-- frigate/config/camera/updater.py | 2 +- 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/frigate/api/app.py b/frigate/api/app.py index 1e487598ac..179c7fb90a 100644 --- a/frigate/api/app.py +++ b/frigate/api/app.py @@ -751,7 +751,9 @@ def _config_set_in_memory(request: Request, body: AppConfigSetBody) -> JSONRespo ) # detect resize also republishes motion + objects so other - # processes pick up the rebuilt masks + # processes pick up the rebuilt masks, and fires refresh so + # the camera maintainer recycles the camera process to pick + # up the new ffmpeg cmd / SHM sizing if field == "detect": cam_cfg = config.cameras.get(camera) if cam_cfg is not None: @@ -768,6 +770,12 @@ def _config_set_in_memory(request: Request, body: AppConfigSetBody) -> JSONRespo ), cam_cfg.objects, ) + request.app.config_publisher.publish_update( + CameraConfigUpdateTopic( + CameraConfigUpdateEnum.refresh, camera + ), + cam_cfg, + ) return JSONResponse( content={"success": True, "message": "Config applied in-memory"}, diff --git a/frigate/camera/maintainer.py b/frigate/camera/maintainer.py index 967f580fe6..ea8df7bff0 100644 --- a/frigate/camera/maintainer.py +++ b/frigate/camera/maintainer.py @@ -51,7 +51,7 @@ class CameraMaintainer(threading.Thread): [ CameraConfigUpdateEnum.add, CameraConfigUpdateEnum.remove, - CameraConfigUpdateEnum.detect, + CameraConfigUpdateEnum.refresh, ], ) self.shm_count = self.__calculate_shm_frame_count() @@ -281,7 +281,7 @@ class CameraMaintainer(threading.Thread): self.region_grids.pop(camera, None) self.camera_metrics.pop(camera, None) self.ptz_metrics.pop(camera, None) - elif update_type == CameraConfigUpdateEnum.detect.name: + elif update_type == CameraConfigUpdateEnum.refresh.name: # Recycle replay cameras so detect width/height/fps # propagate through ffmpeg args, SHM sizing, and the # region grid. Regular cameras detect change still @@ -301,6 +301,10 @@ class CameraMaintainer(threading.Thread): ): continue + # rebuild ffmpeg cmds on the shared config so the + # new subprocesses spawn with current args + new_config.recreate_ffmpeg_cmds() + self.__stop_camera_capture_process(camera) self.__stop_camera_process(camera) self.__unlink_camera_frame_slots(camera) diff --git a/frigate/config/camera/updater.py b/frigate/config/camera/updater.py index 4579504d27..b475f42157 100644 --- a/frigate/config/camera/updater.py +++ b/frigate/config/camera/updater.py @@ -26,6 +26,7 @@ class CameraConfigUpdateEnum(str, Enum): object_genai = "object_genai" onvif = "onvif" record = "record" + refresh = "refresh" # signals the camera maintainer to recycle the camera process remove = "remove" # for removing a camera review = "review" review_genai = "review_genai" @@ -108,7 +109,6 @@ class CameraConfigUpdateSubscriber: config.birdseye = updated_config elif update_type == CameraConfigUpdateEnum.detect: config.detect = updated_config - config.recreate_ffmpeg_cmds() elif update_type == CameraConfigUpdateEnum.enabled: config.enabled = updated_config elif update_type == CameraConfigUpdateEnum.object_genai: