From ebae6cb1edef1dfe770a9cf5167775d59231f227 Mon Sep 17 00:00:00 2001 From: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com> Date: Fri, 16 May 2025 17:37:25 -0500 Subject: [PATCH] Fixes (#18262) * Don't use timezone in export dialog timestamps Revert an unnecessary change made in https://github.com/blakeblackshear/frigate/pull/18257 * Ensure notifications register button is only disabled when both all cameras and every individual camera is disabled * Send test notification if any cameras are enabled * clarify docs about disabling cameras * fix crash in autotracking zoom * clean up * masks and zones i18n fixes * Check if camera is enabled in config --------- Co-authored-by: Nicolas Mowen --- docs/docs/configuration/live.md | 6 ++++++ frigate/app.py | 4 ++-- frigate/comms/webpush.py | 7 ++++++- frigate/ptz/autotrack.py | 1 + web/public/locales/en/views/settings.json | 2 ++ web/src/components/overlay/ExportDialog.tsx | 2 -- web/src/views/settings/MasksAndZonesView.tsx | 14 +++++++++++--- .../views/settings/NotificationsSettingsView.tsx | 4 +++- 8 files changed, 31 insertions(+), 9 deletions(-) diff --git a/docs/docs/configuration/live.md b/docs/docs/configuration/live.md index cdf2d537d..611922d84 100644 --- a/docs/docs/configuration/live.md +++ b/docs/docs/configuration/live.md @@ -197,6 +197,12 @@ The default dashboard ("All Cameras") will always use Smart Streaming and the fi Cameras can be temporarily disabled through the Frigate UI and through [MQTT](/integrations/mqtt#frigatecamera_nameenabledset) to conserve system resources. When disabled, Frigate's ffmpeg processes are terminated — recording stops, object detection is paused, and the Live dashboard displays a blank image with a disabled message. Review items, tracked objects, and historical footage for disabled cameras can still be accessed via the UI. +:::note + +Disabling a camera via the Frigate UI or MQTT is temporary and does not persist through restarts of Frigate. + +::: + For restreamed cameras, go2rtc remains active but does not use system resources for decoding or processing unless there are active external consumers (such as the Advanced Camera Card in Home Assistant using a go2rtc source). Note that disabling a camera through the config file (`enabled: False`) removes all related UI elements, including historical footage access. To retain access while disabling the camera, keep it enabled in the config and use the UI or MQTT to disable it temporarily. diff --git a/frigate/app.py b/frigate/app.py index ac3e6d7da..703877f6d 100644 --- a/frigate/app.py +++ b/frigate/app.py @@ -438,7 +438,7 @@ class FrigateApp: def start_camera_processors(self) -> None: for name, config in self.config.cameras.items(): - if not self.config.cameras[name].enabled: + if not self.config.cameras[name].enabled_in_config: logger.info(f"Camera processor not started for disabled camera {name}") continue @@ -467,7 +467,7 @@ class FrigateApp: shm_frame_count = self.shm_frame_count() for name, config in self.config.cameras.items(): - if not self.config.cameras[name].enabled: + if not self.config.cameras[name].enabled_in_config: logger.info(f"Capture process not started for disabled camera {name}") continue diff --git a/frigate/comms/webpush.py b/frigate/comms/webpush.py index cbc274aef..47b0bafc7 100644 --- a/frigate/comms/webpush.py +++ b/frigate/comms/webpush.py @@ -173,7 +173,12 @@ class WebPushClient(Communicator): # type: ignore[misc] return self.send_alert(decoded) elif topic == "notification_test": - if not self.config.notifications.enabled: + if not self.config.notifications.enabled and not any( + cam.notifications.enabled for cam in self.config.cameras.values() + ): + logger.debug( + "No cameras have notifications enabled, test notification not sent" + ) return self.send_notification_test() diff --git a/frigate/ptz/autotrack.py b/frigate/ptz/autotrack.py index f9fb70d4f..f38bf1f5f 100644 --- a/frigate/ptz/autotrack.py +++ b/frigate/ptz/autotrack.py @@ -1109,6 +1109,7 @@ class PtzAutoTracker: camera_height = camera_config.frame_shape[0] camera_fps = camera_config.detect.fps predicted_movement_time = 0 + zoom_distance = 0 average_velocity = np.zeros((4,)) predicted_box = obj.obj_data["box"] diff --git a/web/public/locales/en/views/settings.json b/web/public/locales/en/views/settings.json index d5f9e140d..7b604cc6e 100644 --- a/web/public/locales/en/views/settings.json +++ b/web/public/locales/en/views/settings.json @@ -191,6 +191,8 @@ "copyCoordinatesFailed": "Could not copy coordinates to clipboard." } }, + "motionMaskLabel": "Motion Mask {{number}}", + "objectMaskLabel": "Object Mask {{number}} ({{label}})", "form": { "zoneName": { "error": { diff --git a/web/src/components/overlay/ExportDialog.tsx b/web/src/components/overlay/ExportDialog.tsx index b1b9b9dc2..44b55bfe3 100644 --- a/web/src/components/overlay/ExportDialog.tsx +++ b/web/src/components/overlay/ExportDialog.tsx @@ -406,14 +406,12 @@ function CustomTimeSelector({ config?.ui.time_format == "24hour" ? t("time.formattedTimestamp.24hour", { ns: "common" }) : t("time.formattedTimestamp.12hour", { ns: "common" }), - config?.ui.timezone, ); const formattedEnd = useFormattedTimestamp( endTime, config?.ui.time_format == "24hour" ? t("time.formattedTimestamp.24hour", { ns: "common" }) : t("time.formattedTimestamp.12hour", { ns: "common" }), - config?.ui.timezone, ); const startClock = useMemo(() => { diff --git a/web/src/views/settings/MasksAndZonesView.tsx b/web/src/views/settings/MasksAndZonesView.tsx index a7836728b..2163bfa51 100644 --- a/web/src/views/settings/MasksAndZonesView.tsx +++ b/web/src/views/settings/MasksAndZonesView.tsx @@ -271,7 +271,9 @@ export default function MasksAndZonesView({ type: "motion_mask" as PolygonType, typeIndex: index, camera: cameraConfig.name, - name: `Motion Mask ${index + 1}`, + name: t("masksAndZones.motionMaskLabel", { + number: index + 1, + }), objects: [], points: interpolatePoints( parseCoordinates(maskData), @@ -295,7 +297,10 @@ export default function MasksAndZonesView({ type: "object_mask" as PolygonType, typeIndex: index, camera: cameraConfig.name, - name: `Object Mask ${index + 1} (all objects)`, + name: t("masksAndZones.objectMaskLabel", { + number: index + 1, + label: t("masksAndZones.zones.allObjects"), + }), objects: [], points: interpolatePoints( parseCoordinates(maskData), @@ -322,7 +327,10 @@ export default function MasksAndZonesView({ type: "object_mask" as PolygonType, typeIndex: subIndex, camera: cameraConfig.name, - name: `Object Mask ${globalObjectMasksCount + index + 1} (${objectName})`, + name: t("masksAndZones.objectMaskLabel", { + number: globalObjectMasksCount + index + 1, + label: t(objectName, { ns: "objects" }), + }), objects: [objectName], points: interpolatePoints( parseCoordinates(maskItem), diff --git a/web/src/views/settings/NotificationsSettingsView.tsx b/web/src/views/settings/NotificationsSettingsView.tsx index f3476decf..2201f9734 100644 --- a/web/src/views/settings/NotificationsSettingsView.tsx +++ b/web/src/views/settings/NotificationsSettingsView.tsx @@ -520,7 +520,9 @@ export default function NotificationView({