PlanMate / planmate /weather.py
embed786's picture
Upload 9 files
6380b21 verified
import requests
from datetime import datetime
from typing import Dict
from .config import OPENWEATHER_BASE, get_openweather_key, UNITS
from .utils import day_list
def geocode_city(city: str) -> Dict:
url = f"{OPENWEATHER_BASE}/geo/1.0/direct"
r = requests.get(
url,
params={"q": city, "limit": 1, "appid": get_openweather_key()},
timeout=20,
)
r.raise_for_status()
arr = r.json()
if not arr:
raise RuntimeError(f"City not found: {city}")
d = arr[0]
return {
"name": d.get("name"),
"lat": d.get("lat"),
"lon": d.get("lon"),
"country": d.get("country"),
}
def forecast_5day(lat: float, lon: float, units=UNITS) -> Dict:
# 5 day / 3-hour forecast
url = f"{OPENWEATHER_BASE}/data/2.5/forecast"
r = requests.get(
url,
params={"lat": lat, "lon": lon, "appid": get_openweather_key(), "units": units},
timeout=25,
)
r.raise_for_status()
return r.json()
def summarize_forecast_for_range(city: str, start_date, days: int) -> Dict:
loc = geocode_city(city)
fc = forecast_5day(loc["lat"], loc["lon"])
daily = {}
for item in fc.get("list", []):
dt_txt = item.get("dt_txt") # 'YYYY-MM-DD HH:MM:SS'
dt = datetime.strptime(dt_txt, "%Y-%m-%d %H:%M:%S")
dkey = dt.date().isoformat()
temp = item.get("main", {}).get("temp")
weather = item.get("weather", [{}])[0].get("description", "")
wind = item.get("wind", {}).get("speed", 0)
if dkey not in daily:
daily[dkey] = {"temps": [], "desc": {}, "wind": []}
daily[dkey]["temps"].append(temp)
daily[dkey]["wind"].append(wind)
daily[dkey]["desc"][weather] = daily[dkey]["desc"].get(weather, 0) + 1
dates = [d.isoformat() for d in day_list(start_date, days)]
rows = []
for dkey in dates:
if dkey in daily:
temps = daily[dkey]["temps"]
avg = sum(temps) / len(temps) if temps else None
wavg = (
sum(daily[dkey]["wind"]) / len(daily[dkey]["wind"]) if daily[dkey]["wind"] else 0
)
desc = max(daily[dkey]["desc"], key=daily[dkey]["desc"].get)
rows.append(
{
"date": dkey,
"temp_avg": round(avg, 1) if avg is not None else None,
"wind": round(wavg, 1),
"desc": desc,
}
)
else:
rows.append(
{
"date": dkey,
"temp_avg": None,
"wind": None,
"desc": "No forecast (beyond 5 days)",
}
)
summary_text = "\n".join(
[
f"{r['date']}: {r['desc']}, avg {r['temp_avg']}°C, wind {r['wind']} m/s"
for r in rows
]
)
return {"location": loc, "daily": rows, "summary_text": summary_text}