from datetime import datetime, timezone
import requests
from pydantic import Field
from todays_paper_web.widgets import DataSource, registerDataSource
from todays_paper_web.widgets.datasource import DataSourceParams
from todays_paper_web.widgets.params import Number
from .core import (
WeatherForecast,
WeatherIcon,
WeatherType,
WeatherForecastModel,
TimeOfDay,
)
def YrToCoreIcon(symbolCode: str) -> WeatherIcon:
icons = {
"clearsky": WeatherType.ClearSky,
"cloudy": WeatherType.ScatteredClouds,
"fair": WeatherType.FewClouds,
"fog": WeatherType.Mist,
"heavyrain": WeatherType.Rain,
# "heavyrainandthunder",
# "heavyrainshowers",
# "heavyrainshowersandthunder",
# "heavysleet",
# "heavysleetandthunder",
# "heavysleetshowers",
# "heavysleetshowersandthunder",
"heavysnow": WeatherType.Snow,
# "heavysnowandthunder",
# "heavysnowshowers",
# "heavysnowshowersandthunder",
"lightrain": WeatherType.ShowerRain,
# "lightrainandthunder",
# "lightrainshowers",
# "lightrainshowersandthunder",
# "lightsleet",
# "lightsleetandthunder",
# "lightsleetshowers",
"lightsnow": WeatherType.Snow,
# "lightsnowandthunder",
# "lightsnowshowers",
# "lightssleetshowersandthunder",
# "lightssnowshowersandthunder",
"partlycloudy": WeatherType.FewClouds,
"rain": WeatherType.Rain,
# "rainandthunder",
"rainshowers": WeatherType.ShowerRain,
# "rainshowersandthunder",
# "sleet",
# "sleetandthunder",
# "sleetshowers",
# "sleetshowersandthunder",
"snow": WeatherType.Snow,
# "snowandthunder",
"snowshowers": WeatherType.Snow,
# "snowshowersandthunder",
}
tods = {"day": TimeOfDay.Day, "night": TimeOfDay.Night}
try:
weather, todStr = symbolCode.split("_", 1)
except:
weather = symbolCode
todStr = "day"
try:
return WeatherIcon(weather=icons[weather], timeOfDay=tods[todStr])
except:
return WeatherIcon(weather=WeatherType.Unknown, timeOfDay=TimeOfDay.Day)
[docs]
class YrParams(DataSourceParams):
lat: Number = Field(..., description="Latitude to forecast for.")
lon: Number = Field(..., description="Longitude to forecast for.")
altitude: Number = Field(
..., description="Site altitude in meters - the API uses this to adjust the forecast."
)
@registerDataSource("weather.yr")
class YrDataSource(DataSource):
Params = YrParams
def fetch(self):
r = requests.get(
"https://api.met.no/weatherapi/locationforecast/2.0/compact",
headers={
"User-Agent": "Todays-Paper 1.0",
},
params={
"lat": self.params.lat,
"lon": self.params.lon,
"altitude": self.params.altitude,
},
)
return WeatherForecastModel(
[
YrDataSource.YrToWeatherForecast(x)
for x in r.json().get("properties", []).get("timeseries", [])
]
)
@staticmethod
def YrToWeatherForecast(data: dict) -> WeatherForecast:
summary = data.get("data", {}).get("next_1_hours", {}).get("summary", {})
instant = data.get("data", {}).get("instant", {}).get("details", {})
return WeatherForecast(
timestamp=datetime.fromisoformat(data["time"][:-1]).replace(
tzinfo=timezone.utc
),
icon=YrToCoreIcon(summary.get("symbol_code", "")),
airTemperature=instant.get("air_temperature", None),
windSpeed=instant.get("wind_speed", None),
)