diff --git a/kobo/monitorink.sh b/kobo/monitorink.sh index f2ed837..20bf841 100755 --- a/kobo/monitorink.sh +++ b/kobo/monitorink.sh @@ -15,8 +15,9 @@ cd "$BASE" || exit 1 # --- Configuration --- export MONITORINK_URL="http://192.168.0.43:8899/image.png" -export MONITORINK_REFRESH=300 # PROD: refresh partiel 5 min -# Cadence du full refresh : côté SERVEUR via MONITORINK_FULL_EVERY (PROD=12 ~1 h à 5 min/cycle). +export MONITORINK_REFRESH=900 # PROD: refresh partiel 15 min (moins de réveils = batterie) +# Cadence du full refresh : côté SERVEUR via MONITORINK_FULL_EVERY. À 15 min/cycle, FULL_EVERY=4 +# -> full refresh ~1 h (ajuster côté backend si besoin pour limiter le ghosting). echo "===== monitorink start $(date) =====" >> "$LOG"; sync diff --git a/kobo/monitorinkloop.sh b/kobo/monitorinkloop.sh index 8f7fbdc..6d9d623 100755 --- a/kobo/monitorinkloop.sh +++ b/kobo/monitorinkloop.sh @@ -121,32 +121,76 @@ frontlight_off() { done } +DIAG_DONE=0 +suspend_diag() { + # DIAGNOSTIC (one-shot) : quand un suspend échoue sur batterie, capture la raison + # du veto noyau dans le log. À retirer une fois la cause identifiée. + [ "$DIAG_DONE" = 1 ] && return + DIAG_DONE=1 + log "===== DIAG suspend (one-shot) =====" + for d in /sys/class/power_supply/*/; do + n=$(basename "$d") + log " $n: status=$(cat "${d}status" 2>/dev/null) online=$(cat "${d}online" 2>/dev/null) present=$(cat "${d}present" 2>/dev/null)" + done + log " wakeup_count=$(cat /sys/power/wakeup_count 2>/dev/null) state-extended=$(cat /sys/power/state-extended 2>/dev/null)" + # IRQ responsable du DERNIER réveil — la clé du mystère. + log " pm_wakeup_irq=$(cat /sys/power/pm_wakeup_irq 2>/dev/null) last_resume_reason=$(cat /sys/kernel/debug/wakeup/last_resume_reason 2>/dev/null)" + # Quels devices d'entrée sont armés comme source de réveil (1=oui). + log " -- input devices (name | wakeup) --" + for inp in /sys/class/input/input*/; do + nm=$(cat "${inp}name" 2>/dev/null) + wk=$(cat "${inp}power/wakeup" 2>/dev/null) + [ -n "$nm" ] && log " $(basename "$inp"): \"$nm\" wakeup=$wk" + done + # debugfs (souvent non monté) -> wakeup_sources triés par nb d'évènements. + mount -t debugfs none /sys/kernel/debug 2>/dev/null + if [ -r /sys/kernel/debug/wakeup_sources ]; then + log " -- top wakeup_sources (event_count) --" + awk 'NR>1 && ($3+0)>0 {print $3"\t"$1}' /sys/kernel/debug/wakeup_sources 2>/dev/null \ + | sort -rn | head -8 | while IFS= read -r l; do log " $l"; done + fi + # Les IRQ qui montent = source matérielle qui spamme (touch elan, gpio, etc.). + log " -- /proc/interrupts (lignes non nulles) --" + awk 'NR>1 && ($2+0)>0 {print $0}' /proc/interrupts 2>/dev/null \ + | sort -t: -k2 -rn 2>/dev/null | head -12 | while IFS= read -r l; do log " $l"; done + log " -- dmesg : lignes PM/wakeup/elan/gpio (40 dernières) --" + dmesg 2>/dev/null | grep -iE 'PM:|wakeup|abort|suspend|elan|gpio|irq' | tail -40 \ + | while IFS= read -r l; do log " $l"; done + log "===== /DIAG =====" +} + suspend_for() { - # Séquence Kobo éprouvée (trmnl-kobo) : state-extended=1 AVANT rtcwake, puis - # suspend manuel (echo mem) si rtcwake n'a pas vraiment suspendu. + # Suspend rtcwake (-m mem), réveil RTC après "secs". + # + # PIÈGE EPDC : juste après un refresh e-ink, la haute tension VEE du panneau n'est pas + # encore redescendue ; le pilote EPDC (20f4000.epdc) refuse alors de suspendre + # ("waiting for VEE stable ... please retry suspend later", error -2) et le noyau avorte + # TOUT le suspend. Sans gestion, on tombait dans un sleep CPU-allumé -> batterie vidée. + # Parade (recommandée par le noyau lui-même) : laisser VEE se décharger, puis RÉESSAYER + # le suspend jusqu'à ce qu'il prenne. secs="$1" sync - echo 1 > /sys/power/state-extended 2>/dev/null - start=$(date +%s) - "$BUSYBOX" rtcwake -a -s "$secs" -m mem 2>/dev/null - elapsed=$(( $(date +%s) - start )) - log "rtcwake elapsed=${elapsed}s" - if [ "$elapsed" -le 10 ]; then - log "suspend manuel via echo mem" - sleep 1; sync; sleep 2 - m_start=$(date +%s) - echo mem > /sys/power/state 2>/dev/null - log "echo mem elapsed=$(( $(date +%s) - m_start ))s (≈${secs}=OK, ≈0=USB branché/suspend bloqué)" - fi - echo 0 > /sys/power/state-extended 2>/dev/null - # Repli : si rien n'a réellement suspendu (USB branché, etc.), on attend le temps - # restant en sleep pour ne pas boucler en continu (martèlement backend + batterie). - total=$(( $(date +%s) - start )) - if [ "$total" -lt "$secs" ]; then - rem=$(( secs - total )) - log "suspend incomplet (${total}s) -> sleep ${rem}s" - sleep "$rem" - fi + sleep 8 # laisse l'EPDC couper ses rails (VEE) ~10s après le refresh + attempt=0 + while [ "$attempt" -lt 6 ]; do + attempt=$((attempt + 1)) + sync + echo 1 > /sys/power/state-extended 2>/dev/null + start=$(date +%s) + "$BUSYBOX" rtcwake -a -s "$secs" -m mem 2>/dev/null + elapsed=$(( $(date +%s) - start )) + echo 0 > /sys/power/state-extended 2>/dev/null + log "rtcwake tentative=$attempt elapsed=${elapsed}s" + # elapsed grand = on a réellement dormi (réveil RTC ou bouton) -> terminé. + [ "$elapsed" -ge 15 ] && return + # Échec immédiat (EPDC/VEE pas prêt) : on attend un peu et on retente. + sleep 3 + done + # Toujours pas suspendu après les retries (cas anormal) -> diag + repli sleep pour ne pas + # marteler le backend, sans laisser le CPU tourner inutilement plus que "secs". + log "suspend impossible après $attempt tentatives -> diag + sleep" + suspend_diag + sleep "$secs" } has_ip() { ip addr show 2>/dev/null | grep -o 'inet [0-9.]*' | grep -qv '127.0'; }