surveiller_dslr : reset USB automatique après 3 échecs de connexion Canon
Quand gphoto2 détecte le DSLR mais que camera.init() timeout répétitivement (USB stall après kill -9 ou déconnexion brutale), on tente un reset USB ioctl (USBDEVFS_RESET sur /dev/bus/usb/<bus>/<dev>) toutes les 3 tentatives (~15s). Évite de rester bloqué indéfiniment sur "Timeout reading from or writing to the port". Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -97,9 +97,29 @@ async def _pusher_preview():
|
||||
b64 = await loop.run_in_executor(None, lambda d=donnees: base64.b64encode(d).decode("ascii"))
|
||||
await diffuser_ws({"type": "preview", "image": f"data:image/jpeg;base64,{b64}"})
|
||||
|
||||
def _usb_reset_canon():
|
||||
"""Reset USB ioctl du Canon EOS (vendor 04a9) pour débloquer un port stall."""
|
||||
import fcntl, glob
|
||||
USBDEVFS_RESET = 0x5514
|
||||
try:
|
||||
for f in glob.glob("/sys/bus/usb/devices/*/idVendor"):
|
||||
if open(f).read().strip() == "04a9":
|
||||
d = __import__("os.path", fromlist=["dirname"]).dirname(f)
|
||||
bus = open(d + "/busnum").read().strip().zfill(3)
|
||||
dev = open(d + "/devnum").read().strip().zfill(3)
|
||||
path = f"/dev/bus/usb/{bus}/{dev}"
|
||||
with open(path, "wb") as fh:
|
||||
fcntl.ioctl(fh, USBDEVFS_RESET, 0)
|
||||
log.info(f"USB reset Canon: {path}")
|
||||
return
|
||||
except Exception as e:
|
||||
log.debug(f"_usb_reset_canon: {e}")
|
||||
|
||||
|
||||
async def surveiller_dslr():
|
||||
"""Surveille le DSLR en continu : detecte les deconnexions et reconnecte automatiquement."""
|
||||
global _dslr_erreurs
|
||||
_echecs_connexion = 0
|
||||
while True:
|
||||
await asyncio.sleep(5)
|
||||
if capture_en_cours:
|
||||
@@ -111,6 +131,7 @@ async def surveiller_dslr():
|
||||
# Le thread preview capture en permanence — preview_dslr_ok reflète la santé réelle
|
||||
if camera.preview_dslr_ok:
|
||||
_dslr_erreurs = 0
|
||||
_echecs_connexion = 0
|
||||
else:
|
||||
_dslr_erreurs += 1
|
||||
if _dslr_erreurs >= 3: # 3 x 5s = 15s sans preview valide
|
||||
@@ -122,6 +143,7 @@ async def surveiller_dslr():
|
||||
camera.connecter(source="gphoto2")
|
||||
if camera.connectee:
|
||||
log.info("DSLR reconnecte avec succes")
|
||||
_echecs_connexion = 0
|
||||
await diffuser_ws({"type": "camera_ok"})
|
||||
else:
|
||||
log.warning("Echec reconnexion DSLR — nouvelle tentative dans 5s")
|
||||
@@ -133,9 +155,16 @@ async def surveiller_dslr():
|
||||
camera.connecter(source="gphoto2")
|
||||
if camera.connectee:
|
||||
log.info("DSLR connecte avec succes")
|
||||
_echecs_connexion = 0
|
||||
await diffuser_ws({"type": "camera_ok"})
|
||||
else:
|
||||
log.warning("Echec connexion DSLR detecte")
|
||||
_echecs_connexion += 1
|
||||
log.warning(f"Echec connexion DSLR ({_echecs_connexion})")
|
||||
# Après 3 échecs consécutifs (~15s), reset USB pour débloquer un port stall
|
||||
if _echecs_connexion % 3 == 0:
|
||||
log.warning("Reset USB Canon tentative de deblocage...")
|
||||
_usb_reset_canon()
|
||||
await asyncio.sleep(3)
|
||||
except Exception as e:
|
||||
log.debug(f"surveiller_dslr: {e}")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user