import logging from datetime import datetime import aiohttp from aiohttp_socks import ProxyConnector, ProxyType from config import API_WEATHER, PROXY_ENABLED, PROXY_URL from bot.bot import bot logger = logging.getLogger(__name__) def get_wind_direction(deg: float) -> str: if deg >= 337.5 or deg < 22.5: return "Север" if deg < 67.5: return "Северо-восток" if deg < 112.5: return "Восток" if deg < 157.5: return "Юго-восток" if deg < 202.5: return "Юг" if deg < 247.5: return "Юго-запад" if deg < 292.5: return "Запад" return "Северо-запад" def _get_connector(): if PROXY_ENABLED and PROXY_URL: parsed = PROXY_URL.replace("socks5://", "").replace("socks5h://", "") if "@" in parsed: auth, host_port = parsed.split("@", 1) username, password = auth.split(":", 1) else: username = None password = None host_port = parsed host, port = host_port.rsplit(":", 1) port = int(port) return ProxyConnector( proxy_type=ProxyType.SOCKS5, host=host, port=port, username=username, password=password, ) return None async def get_weather(message) -> None: if len(message.text.split(maxsplit=1)) == 1: await bot.send_message(message.chat.id, "Пожалуйста, укажите город.") return city = message.text.split(maxsplit=1)[1].strip() url = "https://api.openweathermap.org/data/2.5/weather" params = {"q": city, "appid": API_WEATHER, "units": "metric", "lang": "ru"} timeout = aiohttp.ClientTimeout(total=30, sock_connect=15, sock_read=15) connector = _get_connector() try: async with aiohttp.ClientSession(timeout=timeout, connector=connector) as session: async with session.get(url, params=params) as response: if response.status == 404: await bot.send_message(message.chat.id, "Город не найден. Пожалуйста, уточните запрос.") return response.raise_for_status() weather_data = await response.json() weather_description = weather_data["weather"][0]["description"] temperature = weather_data["main"]["temp"] feels_like = weather_data["main"]["feels_like"] temp_min = weather_data["main"]["temp_min"] temp_max = weather_data["main"]["temp_max"] humidity = weather_data["main"]["humidity"] pressure = int(weather_data["main"]["pressure"] / 1.333) wind_speed = weather_data["wind"]["speed"] wind_deg = weather_data["wind"].get("deg", 0) wind_direction = get_wind_direction(wind_deg) rain_1h = weather_data.get("rain", {}).get("1h", 0) clouds_all = weather_data["clouds"]["all"] visibility = weather_data.get("visibility", 0) sunrise_time = datetime.fromtimestamp(weather_data["sys"]["sunrise"]).strftime("%H:%M") sunset_time = datetime.fromtimestamp(weather_data["sys"]["sunset"]).strftime("%H:%M") weather_message = ( f"Погода в городе {city}:\n\n" f"Описание: {weather_description}\n" f"Температура: {temperature}°C (ощущается как {feels_like}°C)\n" f"Минимальная температура: {temp_min}°C\n" f"Максимальная температура: {temp_max}°C\n" f"Влажность: {humidity}%\n" f"Давление: {pressure} мм рт.ст\n" f"Скорость ветра: {wind_speed} м/с, направление: {wind_direction}\n" f"Осадки за последний час: {rain_1h} мм\n" f"Облачность: {clouds_all}%\n" f"Видимость: {visibility} м\n" f"Восход: {sunrise_time}, закат: {sunset_time}" ) await bot.send_message(message.chat.id, weather_message, parse_mode=None) except aiohttp.ClientResponseError as exc: logger.error("HTTP ошибка погоды: %s", exc) await bot.send_message(message.chat.id, "При получении данных произошла ошибка, попробуйте еще раз.") except aiohttp.ClientError as exc: logger.error("Ошибка запроса погоды: %s", exc) await bot.send_message(message.chat.id, "Не удалось связаться с погодным сервисом.") except Exception as exc: logger.exception("Неожиданная ошибка погоды: %s", exc) await bot.send_message(message.chat.id, "Произошла ошибка при обработке погоды.") finally: if connector: await connector.close()