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:
@@ -10,8 +10,9 @@ from __future__ import annotations
|
||||
import time
|
||||
|
||||
from fastapi import FastAPI, Response
|
||||
from fastapi.responses import HTMLResponse
|
||||
from fastapi.responses import HTMLResponse, PlainTextResponse
|
||||
|
||||
import frame
|
||||
import render
|
||||
from config import config
|
||||
from integrations import kobo
|
||||
@@ -46,6 +47,26 @@ async def image(fresh: int = 0, bat: int | None = None, chg: int = 0) -> Respons
|
||||
)
|
||||
|
||||
|
||||
@app.get("/frame.meta", response_class=PlainTextResponse)
|
||||
async def frame_meta(client: str = "kobo", bat: int | None = None, chg: int = 0) -> Response:
|
||||
# Refresh partiel : rend l'image, calcule la zone modifiée vs le dernier frame de ce client,
|
||||
# et renvoie une ligne "MODE X Y W H SEQ" triviale à parser en shell busybox.
|
||||
# MODE ∈ {full, partial, noop}. Le PNG correspondant est récupéré via /frame.png.
|
||||
kobo.record(bat, bool(chg))
|
||||
info = await frame.compute_frame(client)
|
||||
line = f"{info['mode']} {info['x']} {info['y']} {info['w']} {info['h']} {info['seq']}"
|
||||
return PlainTextResponse(line, headers={"Cache-Control": "no-store"})
|
||||
|
||||
|
||||
@app.get("/frame.png")
|
||||
async def frame_png(client: str = "kobo") -> Response:
|
||||
# PNG décidé lors du dernier /frame.meta (crop en partial, image pleine en full).
|
||||
png = frame.get_png(client)
|
||||
if png is None:
|
||||
return Response(status_code=503)
|
||||
return Response(content=png, media_type="image/png", headers={"Cache-Control": "no-store"})
|
||||
|
||||
|
||||
@app.get("/debug.html", response_class=HTMLResponse)
|
||||
async def debug_html() -> str:
|
||||
context = await render.build_context()
|
||||
|
||||
Reference in New Issue
Block a user