From a13b9815f61089e13d678599e1cae398a18437d3 Mon Sep 17 00:00:00 2001 From: Nicolas Mowen Date: Mon, 4 Nov 2024 07:07:57 -0700 Subject: [PATCH] Various fixes (#14786) * Catch openvino error * Remove clip deletion * Update deletion text * Fix timeline not respecting timezone config * Tweaks * More timezone fixes * Fix * More timezone fixes * Fix shm docs --- docs/docs/frigate/installation.md | 14 +- frigate/api/event.py | 3 - frigate/app.py | 4 +- frigate/util/model.py | 33 ++- web/src/components/bar/TimelineBar.tsx | 191 ------------------ web/src/components/graph/CameraGraph.tsx | 15 +- web/src/components/graph/SystemGraph.tsx | 17 +- .../components/menu/SearchResultActions.tsx | 8 +- .../overlay/detail/ObjectLifecycle.tsx | 1 + .../components/timeline/segment-metadata.tsx | 46 +++-- web/src/hooks/use-draggable-element.ts | 28 ++- 11 files changed, 103 insertions(+), 257 deletions(-) delete mode 100644 web/src/components/bar/TimelineBar.tsx diff --git a/docs/docs/frigate/installation.md b/docs/docs/frigate/installation.md index 10c83b013..e3599e628 100644 --- a/docs/docs/frigate/installation.md +++ b/docs/docs/frigate/installation.md @@ -81,15 +81,15 @@ You can calculate the **minimum** shm size for each camera with the following fo ```console # Replace and -$ python -c 'print("{:.2f}MB".format(( * * 1.5 * 10 + 270480) / 1048576))' +$ python -c 'print("{:.2f}MB".format(( * * 1.5 * 20 + 270480) / 1048576))' -# Example for 1280x720 -$ python -c 'print("{:.2f}MB".format((1280 * 720 * 1.5 * 10 + 270480) / 1048576))' -13.44MB +# Example for 1280x720, including logs +$ python -c 'print("{:.2f}MB".format((1280 * 720 * 1.5 * 20 + 270480) / 1048576)) + 40' +46.63MB # Example for eight cameras detecting at 1280x720, including logs -$ python -c 'print("{:.2f}MB".format(((1280 * 720 * 1.5 * 10 + 270480) / 1048576) * 8 + 40))' -136.99MB +$ python -c 'print("{:.2f}MB".format(((1280 * 720 * 1.5 * 20 + 270480) / 1048576) * 8 + 40))' +253MB ``` The shm size cannot be set per container for Home Assistant add-ons. However, this is probably not required since by default Home Assistant Supervisor allocates `/dev/shm` with half the size of your total memory. If your machine has 8GB of memory, chances are that Frigate will have access to up to 4GB without any additional configuration. @@ -194,7 +194,7 @@ services: privileged: true # this may not be necessary for all setups restart: unless-stopped image: ghcr.io/blakeblackshear/frigate:stable - shm_size: "64mb" # update for your cameras based on calculation above + shm_size: "512mb" # update for your cameras based on calculation above devices: - /dev/bus/usb:/dev/bus/usb # Passes the USB Coral, needs to be modified for other versions - /dev/apex_0:/dev/apex_0 # Passes a PCIe Coral, follow driver instructions here https://coral.ai/docs/m2/get-started/#2a-on-linux diff --git a/frigate/api/event.py b/frigate/api/event.py index 869b61aaf..ac414cdde 100644 --- a/frigate/api/event.py +++ b/frigate/api/event.py @@ -1042,9 +1042,6 @@ def delete_event(request: Request, event_id: str): media.unlink(missing_ok=True) media = Path(f"{os.path.join(CLIPS_DIR, media_name)}-clean.png") media.unlink(missing_ok=True) - if event.has_clip: - media = Path(f"{os.path.join(CLIPS_DIR, media_name)}.mp4") - media.unlink(missing_ok=True) event.delete_instance() Timeline.delete().where(Timeline.source_id == event_id).execute() diff --git a/frigate/app.py b/frigate/app.py index 2f771ec4d..d0d3ab8a1 100644 --- a/frigate/app.py +++ b/frigate/app.py @@ -521,9 +521,9 @@ class FrigateApp: f"Calculated total camera size {available_shm} / {cam_total_frame_size} :: {shm_frame_count} frames for each camera in SHM" ) - if shm_frame_count < 10: + if shm_frame_count < 20: logger.warning( - f"The current SHM size of {total_shm}MB is too small, recommend increasing it to at least {round(min_req_shm + cam_total_frame_size * 10)}MB." + f"The current SHM size of {total_shm}MB is too small, recommend increasing it to at least {round(min_req_shm + cam_total_frame_size * 20)}MB." ) return shm_frame_count diff --git a/frigate/util/model.py b/frigate/util/model.py index 2aa06d0b2..091bb0833 100644 --- a/frigate/util/model.py +++ b/frigate/util/model.py @@ -1,5 +1,6 @@ """Model Utils""" +import logging import os from typing import Any @@ -11,6 +12,8 @@ except ImportError: # openvino is not included pass +logger = logging.getLogger(__name__) + def get_ort_providers( force_cpu: bool = False, device: str = "AUTO", requires_fp16: bool = False @@ -89,19 +92,27 @@ class ONNXModelRunner: self.ort: ort.InferenceSession = None self.ov: ov.Core = None providers, options = get_ort_providers(device == "CPU", device, requires_fp16) + self.interpreter = None if "OpenVINOExecutionProvider" in providers: - # use OpenVINO directly - self.type = "ov" - self.ov = ov.Core() - self.ov.set_property( - {ov.properties.cache_dir: "/config/model_cache/openvino"} - ) - self.interpreter = self.ov.compile_model( - model=model_path, device_name=device - ) - else: - # Use ONNXRuntime + try: + # use OpenVINO directly + self.type = "ov" + self.ov = ov.Core() + self.ov.set_property( + {ov.properties.cache_dir: "/config/model_cache/openvino"} + ) + self.interpreter = self.ov.compile_model( + model=model_path, device_name=device + ) + except Exception as e: + logger.warning( + f"OpenVINO failed to build model, using CPU instead: {e}" + ) + self.interpreter = None + + # Use ONNXRuntime + if self.interpreter is None: self.type = "ort" self.ort = ort.InferenceSession( model_path, diff --git a/web/src/components/bar/TimelineBar.tsx b/web/src/components/bar/TimelineBar.tsx deleted file mode 100644 index fe05b876f..000000000 --- a/web/src/components/bar/TimelineBar.tsx +++ /dev/null @@ -1,191 +0,0 @@ -import { FrigateConfig } from "@/types/frigateConfig"; -import { GraphDataPoint } from "@/types/graph"; -import { formatUnixTimestampToDateTime } from "@/utils/dateUtil"; -import useSWR from "swr"; -import ActivityIndicator from "../indicators/activity-indicator"; - -type TimelineBarProps = { - startTime: number; - graphData: - | { - objects: number[]; - motion: GraphDataPoint[]; - } - | undefined; - onClick?: () => void; -}; -export default function TimelineBar({ - startTime, - graphData, - onClick, -}: TimelineBarProps) { - const { data: config } = useSWR("config"); - - if (!config) { - return ; - } - - return ( -
- {graphData != undefined && ( -
- {getHourBlocks().map((idx) => { - return ( -
- ); - })} -
-
- {formatUnixTimestampToDateTime(startTime, { - strftime_fmt: - config?.ui.time_format == "24hour" ? "%H:00" : "%I:00%P", - time_style: "medium", - date_style: "medium", - })} -
-
-
-
- {formatUnixTimestampToDateTime(startTime, { - strftime_fmt: - config?.ui.time_format == "24hour" ? "%H:05" : "%I:05%P", - time_style: "medium", - date_style: "medium", - })} -
-
-
-
- {formatUnixTimestampToDateTime(startTime, { - strftime_fmt: - config?.ui.time_format == "24hour" ? "%H:10" : "%I:10%P", - time_style: "medium", - date_style: "medium", - })} -
-
-
-
- {formatUnixTimestampToDateTime(startTime, { - strftime_fmt: - config?.ui.time_format == "24hour" ? "%H:15" : "%I:15%P", - time_style: "medium", - date_style: "medium", - })} -
-
-
-
- {formatUnixTimestampToDateTime(startTime, { - strftime_fmt: - config?.ui.time_format == "24hour" ? "%H:20" : "%I:20%P", - time_style: "medium", - date_style: "medium", - })} -
-
-
-
- {formatUnixTimestampToDateTime(startTime, { - strftime_fmt: - config?.ui.time_format == "24hour" ? "%H:25" : "%I:25%P", - time_style: "medium", - date_style: "medium", - })} -
-
-
-
- {formatUnixTimestampToDateTime(startTime, { - strftime_fmt: - config?.ui.time_format == "24hour" ? "%H:30" : "%I:30%P", - time_style: "medium", - date_style: "medium", - })} -
-
-
-
- {formatUnixTimestampToDateTime(startTime, { - strftime_fmt: - config?.ui.time_format == "24hour" ? "%H:35" : "%I:35%P", - time_style: "medium", - date_style: "medium", - })} -
-
-
-
- {formatUnixTimestampToDateTime(startTime, { - strftime_fmt: - config?.ui.time_format == "24hour" ? "%H:40" : "%I:40%P", - time_style: "medium", - date_style: "medium", - })} -
-
-
-
- {formatUnixTimestampToDateTime(startTime, { - strftime_fmt: - config?.ui.time_format == "24hour" ? "%H:45" : "%I:45%P", - time_style: "medium", - date_style: "medium", - })} -
-
-
-
- {formatUnixTimestampToDateTime(startTime, { - strftime_fmt: - config?.ui.time_format == "24hour" ? "%H:50" : "%I:50%P", - time_style: "medium", - date_style: "medium", - })} -
-
-
-
- {formatUnixTimestampToDateTime(startTime, { - strftime_fmt: - config?.ui.time_format == "24hour" ? "%H:55" : "%I:55%P", - time_style: "medium", - date_style: "medium", - })} -
-
-
- )} -
- {formatUnixTimestampToDateTime(startTime, { - strftime_fmt: - config.ui.time_format == "24hour" ? "%m/%d %H:%M" : "%m/%d %I:%M%P", - time_style: "medium", - date_style: "medium", - })} -
-
- ); -} - -function getHourBlocks() { - const arr = []; - - for (let x = 0; x <= 59; x++) { - arr.push(x); - } - - return arr; -} diff --git a/web/src/components/graph/CameraGraph.tsx b/web/src/components/graph/CameraGraph.tsx index 3289887c5..ab5d6e03f 100644 --- a/web/src/components/graph/CameraGraph.tsx +++ b/web/src/components/graph/CameraGraph.tsx @@ -1,5 +1,6 @@ import { useTheme } from "@/context/theme-provider"; import { FrigateConfig } from "@/types/frigateConfig"; +import { formatUnixTimestampToDateTime } from "@/utils/dateUtil"; import { useCallback, useEffect, useMemo } from "react"; import Chart from "react-apexcharts"; import { isMobileOnly } from "react-device-detect"; @@ -42,12 +43,14 @@ export function CameraLineGraph({ const formatTime = useCallback( (val: unknown) => { - const date = new Date(updateTimes[Math.round(val as number)] * 1000); - return date.toLocaleTimeString([], { - hour12: config?.ui.time_format != "24hour", - hour: "2-digit", - minute: "2-digit", - }); + return formatUnixTimestampToDateTime( + updateTimes[Math.round(val as number)], + { + timezone: config?.ui.timezone, + strftime_fmt: + config?.ui.time_format == "24hour" ? "%H:%M" : "%I:%M %p", + }, + ); }, [config, updateTimes], ); diff --git a/web/src/components/graph/SystemGraph.tsx b/web/src/components/graph/SystemGraph.tsx index 572eae5cd..aaf838763 100644 --- a/web/src/components/graph/SystemGraph.tsx +++ b/web/src/components/graph/SystemGraph.tsx @@ -1,6 +1,7 @@ import { useTheme } from "@/context/theme-provider"; import { FrigateConfig } from "@/types/frigateConfig"; import { Threshold } from "@/types/graph"; +import { formatUnixTimestampToDateTime } from "@/utils/dateUtil"; import { useCallback, useEffect, useMemo } from "react"; import Chart from "react-apexcharts"; import { isMobileOnly } from "react-device-detect"; @@ -50,17 +51,17 @@ export function ThresholdBarGraph({ let timeOffset = 0; if (dateIndex < 0) { - timeOffset = 5000 * Math.abs(dateIndex); + timeOffset = 5 * Math.abs(dateIndex); } - const date = new Date( - updateTimes[Math.max(1, dateIndex) - 1] * 1000 - timeOffset, + return formatUnixTimestampToDateTime( + updateTimes[Math.max(1, dateIndex) - 1] - timeOffset, + { + timezone: config?.ui.timezone, + strftime_fmt: + config?.ui.time_format == "24hour" ? "%H:%M" : "%I:%M %p", + }, ); - return date.toLocaleTimeString([], { - hour12: config?.ui.time_format != "24hour", - hour: "2-digit", - minute: "2-digit", - }); }, [config, updateTimes], ); diff --git a/web/src/components/menu/SearchResultActions.tsx b/web/src/components/menu/SearchResultActions.tsx index 8a9373bcc..a07d27240 100644 --- a/web/src/components/menu/SearchResultActions.tsx +++ b/web/src/components/menu/SearchResultActions.tsx @@ -159,7 +159,13 @@ export default function SearchResultActions({ Confirm Delete - Are you sure you want to delete this tracked object? + Deleting this tracked object removes the snapshot, any saved + embeddings, and any associated object lifecycle entries. Recorded + footage of this tracked object in History view will NOT be + deleted. +
+
+ Are you sure you want to proceed?
Cancel diff --git a/web/src/components/overlay/detail/ObjectLifecycle.tsx b/web/src/components/overlay/detail/ObjectLifecycle.tsx index d687915ca..7a667529e 100644 --- a/web/src/components/overlay/detail/ObjectLifecycle.tsx +++ b/web/src/components/overlay/detail/ObjectLifecycle.tsx @@ -427,6 +427,7 @@ export default function ObjectLifecycle({
{formatUnixTimestampToDateTime(item.timestamp, { + timezone: config.ui.timezone, strftime_fmt: config.ui.time_format == "24hour" ? "%d %b %H:%M:%S" diff --git a/web/src/components/timeline/segment-metadata.tsx b/web/src/components/timeline/segment-metadata.tsx index 6ca71af24..3e3c99393 100644 --- a/web/src/components/timeline/segment-metadata.tsx +++ b/web/src/components/timeline/segment-metadata.tsx @@ -1,4 +1,6 @@ import { FrigateConfig } from "@/types/frigateConfig"; +import { formatUnixTimestampToDateTime } from "@/utils/dateUtil"; +import { useMemo } from "react"; import useSWR from "swr"; type MinimapSegmentProps = { @@ -40,22 +42,22 @@ export function MinimapBounds({ className="pointer-events-none absolute inset-0 -bottom-7 z-20 flex w-full select-none scroll-mt-8 items-center justify-center text-center text-[10px] font-medium text-primary" ref={firstMinimapSegmentRef} > - {new Date(alignedMinimapStartTime * 1000).toLocaleTimeString([], { - hour12: config?.ui.time_format != "24hour", - hour: "2-digit", - minute: "2-digit", - ...(!dense && { month: "short", day: "2-digit" }), + {formatUnixTimestampToDateTime(alignedMinimapStartTime, { + timezone: config?.ui.timezone, + strftime_fmt: !dense + ? `%b %d, ${config?.ui.time_format == "24hour" ? "%H:%M" : "%I:%M %p"}` + : `${config?.ui.time_format == "24hour" ? "%H:%M" : "%I:%M %p"}`, })}
)} {isLastSegmentInMinimap && (
- {new Date(alignedMinimapEndTime * 1000).toLocaleTimeString([], { - hour12: config?.ui.time_format != "24hour", - hour: "2-digit", - minute: "2-digit", - ...(!dense && { month: "short", day: "2-digit" }), + {formatUnixTimestampToDateTime(alignedMinimapEndTime, { + timezone: config?.ui.timezone, + strftime_fmt: !dense + ? `%b %d, ${config?.ui.time_format == "24hour" ? "%H:%M" : "%I:%M %p"}` + : `${config?.ui.time_format == "24hour" ? "%H:%M" : "%I:%M %p"}`, })}
)} @@ -92,6 +94,22 @@ export function Timestamp({ }: TimestampSegmentProps) { const { data: config } = useSWR("config"); + const formattedTimestamp = useMemo(() => { + if ( + !( + timestamp.getMinutes() % timestampSpread === 0 && + timestamp.getSeconds() === 0 + ) + ) { + return undefined; + } + + return formatUnixTimestampToDateTime(timestamp.getTime() / 1000, { + timezone: config?.ui.timezone, + strftime_fmt: config?.ui.time_format == "24hour" ? "%H:%M" : "%I:%M %p", + }); + }, [config, timestamp, timestampSpread]); + return (
{!isFirstSegmentInMinimap && !isLastSegmentInMinimap && ( @@ -99,13 +117,7 @@ export function Timestamp({ key={`${segmentKey}_timestamp`} className="pointer-events-none select-none text-[8px] text-neutral_variant dark:text-neutral" > - {timestamp.getMinutes() % timestampSpread === 0 && - timestamp.getSeconds() === 0 && - timestamp.toLocaleTimeString([], { - hour12: config?.ui.time_format != "24hour", - hour: "2-digit", - minute: "2-digit", - })} + {formattedTimestamp}
)} diff --git a/web/src/hooks/use-draggable-element.ts b/web/src/hooks/use-draggable-element.ts index 0168cd5a2..73013de58 100644 --- a/web/src/hooks/use-draggable-element.ts +++ b/web/src/hooks/use-draggable-element.ts @@ -10,6 +10,7 @@ import scrollIntoView from "scroll-into-view-if-needed"; import { useTimelineUtils } from "./use-timeline-utils"; import { FrigateConfig } from "@/types/frigateConfig"; import useSWR from "swr"; +import { formatUnixTimestampToDateTime } from "@/utils/dateUtil"; type DraggableElementProps = { contentRef: React.RefObject; @@ -168,6 +169,19 @@ function useDraggableElement({ [segmentDuration, timelineStartAligned, segmentHeight], ); + const getFormattedTimestamp = useCallback( + (segmentStartTime: number) => { + return formatUnixTimestampToDateTime(segmentStartTime, { + timezone: config?.ui.timezone, + strftime_fmt: + config?.ui.time_format == "24hour" + ? `%H:%M${segmentDuration < 60 && !dense ? ":%S" : ""}` + : `%I:%M${segmentDuration < 60 && !dense ? ":%S" : ""} %p`, + }); + }, + [config, dense, segmentDuration], + ); + const updateDraggableElementPosition = useCallback( ( newElementPosition: number, @@ -184,14 +198,8 @@ function useDraggableElement({ } if (draggableElementTimeRef.current) { - draggableElementTimeRef.current.textContent = new Date( - segmentStartTime * 1000, - ).toLocaleTimeString([], { - hour12: config?.ui.time_format != "24hour", - hour: "2-digit", - minute: "2-digit", - ...(segmentDuration < 60 && !dense && { second: "2-digit" }), - }); + draggableElementTimeRef.current.textContent = + getFormattedTimestamp(segmentStartTime); if (scrollTimeline && !userInteracting) { scrollIntoView(thumb, { block: "center", @@ -208,13 +216,11 @@ function useDraggableElement({ } }, [ - segmentDuration, draggableElementTimeRef, draggableElementRef, setDraggableElementTime, setDraggableElementPosition, - dense, - config, + getFormattedTimestamp, userInteracting, ], );