ElecStat : un dashboard sur les données électriques françaises, sur une stack 100 % européenne
July 27, 2026•1,231 words
Introduction
Ce projet a pour vocation de tester les différentes alternatives européennes aux cloud providers américains : Scaleway pour les fonctions serverless et le stockage objet, Clever Cloud pour l'hébergement applicatif, Mistral AI pour le LLM. Le tout sur un cas d'usage réel.
Le périmètre retenu couvre les besoins classiques d'un projet data engineering : fonctions serverless, pipeline ETL planifié, stockage S3-compatible au format Parquet, infrastructure as code (Terraform), déploiement continu (GitHub Actions), authentification, exposition d'une API publique, et un chatbot branché sur les données. ElecStat les couvre tous.
Pourquoi les données électriques ?
Les données du système électrique français ont deux avantages pratiques : elles sont publiques, et elles sont mises à jour en continu — consommation et production sont publiées en quasi temps réel, à pas de 15/30 minutes. C'est une bonne source pour alimenter un pipeline.
RTE, le gestionnaire du réseau de transport français, publie des données très complètes, réparties sur plusieurs sites, chacun avec son usage :
- éCO2mix, l'application grand public, affiche les courbes de charge et le mix de production en temps réel.
- ODRE (Open Data Réseaux Énergies) publie les données brutes d'éCO2mix en open data, avec API et exports.
- Le portail Analyses & Données propose des données aggrégées et des exports CSV.
Chaque site couvre bien son usage. ElecStat est une proposition open source qui, sur un périmètre restreint (consommation, production, échanges), combine ces différents usages : visualiser les courbes ou les grands agrégats, interroger les données par API ou les exporter, questionner les données en langage naturel — le tout sur une stack technique européenne.
| Fonctionnalité | ODRE | Analyses & Données (RTE) | éCO2mix | ElecStat |
|---|---|---|---|---|
| Courbes de charge (pas 30 min) | 🟡 (données brutes) | ❌ | 🟡 (limitées à 8 semaines) | ✅ |
| Énergies (production par filière) | ❌ | ✅ | ❌ | ✅ |
| Exposition API | ✅ | ❌ | ❌ | ✅ |
| Chatbot | ❌ | ❌ | ❌ | ✅ |
| Téléchargement CSV | ✅ | ✅ | ❌ | ✅ |
ElecStat est en ligne sur statelec.cleverapps.io : visualisations Plotly, API publique documentée avec clés en libre-service, exports CSV sur toutes les pages, et un chatbot qui interroge directement les données.
La stack technique choisie
| Besoin | Choix |
|---|---|
| ETL serverless | Scaleway Functions |
| Stockage données | Scaleway Object Storage |
| Webapp + Postgres (clés api) | Clever Cloud |
| Chatbot IA | Mistral |
| IaC | Terraform |
| Déploiement continu | GitHub Actions |
La partie GitHub Actions est en cours de migration vers Gitea Actions.
Architecture
Le point structurant : l'ETL et la webapp ne communiquent que par le stockage. Les fonctions écrivent, la webapp lit ; le contrat entre les deux est le schéma des fichiers Parquet. Aucun appel direct, aucun couplage — chaque composant peut être redéployé, testé ou remplacé indépendamment de l'autre.
Pas de base de données pour les données métier
C'est le choix le plus original du projet : les fichiers Parquet sur Object Storage sont la base de données, interrogés en SQL par DuckDB depuis la webapp. Postgres n'existe que pour une seule table — les clés d'API —, le système de fichiers de l'hébergeur étant éphémère.
Le raisonnement : les données sont rafraîchies quelques fois par jour, lues en lecture seule, et se prêtent à des agrégations analytiques sur colonnes — exactement le cas d'usage de DuckDB. Une base relationnelle aurait imposé un service à administrer, des migrations de schéma et un coût fixe, pour un besoin purement lecture.
Côté performances, un cache local télécharge chaque fichier Parquet une fois par déploiement, puis un thread de fond revérifie les ETags S3 toutes les dix minutes et ne retélécharge que ce qui a changé. Les requêtes des visiteurs restent en permanence sur le disque local : environ 2,3 s au premier chargement du dashboard, 8 ms ensuite.
L'ETL : deux fonctions cron, zéro serveur
Deux fonctions Python 3.12 sur Scaleway Functions, déclenchées par cron, provisionnées par Terraform.
odre-eco2mix (horaire) est le cœur du pipeline :
- Téléchargement conditionnel : la fonction consulte d'abord la métadonnée de fraîcheur du dataset via l'API catalogue ODRE, sans télécharger le fichier. Si rien n'a changé, elle s'arrête là — la plupart des exécutions sont donc des no-op de quelques centaines de millisecondes.
- Fusion temps réel / consolidé : ODRE publie deux versions des mêmes données. Sur les horodatages communs, le consolidé gagne ; le temps réel ne sert qu'au-delà de sa frontière.
- Conservation de l'historique : ODRE purge son historique au fil du temps. Chaque nouvelle extraction est fusionnée avec l'existant sur le bucket — le fichier résultant conserve un historique indéfini, devenu irremplaçable.
scrape-rte-production (quotidienne) extrait les séries mensuelles éolien et solaire (production, facteur de charge) du portail Analyses & Données de RTE, en parsant les blocs JSON embarqués dans le HTML des pages. Fragile par nature : la structure de la page n'est pas contractuelle.
La webapp Django
Django 6, servi par Gunicorn et WhiteNoise sur une instance XS de Clever Cloud :
- Pages Consommation, Production, Échanges : graphiques Plotly chargés en AJAX (la page s'affiche immédiatement, les courbes suivent), exports CSV partout, et une page d'accueil en scrollytelling rendue côté serveur.
- API publique JSON en lecture seule (django-ninja) : documentation Swagger sur
/api/v1/docs, clés en libre-service — seul leur hash SHA-256 est stocké — et limitation de débit par clé. - Authentification OIDC générique : les endpoints sont découverts via l'issuer, n'importe quel fournisseur d'identité conforme fonctionne en changeant trois variables d'environnement. Sessions en cookies signés : aucun état côté serveur.
Le chatbot Mistral
Le chatbot repose sur une boucle tool-use : le modèle ne sort jamais un chiffre de sa mémoire, il appelle des outils qui encapsulent les mêmes services de données que l'API publique (consommation, production, échanges, pics, parc installé). Le prompt système injecte la date du jour et borne le périmètre à l'électricité française.
Le tout est stateless : le serveur ne stocke rien, l'historique vit dans le navigateur et expire après une heure d'inactivité. Les limites de débit de l'API Mistral (réponses 429) sont absorbées par des retries avec backoff, et un quota par utilisateur borne la dépense mensuelle.
Bilan
Coût total : environ 16 € par mois, dont l'essentiel pour la webapp sur Clever Cloud. Le free tier de Scaleway Functions couvre largement l'ETL (une quinzaine d'exécutions par jour) et l'Object Storage revient à quelques centimes.
Limites assumées :
- Le cloud public Scaleway n'est pas qualifié SecNumCloud — sans conséquence pour des données publiques, mais c'est un critère à considérer pour d'autres contextes.
- Le scraping RTE est fragile par construction : un changement de structure de la page source casse la collecte (les fonctions loguent ce qu'elles trouvent pour accélérer le diagnostic).
Ouvertures : un nom de domaine propre pour remplacer statelec.cleverapps.io, et de nouvelles sources de données — le découplage par le stockage rend leur ajout indolore pour la webapp.