Le 8 novembre 2026, j’ai donné vie à BIP : un petit robot qui habite sur un écran e-paper posé sur mon bureau. Son rôle est simple : me montrer mes merge requests, mes reviews et mes tickets Jira sans m’obliger à rouvrir trois onglets.

Au fil de la journée, BIP est passé d’une image de démonstration à un affichage connecté à mes outils. J’ai aussi appris une chose très concrète : un personnage peut être joli, mais si les chiffres sont trop petits, le tableau de bord rate son objectif.

Voici le montage et les étapes pour reproduire cette première version. Le code est téléchargeable ; les images de cet article utilisent des compteurs fictifs pour illustrer le résultat.

Ce que nous allons construire

BIP possède six scènes : café, compilation, review, panne, fusion et repos. Un script Python interroge GitLab et Jira toutes les cinq minutes, choisit une scène et compose une image en noir et blanc. L’écran ne reçoit une nouvelle image que si le contenu a changé.

Les trois compteurs représentent les MR ouvertes que vous avez créées, les MR où vous êtes désigné reviewer et les tickets Jira ouverts qui vous sont assignés. Le périmètre GitLab est limité au groupe choisi et à ses sous-groupes accessibles. Les brouillons sont inclus.

Une nuance compte : « reviews assignées » ne veut pas dire « reviews que je n’ai jamais relues ». Le compteur reste présent tant que vous êtes désigné reviewer sur une MR ouverte.

BIP avec trois grands compteurs MR, reviews et tickets Jira

Le rendu final : les chiffres passent au premier plan, BIP garde sa place en dessous. Données d’exemple.

Télécharger le code complet de BIP

1. Préparer le Raspberry Pi et l’écran

Mon montage utilise un Raspberry Pi Zero 2 W, une carte microSD avec Raspberry Pi OS Lite, une alimentation adaptée et un Waveshare e-Paper HAT 4,26 pouces noir et blanc de 800 × 480 pixels. Ce modèle communique en SPI. Vérifiez la référence exacte de votre dalle : un pilote pour un écran de taille voisine ne suffit pas.

Préparez le système avec Raspberry Pi Imager en configurant votre utilisateur, le Wi-Fi et SSH. Branchez le HAT lorsque le Pi est hors tension, puis démarrez et connectez-vous depuis votre ordinateur :

bash

ssh utilisateur@adresse-du-pi

Les commandes suivantes s’exécutent sur le Pi. Si vous préférez vérifier le branchement et lancer d’abord la démonstration du fabricant, suivez le manuel Waveshare du modèle 4,26 pouces.

2. Installer les dépendances et activer le SPI

L’application utilise Pillow pour dessiner l’image et les bibliothèques SPI/GPIO pour l’envoyer à l’écran. J’installe ici les paquets fournis par Raspberry Pi OS :

bash

sudo apt update
sudo apt install -y python3-pil python3-spidev python3-gpiozero fonts-dejavu-core cron unzip
sudo raspi-config nonint do_spi 0
sudo usermod -aG spi,gpio "$USER"
sudo systemctl enable --now cron
sudo reboot

Reconnectez-vous après le redémarrage, puis vérifiez que le périphérique existe :

bash

ls -l /dev/spidev0.0

Dans notre session, le SPI n’était pas encore activé : le programme pouvait générer une image, mais cela ne suffisait pas pour piloter l’écran. La documentation Raspberry Pi détaille les différentes méthodes de configuration, dont raspi-config.

3. Installer le code et afficher une première scène

Téléchargez l’archive sur le Pi, puis décompressez-la dans votre dossier personnel. Elle contient le dessin de BIP, la synchronisation, l’assistant de configuration, l’installation cron et les pilotes Waveshare utilisés, avec leurs en-têtes de licence conservés.

bash

curl -fL 'https://cdn.sanity.io/files/nrxsmjzk/production/7548c16e253204e86f4e506cbc905253d4de63d7.zip' -o /tmp/bip-raspberry-pi-gitlab-jira.zip
unzip -q /tmp/bip-raspberry-pi-gitlab-jira.zip -d "$HOME"
cd ~/devagotchi
python3 robot.py --state ready

Cette dernière commande génère un fichier preview.png sans toucher à l’écran. Pour envoyer la scène au HAT :

bash

python3 ~/devagotchi/robot.py --state ready --display

Une commande correspond à un affichage, puis l’écran est mis en veille. Ne lancez pas une boucle de démonstration rapide : ce projet est conçu pour une information qui change lentement.

Les scènes disponibles sont ready, build, review, error, merge et sleep. À cette étape, BIP fonctionne encore sans GitLab ni Jira : c’est volontairement un premier test isolé du matériel.

4. Préparer un accès GitLab en lecture

Créez un jeton personnel GitLab avec le périmètre read_api. Le compte associé doit pouvoir lire le groupe suivi et ses projets. Le projet n’a pas besoin d’écrire dans les dépôts ni de modifier les MR : il consulte les API. Consultez les périmètres des jetons GitLab pour adapter les droits à votre organisation.

L’assistant vérifie le compte via /api/v4/user et résout le groupe à partir de son chemin. Il enregistre son identifiant et celui de l’utilisateur pour filtrer les MR.

Pour détecter une compilation ou un échec, BIP lit le dernier pipeline associé à chacune de vos MR ouvertes. Il ne surveille donc pas tous les pipelines de tous les projets, ni les pipelines de branches sans MR. C’est une limite assumée de cette première version ; la documentation de l’API des merge requests décrit ces filtres et les informations de pipeline.

5. Connecter Jira et éviter le piège du HTTP 401

Créez ensuite un jeton API pour votre compte Atlassian. L’authentification utilisée ici associe l’adresse e-mail exacte du compte et le jeton. Avec un jeton doté de périmètres, l’URL de l’API passe par api.atlassian.com/ex/jira/{cloudId}, au lieu de l’URL habituelle du site. Les instructions Atlassian expliquent ces deux cas.

C’est le point qui nous a fait perdre du temps aujourd’hui. Plusieurs tests renvoyaient 401 et nous avions même essayé un nouveau jeton. La correction déterminante a été l’adresse du compte : une terminaison de domaine incorrecte. Dès que l’e-mail exact a été utilisé avec le nouveau jeton, l’authentification puis la recherche des tickets ont fonctionné.

Un 401 ne permet donc pas, à lui seul, de conclure que le jeton a expiré. Vérifiez d’abord le couple e-mail/jeton, puis le mode d’accès correspondant au type de jeton.

La requête de notre version est :

text

assignee = currentUser() AND statusCategory != Done ORDER BY updated DESC

Elle compte les tickets qui vous sont assignés et qui ne sont pas dans une catégorie de statut terminée. Le script utilise la recherche JQL /rest/api/3/search/jql et suit la pagination, conformément à la référence de recherche Jira Cloud.

6. Enregistrer les accès sans les afficher

Lancez l’assistant fourni dans l’archive :

bash

python3 ~/devagotchi/configure.py

Il demande l’URL GitLab, le chemin du groupe, le jeton GitLab, puis le site Jira, l’e-mail exact et le jeton Atlassian. La saisie des jetons utilise getpass : leur valeur n’apparaît pas pendant la saisie. Indiquez si le jeton Jira a été créé avec des périmètres.

Après vérification des accès, la configuration est écrite dans ~/.config/devagotchi/config.json. Le dossier a les permissions 0700 et le fichier 0600. Le fichier reste en clair pour que le programme puisse l’utiliser : les permissions limitent les accès des autres comptes ordinaires, elles ne constituent pas un chiffrement.

Aujourd’hui, nous avons aussi utilisé un fichier .env.local existant pour vérifier les accès. L’archive publique préfère une saisie interactive afin de ne dépendre ni de mon environnement de travail ni du nom de mes variables. Aucun jeton ni fichier de configuration personnel n’est inclus dans le téléchargement.

7. Transformer les événements en scènes

La synchronisation récupère les données des deux services, puis choisit la scène selon cet ordre :

  • Pipeline en échec sur une de mes MR ouvertes : BIP sort ses outils de réparation.
  • Pipeline en cours ou en attente : BIP bricole pendant la compilation.
  • Une de mes MR fusionnée depuis moins de quinze minutes : petite célébration.
  • Des reviews me sont assignées : BIP reçoit du courrier.
  • Des MR ou tickets restent ouverts sans ces événements : pause café entre deux actions.
  • Aucune MR, review ni ticket ouvert : repos.

La priorité évite de célébrer une fusion alors qu’un autre pipeline demande une intervention. L’état de repos est déduit des compteurs ; il n’est pas lié à un calendrier de travail.

Un échec réseau est traité séparément d’un pipeline en échec : le compteur du service inaccessible devient « ? » et un message invite à vérifier la connexion. Le programme ne remplace pas silencieusement une panne d’API par un zéro rassurant.

Pour vérifier la collecte sans changer l’écran :

bash

python3 ~/devagotchi/sync.py

Pour afficher les données :

bash

python3 ~/devagotchi/sync.py --display

8. Corriger l’UX : les chiffres avant le décor

Le premier rendu remplissait presque tout l’écran avec le robot et son atelier. Les compteurs étaient regroupés dans une petite ligne en bas. C’était joli, mais depuis le bureau, il fallait chercher l’information.

Première version de BIP avec des compteurs petits dans le pied de page

La première composition, reproduite avec des données fictives : le décor dominait les chiffres.

Nous avons inversé la hiérarchie : trois cartes occupent le haut de l’écran ; chaque valeur utilise une police de 96 pixels au lieu des 15 pixels de la première ligne. Les sous-libellés précisent « créées par toi », « assignées à toi » et « ouverts à ton nom ». BIP et son message restent en dessous, dans une scène plus compacte.

C’est la leçon UX de cette journée : décider ce qu’on doit lire en premier avant de travailler le décor. Le robot donne une personnalité au projet ; les compteurs en font un outil.

9. Automatiser sans rafraîchir inutilement l’écran

Installez la tâche planifiée fournie :

bash

python3 ~/devagotchi/install-cron.py
crontab -l
systemctl is-active cron

L’installateur conserve les autres tâches et ajoute une seule entrée pour BIP, toutes les cinq minutes. Sur le système configuré plus haut, cron la reprend aussi après un redémarrage.

Chaque exécution calcule une empreinte SHA-256 des pixels. Si l’image est identique à la dernière image envoyée avec succès, aucun nouvel affichage n’est déclenché. Un verrou empêche aussi deux synchronisations de piloter l’écran en même temps.

L’aperçu est enregistré dans ~/.cache/devagotchi/preview.png et le journal dans ~/.cache/devagotchi/sync.log. Ce journal est remplacé à chaque exécution et ne contient que l’état, les compteurs et des catégories d’erreur. Pour désactiver le suivi, retirez la ligne contenant « # BIP live sync » avec crontab -e.

bash

cat ~/.cache/devagotchi/sync.log

Ce qui fonctionne, et ce qui reste à améliorer

À la fin de cette session, nous avons validé l’accès réel aux deux services, envoyé l’image à l’écran et installé la planification. Un second passage avec des données identiques a confirmé l’absence de rafraîchissement inutile. Les compteurs publiés dans les illustrations restent des exemples.

Le Pi a également perdu la connexion SSH plusieurs fois pendant la mise en place. Nous avons pu reprendre les transferts, mais la stabilité du réseau reste un point à surveiller. La tâche tourne sur le Pi ; elle n’a pas besoin que le poste de développement reste connecté en SSH.

La prochaine évolution utile serait de distinguer une review simplement assignée d’une review qui nécessite encore une action, puis de choisir plus finement les projets suivis. Pour cette première journée, le résultat est déjà concret : BIP vit sur mon bureau, lit mes outils et me montre enfin des chiffres que je peux voir.