diff --git a/weather.py b/weather.py index f294035..0630dc8 100644 --- a/weather.py +++ b/weather.py @@ -1,49 +1,109 @@ import json -import urllib +import requests import re import datetime +import dateutil.parser as dp class WeatherApi: - def __init__(self): + def __init__(self, nick): + self.nick = nick self.weather_api_url = "https://api.weatherapi.com/v1" self.api_key_filename = "./weather_api_key.txt" - read_api_key() + self.user_preferences_filename = "./weather_user_preferences.json" + self.read_api_key() + + self.unit_suffices = { + 'metric': { + 'temp': 'c', + 'rate': 'kph', + 'volume': 'mm', + 'baro': 'mb', + 'distance': 'km' + }, + 'imperial': { + 'temp': 'f', + 'rate': 'mph', + 'volume': 'in', + 'baro': 'in', + 'distance': 'miles' + } + } def read_api_key(self): with open(self.api_key_filename) as fp: - self.api_key = fp.read() + api_key = fp.read() + self.api_key = api_key.strip() + + def get_current_conditions(self, nick, location=None, units='metric'): + user_preferences = self.get_user_preferences(nick) + + if not location: + location = user_preferences[nick]['location'] - def get_current_conditions(self, units='metric'): # URL for current conditions current_url = f"{self.weather_api_url}/current.json?key={self.api_key}&q={location}&qai=no" # Make the request and get the results - current_request = urllib.request.urlopen(current_url) - current_data = current_request.read() + current_request = requests.get(current_url) + current_data = current_request.content current_json = json.loads(current_data.decode('utf-8')) # Different formats for different units - current_output_format = {} - current_output_format['metric'] = f"{location['name']}, {location['region']}, {location['country']} | {current['temp_c']}°C | {current['humidity']}% | {current['condition']['text']} | {current['wind_dir']} {current['wind_degree']}° {current['wind_kph']} kph" - current_output_format['imperial'] = f"{location['name']}, {location['region']}, {location['country']} | {current['temp_f']}°F | {current['humidity']}% | {current['condition']['text']} | {current['wind_dir']} {current['wind_degree']}° {current['wind_mph']} mph" + current = current_json['current'] + location = current_json['location'] - return current_output_format[units] + current_output_location = f"{location['name']}, {location['region']}, {location['country']}" + + temp = current[f"temp_{self.unit_suffices[units]['temp']}"] + wind_speed = current[f"wind_{self.unit_suffices[units]['rate']}"] + + current_output_format = f"{current_output_location} | {temp}°{self.unit_suffices[units]['temp'].upper()} | {current['humidity']}% | {current['condition']['text']} | {current['wind_dir']} {current['wind_degree']}° {wind_speed} {self.unit_suffices[units]['rate']}" + + return current_output_format def get_user_preferences(self, nick): - # Read SQLite DB for default location and units for the nick provided + try: + with open(self.user_preferences_filename) as fp: + user_preferences = json.load(fp) + except FileNotFoundError: + user_preferences = { + nick: { + 'location': None, + 'units': 'metric' + }, + } - def set_user_preferences(self, nick, location=None, units='metric'): - # Set the default location and units for the nick in a SQLite DB + return user_preferences + + def set_user_preferences(self, nick, location=None, units=None): + user_preferences = self.get_user_preferences(nick) + + # Only acceptable units are 'imperial' or 'metric' (no kelvin for now) + if not units or (units and units not in ['metric', 'imperial']): + units = 'metric' + + user_preferences[nick]['units'] = units + + if location: + user_preferences[nick]['location'] = location + + with open(self.user_preferences_filename, 'w') as fp: + json.dump(user_preferences, fp) + + def get_forecast(self, nick, location=None, days=5, units='metric'): + user_preferences = self.get_user_preferences(nick) + + if not location: + location = user_preferences[nick]['location'] - def get_forecast(self, days=4, units='metric'): # URL for current conditions forecast_url = f"{self.weather_api_url}/forecast.json?key={self.api_key}&q={location}&days={days}&qai=no" # Make the request and get the results - forecast_request = urllib.request.urlopen(forecast_url) - forecast_data = forecast_request.read() + forecast_request = requests.get(forecast_url) + forecast_data = forecast_request.content forecast_json = json.loads(forecast_data.decode('utf-8')) location = forecast_json['location'] forecast = forecast_json['forecast']['forecastday'] @@ -55,15 +115,16 @@ class WeatherApi: # Set the initial high and low values to absurd values daily_temp_range = { 'day': day['date'], - 'high': 10000.0, - 'low': -10000.0, + 'day_of_week': datetime.datetime.strftime(dp.parse(day['date']), '%a'), + 'high': -10000.0, + 'low': 10000.0, 'conditions': '' - }} + } for hour in day['hour']: - temp = day['hour']['temp_c'] if units == 'metric' else day['hour']['temp_f'] + temp = hour[f"temp_{self.unit_suffices[units]['temp']}"] - if temp > daily_temp_range['high']: + if temp >= daily_temp_range['high']: daily_temp_range['high'] = temp # We only want the conditions for when the temp is the highest daily_temp_range['conditions'] = hour['condition']['text'] @@ -71,12 +132,17 @@ class WeatherApi: if temp < daily_temp_range['low']: daily_temp_range['low'] = temp + forecast_temps.append(daily_temp_range) # Different formats for different units - forecast_output_format = {} - forecast_output_format['metric'] = f"{location['name']}, {location['region']}, {location['country']} | {current['temp_c']}°C | {current['humidity']}% | {current['condition']['text']} | {current['wind_dir']} {current['wind_degree']}° {current['wind_kph']} kph" - forecast_output_format['imperial'] = f"{location['name']}, {location['region']}, {location['country']} | {current['temp_f']}°F | {current['humidity']}% | {current['condition']['text']} | {current['wind_dir']} {current['wind_degree']}° {current['wind_mph']} mph" + forecast_output_location = f"{location['name']}, {location['region']}, {location['country']}" + forecast_days = "" - return current_output_format[units] + for forecast_temp in forecast_temps: + forecast_days += f" | {forecast_temp['day_of_week']} - {forecast_temp['high']}°{self.unit_suffices[units]['temp'].upper()}/{forecast_temp['low']}°{self.unit_suffices[units]['temp'].upper()} - {forecast_temp['conditions']}" + + forecast_output_format = f"{forecast_output_location}{forecast_days}" + + return forecast_output_format