From f002513d362c02d6875986e64067004476137a1b Mon Sep 17 00:00:00 2001 From: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com> Date: Sun, 29 Mar 2026 12:33:57 -0500 Subject: [PATCH] send MQTT snapshot when object enters required zone (#22690) When mqtt.required_zones is configured, the initial mqtt snapshot on object creation is always blocked because zone evaluation hasn't run yet (entered_zones is empty). Later, the snapshot is only re-sent if a better thumbnail is found, so if the first frame was already the best capture the snapshot is silently lost. Add a new_zone_entered flag to TrackedObject that triggers an mqtt snapshot publish as soon as zone entry is confirmed, closing the gap between object detection and zone evaluation. Closes blakeblackshear/frigate#21027 --- frigate/camera/state.py | 12 ++++++++++++ frigate/track/tracked_object.py | 2 ++ 2 files changed, 14 insertions(+) diff --git a/frigate/camera/state.py b/frigate/camera/state.py index a203264a6..8d0b58602 100644 --- a/frigate/camera/state.py +++ b/frigate/camera/state.py @@ -428,6 +428,18 @@ class CameraState: c(self.name, updated_obj, frame_name) updated_obj.last_published = frame_time + # send MQTT snapshot when object first enters a required zone, + # since the initial snapshot at creation time is blocked before + # zone evaluation has run + if updated_obj.new_zone_entered and not updated_obj.false_positive: + mqtt_required = self.camera_config.mqtt.required_zones + if mqtt_required and set(updated_obj.entered_zones) & set( + mqtt_required + ): + object_type = updated_obj.obj_data["label"] + self.send_mqtt_snapshot(updated_obj, object_type) + updated_obj.new_zone_entered = False + for id in removed_ids: # publish events to mqtt removed_obj = tracked_objects[id] diff --git a/frigate/track/tracked_object.py b/frigate/track/tracked_object.py index 44d270875..f5c33d1e6 100644 --- a/frigate/track/tracked_object.py +++ b/frigate/track/tracked_object.py @@ -61,6 +61,7 @@ class TrackedObject: self.zone_loitering: dict[str, int] = {} self.current_zones: list[str] = [] self.entered_zones: list[str] = [] + self.new_zone_entered: bool = False self.attributes: dict[str, float] = defaultdict(float) self.false_positive = True self.has_clip = False @@ -278,6 +279,7 @@ class TrackedObject: if name not in self.entered_zones: self.entered_zones.append(name) + self.new_zone_entered = True else: self.zone_loitering[name] = loitering_score