meteocompare

MeteoCompare

License: Apache 2.0 F-Droid Liberapay patrons

Application Android de comparaison multi-modèles météorologiques (AROME, ARPEGE, ICON, GFS, HRRR, ECMWF, UKMO, AIFS, GEM, MET Nordic, HARMONIE, ACCESS, GRAPES…) basée sur l’API Open-Meteo.

L’app se concentre sur les données brutes et l’incertitude : au lieu d’agréger silencieusement les modèles en une seule prévision, elle expose les désaccords entre modèles pour que l’utilisateur puisse juger lui-même du niveau de confiance à accorder à la prévision.

Depuis la v1.0, l’app apprend aussi le biais historique de chaque modèle sur chaque ville favorite — comparaison quotidienne des prévisions passées à ce qui a réellement été observé (ERA5). Les modèles qui surestiment ou sous-estiment systématiquement sont signalés d’une pastille discrète dans les tableaux, sans jamais modifier la donnée brute.

Get it on F-Droid Get it on Google Play

Fonctionnalités

Stack technique

Structure

app/src/main/java/com/meteocompare/app/
├── di/              ← Modules Hilt (Network, Repository, Dispatchers)
├── core/
│   ├── locale/      ← Helper applyPersistedLocale — source unique pour app + widgets
│   └── network/     ← ApiResult, NetworkMonitor, error mapping
├── data/
│   ├── remote/      ← Interfaces Retrofit + DTOs + BatchedForecastSplitter
│   │                  (+ HistoricalForecastApi pour le backfill de biais)
│   ├── mapper/      ← DTO ↔ domain
│   ├── local/       ← Room (ForecastCache, ClimateNormals, ForecastSample, ObservationSample)
│   ├── preferences/ ← DataStore
│   ├── repository/  ← Implémentations (dont le coalescing des fetches concurrents)
│   └── worker/      ← BiasRefreshWorker + Scheduler (WorkManager, fenêtre 24h)
├── domain/
│   ├── model/       ← Modèles métier (City, ForecastSeries, WeatherModel, ModelFamily,
│   │                  Coverage, DayNormals, HourlyConfidenceBand, WeatherCondition,
│   │                  BiasSample, ModelBias, BiasVariable, BiasSignificance…)
│   ├── repository/  ← Interfaces (dont BiasSampleRepository)
│   └── usecase/     ← ConfidenceCalculator, ComputeBiasUseCase, SnapshotForecastUseCase,
│                      FetchBiasObservationsUseCase, BackfillHistoricalForecastUseCase,
│                      weighting strategies
├── ui/
│   ├── citylist/    ← Liste des villes favorites (accueil)
│   ├── citydetail/  ← Détail d'une ville : cartes, chart, tableaux
│   │   └── confidence/  ← Écran "Pourquoi cette confiance ?"
│   ├── settings/    ← Paramètres (modèles avec tri, thème, langue)
│   ├── components/  ← Composables réutilisables (WeatherIcon, WindArrow, ShimmerBox…)
│   ├── accessibility/ ← Formatage des descriptions TalkBack
│   ├── theme/       ← Couleurs, typographie, tokens M3
│   └── navigation/  ← Routes et NavHost
└── widget/          ← MeteoWidget (Glance), config activity, splitter loader

Modèles supportés

Listés dans WeatherModel.kt avec leur résolution native (km), leur horizon, leur zone de couverture, et leur institution source (ModelFamily).

Modèle Résolution Couverture Horizon Institution Par défaut
AROME France HD 1.5 km France 2 j Météo-France
AROME France 2.5 km France 2 j Météo-France  
ARPEGE Europe 11 km Europe 4 j Météo-France
ARPEGE World 25 km Global 4 j Météo-France  
ICON-EU 7 km Europe 5 j DWD (Allemagne)
ICON 13 km Global 7 j DWD  
ICON-D2 2 km Europe centrale 2 j DWD  
GFS 13 km Global 16 j NOAA (USA)
ECMWF 25 km Global 10 j ECMWF (UE)
ECMWF AIFS 25 km Global (IA) 10 j ECMWF
UKMO Global 10 km Global 7 j UK Met Office
GEM Global 15 km Global 10 j ECCC (Canada)  
HRRR 3 km USA continental 2 j NOAA  
MET Nordic 1 km Scandinavie 3 j MET Norway  
HARMONIE 5.5 km Europe 2 j KNMI (Pays-Bas)  
BOM ACCESS 12 km Global 10 j Bureau of Meteorology (Australie)  
CMA GRAPES 15 km Global 10 j China Meteorological Administration  

Les modèles marqués “Par défaut” sont activés dès la première ouverture ; les autres sont activables dans les Settings, désormais triables par zone, par famille ou par finesse (résolution native).

Diversité éditoriale du catalogue :

Note sur AROME HD et les icônes de temps

Open-Meteo documente que “AROME France HD has the same model area, but at higher resolution with a smaller selection of weather variables” — la variable weather_code (code météo synthétique) n’est pas exposée pour AROME HD, contrairement à AROME (2.5 km) qui la fournit. Le compromis est assumé côté modèle : la résolution 1.5 km au prix d’un jeu de sorties réduit. Idem pour cloud_cover et precipitation_probability — non exposées.

Pour éviter des cellules vides dans le tableau Jour × Modèle, on infère la condition pour AROME HD depuis les précipitations et la température min :

Les badges “%” (couverture nuageuse / probabilité de pluie) sous les icônes ne s’affichent que pour les modèles qui exposent effectivement les variables — pas de fallback bidouillé côté client.

Indice de confiance

ConfidenceCalculator agrège les prédictions multi-modèles en un score 0-100 par variable pour chaque jour ET pour chaque heure.

Algorithme :

val daily = calculator.dayConfidence(forecast, LocalDate.now())
val hourlyTemp: List<HourlyConfidenceBand> = calculator.hourlyTemperatureConfidence(forecast)
val hourlyPrecip: List<HourlyConfidenceBand> = calculator.hourlyPrecipitationConfidence(forecast)
val hourlyWind: List<HourlyConfidenceBand> = calculator.hourlyWindConfidence(forecast)
val currentCondition: WeatherCondition? = calculator.currentWeatherCondition(forecast)
val currentCloudCover: Int? = calculator.currentCloudCover(forecast)
val matrix: List<DayConditionsRow> = calculator.dailyConditionsByModel(forecast)

DayConditionsRow.extrasByModel porte les métadonnées par cellule (probabilité de pluie max journalière, couverture nuageuse moyenne journalière) qui alimentent les badges “%” sous les icônes.

Bande de confiance multi-métriques : le composant ConfidenceBandSection encapsule un sélecteur segmenté à 3 états (Température / Précipitations / Vent) au-dessus d’un graphe unique. Les 3 séries de bandes sont pré-calculées dans le ViewModel — la transition entre métriques est instantanée. Chaque bande superpose l’overlay des normales climatiques 10 ans (traits pointillés colorés par métrique) chargées depuis l’API archive d’Open-Meteo et cachées 180 jours dans Room. Le graphique est zoomable au pincement sur l’axe temps (pinch à 2 doigts + pan) et réinitialisable au double-tap.

Les seuils sont calibrés à partir d’observations empiriques sur l’Europe. À ajuster quand on aura des données de skill verification.

Page “Pourquoi cette confiance ?”

Un clic sur le badge de confiance (en haut à droite de la carte “Aujourd’hui”) ouvre une explication détaillée qui compose l’edge éditorial de l’app :

  1. Résumé du jour avec verdict en langage naturel (“les modèles convergent fortement”, “désaccord significatif”…)
  2. Une carte par variable (température max, min, précipitations, vent) montrant :
    • Le résumé inter-modèles (valeur unique si convergence, plage si dispersion)
    • Le tableau modèle par modèle avec code couleur identique aux graphes de comparaison
    • La résolution de chaque modèle contribuant à ce jour
    • Une phrase d’interprétation qui traduit les chiffres en sens
  3. Section éducative “Pourquoi les modèles diffèrent ?” : paragraphe pédagogique sur la résolution + tableau des modèles ayant réellement contribué + astuce AROME HD vs GFS/ECMWF

Suivi de biais par modèle

L’app évalue en continu la précision de chaque modèle sur chaque ville favorite en croisant :

Pour chaque paire (modèle, variable), ComputeBiasUseCase calcule sur une fenêtre glissante 30 jours :

Trois états visuels dans le tableau prévisions, footprint vertical identique pour préserver l’alignement des noms de modèle entre colonnes :

État Rendu Sémantique
Biais significatif Chip coloré rouge/bleu + flèche + valeur signée Le modèle sur/sous-estime — utile de le corriger mentalement
Calibré Chip gris neutre + coche + petite valeur signée Le modèle est fiable, aucune correction nécessaire
En attente Pastille vide avec dash < 14 jours de recouvrement, pas assez de données

Clic sur un chip (les deux premiers états) ouvre une sheet avec sparkline 30 jours superposant la prévision et l’observation, une grille de stats et un texte contextuel adapté à l’état. Pour un modèle calibré, le texte de la sheet ne parle plus de “surestimation” (mensonger) mais confirme la calibration — cohérence sémantique de bout en bout.

Coalescing des fetches : le ForecastRepositoryImpl dédoublonne les requêtes HTTPS concurrentes pour la même (city, models, forecastDays) via un registre Deferred sur un SupervisorJob du repo. Quand CityList, CityDetail et le widget cold-start-refreshent Paris en parallèle, une seule requête part réellement.

Widgets homescreen

Widget Glance redimensionnable en 4 tailles :

Les modes confidence rendent une heatmap horizontale colorée par la confiance sur 7 jours, avec sous chaque cellule la valeur agrégée et le jour de la semaine. C’est le rendu widget de la bande de confiance de l’écran détail.

Localisation widget : l’écran de config et le rendu du widget utilisent tous deux le helper applyPersistedLocale (dans core/locale/) pour respecter la préférence de langue de l’app, indépendamment de la locale système.

Batching multi-modèles

Depuis la refonte réseau, l’app fait 1 seule requête HTTPS pour récupérer les N modèles activés, au lieu de N requêtes parallèles. OpenMeteoApi.getForecastBatched demande ?models=arome_france_hd,arpege_europe,gfs_seamless,… et Open-Meteo répond avec les variables suffixées par la clé du modèle (temperature_2m_arome_france_hd, temperature_2m_arpege_europe, …).

Le BatchedForecastSplitter décompose la réponse en un ForecastResponseDto par modèle, transparent pour le reste de la chaîne (mapper et cache Room inchangés — chaque modèle a toujours sa propre ligne cache). Un log dédié Log.i("MeteoCompare/Net", "Batched fetch: N models…") permet de vérifier l’invariant en dev via adb logcat -s MeteoCompare/Net:I.

Gain observé : latence perçue divisée par ~2 sur 3G/4G lents, économie de handshakes TLS et de wakeups radio (batterie).

Premier lancement

  1. Ouvrir le projet dans Android Studio.
  2. Sync Gradle (le wrapper sera téléchargé automatiquement la première fois).
  3. Lancer sur émulateur API 27+ ou device.

Aucune clé API n’est nécessaire — Open-Meteo est gratuit pour usage non commercial.

Tests

./gradlew testDebugUnitTest             # tests JVM rapides
./gradlew connectedDebugAndroidTest     # UI, navigation, Room et DataStore sur appareil
./gradlew lintDebug assembleDebug        # analyse statique + compilation APK

La suite instrumentée utilise des repositories Hilt factices : aucune requête Open-Meteo n’est effectuée pendant androidTest. Elle couvre les parcours de navigation, les états Compose, l’accessibilité, la configuration widget, les DAO Room en mémoire, DataStore et la locale persistée.

La stratégie complète, les règles de stabilité et les commandes Windows sont documentées dans TESTING.md.

Accessibilité

Toutes les zones interactives ont des contentDescription lisibles par TalkBack :

Le module ui/accessibility/A11yFormatter.kt centralise les chaînes pour garder une terminologie cohérente.

Politique de confidentialité

Le fichier PRIVACY.md à la racine est conforme aux exigences Play Store : zéro collecte de données, déclaration explicite des permissions, des services tiers (Open-Meteo) et du stockage local.

À héberger sur GitHub Pages ou un Gist public, puis fournir l’URL dans Play Console.

Soutenir le développement

L’app est gratuite et open-source. Plusieurs options pour soutenir :

Aucun privilège n’est accordé aux donateurs — l’app et le code source restent identiques pour tous. Voir DONATIONS.md pour plus de détails.

Roadmap

Fait :

À venir :

Licence

Apache License 2.0 — vous pouvez utiliser, modifier et redistribuer le code librement, à condition de conserver la notice de copyright.

Les données météo sont fournies par Open-Meteo (également open-source, AGPL-3.0). Les modèles eux-mêmes sont produits par leurs organismes respectifs : Météo-France (AROME, ARPEGE), DWD (ICON, ICON-D2), NOAA (GFS, HRRR), ECMWF (IFS et AIFS), UK Met Office (UKMO), Environnement et Changement climatique Canada (GEM), MET Norway (MET Nordic), KNMI (HARMONIE), Bureau of Meteorology Australie (ACCESS), China Meteorological Administration (GRAPES).