* 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 <nickmowen213@gmail.com>
This commit is contained in:
Josh Hawkins 2025-05-16 17:37:25 -05:00 committed by GitHub
parent 2f9b373c1a
commit ebae6cb1ed
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 31 additions and 9 deletions

View File

@ -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.

View File

@ -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

View File

@ -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()

View File

@ -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"]

View File

@ -191,6 +191,8 @@
"copyCoordinatesFailed": "Could not copy coordinates to clipboard."
}
},
"motionMaskLabel": "Motion Mask {{number}}",
"objectMaskLabel": "Object Mask {{number}} ({{label}})",
"form": {
"zoneName": {
"error": {

View File

@ -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(() => {

View File

@ -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),

View File

@ -520,7 +520,9 @@ export default function NotificationView({
<Button
aria-label={t("notification.registerDevice")}
disabled={
!config?.notifications.enabled || publicKey == undefined
(!config?.notifications.enabled &&
notificationCameras.length === 0) ||
publicKey == undefined
}
onClick={() => {
if (registration == null) {