diff --git a/frigate/api/defs/query/media_query_parameters.py b/frigate/api/defs/query/media_query_parameters.py index 4750d3277..1c44fdb48 100644 --- a/frigate/api/defs/query/media_query_parameters.py +++ b/frigate/api/defs/query/media_query_parameters.py @@ -17,6 +17,7 @@ class MediaLatestFrameQueryParams(BaseModel): zones: Optional[int] = None mask: Optional[int] = None motion: Optional[int] = None + motion_paths: Optional[int] = None regions: Optional[int] = None quality: Optional[int] = 70 height: Optional[int] = None @@ -40,6 +41,7 @@ class MediaMjpegFeedQueryParams(BaseModel): zones: Optional[int] = None mask: Optional[int] = None motion: Optional[int] = None + motion_paths: Optional[int] = None regions: Optional[int] = None diff --git a/frigate/api/media.py b/frigate/api/media.py index a9455919b..9a02d928b 100644 --- a/frigate/api/media.py +++ b/frigate/api/media.py @@ -55,6 +55,7 @@ def mjpeg_feed( ): draw_options = { "bounding_boxes": params.bbox, + "motion_paths": params.motion_paths, "timestamp": params.timestamp, "zones": params.zones, "mask": params.mask, @@ -127,6 +128,7 @@ def latest_frame( frame_processor: TrackedObjectProcessor = request.app.detected_frames_processor draw_options = { "bounding_boxes": params.bbox, + "motion_paths": params.motion_paths, "timestamp": params.timestamp, "zones": params.zones, "mask": params.mask, diff --git a/frigate/config/camera/motion_path.py b/frigate/config/camera/motion_path.py new file mode 100644 index 000000000..d06177e03 --- /dev/null +++ b/frigate/config/camera/motion_path.py @@ -0,0 +1,44 @@ +from typing import Any, Optional, Union + +from pydantic import Field, field_serializer + +from ..base import FrigateBaseModel + +__all__ = ["MotionPathConfig"] + + +class MotionPathConfig(FrigateBaseModel): + enabled: bool = Field(default=True, title="Enable motion path tracking on all cameras.") + threshold: int = Field( + default=30, + title="Motion detection threshold (1-255).", + ge=1, + le=255, + ) + lightning_threshold: float = Field( + default=0.8, title="Lightning detection threshold (0.3-1.0).", ge=0.3, le=1.0 + ) + improve_contrast: bool = Field(default=True, title="Improve Contrast") + contour_area: Optional[int] = Field(default=10, title="Contour Area") + delta_alpha: float = Field(default=0.2, title="Delta Alpha") + frame_alpha: float = Field(default=0.01, title="Frame Alpha") + frame_height: Optional[int] = Field(default=100, title="Frame Height") + mask: Union[str, list[str]] = Field( + default="", title="Coordinates polygon for the motion mask." + ) + mqtt_off_delay: int = Field( + default=30, + title="Delay for updating MQTT with no motion detected.", + ) + enabled_in_config: Optional[bool] = Field( + default=None, title="Keep track of original state of motion detection." + ) + raw_mask: Union[str, list[str]] = "" + + @field_serializer("mask", when_used="json") + def serialize_mask(self, value: Any, info): + return self.raw_mask + + @field_serializer("raw_mask", when_used="json") + def serialize_raw_mask(self, value: Any, info): + return None diff --git a/frigate/config/camera/snapshots.py b/frigate/config/camera/snapshots.py index 156b56a7e..3d60fe58b 100644 --- a/frigate/config/camera/snapshots.py +++ b/frigate/config/camera/snapshots.py @@ -27,6 +27,9 @@ class SnapshotsConfig(FrigateBaseModel): bounding_box: bool = Field( default=True, title="Add a bounding box overlay on the snapshot." ) + motion_paths: bool = Field( + default=True, title="Add a motion path overlay on the snapshot." + ) crop: bool = Field(default=False, title="Crop the snapshot to the detected object.") required_zones: list[str] = Field( default_factory=list, diff --git a/frigate/config/config.py b/frigate/config/config.py index 39ee31411..f2a57ff60 100644 --- a/frigate/config/config.py +++ b/frigate/config/config.py @@ -46,6 +46,7 @@ from .camera.detect import DetectConfig from .camera.ffmpeg import FfmpegConfig from .camera.genai import GenAIConfig from .camera.motion import MotionConfig +from .camera.motion_path import MotionPathConfig from .camera.notification import NotificationConfig from .camera.objects import FilterConfig, ObjectConfig from .camera.record import RecordConfig, RetainModeEnum @@ -388,6 +389,9 @@ class FrigateConfig(FrigateBaseModel): motion: Optional[MotionConfig] = Field( default=None, title="Global motion detection configuration." ) + motion_paths: Optional[MotionPathConfig] = Field( + default=None, title="Global motion path tracking configuration." + ) objects: ObjectConfig = Field( default_factory=ObjectConfig, title="Global object configuration." ) diff --git a/web/src/components/camera/DebugCameraImage.tsx b/web/src/components/camera/DebugCameraImage.tsx index 998f15faa..6a844524b 100644 --- a/web/src/components/camera/DebugCameraImage.tsx +++ b/web/src/components/camera/DebugCameraImage.tsx @@ -101,6 +101,16 @@ function DebugSettings({ handleSetOption, options }: DebugSettingsProps) { /> +