diff --git a/deploy/releve-cellules/README.md b/deploy/releve-cellules/README.md index 46771c6..1124944 100644 --- a/deploy/releve-cellules/README.md +++ b/deploy/releve-cellules/README.md @@ -95,9 +95,15 @@ eux, couvrent tout le parc (agregat du Cerbo). Debrancher puis rebrancher le cable recree `/dev/ttyUSB0` accessible a root seul : le conteneur (uid 1026) meurt (« EIO: i/o error ») et ne repart pas. -`surveiller-port.sh` corrige cela toutes les 5 minutes, en root : pilotes -recharges si absents, droits du port rouverts, conteneur relance s'il est -arrete. Il ne fait rien si le cable est debranche, et ne journalise (tag +Et le NUMERO du port change : rebranche pendant que le conteneur tenait +`ttyUSB0` ouvert, le cable est revenu en `ttyUSB1` (25/09). `surveiller-port.sh` +corrige les deux toutes les 5 minutes, en root : pilotes recharges si absents, +lien stable **`/dev/pylontech-pack2`** cree d'apres le NUMERO DE SERIE du cable +(`A78KC4LE`, jamais l'ordre d'enumeration), droits rouverts, conteneur RECREE +si le port a change de numero (Docker resout le lien a la creation), relance +s'il est simplement arrete. `compose.yaml` mappe `/dev/pylontech-pack2` sur +`/dev/ttyUSB0` dans le conteneur. Un 2e cable FTDI s'ajoutera a la liste +`CABLES` du script, avec son propre service. Il ne fait rien si le cable est debranche, et ne journalise (tag `evcs-releve`, `journalctl -t evcs-releve`) que lorsqu'il agit. Pose en timer systemd (le Planificateur DSM n'a pas d'ajout en ligne de diff --git a/deploy/releve-cellules/compose.yaml b/deploy/releve-cellules/compose.yaml index 960854f..0927a0a 100644 --- a/deploy/releve-cellules/compose.yaml +++ b/deploy/releve-cellules/compose.yaml @@ -31,8 +31,13 @@ services: # Le depot est monte sur le .17 depuis le .22 : # 10.10.10.22:/volume2/projects -> /volume1/homes/TMZF5455/projects - /volume1/homes/TMZF5455/projects/EVCS/EVCS:/depot + # Nom STABLE cote hote (25/09) : le noyau numerote les ports a + # l'enumeration, et un rebranchement pendant que le port est tenu ouvert + # donne ttyUSB1 au lieu de ttyUSB0. surveiller-port.sh cree + # /dev/pylontech-pack2 d'apres le NUMERO DE SERIE du cable. Dans le + # conteneur le port reste /dev/ttyUSB0 : rien d'autre ne change. devices: - - /dev/ttyUSB0:/dev/ttyUSB0 + - /dev/pylontech-pack2:/dev/ttyUSB0 # ⚠️ Le pack 2 compte CINQ US2000 (adresses 1..5). Verifier cette liste # apres toute intervention physique sur la chaine. command: diff --git a/deploy/releve-cellules/surveiller-port.sh b/deploy/releve-cellules/surveiller-port.sh index b3e76e5..10aa0d0 100644 --- a/deploy/releve-cellules/surveiller-port.sh +++ b/deploy/releve-cellules/surveiller-port.sh @@ -2,19 +2,25 @@ # Garde du releve des cellules sur le Synology .17 (ARCHIVE3). A LANCER EN ROOT, # toutes les 5 minutes (timer systemd evcs-releve-port.timer, voir README). # -# Pourquoi (25/09/2026) : debrancher puis rebrancher le cable FTDI recree -# /dev/ttyUSB0 en crw------- root. Le conteneur, qui tourne en uid 1026, ne -# peut plus l'ouvrir : il meurt (« EIO: i/o error ») et ne repart pas seul. -# charger-pilotes.sh ne tourne qu'au demarrage du NAS, donc sans cette garde -# chaque debranchement coupait le releve jusqu'a une intervention manuelle. +# Deux defauts qu'elle corrige, tous deux vus le 25/09/2026 : +# 1. Un rebranchement recree le port accessible a root seul : le conteneur +# (uid 1026) meurt (« EIO: i/o error ») et ne repart pas. +# 2. Le NUMERO du port change : rebranche pendant que le conteneur tenait +# ttyUSB0 ouvert, le cable est revenu en ttyUSB1. Le conteneur pointait +# alors vers un port qui n'existait plus. +# D'ou un nom stable, /dev/pylontech-pack2, choisi d'apres le numero de SERIE +# du cable (jamais d'apres l'ordre d'enumeration), que le conteneur utilise. # -# Ce script ne fait RIEN quand tout va bien, et n'ecrit une ligne dans le -# journal systeme (tag evcs-releve) que lorsqu'il agit. Idempotent. +# Ne fait RIEN quand tout va bien ; n'ecrit dans le journal systeme (tag +# evcs-releve) que lorsqu'il agit. Idempotent. -PORT=/dev/ttyUSB0 +# Numero de serie du cable FTDI -> nom stable. Un 2e cable (pack 1, US5000) +# s'ajoutera ici, avec son propre service dans compose.yaml. +CABLES="A78KC4LE:pylontech-pack2" CONTENEUR=evcs-releve-cellules DOCKER=/usr/local/bin/docker -DIR=$(dirname "$0") +DIR=$(cd "$(dirname "$0")" && pwd) +ETAT=/run/evcs-releve-port.cible dire() { logger -t evcs-releve "$*"; echo "$*"; } # Pilotes decharges (ne devrait arriver qu'apres une MAJ DSM) : on les recharge. @@ -23,19 +29,46 @@ if ! /sbin/lsmod | grep -q "^ftdi_sio "; then /bin/sh "$DIR/charger-pilotes.sh" >/dev/null 2>&1 fi -# Cable debranche : rien a faire, le conteneur ne peut de toute facon pas -# demarrer sans son device. On attend le rebranchement. -[ -e "$PORT" ] || exit 0 +# Numero de serie du peripherique USB qui porte un ttyUSBn. +serie_de() { cat "$(dirname "$(dirname "$(readlink -f "/sys/bus/usb-serial/devices/$1")")")/serial" 2>/dev/null; } -# Droits perdus au rebranchement : on les rouvre. -if [ "$(stat -c %a "$PORT")" != "666" ]; then - chmod 666 "$PORT" - dire "droits de $PORT rouverts (cable rebranche ?)" +cible="" +for entree in $CABLES; do + sn=${entree%%:*}; nom=${entree#*:} + tty="" + for t in /sys/bus/usb-serial/devices/ttyUSB*; do + [ -e "$t" ] || continue + n=$(basename "$t") + [ "$(serie_de "$n")" = "$sn" ] && tty=$n + done + if [ -z "$tty" ]; then + rm -f "/dev/$nom" # cable absent : pas de lien qui pointe dans le vide + continue + fi + if [ "$(readlink "/dev/$nom")" != "/dev/$tty" ]; then + ln -sf "/dev/$tty" "/dev/$nom" + dire "/dev/$nom -> /dev/$tty (cable $sn)" + fi + if [ "$(stat -c %a "/dev/$tty")" != "666" ]; then + chmod 666 "/dev/$tty" + dire "droits de /dev/$tty rouverts (cable rebranche ?)" + fi + [ "$nom" = pylontech-pack2 ] && cible=$tty +done + +# Cable debranche : le conteneur ne peut pas tourner sans son port. On attend. +[ -n "$cible" ] || exit 0 + +# Le port a change de numero depuis la derniere creation du conteneur : il faut +# le RECREER (Docker resout le lien a la creation). Sinon, simple relance s'il +# est arrete. +if [ "$(cat "$ETAT" 2>/dev/null)" != "$cible" ]; then + (cd "$DIR" && "$DOCKER" compose up -d --force-recreate >/dev/null 2>&1) \ + && { echo "$cible" > "$ETAT"; dire "$CONTENEUR recree sur /dev/$cible"; } \ + || dire "$CONTENEUR : echec de la recreation" + exit 0 fi - -# Conteneur arrete : on le relance. -etat=$("$DOCKER" inspect -f '{{.State.Running}}' "$CONTENEUR" 2>/dev/null) -if [ "$etat" != "true" ]; then +if [ "$("$DOCKER" inspect -f '{{.State.Running}}' "$CONTENEUR" 2>/dev/null)" != "true" ]; then "$DOCKER" start "$CONTENEUR" >/dev/null 2>&1 \ && dire "$CONTENEUR relance" \ || dire "$CONTENEUR : echec de la relance"