diff --git a/frigate/http.py b/frigate/http.py
index a4bc5ffc1..f2731ec2f 100644
--- a/frigate/http.py
+++ b/frigate/http.py
@@ -616,8 +616,8 @@ def event_preview(id: str, max_cache_age=2592000):
)
start_ts = event.start_time
- end_ts = (
- start_ts + min(event.end_time - event.start_time, 20) if event.end_time else 20
+ end_ts = start_ts + (
+ min(event.end_time - event.start_time, 20) if event.end_time else 20
)
if datetime.fromtimestamp(event.start_time) < datetime.now().replace(
diff --git a/frigate/util/services.py b/frigate/util/services.py
index fa8622210..b9b8ceace 100644
--- a/frigate/util/services.py
+++ b/frigate/util/services.py
@@ -103,8 +103,17 @@ def get_cpu_stats() -> dict[str, dict]:
docker_memlimit = get_docker_memlimit_bytes() / 1024
total_mem = os.sysconf("SC_PAGE_SIZE") * os.sysconf("SC_PHYS_PAGES") / 1024
+ system_cpu = psutil.cpu_percent(
+ interval=None
+ ) # no interval as we don't want to be blocking
+ system_mem = psutil.virtual_memory()
+ usages["frigate.full_system"] = {
+ "cpu": str(system_cpu),
+ "mem": str(system_mem.percent),
+ }
+
for process in psutil.process_iter(["pid", "name", "cpu_percent", "cmdline"]):
- pid = process.info["pid"]
+ pid = str(process.info["pid"])
try:
cpu_percent = process.info["cpu_percent"]
cmdline = process.info["cmdline"]
diff --git a/web/src/App.tsx b/web/src/App.tsx
index 2ad151c0f..af3483004 100644
--- a/web/src/App.tsx
+++ b/web/src/App.tsx
@@ -15,6 +15,8 @@ import NoMatch from "@/pages/NoMatch";
import Settings from "@/pages/Settings";
import UIPlayground from "./pages/UIPlayground";
import Events from "./pages/Events";
+import { isDesktop } from "react-device-detect";
+import Statusbar from "./components/Statusbar";
function App() {
const [sheetOpen, setSheetOpen] = useState(false);
@@ -30,9 +32,10 @@ function App() {
+ {isDesktop &&
}
-
+
);
diff --git a/web/src/components/Statusbar.tsx b/web/src/components/Statusbar.tsx
new file mode 100644
index 000000000..d2a038209
--- /dev/null
+++ b/web/src/components/Statusbar.tsx
@@ -0,0 +1,84 @@
+import { useFrigateStats } from "@/api/ws";
+import { FrigateStats } from "@/types/stats";
+import { useMemo } from "react";
+import { MdCircle } from "react-icons/md";
+import useSWR from "swr";
+
+export default function Statusbar({}) {
+ const { data: initialStats } = useSWR
("stats", {
+ revalidateOnFocus: false,
+ });
+ const { payload: latestStats } = useFrigateStats();
+ const stats = useMemo(() => {
+ if (latestStats) {
+ return latestStats;
+ }
+
+ return initialStats;
+ }, [initialStats, latestStats]);
+
+ const cpuPercent = useMemo(() => {
+ const systemCpu = stats?.cpu_usages["frigate.full_system"]?.cpu;
+
+ if (!systemCpu || systemCpu == "0.0") {
+ return null;
+ }
+
+ return parseInt(systemCpu);
+ }, [stats]);
+
+ return (
+
+ {cpuPercent && (
+
+
+ CPU {cpuPercent}%
+
+ )}
+ {Object.entries(stats?.gpu_usages || {}).map(([name, stats]) => {
+ if (name == "error-gpu") {
+ return;
+ }
+
+ let gpuTitle;
+ switch (name) {
+ case "amd-vaapi":
+ gpuTitle = "AMD GPU";
+ break;
+ case "intel-vaapi":
+ case "intel-qsv":
+ gpuTitle = "Intel GPU";
+ break;
+ default:
+ gpuTitle = name;
+ break;
+ }
+
+ const gpu = parseInt(stats.gpu);
+
+ return (
+
+
+ {gpuTitle} {gpu}%
+
+ );
+ })}
+
+ );
+}
diff --git a/web/src/pages/Live.tsx b/web/src/pages/Live.tsx
index fd13a4a9c..ed66a8e38 100644
--- a/web/src/pages/Live.tsx
+++ b/web/src/pages/Live.tsx
@@ -79,7 +79,7 @@ function Live() {
}, []);
return (
-
+
{events && events.length > 0 && (
diff --git a/web/src/types/stats.ts b/web/src/types/stats.ts
new file mode 100644
index 000000000..0ed34de14
--- /dev/null
+++ b/web/src/types/stats.ts
@@ -0,0 +1,60 @@
+export interface FrigateStats {
+ cameras: { [camera_name: string]: CameraStats };
+ cpu_usages: { [pid: string]: CpuStats };
+ detectors: { [detectorKey: string]: DetectorStats };
+ gpu_usages?: { [gpuKey: string]: GpuStats };
+ processes: { [processKey: string]: ExtraProcessStats };
+ service: ServiceStats;
+ detection_fps: number;
+ }
+
+ export type CameraStats = {
+ audio_dBFPS: number;
+ audio_rms: number;
+ camera_fps: number;
+ capture_pid: number;
+ detection_enabled: number;
+ detection_fps: number;
+ ffmpeg_pid: number;
+ pid: number;
+ process_fps: number;
+ skipped_fps: number;
+ };
+
+ export type CpuStats = {
+ cmdline: string;
+ cpu: string;
+ cpu_average: string;
+ mem: string;
+ };
+
+ export type DetectorStats = {
+ detection_start: number;
+ inference_speed: number;
+ pid: number;
+ };
+
+ export type ExtraProcessStats = {
+ pid: number;
+ };
+
+ export type GpuStats = {
+ gpu: string;
+ mem: string;
+ };
+
+ export type ServiceStats = {
+ last_updated: number;
+ storage: { [path: string]: StorageStats };
+ temperatures: { [apex: string]: number };
+ update: number;
+ latest_version: string;
+ version: string;
+ };
+
+ export type StorageStats = {
+ free: number;
+ total: number;
+ used: number;
+ mount_type: string;
+ };
\ No newline at end of file