dataforgoodfr / energetic-stress-production

Forecast the Energy production in France
https://greenforecast-squad.github.io/energetic-stress-production/
MIT License
1 stars 1 forks source link

Utiliser directement l'API Météo-France plutôt que data.gouv.fr #24

Open antoinetavant opened 1 month ago

antoinetavant commented 1 month ago

pourquoi

  1. début octobre, nous avons été gêné par data.gouv.fr qui était down. Notre service était également down, alors que la source original de la donné, météo-france, était up.
  2. les données de data.gouv.fr sont uniquement au format GRIB2, qui nécéssite une dépendance un peut embétante à installer : eeCodes. Alors que météofrance fourni également le format TIFF, qui est plus simple à lire avec des packages usuels. permet de résoudre #17 également
  3. les données data.gouv.fr sont archivées : un seul fichier avec les données de toutes l'europes, et de toutes les variables, alors que nous n'utilisons que 2 variables sur le territoire français

Avantages

Limitations

Comment faire

J'ai créé une interface de l'api https://portail-api.meteofrance.fr/web/fr/api/ARPEGE sur https://github.com/antoinetavant/meteofranceapi. Elle est presque fonctionnelle (quelques paramètres à changer).

il ne faut presque rien changer pour que ça marche sans souci.

guillaumepot commented 1 month ago

Hello,

quid de l'API open-meteo ?

Avantages

Limitations

Documentation

https://open-meteo.com/en/docs

Exemple d'implémentation

Dépendances:

!pip install openmeteo-requests
!pip install requests-cache retry-requests numpy pandas

Import

import openmeteo_requests
import requests_cache
import pandas as pd
from retry_requests import retry

Cache

cache_session = requests_cache.CachedSession('.cache', expire_after = 3600)
retry_session = retry(cache_session, retries = 5, backoff_factor = 0.2)
openmeteo = openmeteo_requests.Client(session = retry_session)

-- Exemple de cache avec Redis:

async def setup_cache_session() -> requests_cache.CachedSession:
    redis_client = await get_redis_client()
    cache_session = requests_cache.CachedSession(
        backend = "redis",
        connection = redis_client,
        expire_after = 600
    )
    return cache_session

cache_session = asyncio.run(setup_cache_session())
retry_session = retry(cache_session, retries = 5, backoff_factor = 0.5)
openmeteo = openmeteo_requests.Client(session = retry_session)

Params

forecast_url = "https://api.open-meteo.com/v1/forecast"
historical_forecast_url = "https://historical-forecast-api.open-meteo.com/v1/forecast"
openmeteo_models = ["meteofrance_arpege_europe", "meteofrance_arome_france"] # Insérer ou supprimer des modèles

# Paramètres suivants à renseigner selon besoins et selon délais (actuel, par jour, par heure)
params_current_weather = ["temperature_2m", "relative_humidity_2m", "precipitation", "wind_speed_10m"]
params_daily_weather = ["temperature_2m_max", "temperature_2m_min", "sunrise", "sunset", "precipitation_sum"]
params_hourly_weather = ["temperature_2m", "precipitation_probability", "rain", "weather_code", "surface_pressure"]

#### Requetes sur l'api
``` python
params = {
    "latitude": latitude,
    "longitude": longitude,
    "daily": params_daily_weather,
    "hourly": params_hourly_weather,
    "current": params_current_weather,
    "models": openmeteo_models,
    "past_days": 0,
   "forecast_days": 3
}

responses = openmeteo.weather_api(url, params = params)
response = responses[0]

Transformation des données requetées (ici on retourne des dict)

 # Transform daily
daily = response.Daily()

daily_data = {"date": pd.date_range(
    start = pd.to_datetime(daily.Time(), unit = "s", utc = True),
    end = pd.to_datetime(daily.TimeEnd(), unit = "s", utc = True),
    freq = pd.Timedelta(seconds = daily.Interval()),
    inclusive = "left"
)}

for index, elt in enumerate(params_daily_weather):
    daily_data[elt] = daily.Variables(index).ValuesAsNumpy()

for key, value in daily_data.items():
    if isinstance(value, list) or isinstance(value, int):
        pass
    else:
        daily_data[key] = value.tolist()

  # Transform hourly
hourly = response.Hourly()

hourly_data = {"date": pd.date_range(
    start = pd.to_datetime(hourly.Time(), unit = "s", utc = True),
    end = pd.to_datetime(hourly.TimeEnd(), unit = "s", utc = True),
    freq = pd.Timedelta(seconds = hourly.Interval()),
    inclusive = "left"
)}

for index, elt in enumerate(params_hourly_weather):
    values = hourly.Variables(index).ValuesAsNumpy()
    hourly_data[elt] = [None if np.isnan(v) else v for v in values]

for key, value in hourly_data.items():
    if isinstance(value, int) or isinstance(value, list):
        pass
    else:
        hourly_data[key] = value.tolist()

    hourly_data[key] = [float(v) if isinstance(v, np.float32) else v for v in value]

  # Transform current
current = response.Current()
transformed_current = {}

for index, elt in enumerate(params_current_weather):
    transformed_current[f"current_{elt}"] = current.Variables(index).Value()
antoinetavant commented 3 weeks ago

Merci @guillaumepot pour cette réponse très riche ! J'étais effectivement tombé dessus, mais je n'avais pas pris le temps l'aller autant dans les détails de l'API.

Une limitation importante est le fait qu'une requête doit être faite pour une position latitude/longitude (ou bien fournir une liste exhaustive des positions). Aujourd'hui, on utilise toutes les positions disponibles sur le sol français, car on ne prend pas en considération la position des centrales ENR. Je préfèrerais pouvoir faire une requête pour un range de longitude/latitude, définissant ainsi une aire plutôt qu'un ou des points.

Cela dit, il pourrait à terme être pertinent de sélectionner les positions d'intérêt plutôt que de traiter toute la France. Je pense à deux approches pour le faire :

antoinetavant commented 3 weeks ago

Un autre point intéressant d'utiliser Open-Météo, c'est que c'est une seulle API pour plusieur modèles, chacuns ayant des aventages différents. On pourrait donc utiliser

Le tout, avec une seule API. ça serait vraiment sympa.

guillaumepot commented 3 weeks ago

Effectivement l'utilisation d'une aire de coordonnées complique l'utilisation de l'API open-meteo. Dans ce cas, il faut soit envisager de "centrer" les coordonnées en un point (et réduire la granularité, à savoir s'il s'agit d'une granularité régionale, descendre quelques niveaux plus bas: departement, etc..)

En revanche, si à l'avenir l'implementation propose à un utilisateur de s'enregistrer et d'obtenir des informations, tout est est place: