@@ -27,6 +27,11 @@ async def get_hourly_forecast(
2727 ) -> List [HourlyObservationOut ]:
2828 ...
2929
30+ async def get_daily_forecast (
31+ self , lat : float , lon : float , days : int = 16
32+ ) -> List [DailyObservationOut ]:
33+ ...
34+
3035
3136class OpenMeteoClient :
3237 BASE_URL = "https://archive-api.open-meteo.com/v1/archive"
@@ -165,6 +170,73 @@ async def get_hourly_forecast(
165170 return results
166171
167172
173+ # ---- Daily forecast (Open-Meteo Forecast API) ----
174+ # Variables for smart irrigation: precipitation, probability, temp range, ET0
175+ DAILY_FORECAST_VARIABLES = [
176+ "precipitation_sum" ,
177+ "precipitation_probability_max" ,
178+ "temperature_2m_min" ,
179+ "temperature_2m_max" ,
180+ "et0_fao_evapotranspiration" ,
181+ ]
182+
183+ async def get_daily_forecast (
184+ self , lat : float , lon : float , days : int = 16
185+ ) -> List [DailyObservationOut ]:
186+ """
187+ Fetch daily weather forecast for irrigation planning from the
188+ Open-Meteo **Forecast** API.
189+
190+ Returns one :class:`DailyObservationOut` per day with:
191+ - precipitation_sum (mm)
192+ - precipitation_probability_max (%)
193+ - temperature_2m_min (°C)
194+ - temperature_2m_max (°C)
195+ - et0_fao_evapotranspiration (mm)
196+
197+ Parameters
198+ ----------
199+ lat, lon : float
200+ Location coordinates.
201+ days : int
202+ Number of forecast days (1–16, default 16).
203+ """
204+ params = {
205+ "latitude" : lat ,
206+ "longitude" : lon ,
207+ "daily" : "," .join (self .DAILY_FORECAST_VARIABLES ),
208+ "timezone" : "auto" ,
209+ "forecast_days" : days ,
210+ }
211+
212+ data = await self ._fetch_data (params , url = self .FORECAST_URL )
213+
214+ if "daily" not in data :
215+ logger .warning ("Open-Meteo returned no daily forecast data" )
216+ return []
217+
218+ timestamps = data ["daily" ]["time" ]
219+ results : List [DailyObservationOut ] = []
220+
221+ for i , t in enumerate (timestamps ):
222+ values : Dict [str , Union [float , None ]] = {}
223+ for var in self .DAILY_FORECAST_VARIABLES :
224+ if var in data ["daily" ]:
225+ values [var ] = data ["daily" ][var ][i ]
226+ results .append (
227+ DailyObservationOut (
228+ date = date .fromisoformat (t ),
229+ values = values ,
230+ )
231+ )
232+
233+ logger .info (
234+ "Open-Meteo daily forecast: %d days for (%s, %s)" ,
235+ len (results ), lat , lon ,
236+ )
237+ return results
238+
239+
168240# Factory using environment variable
169241class WeatherClientFactory :
170242 _provider : Optional [WeatherProvider ] = None
0 commit comments