Weather plugin added
This commit is contained in:
@@ -20,7 +20,7 @@ from plugins.config import FunguyConfig
|
||||
# Whitelist of allowed plugins to prevent arbitrary code execution
|
||||
ALLOWED_PLUGINS = {'ai', 'config', 'cron', 'date', 'fortune', 'help', 'isup', 'karma',
|
||||
'loadplugin', 'plugins', 'proxy', 'sd_text', 'stable-diffusion',
|
||||
'xkcd', 'youtube-preview', 'youtube-search'}
|
||||
'xkcd', 'youtube-preview', 'youtube-search', 'weather'}
|
||||
|
||||
class FunguyBot:
|
||||
"""
|
||||
|
@@ -56,6 +56,7 @@ async def load_plugin(plugin_name):
|
||||
'xkcd': 'plugins.xkcd',
|
||||
'youtube-preview': 'plugins.youtube-preview',
|
||||
'youtube-search': 'plugins.youtube-search',
|
||||
'weather': 'plugins.weather'
|
||||
}
|
||||
|
||||
# Get the module path from the mapping
|
||||
|
167
plugins/weather.py
Normal file
167
plugins/weather.py
Normal file
@@ -0,0 +1,167 @@
|
||||
"""
|
||||
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><br>
|
||||
<strong>Condition:</strong> {description}<br>
|
||||
<strong>Temperature:</strong> {temp:.1f}°C ({temp_f:.1f}°F)<br>
|
||||
<strong>Feels like:</strong> {feels_like:.1f}°C ({feels_like_f:.1f}°F)<br>
|
||||
<strong>Humidity:</strong> {humidity}%<br>
|
||||
<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, '🌡️')
|
Reference in New Issue
Block a user