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 KNMI/DMI, ICON-CH2, 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 suit aussi le biais historique de chaque modèle sur chaque ville favorite — comparaison des prévisions J+1 passées à une référence de réanalyse historique Open-Meteo. Cette référence combine observations assimilées et modélisation : elle ne doit pas être confondue avec une station au point exact. Les écarts systématiques 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/      ← LocaleUtils / applyPersistedLocale — SharedPreferences dédié, source unique app + widgets
│   └── network/     ← ApiResult, NetworkMonitor, error mapping
├── data/
│   ├── remote/      ← Interfaces Retrofit + DTOs + BatchedForecastSplitter
│   │                  (+ PreviousRunsApi pour le bootstrap J+1 du 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,
│                      FetchBiasObservationsUseCase, BootstrapBiasHistoryUseCase,
│                      weighting strategies
├── ui/
│   ├── citylist/    ← Accueil : cartes favorites compactes, scénarios repliables, heatmap 12 h
│   ├── citydetail/  ← Détail d'une ville : cartes, chart, tableaux
│   │   └── confidence/  ← Écran "Pourquoi cette confiance ?"
│   ├── enginecomparison/ ← Comparaison des quatre moteurs V3
│   ├── settings/    ← Paramètres (modèles, moteur V3, 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 (48 h) Météo-France
AROME France 2.5 km France 2 j (48 h) 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 11 km Global 7,5 j DWD  
ICON-D2 2 km Europe centrale 2 j DWD  
GFS 13 km Global 16 j NOAA (USA)
ECMWF 25 km Global 15 j ECMWF (UE)
ECMWF AIFS 28 km Global (IA) 15 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 18 h standard (48 h sur 00/06/12/18Z) NOAA  
MET Nordic 1 km Scandinavie 2,5 j MET Norway  
HARMONIE KNMI 5.5 km Europe 2,5 j KNMI (Pays-Bas)  
HARMONIE DMI 2 km Europe 2,5 j DMI (Danemark)  
ICON-CH2 2 km Suisse / Europe centrale 5 j MeteoSwiss  
BOM ACCESS 15 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).

À propos du groupe « France » : il désigne les domaines natifs Météo-France AROME. Il ne représente pas tous les modèles utilisables sur le territoire français. ARPEGE Europe, ICON-EU, HARMONIE DMI/KNMI et, selon la position, ICON-D2 ou ICON-CH2 peuvent aussi couvrir une ville française mais restent classés dans « Europe ». Les variantes AROME 15 minutes d’Open-Meteo ne sont pas ajoutées comme modèles indépendants : elles utilisent la même lignée AROME et leur horizon n’est que de quelques heures.

Diversité éditoriale du catalogue :

Autres modèles régionaux pouvant intéresser la France : Open-Meteo expose également MeteoSwiss ICON-CH1 (1 km), CHMI ALADIN Central Europe (~2,3 km), GeoSphere AROME Austria (2,5 km) et ItaliaMeteo ICON-2I (2 km). Leur domaine est plus régional : ils ne sont pas activés dans MeteoCompare 1.9.0 afin d’éviter d’ajouter des modèles souvent hors couverture selon la ville.

Note sur AROME HD et les variables dérivées

AROME France HD conserve un jeu de champs natifs plus réduit que certains autres modèles. La documentation Open-Meteo définit weather_code comme une variable dérivée pour AROME/ARPEGE, mais le client tolère également les réponses opérationnelles où weather_code ou cloud_cover total sont absents pour AROME HD.

Le client utilise donc en priorité le weather_code fourni par l’API. S’il manque, il infère d’abord pluie/neige depuis les précipitations et la température du même modèle. Pour les situations sèches où cloud_cover total manque aussi, les couches cloud_cover_low, cloud_cover_mid et cloud_cover_high servent à construire un indicateur de nébulosité de secours (maximum des couches) uniquement pour choisir l’icône clair/nuageux/couvert. Cette icône reste visuellement marquée comme inférée. Les données d’un modèle voisin ne sont jamais copiées pour « compléter » une cellule.

Les badges “%” restent conditionnés à la présence réelle de leur variable : une probabilité de précipitation absente n’est jamais transformée en 0 %, et une couverture nuageuse absente n’est jamais inventée.

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.

La TodaySummaryCard conserve un résumé immédiatement lisible mais détaille chaque variable dans quatre mini-cartes de même hauteur. La valeur centrale provient du moteur V3 sélectionné (Multi-consensus, Calibration, Scénarios ou Adaptatif), tandis que la plage, le spread et les indicateurs de convergence restent calculés exclusivement sur les sorties brutes des modèles.

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. La bande température superpose les repères ERA5 Tmax/Tmin sur 10 ans, chargés depuis l’API archive d’Open-Meteo et cachés 180 jours dans Room. Les graphes pluie/vent n’affichent pas de repère journalier sur une série horaire afin d’éviter de comparer des fenêtres temporelles différentes. Le graphique est zoomable au pincement sur l’axe temps (pinch à 2 doigts + pan) et réinitialisable au double-tap.

Les seuils actuels sont des heuristiques de présentation, pas une calibration scientifique ni une probabilité de justesse. Une future calibration prédictive devrait s’appuyer sur un corpus de vérification par variable, zone et échéance.

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
Biais faible Chip gris neutre + coche + petite valeur signée Le biais moyen signé est faible sur la fenêtre observée ; cela ne garantit pas la fiabilité globale du modèle
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 biais signé faible, la sheet reste volontairement prudente : elle ne transforme pas l’absence de biais moyen en garantie de précision générale.

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=meteofrance_arome_france_hd,meteofrance_arpege_europe,ncep_gfs_seamless,… et Open-Meteo répond avec les variables suffixées par la clé du modèle (temperature_2m_meteofrance_arome_france_hd, temperature_2m_meteofrance_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 DEBUG dédié MeteoCompare/Net permet de vérifier l’invariant en développement via Logcat.

Le batching réduit surtout le nombre de connexions, handshakes TLS et réveils radio. Aucun gain chiffré n’est annoncé sans benchmark reproductible.

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 :

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 et DMI (HARMONIE), MeteoSwiss (ICON-CH2), Bureau of Meteorology Australie (ACCESS), China Meteorological Administration (GRAPES).