Skip to content

Commit aa2f99a

Browse files
committed
stop reprocessing polled events and log the silent ones
The finalizer drops an event from memory when done, so the poller treated an already-processed MQTT event as new - and claimed in the log that MQTT never announced it. Keep a memory of handled ids. Also log events that yield no face: 17 of 20 events over 19 hours produced no log line at all here, which makes a working install indistinguishable from a dead one - exactly the confusion reported in the community thread.
1 parent eb8d9d3 commit aa2f99a

5 files changed

Lines changed: 49 additions & 3 deletions

File tree

CHANGELOG.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,18 @@
33
All notable changes to FaceID. The Home Assistant app shows this file in the
44
update dialog; standalone users can watch GitHub releases.
55

6+
## 0.6.10 — 2026-07-26
7+
8+
- **Fixed: polled events could be processed twice.** The finalizer clears an event from
9+
memory once it is done, so the poller then saw a fully processed MQTT event as new and
10+
ran it again — while logging the untruth "never announced by MQTT". It now remembers
11+
the last 1000 event ids it handled.
12+
- **The log no longer goes silent when nothing is recognised.** Events without a usable
13+
face are the normal case (back to camera, too far away), but they were dropped without
14+
a word — making a healthy install look identical to a broken one. Both "no snapshot"
15+
and "no face >= min_face_px" are now logged. Measured here: over 19 hours, 17 of 20
16+
events held no face at all, and the log said nothing about any of them.
17+
618
## 0.6.9 — 2026-07-26
719

820
- **Fixed: no Home Assistant entities unless you listed your cameras.** An empty

app/mqtt_listener.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,9 @@ def __init__(self, cfg: dict, engine, gallery, frigate):
5050
self.frigate_topic = str(f.get("frigate_topic_prefix", "frigate")).strip("/") or "frigate"
5151
self._polled: deque = deque(maxlen=500) # schon gesehene IDs
5252
self._announced: set = set() # Kameras mit angemeldetem Sensor
53+
# Der Finalizer raeumt self.events nach der Verarbeitung ab — ohne dieses
54+
# Gedaechtnis haelt der Poller ein fertig verarbeitetes Ereignis fuer neu.
55+
self._handled: deque = deque(maxlen=1000)
5356
self.prefix = str(f.get("mqtt_prefix", "faceid")).strip("/") or "faceid"
5457
self.present: dict[str, dict[str, float]] = {} # camera -> {person: zuletzt gesehen}
5558
self._last_presence: dict[str, list] = {} # zuletzt publizierter Stand je Kamera
@@ -117,6 +120,8 @@ def _on_message(self, client, userdata, msg):
117120
eid = after.get("id")
118121
if not eid:
119122
return
123+
if eid not in self._handled:
124+
self._handled.append(eid)
120125
self._ensure_discovery(cam)
121126
st = self.events.setdefault(
122127
eid,
@@ -154,9 +159,14 @@ def _process(self, eid: str):
154159
st["attempts"] += 1
155160
img = self.frigate.snapshot(eid, crop=True)
156161
if img is None:
162+
log.info("Event %s (%s): kein Snapshot von Frigate", eid, st["camera"])
157163
return
158164
face = FaceEngine.best_face(self.engine.faces(img), min_px=self.min_face_px)
159165
if face is None:
166+
# Der haeufigste Normalfall (Ruecken zur Kamera, zu weit weg) — trotzdem
167+
# protokollieren, sonst sieht ein stiller Log wie ein Defekt aus.
168+
log.info("Event %s (%s): Versuch %d, kein Gesicht >= %dpx im Snapshot",
169+
eid, st["camera"], st["attempts"], self.min_face_px)
160170
return
161171
emb = face.normed_embedding
162172
slug, name, score = self.gallery.match(emb)
@@ -220,7 +230,8 @@ def _poller(self):
220230
since = time.time()
221231
for ev in batch:
222232
eid = ev.get("id")
223-
if not eid or eid in self._polled or eid in self.events:
233+
if (not eid or eid in self._polled or eid in self.events
234+
or eid in self._handled):
224235
continue
225236
cam = ev.get("camera", "")
226237
if self.cameras and cam not in self.cameras:

faceid-addon/CHANGELOG.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,18 @@
33
All notable changes to FaceID. The Home Assistant app shows this file in the
44
update dialog; standalone users can watch GitHub releases.
55

6+
## 0.6.10 — 2026-07-26
7+
8+
- **Fixed: polled events could be processed twice.** The finalizer clears an event from
9+
memory once it is done, so the poller then saw a fully processed MQTT event as new and
10+
ran it again — while logging the untruth "never announced by MQTT". It now remembers
11+
the last 1000 event ids it handled.
12+
- **The log no longer goes silent when nothing is recognised.** Events without a usable
13+
face are the normal case (back to camera, too far away), but they were dropped without
14+
a word — making a healthy install look identical to a broken one. Both "no snapshot"
15+
and "no face >= min_face_px" are now logged. Measured here: over 19 hours, 17 of 20
16+
events held no face at all, and the log said nothing about any of them.
17+
618
## 0.6.9 — 2026-07-26
719

820
- **Fixed: no Home Assistant entities unless you listed your cameras.** An empty

faceid-addon/app/mqtt_listener.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,9 @@ def __init__(self, cfg: dict, engine, gallery, frigate):
5050
self.frigate_topic = str(f.get("frigate_topic_prefix", "frigate")).strip("/") or "frigate"
5151
self._polled: deque = deque(maxlen=500) # schon gesehene IDs
5252
self._announced: set = set() # Kameras mit angemeldetem Sensor
53+
# Der Finalizer raeumt self.events nach der Verarbeitung ab — ohne dieses
54+
# Gedaechtnis haelt der Poller ein fertig verarbeitetes Ereignis fuer neu.
55+
self._handled: deque = deque(maxlen=1000)
5356
self.prefix = str(f.get("mqtt_prefix", "faceid")).strip("/") or "faceid"
5457
self.present: dict[str, dict[str, float]] = {} # camera -> {person: zuletzt gesehen}
5558
self._last_presence: dict[str, list] = {} # zuletzt publizierter Stand je Kamera
@@ -117,6 +120,8 @@ def _on_message(self, client, userdata, msg):
117120
eid = after.get("id")
118121
if not eid:
119122
return
123+
if eid not in self._handled:
124+
self._handled.append(eid)
120125
self._ensure_discovery(cam)
121126
st = self.events.setdefault(
122127
eid,
@@ -154,9 +159,14 @@ def _process(self, eid: str):
154159
st["attempts"] += 1
155160
img = self.frigate.snapshot(eid, crop=True)
156161
if img is None:
162+
log.info("Event %s (%s): kein Snapshot von Frigate", eid, st["camera"])
157163
return
158164
face = FaceEngine.best_face(self.engine.faces(img), min_px=self.min_face_px)
159165
if face is None:
166+
# Der haeufigste Normalfall (Ruecken zur Kamera, zu weit weg) — trotzdem
167+
# protokollieren, sonst sieht ein stiller Log wie ein Defekt aus.
168+
log.info("Event %s (%s): Versuch %d, kein Gesicht >= %dpx im Snapshot",
169+
eid, st["camera"], st["attempts"], self.min_face_px)
160170
return
161171
emb = face.normed_embedding
162172
slug, name, score = self.gallery.match(emb)
@@ -220,7 +230,8 @@ def _poller(self):
220230
since = time.time()
221231
for ev in batch:
222232
eid = ev.get("id")
223-
if not eid or eid in self._polled or eid in self.events:
233+
if (not eid or eid in self._polled or eid in self.events
234+
or eid in self._handled):
224235
continue
225236
cam = ev.get("camera", "")
226237
if self.cameras and cam not in self.cameras:

faceid-addon/config.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name: FaceID
2-
version: "0.6.9"
2+
version: "0.6.10"
33
slug: faceid
44
description: Face recognition for Frigate — trainable gallery, clustered unknown review, HA sensors
55
url: https://github.com/SkyTechNerds/faceid

0 commit comments

Comments
 (0)