fix(mqtt): stop logging retained boot_report/alerts as new events

The firmware publishes boot_report on system/info and alerts on
system/alerts with retain=true. Every time the backend (re)connects - which
under uvicorn --reload means every backend file save - the broker redelivers
the last retained message and we inserted it again with occurred_at=now().
Result: the Health tab showed fresh PANIC boots and "Device reset due to
fault" alerts for a device that had been up for 4 days.

- insert_boot_event skips the insert when a row with the same
  (device_serial, boot_count) already exists. boot_count is the firmware's
  lifetime counter, so it uniquely identifies a boot.
- upsert_alert only writes when state/message actually changed and returns
  whether it did; the alert-event history row is only added on a change.
  A redelivered identical alert no longer bumps updated_at either.

Existing duplicate rows are not touched by this commit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-09-30 15:48:48 +03:00
co-authored by Claude Opus 5.5
parent 36f9540a89
commit 98dd16b597
2 changed files with 34 additions and 6 deletions
+5 -2
View File
@@ -86,10 +86,13 @@ async def _handle_alerts(serial: str, payload: dict):
if state == "CLEARED":
await db.delete_alert(serial, subsystem)
else:
await db.upsert_alert(serial, subsystem, state, payload.get("msg"))
changed = await db.upsert_alert(serial, subsystem, state, payload.get("msg"))
# Append-only history — survives past the alert being resolved, used to
# answer "when was the most recent issue" even once it's cleared.
await db.insert_alert_event(serial, subsystem, state, payload.get("msg"))
# Skipped when nothing changed: alerts are retained, so the broker
# re-sends every active one on each backend (re)subscribe.
if changed:
await db.insert_alert_event(serial, subsystem, state, payload.get("msg"))
async def _handle_info(serial: str, payload: dict):