diff --git a/README.md b/README.md index ed3a474d2..96e293f79 100644 --- a/README.md +++ b/README.md @@ -11,9 +11,12 @@ openWeatherApiKey: ``` 2. Create `RECEIVERS.txt` and put email subscribers as: ``` -example@gmail.com -example2@yahoo.com -example3@hotmail.com +example1@gmail.com, "" +example2@gmail.com, "Berlin" +example3@gmail.com, "Milwaukee" +example4@gmail.com, "Mobile, Alabama" +example5@gmail.com, "Nashville, Tennessee" +example6@gmail.com, "Nashville, Indiana" ``` 3. Activate virtualenv. 4. Install dependencies from `requirements.txt`. diff --git a/forecast.py b/forecast.py index d0129da49..46f72478c 100644 --- a/forecast.py +++ b/forecast.py @@ -7,19 +7,19 @@ RAIN_PROB_TRESHOLD = 0.5 -class Forecast(OpenWeather): - def __init__(self, apiKey): - super().__init__(apiKey) - self.rainToday = False - self.rainStartHour = None +class Forecast: + def __init__(self, location): + self.location = location + self.forecastToday = self.get_forecast_today() - def get_forecast_today(self, location): + def get_forecast_today(self): forecastToday = [] - lat, lon = location.get_latitude_longitude() + lat, lon = self.location.get_latitude_longitude() - forecasts = self.get_forecast(lat, lon) - localDate = location.get_local_time().date() + ow = OpenWeather() + forecasts = ow.get_forecast(lat, lon) + localDate = self.location.get_local_time().date() for forecast in forecasts: forecastDate = forecast['t'].date() @@ -36,25 +36,25 @@ def get_forecast_today(self, location): return forecastToday - def get_rain_start_hour(self, forecastToday): + def get_rain_start_hour(self): hour = None - for forecast in forecastToday: + for forecast in self.forecastToday: if forecast['b']: hour = forecast['h'] break return hour - def construct_forecast_message(self, forecastToday, location): - rainStartHour = self.get_rain_start_hour(forecastToday) - locationName = location.get_location_name() + def construct_forecast_message(self): + rainStartHour = self.get_rain_start_hour() + locationName = self.location.get_location_name() subject = f'Rain in {locationName} from {rainStartHour}h' html = '' plain = '' - for forecast in forecastToday: + for forecast in self.forecastToday: hourStr = str(forecast['h']) probStr = str(round(forecast['p'] * 100)) @@ -74,5 +74,5 @@ def construct_forecast_message(self, forecastToday, location): return subject, plain, html - def rain_today(self, forecastToday): - return True in [forecast['b'] for forecast in forecastToday] + def rain_today(self): + return True in [forecast['b'] for forecast in self.forecastToday] diff --git a/location.py b/location.py index 594af2d88..43fefcb8a 100644 --- a/location.py +++ b/location.py @@ -14,6 +14,9 @@ def __init__(self, name): geolocator = geocoders.Nominatim(user_agent=GEOLOC_APP_NAME) self.point = geolocator.geocode(self.name) + if self.point == None: + exit(f'ERROR: Can not find place by name.') + # get timezone tf = TimezoneFinder() self.timezone = tf.timezone_at( diff --git a/main.py b/main.py index 29ab7b3e8..addfeb114 100644 --- a/main.py +++ b/main.py @@ -1,31 +1,34 @@ -import utils +from open_weather import OpenWeather +from utils import get_email_credentials, get_emails_and_locations from gmail import Gmail from forecast import Forecast from location import Location SEND_EMAIL_HOUR = 5 # AM local time -CREDENTIALS_FILE_PATH = 'CREDENTIALS.yaml' -RECEIVERS_FILE_PATH = 'RECEIVERS.txt' if __name__ == "__main__": - sender, password, openWeatherApiKey = utils.get_credentials( - CREDENTIALS_FILE_PATH) - receivers = utils.get_emails_and_locations(RECEIVERS_FILE_PATH) + sender, password = get_email_credentials() + receivers = get_emails_and_locations() + + numOfReceivers = len(receivers) + print(f'INFO: found {numOfReceivers} receive emails.') gmail = Gmail(sender, password) - forecast = Forecast(openWeatherApiKey) - for receiver in receivers: + for num, receiver in enumerate(receivers, start=1): + print(f'INFO: {num}/{numOfReceivers}', end =' ') location = Location(receiver['location']) - # is it time to send an email if location.get_local_time().hour == SEND_EMAIL_HOUR: - forecastToday = forecast.get_forecast_today(location) + forecast = Forecast(location) - if forecast.rain_today(forecastToday): - subject, content, contentHtml = forecast.construct_forecast_message( - forecastToday, location) - print('INFO: Sending emails.') + if forecast.rain_today(): + subject, content, contentHtml = forecast.construct_forecast_message() + print('Sending email.') gmail.send(receiver['email'], subject, content, contentHtml) - + else: + print('No rain today.') + else: + print("It's not time.") + print('INFO: Done.') diff --git a/open_weather.py b/open_weather.py index 94b2d0370..38abe90c9 100644 --- a/open_weather.py +++ b/open_weather.py @@ -1,12 +1,13 @@ import requests -import json from datetime import datetime -import pytz +from utils import get_openWeather_api_key class OpenWeather: - def __init__(self, apiKey) -> None: - self.__apiKey = apiKey + __API_KEY = get_openWeather_api_key() + + def __init__(self): + pass def _get_data_from_api(self, latitude, longitude): @@ -14,7 +15,7 @@ def _get_data_from_api(self, latitude, longitude): f'&lat={latitude}'\ f'&lon={longitude}'\ '&exclude=current,minutely,daily,alerts&units=metric'\ - f'&appid={self.__apiKey}' + f'&appid={self.__API_KEY}' try: response = requests.get(API_URL) diff --git a/utils.py b/utils.py index ed0e591ef..5a1d0d316 100644 --- a/utils.py +++ b/utils.py @@ -1,9 +1,12 @@ import yaml +CREDENTIALS_FILE_PATH = 'CREDENTIALS.yaml' +RECEIVERS_FILE_PATH = 'RECEIVERS.txt' -def get_credentials(filePath): + +def get_email_credentials(): try: - with open(filePath, 'r') as file: + with open(CREDENTIALS_FILE_PATH, 'r') as file: credentials = yaml.load(file, Loader=yaml.FullLoader) except FileNotFoundError: @@ -11,14 +14,24 @@ def get_credentials(filePath): sender = credentials['senderEmail'] password = credentials['senderPassword'] - openWeatherApiKey = credentials['openWeatherApiKey'] - return sender, password, openWeatherApiKey + return sender, password + + +def get_openWeather_api_key(): + try: + with open(CREDENTIALS_FILE_PATH, 'r') as file: + credentials = yaml.load(file, Loader=yaml.FullLoader) + + except FileNotFoundError: + exit('ERROR: credentials file not found.') + + return credentials['openWeatherApiKey'] -def get_emails_and_locations(filePath): +def get_emails_and_locations(): try: - with open(filePath, 'r') as file: + with open(RECEIVERS_FILE_PATH, 'r') as file: receivers = file.read().splitlines() except FileNotFoundError: @@ -29,8 +42,9 @@ def get_emails_and_locations(filePath): for receiver in receivers: email_and_location = {} - email_and_location['email'] = receiver.split(',')[0].strip() - email_and_location['location'] = receiver.split(',')[1].strip() + string = receiver.partition(',') + email_and_location['email'] = string[0].strip() + email_and_location['location'] = string[2].replace('"', '').strip() emails_and_locations.append(email_and_location) return emails_and_locations