Refresh partiel e-ink : ne redessine que la zone changée, full refresh ~1h

Backend : endpoints /frame.meta (ligne 'MODE X Y W H SEQ') + /frame.png qui
servent un crop de la zone modifiée (diff PIL par client) ou l'image pleine.
Full refresh forcé tous les N cycles (MONITORINK_FULL_EVERY=12, ~1h) ou si la
zone change sur plus de 60% de l'écran. Mode 'noop' quand rien ne change.

Anti-429 : l'usage Claude est mis en cache (MONITORINK_USAGE_TTL=120s) avec
repli sur la dernière valeur connue en cas d'erreur transitoire.

Kobo : monitorinkloop.sh récupère meta puis png et fait un fbink partiel
(-g file=,x=,y=) sans flash, full refresh (-c -f) en mode full. Refresh 5 min.
This commit is contained in:
jerem
2026-06-15 18:42:32 +02:00
parent ce20d3675d
commit c7395d1c37
8 changed files with 257 additions and 27 deletions

View File

@@ -202,7 +202,31 @@ def _burn_rate_from_ccusage() -> float | None:
return None
# Dernier usage récupéré avec succès : sert de cache (throttle) ET de repli en cas d'erreur
# transitoire (429, réseau) pour ne pas afficher "HTTP 429" sur l'e-ink. Les libellés dynamiques
# (resets_in_human) restent corrects car recalculés à la volée depuis resets_at.
_usage_cache: dict[str, object] = {"value": None, "ts": 0.0}
async def fetch_usage() -> ClaudeUsage:
now = time.time()
cached = _usage_cache["value"]
if isinstance(cached, ClaudeUsage) and cached.ok and (now - float(_usage_cache["ts"])) < config.usage_ttl_seconds:
return cached
result = await _fetch_usage()
if result.ok:
_usage_cache["value"] = result
_usage_cache["ts"] = now
return result
# Erreur (429, réseau, auth transitoire) : on réaffiche la dernière valeur correcte connue
# plutôt qu'un message d'erreur, le temps que ça se rétablisse.
if isinstance(cached, ClaudeUsage) and cached.ok:
return cached
return result
async def _fetch_usage() -> ClaudeUsage:
if not os.path.exists(config.claude_creds_path):
return ClaudeUsage(ok=False, error="credentials Claude absents — login isolé requis")