Add api and data

This commit is contained in:
Nick Mowen 2024-01-02 13:51:17 -07:00
parent 08ca024426
commit afb9997c7d
2 changed files with 84 additions and 1 deletions

View File

@ -8,6 +8,7 @@ import re
import subprocess as sp
import time
import traceback
from collections import defaultdict
from datetime import datetime, timedelta, timezone
from functools import reduce
from pathlib import Path
@ -620,7 +621,9 @@ def hourly_timeline():
after = request.args.get("after", type=float)
limit = request.args.get("limit", 200)
tz_name = request.args.get("timezone", default="utc", type=str)
_, minute_modifier, _ = get_tz_modifiers(tz_name)
minute_offset = int(minute_modifier.split(" ")[0])
clauses = []
@ -675,7 +678,7 @@ def hourly_timeline():
minute=0, second=0, microsecond=0
)
+ timedelta(
minutes=int(minute_modifier.split(" ")[0]),
minutes=minute_offset,
)
).timestamp()
if hour not in hours:
@ -693,6 +696,85 @@ def hourly_timeline():
)
@bp.route("/<camera_name>/recording/hourly/activity")
def hourly_timeline_activity(camera_name: str):
"""Get hourly summary for timeline."""
if camera_name not in current_app.frigate_config.cameras:
return make_response(
jsonify({"success": False, "message": "Camera not found"}),
404,
)
before = request.args.get("before", type=float, default=datetime.now())
after = request.args.get(
"after", type=float, default=datetime.now() - timedelta(hours=1)
)
tz_name = request.args.get("timezone", default="utc", type=str)
_, minute_modifier, _ = get_tz_modifiers(tz_name)
minute_offset = int(minute_modifier.split(" ")[0])
all_recordings: list[Recordings] = (
Recordings.select(
Recordings.start_time,
Recordings.duration,
Recordings.objects,
Recordings.motion,
)
.where(Recordings.camera == camera_name)
.where(Recordings.motion > 0)
.where((Recordings.start_time > after) & (Recordings.end_time < before))
.iterator()
)
# data format is ex:
# {timestamp: [{ date: 1, count: 1, type: motion }]}] }}
hours: dict[int, list[dict[str, any]]] = defaultdict(list)
key = datetime.fromtimestamp(after).replace(second=0, microsecond=0) + timedelta(
minutes=minute_offset
)
check = (key + timedelta(hours=1)).timestamp()
for recording in all_recordings:
if recording.start_time > check:
key = key + timedelta(hours=1)
check = (key + timedelta(hours=1)).timestamp()
data_type = "motion" if recording.objects == 0 else "objects"
hours[int(key.timestamp())].append(
{
"date": recording.start_time + (recording.duration / 2),
"count": recording.motion,
"type": data_type,
}
)
# process data to make data counts relative
for hour, data in hours.items():
motion_values = np.asarray(list(map(lambda m: m["count"], data)))
avg = motion_values.mean()
std = motion_values.std()
for idx, motion in enumerate(motion_values):
if motion < (avg - (std * 2)):
value = 1
elif motion < (avg - std):
value = 2
elif motion < avg:
value = 3
elif motion < (avg + std):
value = 4
elif motion < (avg + (std * 2)):
value = 5
else:
value = 6
hours[hour][idx]["count"] = value
return jsonify(hours)
@bp.route("/<camera_name>/<label>/best.jpg")
@bp.route("/<camera_name>/<label>/thumbnail.jpg")
def label_thumbnail(camera_name, label):

View File

@ -14,6 +14,7 @@ export default function TimelineGraph({ id, data }: TimelineGraphProps) {
<Chart
type="bar"
options={{
colors: ["#991b1b", "#06b6d4", "#ea580c"],
chart: {
id: id,
selection: {