Files
FunguyBot/plugins/weather.py

163 lines
5.8 KiB
Python

"""
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 <location>\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"""
<strong>[{weather_emoji} Weather for {city_name}, {country}]</strong>: <strong>Condition:</strong> {description} | <strong>Temperature:</strong> {temp:.1f}°C ({temp_f:.1f}°F) | <strong>Feels like:</strong> {feels_like:.1f}°C ({feels_like_f:.1f}°F) | <strong>Humidity:</strong> {humidity}% | <strong>Wind Speed:</strong> {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, '🌡️')