Motion timeline data (#10245)

* Refactor activity api to send motion and audio data

* Prepare for using motion data timeline

* Get working

* reduce to 0

* fix

* Formatting

* fix typing

* add motion data to timelines and allow motion cameas to be selectable

* Fix tests

* cleanup

* Fix not loading preview when changing hours
This commit is contained in:
Nicolas Mowen
2024-03-05 12:55:44 -07:00
committed by GitHub
parent a174d82eb9
commit 9e8a42ca0e
11 changed files with 269 additions and 197 deletions

View File

@@ -4,6 +4,7 @@ import logging
from datetime import datetime, timedelta
from functools import reduce
import pandas as pd
from flask import (
Blueprint,
jsonify,
@@ -12,7 +13,7 @@ from flask import (
)
from peewee import Case, DoesNotExist, fn, operator
from frigate.models import ReviewSegment
from frigate.models import Recordings, ReviewSegment
from frigate.util.builtin import get_tz_modifiers
logger = logging.getLogger(__name__)
@@ -258,3 +259,66 @@ def delete_reviews(ids: str):
ReviewSegment.delete().where(ReviewSegment.id << list_of_ids).execute()
return make_response(jsonify({"success": True, "message": "Delete reviews"}), 200)
@ReviewBp.route("/review/activity")
def review_activity():
"""Get motion and audio activity."""
before = request.args.get("before", type=float, default=datetime.now().timestamp())
after = request.args.get(
"after", type=float, default=(datetime.now() - timedelta(hours=1)).timestamp()
)
# get scale in seconds
scale = request.args.get("scale", type=int, default=30)
all_recordings: list[Recordings] = (
Recordings.select(
Recordings.start_time,
Recordings.duration,
Recordings.objects,
Recordings.motion,
Recordings.dBFS,
)
.where((Recordings.start_time > after) & (Recordings.end_time < before))
.order_by(Recordings.start_time.asc())
.iterator()
)
# format is: { timestamp: segment_start_ts, motion: [0-100], audio: [0 - -100] }
# periods where active objects / audio was detected will cause motion / audio to be scaled down
data: list[dict[str, float]] = []
for rec in all_recordings:
data.append(
{
"start_time": rec.start_time,
"motion": rec.motion if rec.objects == 0 else 0,
"audio": rec.dBFS if rec.objects == 0 else 0,
}
)
# resample data using pandas to get activity on scaled basis
df = pd.DataFrame(data, columns=["start_time", "motion", "audio"])
# set date as datetime index
df["start_time"] = pd.to_datetime(df["start_time"], unit="s")
df.set_index(["start_time"], inplace=True)
# normalize data
df = df.resample(f"{scale}S").mean().fillna(0.0)
df["motion"] = (
(df["motion"] - df["motion"].min())
/ (df["motion"].max() - df["motion"].min())
* 100
)
df["audio"] = (
(df["audio"] - df["audio"].max())
/ (df["audio"].min() - df["audio"].max())
* -100
)
# change types for output
df.index = df.index.astype(int) // (10**9)
normalized = df.reset_index().to_dict("records")
return jsonify(normalized)