Module relais USB HID : pilotage projecteurs + alim Canon + eclairage auto
Pilote backend/relais.py (hidapi/ctypes) pour module LCUS 5131:2007. Relais 1-2 = projecteurs (NO), relais 3 = alim Canon (NF). API : status, on/off par nom, power-cycle, config seuils. Eclairage auto : analyse luminosite visage → allume projecteurs selon seuils. Admin : onglet eclairage enrichi avec boutons relais + seuils configurables. Note : power-cycle Canon par relais ne redémarre pas le DSLR (contact capot batterie). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -31,6 +31,7 @@ from backend.destinations import distribuer_photo, detecter_usb, compteur_restan
|
||||
from backend.printer import lister_imprimantes, imprimer
|
||||
from backend.mailer import envoyer_photo, charger_emails_historique, effacer_emails_historique, ajouter_au_spool, taille_spool, tache_spool_demarrage
|
||||
from backend.qrcode_gen import generer_qr, qr_galerie
|
||||
from backend import relais
|
||||
from backend.evenements import (
|
||||
lister_evenements, creer_evenement, obtenir_evenement,
|
||||
modifier_evenement, supprimer_evenement, activer_evenement,
|
||||
@@ -122,6 +123,33 @@ async def _pusher_preview():
|
||||
eclairage = await loop.run_in_executor(None, analyser_eclairage, donnees)
|
||||
if eclairage is not None:
|
||||
await diffuser_ws({"type": "eclairage", **eclairage})
|
||||
_gerer_eclairage_auto(eclairage)
|
||||
|
||||
_proj_etat = {"proj1": False, "proj2": False}
|
||||
|
||||
def _gerer_eclairage_auto(eclairage: dict):
|
||||
config = charger_config()
|
||||
rcfg = config.get("relais", {})
|
||||
if not rcfg.get("eclairage_auto") or not relais.est_connecte():
|
||||
return
|
||||
score = eclairage.get("score", -1)
|
||||
if score < 0:
|
||||
return
|
||||
seuil_1 = rcfg.get("seuil_proj1", 45)
|
||||
seuil_2 = rcfg.get("seuil_proj2", 30)
|
||||
seuil_off = rcfg.get("seuil_off", 65)
|
||||
if score >= seuil_off and (_proj_etat["proj1"] or _proj_etat["proj2"]):
|
||||
relais.projecteurs(False)
|
||||
_proj_etat["proj1"] = False
|
||||
_proj_etat["proj2"] = False
|
||||
elif score < seuil_2 and not _proj_etat["proj2"]:
|
||||
relais.projecteurs(True)
|
||||
_proj_etat["proj1"] = True
|
||||
_proj_etat["proj2"] = True
|
||||
elif score < seuil_1 and not _proj_etat["proj1"]:
|
||||
relais.activer("projecteur_gauche")
|
||||
_proj_etat["proj1"] = True
|
||||
|
||||
|
||||
def _usb_reset_canon():
|
||||
"""Reset USB ioctl du Canon EOS (vendor 04a9) pour débloquer un port stall."""
|
||||
@@ -316,11 +344,13 @@ async def lifespan(app: FastAPI):
|
||||
task_push = asyncio.create_task(_pusher_preview())
|
||||
task_spool = asyncio.create_task(tache_spool_demarrage())
|
||||
task_watchdog = asyncio.create_task(_watchdog_systemd())
|
||||
relais.connecter()
|
||||
yield
|
||||
task_dslr.cancel()
|
||||
task_push.cancel()
|
||||
task_spool.cancel()
|
||||
task_watchdog.cancel()
|
||||
relais.deconnecter()
|
||||
log.info("Arret du photobooth")
|
||||
camera.deconnecter()
|
||||
|
||||
@@ -609,6 +639,60 @@ async def api_eclairage():
|
||||
return resultat
|
||||
|
||||
|
||||
# --- API Relais ---
|
||||
|
||||
@app.get("/api/relais")
|
||||
async def api_relais_status():
|
||||
return relais.etat_complet()
|
||||
|
||||
|
||||
@app.post("/api/relais/{nom}/on")
|
||||
async def api_relais_on(nom: str):
|
||||
if nom == "projecteurs":
|
||||
relais.projecteurs(True)
|
||||
return {"ok": True}
|
||||
if not relais.activer(nom):
|
||||
return JSONResponse({"erreur": f"relais '{nom}' introuvable ou non connecté"}, 400)
|
||||
return {"ok": True}
|
||||
|
||||
|
||||
@app.post("/api/relais/{nom}/off")
|
||||
async def api_relais_off(nom: str):
|
||||
if nom == "projecteurs":
|
||||
relais.projecteurs(False)
|
||||
return {"ok": True}
|
||||
if not relais.desactiver(nom):
|
||||
return JSONResponse({"erreur": f"relais '{nom}' introuvable ou non connecté"}, 400)
|
||||
return {"ok": True}
|
||||
|
||||
|
||||
@app.post("/api/relais/canon/power-cycle")
|
||||
async def api_power_cycle_canon(req: Request):
|
||||
body = await req.json() if req.headers.get("content-type", "").startswith("application/json") else {}
|
||||
duree = body.get("duree", 3.0)
|
||||
loop = asyncio.get_event_loop()
|
||||
await loop.run_in_executor(None, relais.power_cycle_canon, duree)
|
||||
return {"ok": True}
|
||||
|
||||
|
||||
@app.get("/api/relais/config")
|
||||
async def api_relais_config():
|
||||
config = charger_config()
|
||||
return config.get("relais", {
|
||||
"eclairage_auto": False,
|
||||
"seuil_proj1": 45,
|
||||
"seuil_proj2": 30,
|
||||
"seuil_off": 65,
|
||||
})
|
||||
|
||||
|
||||
@app.post("/api/relais/config")
|
||||
async def api_relais_config_save(req: Request):
|
||||
body = await req.json()
|
||||
mettre_a_jour_config({"relais": body})
|
||||
return {"ok": True}
|
||||
|
||||
|
||||
@app.get("/api/camera/debug")
|
||||
async def api_camera_debug():
|
||||
"""Diagnostic complet de la caméra (preview, viewfinder, erreurs gphoto2)."""
|
||||
|
||||
Reference in New Issue
Block a user