8x32 PI : séquences jusqu'à 120 PNG, test du fil de données, montage A validé

- serveur_web.py : séquences limitées à 120 PNG (message clair au-delà),
  envois jusqu'à 200 Mo, fichiers temporaires sur la carte SD (et plus dans
  /run, trop petit), garde-fou si une séquence est envoyée dans le cadre
  « fichiers séparés ».
- outils/test_fil_donnees.py : met GPIO 18 à 1 puis à 0 toutes les 10 s,
  pour suivre le signal au multimètre du Pi jusqu'à DIN.
- README : montage A (Pi en direct, LED en 4,4 V) testé et validé ; montage B
  (transistor 2N3904) déconseillé, trop lent (temps de stockage ≈ 0,2 µs
  face à un « 0 » de 0,4 µs) ; mise en garde sur les convertisseurs HV/LV ;
  dépannage « seule la 1re LED s'allume ».
- INTERFACE_WEB.md, CLAUDE.md : nouvelles limites, accès au Pi en Wi-Fi seul,
  lecteur activé au démarrage.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
bach
2026-10-08 20:15:01 +02:00
co-authored by Claude Opus 5.5
parent 1ea8500b82
commit 156f9ce438
6 changed files with 155 additions and 14 deletions
+29 -4
View File
@@ -85,8 +85,21 @@ PORT = 80
# d'utilisateur, n'importe lequel, et ce mot de passe).
MOT_DE_PASSE = None
# Taille maximum d'un envoi, en mégaoctets.
TAILLE_MAX_MO = 50
# Taille maximum d'un envoi, en mégaoctets (tous les fichiers ensemble).
TAILLE_MAX_MO = 200
# Nombre maximum d'images dans une SÉQUENCE de PNG (120 images = 10 secondes
# à 12 images/s, 5 secondes à 24 images/s).
MAX_IMAGES_SEQUENCE = 120
# Au-delà de ce nombre de PNG envoyés d'un coup dans le cadre « Un ou
# plusieurs fichiers », c'est sûrement une séquence envoyée au mauvais
# endroit (chaque PNG deviendrait une animation) : on refuse et on explique.
MAX_PNG_SEPARES = 10
# Où ranger les envois le temps de les vérifier : le dossier temporaire du
# système (sur la carte SD), pas /run qui est en mémoire vive et trop petit.
DOSSIER_ENVOIS = tempfile.gettempdir()
# Sous-dossiers spéciaux du dossier des animations. Leur nom commence par
# un point : le lecteur les ignore (voir lecteur.est_cache).
@@ -344,6 +357,7 @@ def accueil():
else ":" + request.host.rsplit(":", 1)[1],
extensions=",".join(lecteur.EXTENSIONS),
taille_max=TAILLE_MAX_MO,
max_images=MAX_IMAGES_SEQUENCE,
largeur=LARGEUR, hauteur=HAUTEUR,
)
@@ -383,6 +397,12 @@ def ajouter():
fichiers = [f for f in request.files.getlist("fichiers") if f.filename]
if not fichiers:
flash("Aucun fichier choisi.", "erreur")
nb_png = sum(f.filename.lower().endswith(".png") for f in fichiers)
if nb_png > MAX_PNG_SEPARES:
flash(f"{nb_png} PNG envoyés d'un coup : est-ce une séquence d'images ? "
"Utilisez plutôt le cadre « Une séquence de PNG », sinon chaque image "
"deviendrait une animation séparée.", "erreur")
return redirect(url_for("accueil"))
for fichier in fichiers:
base, extension = os.path.splitext(fichier.filename)
extension = extension.lower()
@@ -391,7 +411,7 @@ def ajouter():
f"(acceptés : {', '.join(lecteur.EXTENSIONS)}).", "erreur")
continue
# On enregistre d'abord dans un dossier temporaire, on vérifie, puis on range.
descripteur, temporaire = tempfile.mkstemp(suffix=extension, dir=lecteur.DOSSIER_ETAT)
descripteur, temporaire = tempfile.mkstemp(suffix=extension, dir=DOSSIER_ENVOIS)
os.close(descripteur)
fichier.save(temporaire)
probleme = verifier_animation(temporaire)
@@ -419,8 +439,13 @@ def ajouter_sequence():
if len(fichiers) < 2:
flash("Une séquence demande au moins 2 images PNG.", "erreur")
return redirect(url_for("accueil"))
if len(fichiers) > MAX_IMAGES_SEQUENCE:
flash(f"{len(fichiers)} images : c'est trop, une séquence peut en compter "
f"{MAX_IMAGES_SEQUENCE} au maximum. Découpez-la en plusieurs "
"animations, ou exportez-la en GIF.", "erreur")
return redirect(url_for("accueil"))
temporaire = tempfile.mkdtemp(dir=lecteur.DOSSIER_ETAT)
temporaire = tempfile.mkdtemp(dir=DOSSIER_ENVOIS)
for i, fichier in enumerate(fichiers):
if not fichier.filename.lower().endswith(".png"):
shutil.rmtree(temporaire)