mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-05-01 11:07:41 +03:00
Cleanup for updating the cameras config
This commit is contained in:
parent
1d0e9829f6
commit
86b5e0f9ae
@ -3,7 +3,7 @@
|
|||||||
from collections import Counter
|
from collections import Counter
|
||||||
from typing import Any, Callable
|
from typing import Any, Callable
|
||||||
|
|
||||||
from frigate.config.config import FrigateConfig
|
from frigate.config import CameraConfig, FrigateConfig
|
||||||
|
|
||||||
|
|
||||||
class CameraActivityManager:
|
class CameraActivityManager:
|
||||||
@ -23,26 +23,33 @@ class CameraActivityManager:
|
|||||||
if not camera_config.enabled_in_config:
|
if not camera_config.enabled_in_config:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
self.last_camera_activity[camera_config.name] = {}
|
self.__init_camera(camera_config)
|
||||||
self.camera_all_object_counts[camera_config.name] = Counter()
|
|
||||||
self.camera_active_object_counts[camera_config.name] = Counter()
|
|
||||||
|
|
||||||
for zone, zone_config in camera_config.zones.items():
|
def __init_camera(self, camera_config: CameraConfig) -> None:
|
||||||
if zone not in self.all_zone_labels:
|
self.last_camera_activity[camera_config.name] = {}
|
||||||
self.zone_all_object_counts[zone] = Counter()
|
self.camera_all_object_counts[camera_config.name] = Counter()
|
||||||
self.zone_active_object_counts[zone] = Counter()
|
self.camera_active_object_counts[camera_config.name] = Counter()
|
||||||
self.all_zone_labels[zone] = set()
|
|
||||||
|
|
||||||
self.all_zone_labels[zone].update(
|
for zone, zone_config in camera_config.zones.items():
|
||||||
zone_config.objects
|
if zone not in self.all_zone_labels:
|
||||||
if zone_config.objects
|
self.zone_all_object_counts[zone] = Counter()
|
||||||
else camera_config.objects.track
|
self.zone_active_object_counts[zone] = Counter()
|
||||||
)
|
self.all_zone_labels[zone] = set()
|
||||||
|
|
||||||
|
self.all_zone_labels[zone].update(
|
||||||
|
zone_config.objects
|
||||||
|
if zone_config.objects
|
||||||
|
else camera_config.objects.track
|
||||||
|
)
|
||||||
|
|
||||||
def update_activity(self, new_activity: dict[str, dict[str, Any]]) -> None:
|
def update_activity(self, new_activity: dict[str, dict[str, Any]]) -> None:
|
||||||
all_objects: list[dict[str, Any]] = []
|
all_objects: list[dict[str, Any]] = []
|
||||||
|
|
||||||
for camera in new_activity.keys():
|
for camera in new_activity.keys():
|
||||||
|
# handle cameras that were added dynamically
|
||||||
|
if camera not in self.camera_all_object_counts:
|
||||||
|
self.__init_camera(self.config.cameras[camera])
|
||||||
|
|
||||||
new_objects = new_activity[camera].get("objects", [])
|
new_objects = new_activity[camera].get("objects", [])
|
||||||
all_objects.extend(new_objects)
|
all_objects.extend(new_objects)
|
||||||
|
|
||||||
|
|||||||
@ -45,6 +45,7 @@ class CameraMaintainer(threading.Thread):
|
|||||||
self.frame_manager = SharedMemoryFrameManager()
|
self.frame_manager = SharedMemoryFrameManager()
|
||||||
self.region_grids: dict[str, list[list[dict[str, int]]]] = {}
|
self.region_grids: dict[str, list[list[dict[str, int]]]] = {}
|
||||||
self.update_subscriber = CameraConfigUpdateSubscriber(
|
self.update_subscriber = CameraConfigUpdateSubscriber(
|
||||||
|
self.config,
|
||||||
{},
|
{},
|
||||||
[
|
[
|
||||||
CameraConfigUpdateEnum.add,
|
CameraConfigUpdateEnum.add,
|
||||||
@ -170,13 +171,15 @@ class CameraMaintainer(threading.Thread):
|
|||||||
camera_process.start()
|
camera_process.start()
|
||||||
logger.info(f"Camera processor started for {config.name}: {camera_process.pid}")
|
logger.info(f"Camera processor started for {config.name}: {camera_process.pid}")
|
||||||
|
|
||||||
def __start_camera_capture(self, name: str, config: CameraConfig) -> None:
|
def __start_camera_capture(
|
||||||
if not self.config.cameras[name].enabled_in_config:
|
self, name: str, config: CameraConfig, runtime: bool = False
|
||||||
|
) -> None:
|
||||||
|
if not config.enabled_in_config:
|
||||||
logger.info(f"Capture process not started for disabled camera {name}")
|
logger.info(f"Capture process not started for disabled camera {name}")
|
||||||
return
|
return
|
||||||
|
|
||||||
# pre-create shms
|
# pre-create shms
|
||||||
for i in range(self.shm_count):
|
for i in range(10 if runtime else self.shm_count):
|
||||||
frame_size = config.frame_shape_yuv[0] * config.frame_shape_yuv[1]
|
frame_size = config.frame_shape_yuv[0] * config.frame_shape_yuv[1]
|
||||||
self.frame_manager.create(f"{config.name}_frame{i}", frame_size)
|
self.frame_manager.create(f"{config.name}_frame{i}", frame_size)
|
||||||
|
|
||||||
|
|||||||
@ -81,7 +81,7 @@ class WebPushClient(Communicator): # type: ignore[misc]
|
|||||||
"config/notifications", exact=True
|
"config/notifications", exact=True
|
||||||
)
|
)
|
||||||
self.config_subscriber = CameraConfigUpdateSubscriber(
|
self.config_subscriber = CameraConfigUpdateSubscriber(
|
||||||
self.config.cameras, [CameraConfigUpdateEnum.notifications]
|
self.config, self.config.cameras, [CameraConfigUpdateEnum.notifications]
|
||||||
)
|
)
|
||||||
|
|
||||||
def subscribe(self, receiver: Callable) -> None:
|
def subscribe(self, receiver: Callable) -> None:
|
||||||
@ -170,7 +170,12 @@ class WebPushClient(Communicator): # type: ignore[misc]
|
|||||||
if updated_notification_config:
|
if updated_notification_config:
|
||||||
self.config.notifications = updated_notification_config
|
self.config.notifications = updated_notification_config
|
||||||
|
|
||||||
self.config_subscriber.check_for_updates()
|
updates = self.config_subscriber.check_for_updates()
|
||||||
|
|
||||||
|
if "add" in updates:
|
||||||
|
for camera in updates["add"]:
|
||||||
|
self.suspended_cameras[camera] = 0
|
||||||
|
self.last_camera_notification_time[camera] = 0
|
||||||
|
|
||||||
if topic == "reviews":
|
if topic == "reviews":
|
||||||
decoded = json.loads(payload)
|
decoded = json.loads(payload)
|
||||||
|
|||||||
@ -5,7 +5,7 @@ from enum import Enum
|
|||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from frigate.comms.config_updater import ConfigPublisher, ConfigSubscriber
|
from frigate.comms.config_updater import ConfigPublisher, ConfigSubscriber
|
||||||
from frigate.config import CameraConfig
|
from frigate.config import CameraConfig, FrigateConfig
|
||||||
|
|
||||||
|
|
||||||
class CameraConfigUpdateEnum(str, Enum):
|
class CameraConfigUpdateEnum(str, Enum):
|
||||||
@ -51,9 +51,11 @@ class CameraConfigUpdatePublisher:
|
|||||||
class CameraConfigUpdateSubscriber:
|
class CameraConfigUpdateSubscriber:
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
|
config: FrigateConfig | None,
|
||||||
camera_configs: dict[str, CameraConfig],
|
camera_configs: dict[str, CameraConfig],
|
||||||
topics: list[CameraConfigUpdateEnum],
|
topics: list[CameraConfigUpdateEnum],
|
||||||
):
|
):
|
||||||
|
self.config = config
|
||||||
self.camera_configs = camera_configs
|
self.camera_configs = camera_configs
|
||||||
self.topics = topics
|
self.topics = topics
|
||||||
|
|
||||||
@ -71,9 +73,11 @@ class CameraConfigUpdateSubscriber:
|
|||||||
self, camera: str, update_type: CameraConfigUpdateEnum, updated_config: Any
|
self, camera: str, update_type: CameraConfigUpdateEnum, updated_config: Any
|
||||||
) -> None:
|
) -> None:
|
||||||
if update_type == CameraConfigUpdateEnum.add:
|
if update_type == CameraConfigUpdateEnum.add:
|
||||||
|
self.config.cameras[camera] = updated_config
|
||||||
self.camera_configs[camera] = updated_config
|
self.camera_configs[camera] = updated_config
|
||||||
return
|
return
|
||||||
elif update_type == CameraConfigUpdateEnum.remove:
|
elif update_type == CameraConfigUpdateEnum.remove:
|
||||||
|
self.config.cameras.pop(camera)
|
||||||
self.camera_configs.pop(camera)
|
self.camera_configs.pop(camera)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|||||||
@ -33,6 +33,10 @@ from frigate.const import (
|
|||||||
CLIPS_DIR,
|
CLIPS_DIR,
|
||||||
UPDATE_EVENT_DESCRIPTION,
|
UPDATE_EVENT_DESCRIPTION,
|
||||||
)
|
)
|
||||||
|
from frigate.config.camera.updater import (
|
||||||
|
CameraConfigUpdateEnum,
|
||||||
|
CameraConfigUpdateSubscriber,
|
||||||
|
)
|
||||||
from frigate.data_processing.common.license_plate.model import (
|
from frigate.data_processing.common.license_plate.model import (
|
||||||
LicensePlateModelRunner,
|
LicensePlateModelRunner,
|
||||||
)
|
)
|
||||||
@ -87,6 +91,11 @@ class EmbeddingMaintainer(threading.Thread):
|
|||||||
self.config = config
|
self.config = config
|
||||||
self.metrics = metrics
|
self.metrics = metrics
|
||||||
self.embeddings = None
|
self.embeddings = None
|
||||||
|
self.config_updater = CameraConfigUpdateSubscriber(
|
||||||
|
self.config,
|
||||||
|
self.config.cameras,
|
||||||
|
[CameraConfigUpdateEnum.add, CameraConfigUpdateEnum.remove],
|
||||||
|
)
|
||||||
|
|
||||||
if config.semantic_search.enabled:
|
if config.semantic_search.enabled:
|
||||||
self.embeddings = Embeddings(config, db, metrics)
|
self.embeddings = Embeddings(config, db, metrics)
|
||||||
@ -198,6 +207,7 @@ class EmbeddingMaintainer(threading.Thread):
|
|||||||
def run(self) -> None:
|
def run(self) -> None:
|
||||||
"""Maintain a SQLite-vec database for semantic search."""
|
"""Maintain a SQLite-vec database for semantic search."""
|
||||||
while not self.stop_event.is_set():
|
while not self.stop_event.is_set():
|
||||||
|
self.config_updater.check_for_updates()
|
||||||
self._process_requests()
|
self._process_requests()
|
||||||
self._process_updates()
|
self._process_updates()
|
||||||
self._process_recordings_updates()
|
self._process_recordings_updates()
|
||||||
@ -206,6 +216,7 @@ class EmbeddingMaintainer(threading.Thread):
|
|||||||
self._process_finalized()
|
self._process_finalized()
|
||||||
self._process_event_metadata()
|
self._process_event_metadata()
|
||||||
|
|
||||||
|
self.config_updater.stop()
|
||||||
self.event_subscriber.stop()
|
self.event_subscriber.stop()
|
||||||
self.event_end_subscriber.stop()
|
self.event_end_subscriber.stop()
|
||||||
self.recordings_subscriber.stop()
|
self.recordings_subscriber.stop()
|
||||||
|
|||||||
@ -162,6 +162,7 @@ class AudioEventMaintainer(threading.Thread):
|
|||||||
# create communication for audio detections
|
# create communication for audio detections
|
||||||
self.requestor = InterProcessRequestor()
|
self.requestor = InterProcessRequestor()
|
||||||
self.config_subscriber = CameraConfigUpdateSubscriber(
|
self.config_subscriber = CameraConfigUpdateSubscriber(
|
||||||
|
None,
|
||||||
{self.camera_config.name: self.camera_config},
|
{self.camera_config.name: self.camera_config},
|
||||||
[
|
[
|
||||||
CameraConfigUpdateEnum.audio,
|
CameraConfigUpdateEnum.audio,
|
||||||
|
|||||||
@ -103,8 +103,10 @@ def output_frames(
|
|||||||
|
|
||||||
detection_subscriber = DetectionSubscriber(DetectionTypeEnum.video)
|
detection_subscriber = DetectionSubscriber(DetectionTypeEnum.video)
|
||||||
config_subscriber = CameraConfigUpdateSubscriber(
|
config_subscriber = CameraConfigUpdateSubscriber(
|
||||||
|
config,
|
||||||
config.cameras,
|
config.cameras,
|
||||||
[
|
[
|
||||||
|
CameraConfigUpdateEnum.add,
|
||||||
CameraConfigUpdateEnum.birdseye,
|
CameraConfigUpdateEnum.birdseye,
|
||||||
CameraConfigUpdateEnum.enabled,
|
CameraConfigUpdateEnum.enabled,
|
||||||
CameraConfigUpdateEnum.record,
|
CameraConfigUpdateEnum.record,
|
||||||
@ -135,7 +137,15 @@ def output_frames(
|
|||||||
|
|
||||||
while not stop_event.is_set():
|
while not stop_event.is_set():
|
||||||
# check if there is an updated config
|
# check if there is an updated config
|
||||||
config_subscriber.check_for_updates()
|
updates = config_subscriber.check_for_updates()
|
||||||
|
|
||||||
|
if "add" in updates:
|
||||||
|
for camera in updates["add"]:
|
||||||
|
jsmpeg_cameras[camera] = JsmpegCamera(
|
||||||
|
cam_config, stop_event, websocket_server
|
||||||
|
)
|
||||||
|
preview_recorders[camera] = PreviewRecorder(cam_config)
|
||||||
|
preview_write_times[camera] = 0
|
||||||
|
|
||||||
(topic, data) = detection_subscriber.check_for_update(timeout=1)
|
(topic, data) = detection_subscriber.check_for_update(timeout=1)
|
||||||
now = datetime.datetime.now().timestamp()
|
now = datetime.datetime.now().timestamp()
|
||||||
|
|||||||
@ -75,7 +75,9 @@ class RecordingMaintainer(threading.Thread):
|
|||||||
# create communication for retained recordings
|
# create communication for retained recordings
|
||||||
self.requestor = InterProcessRequestor()
|
self.requestor = InterProcessRequestor()
|
||||||
self.config_subscriber = CameraConfigUpdateSubscriber(
|
self.config_subscriber = CameraConfigUpdateSubscriber(
|
||||||
self.config.cameras, [CameraConfigUpdateEnum.record]
|
self.config,
|
||||||
|
self.config.cameras,
|
||||||
|
[CameraConfigUpdateEnum.add, CameraConfigUpdateEnum.record],
|
||||||
)
|
)
|
||||||
self.detection_subscriber = DetectionSubscriber(DetectionTypeEnum.all)
|
self.detection_subscriber = DetectionSubscriber(DetectionTypeEnum.all)
|
||||||
self.recordings_publisher = RecordingsDataPublisher(
|
self.recordings_publisher = RecordingsDataPublisher(
|
||||||
|
|||||||
@ -154,10 +154,13 @@ class ReviewSegmentMaintainer(threading.Thread):
|
|||||||
# create communication for review segments
|
# create communication for review segments
|
||||||
self.requestor = InterProcessRequestor()
|
self.requestor = InterProcessRequestor()
|
||||||
self.config_subscriber = CameraConfigUpdateSubscriber(
|
self.config_subscriber = CameraConfigUpdateSubscriber(
|
||||||
|
config,
|
||||||
config.cameras,
|
config.cameras,
|
||||||
[
|
[
|
||||||
|
CameraConfigUpdateEnum.add,
|
||||||
CameraConfigUpdateEnum.enabled,
|
CameraConfigUpdateEnum.enabled,
|
||||||
CameraConfigUpdateEnum.record,
|
CameraConfigUpdateEnum.record,
|
||||||
|
CameraConfigUpdateEnum.remove,
|
||||||
CameraConfigUpdateEnum.review,
|
CameraConfigUpdateEnum.review,
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|||||||
@ -67,6 +67,7 @@ class TrackedObjectProcessor(threading.Thread):
|
|||||||
self.ptz_autotracker_thread = ptz_autotracker_thread
|
self.ptz_autotracker_thread = ptz_autotracker_thread
|
||||||
|
|
||||||
self.camera_config_subscriber = CameraConfigUpdateSubscriber(
|
self.camera_config_subscriber = CameraConfigUpdateSubscriber(
|
||||||
|
self.config,
|
||||||
self.config.cameras,
|
self.config.cameras,
|
||||||
[
|
[
|
||||||
CameraConfigUpdateEnum.add,
|
CameraConfigUpdateEnum.add,
|
||||||
|
|||||||
@ -116,7 +116,7 @@ def capture_frames(
|
|||||||
skipped_eps = EventsPerSecond()
|
skipped_eps = EventsPerSecond()
|
||||||
skipped_eps.start()
|
skipped_eps.start()
|
||||||
config_subscriber = CameraConfigUpdateSubscriber(
|
config_subscriber = CameraConfigUpdateSubscriber(
|
||||||
{config.name: config}, [CameraConfigUpdateEnum.enabled]
|
None, {config.name: config}, [CameraConfigUpdateEnum.enabled]
|
||||||
)
|
)
|
||||||
|
|
||||||
def get_enabled_state():
|
def get_enabled_state():
|
||||||
@ -196,7 +196,7 @@ class CameraWatchdog(threading.Thread):
|
|||||||
self.sleeptime = self.config.ffmpeg.retry_interval
|
self.sleeptime = self.config.ffmpeg.retry_interval
|
||||||
|
|
||||||
self.config_subscriber = CameraConfigUpdateSubscriber(
|
self.config_subscriber = CameraConfigUpdateSubscriber(
|
||||||
{config.name: config}, [CameraConfigUpdateEnum.enabled]
|
None, {config.name: config}, [CameraConfigUpdateEnum.enabled]
|
||||||
)
|
)
|
||||||
self.was_enabled = self.config.enabled
|
self.was_enabled = self.config.enabled
|
||||||
|
|
||||||
@ -596,6 +596,7 @@ def process_frames(
|
|||||||
):
|
):
|
||||||
next_region_update = get_tomorrow_at_time(2)
|
next_region_update = get_tomorrow_at_time(2)
|
||||||
config_subscriber = CameraConfigUpdateSubscriber(
|
config_subscriber = CameraConfigUpdateSubscriber(
|
||||||
|
None,
|
||||||
{camera_name: camera_config},
|
{camera_name: camera_config},
|
||||||
[
|
[
|
||||||
CameraConfigUpdateEnum.detect,
|
CameraConfigUpdateEnum.detect,
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user