272 lines
7.0 KiB
Markdown
272 lines
7.0 KiB
Markdown
# consigne.md — Scraping / Collecte des prévisions météo (Open-Meteo)
|
||
|
||
## Objectif
|
||
|
||
Mettre en place une collecte **automatique** des données météo de **prévision** (et optionnellement d’historique) depuis **Open-Meteo** pour alimenter un **calendrier météo** dans l’application jardin.
|
||
|
||
Le système doit :
|
||
- récupérer les **prévisions** (horizon configurable, ex. 7 à 16 jours)
|
||
- stocker les données dans un format exploitable (JSON + SQLite conseillé)
|
||
- pouvoir recalculer/mettre à jour chaque jour sans dupliquer inutilement
|
||
- gérer correctement le **fuseau Europe/Paris**
|
||
- fournir une structure de données stable pour l’UI (calendrier jour + détail horaire)
|
||
|
||
---
|
||
|
||
## Source de données
|
||
|
||
### API Open-Meteo (sans clé)
|
||
- Endpoint prévisions : `https://api.open-meteo.com/v1/forecast`
|
||
- Endpoint historique (optionnel) : `https://api.open-meteo.com/v1/archive`
|
||
- Format : JSON
|
||
|
||
Variables recommandées (prévisions) :
|
||
- **hourly** :
|
||
- `temperature_2m`
|
||
- `precipitation_probability`
|
||
- `precipitation`
|
||
- `relativehumidity_2m`
|
||
- `windspeed_10m`
|
||
- `winddirection_10m`
|
||
- `cloudcover`
|
||
- `weathercode`
|
||
- **daily** :
|
||
- `temperature_2m_max`
|
||
- `temperature_2m_min`
|
||
- `precipitation_sum`
|
||
- `precipitation_probability_max`
|
||
- `windspeed_10m_max`
|
||
- `sunrise`
|
||
- `sunset`
|
||
- `weathercode`
|
||
|
||
Remarques :
|
||
- Toujours inclure `timezone=Europe/Paris`
|
||
- Toujours inclure `timeformat=iso8601` (par défaut)
|
||
- Conserver l’élévation renvoyée (utile pour contexte jardin)
|
||
|
||
Documentation :
|
||
- https://open-meteo.com/en/docs
|
||
|
||
---
|
||
|
||
## Paramètres de localisation
|
||
|
||
Localisation cible : **Messinhac – Bessamorel** (ou proche).
|
||
|
||
Le système doit permettre :
|
||
- configuration par **latitude/longitude**
|
||
- stockage de la localisation dans un fichier `config.yml` (ou `.env`)
|
||
|
||
Exemple :
|
||
- `latitude: 45.05`
|
||
- `longitude: 3.48`
|
||
|
||
---
|
||
|
||
## Requêtes à implémenter
|
||
|
||
### 1) Prévisions quotidiennes + horaires (une seule requête)
|
||
|
||
Exemple `curl` (référence) :
|
||
|
||
```bash
|
||
curl "https://api.open-meteo.com/v1/forecast?latitude=45.05&longitude=3.48&hourly=temperature_2m,precipitation_probability,precipitation,relativehumidity_2m,windspeed_10m,winddirection_10m,cloudcover,weathercode&daily=temperature_2m_max,temperature_2m_min,precipitation_sum,precipitation_probability_max,windspeed_10m_max,sunrise,sunset,weathercode&timezone=Europe/Paris&forecast_days=16"
|
||
|
||
Règles :
|
||
|
||
forecast_days configurable (7/10/16)
|
||
|
||
si forecast_days absent, Open-Meteo peut renvoyer une valeur par défaut (éviter : toujours préciser)
|
||
|
||
2) Historique (optionnel) pour “ce qui s’est réellement passé”
|
||
|
||
Exemple curl :
|
||
|
||
curl "https://api.open-meteo.com/v1/archive?latitude=45.05&longitude=3.48&start_date=2026-01-01&end_date=2026-02-21&daily=temperature_2m_max,temperature_2m_min,precipitation_sum&timezone=Europe/Paris"
|
||
|
||
Règles :
|
||
|
||
requête par tranche (ex. mensuelle) pour éviter des payloads trop gros
|
||
|
||
historiser “source=archive” vs “source=forecast”
|
||
|
||
Exigences de stockage (recommandé)
|
||
1) JSON brut (cache)
|
||
|
||
Conserver la réponse JSON brute pour audit/debug :
|
||
|
||
data/cache/openmeteo_forecast_<YYYY-MM-DD>.json
|
||
|
||
Conserver un historique minimal des runs (ex. 30 derniers) :
|
||
|
||
rotation ou purge automatique
|
||
|
||
2) SQLite (données normalisées)
|
||
|
||
Créer 2 tables :
|
||
|
||
Table meteo_daily
|
||
|
||
date (YYYY-MM-DD) PRIMARY KEY
|
||
|
||
tmin_c, tmax_c
|
||
|
||
precip_mm (cumul)
|
||
|
||
precip_prob_max_pct
|
||
|
||
wind_max_kmh
|
||
|
||
sunrise_local, sunset_local
|
||
|
||
weathercode
|
||
|
||
source (forecast|archive)
|
||
|
||
fetched_at (timestamp)
|
||
|
||
lat, lon, elevation
|
||
|
||
Table meteo_hourly
|
||
|
||
datetime_local (YYYY-MM-DDTHH:MM) PRIMARY KEY
|
||
|
||
temp_c
|
||
|
||
precip_mm
|
||
|
||
precip_prob_pct
|
||
|
||
humidity_pct
|
||
|
||
wind_kmh
|
||
|
||
wind_dir_deg
|
||
|
||
cloud_pct
|
||
|
||
weathercode
|
||
|
||
source (forecast|archive)
|
||
|
||
fetched_at
|
||
|
||
lat, lon, elevation
|
||
|
||
Règles d’upsert :
|
||
|
||
si source=forecast : écraser les mêmes timestamps lors d’un nouveau run (les prévisions changent)
|
||
|
||
si source=archive : ne pas écraser si déjà présent (ou écraser seulement si “qualité” supérieure)
|
||
|
||
Normalisation / conversions
|
||
|
||
Open-Meteo renvoie souvent les vitesses en km/h selon endpoint/paramètre, vérifier les unités :
|
||
|
||
lire hourly_units et daily_units dans la réponse
|
||
|
||
stocker les unités (au moins en logging)
|
||
|
||
conserver les dates en timezone Europe/Paris pour affichage calendrier
|
||
|
||
Plan de collecte (cron)
|
||
|
||
Prévisions :
|
||
|
||
fréquence : 1 fois par jour (ex. 06:10 Europe/Paris)
|
||
|
||
stocker fetched_at pour savoir quand la prévision a été téléchargée
|
||
|
||
Historique (optionnel) :
|
||
|
||
1 fois par jour pour la veille (ex. récupérer “hier” en archive) afin de figer le “réel”
|
||
|
||
ou batch mensuel si besoin de rattrapage
|
||
|
||
Contrôles qualité (obligatoires)
|
||
|
||
Après chaque run :
|
||
|
||
vérifier que daily.time contient au moins 7 jours
|
||
|
||
vérifier cohérence : tmin <= tmax
|
||
|
||
vérifier que les tableaux time et temperature_2m ont la même longueur
|
||
|
||
si champs manquants : log d’erreur + sauvegarde JSON brute + arrêt gracieux
|
||
|
||
Sorties attendues pour l’UI
|
||
Vue calendrier (jour)
|
||
|
||
Pour chaque jour :
|
||
|
||
date
|
||
|
||
Tmin/Tmax
|
||
|
||
pluie cumulée
|
||
|
||
probabilité max pluie
|
||
|
||
icône/code météo (weathercode)
|
||
|
||
lever/coucher du soleil
|
||
|
||
badges : gel (tmin <= 0), pluie (precip_mm > 0), vent fort (wind_max_kmh > seuil)
|
||
|
||
Vue détail (horaire)
|
||
|
||
Pour une date sélectionnée :
|
||
|
||
liste des heures (locales)
|
||
|
||
température + probabilité pluie + pluie mm + vent + humidité + nuages
|
||
|
||
Notes sur weathercode
|
||
|
||
Open-Meteo utilise un weathercode (WMO).
|
||
Le projet doit :
|
||
|
||
stocker le code brut
|
||
|
||
fournir une table de mapping côté UI (code -> libellé FR + icône)
|
||
|
||
Livrables
|
||
|
||
scripts/fetch_openmeteo_forecast.py
|
||
|
||
récupère prévisions + écrit cache JSON + upsert SQLite
|
||
|
||
scripts/fetch_openmeteo_archive.py (optionnel)
|
||
|
||
récupère archive sur période + écrit cache JSON + insert SQLite
|
||
|
||
db/schema.sql
|
||
|
||
schéma SQLite (tables + index)
|
||
|
||
config.yml.example
|
||
|
||
latitude/longitude, timezone, forecast_days, chemins
|
||
|
||
Commandes de test
|
||
Test rapide (curl)
|
||
curl -s "https://api.open-meteo.com/v1/forecast?latitude=45.05&longitude=3.48&daily=temperature_2m_max,temperature_2m_min,precipitation_sum&timezone=Europe/Paris&forecast_days=7" | head
|
||
Test avec jq (si installé)
|
||
curl -s "https://api.open-meteo.com/v1/forecast?latitude=45.05&longitude=3.48&daily=temperature_2m_max,temperature_2m_min,precipitation_sum&timezone=Europe/Paris&forecast_days=7" | jq '.daily'
|
||
Critères d’acceptation
|
||
|
||
Une exécution quotidienne met à jour les prévisions (forecast) sans dupliquer en base.
|
||
|
||
Le calendrier UI peut afficher au minimum : Tmin/Tmax + pluie + probabilité pluie + code météo.
|
||
|
||
Le détail horaire d’une journée est affichable (température + probabilité pluie).
|
||
|
||
Les données sont en Europe/Paris (pas de décalage d’un jour).
|
||
|
||
Les fichiers JSON de cache existent pour debug.
|
||
|
||
https://api.open-meteo.com/v1/forecast?latitude=45.1412&longitude=4.0736&hourly=temperature_2m,weather_code,cloud_cover,evapotranspiration,precipitation,precipitation_probability&forecast_days=14
|
||
|
||
https://api.open-meteo.com/v1/forecast?latitude=45.1412&longitude=4.0736&hourly=temperature_2m,weather_code,cloud_cover,evapotranspiration,precipitation,precipitation_probability&forecast_days=14 |