Reboot Kobo: 3 appuis bouton de page (evdev EV_KEY) au lieu du triple-tap tactile
L'ancien triple-tap via finger_trace dessinait des points noirs (outil de demo FBInk), ne respawnait pas (mort definitif si le process tombait) et le tactile ne reveille pas l'appareil. Le power, lui, n'emet que des scancodes MSC_SCAN parasites (etat de charge USB). Les boutons de page emettent des EV_KEY propres (codes 193/194). reboot_watcher.sh: lit l'evdev (FD persistant, pas de perte d'evenements), declenche sur 3 press EV_KEY < 3 s, boucle de respawn. Plus de finger_trace. Refresh: full force au (re)demarrage (reset=1 cote client -> oubli de prev_image cote serveur) pour eviter un refresh partiel pose sur un ecran efface par le reboot.
This commit is contained in:
@@ -48,12 +48,15 @@ async def image(fresh: int = 0, bat: int | None = None, chg: int = 0) -> Respons
|
||||
|
||||
|
||||
@app.get("/frame.meta", response_class=PlainTextResponse)
|
||||
async def frame_meta(client: str = "kobo", bat: int | None = None, chg: int = 0) -> Response:
|
||||
async def frame_meta(
|
||||
client: str = "kobo", bat: int | None = None, chg: int = 0, reset: int = 0
|
||||
) -> Response:
|
||||
# Refresh partiel : rend l'image, calcule la zone modifiée vs le dernier frame de ce client,
|
||||
# et renvoie une ligne "MODE X Y W H SEQ" triviale à parser en shell busybox.
|
||||
# MODE ∈ {full, partial, noop}. Le PNG correspondant est récupéré via /frame.png.
|
||||
# reset=1 (1er cycle après un (re)démarrage Kobo) -> oublie l'état et force un full refresh.
|
||||
kobo.record(bat, bool(chg))
|
||||
info = await frame.compute_frame(client)
|
||||
info = await frame.compute_frame(client, reset=bool(reset))
|
||||
line = f"{info['mode']} {info['x']} {info['y']} {info['w']} {info['h']} {info['seq']}"
|
||||
return PlainTextResponse(line, headers={"Cache-Control": "no-store"})
|
||||
|
||||
|
||||
@@ -42,11 +42,17 @@ def _changed_bbox(prev: Image.Image, cur: Image.Image) -> tuple[int, int, int, i
|
||||
return diff.getbbox()
|
||||
|
||||
|
||||
async def compute_frame(client: str) -> dict:
|
||||
async def compute_frame(client: str, reset: bool = False) -> dict:
|
||||
"""Rend le dashboard, calcule le diff vs l'image précédente du client, met à jour son état
|
||||
et renvoie {mode, x, y, w, h, seq}. Le PNG correspondant est stocké pour /frame.png."""
|
||||
et renvoie {mode, x, y, w, h, seq}. Le PNG correspondant est stocké pour /frame.png.
|
||||
|
||||
reset=True (envoyé par la Kobo au 1er cycle après un (re)démarrage) oublie l'image
|
||||
précédente : l'écran a été effacé par le reboot, un diff partiel se poserait sur une base
|
||||
erronée. On force alors un full refresh propre."""
|
||||
state = _clients.setdefault(client, _ClientState())
|
||||
async with state.lock:
|
||||
if reset:
|
||||
state.prev_image = None # -> force_full ci-dessous
|
||||
cur = await render.render_image()
|
||||
full_w, full_h = cur.size
|
||||
state.seq += 1
|
||||
|
||||
@@ -174,7 +174,7 @@
|
||||
</div>
|
||||
|
||||
<footer>
|
||||
<span>Monitorink · 3 taps = redémarrer</span>
|
||||
<span>Monitorink · 3 appuis bouton page = redémarrer</span>
|
||||
{% if kobo.ok %}<span class="{% if kobo.low %}stale{% endif %}">{% if kobo.charging %}⚡{% else %}🔋{% endif %} Kobo {{ kobo.percent }}%{% if kobo.stale %} · ?{% endif %}</span>{% endif %}
|
||||
<span class="{% if stale %}stale{% endif %}">maj {{ updated }}{% if stale %} · DONNÉE PÉRIMÉE{% endif %}</span>
|
||||
</footer>
|
||||
|
||||
@@ -45,8 +45,19 @@ afin de ne pas réinventer (et risquer de casser) la gestion WiFi/suspend spéci
|
||||
- **Mode prod** (réglages par défaut) : refresh **5 min** (`MONITORINK_REFRESH=300`),
|
||||
**rétroéclairage éteint** (frontlight à 0), et **WiFi cyclé** — la radio est rallumée le
|
||||
temps du fetch puis coupée pendant le suspend `rtcwake -m mem` pour économiser la batterie.
|
||||
- Un **swipe** sur l'écran réveille le device et force un rafraîchissement.
|
||||
- Pour **arrêter** : maintenir le bouton power (le device se réveille sous Nickel).
|
||||
- **Redémarrer / restaurer Nickel** : **3 appuis rapides (< 3 s) sur un bouton de page**
|
||||
(frontal). `reboot_watcher.sh` lit l'evdev et déclenche un reboot logiciel propre sur 3 press
|
||||
EV_KEY (codes 193/194). Sur **batterie** le device est en suspend profond et les boutons
|
||||
frontaux ne le réveillent pas : faire d'abord **un appui power** (réveil), puis les 3 appuis
|
||||
dans la fenêtre d'éveil. Filet de secours : appui power **long** = reboot matériel.
|
||||
- Pourquoi pas le bouton power directement : sur ce Kobo (mx6sll) le power n'émet que des
|
||||
scancodes bruts `MSC_SCAN`, parasités par l'état de charge USB (peu fiable). Les boutons
|
||||
frontaux émettent des `EV_KEY` propres.
|
||||
- `reboot_watcher.sh` tourne en arrière-plan avec une boucle de respawn (il ne reste jamais
|
||||
mort). Calage/debug : lancer avec `MONITORINK_PWR_DEBUG=1` pour logger chaque évènement
|
||||
(`type/code/val`), puis repasser à `0`.
|
||||
- `finger_trace` (ancien déclencheur triple-tap tactile) n'est **plus utilisé** : on peut le
|
||||
retirer de `bin/fbink/`.
|
||||
- Logs : `/tmp/monitorink.log` (effacés au reboot).
|
||||
|
||||
## À valider sur l'appareil (cf. plan, tâche 8)
|
||||
@@ -57,4 +68,9 @@ afin de ne pas réinventer (et risquer de casser) la gestion WiFi/suspend spéci
|
||||
- Stabilité de `rtcwake -m mem` sur FW 4.38.23171 (sinon le fallback `state-extended` prend le
|
||||
relais ; en dernier recours `sleep`).
|
||||
- Cycle WiFi : confirmer qu'au réveil la reconnexion DHCP aboutit en < ~24 s (`has_ip` OK).
|
||||
- Boutons (reboot) : sur ce Kobo, `find_button_dev` retient `/dev/input/event3` et les boutons
|
||||
de page émettent `EV_KEY` codes 193/194 (struct `input_event` 16 o). Sur un autre modèle,
|
||||
recaler via `MONITORINK_PWR_DEBUG=1` (codes/format dans le log). **Sur batterie**, vérifier
|
||||
le geste réveil-power → 3 appuis frontaux dans la fenêtre d'éveil (les frontaux ne réveillent
|
||||
pas du suspend).
|
||||
- Autonomie réelle sur 24 h.
|
||||
|
||||
@@ -53,7 +53,8 @@ fi
|
||||
# Synchronise l'horloge RTC (sinon rtcwake calcule mal le réveil).
|
||||
hwclock -w -u 2>/dev/null
|
||||
|
||||
# Watcher triple-tap -> reboot (en arrière-plan, écran tactile libre car Nickel est mort).
|
||||
# Watcher bouton power -> reboot logiciel (en arrière-plan, Nickel mort).
|
||||
# Premier calage : préfixer par MONITORINK_PWR_DEBUG=1 pour logger device/format dans le log.
|
||||
sh "$BASE/reboot_watcher.sh" &
|
||||
|
||||
# Boucle bloquante. À la sortie (STOP tue monitorinkloop.sh), on reboot pour restaurer Nickel.
|
||||
|
||||
@@ -65,7 +65,10 @@ http_get() {
|
||||
|
||||
fetch_meta() {
|
||||
# Récupère la ligne "MODE X Y W H SEQ" du backend (avec batterie + client). Vide si KO.
|
||||
# Au 1er cycle après un (re)démarrage (FIRST=1), on demande reset=1 : l'écran a été effacé
|
||||
# par le reboot, on force un full refresh côté serveur pour éviter un partiel sur base erronée.
|
||||
murl="$META_URL?client=$CLIENT"
|
||||
[ "${FIRST:-0}" = 1 ] && murl="$murl&reset=1"
|
||||
q="$(bat_query)"; [ -n "$q" ] && murl="$murl&$q"
|
||||
http_get "$murl" -
|
||||
}
|
||||
@@ -170,6 +173,7 @@ wifi_down() {
|
||||
# MODE PROD : frontlight éteint, WiFi cyclé (off pendant le suspend), rtcwake mem.
|
||||
frontlight_off
|
||||
|
||||
FIRST=1 # 1er cycle après lancement -> demande un full refresh (reset=1) au backend
|
||||
while true; do
|
||||
log "--- itération ---"
|
||||
frontlight_off # réaffirme après chaque réveil
|
||||
@@ -195,6 +199,7 @@ while true; do
|
||||
partial) show_frame partial "$mx" "$my" ;;
|
||||
*) show_frame full ;; # full ou valeur inattendue -> full refresh sûr
|
||||
esac
|
||||
FIRST=0 # meta obtenue : le reset n'a plus lieu d'être pour les cycles suivants
|
||||
else
|
||||
log "meta ECHEC"
|
||||
offline
|
||||
|
||||
@@ -1,33 +1,92 @@
|
||||
#!/bin/sh
|
||||
# Monitorink — redémarrage par TRIPLE-TAP (restaure Nickel / relance proprement).
|
||||
# Lancé en arrière-plan par monitorink.sh (après que Nickel a été tué -> écran tactile libre).
|
||||
# Utilise finger_trace (FBInk) pour détecter les touchers ; pas de mapping de coordonnées.
|
||||
# Monitorink — reboot logiciel par TRIPLE-APPUI sur un BOUTON FRONTAL (restaure Nickel).
|
||||
# Lancé en arrière-plan par monitorink.sh. Remplace l'ancien triple-tap finger_trace qui
|
||||
# barbouillait l'écran de points noirs. Appui long sur power = reboot matériel = filet de
|
||||
# secours ultime.
|
||||
#
|
||||
# Pourquoi les boutons frontaux et pas le power : sur ce Kobo (mx6sll) le bouton power n'émet
|
||||
# que des scancodes bruts EV_MSC/MSC_SCAN, parasités par l'état de charge USB (impossible à
|
||||
# distinguer de façon fiable). Les boutons frontaux, eux, émettent des EV_KEY PROPRES
|
||||
# (type=1) codes 193 (KEY_F23) et 194 (KEY_F24), press(val=1)/release(val=0) nets, sans aucun
|
||||
# parasite. On compte 3 appuis (press) sur l'un OU l'autre en moins de 3 s.
|
||||
#
|
||||
# NB suspend : les boutons frontaux ne réveillent pas l'appareil du suspend profond (seul le
|
||||
# power le fait). En usage sur secteur (USB) l'appareil ne suspend pas vraiment -> le watcher
|
||||
# tourne en continu et le triple-appui marche tout le temps. Sur batterie, réveiller d'abord
|
||||
# par un appui power, puis faire les 3 appuis frontaux dans la fenêtre d'éveil.
|
||||
|
||||
BASE="$(dirname "$0")"
|
||||
cd "$BASE" || exit 1
|
||||
LOG="$BASE/monitorink.log"
|
||||
FT="./bin/fbink/finger_trace"
|
||||
FBINK="./bin/fbink/fbink"
|
||||
BB="./bin/busybox_kobo"
|
||||
DEBUG="${MONITORINK_PWR_DEBUG:-0}" # 1 = logge chaque évènement pour caler device/codes
|
||||
BTN_A=193 # bouton frontal 1 (KEY_F23)
|
||||
BTN_B=194 # bouton frontal 2 (KEY_F24)
|
||||
|
||||
[ -x "$FT" ] || { echo "[watcher] finger_trace absent" >> "$LOG"; exit 0; }
|
||||
echo "[watcher] triple-tap reboot actif" >> "$LOG"; sync
|
||||
# Repère le périphérique input des boutons (gpio-keys). Repli : event0.
|
||||
find_button_dev() {
|
||||
for ev in /dev/input/event*; do
|
||||
[ -e "$ev" ] || continue
|
||||
case "$(cat "/sys/class/input/${ev##*/}/device/name" 2>/dev/null)" in
|
||||
*gpio*key*|*power*|*Power*|*pmic*|*keys*) echo "$ev"; return 0 ;;
|
||||
esac
|
||||
done
|
||||
[ -e /dev/input/event0 ] && echo /dev/input/event0
|
||||
}
|
||||
|
||||
count=0
|
||||
last=0
|
||||
"$FT" 2>/dev/null | while read -r line; do
|
||||
case "$line" in
|
||||
*UP*|*RELEASE*|*Release*)
|
||||
now=$(date +%s)
|
||||
[ $((now - last)) -gt 3 ] && count=0
|
||||
count=$((count + 1))
|
||||
last=$now
|
||||
echo "[watcher] tap $count/3" >> "$LOG"; sync
|
||||
if [ "$count" -ge 3 ]; then
|
||||
echo "[watcher] TRIPLE-TAP -> reboot" >> "$LOG"; sync
|
||||
"$FBINK" -c -pmh "Redemarrage..." 2>/dev/null
|
||||
sleep 1; sync
|
||||
reboot
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
graceful_reboot() {
|
||||
echo "[watcher] TRIPLE-APPUI frontal -> reboot logiciel" >> "$LOG"; sync
|
||||
"$FBINK" -c -pmh "Redemarrage..." 2>/dev/null
|
||||
sleep 1; sync
|
||||
reboot
|
||||
}
|
||||
|
||||
echo "[watcher] reboot triple-appui frontal actif" >> "$LOG"; sync
|
||||
|
||||
# Boucle de respawn : si le lecteur meurt (réinit input au réveil, fd fermé), on le relance.
|
||||
# Le watcher ne reste jamais mort -> le reboot logiciel est toujours disponible.
|
||||
while true; do
|
||||
DEV="$(find_button_dev)"
|
||||
if [ -z "$DEV" ]; then
|
||||
echo "[watcher] aucun input bouton trouvé, retry 5s" >> "$LOG"; sync
|
||||
sleep 5; continue
|
||||
fi
|
||||
echo "[watcher] écoute $DEV" >> "$LOG"; sync
|
||||
|
||||
# IMPORTANT : ouvrir le périphérique UNE seule fois (FD 4) et lire séquentiellement.
|
||||
# Rouvrir à chaque évènement (dd if=$DEV) crée un gap qui fait perdre des évènements.
|
||||
# FD persistant = flux continu, zéro perte, zéro buffering.
|
||||
if ! exec 4< "$DEV"; then
|
||||
echo "[watcher] ouverture $DEV KO -> retry 5s" >> "$LOG"; sync
|
||||
sleep 5; continue
|
||||
fi
|
||||
|
||||
# Lit le flux evdev par enregistrements de 16 octets (struct input_event 32 bits :
|
||||
# timeval 8o + type 2o + code 2o + value 4o). od -> 16 octets décimaux (little-endian).
|
||||
count=0
|
||||
last=0
|
||||
while rec="$("$BB" dd bs=16 count=1 <&4 2>/dev/null | "$BB" od -An -tu1)"; do
|
||||
[ -z "$rec" ] && break # fd fermé/EOF -> respawn
|
||||
# shellcheck disable=SC2086
|
||||
set -- $rec # $1..$16
|
||||
[ "$#" -ge 13 ] || continue
|
||||
type=$(( $9 + ${10} * 256 ))
|
||||
code=$(( ${11} + ${12} * 256 ))
|
||||
val="${13}"
|
||||
[ "$DEBUG" = 1 ] && { echo "[ft] type=$type code=$code val=$val" >> "$LOG"; sync; }
|
||||
# On ne compte que les PRESS (val=1) EV_KEY (type=1) d'un bouton frontal.
|
||||
[ "$type" -eq 1 ] && [ "$val" -eq 1 ] || continue
|
||||
[ "$code" -eq "$BTN_A" ] || [ "$code" -eq "$BTN_B" ] || continue
|
||||
now=$(date +%s)
|
||||
[ $((now - last)) -gt 3 ] && count=0 # reset si > 3 s depuis le dernier appui
|
||||
count=$((count + 1))
|
||||
last=$now
|
||||
echo "[watcher] appui $count/3" >> "$LOG"; sync
|
||||
[ "$count" -ge 3 ] && graceful_reboot
|
||||
done
|
||||
|
||||
exec 4<&-
|
||||
echo "[watcher] lecteur input arrêté -> respawn" >> "$LOG"; sync
|
||||
sleep 1
|
||||
done
|
||||
|
||||
Reference in New Issue
Block a user