Watchdog WiFi + reconnexion auto + fix timing surprise capture

- Watchdog connectivite toutes les 60s (check TCP 1.1.1.1:53)
- Si offline : scan WiFi et reconnexion auto aux reseaux enregistres
- Si internet restaure : flush immediat des spools (email + galerie)
- Surprise : capture declenchee 500ms apres affichage (au lieu de 1.7s apres)
  pour capturer la reaction naturelle des gens

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-09-18 12:32:31 +02:00
parent d21d87347d
commit 5f1a96ab8a
4 changed files with 113 additions and 36 deletions

View File

@@ -179,28 +179,46 @@ def envoyer_rapport_spool(nb_envoyes: int, destinataires: list[str], nb_echoues:
RETRY_INTERVAL = 300 # 5 minutes
WATCHDOG_INTERVAL = 60 # 1 minute
async def _flush_spools():
"""Vide les spools email + galerie."""
from backend.destinations import traiter_booth_spool, taille_booth_spool
loop = asyncio.get_event_loop()
total_mail = taille_spool()
if total_mail > 0:
log.info(f"Spool email: retry ({total_mail} en attente)")
nb, dests = await loop.run_in_executor(None, traiter_spool)
if nb > 0:
echoues = total_mail - nb
await loop.run_in_executor(None, envoyer_rapport_spool, nb, dests, echoues)
total_booth = taille_booth_spool()
if total_booth > 0:
log.info(f"Spool galerie: retry ({total_booth} en attente)")
await loop.run_in_executor(None, traiter_booth_spool)
async def tache_spool_periodique():
"""Retente emails + galerie en spool toutes les 5 min."""
from backend.destinations import traiter_booth_spool, taille_booth_spool
"""Watchdog connectivite (60s) + retry spool (5 min)."""
from backend.wifi import watchdog_tick
from backend.destinations import taille_booth_spool
await asyncio.sleep(15)
loop = asyncio.get_event_loop()
ticks_depuis_flush = 0
while True:
loop = asyncio.get_event_loop()
# Emails
total_mail = taille_spool()
if total_mail > 0:
log.info(f"Spool email: retry ({total_mail} en attente)")
nb, dests = await loop.run_in_executor(None, traiter_spool)
if nb > 0:
echoues = total_mail - nb
await loop.run_in_executor(None, envoyer_rapport_spool, nb, dests, echoues)
# Galerie booth
total_booth = taille_booth_spool()
if total_booth > 0:
log.info(f"Spool galerie: retry ({total_booth} en attente)")
await loop.run_in_executor(None, traiter_booth_spool)
await asyncio.sleep(RETRY_INTERVAL)
result = await loop.run_in_executor(None, watchdog_tick)
if result == "restored":
await _flush_spools()
ticks_depuis_flush = 0
else:
ticks_depuis_flush += 1
if ticks_depuis_flush >= RETRY_INTERVAL // WATCHDOG_INTERVAL:
has_spool = taille_spool() > 0 or taille_booth_spool() > 0
if has_spool:
await _flush_spools()
ticks_depuis_flush = 0
await asyncio.sleep(WATCHDOG_INTERVAL)
async def tache_spool_demarrage():

View File

@@ -201,3 +201,62 @@ def wifi_forget(ssid: str) -> dict:
def wifi_get_password(ssid: str) -> str | None:
return _charger_mdp().get(ssid)
# --- Watchdog connectivité ---
_internet_ok = False
def check_internet(timeout: int = 5) -> bool:
"""Teste la connectivité internet (DNS + HTTP rapide)."""
import socket
try:
socket.create_connection(("1.1.1.1", 53), timeout=timeout).close()
return True
except OSError:
return False
def watchdog_tick() -> str | None:
"""Vérifie internet. Retourne 'restored' si passage offline→online, None sinon."""
global _internet_ok
now_ok = check_internet()
if now_ok and not _internet_ok:
_internet_ok = True
log.info("Internet restauré — flush spool")
return "restored"
_internet_ok = now_ok
if not now_ok:
_tenter_reconnexion_wifi()
return None
def _tenter_reconnexion_wifi():
"""Si déconnecté du WiFi, tente de se reconnecter à un réseau enregistré visible."""
status = wifi_status()
if status["connecte"]:
return
log.info("Pas de WiFi — scan des réseaux enregistrés")
saved = {n["ssid"] for n in wifi_saved_list()}
if not saved:
return
try:
r = subprocess.run(
["nmcli", "-t", "-f", "SSID,SIGNAL", "dev", "wifi", "list", "--rescan", "yes"],
capture_output=True, text=True, timeout=15,
)
candidates = []
for line in r.stdout.strip().split("\n"):
p = _nmcli_split(line)
if len(p) >= 2 and p[0] in saved and p[1].isdigit():
candidates.append((p[0], int(p[1])))
candidates.sort(key=lambda x: -x[1])
for ssid, sig in candidates:
log.info(f"Tentative reconnexion WiFi: {ssid} (signal {sig}%)")
result = wifi_connect(ssid)
if result.get("succes"):
log.info(f"Reconnecté à {ssid}")
return
except Exception as e:
log.warning(f"Reconnexion WiFi échouée: {e}")