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"))
|
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}"})
|
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():
|
async def surveiller_dslr():
|
||||||
"""Surveille le DSLR en continu : detecte les deconnexions et reconnecte automatiquement."""
|
"""Surveille le DSLR en continu : detecte les deconnexions et reconnecte automatiquement."""
|
||||||
global _dslr_erreurs
|
global _dslr_erreurs
|
||||||
|
_echecs_connexion = 0
|
||||||
while True:
|
while True:
|
||||||
await asyncio.sleep(5)
|
await asyncio.sleep(5)
|
||||||
if capture_en_cours:
|
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
|
# Le thread preview capture en permanence — preview_dslr_ok reflète la santé réelle
|
||||||
if camera.preview_dslr_ok:
|
if camera.preview_dslr_ok:
|
||||||
_dslr_erreurs = 0
|
_dslr_erreurs = 0
|
||||||
|
_echecs_connexion = 0
|
||||||
else:
|
else:
|
||||||
_dslr_erreurs += 1
|
_dslr_erreurs += 1
|
||||||
if _dslr_erreurs >= 3: # 3 x 5s = 15s sans preview valide
|
if _dslr_erreurs >= 3: # 3 x 5s = 15s sans preview valide
|
||||||
@@ -122,6 +143,7 @@ async def surveiller_dslr():
|
|||||||
camera.connecter(source="gphoto2")
|
camera.connecter(source="gphoto2")
|
||||||
if camera.connectee:
|
if camera.connectee:
|
||||||
log.info("DSLR reconnecte avec succes")
|
log.info("DSLR reconnecte avec succes")
|
||||||
|
_echecs_connexion = 0
|
||||||
await diffuser_ws({"type": "camera_ok"})
|
await diffuser_ws({"type": "camera_ok"})
|
||||||
else:
|
else:
|
||||||
log.warning("Echec reconnexion DSLR — nouvelle tentative dans 5s")
|
log.warning("Echec reconnexion DSLR — nouvelle tentative dans 5s")
|
||||||
@@ -133,9 +155,16 @@ async def surveiller_dslr():
|
|||||||
camera.connecter(source="gphoto2")
|
camera.connecter(source="gphoto2")
|
||||||
if camera.connectee:
|
if camera.connectee:
|
||||||
log.info("DSLR connecte avec succes")
|
log.info("DSLR connecte avec succes")
|
||||||
|
_echecs_connexion = 0
|
||||||
await diffuser_ws({"type": "camera_ok"})
|
await diffuser_ws({"type": "camera_ok"})
|
||||||
else:
|
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:
|
except Exception as e:
|
||||||
log.debug(f"surveiller_dslr: {e}")
|
log.debug(f"surveiller_dslr: {e}")
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user