diff --git a/frigate/events/maintainer.py b/frigate/events/maintainer.py index db8341656..19bb44ef4 100644 --- a/frigate/events/maintainer.py +++ b/frigate/events/maintainer.py @@ -45,6 +45,12 @@ def should_update_state(prev_event: Event, current_event: Event) -> bool: if prev_event["attributes"] != current_event["attributes"]: return True + if prev_event["sub_label"] != current_event["sub_label"]: + return True + + if len(prev_event["current_zones"]) < len(current_event["current_zones"]): + return True + return False diff --git a/frigate/http.py b/frigate/http.py index c43feee9f..6b7ff8c3a 100644 --- a/frigate/http.py +++ b/frigate/http.py @@ -611,6 +611,78 @@ def timeline(): return jsonify([t for t in timeline]) +@bp.route("/timeline/hourly") +def hourly_timeline(): + """Get hourly summary for timeline.""" + camera = request.args.get("camera", "all") + before = request.args.get("before", 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) + + clauses = [] + + if camera != "all": + clauses.append((Timeline.camera == camera)) + + if before: + clauses.append((Timeline.timestamp < before)) + + if len(clauses) == 0: + clauses.append((True)) + + timeline = ( + Timeline.select( + Timeline.camera, + Timeline.timestamp, + Timeline.data, + Timeline.class_type, + Timeline.source_id, + Timeline.source, + ) + .where(reduce(operator.and_, clauses)) + .order_by(Timeline.timestamp.desc()) + .limit(limit) + .dicts() + .iterator() + ) + + count = 0 + start = 0 + end = 0 + hours: dict[str, list[dict[str, any]]] = {} + + for t in timeline: + if count == 0: + start = t["timestamp"] + else: + end = t["timestamp"] + + count += 1 + + hour = ( + datetime.fromtimestamp(t["timestamp"]).replace( + minute=0, second=0, microsecond=0 + ) + + timedelta( + minutes=int(minute_modifier.split(" ")[0]), + ) + ).timestamp() + if hour not in hours: + hours[hour] = [t] + else: + hours[hour].insert(0, t) + + return jsonify( + { + "start": start, + "end": end, + "count": count, + "hours": hours, + } + ) + + @bp.route("//