1+ import openmeteo_requests
2+
3+ import pandas as pd
4+ import requests_cache
5+ from retry_requests import retry
6+
7+ # All supported hourly fields exposed by this service
8+ ALL_HOURLY_FIELDS = [
9+ "temperature_2m" ,
10+ "relative_humidity_2m" ,
11+ "rain" ,
12+ "apparent_temperature" ,
13+ "precipitation_probability" ,
14+ "precipitation" ,
15+ "wind_direction_10m" ,
16+ "wind_speed_10m" ,
17+ "soil_temperature_0cm" ,
18+ "uv_index" ,
19+ ]
20+
21+ class WeatherAPI :
22+ def __init__ (self ):
23+ pass
24+
25+ def get_weather (self , latitude : float , longitude : float , start_date : str , end_date : str , hourly_fields : list [str ] | None = None ):
26+ """
27+ Get weather data for a given latitude and longitude.
28+
29+ Args:
30+ latitude (float): The latitude of the location.
31+ longitude (float): The longitude of the location.
32+ hourly_fields (list[str] | None): Subset of hourly variables to request.
33+ Defaults to ALL_HOURLY_FIELDS when None or empty.
34+
35+ Returns:
36+ dict: A dictionary containing the weather data.
37+ """
38+ requested = [f for f in (hourly_fields or []) if f in ALL_HOURLY_FIELDS ]
39+ if not requested :
40+ requested = list (ALL_HOURLY_FIELDS )
41+
42+ # Setup the Open-Meteo API client with cache and retry on error
43+ cache_session = requests_cache .CachedSession ('.cache' , expire_after = 3600 )
44+ retry_session = retry (cache_session , retries = 5 , backoff_factor = 0.2 )
45+ openmeteo = openmeteo_requests .Client (session = retry_session )
46+
47+ url = "https://api.open-meteo.com/v1/forecast"
48+ params = {
49+ "latitude" : latitude ,
50+ "longitude" : longitude ,
51+ "hourly" : requested ,
52+ "start_date" : start_date ,
53+ "end_date" : end_date ,
54+ }
55+ responses = openmeteo .weather_api (url , params = params )
56+
57+ response = responses [0 ]
58+
59+ hourly = response .Hourly ()
60+
61+ hourly_data : dict = {
62+ "date" : pd .date_range (
63+ start = pd .to_datetime (hourly .Time (), unit = "s" , utc = True ),
64+ end = pd .to_datetime (hourly .TimeEnd (), unit = "s" , utc = True ),
65+ freq = pd .Timedelta (seconds = hourly .Interval ()),
66+ inclusive = "left" ,
67+ )
68+ }
69+
70+ for i , field in enumerate (requested ):
71+ hourly_data [field ] = hourly .Variables (i ).ValuesAsNumpy ().tolist ()
72+
73+ # Convert pandas Timestamp objects to ISO strings for JSON serialization
74+ hourly_data ["date" ] = [d .isoformat () for d in hourly_data ["date" ]]
75+
76+ return {
77+ "latitude" : response .Latitude (),
78+ "longitude" : response .Longitude (),
79+ "elevation" : response .Elevation (),
80+ "timezone" : response .Timezone (),
81+ "timezone_abbreviation" : response .TimezoneAbbreviation (),
82+ "utc_offset_seconds" : response .UtcOffsetSeconds (),
83+ "hourly" : hourly_data ,
84+ }
0 commit comments