123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151 |
- # SPDX-License-Identifier: AGPL-3.0-or-later
- """Open Meteo (weather)"""
- from urllib.parse import urlencode
- from datetime import datetime
- from searx.result_types import EngineResults, WeatherAnswer
- from searx import weather
- about = {
- "website": "https://open-meteo.com",
- "wikidata_id": None,
- "official_api_documentation": "https://open-meteo.com/en/docs",
- "use_official_api": True,
- "require_api_key": False,
- "results": "JSON",
- }
- categories = ["weather"]
- geo_url = "https://geocoding-api.open-meteo.com"
- api_url = "https://api.open-meteo.com"
- data_of_interest = (
- "temperature_2m",
- "apparent_temperature",
- "relative_humidity_2m",
- "apparent_temperature",
- "cloud_cover",
- "pressure_msl",
- "wind_speed_10m",
- "wind_direction_10m",
- "weather_code",
- # "visibility",
- # "is_day",
- )
- def request(query, params):
- try:
- location = weather.GeoLocation.by_query(query)
- except ValueError:
- return
- args = {
- "latitude": location.latitude,
- "longitude": location.longitude,
- "timeformat": "unixtime",
- "timezone": "auto", # use timezone of the location
- "format": "json",
- "current": ",".join(data_of_interest),
- "forecast_days": 3,
- "hourly": ",".join(data_of_interest),
- }
- params["url"] = f"{api_url}/v1/forecast?{urlencode(args)}"
- # https://open-meteo.com/en/docs#weather_variable_documentation
- # https://nrkno.github.io/yr-weather-symbols/
- WMO_TO_CONDITION: dict[int, weather.WeatherConditionType] = {
- # 0 Clear sky
- 0: "clear sky",
- # 1, 2, 3 Mainly clear, partly cloudy, and overcast
- 1: "fair",
- 2: "partly cloudy",
- 3: "cloudy",
- # 45, 48 Fog and depositing rime fog
- 45: "fog",
- 48: "fog",
- # 51, 53, 55 Drizzle: Light, moderate, and dense intensity
- 51: "light rain",
- 53: "light rain",
- 55: "light rain",
- # 56, 57 Freezing Drizzle: Light and dense intensity
- 56: "light sleet showers",
- 57: "light sleet",
- # 61, 63, 65 Rain: Slight, moderate and heavy intensity
- 61: "light rain",
- 63: "rain",
- 65: "heavy rain",
- # 66, 67 Freezing Rain: Light and heavy intensity
- 66: "light sleet showers",
- 67: "light sleet",
- # 71, 73, 75 Snow fall: Slight, moderate, and heavy intensity
- 71: "light sleet",
- 73: "sleet",
- 75: "heavy sleet",
- # 77 Snow grains
- 77: "snow",
- # 80, 81, 82 Rain showers: Slight, moderate, and violent
- 80: "light rain showers",
- 81: "rain showers",
- 82: "heavy rain showers",
- # 85, 86 Snow showers slight and heavy
- 85: "snow showers",
- 86: "heavy snow showers",
- # 95 Thunderstorm: Slight or moderate
- 95: "rain and thunder",
- # 96, 99 Thunderstorm with slight and heavy hail
- 96: "light snow and thunder",
- 99: "heavy snow and thunder",
- }
- def _weather_data(location: weather.GeoLocation, data: dict):
- return WeatherAnswer.Item(
- location=location,
- temperature=weather.Temperature(unit="°C", value=data["temperature_2m"]),
- condition=WMO_TO_CONDITION[data["weather_code"]],
- feels_like=weather.Temperature(unit="°C", value=data["apparent_temperature"]),
- wind_from=weather.Compass(data["wind_direction_10m"]),
- wind_speed=weather.WindSpeed(data["wind_speed_10m"], unit="km/h"),
- pressure=weather.Pressure(data["pressure_msl"], unit="hPa"),
- humidity=weather.RelativeHumidity(data["relative_humidity_2m"]),
- cloud_cover=data["cloud_cover"],
- )
- def response(resp):
- location = weather.GeoLocation.by_query(resp.search_params["query"])
- res = EngineResults()
- json_data = resp.json()
- weather_answer = WeatherAnswer(
- current=_weather_data(location, json_data["current"]),
- service="Open-meteo",
- # url="https://open-meteo.com/en/docs",
- )
- for index, time in enumerate(json_data["hourly"]["time"]):
- if time < json_data["current"]["time"]:
- # Cut off the hours that are already in the past
- continue
- hourly_data = {}
- for key in data_of_interest:
- hourly_data[key] = json_data["hourly"][key][index]
- forecast_data = _weather_data(location, hourly_data)
- forecast_data.datetime = weather.DateTime(datetime.fromtimestamp(time))
- weather_answer.forecasts.append(forecast_data)
- res.add(weather_answer)
- return res
|