Application Android de comparaison de 21 modèles météorologiques (AROME, ARPEGE, ICON, GFS, HRRR, NOAA AIGFS, ECMWF IFS/AIFS, UKMO, GEM, JMA GSM, MET Nordic, HARMONIE KNMI/DMI, ICON-CH2, ACCESS, GRAPES…) basée sur l’API Open-Meteo, avec un horizon d’affichage allant jusqu’à 10 jours et la Vigilance officielle Météo-France relayée par le Worker public MeteoCompare.
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.
💝 Vous aimez MeteoCompare ? L’application est gratuite, libre, sans publicité et sans fonctions premium. Vous pouvez soutenir son développement via Liberapay, GitHub Sponsors ou Ko-Fi. Les dons restent entièrement facultatifs et ne changent pas les fonctionnalités disponibles.
WeatherConditionConsensus consolide les codes WMO par grandes familles météorologiques (précipitation / non-précipitation, puis ciel/brouillard et liquide/neige/verglas/orage) avant de choisir la condition précise. La branche ciel utilise la nébulosité centrale V3 pour éviter de sur-représenter « Couvert ».meteocompare.app/_mcx/vigilance, détail des phénomènes et créneaux, et vagues-submersion dans la section marine. Les villes hors France ne déclenchent aucun appel Vigilance et la suppression d’un favori purge son état/cache Vigilance. Aucun secret Météo-France n’est embarqué dans l’APK.⋮ lorsqu’une localité est éligible au mode côtier, puis une icône 🌊 près du nom uniquement lorsque l’option est réellement activée. La page Détails affiche alors vagues, houle, température de mer et marées estimées. La décision d’éligibilité est mise en cache 6 h avec revalidation ; les données restent indicatives et ne sont pas destinées à la navigation.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
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) | ✓ |
| NOAA AIGFS | 25 km | Global (IA) | 16 j | NOAA (USA) | ✓ |
| ECMWF IFS HRES | 9 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) | |
| JMA GSM | 55 km | Global | 11 j | JMA (Japon) | ✓ |
| 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.
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.
ConfidenceCalculator agrège les prédictions multi-modèles en un score 0-100 par variable pour chaque jour ET pour chaque heure.
Algorithme :
ForecastConsensus déduplique les variantes apparentées par lignée numérique et leur partage une masse de vote, afin d’éviter qu’une famille disposant de plusieurs variantes ne domine artificiellement le résultat.PRECIPITATION / NON_PRECIPITATION, puis SKY / FOG ou LIQUID / FROZEN / FREEZING_RAIN / THUNDERSTORM, puis la feuille WMO précise. À chaque niveau, les variantes de modèles restent équilibrées par lignée. Cette structure évite aussi bien la fragmentation CLEAR / MAINLY_CLEAR / PARTLY_CLOUDY / OVERCAST que des cas DRIZZLE / RAIN_SHOWERS / RAIN ou SNOW_SHOWERS / SNOW.SKY gagne, la feuille affichée est dérivée de la nébulosité centrale V3 avec des seuils conservateurs : <20 % clair, <45 % plutôt clair, <85 % partiellement nuageux, puis couvert. Sans nébulosité exploitable, le consensus descend jusqu’aux feuilles WMO du ciel.ModelWeightingStrategy reste un point d’extension injectable, mais la production utilise des poids égaux. La résolution de grille n’est pas utilisée comme proxy de qualité ; une pondération différente ne serait légitime qu’après un backtest vérifié.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.
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 :
L’app évalue en continu la précision de chaque modèle sur chaque ville favorite en croisant :
_previous_day1) ; le bootstrap manuel tente jusqu’à 21 jours, le cycle quotidien ne recharge qu’une courte fenêtre pour rester idempotent et peu coûteuxBiasRefreshWorker depuis l’Historical Weather API d’Open-Meteo et stockée dans Room. C’est une réanalyse / donnée historique modélisée et assimilée, pas une observation de station au point exactPour 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.
Deux widgets Glance sont proposés dans le sélecteur Android :
Depuis la v1.17.1 : les anciens raccourcis de tailles (dont 2×5) ont été regroupés dans le seul widget « Météo ». Le « 2×1 » éventuellement affiché par Android indique son emprise initiale, pas une limitation. Ajoutez « Météo », choisissez le mode souhaité (5 heures, 12 heures, 5 jours…), puis sur l’écran d’accueil appuyez longuement pour redimensionner le widget. Selon le lanceur Android, des poignées apparaissent directement ou une commande « Redimensionner » est proposée. Le contenu détaillé apparaît lorsqu’il dispose de suffisamment de place.
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.
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.
Aucune clé API ni credential Météo-France n’est nécessaire dans Android : Open-Meteo est appelé directement et la Vigilance passe par le Worker public MeteoCompare, qui conserve ses secrets côté serveur. Le radar utilise l’API publique RainViewer et les tuiles OpenStreetMap uniquement après ouverture explicite de cet écran.
Par défaut, le build utilise https://meteocompare.app/ comme base du Worker. Pour un environnement de test, elle peut être surchargée sans secret avec -PVIGILANCE_BASE_URL=https://votre-worker.workers.dev/. Seules les URL HTTPS sont acceptées.
./gradlew testDebugUnitTest # tests JVM rapides
./gradlew connectedDebugAndroidTest # UI, navigation, Room et DataStore sur appareil
./gradlew lintDebug assembleDebug # analyse statique + compilation APK
python3 scripts/check_android_strings.py # ressources textuelles inutilisées, orphelines ou absentes (sans Gradle)
Le contrôle des ressources prend en compte les références R.string, R.plurals,
R.array et leurs équivalents XML, dans les sources, tests et widgets. Les
traductions peuvent volontairement manquer dans une langue : Android utilise
alors les ressources par défaut. Une ressource obtenue dynamiquement par son
nom doit être déclarée dans la liste d’exceptions documentée du script.
La suite instrumentée utilise des repositories Hilt factices : aucune requête
Open-Meteo ou Worker Vigilance 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.
Toutes les zones interactives ont des contentDescription lisibles par TalkBack :
A11yFormatter qui résument les données clés. La bande de confiance annonce en plus son état de zoom (“Graphique zoomé, double-tap pour réinitialiser”) pour rester compréhensible quand l’utilisateur zoome sans voir l’écran.heading() pour permettre la navigation par titre.Le module ui/accessibility/A11yFormatter.kt centralise les chaînes pour garder une terminologie cohérente.
Le fichier PRIVACY.md décrit les données traitées localement et les transmissions fonctionnelles vers Open-Meteo, le Worker Vigilance, RainViewer et OpenStreetMap. MeteoCompare n’intègre ni publicité, ni analytics, ni crash reporting distant, ni compte utilisateur.
Pour Google Play, la préparation du formulaire Sécurité des données est documentée dans play-store/DATA_SAFETY.md. Les conditions et attributions des services radar/cartographiques sont suivies dans THIRD_PARTY_SERVICES.md.
La politique de confidentialité doit être hébergée sur une URL publique puis renseignée dans Play Console.
MeteoCompare est développé sans publicité, sans abonnement et sans fonctionnalités premium. Si l’application vous est utile, un don aide directement à financer le temps consacré aux corrections, aux nouveaux modèles, aux nouvelles visualisations, aux tests et à la maintenance des publications.
Les dons sont entièrement facultatifs : aucun privilège, contenu exclusif ou fonction n’est réservé aux donateurs. L’application et le code source restent identiques pour tout le monde. Voir DONATIONS.md pour les détails et les autres façons de contribuer.
Merci à toutes les personnes qui soutiennent MeteoCompare.
No public sponsors yet ❤️
Chaque personne qui soutient MeteoCompare peut ajouter le badge suivant à son profil :
[](https://github.com/sponsors/Pat0chat)
À remplacer :
OWNER : propriétaire du dépôt où se trouvent les badges ;REPO : nom de ce dépôt ;LOGIN : login GitHub du sponsor en minuscules ;SPONSORABLE_LOGIN : ton compte GitHub Sponsors.Fait :
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, AIGFS), ECMWF (IFS et AIFS), UK Met Office (UKMO), Environnement et Changement climatique Canada (GEM), Japan Meteorological Agency (GSM), MET Norway (MET Nordic), KNMI et DMI (HARMONIE), MeteoSwiss (ICON-CH2), Bureau of Meteorology Australie (ACCESS), China Meteorological Administration (GRAPES).