You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 088cb16
Browse filesBrowse the repository at this point in the historyBrowse files
fix(cron): never store a frozen Deye reading; health reports logger-offline; operator purge endpoint
Incident 2026-09-18 13:30 -> 09-22 16:20 BKK: the site's logger dropped off Deye Cloud and /station/latest kept re-serving its last reading (PV 2631 W) for 4 days; the cron stored it every 5 min (1,187 fabricated samples), Deye has no day totals for 09-19..21.
- lib/freeze.ts isFrozenReading(readingTs, lastStoredReadingTs, now, staleS): unchanged device timestamp older than the stale window = no evidence; pollAndStore then writes no sample/daily, records last_poll_ok + frozen_since (first), still runs alerts (offline rule); on a fresh reading clears frozen_since and stores last_reading_ts
- /api/_health: cronHealthy from max(last sample, last successful poll); inverterFrozenSince + summary note so a polling-but-not-storing collector is not reported as dead
- POST /api/_purge?from&to[&confirm=1] (operator, dry-run default, <=31 d): deletes samples/device_samples in the window and drops day/battery caches; daily untouched
- 5 tests (105 total)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
console.warn("poll: frozen reading — not stored:",fz.reason);
170
+
awaitenv.DB.batch([
171
+
env.DB.prepare("INSERT INTO meta (k,v) VALUES ('last_poll_ok',?) ON CONFLICT(k) DO UPDATE SET v=excluded.v").bind(String(ts)),
172
+
env.DB.prepare("INSERT INTO meta (k,v) VALUES ('frozen_since',?) ON CONFLICT(k) DO UPDATE SET v=v").bind(String(l.updatedAt)),// keep the FIRST frozen timestamp
173
+
env.DB.prepare("DELETE FROM meta WHERE k='last_poll_error'"),
174
+
]);
175
+
// Alerts still run so the offline rule can fire from the device snapshot.
0 commit comments