diff --git a/frigate/app.py b/frigate/app.py index 81603b4e0..29a19f893 100644 --- a/frigate/app.py +++ b/frigate/app.py @@ -1,23 +1,17 @@ -import json import logging import multiprocessing as mp from multiprocessing.queues import Queue from multiprocessing.synchronize import Event -from multiprocessing.context import Process import os import signal import sys -import threading -from logging.handlers import QueueHandler from typing import Optional from types import FrameType import traceback -import yaml from peewee_migrate import Router from playhouse.sqlite_ext import SqliteExtDatabase from playhouse.sqliteq import SqliteQueueDatabase -from pydantic import ValidationError from frigate.config import DetectorTypeEnum, FrigateConfig from frigate.const import CACHE_DIR, CLIPS_DIR, RECORD_DIR @@ -32,6 +26,7 @@ from frigate.output import output_frames from frigate.plus import PlusApi from frigate.record import RecordingCleanup, RecordingMaintainer from frigate.stats import StatsEmitter, stats_init +from frigate.storage import StorageMaintainer from frigate.version import VERSION from frigate.video import capture_camera, track_camera from frigate.watchdog import FrigateWatchdog @@ -310,6 +305,12 @@ class FrigateApp: self.recording_cleanup = RecordingCleanup(self.config, self.stop_event) self.recording_cleanup.start() + def start_storage_maintainer(self) -> None: + self.storage_maintainer = StorageMaintainer( + self.config, self.stop_event + ) + self.storage_maintainer.start() + def start_stats_emitter(self) -> None: self.stats_emitter = StatsEmitter( self.config, @@ -369,6 +370,7 @@ class FrigateApp: self.start_event_cleanup() self.start_recording_maintainer() self.start_recording_cleanup() + self.start_storage_maintainer() self.start_stats_emitter() self.start_watchdog() # self.zeroconf = broadcast_zeroconf(self.config.mqtt.client_id) diff --git a/frigate/storage.py b/frigate/storage.py index 0a2d96aca..8574cc03a 100644 --- a/frigate/storage.py +++ b/frigate/storage.py @@ -1,6 +1,45 @@ """Handle storage retention and usage.""" +import logging import threading +from peewee import SqliteDatabase, operator, fn, DoesNotExist + +from frigate.config import FrigateConfig +from frigate.models import Recordings + +logger = logging.getLogger(__name__) + + class StorageMaintainer(threading.Thread): - """Maintain frigates recording storage.""" \ No newline at end of file + """Maintain frigates recording storage.""" + + def __init__(self, config: FrigateConfig, stop_event): + threading.Thread.__init__(self) + self.name = "recording_cleanup" + self.config = config + self.stop_event = stop_event + self.avg_segment_sizes = {} + + def calculate_camera_segment_sizes(self): + """Calculate the size of each cameras recording segments over the last hour.""" + for camera in self.config.cameras.keys(): + if not self.config.cameras[camera].record.enabled: + continue + + self.avg_segment_sizes[camera] = ( + Recordings.select(fn.AVG(Recordings.segment_size)) + .where(Recordings.camera == camera) + .where(Recordings.segment_size != 0) + .scalar() + ) + + def run(self): + # Check storage consumption every 5 minutes + while not self.stop_event.wait(20): + + if not self.avg_segment_sizes: + self.calculate_camera_segment_sizes() + logger.debug(f"Default camera segment sizes: {self.avg_segment_sizes}") + + logger.info(f"Exiting storage maintainer...")