mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-11-12 00:23:01 +03:00
CI / AMD64 Build (push) Canceled after 0s
CI / ARM Build (push) Canceled after 0s
CI / Jetson Jetpack 6 (push) Canceled after 0s
CI / AMD64 Smoke Test (push) Canceled after 0s
CI / AMD64 Extra Build (push) Canceled after 0s
CI / ARM Extra Build (push) Canceled after 0s
CI / Synaptics Build (push) Canceled after 0s
CI / Assemble and push default build (push) Canceled after 0s
* don't calibrate or skip capability checks when autotracking is enabled at runtime Enabling autotracking from the UI on a camera that had been disabled for missing FOV relative movement or MoveStatus skipped both checks because ONVIF was already initialized, then ran calibration on the object processing thread and hung waiting for a motor stop that never came. Setup now runs the capability checks every time, only calibrates at startup, stops tracking the triggering object when setup disables the camera, and publishes the OFF state so the toggle reflects it. * only show settings reset buttons when the reset can succeed Reset to Global and Reset to Default delete the section from config.yml, and the delete raised a KeyError (HTTP 500) when the key wasn't in the file. Camera live sections always read as overridden because the backend fills in live.streams per camera, and the global Reset to Default button showed for every section, including ones the user never wrote. Global reset now only shows when the section differs from its schema defaults, ignoring fields the backend resolves at runtime (ffmpeg and record export hwaccel_args, audio filters). Camera live overrides skip streams, ffmpeg overrides skip inputs, and reset is hidden for camera ffmpeg and detection models, where deleting the section can't produce a valid config. Birdseye modes uses a plain default so the schema carries it. * Added an e2e spec covering reset visibility for default and customized global sections, the runtime-resolved fields, camera live overrides, and camera ffmpeg
147 lines
4.3 KiB
Python
147 lines
4.3 KiB
Python
from enum import Enum
|
|
|
|
from pydantic import BaseModel, Field
|
|
|
|
from ..base import FrigateBaseModel
|
|
|
|
__all__ = [
|
|
"BirdseyeCameraConfig",
|
|
"BirdseyeConfig",
|
|
"BirdseyeLayoutConfig",
|
|
"BirdseyeModeEnum",
|
|
"birdseye_modes_from_mqtt_payload",
|
|
"birdseye_modes_to_mqtt_payload",
|
|
]
|
|
|
|
# canonical MQTT payload for an empty mode list
|
|
MQTT_NO_MODES = "NONE"
|
|
|
|
|
|
class BirdseyeModeEnum(str, Enum):
|
|
continuous = "continuous"
|
|
motion = "motion"
|
|
all_objects = "all_objects"
|
|
alerts = "alerts"
|
|
detections = "detections"
|
|
|
|
|
|
def birdseye_modes_from_mqtt_payload(payload: str) -> list[BirdseyeModeEnum] | None:
|
|
"""Parse an uppercase MQTT payload into activity modes, or None when invalid."""
|
|
raw_modes = payload.split(",")
|
|
|
|
if any(not raw_mode or raw_mode != raw_mode.upper() for raw_mode in raw_modes):
|
|
return None
|
|
|
|
if raw_modes == [MQTT_NO_MODES]:
|
|
return []
|
|
|
|
modes: list[BirdseyeModeEnum] = []
|
|
|
|
for raw_mode in raw_modes:
|
|
try:
|
|
mode = BirdseyeModeEnum(raw_mode.lower())
|
|
except ValueError:
|
|
return None
|
|
|
|
if mode in modes:
|
|
return None
|
|
|
|
modes.append(mode)
|
|
|
|
return modes
|
|
|
|
|
|
def birdseye_modes_to_mqtt_payload(modes: list[BirdseyeModeEnum]) -> str:
|
|
"""Serialize activity modes for MQTT state topics."""
|
|
payload = ",".join(mode.value.upper() for mode in BirdseyeModeEnum if mode in modes)
|
|
return payload or MQTT_NO_MODES
|
|
|
|
|
|
class BirdseyeLayoutConfig(FrigateBaseModel):
|
|
scaling_factor: float = Field(
|
|
default=2.0,
|
|
title="Scaling factor",
|
|
description="Scaling factor used by the layout calculator (range 1.0 to 5.0).",
|
|
ge=1.0,
|
|
le=5.0,
|
|
)
|
|
max_cameras: int | None = Field(
|
|
default=None,
|
|
title="Max cameras",
|
|
description="Maximum number of cameras to display at once in Birdseye; shows the most recent cameras.",
|
|
)
|
|
|
|
|
|
class BirdseyeConfig(FrigateBaseModel):
|
|
enabled: bool = Field(
|
|
default=True,
|
|
title="Enable Birdseye",
|
|
description="Enable or disable the Birdseye view feature.",
|
|
)
|
|
modes: list[BirdseyeModeEnum] = Field(
|
|
default=[BirdseyeModeEnum.all_objects],
|
|
title="Activity types",
|
|
description="Activity types that include cameras in Birdseye.",
|
|
)
|
|
|
|
restream: bool = Field(
|
|
default=False,
|
|
title="Restream RTSP",
|
|
description="Re-stream the Birdseye output as an RTSP feed; enabling this will keep Birdseye running continuously.",
|
|
)
|
|
width: int = Field(
|
|
default=1280,
|
|
title="Width",
|
|
description="Output width (pixels) of the composed Birdseye frame.",
|
|
)
|
|
height: int = Field(
|
|
default=720,
|
|
title="Height",
|
|
description="Output height (pixels) of the composed Birdseye frame.",
|
|
)
|
|
quality: int = Field(
|
|
default=8,
|
|
title="Encoding quality",
|
|
description="Encoding quality for the Birdseye mpeg1 feed (1 highest quality, 31 lowest).",
|
|
ge=1,
|
|
le=31,
|
|
)
|
|
inactivity_threshold: int = Field(
|
|
default=30,
|
|
title="Inactivity threshold",
|
|
description="Seconds of inactivity after which a camera will stop being shown in Birdseye.",
|
|
gt=0,
|
|
)
|
|
layout: BirdseyeLayoutConfig = Field(
|
|
default_factory=BirdseyeLayoutConfig,
|
|
title="Layout",
|
|
description="Layout options for the Birdseye composition.",
|
|
)
|
|
idle_heartbeat_fps: float = Field(
|
|
default=0.0,
|
|
ge=0.0,
|
|
le=10.0,
|
|
title="Idle heartbeat FPS",
|
|
description="Frames-per-second to resend the last composed Birdseye frame when idle; set to 0 to disable.",
|
|
)
|
|
|
|
|
|
# uses BaseModel because some global attributes are not available at the camera level
|
|
class BirdseyeCameraConfig(BaseModel):
|
|
enabled: bool = Field(
|
|
default=True,
|
|
title="Enable Birdseye",
|
|
description="Enable or disable the Birdseye view feature.",
|
|
)
|
|
modes: list[BirdseyeModeEnum] = Field(
|
|
default=[BirdseyeModeEnum.all_objects],
|
|
title="Activity types",
|
|
description="Activity types that include cameras in Birdseye.",
|
|
)
|
|
|
|
order: int = Field(
|
|
default=0,
|
|
title="Position",
|
|
description="Numeric position controlling the camera's ordering in the Birdseye layout.",
|
|
)
|