mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-03-05 22:57:16 -05:00
Allow API Events to be Detections or Alerts, depending on the Event Label (#21923)
* - API created events will be alerts OR detections, depending on the event label, defaulting to alerts
- Indefinite API events will extend the recording segment until those events are ended
- API event start time is the actual start time, instead of having a pre-buffer of record.event_pre_capture
* Instead of checking for indefinite events on a camera before deciding if we should end the segment, only update last_detection_time and last_alert_time if frame_time is greater, which should have the same effect
* Add the ability to set a pre_capture number of seconds when creating a manual event via the API. Default behavior unchanged
* Remove unnecessary _publish_segment_start() call
* Formatting
* handle last_alert_time or last_detection_time being None when checking them against the frame_time
* comment manual_info["label"].split(": ")[0] for clarity
This commit is contained in:
7
docs/static/frigate-api.yaml
vendored
7
docs/static/frigate-api.yaml
vendored
@@ -3200,6 +3200,7 @@ paths:
|
||||
duration: 30
|
||||
include_recording: true
|
||||
draw: {}
|
||||
pre_capture: null
|
||||
responses:
|
||||
"200":
|
||||
description: Successful Response
|
||||
@@ -5002,6 +5003,12 @@ components:
|
||||
- type: "null"
|
||||
title: Draw
|
||||
default: {}
|
||||
pre_capture:
|
||||
anyOf:
|
||||
- type: integer
|
||||
- type: "null"
|
||||
title: Pre Capture Seconds
|
||||
default: null
|
||||
type: object
|
||||
title: EventsCreateBody
|
||||
EventsDeleteBody:
|
||||
|
||||
@@ -41,6 +41,7 @@ class EventsCreateBody(BaseModel):
|
||||
duration: Optional[int] = 30
|
||||
include_recording: Optional[bool] = True
|
||||
draw: Optional[dict] = {}
|
||||
pre_capture: Optional[int] = None
|
||||
|
||||
|
||||
class EventsEndBody(BaseModel):
|
||||
|
||||
@@ -1782,6 +1782,7 @@ def create_event(
|
||||
body.duration,
|
||||
"api",
|
||||
body.draw,
|
||||
body.pre_capture,
|
||||
),
|
||||
EventMetadataTypeEnum.manual_event_create.value,
|
||||
)
|
||||
|
||||
@@ -394,7 +394,11 @@ class ReviewSegmentMaintainer(threading.Thread):
|
||||
|
||||
if activity.has_activity_category(SeverityEnum.alert):
|
||||
# update current time for last alert activity
|
||||
segment.last_alert_time = frame_time
|
||||
if (
|
||||
segment.last_alert_time is None
|
||||
or frame_time > segment.last_alert_time
|
||||
):
|
||||
segment.last_alert_time = frame_time
|
||||
|
||||
if segment.severity != SeverityEnum.alert:
|
||||
# if segment is not alert category but current activity is
|
||||
@@ -404,7 +408,11 @@ class ReviewSegmentMaintainer(threading.Thread):
|
||||
should_update_image = True
|
||||
|
||||
if activity.has_activity_category(SeverityEnum.detection):
|
||||
segment.last_detection_time = frame_time
|
||||
if (
|
||||
segment.last_detection_time is None
|
||||
or frame_time > segment.last_detection_time
|
||||
):
|
||||
segment.last_detection_time = frame_time
|
||||
|
||||
for object in activity.get_all_objects():
|
||||
# Alert-level objects should always be added (they extend/upgrade the segment)
|
||||
@@ -695,17 +703,28 @@ class ReviewSegmentMaintainer(threading.Thread):
|
||||
current_segment.detections[manual_info["event_id"]] = (
|
||||
manual_info["label"]
|
||||
)
|
||||
if (
|
||||
topic == DetectionTypeEnum.api
|
||||
and self.config.cameras[camera].review.alerts.enabled
|
||||
):
|
||||
current_segment.severity = SeverityEnum.alert
|
||||
if topic == DetectionTypeEnum.api:
|
||||
# manual_info["label"] contains 'label: sub_label'
|
||||
# so split out the label without modifying manual_info
|
||||
if (
|
||||
self.config.cameras[camera].review.detections.enabled
|
||||
and manual_info["label"].split(": ")[0]
|
||||
in self.config.cameras[camera].review.detections.labels
|
||||
):
|
||||
current_segment.last_detection_time = manual_info[
|
||||
"end_time"
|
||||
]
|
||||
elif self.config.cameras[camera].review.alerts.enabled:
|
||||
current_segment.severity = SeverityEnum.alert
|
||||
current_segment.last_alert_time = manual_info[
|
||||
"end_time"
|
||||
]
|
||||
elif (
|
||||
topic == DetectionTypeEnum.lpr
|
||||
and self.config.cameras[camera].review.detections.enabled
|
||||
):
|
||||
current_segment.severity = SeverityEnum.detection
|
||||
current_segment.last_alert_time = manual_info["end_time"]
|
||||
current_segment.last_alert_time = manual_info["end_time"]
|
||||
elif manual_info["state"] == ManualEventState.start:
|
||||
self.indefinite_events[camera][manual_info["event_id"]] = (
|
||||
manual_info["label"]
|
||||
@@ -717,7 +736,18 @@ class ReviewSegmentMaintainer(threading.Thread):
|
||||
topic == DetectionTypeEnum.api
|
||||
and self.config.cameras[camera].review.alerts.enabled
|
||||
):
|
||||
current_segment.severity = SeverityEnum.alert
|
||||
# manual_info["label"] contains 'label: sub_label'
|
||||
# so split out the label without modifying manual_info
|
||||
if (
|
||||
not self.config.cameras[
|
||||
camera
|
||||
].review.detections.enabled
|
||||
or manual_info["label"].split(": ")[0]
|
||||
not in self.config.cameras[
|
||||
camera
|
||||
].review.detections.labels
|
||||
):
|
||||
current_segment.severity = SeverityEnum.alert
|
||||
elif (
|
||||
topic == DetectionTypeEnum.lpr
|
||||
and self.config.cameras[camera].review.detections.enabled
|
||||
@@ -789,11 +819,23 @@ class ReviewSegmentMaintainer(threading.Thread):
|
||||
detections,
|
||||
)
|
||||
elif topic == DetectionTypeEnum.api:
|
||||
if self.config.cameras[camera].review.alerts.enabled:
|
||||
severity = None
|
||||
# manual_info["label"] contains 'label: sub_label'
|
||||
# so split out the label without modifying manual_info
|
||||
if (
|
||||
self.config.cameras[camera].review.detections.enabled
|
||||
and manual_info["label"].split(": ")[0]
|
||||
in self.config.cameras[camera].review.detections.labels
|
||||
):
|
||||
severity = SeverityEnum.detection
|
||||
elif self.config.cameras[camera].review.alerts.enabled:
|
||||
severity = SeverityEnum.alert
|
||||
|
||||
if severity:
|
||||
self.active_review_segments[camera] = PendingReviewSegment(
|
||||
camera,
|
||||
frame_time,
|
||||
SeverityEnum.alert,
|
||||
severity,
|
||||
{manual_info["event_id"]: manual_info["label"]},
|
||||
{},
|
||||
[],
|
||||
@@ -820,7 +862,7 @@ class ReviewSegmentMaintainer(threading.Thread):
|
||||
].last_detection_time = manual_info["end_time"]
|
||||
else:
|
||||
logger.warning(
|
||||
f"Manual event API has been called for {camera}, but alerts are disabled. This manual event will not appear as an alert."
|
||||
f"Manual event API has been called for {camera}, but alerts and detections are disabled. This manual event will not appear as an alert or detection."
|
||||
)
|
||||
elif topic == DetectionTypeEnum.lpr:
|
||||
if self.config.cameras[camera].review.detections.enabled:
|
||||
|
||||
@@ -515,6 +515,7 @@ class TrackedObjectProcessor(threading.Thread):
|
||||
duration,
|
||||
source_type,
|
||||
draw,
|
||||
pre_capture,
|
||||
) = payload
|
||||
|
||||
# save the snapshot image
|
||||
@@ -522,6 +523,11 @@ class TrackedObjectProcessor(threading.Thread):
|
||||
None, event_id, label, draw
|
||||
)
|
||||
end_time = frame_time + duration if duration is not None else None
|
||||
start_time = (
|
||||
frame_time - self.config.cameras[camera_name].record.event_pre_capture
|
||||
if pre_capture is None
|
||||
else frame_time - pre_capture
|
||||
)
|
||||
|
||||
# send event to event maintainer
|
||||
self.event_sender.publish(
|
||||
@@ -536,8 +542,7 @@ class TrackedObjectProcessor(threading.Thread):
|
||||
"sub_label": sub_label,
|
||||
"score": score,
|
||||
"camera": camera_name,
|
||||
"start_time": frame_time
|
||||
- self.config.cameras[camera_name].record.event_pre_capture,
|
||||
"start_time": start_time,
|
||||
"end_time": end_time,
|
||||
"has_clip": self.config.cameras[camera_name].record.enabled
|
||||
and include_recording,
|
||||
|
||||
Reference in New Issue
Block a user