optimize recordings/unavailable gap detection and drop empty motion activity buckets

This commit is contained in:
Josh Hawkins 2026-06-01 14:50:13 -05:00
parent 373fdad7f4
commit 51770e6922
2 changed files with 25 additions and 6 deletions

View File

@ -299,22 +299,36 @@ async def no_recordings(
.iterator() .iterator()
) )
# Convert recordings to list of (start, end) tuples # Convert recordings to list of (start, end) tuples, ordered by start_time
recordings = [(r["start_time"], r["end_time"]) for r in data] recordings = [(r["start_time"], r["end_time"]) for r in data]
# Merge overlapping/adjacent recordings into covered intervals. The query
# orders by start_time, so a single pass merges them
covered: list[tuple[float, float]] = []
for rec_start, rec_end in recordings:
if covered and rec_start <= covered[-1][1]:
covered[-1] = (covered[-1][0], max(covered[-1][1], rec_end))
else:
covered.append((rec_start, rec_end))
# Iterate through time segments and check if each has any recording # Iterate through time segments and check if each has any recording
no_recording_segments = [] no_recording_segments = []
current = after current = after
current_gap_start = None current_gap_start = None
idx = 0
covered_count = len(covered)
while current < before: while current < before:
segment_end = min(current + scale, before) segment_end = min(current + scale, before)
# Check if this segment overlaps with any recording # Advance past covered intervals that end before this segment begins;
has_recording = any( # they cannot overlap this or any later segment.
rec_start < segment_end and rec_end > current while idx < covered_count and covered[idx][1] <= current:
for rec_start, rec_end in recordings idx += 1
)
# A covered interval overlaps the segment when it starts before the
# segment ends (its end is already known to be > current).
has_recording = idx < covered_count and covered[idx][0] < segment_end
if not has_recording: if not has_recording:
# This segment has no recordings # This segment has no recordings

View File

@ -658,6 +658,11 @@ def motion_activity(
else: else:
df.iloc[i : i + chunk, 0] = 0.0 df.iloc[i : i + chunk, 0] = 0.0
# Drop resample gap-fill buckets. The resample above emits a row for every
# {scale}s bucket spanning the range, and buckets with no recording get a
# motion of 0 (from fillna) and an empty camera (from joining an empty set).
df = df[df["camera"] != ""]
# change types for output # change types for output
df.index = df.index.astype(int) // (10**9) df.index = df.index.astype(int) // (10**9)
normalized = df.reset_index().to_dict("records") normalized = df.reset_index().to_dict("records")