# Consigne — Collecte météo Open‑Meteo (Prévisions + Historique)

## 1. Objectif

Mettre en place une collecte automatique des données Open‑Meteo pour alimenter :
- une vue calendrier météo (agrégat journalier),
- une vue détail horaire.

Le système doit :
- récupérer les prévisions sur horizon configurable (`7`, `10`, `16` jours),
- stocker un cache JSON brut (debug/audit),
- upserter en SQLite sans duplication,
- gérer `Europe/Paris` sans décalage de date,
- permettre un mode historique (`archive`) optionnel.

---

## 2. Source de données

- API prévisions : `https://api.open-meteo.com/v1/forecast`
- API historique : `https://api.open-meteo.com/v1/archive`
- Doc : `https://open-meteo.com/en/docs`

Toujours envoyer :
- `timezone=Europe/Paris`
- `timeformat=iso8601`

---

## 3. Configuration

Créer `config.yml` (et `config.yml.example`) :

```yaml
open_meteo:
  latitude: 45.05
  longitude: 3.48
  timezone: Europe/Paris
  forecast_days: 14
  cache_dir: data/cache
  db_path: data/jardin.db
  wind_strong_kmh: 40
```

---

## 4. Requête prévisions (obligatoire)

Variables demandées :
- `hourly`: `temperature_2m,precipitation_probability,precipitation,relative_humidity_2m,wind_speed_10m,wind_direction_10m,cloud_cover,weather_code`
- `daily`: `temperature_2m_max,temperature_2m_min,precipitation_sum,precipitation_probability_max,wind_speed_10m_max,sunrise,sunset,weather_code`

Exemple :

```bash
curl -s "https://api.open-meteo.com/v1/forecast?latitude=45.05&longitude=3.48&hourly=temperature_2m,precipitation_probability,precipitation,relative_humidity_2m,wind_speed_10m,wind_direction_10m,cloud_cover,weather_code&daily=temperature_2m_max,temperature_2m_min,precipitation_sum,precipitation_probability_max,wind_speed_10m_max,sunrise,sunset,weather_code&timezone=Europe/Paris&timeformat=iso8601&forecast_days=14"
```

Règles :
- `forecast_days` doit toujours être explicite.
- Lire et logger `hourly_units` et `daily_units`.

---

## 5. Requête archive (optionnelle)

Exemple :

```bash
curl -s "https://api.open-meteo.com/v1/archive?latitude=45.05&longitude=3.48&start_date=2026-01-01&end_date=2026-01-31&daily=temperature_2m_max,temperature_2m_min,precipitation_sum&hourly=temperature_2m,precipitation,weather_code&timezone=Europe/Paris&timeformat=iso8601"
```

Règles :
- exécuter par tranche (mensuelle recommandée),
- source marquée `archive`.

---

## 6. Stockage

### 6.1 Cache JSON brut

Fichiers à écrire à chaque run :
- `data/cache/openmeteo_forecast_<YYYY-MM-DDTHHMMSS>.json`
- `data/cache/openmeteo_archive_<YYYY-MM-DDTHHMMSS>.json` (si archive)

Purge :
- conserver les `30` derniers fichiers par type.

### 6.2 SQLite normalisée

Table `meteo_daily` :
- `date TEXT NOT NULL`
- `source TEXT NOT NULL` (`forecast` | `archive`)
- `tmin_c REAL`
- `tmax_c REAL`
- `precip_mm REAL`
- `precip_prob_max_pct REAL`
- `wind_max_kmh REAL`
- `sunrise_local TEXT`
- `sunset_local TEXT`
- `weather_code INTEGER`
- `fetched_at TEXT NOT NULL`
- `lat REAL NOT NULL`
- `lon REAL NOT NULL`
- `elevation REAL`
- `PRIMARY KEY (date, source)`

Table `meteo_hourly` :
- `datetime_local TEXT NOT NULL` (`YYYY-MM-DDTHH:MM`)
- `source TEXT NOT NULL` (`forecast` | `archive`)
- `temp_c REAL`
- `precip_mm REAL`
- `precip_prob_pct REAL`
- `humidity_pct REAL`
- `wind_kmh REAL`
- `wind_dir_deg REAL`
- `cloud_pct REAL`
- `weather_code INTEGER`
- `fetched_at TEXT NOT NULL`
- `lat REAL NOT NULL`
- `lon REAL NOT NULL`
- `elevation REAL`
- `PRIMARY KEY (datetime_local, source)`

Index recommandés :
- `idx_meteo_daily_date ON meteo_daily(date)`
- `idx_meteo_hourly_dt ON meteo_hourly(datetime_local)`

---

## 7. Règles d’upsert

- `forecast` : `INSERT ... ON CONFLICT (...) DO UPDATE` (les prévisions évoluent).
- `archive` : `INSERT ... ON CONFLICT (...) DO NOTHING` (on fige l’observé).

Conflits :
- `meteo_daily` : `(date, source)`
- `meteo_hourly` : `(datetime_local, source)`

---

## 8. Contrôles qualité obligatoires

Après récupération JSON :
- `daily.time` contient au moins `7` jours,
- longueurs cohérentes des tableaux `hourly`,
- pour chaque jour : `tmin_c <= tmax_c`,
- présence de `timezone == Europe/Paris`.

En cas d’échec :
- logger erreur explicite,
- conserver le JSON brut,
- sortie non fatale avec code d’erreur contrôlé.

---

## 9. Champs attendus pour l’UI

### Vue calendrier (jour)
- `date`
- `tmin_c`, `tmax_c`
- `precip_mm`
- `precip_prob_max_pct`
- `weather_code`
- `sunrise_local`, `sunset_local`
- badges calculés :
  - `gel` si `tmin_c <= 0`
  - `pluie` si `precip_mm > 0`
  - `vent_fort` si `wind_max_kmh >= wind_strong_kmh`

### Vue détail (horaire)
- `datetime_local`
- `temp_c`
- `precip_prob_pct`
- `precip_mm`
- `wind_kmh`, `wind_dir_deg`
- `humidity_pct`
- `cloud_pct`
- `weather_code`

---

## 10. Livrables

- `prevision meteo/scripts/fetch_openmeteo_forecast.py`
- `prevision meteo/scripts/fetch_openmeteo_archive.py` (optionnel)
- `prevision meteo/db/schema.sql`
- `prevision meteo/config.yml.example`

---

## 11. Exécution planifiée

- Prévisions : tous les jours à `06:10` Europe/Paris.
- Archive (optionnel) : tous les jours à `06:20` pour `J-1`.

Exemple cron :

```cron
10 6 * * * /usr/bin/python3 /path/prevision\ meteo/scripts/fetch_openmeteo_forecast.py
20 6 * * * /usr/bin/python3 /path/prevision\ meteo/scripts/fetch_openmeteo_archive.py --yesterday
```

---

## 12. Critères d’acceptation

- Une exécution quotidienne met à jour `forecast` sans duplication.
- Le calendrier UI affiche au minimum : Tmin/Tmax, pluie, probabilité pluie, weather code.
- Le détail horaire est consultable pour un jour donné.
- Les dates/heures sont correctes en `Europe/Paris`.
- Les caches JSON sont présents et exploitables 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,rain,snowfall,wind_speed_10m,relative_humidity_2m,wind_direction_10m,soil_temperature_0cm,soil_temperature_6cm,soil_moisture_1_to_3cm,soil_moisture_3_to_9cm,sunshine_duration&forecast_days=14