diff --git a/frigate/analytics/collectors/cameras.py b/frigate/analytics/collectors/cameras.py index ebc51d7d70..fe603c8c73 100644 --- a/frigate/analytics/collectors/cameras.py +++ b/frigate/analytics/collectors/cameras.py @@ -35,6 +35,7 @@ QUALITIES = frozenset(ConnectionQuality) def height_bucket(height: int) -> HeightBucket: + """The nearest standard resolution bucket for a detect height.""" for limit, bucket in HEIGHT_BUCKETS: if height <= limit: return bucket @@ -43,6 +44,7 @@ def height_bucket(height: int) -> HeightBucket: def fps_bucket(fps: int) -> FpsBucket: + """The bucket for a detect fps.""" if fps <= 5: return FpsBucket.le_5 @@ -53,6 +55,7 @@ def fps_bucket(fps: int) -> FpsBucket: def retain_bucket(days: float) -> RetainBucket: + """The bucket for a retention period in days.""" if days <= 0: return RetainBucket.zero @@ -77,6 +80,7 @@ def preset_key(args: str | list[str], enum: Any) -> Any: def is_restream(path: str) -> bool: + """Whether an input reads from the local go2rtc restream.""" try: url = urlsplit(path) return url.hostname in RESTREAM_HOSTS and url.port == RESTREAM_PORT @@ -85,11 +89,12 @@ def is_restream(path: str) -> bool: def role_input(camera: CameraConfig, role: CameraRoleEnum) -> CameraInput | None: + """The camera's first input with the given role.""" return next((i for i in camera.ffmpeg.inputs if role in i.roles), None) def object_masks(camera: CameraConfig) -> int: - # parsing copies camera-wide masks into every filter as global_ + """Camera and per-label object masks, minus the global_ filter copies.""" own = sum(1 for mask in camera.objects.mask.values() if mask is not None) per_label = sum( 1 diff --git a/frigate/analytics/collectors/features.py b/frigate/analytics/collectors/features.py index 2f79738f51..1eca92af6f 100644 --- a/frigate/analytics/collectors/features.py +++ b/frigate/analytics/collectors/features.py @@ -50,6 +50,7 @@ def enrichment_device(label: object) -> EnrichmentDevice | None: def model_name(model: object) -> str | None: + """The model's config value as a string.""" if model is None: return None @@ -57,7 +58,7 @@ def model_name(model: object) -> str | None: def semantic_model(model: object) -> SemanticSearchModel | None: - # any string that isn't a built-in model names a GenAI provider + """A built-in Jina model, or genai for any GenAI provider name.""" name = model_name(model) if name is None: @@ -70,6 +71,7 @@ def semantic_model(model: object) -> SemanticSearchModel | None: def transcription_model(model: object) -> TranscriptionModel | None: + """Whisper, or genai for any GenAI provider name.""" name = model_name(model) if name is None: @@ -79,6 +81,7 @@ def transcription_model(model: object) -> TranscriptionModel | None: def users() -> dict[UserRole, int]: + """Count users by role, with any custom role counted as custom.""" roles: Counter[UserRole] = Counter( closed(UserRole, user.role, UserRole.custom) for user in User.select(User.role) ) diff --git a/frigate/analytics/collectors/hardware.py b/frigate/analytics/collectors/hardware.py index a0ea9839da..99037f3ac2 100644 --- a/frigate/analytics/collectors/hardware.py +++ b/frigate/analytics/collectors/hardware.py @@ -49,6 +49,7 @@ def cpu_model() -> str: def gpus(stats: dict[str, Any]) -> list[GpuInfo]: + """GPUs with a stats entry, by vendor and capped name.""" found: list[GpuInfo] = [] for name, entry in stats.get("gpu_usages", {}).items(): @@ -64,6 +65,7 @@ def gpus(stats: dict[str, Any]) -> list[GpuInfo]: def decode_families() -> list[DecodeFamily]: + """Hardware decode families the host supports.""" _, available = hwaccel_options() families = [ closed(DecodeFamily, family.key, DecodeFamily.other) for family in available @@ -72,6 +74,7 @@ def decode_families() -> list[DecodeFamily]: def detection_hardware() -> dict[HardwareKey, int]: + """Detection accelerators found by the hardware probe, by unit count.""" units: Counter[HardwareKey] = Counter() for found in hardware_prober.probe(): @@ -81,7 +84,10 @@ def detection_hardware() -> dict[HardwareKey, int]: def storage(stats: dict[str, Any]) -> StorageInfo: - # stats report sizes in MB + """Filesystem, size, and usage of the recordings volume. + + Stats report sizes in MB. + """ entry = stats.get("service", {}).get("storage", {}).get(RECORD_DIR) or {} total_mb = float(entry.get("total") or 0) used_mb = float(entry.get("used") or 0) diff --git a/frigate/analytics/collectors/install.py b/frigate/analytics/collectors/install.py index c2b7a45eee..45be1324b5 100644 --- a/frigate/analytics/collectors/install.py +++ b/frigate/analytics/collectors/install.py @@ -21,7 +21,7 @@ def image_variant(value: str | None) -> ImageVariant: def install_type() -> InstallType: - # the add-on is a container too, so it has to be checked first + """How Frigate runs; the add-on is a container too, so it's checked first.""" if os.path.isfile("/data/options.json"): return InstallType.ha_addon @@ -38,6 +38,7 @@ def install_type() -> InstallType: def arch(machine: str) -> Arch: + """The CPU architecture for a platform.machine() value.""" match machine.lower(): case "x86_64" | "amd64": return Arch.x86_64 @@ -48,6 +49,7 @@ def arch(machine: str) -> Arch: def kernel(release: str) -> str: + """The major.minor of a kernel release string, or unknown.""" match = KERNEL_PATTERN.match(release) return f"{match.group(1)}.{match.group(2)}" if match else "unknown" diff --git a/frigate/analytics/reporter.py b/frigate/analytics/reporter.py index aeb571d532..e77a5d952d 100644 --- a/frigate/analytics/reporter.py +++ b/frigate/analytics/reporter.py @@ -75,6 +75,7 @@ class AnalyticsReporter(threading.Thread): return INTERVAL_S + self.rng.uniform(-JITTER_S, JITTER_S) def run(self) -> None: + """Tick every wake until stopped; a failed tick never ends the thread.""" while True: try: self.tick() diff --git a/frigate/analytics/schema.py b/frigate/analytics/schema.py index 7f6053be16..cf1da36fdc 100644 --- a/frigate/analytics/schema.py +++ b/frigate/analytics/schema.py @@ -188,6 +188,7 @@ def metric(description: str, *, public: bool = True, **kwargs: Any) -> Any: def count(description: str) -> Any: + """Declare a non-negative count field.""" return metric(description, ge=0) diff --git a/generate_analytics_schema.py b/generate_analytics_schema.py index 4b2f008ff5..1fa52fa7c9 100644 --- a/generate_analytics_schema.py +++ b/generate_analytics_schema.py @@ -22,6 +22,7 @@ OUTPUT = Path(__file__).parent / "docs" / "static" / "frigate-analytics-schema.j def render() -> str: + """The JSON Schema for the current report models.""" schema = AnalyticsReport.model_json_schema() schema["$schema"] = "https://json-schema.org/draft/2020-12/schema" schema["$id"] = "https://docs.frigate.video/frigate-analytics-schema.json"