Improve wake behavior when a zone is not specified

This commit is contained in:
Nicolas Mowen 2026-03-26 18:11:51 -06:00
parent 773aa18b94
commit e8a63d138f

View File

@ -25,6 +25,9 @@ logger = logging.getLogger(__name__)
_MIN_INTERVAL = 1 _MIN_INTERVAL = 1
_MAX_INTERVAL = 300 _MAX_INTERVAL = 300
# Minimum seconds between VLM iterations when woken by detections (no zone filter)
_DETECTION_COOLDOWN_WITHOUT_ZONE = 10
# Max user/assistant turn pairs to keep in conversation history # Max user/assistant turn pairs to keep in conversation history
_MAX_HISTORY = 10 _MAX_HISTORY = 10
@ -223,12 +226,28 @@ class VLMWatchRunner(threading.Thread):
return next_run_in return next_run_in
def _wait_for_trigger(self, max_wait: float) -> None: def _wait_for_trigger(self, max_wait: float) -> None:
"""Wait up to max_wait seconds, returning early if a relevant detection fires on the target camera.""" """Wait up to max_wait seconds, returning early if a relevant detection fires on the target camera.
deadline = time.time() + max_wait
With zones configured, a matching detection wakes immediately (events
are already filtered). Without zones, detections are frequent so a
cooldown is enforced: messages are continuously drained to prevent
queue backup, but the loop only exits once a match has been seen
*and* the cooldown period has elapsed.
"""
now = time.time()
deadline = now + max_wait
use_cooldown = not self.job.zones
earliest_wake = now + _DETECTION_COOLDOWN_WITHOUT_ZONE if use_cooldown else 0
triggered = False
while not self.cancel_event.is_set(): while not self.cancel_event.is_set():
remaining = deadline - time.time() remaining = deadline - time.time()
if remaining <= 0: if remaining <= 0:
break break
if triggered and time.time() >= earliest_wake:
break
result = self.detection_subscriber.check_for_update( result = self.detection_subscriber.check_for_update(
timeout=min(1.0, remaining) timeout=min(1.0, remaining)
) )
@ -253,12 +272,22 @@ class VLMWatchRunner(threading.Thread):
if cam != self.job.camera or not tracked_objects: if cam != self.job.camera or not tracked_objects:
continue continue
if self._detection_matches_filters(tracked_objects): if self._detection_matches_filters(tracked_objects):
logger.debug( if not use_cooldown:
"VLM watch job %s: woken early by detection event on %s", logger.debug(
self.job.id, "VLM watch job %s: woken early by detection event on %s",
self.job.camera, self.job.id,
) self.job.camera,
break )
break
if not triggered:
logger.debug(
"VLM watch job %s: detection match on %s, draining for %.0fs",
self.job.id,
self.job.camera,
max(0, earliest_wake - time.time()),
)
triggered = True
def _detection_matches_filters(self, tracked_objects: list) -> bool: def _detection_matches_filters(self, tracked_objects: list) -> bool:
"""Return True if any tracked object passes the label and zone filters.""" """Return True if any tracked object passes the label and zone filters."""