mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-07-29 15:19:00 +03:00
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:
committed by
Blake Blackshear
parent
b7dbcce6e5
commit
dc187eee1c
+64
-19
@@ -8,9 +8,13 @@ from typing import Any, Callable, Optional
|
||||
from frigate.camera import PTZMetrics
|
||||
from frigate.camera.activity_manager import CameraActivityManager
|
||||
from frigate.comms.base_communicator import Communicator
|
||||
from frigate.comms.config_updater import ConfigPublisher
|
||||
from frigate.comms.webpush import WebPushClient
|
||||
from frigate.config import BirdseyeModeEnum, FrigateConfig
|
||||
from frigate.config.camera.updater import (
|
||||
CameraConfigUpdateEnum,
|
||||
CameraConfigUpdatePublisher,
|
||||
CameraConfigUpdateTopic,
|
||||
)
|
||||
from frigate.const import (
|
||||
CLEAR_ONGOING_REVIEW_SEGMENTS,
|
||||
INSERT_MANY_RECORDINGS,
|
||||
@@ -38,7 +42,7 @@ class Dispatcher:
|
||||
def __init__(
|
||||
self,
|
||||
config: FrigateConfig,
|
||||
config_updater: ConfigPublisher,
|
||||
config_updater: CameraConfigUpdatePublisher,
|
||||
onvif: OnvifController,
|
||||
ptz_metrics: dict[str, PTZMetrics],
|
||||
communicators: list[Communicator],
|
||||
@@ -273,8 +277,11 @@ class Dispatcher:
|
||||
f"Turning on motion for {camera_name} due to detection being enabled."
|
||||
)
|
||||
motion_settings.enabled = True
|
||||
self.config_updater.publish(
|
||||
f"config/motion/{camera_name}", motion_settings
|
||||
self.config_updater.publish_update(
|
||||
CameraConfigUpdateTopic(
|
||||
CameraConfigUpdateEnum.motion, camera_name
|
||||
),
|
||||
motion_settings,
|
||||
)
|
||||
self.publish(f"{camera_name}/motion/state", payload, retain=True)
|
||||
elif payload == "OFF":
|
||||
@@ -303,7 +310,10 @@ class Dispatcher:
|
||||
logger.info(f"Turning off camera {camera_name}")
|
||||
camera_settings.enabled = False
|
||||
|
||||
self.config_updater.publish(f"config/enabled/{camera_name}", camera_settings)
|
||||
self.config_updater.publish_update(
|
||||
CameraConfigUpdateTopic(CameraConfigUpdateEnum.enabled, camera_name),
|
||||
camera_settings.enabled,
|
||||
)
|
||||
self.publish(f"{camera_name}/enabled/state", payload, retain=True)
|
||||
|
||||
def _on_motion_command(self, camera_name: str, payload: str) -> None:
|
||||
@@ -326,7 +336,10 @@ class Dispatcher:
|
||||
logger.info(f"Turning off motion for {camera_name}")
|
||||
motion_settings.enabled = False
|
||||
|
||||
self.config_updater.publish(f"config/motion/{camera_name}", motion_settings)
|
||||
self.config_updater.publish_update(
|
||||
CameraConfigUpdateTopic(CameraConfigUpdateEnum.motion, camera_name),
|
||||
motion_settings,
|
||||
)
|
||||
self.publish(f"{camera_name}/motion/state", payload, retain=True)
|
||||
|
||||
def _on_motion_improve_contrast_command(
|
||||
@@ -344,7 +357,10 @@ class Dispatcher:
|
||||
logger.info(f"Turning off improve contrast for {camera_name}")
|
||||
motion_settings.improve_contrast = False # type: ignore[union-attr]
|
||||
|
||||
self.config_updater.publish(f"config/motion/{camera_name}", motion_settings)
|
||||
self.config_updater.publish_update(
|
||||
CameraConfigUpdateTopic(CameraConfigUpdateEnum.motion, camera_name),
|
||||
motion_settings,
|
||||
)
|
||||
self.publish(f"{camera_name}/improve_contrast/state", payload, retain=True)
|
||||
|
||||
def _on_ptz_autotracker_command(self, camera_name: str, payload: str) -> None:
|
||||
@@ -384,7 +400,10 @@ class Dispatcher:
|
||||
motion_settings = self.config.cameras[camera_name].motion
|
||||
logger.info(f"Setting motion contour area for {camera_name}: {payload}")
|
||||
motion_settings.contour_area = payload # type: ignore[union-attr]
|
||||
self.config_updater.publish(f"config/motion/{camera_name}", motion_settings)
|
||||
self.config_updater.publish_update(
|
||||
CameraConfigUpdateTopic(CameraConfigUpdateEnum.motion, camera_name),
|
||||
motion_settings,
|
||||
)
|
||||
self.publish(f"{camera_name}/motion_contour_area/state", payload, retain=True)
|
||||
|
||||
def _on_motion_threshold_command(self, camera_name: str, payload: int) -> None:
|
||||
@@ -398,7 +417,10 @@ class Dispatcher:
|
||||
motion_settings = self.config.cameras[camera_name].motion
|
||||
logger.info(f"Setting motion threshold for {camera_name}: {payload}")
|
||||
motion_settings.threshold = payload # type: ignore[union-attr]
|
||||
self.config_updater.publish(f"config/motion/{camera_name}", motion_settings)
|
||||
self.config_updater.publish_update(
|
||||
CameraConfigUpdateTopic(CameraConfigUpdateEnum.motion, camera_name),
|
||||
motion_settings,
|
||||
)
|
||||
self.publish(f"{camera_name}/motion_threshold/state", payload, retain=True)
|
||||
|
||||
def _on_global_notification_command(self, payload: str) -> None:
|
||||
@@ -410,8 +432,8 @@ class Dispatcher:
|
||||
notification_settings = self.config.notifications
|
||||
logger.info(f"Setting all notifications: {payload}")
|
||||
notification_settings.enabled = payload == "ON" # type: ignore[union-attr]
|
||||
self.config_updater.publish(
|
||||
"config/notifications", {"_global_notifications": notification_settings}
|
||||
self.config_updater.publisher.publish(
|
||||
"config/notifications", notification_settings
|
||||
)
|
||||
self.publish("notifications/state", payload, retain=True)
|
||||
|
||||
@@ -434,7 +456,10 @@ class Dispatcher:
|
||||
logger.info(f"Turning off audio detection for {camera_name}")
|
||||
audio_settings.enabled = False
|
||||
|
||||
self.config_updater.publish(f"config/audio/{camera_name}", audio_settings)
|
||||
self.config_updater.publish_update(
|
||||
CameraConfigUpdateTopic(CameraConfigUpdateEnum.audio, camera_name),
|
||||
audio_settings,
|
||||
)
|
||||
self.publish(f"{camera_name}/audio/state", payload, retain=True)
|
||||
|
||||
def _on_recordings_command(self, camera_name: str, payload: str) -> None:
|
||||
@@ -456,7 +481,10 @@ class Dispatcher:
|
||||
logger.info(f"Turning off recordings for {camera_name}")
|
||||
record_settings.enabled = False
|
||||
|
||||
self.config_updater.publish(f"config/record/{camera_name}", record_settings)
|
||||
self.config_updater.publish_update(
|
||||
CameraConfigUpdateTopic(CameraConfigUpdateEnum.record, camera_name),
|
||||
record_settings,
|
||||
)
|
||||
self.publish(f"{camera_name}/recordings/state", payload, retain=True)
|
||||
|
||||
def _on_snapshots_command(self, camera_name: str, payload: str) -> None:
|
||||
@@ -472,6 +500,10 @@ class Dispatcher:
|
||||
logger.info(f"Turning off snapshots for {camera_name}")
|
||||
snapshots_settings.enabled = False
|
||||
|
||||
self.config_updater.publish_update(
|
||||
CameraConfigUpdateTopic(CameraConfigUpdateEnum.snapshots, camera_name),
|
||||
snapshots_settings,
|
||||
)
|
||||
self.publish(f"{camera_name}/snapshots/state", payload, retain=True)
|
||||
|
||||
def _on_ptz_command(self, camera_name: str, payload: str) -> None:
|
||||
@@ -506,7 +538,10 @@ class Dispatcher:
|
||||
logger.info(f"Turning off birdseye for {camera_name}")
|
||||
birdseye_settings.enabled = False
|
||||
|
||||
self.config_updater.publish(f"config/birdseye/{camera_name}", birdseye_settings)
|
||||
self.config_updater.publish_update(
|
||||
CameraConfigUpdateTopic(CameraConfigUpdateEnum.birdseye, camera_name),
|
||||
birdseye_settings,
|
||||
)
|
||||
self.publish(f"{camera_name}/birdseye/state", payload, retain=True)
|
||||
|
||||
def _on_birdseye_mode_command(self, camera_name: str, payload: str) -> None:
|
||||
@@ -527,7 +562,10 @@ class Dispatcher:
|
||||
f"Setting birdseye mode for {camera_name} to {birdseye_settings.mode}"
|
||||
)
|
||||
|
||||
self.config_updater.publish(f"config/birdseye/{camera_name}", birdseye_settings)
|
||||
self.config_updater.publish_update(
|
||||
CameraConfigUpdateTopic(CameraConfigUpdateEnum.birdseye, camera_name),
|
||||
birdseye_settings,
|
||||
)
|
||||
self.publish(f"{camera_name}/birdseye_mode/state", payload, retain=True)
|
||||
|
||||
def _on_camera_notification_command(self, camera_name: str, payload: str) -> None:
|
||||
@@ -559,8 +597,9 @@ class Dispatcher:
|
||||
):
|
||||
self.web_push_client.suspended_cameras[camera_name] = 0
|
||||
|
||||
self.config_updater.publish(
|
||||
"config/notifications", {camera_name: notification_settings}
|
||||
self.config_updater.publish_update(
|
||||
CameraConfigUpdateTopic(CameraConfigUpdateEnum.notifications, camera_name),
|
||||
notification_settings,
|
||||
)
|
||||
self.publish(f"{camera_name}/notifications/state", payload, retain=True)
|
||||
self.publish(f"{camera_name}/notifications/suspended", "0", retain=True)
|
||||
@@ -617,7 +656,10 @@ class Dispatcher:
|
||||
logger.info(f"Turning off alerts for {camera_name}")
|
||||
review_settings.alerts.enabled = False
|
||||
|
||||
self.config_updater.publish(f"config/review/{camera_name}", review_settings)
|
||||
self.config_updater.publish_update(
|
||||
CameraConfigUpdateTopic(CameraConfigUpdateEnum.review, camera_name),
|
||||
review_settings,
|
||||
)
|
||||
self.publish(f"{camera_name}/review_alerts/state", payload, retain=True)
|
||||
|
||||
def _on_detections_command(self, camera_name: str, payload: str) -> None:
|
||||
@@ -639,5 +681,8 @@ class Dispatcher:
|
||||
logger.info(f"Turning off detections for {camera_name}")
|
||||
review_settings.detections.enabled = False
|
||||
|
||||
self.config_updater.publish(f"config/review/{camera_name}", review_settings)
|
||||
self.config_updater.publish_update(
|
||||
CameraConfigUpdateTopic(CameraConfigUpdateEnum.review, camera_name),
|
||||
review_settings,
|
||||
)
|
||||
self.publish(f"{camera_name}/review_detections/state", payload, retain=True)
|
||||
|
||||
@@ -17,6 +17,10 @@ from titlecase import titlecase
|
||||
from frigate.comms.base_communicator import Communicator
|
||||
from frigate.comms.config_updater import ConfigSubscriber
|
||||
from frigate.config import FrigateConfig
|
||||
from frigate.config.camera.updater import (
|
||||
CameraConfigUpdateEnum,
|
||||
CameraConfigUpdateSubscriber,
|
||||
)
|
||||
from frigate.const import CONFIG_DIR
|
||||
from frigate.models import User
|
||||
|
||||
@@ -73,7 +77,12 @@ class WebPushClient(Communicator): # type: ignore[misc]
|
||||
self.web_pushers[user["username"]].append(WebPusher(sub))
|
||||
|
||||
# notification config updater
|
||||
self.config_subscriber = ConfigSubscriber("config/notifications")
|
||||
self.global_config_subscriber = ConfigSubscriber(
|
||||
"config/notifications", exact=True
|
||||
)
|
||||
self.config_subscriber = CameraConfigUpdateSubscriber(
|
||||
self.config.cameras, [CameraConfigUpdateEnum.notifications]
|
||||
)
|
||||
|
||||
def subscribe(self, receiver: Callable) -> None:
|
||||
"""Wrapper for allowing dispatcher to subscribe."""
|
||||
@@ -154,15 +163,14 @@ class WebPushClient(Communicator): # type: ignore[misc]
|
||||
def publish(self, topic: str, payload: Any, retain: bool = False) -> None:
|
||||
"""Wrapper for publishing when client is in valid state."""
|
||||
# check for updated notification config
|
||||
_, updated_notification_config = self.config_subscriber.check_for_update()
|
||||
_, updated_notification_config = (
|
||||
self.global_config_subscriber.check_for_update()
|
||||
)
|
||||
|
||||
if updated_notification_config:
|
||||
for key, value in updated_notification_config.items():
|
||||
if key == "_global_notifications":
|
||||
self.config.notifications = value
|
||||
self.config.notifications = updated_notification_config
|
||||
|
||||
elif key in self.config.cameras:
|
||||
self.config.cameras[key].notifications = value
|
||||
self.config_subscriber.check_for_updates()
|
||||
|
||||
if topic == "reviews":
|
||||
decoded = json.loads(payload)
|
||||
|
||||
Reference in New Issue
Block a user