T2C-Screen : afficher les prochains départs T2C partout

T2C-Screen est un projet personnel autour des transports de Clermont-Ferrand. L'objectif était de récupérer les données du réseau T2C, calculer les prochains départs en temps réel, puis les afficher sur plusieurs supports : navigateur, matrice LED pilotée par ESP32 et widget Android.

L'historique GitHub visible s'étend de novembre 2025 à janvier 2026 pour le backend et le widget. Le projet est l'un des plus complets de mon portfolio parce qu'il relie données publiques, backend, IoT, application mobile et déploiement Docker.

T2C-Screen cover

Caractéristiques techniques du projet

  • Backend : Node.js, Express.
  • Données transport : GTFS statique, GTFS-RT Trip Updates, parsing ZIP/CSV et Protobuf.
  • Sécurité API : clés API, scopes, hash SHA-256, comparaison timing-safe.
  • Déploiement : Docker, Docker Compose, configuration pour NAS ou serveur personnel.
  • Frontend : SPA statique servie par Express, avec mode panneau plein écran.
  • IoT : ESP32, PlatformIO, matrice LED HUB75.
  • Mobile : widget Android Kotlin configurable.
  • Outils : scripts Python pour convertir et envoyer des bitmaps vers l'écran.

Architecture globale

Le projet est découpé en plusieurs clients autour d'une même API.

  1. Serveur Node/Express : télécharge le GTFS statique, construit les index, interroge le GTFS-RT et expose les endpoints.
  2. Frontend panneau : affiche les prochains départs dans une vue web simple, utile pour debug ou écran permanent.
  3. ESP32 + matrice HUB75 : consomme l'API et affiche deux directions sur une matrice LED.
  4. Widget Android : affiche les prochains départs directement sur l'écran d'accueil.
  5. Scripts Python : envoient des images ou bitmaps vers l'écran ESP32.

Backend Node/Express

Le backend parse les données GTFS statiques, puis les combine avec le flux GTFS-RT. Il expose ensuite des endpoints comme :

  • GET /api/routes
  • GET /api/stops?route=A
  • GET /api/departures?route=A&stopId=...
  • GET /api/_health/live
  • GET /api/_health/ready

Le service GTFS statique construit des index en mémoire. Le rechargement est fait par swap atomique : si une mise à jour échoue, l'ancien snapshot reste disponible.

Le service GTFS-RT met en cache le flux quelques secondes pour éviter de refaire un appel externe à chaque requête.

Sécurité de l'API

Les endpoints de données sont protégés par des clés API à scopes.

Le client peut envoyer une clé via Authorization: Bearer <token> ou X-API-Key. Le serveur compare le hash SHA-256 de la clé avec les valeurs stockées dans un fichier de configuration.

Cela permet de créer des clés différentes selon l'usage : frontend de debug, ESP32, widget Android ou client personnel.

ESP32 et matrice LED

La partie ESP32 vise un affichage physique, proche d'un petit panneau d'arrêt. Le firmware interroge régulièrement l'API et affiche les prochains départs sur une matrice HUB75.

L'ESP32 expose aussi quelques endpoints locaux pour :

  • changer la configuration route/arrêt ;
  • envoyer un message texte ;
  • envoyer un bitmap ;
  • vider l'affichage ;
  • régler la luminosité.

Les scripts Python convertissent des images en RGB565 pour les pousser vers l'écran.

Widget Android

Le dépôt t2c-widget complète le backend. Il contient un widget Android Kotlin configurable, avec choix de ligne et arrêt, préférences locales et mise à jour au déverrouillage.

Ce composant est intéressant parce qu'il montre que l'API n'a pas été pensée pour un seul écran. Le même backend peut servir un navigateur, un objet connecté et un widget mobile.

Ce que le projet m'a appris

T2C-Screen m'a fait travailler sur un vrai flux de données publiques, avec les problèmes classiques qui vont avec : format GTFS, temps réel partiel, cache, erreurs réseau, normalisation des arrêts et robustesse du parsing.

J'ai aussi appris à concevoir une API simple mais suffisamment propre pour être consommée par plusieurs clients très différents.

Auto-critique du résultat

Le projet gagnerait à avoir davantage de tests automatisés, surtout sur le calcul des départs et les fallbacks GTFS/GTFS-RT. Côté ESP32, la configuration pourrait être plus persistante et l'affichage pourrait mieux gérer les noms longs.

Le widget Android mérite aussi un README et une capture d'écran pour être immédiatement compréhensible.

Sources du projet

Sources du backend T2C-Screen

Le widget Android est dans un dépôt privé, mais il est intégré au périmètre technique présenté sur cette page.