Un panneau mural sans clavier
Une dalle bandeau de 1480 × 320 sur un mur, un Raspberry Pi derrière, et personne pour débuguer quand ça casse. Cette dernière contrainte a décidé de tout le reste.

Le point de départ de ce projet n’est pas une idée. C’est une déception.
Le Corsair Xeneon Edge m’a fait de l’œil pendant des semaines. Une dalle bandeau de 14,5 pouces, 2560 × 720 en 32:9, tactile cinq points, quatorze aimants intégrés pour la coller sur n’importe quelle surface en acier, 259,90 €. Exactement l’objet que je cherchais, fini, garanti trois ans.

Puis j’ai lu ce qu’il fait vraiment.
Ce n’est pas un appareil, c’est un deuxième écran. Corsair le classe lui-même en auxiliary display et en secondary display : il a une entrée HDMI, une entrée USB-C en DP Alt-Mode, et rien d’autre. Tout ce qu’il affiche est calculé par une machine qui doit être allumée.
Les widgets, alors ? Ils viennent d’iCUE. La FAQ de Corsair est d’une honnêteté désarmante :
You do not need iCUE to use the XENEON EDGE. […] Without iCUE, the XENEON EDGE will simply work as an additional monitor.
Autrement dit : la couche qui en fait un tableau de bord est iCUE. Sans elle, c’est un moniteur. Et les widgets d’iCUE se téléchargent sur le marché d’Elgato, où ils portent tous la même étiquette — Windows only.
Le compte est vite fait. Pour afficher l’heure sur un mur, il faut un PC Windows allumé en permanence. L’écran, lui, ne sait rien faire seul : ni au réveil, ni après une coupure, ni quand le PC est éteint.
Donc, le faire
Il y a un mur dans mon bureau où il ne se passait rien, et je voulais un écran qui tienne dessus sans avoir l’air d’un écran — autonome, allumé en permanence, sans rien d’autre derrière.
Le format, lui, ne se négociait pas : une dalle bandeau. J’ai pris une Waveshare 11,9 pouces en DSI à 130,99 € — 320 × 1480 natif, tournée en paysage, donc 1480 pixels de large sur 320 de haut. Un ratio de 4,6 pour 1. Pas de carte-mère, pas de logiciel, pas d’écosystème : une dalle nue et une nappe, que le Raspberry Pi pilote directement.
Le Raspberry Pi, je l’avais déjà — un 4B qui ne servait plus. Avec l’alimentation officielle 27 W, 19,84 €, et on verra plus loin pourquoi elle n’était pas facultative, le panneau m’aura donc coûté 150,83 € contre 259,90 € pour le Corsair.
Ce n’est pas ce qui m’a décidé, et je ne compte pas les trois semaines. Mais sortir une carte d’un tiroir pour obtenir l’objet qu’un produit fini ne savait pas être, c’est une satisfaction à part.
Rien n’est conçu pour ce format. Aucun thème, aucune grille, aucun tableau de bord. Les projets de miroir connecté supposent tous un écran vertical ou un 16/9. J’ai donc écrit le mien.

Mais ce n’est pas le format qui a été structurant. C’est autre chose, que je n’avais pas vu venir : l’appareil n’a pas de clavier, et ses lecteurs principaux sont mes enfants. Personne, devant ce mur, ne lira jamais un message d’erreur pour en faire quelque chose.
Trois semaines, 291 commits
Le dépôt commence le 26 août 2026 et la dernière version date du 21 septembre. Entre les deux, 291 commits — dont 49 le premier jour, 45 le deuxième, 36 le troisième.
Quarante-neuf commits en un jour, ça demande une explication, et je préfère la donner tout de suite : je n’ai pas écrit ce code tout seul. Je l’ai écrit avec une IA, en conversation, pendant trois semaines. C’est ce qu’on appelle maintenant du vibecoding, et j’y reviens à la fin — parce que c’est sans doute ce qu’il y a de plus intéressant dans ce projet.
Le rythme a aussi une raison matérielle : la dalle n’est arrivée que le 4 septembre. Pendant la première semaine, j’ai développé contre une géométrie que je n’avais pas, dans une fenêtre de navigateur redimensionnée à la main. Tout ce qui pouvait se décider sans le matériel a été décidé à ce moment-là, et c’est probablement ce qui a sauvé le projet : quand la dalle est arrivée, il restait un seul réglage à faire, l’orientation.
Les quatre lignes que j’avais écrites dans ma feuille de route avant la livraison valent d’être relues avec ce qui s’est réellement passé :
| Ce qui était prévu | Ce qui s’est passé |
|---|---|
Rotation par video=HDMI-A-1:…rotate=90 | écartée par la mesure — trois voies essayées, aucune ne fonctionne en KMS |
| Matrice de calibration tactile par règle udev | inutile — le compositeur applique la même transformation au tactile |
| Sous-tension à régler avant de brancher | disparue — la dalle alimente le Pi |
| « La dalle tire son 5 V du rail du Pi » | faux — la nappe DSI ne porte que la vidéo et l’I²C |
Quatre prévisions, quatre erreurs. Aucune n’a coûté cher parce qu’aucune n’avait été implémentée avant d’être mesurée.
Un écran sans clavier change tout
C’est la règle dont tout découle, et je l’ai écrite en tête du dépôt :
Dégradé, jamais blanc. Une coupure réseau grise une tuile, elle ne vide pas l’écran. Un layout fautif rend les tuiles valides et grise la fautive avec son message. Un certificat absent laisse l’administration en HTTP plutôt que de la rendre injoignable.
Formulé autrement : tout ce qui peut échouer doit échouer en affichant encore quelque chose. Sur un poste de travail, une page blanche est une invitation à ouvrir la console. Sur un mur, c’est un appareil mort.
J’ai appris la différence le 27 août, et de la pire manière.
La correction tient en trois lignes, et elle m’a coûté une soirée à comprendre :
[Service]
# systemd considere Caddy demarre avant qu'il n'ecoute : on attend la
# premiere reponse HTTP, pas le demarrage de l'unite.
ExecStartPre=/bin/sh -c 'for i in $(seq 1 30); do curl -sf http://localhost/ >/dev/null && exit 0; sleep 1; done; exit 1'
ExecStart=/usr/bin/chromium --kiosk http://localhost
Restart=alwaysLe même raisonnement a produit le volet de maintenance, qui descend du bord haut comme sur un téléphone. Il porte l’état des sources, la carte d’identité réseau de la machine — IP, MAC, SSID, passerelle, DNS, état de SSH — et trois boutons : Recharger, Redémarrer, Éteindre.
Il existe pour une seule raison : la page d’administration passe par le
réseau. Le jour où le LAN tombe, elle est injoignable exactement quand on en a
besoin. Le volet, lui, parle à 127.0.0.1.
Et il se referme seul au bout de quinze secondes — faute de quoi un enfant qui l’ouvre et s’en va laisserait le tableau caché.


Zéro dépendance, zéro build
Le navigateur charge les fichiers tels qu’ils sont écrits. Pas de framework, pas de bundler, pas de chaîne de build.
Ce n’est pas du purisme. Un bundle React ici coûterait 200 Ko pour afficher
douze chiffres, et une chaîne de build à maintenir pour un appareil censé
tenir des mois sans intervention. La contrepartie est le genre de simplicité
qu’on ne regrette pas : git pull sur le Pi est le déploiement.
Mais la règle a une exception, et c’est elle qui l’explique le mieux.
Trois tuiles posent un emoji en filigrane — météo, vacances, semaine A/B. Un emoji n’est pas un fichier du dépôt : c’est un glyphe fourni par une police du système. Raspberry Pi OS minimal n’en a aucune.
fc-list | grep -ci emoji
# 0
Chromium ne dessine alors rien. Pas d’erreur, pas de carré blanc, pas une ligne en console. La tuile s’affiche, correctement, sans son filigrane — et on peut passer à côté longtemps.
La leçon est plus large que l’emoji : tout ce qui sort du dépôt doit être posé
par le script d’amorçage, sinon une carte neuve arrive incomplète sans le
dire. bootstrap.sh installe donc fonts-noto-color-emoji.
Le runtime possède les timers
Un widget n’appelle jamais setInterval, fetch ni addEventListener sur
window. Il passe par ctx.every() et ctx.on().
Ça paraît cérémonieux pour un projet sans dépendances. C’est ce qui permet de suspendre les pages non affichées — sans quoi cinq pages de six widgets feraient tourner trente collectes en permanence, sur un Pi qui porte déjà Chromium.
Le navigateur ne parle jamais à une source
Ni adresse, ni identifiant, ni jeton ne descendent dans la page. Le shell
demande /relais/z420/data.json ; seul le serveur sait où cela mène. Le
CORS se résout au passage, sans y penser.
Quatre surfaces réseau, volontairement séparées :
| Port | Sert | Authentification |
|---|---|---|
80 | le shell, en clair — c’est ce que charge le kiosque | aucune |
443 | le même shell en HTTPS, si un certificat est configuré | aucune |
8080 | l’administration | mot de passe |
8081 | le service d’écriture | lié à 127.0.0.1 |
Le port qui alimente l’écran ne sert jamais de point d’écriture.
Ce que le matériel a coûté
C’est la partie où j’ai perdu le plus de temps, et pour une raison qui n’a rien à voir avec le logiciel.

Le Pi remontait des sous-tensions en continu : de l’ordre de 160 par heure. Le réflexe est d’accuser la puissance du chargeur. C’est faux.
vcgencmd get_throttled
# 0x50005 -> sous-tension detectee, et depuis le demarrage
J’ai commandé une alimentation officielle 27 W, puis mesuré une heure pleine, kiosque en marche :
fenêtre : 3600 s
sous-tensions : +0 (total 0)
get_throttled : 0x0
température : 68,2 → 69,6 °CZéro, contre une référence d’environ 160 par heure.
Et la cause est établie : c’est le câble, pas la puissance. Les 22,5 W du chargeur précédent suffisaient sur le papier ; c’est la chute de tension dans un câble USB-C quelconque qui provoquait les sous-tensions. Le bloc officiel a un câble captif dimensionné pour 5 A, qui n’en transporte que 1,5 — donc une chute négligeable.

Dernier retournement : la dalle n’est pas alimentée par le Pi. La nappe DSI ne porte que la vidéo et l’I²C ; le courant arrive par le Type-C de la dalle, qui alimente le Pi à son tour. Toute mon inquiétude sur le rail 5 V portait sur un circuit qui n’existe pas.

Deux réglages, et un seul comptait
En DSI, il n’y a pas de hdmi_timings : la dalle s’annonce elle-même. La
rotation ne passe pas non plus par le noyau — trois voies essayées en KMS,
aucune ne fonctionne. C’est le compositeur qui tourne :
output DSI-1 transform 90Une ligne. Et le tactile suit sans rien demander : sway lui applique la même
transformation, ce qui rend inutile la règle udev que j’avais prévue.
Le résultat
Version 3.12.1, en service sur sa dalle définitive.
| Hôte | Raspberry Pi 4B 2 Go, Raspberry Pi OS Lite Trixie |
| Affichage | sway + Chromium en kiosque sur http://localhost |
| Dalle | Waveshare 11.9” DSI, 320 × 1480 natif, tournée en paysage |
| Serveur | Caddy — fichiers statiques et relais |
| Démarrage | 13,2 s, NRestarts=0 |
| Widgets | 26 |
| Préréglages prêts à l’emploi | 48 |
| Dépendances | aucune |
Les tuiles vont de l’heure et la météo aux métriques d’un PC, un serveur Minecraft, une borne de recharge, la supervision Zabbix — et cinq tuiles qui ne servent qu’à la maison : les vacances scolaires, la semaine A ou B du collège, ce qu’il faut prendre ce matin, quel bac sortir ce soir, et un « ça va où ? » qui répond au toucher.


Le geste est la seule interface. Balayage horizontal pour changer de page, vertical pour changer de variante, appui court pour suspendre la rotation, appui long de 0,7 s pour épingler une page.
Un détail m’a occupé plus longtemps qu’il ne devrait : l’axe se décide au premier mouvement de 12 pixels, puis se fige. Sans ce verrou, un geste légèrement diagonal déclenchait les deux à la fois.

Ce que je n’aurais pas fait seul
Il faut que je sois clair, parce que c’est la chose la plus honnête que je puisse écrire sur ce projet : sans IA, je ne m’y serais jamais mis.
Je suis ingénieur systèmes et réseaux. Je lis du code, j’en corrige, j’en écris quand il le faut. Mais vingt-six widgets en JavaScript sans framework, un moteur de grille, un schéma de layout versionné, une page d’administration complète — j’aurais estimé le chantier à plusieurs mois de soirées, et je ne l’aurais pas commencé. Pas par incompétence : par arbitrage. Le coût d’entrée était plus élevé que l’envie.
C’est exactement ce que l’IA a déplacé. Pas la compétence — l’accès. Une idée du samedi matin devient une maquette le samedi soir, et c’est au moment où on la voit tourner qu’on décide si elle mérite trois semaines.
Il faut une idée, et quelqu’un pour trancher
Ce n’est pas de la dictée. Il faut une idée de départ — personne ne m’a soufflé qu’un mur de mon bureau était vide — et il faut vérifier ce qui sort, étape par étape.
Ça n’est pas de l’hygiène de principe, c’est structurel : une IA produit une réponse fausse avec exactement le même aplomb qu’une réponse juste. Elle ne sait pas qu’elle se trompe, donc elle ne le dit pas. Les quatre prévisions de ma feuille de route plus haut, elle les aurait implémentées toutes les quatre sans sourciller — c’est moi qui ai mesuré, et c’est la mesure qui les a démenties.
Le corollaire est moins intuitif : une IA est complaisante. Elle propose, et
ce qu’elle propose est presque toujours raisonnable en général. Sur ce projet,
elle m’a proposé un framework, une chaîne de build, SQLite pour la
configuration, une règle udev pour calibrer le tactile. Quatre réponses
parfaitement défendables. Quatre réponses fausses ici — pour un appareil
sans clavier qui doit tenir des mois et dont le déploiement doit rester un
git pull.
Cadrer et trancher, c’est le vrai travail. Et ça ne se délègue pas, parce que ça demande de savoir ce qu’on veut vraiment — ce qu’une conversation ne contient jamais entièrement.
Ce qu’elle n’a pas fait
Il serait malhonnête de s’arrêter là, parce que la liste des choses que l’IA n’a pas résolues est précisément celle des problèmes qui m’ont coûté du temps :
- Les 160 sous-tensions par heure. Aucune conversation ne les aurait trouvées. Il a fallu brancher un wattmètre, lancer une mesure d’une heure, et accepter que la réponse contredise l’hypothèse de départ.
- Les trois voies de rotation en KMS. Elles paraissaient toutes correctes sur le papier. Aucune ne fonctionne.
- Le kiosque qui n’essaie plus jamais. Le défaut n’est visible que sur le mur, après une coupure de courant, un soir.
- « La dalle tire son 5 V du rail du Pi ». Une supposition que j’ai portée trois semaines, et qu’une nappe DSI démentait depuis le début.
Le partage est net, et il n’a rien de décevant : l’IA a supprimé le coût d’entrée du logiciel ; le monde physique a continué de facturer plein tarif.
Ce qui change vraiment, du coup, ce n’est pas la vitesse d’écriture. C’est que le temps qu’on ne passe plus à produire du code, on le passe à mesurer — et c’est là que les vrais problèmes étaient.
Et surtout : elle n’a rien hébergé
C’est le point que j’ai failli écrire comme une nuance, et c’est en fait le cœur.
Ce panneau affiche la supervision Zabbix de mon parc, Plex via Tautulli, un serveur Minecraft, une borne de recharge, un agrégateur FreshRSS, qui est connecté au VPN, les capteurs d’une station de travail. Rien de tout ça n’est sorti d’une conversation. Ce sont des années d’infrastructure montée chez moi, supervisée, sauvegardée et maintenue — avec ses pannes, ses migrations et ses nuits blanches.
Sans ce substrat, le plus beau moteur de widgets du monde affiche l’heure et la météo. Autrement dit : un réveil.
Je n’ai pas fait écrire un tableau de bord. J’ai fait écrire une vitrine pour quelque chose qui existait déjà, et dont l’IA n’a pas posé une brique.
C’est pour ça que la question « quelle part revient à qui ? » me paraît mal posée. Ce n’est pas un pourcentage de lignes — ce serait mesurer un livre au poids de son encre. C’est une antériorité : il fallait que tout ça tourne déjà, chez moi, pour qu’il y ait quoi que ce soit à afficher.
Ce qui reste
Le boîtier — cotes relevées, dessin en cours. C’est la seule chose qui sépare ce panneau d’un objet fini, et ce sera un autre article.
En attendant, l’ensemble tient debout sur un socle à smartphone en bois, de ceux qu’on trouve chez Ikea pour trois euros. Ça n’a rien d’élégant, et ça a une vertu que je n’avais pas prévue : ça empêche de considérer le projet comme terminé. Un appareil posé de travers sur un bout de hêtre se rappelle à vous tous les matins.
Et un agrégateur : un service unique côté serveur qui collecte les sources
lentes et les expose en SSE. EventSource reconnecte seul, avec un backoff
intégré — sur un appareil qui doit tenir des mois, c’est zéro logique de reprise
à écrire. L’articulation est déjà en place : le jour venu, aucun widget ne
changera, seule la source à laquelle il s’abonne.
Ce que je retiens de ces trois semaines n’est pas une technique mais une discipline : chaque fois que j’ai voulu régler un problème avant de l’avoir mesuré, je me suis trompé. Les quatre prévisions de la feuille de route, la puissance du chargeur, la rotation par le noyau — quatre fois sur quatre, la mesure disait autre chose.
Un écran sans clavier ne pardonne pas les suppositions. Il les affiche.
Et c’est peut-être la vraie leçon du vibecoding : il rend le code bon marché, ce qui laisse d’autant moins d’excuses pour ne pas aller mesurer le reste.
Sommaire
Sommaire
- Donc, le faire
- Trois semaines, 291 commits
- Un écran sans clavier change tout
- Zéro dépendance, zéro build
- Le runtime possède les timers
- Le navigateur ne parle jamais à une source
- Ce que le matériel a coûté
- Deux réglages, et un seul comptait
- Le résultat
- Ce que je n’aurais pas fait seul
- Il faut une idée, et quelqu’un pour trancher
- Ce qu’elle n’a pas fait
- Et surtout : elle n’a rien hébergé
- Ce qui reste
