Flash Canon configurable, choix de cadre a l'impression, fixes capture/reconnexion DSLR
- Flash integre Canon activable/desactivable depuis l'admin (configurer_flash) - Popup de choix de cadre juste avant impression, layout sans defilement (flex nowrap + aspect-ratio) - Capture : ignore camera_erreur pendant une capture en cours (laisse l'API trancher) - surveiller_dslr : grace period preview augmentee a 2s, reapplique la config camera apres reconnexion - start.sh simplifie (Chromium gere par kiosk-session.sh), remote debugging port 9222 active
This commit is contained in:
@@ -49,7 +49,7 @@ _loop_principal: asyncio.AbstractEventLoop | None = None # loop asyncio princip
|
||||
|
||||
|
||||
_preview_none_count = 0
|
||||
_PREVIEW_GRACE_FRAMES = 15 # ~500ms avant de declarer une erreur
|
||||
_PREVIEW_GRACE_FRAMES = 40 # 40 x 50ms = 2s avant de declarer une erreur (Canon LiveView peut être lent à démarrer)
|
||||
|
||||
|
||||
def _thread_preview():
|
||||
@@ -88,6 +88,7 @@ async def _pusher_preview():
|
||||
# Grace period : attendre plusieurs frames avant de signaler l'erreur
|
||||
# Ne pas signaler pendant une capture (race condition HTTP/WS)
|
||||
if camera.mode == "gphoto2" and _preview_none_count > _PREVIEW_GRACE_FRAMES and not capture_en_cours:
|
||||
log.warning(f"camera_erreur envoyé : preview None depuis {_preview_none_count * 50}ms")
|
||||
await diffuser_ws({"type": "camera_erreur", "message": "DSLR ne repond pas au preview"})
|
||||
_preview_actif = False
|
||||
_preview_none_count = 0
|
||||
@@ -134,8 +135,8 @@ async def surveiller_dslr():
|
||||
_echecs_connexion = 0
|
||||
else:
|
||||
_dslr_erreurs += 1
|
||||
if _dslr_erreurs >= 3: # 3 x 5s = 15s sans preview valide
|
||||
log.warning("DSLR ne repond plus (preview KO depuis 15s), reconnexion forcee...")
|
||||
if _dslr_erreurs >= 3 and not _preview_actif: # Ne pas couper pendant le countdown
|
||||
log.warning(f"camera_erreur : DSLR preview KO depuis {_dslr_erreurs * 5}s, reconnexion forcee...")
|
||||
_dslr_erreurs = 0
|
||||
camera.deconnecter()
|
||||
await diffuser_ws({"type": "camera_erreur", "message": "Appareil photo deconnecte"})
|
||||
@@ -144,6 +145,7 @@ async def surveiller_dslr():
|
||||
if camera.connectee:
|
||||
log.info("DSLR reconnecte avec succes")
|
||||
_echecs_connexion = 0
|
||||
_appliquer_config_camera()
|
||||
await diffuser_ws({"type": "camera_ok"})
|
||||
else:
|
||||
log.warning("Echec reconnexion DSLR — nouvelle tentative dans 5s")
|
||||
@@ -156,6 +158,7 @@ async def surveiller_dslr():
|
||||
if camera.connectee:
|
||||
log.info("DSLR connecte avec succes")
|
||||
_echecs_connexion = 0
|
||||
_appliquer_config_camera()
|
||||
await diffuser_ws({"type": "camera_ok"})
|
||||
else:
|
||||
_echecs_connexion += 1
|
||||
@@ -164,6 +167,13 @@ async def surveiller_dslr():
|
||||
log.debug(f"surveiller_dslr: {e}")
|
||||
|
||||
|
||||
def _appliquer_config_camera():
|
||||
"""Applique les paramètres caméra persistants (flash, etc.) après connexion."""
|
||||
cfg = charger_config()
|
||||
flash_integre = cfg.get("camera", {}).get("flash_integre", True)
|
||||
camera.configurer_flash(flash_integre)
|
||||
|
||||
|
||||
@asynccontextmanager
|
||||
async def lifespan(app: FastAPI):
|
||||
"""Demarrage et arret de l'application."""
|
||||
@@ -171,6 +181,7 @@ async def lifespan(app: FastAPI):
|
||||
log.info("Demarrage du photobooth")
|
||||
_loop_principal = asyncio.get_event_loop()
|
||||
camera.connecter()
|
||||
_appliquer_config_camera()
|
||||
# Thread de capture preview (bloquant, tourne en parallele)
|
||||
t = threading.Thread(target=_thread_preview, daemon=True)
|
||||
t.start()
|
||||
@@ -276,6 +287,9 @@ async def api_config():
|
||||
async def api_config_update(modifications: dict):
|
||||
config = mettre_a_jour_config(modifications)
|
||||
await diffuser_ws({"type": "config_maj", "config": config})
|
||||
# Appliquer immédiatement les paramètres caméra si modifiés
|
||||
if "camera" in modifications and camera.connectee:
|
||||
_appliquer_config_camera()
|
||||
return config
|
||||
|
||||
|
||||
@@ -430,6 +444,13 @@ async def api_systeme_info():
|
||||
}
|
||||
|
||||
|
||||
@app.post("/api/log-js")
|
||||
async def api_log_js(request: Request):
|
||||
data = await request.json()
|
||||
log.warning(f"[JS] {data.get('msg', '?')}")
|
||||
return {"ok": True}
|
||||
|
||||
|
||||
@app.get("/api/camera/statut")
|
||||
async def api_camera_statut():
|
||||
return {
|
||||
@@ -476,6 +497,8 @@ async def api_camera_reconnecter(body: dict = {}):
|
||||
camera.deconnecter()
|
||||
source = body.get("source")
|
||||
ok = camera.connecter(source=source)
|
||||
if ok:
|
||||
_appliquer_config_camera()
|
||||
return {"connectee": ok, "mode": camera.mode}
|
||||
|
||||
|
||||
@@ -1073,8 +1096,10 @@ async def traiter_message_ws(msg: dict, ws: WebSocket):
|
||||
elif type_msg == "preview_start":
|
||||
global _preview_actif
|
||||
_preview_actif = True
|
||||
log.info("WS: preview_start recu")
|
||||
elif type_msg == "preview_stop":
|
||||
_preview_actif = False
|
||||
log.info("WS: preview_stop recu")
|
||||
|
||||
|
||||
async def diffuser_ws(message: dict):
|
||||
|
||||
Reference in New Issue
Block a user