diff --git a/frigate/config/updater.py b/frigate/config/updater.py index db01d8e22..b7ed26114 100644 --- a/frigate/config/updater.py +++ b/frigate/config/updater.py @@ -45,21 +45,21 @@ class GlobalConfigUpdateSubscriber: exact=False, ) - def check_for_updates(self) -> dict[str, list[str]]: - updated_topics: list[str] = [] + def check_for_updates(self) -> list[tuple[GlobalConfigUpdateEnum, Any]]: + updated_topics: list[tuple[GlobalConfigUpdateEnum, Any]] = [] # get all updates available while True: - update_topic, update_config = self.subscriber.check_for_update() + update_topic, payload = self.subscriber.check_for_update() - if update_topic is None or update_config is None: + if update_topic is None or payload is None: break _, raw_type = update_topic.split("/") update_type = GlobalConfigUpdateEnum[raw_type] if update_type in self.topics: - updated_topics.append(update_type.name) + updated_topics.append((update_type, payload)) return updated_topics diff --git a/frigate/track/object_processing.py b/frigate/track/object_processing.py index af4f7bd42..937086117 100644 --- a/frigate/track/object_processing.py +++ b/frigate/track/object_processing.py @@ -32,6 +32,7 @@ from frigate.config.camera.updater import ( CameraConfigUpdateEnum, CameraConfigUpdateSubscriber, ) +from frigate.config.updater import GlobalConfigUpdateEnum, GlobalConfigUpdateSubscriber from frigate.const import FAST_QUEUE_TIMEOUT, UPDATE_CAMERA_ACTIVITY from frigate.events.types import EventStateEnum, EventTypeEnum from frigate.models import Event, Timeline @@ -66,7 +67,10 @@ class TrackedObjectProcessor(threading.Thread): self.last_motion_detected: dict[str, float] = {} self.ptz_autotracker_thread = ptz_autotracker_thread - self.config_subscriber = CameraConfigUpdateSubscriber( + self.global_config_subscriber = GlobalConfigUpdateSubscriber( + [GlobalConfigUpdateEnum.add_camera, GlobalConfigUpdateEnum.remove_camera] + ) + self.camera_config_subscriber = CameraConfigUpdateSubscriber( self.config.cameras, [CameraConfigUpdateEnum.enabled, CameraConfigUpdateEnum.zones], ) @@ -91,6 +95,12 @@ class TrackedObjectProcessor(threading.Thread): self.zone_data = defaultdict(lambda: defaultdict(dict)) self.active_zone_data = defaultdict(lambda: defaultdict(dict)) + for camera in self.config.cameras.keys(): + self.create_camera_state(camera) + + def create_camera_state(self, camera: str) -> None: + """Creates a new camera state.""" + def start(camera: str, obj: TrackedObject, frame_name: str): self.event_sender.publish( ( @@ -198,17 +208,16 @@ class TrackedObjectProcessor(threading.Thread): self.camera_activity[camera] = activity self.requestor.send_data(UPDATE_CAMERA_ACTIVITY, self.camera_activity) - for camera in self.config.cameras.keys(): - camera_state = CameraState( - camera, self.config, self.frame_manager, self.ptz_autotracker_thread - ) - camera_state.on("start", start) - camera_state.on("autotrack", autotrack) - camera_state.on("update", update) - camera_state.on("end", end) - camera_state.on("snapshot", snapshot) - camera_state.on("camera_activity", camera_activity) - self.camera_states[camera] = camera_state + camera_state = CameraState( + camera, self.config, self.frame_manager, self.ptz_autotracker_thread + ) + camera_state.on("start", start) + camera_state.on("autotrack", autotrack) + camera_state.on("update", update) + camera_state.on("end", end) + camera_state.on("snapshot", snapshot) + camera_state.on("camera_activity", camera_activity) + self.camera_states[camera] = camera_state def should_save_snapshot(self, camera, obj: TrackedObject): if obj.false_positive: @@ -581,8 +590,18 @@ class TrackedObjectProcessor(threading.Thread): def run(self): while not self.stop_event.is_set(): + # check for global config updates + for topic, payload in self.global_config_subscriber.check_for_updates(): + if topic == GlobalConfigUpdateEnum.add_camera: + self.create_camera_state(payload["camera"]) + elif topic == GlobalConfigUpdateEnum.remove_camera: + camera = payload["camera"] + camera_state = self.camera_states[camera] + camera_state.shutdown() + del self.camera_states[camera] + # check for config updates - updated_topics = self.config_subscriber.check_for_updates() + updated_topics = self.camera_config_subscriber.check_for_updates() if "enabled" in updated_topics: for camera in updated_topics["enabled"]: @@ -698,6 +717,6 @@ class TrackedObjectProcessor(threading.Thread): self.event_sender.stop() self.event_end_subscriber.stop() self.sub_label_subscriber.stop() - self.config_subscriber.stop() + self.camera_config_subscriber.stop() logger.info("Exiting object processor...")