""" This plugin provides a command to get weather information for a location. """ import logging import requests import os import simplematrixbotlib as botlib from dotenv import load_dotenv # Load environment variables from .env file in the parent directory # Get the directory where this plugin file is located plugin_dir = os.path.dirname(os.path.abspath(__file__)) # Get the parent directory (main bot directory) parent_dir = os.path.dirname(plugin_dir) # Load .env from parent directory dotenv_path = os.path.join(parent_dir, '.env') load_dotenv(dotenv_path) # OpenWeatherMap API configuration # Get your free API key from: https://openweathermap.org/api WEATHER_API_KEY = os.getenv("OPENWEATHER_API_KEY", "") WEATHER_API_URL = "https://api.openweathermap.org/data/2.5/weather" async def handle_command(room, message, bot, prefix, config): """ Function to handle the !weather command. Args: room (Room): The Matrix room where the command was invoked. message (RoomMessage): The message object containing the command. bot (Bot): The bot object. prefix (str): The command prefix. config (dict): Configuration parameters. Returns: None """ match = botlib.MessageMatch(room, message, bot, prefix) if match.is_not_from_this_bot() and match.prefix() and match.command("weather"): logging.info("Received !weather command") # Check if API key is configured if not WEATHER_API_KEY: await bot.api.send_text_message( room.room_id, "Weather API key not configured. Please set OPENWEATHER_API_KEY environment variable." ) return args = match.args() # Check if location was provided if len(args) < 1: await bot.api.send_text_message( room.room_id, "Usage: !weather \nExample: !weather London or !weather New York,US" ) logging.info("Sent usage message for !weather") return location = ' '.join(args) try: # Make API request to OpenWeatherMap params = { 'q': location, 'appid': WEATHER_API_KEY, 'units': 'metric' # Use metric units (Celsius) } response = requests.get(WEATHER_API_URL, params=params, timeout=10) response.raise_for_status() weather_data = response.json() # Extract relevant weather information city_name = weather_data['name'] country = weather_data['sys']['country'] temp = weather_data['main']['temp'] feels_like = weather_data['main']['feels_like'] humidity = weather_data['main']['humidity'] description = weather_data['weather'][0]['description'].capitalize() wind_speed = weather_data['wind'].get('speed', 0) # Convert temperature to Fahrenheit for display temp_f = (temp * 9/5) + 32 feels_like_f = (feels_like * 9/5) + 32 # Get weather emoji based on condition weather_emoji = get_weather_emoji(weather_data['weather'][0]['main']) # Format the weather message weather_message = f""" [{weather_emoji} Weather for {city_name}, {country}]: Condition: {description} | Temperature: {temp:.1f}°C ({temp_f:.1f}°F) | Feels like: {feels_like:.1f}°C ({feels_like_f:.1f}°F) | Humidity: {humidity}% | Wind Speed: {wind_speed} m/s """.strip() await bot.api.send_markdown_message(room.room_id, weather_message) logging.info(f"Sent weather information for {city_name}") except requests.exceptions.HTTPError as e: if e.response.status_code == 404: await bot.api.send_text_message( room.room_id, f"Location '{location}' not found. Please check the spelling and try again." ) elif e.response.status_code == 401: await bot.api.send_text_message( room.room_id, "Weather API authentication failed. Please check the API key configuration." ) else: await bot.api.send_text_message( room.room_id, f"Error fetching weather data: HTTP {e.response.status_code}" ) logging.error(f"HTTP error fetching weather for '{location}': {e}") except requests.exceptions.RequestException as e: await bot.api.send_text_message( room.room_id, f"Error connecting to weather service: {e}" ) logging.error(f"Request error fetching weather for '{location}': {e}") except (KeyError, ValueError) as e: await bot.api.send_text_message( room.room_id, "Error parsing weather data. Please try again later." ) logging.error(f"Error parsing weather data for '{location}': {e}") def get_weather_emoji(condition): """ Get an emoji based on weather condition. Args: condition (str): Weather condition from API. Returns: str: Weather emoji. """ weather_emojis = { 'Clear': '☀️', 'Clouds': '☁️', 'Rain': '🌧️', 'Drizzle': '🌦️', 'Thunderstorm': '⛈️', 'Snow': '❄️', 'Mist': '🌫️', 'Fog': '🌫️', 'Haze': '🌫️', 'Smoke': '🌫️', 'Dust': '🌫️', 'Sand': '🌫️', 'Ash': '🌫️', 'Squall': '💨', 'Tornado': '🌪️' } return weather_emojis.get(condition, '🌡️')