Skip to content

Commit

Permalink
Bug Fixes (#15598)
Browse files Browse the repository at this point in the history
* Catch onvif command error

* fix review item pre and post capture

* Include severity in query
  • Loading branch information
NickM-27 authored Dec 19, 2024
1 parent b149828 commit 4af7520
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 33 deletions.
13 changes: 13 additions & 0 deletions frigate/config/camera/record.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from pydantic import Field

from frigate.const import MAX_PRE_CAPTURE
from frigate.review.types import SeverityEnum

from ..base import FrigateBaseModel

Expand Down Expand Up @@ -101,3 +102,15 @@ def event_pre_capture(self) -> int:
self.alerts.pre_capture,
self.detections.pre_capture,
)

def get_review_pre_capture(self, severity: SeverityEnum) -> int:
if severity == SeverityEnum.alert:
return self.alerts.pre_capture
else:
return self.detections.pre_capture

def get_review_post_capture(self, severity: SeverityEnum) -> int:
if severity == SeverityEnum.alert:
return self.alerts.post_capture
else:
return self.detections.post_capture
36 changes: 20 additions & 16 deletions frigate/ptz/onvif.py
Original file line number Diff line number Diff line change
Expand Up @@ -558,22 +558,26 @@ def handle_command(
if not self._init_onvif(camera_name):
return

if command == OnvifCommandEnum.init:
# already init
return
elif command == OnvifCommandEnum.stop:
self._stop(camera_name)
elif command == OnvifCommandEnum.preset:
self._move_to_preset(camera_name, param)
elif command == OnvifCommandEnum.move_relative:
_, pan, tilt = param.split("_")
self._move_relative(camera_name, float(pan), float(tilt), 0, 1)
elif (
command == OnvifCommandEnum.zoom_in or command == OnvifCommandEnum.zoom_out
):
self._zoom(camera_name, command)
else:
self._move(camera_name, command)
try:
if command == OnvifCommandEnum.init:
# already init
return
elif command == OnvifCommandEnum.stop:
self._stop(camera_name)
elif command == OnvifCommandEnum.preset:
self._move_to_preset(camera_name, param)
elif command == OnvifCommandEnum.move_relative:
_, pan, tilt = param.split("_")
self._move_relative(camera_name, float(pan), float(tilt), 0, 1)
elif (
command == OnvifCommandEnum.zoom_in
or command == OnvifCommandEnum.zoom_out
):
self._zoom(camera_name, command)
else:
self._move(camera_name, command)
except ONVIFError as e:
logger.error(f"Unable to handle onvif command: {e}")

def get_camera_info(self, camera_name: str) -> dict[str, any]:
if camera_name not in self.cams.keys():
Expand Down
48 changes: 31 additions & 17 deletions frigate/record/maintainer.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
RECORD_DIR,
)
from frigate.models import Recordings, ReviewSegment
from frigate.review.types import SeverityEnum
from frigate.util.services import get_video_properties

logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -194,6 +195,7 @@ async def move_files(self) -> None:
ReviewSegment.select(
ReviewSegment.start_time,
ReviewSegment.end_time,
ReviewSegment.severity,
ReviewSegment.data,
)
.where(
Expand All @@ -219,20 +221,23 @@ async def move_files(self) -> None:
[r for r in recordings_to_insert if r is not None],
)

def drop_segment(self, cache_path: str) -> None:
Path(cache_path).unlink(missing_ok=True)
self.end_time_cache.pop(cache_path, None)

async def validate_and_move_segment(
self, camera: str, reviews: list[ReviewSegment], recording: dict[str, any]
) -> None:
cache_path = recording["cache_path"]
start_time = recording["start_time"]
cache_path: str = recording["cache_path"]
start_time: datetime.datetime = recording["start_time"]
record_config = self.config.cameras[camera].record

# Just delete files if recordings are turned off
if (
camera not in self.config.cameras
or not self.config.cameras[camera].record.enabled
):
Path(cache_path).unlink(missing_ok=True)
self.end_time_cache.pop(cache_path, None)
self.drop_segment(cache_path)
return

if cache_path in self.end_time_cache:
Expand Down Expand Up @@ -260,24 +265,34 @@ async def validate_and_move_segment(
return

# if cached file's start_time is earlier than the retain days for the camera
# meaning continuous recording is not enabled
if start_time <= (
datetime.datetime.now().astimezone(datetime.timezone.utc)
- datetime.timedelta(days=self.config.cameras[camera].record.retain.days)
):
# if the cached segment overlaps with the events:
# if the cached segment overlaps with the review items:
overlaps = False
for review in reviews:
# if the event starts in the future, stop checking events
severity = SeverityEnum[review.severity]

# if the review item starts in the future, stop checking review items
# and remove this segment
if review.start_time > end_time.timestamp():
if (
review.start_time - record_config.get_review_pre_capture(severity)
) > end_time.timestamp():
overlaps = False
Path(cache_path).unlink(missing_ok=True)
self.end_time_cache.pop(cache_path, None)
break

# if the event is in progress or ends after the recording starts, keep it
# and stop looking at events
if review.end_time is None or review.end_time >= start_time.timestamp():
# if the review item is in progress or ends after the recording starts, keep it
# and stop looking at review items
if (
review.end_time is None
or (
review.end_time
+ record_config.get_review_post_capture(severity)
)
>= start_time.timestamp()
):
overlaps = True
break

Expand All @@ -296,7 +311,7 @@ async def validate_and_move_segment(
cache_path,
record_mode,
)
# if it doesn't overlap with an event, go ahead and drop the segment
# if it doesn't overlap with an review item, go ahead and drop the segment
# if it ends more than the configured pre_capture for the camera
else:
camera_info = self.object_recordings_info[camera]
Expand All @@ -307,9 +322,9 @@ async def validate_and_move_segment(
most_recently_processed_frame_time - record_config.event_pre_capture
).astimezone(datetime.timezone.utc)
if end_time < retain_cutoff:
Path(cache_path).unlink(missing_ok=True)
self.end_time_cache.pop(cache_path, None)
self.drop_segment(cache_path)
# else retain days includes this segment
# meaning continuous recording is enabled
else:
# assume that empty means the relevant recording info has not been received yet
camera_info = self.object_recordings_info[camera]
Expand Down Expand Up @@ -390,8 +405,7 @@ async def move_segment(

# check if the segment shouldn't be stored
if segment_info.should_discard_segment(store_mode):
Path(cache_path).unlink(missing_ok=True)
self.end_time_cache.pop(cache_path, None)
self.drop_segment(cache_path)
return

# directory will be in utc due to start_time being in utc
Expand Down

0 comments on commit 4af7520

Please sign in to comment.