mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-03-10 02:29:19 +03: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:
parent
12506f8c80
commit
bb6e889449
7
docs/static/frigate-api.yaml
vendored
7
docs/static/frigate-api.yaml
vendored
@ -3200,6 +3200,7 @@ paths:
|
|||||||
duration: 30
|
duration: 30
|
||||||
include_recording: true
|
include_recording: true
|
||||||
draw: {}
|
draw: {}
|
||||||
|
pre_capture: null
|
||||||
responses:
|
responses:
|
||||||
"200":
|
"200":
|
||||||
description: Successful Response
|
description: Successful Response
|
||||||
@ -5002,6 +5003,12 @@ components:
|
|||||||
- type: "null"
|
- type: "null"
|
||||||
title: Draw
|
title: Draw
|
||||||
default: {}
|
default: {}
|
||||||
|
pre_capture:
|
||||||
|
anyOf:
|
||||||
|
- type: integer
|
||||||
|
- type: "null"
|
||||||
|
title: Pre Capture Seconds
|
||||||
|
default: null
|
||||||
type: object
|
type: object
|
||||||
title: EventsCreateBody
|
title: EventsCreateBody
|
||||||
EventsDeleteBody:
|
EventsDeleteBody:
|
||||||
|
|||||||
@ -41,6 +41,7 @@ class EventsCreateBody(BaseModel):
|
|||||||
duration: Optional[int] = 30
|
duration: Optional[int] = 30
|
||||||
include_recording: Optional[bool] = True
|
include_recording: Optional[bool] = True
|
||||||
draw: Optional[dict] = {}
|
draw: Optional[dict] = {}
|
||||||
|
pre_capture: Optional[int] = None
|
||||||
|
|
||||||
|
|
||||||
class EventsEndBody(BaseModel):
|
class EventsEndBody(BaseModel):
|
||||||
|
|||||||
@ -1782,6 +1782,7 @@ def create_event(
|
|||||||
body.duration,
|
body.duration,
|
||||||
"api",
|
"api",
|
||||||
body.draw,
|
body.draw,
|
||||||
|
body.pre_capture,
|
||||||
),
|
),
|
||||||
EventMetadataTypeEnum.manual_event_create.value,
|
EventMetadataTypeEnum.manual_event_create.value,
|
||||||
)
|
)
|
||||||
|
|||||||
@ -394,7 +394,11 @@ class ReviewSegmentMaintainer(threading.Thread):
|
|||||||
|
|
||||||
if activity.has_activity_category(SeverityEnum.alert):
|
if activity.has_activity_category(SeverityEnum.alert):
|
||||||
# update current time for last alert activity
|
# 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.severity != SeverityEnum.alert:
|
||||||
# if segment is not alert category but current activity is
|
# if segment is not alert category but current activity is
|
||||||
@ -404,7 +408,11 @@ class ReviewSegmentMaintainer(threading.Thread):
|
|||||||
should_update_image = True
|
should_update_image = True
|
||||||
|
|
||||||
if activity.has_activity_category(SeverityEnum.detection):
|
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():
|
for object in activity.get_all_objects():
|
||||||
# Alert-level objects should always be added (they extend/upgrade the segment)
|
# 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"]] = (
|
current_segment.detections[manual_info["event_id"]] = (
|
||||||
manual_info["label"]
|
manual_info["label"]
|
||||||
)
|
)
|
||||||
if (
|
if topic == DetectionTypeEnum.api:
|
||||||
topic == DetectionTypeEnum.api
|
# manual_info["label"] contains 'label: sub_label'
|
||||||
and self.config.cameras[camera].review.alerts.enabled
|
# so split out the label without modifying manual_info
|
||||||
):
|
if (
|
||||||
current_segment.severity = SeverityEnum.alert
|
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 (
|
elif (
|
||||||
topic == DetectionTypeEnum.lpr
|
topic == DetectionTypeEnum.lpr
|
||||||
and self.config.cameras[camera].review.detections.enabled
|
and self.config.cameras[camera].review.detections.enabled
|
||||||
):
|
):
|
||||||
current_segment.severity = SeverityEnum.detection
|
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:
|
elif manual_info["state"] == ManualEventState.start:
|
||||||
self.indefinite_events[camera][manual_info["event_id"]] = (
|
self.indefinite_events[camera][manual_info["event_id"]] = (
|
||||||
manual_info["label"]
|
manual_info["label"]
|
||||||
@ -717,7 +736,18 @@ class ReviewSegmentMaintainer(threading.Thread):
|
|||||||
topic == DetectionTypeEnum.api
|
topic == DetectionTypeEnum.api
|
||||||
and self.config.cameras[camera].review.alerts.enabled
|
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 (
|
elif (
|
||||||
topic == DetectionTypeEnum.lpr
|
topic == DetectionTypeEnum.lpr
|
||||||
and self.config.cameras[camera].review.detections.enabled
|
and self.config.cameras[camera].review.detections.enabled
|
||||||
@ -789,11 +819,23 @@ class ReviewSegmentMaintainer(threading.Thread):
|
|||||||
detections,
|
detections,
|
||||||
)
|
)
|
||||||
elif topic == DetectionTypeEnum.api:
|
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(
|
self.active_review_segments[camera] = PendingReviewSegment(
|
||||||
camera,
|
camera,
|
||||||
frame_time,
|
frame_time,
|
||||||
SeverityEnum.alert,
|
severity,
|
||||||
{manual_info["event_id"]: manual_info["label"]},
|
{manual_info["event_id"]: manual_info["label"]},
|
||||||
{},
|
{},
|
||||||
[],
|
[],
|
||||||
@ -820,7 +862,7 @@ class ReviewSegmentMaintainer(threading.Thread):
|
|||||||
].last_detection_time = manual_info["end_time"]
|
].last_detection_time = manual_info["end_time"]
|
||||||
else:
|
else:
|
||||||
logger.warning(
|
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:
|
elif topic == DetectionTypeEnum.lpr:
|
||||||
if self.config.cameras[camera].review.detections.enabled:
|
if self.config.cameras[camera].review.detections.enabled:
|
||||||
|
|||||||
@ -515,6 +515,7 @@ class TrackedObjectProcessor(threading.Thread):
|
|||||||
duration,
|
duration,
|
||||||
source_type,
|
source_type,
|
||||||
draw,
|
draw,
|
||||||
|
pre_capture,
|
||||||
) = payload
|
) = payload
|
||||||
|
|
||||||
# save the snapshot image
|
# save the snapshot image
|
||||||
@ -522,6 +523,11 @@ class TrackedObjectProcessor(threading.Thread):
|
|||||||
None, event_id, label, draw
|
None, event_id, label, draw
|
||||||
)
|
)
|
||||||
end_time = frame_time + duration if duration is not None else None
|
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
|
# send event to event maintainer
|
||||||
self.event_sender.publish(
|
self.event_sender.publish(
|
||||||
@ -536,8 +542,7 @@ class TrackedObjectProcessor(threading.Thread):
|
|||||||
"sub_label": sub_label,
|
"sub_label": sub_label,
|
||||||
"score": score,
|
"score": score,
|
||||||
"camera": camera_name,
|
"camera": camera_name,
|
||||||
"start_time": frame_time
|
"start_time": start_time,
|
||||||
- self.config.cameras[camera_name].record.event_pre_capture,
|
|
||||||
"end_time": end_time,
|
"end_time": end_time,
|
||||||
"has_clip": self.config.cameras[camera_name].record.enabled
|
"has_clip": self.config.cameras[camera_name].record.enabled
|
||||||
and include_recording,
|
and include_recording,
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user