123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133 |
- # SPDX-License-Identifier: AGPL-3.0-or-later
- """wttr.in (weather forecast service)"""
- from urllib.parse import quote
- from datetime import datetime
- from searx.result_types import EngineResults, WeatherAnswer
- from searx import weather
- about = {
- "website": "https://wttr.in",
- "wikidata_id": "Q107586666",
- "official_api_documentation": "https://github.com/chubin/wttr.in#json-output",
- "use_official_api": True,
- "require_api_key": False,
- "results": "JSON",
- }
- categories = ["weather"]
- url = "https://wttr.in/{query}?format=j1&lang={lang}"
- # adapted from https://github.com/chubin/wttr.in/blob/master/lib/constants.py
- WWO_TO_CONDITION = {
- "113": "clear sky",
- "116": "partly cloudy",
- "119": "cloudy",
- "122": "very cloudy",
- "143": "fog",
- "176": "light showers",
- "179": "light sleet showers",
- "182": "light sleet",
- "185": "light sleet",
- "200": "rain and thunder",
- "227": "light snow",
- "230": "heavy snow",
- "248": "fog",
- "260": "fog",
- "263": "light showers",
- "266": "light rain",
- "281": "light sleet",
- "284": "light sleet",
- "293": "light rain",
- "296": "light rain",
- "299": "heavy showers",
- "302": "heavy rain",
- "305": "heavy showers",
- "308": "heavy rain",
- "311": "light sleet",
- "314": "light sleet",
- "317": "light sleet",
- "320": "light snow",
- "323": "light snow showers",
- "326": "light snow showers",
- "329": "heavy snow",
- "332": "heavy snow",
- "335": "heavy snow showers",
- "338": "heavy snow",
- "350": "light sleet",
- "353": "light showers",
- "356": "heavy showers",
- "359": "heavy rain",
- "362": "light sleet showers",
- "365": "light sleet showers",
- "368": "light snow showers",
- "371": "heavy snow showers",
- "374": "light sleet showers",
- "377": "light sleet",
- "386": "rain showers and thunder",
- "389": "heavy rain showers and thunder",
- "392": "snow showers and thunder",
- "395": "heavy snow showers",
- }
- def request(query, params):
- params["url"] = url.format(query=quote(query), lang=params["language"])
- params["raise_for_httperror"] = False
- return params
- def _weather_data(location: weather.GeoLocation, data: dict):
- return WeatherAnswer.Item(
- location=location,
- # the naming between different data objects is inconsitent, thus temp_C and tempC are possible
- temperature=weather.Temperature(unit="°C", value=data.get("temp_C") or data.get("tempC")),
- condition=WWO_TO_CONDITION[data["weatherCode"]],
- feels_like=weather.Temperature(unit="°C", value=data["FeelsLikeC"]),
- wind_from=weather.Compass(int(data["winddirDegree"])),
- wind_speed=weather.WindSpeed(data["windspeedKmph"], unit="km/h"),
- pressure=weather.Pressure(data["pressure"], unit="hPa"),
- humidity=weather.RelativeHumidity(data["humidity"]),
- cloud_cover=data["cloudcover"],
- )
- def response(resp):
- res = EngineResults()
- if resp.status_code == 404:
- return res
- json_data = resp.json()
- if len(json_data.get("nearest_area", [])) == 0:
- return res # no matching location found
- location = json_data["nearest_area"][0]
- geoloc = weather.GeoLocation(
- name=location["areaName"][0]["value"],
- longitude=float(location["longitude"]),
- latitude=float(location["latitude"]),
- elevation="",
- country_code="",
- timezone="",
- )
- weather_answer = WeatherAnswer(
- current=_weather_data(geoloc, json_data["current_condition"][0]),
- service="wttr.in",
- )
- for day in json_data["weather"]:
- date = datetime.fromisoformat(day["date"])
- time_slot_len = 24 // len(day["hourly"])
- for index, forecast in enumerate(day["hourly"]):
- forecast_data = _weather_data(geoloc, forecast)
- forecast_data.datetime = weather.DateTime(date.replace(hour=index * time_slot_len + 1))
- weather_answer.forecasts.append(forecast_data)
- res.add(weather_answer)
- return res
|