Skip to content

Commit 83cdddd

Browse files
committed
feat: ✨ start and end date
1 parent 4994cfb commit 83cdddd

4 files changed

Lines changed: 97 additions & 86 deletions

File tree

app/api/routes/weather.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
def get_weather_forecast(
2424
latitude: float,
2525
longitude: float,
26+
start_date: str,
27+
end_date: str,
2628
fields: str | None = None,
2729
):
2830
"""
@@ -36,7 +38,7 @@ def get_weather_forecast(
3638
controller = Controller()
3739
try:
3840
requested = [f.strip() for f in fields.split(",") if f.strip()] if fields else []
39-
weather_data = controller.get_weather(latitude, longitude, hourly_fields=requested)
41+
weather_data = controller.get_weather(latitude, longitude, start_date, end_date, hourly_fields=requested)
4042
return weather_data
4143
except Exception as e:
4244
raise AppError(str(e), status_code=500)

app/services/controller.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,5 @@ def fill_form(self, user_input: str, fields: list, pdf_form_path: str, model: st
1313
def prepare_fillable(self, pdf_path: str):
1414
return self.file_manipulator.prepare_fillable(pdf_path)
1515

16-
def get_weather(self, latitude: float, longitude: float, hourly_fields: list = None):
17-
return self.external_apis_coordinator.get_weather(latitude, longitude, hourly_fields=hourly_fields)
16+
def get_weather(self, latitude: float, longitude: float, start_date: str, end_date: str, hourly_fields: list = None):
17+
return self.external_apis_coordinator.get_weather(latitude, longitude, start_date, end_date, hourly_fields)
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
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+
print(f"Coordinates: {response.Latitude()}°N {response.Longitude()}°E")
59+
print(f"Elevation: {response.Elevation()} m asl")
60+
print(f"Timezone difference to GMT+0: {response.UtcOffsetSeconds()}s")
61+
62+
hourly = response.Hourly()
63+
64+
hourly_data: dict = {
65+
"date": pd.date_range(
66+
start=pd.to_datetime(hourly.Time(), unit="s", utc=True),
67+
end=pd.to_datetime(hourly.TimeEnd(), unit="s", utc=True),
68+
freq=pd.Timedelta(seconds=hourly.Interval()),
69+
inclusive="left",
70+
)
71+
}
72+
73+
for i, field in enumerate(requested):
74+
hourly_data[field] = hourly.Variables(i).ValuesAsNumpy().tolist()
75+
76+
# Convert pandas Timestamp objects to ISO strings for JSON serialization
77+
hourly_data["date"] = [d.isoformat() for d in hourly_data["date"]]
78+
79+
return {
80+
"latitude": response.Latitude(),
81+
"longitude": response.Longitude(),
82+
"elevation": response.Elevation(),
83+
"timezone": response.Timezone(),
84+
"timezone_abbreviation": response.TimezoneAbbreviation(),
85+
"utc_offset_seconds": response.UtcOffsetSeconds(),
86+
"hourly": hourly_data,
87+
}
Lines changed: 5 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -1,86 +1,8 @@
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-
1+
from app.services.external_apis.weather_api import WeatherAPI
212

223
class ExternalAPIsCoordinator:
234
def __init__(self):
24-
pass
25-
26-
def get_weather(self, latitude: float, longitude: float, hourly_fields: list[str] | None = None):
27-
"""
28-
Get weather data for a given latitude and longitude.
29-
30-
Args:
31-
latitude (float): The latitude of the location.
32-
longitude (float): The longitude of the location.
33-
hourly_fields (list[str] | None): Subset of hourly variables to request.
34-
Defaults to ALL_HOURLY_FIELDS when None or empty.
35-
36-
Returns:
37-
dict: A dictionary containing the weather data.
38-
"""
39-
requested = [f for f in (hourly_fields or []) if f in ALL_HOURLY_FIELDS]
40-
if not requested:
41-
requested = list(ALL_HOURLY_FIELDS)
42-
43-
# Setup the Open-Meteo API client with cache and retry on error
44-
cache_session = requests_cache.CachedSession('.cache', expire_after=3600)
45-
retry_session = retry(cache_session, retries=5, backoff_factor=0.2)
46-
openmeteo = openmeteo_requests.Client(session=retry_session)
47-
48-
url = "https://api.open-meteo.com/v1/forecast"
49-
params = {
50-
"latitude": latitude,
51-
"longitude": longitude,
52-
"hourly": requested,
53-
}
54-
responses = openmeteo.weather_api(url, params=params)
55-
56-
response = responses[0]
57-
print(f"Coordinates: {response.Latitude()}°N {response.Longitude()}°E")
58-
print(f"Elevation: {response.Elevation()} m asl")
59-
print(f"Timezone difference to GMT+0: {response.UtcOffsetSeconds()}s")
60-
61-
hourly = response.Hourly()
62-
63-
hourly_data: dict = {
64-
"date": pd.date_range(
65-
start=pd.to_datetime(hourly.Time(), unit="s", utc=True),
66-
end=pd.to_datetime(hourly.TimeEnd(), unit="s", utc=True),
67-
freq=pd.Timedelta(seconds=hourly.Interval()),
68-
inclusive="left",
69-
)
70-
}
71-
72-
for i, field in enumerate(requested):
73-
hourly_data[field] = hourly.Variables(i).ValuesAsNumpy().tolist()
74-
75-
# Convert pandas Timestamp objects to ISO strings for JSON serialization
76-
hourly_data["date"] = [d.isoformat() for d in hourly_data["date"]]
77-
78-
return {
79-
"latitude": response.Latitude(),
80-
"longitude": response.Longitude(),
81-
"elevation": response.Elevation(),
82-
"timezone": response.Timezone(),
83-
"timezone_abbreviation": response.TimezoneAbbreviation(),
84-
"utc_offset_seconds": response.UtcOffsetSeconds(),
85-
"hourly": hourly_data,
86-
}
5+
self.weather_api = WeatherAPI()
6+
7+
def get_weather(self, latitude: float, longitude: float, start_date: str, end_date: str, hourly_fields: list[str] | None = None):
8+
return self.weather_api.get_weather(latitude, longitude, start_date, end_date, hourly_fields)

0 commit comments

Comments
 (0)