Skip to content

Commit ba6be11

Browse files
Add files via upload
1 parent ea3a771 commit ba6be11

File tree

3 files changed

+200
-0
lines changed

3 files changed

+200
-0
lines changed

main.py

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import smtplib, os
2+
from email.message import EmailMessage
3+
from datetime import date
4+
from weatherdata import generate_tables
5+
6+
EMAIL = os.environ.get("email")
7+
APP_PW = os.environ.get("app_pw")
8+
TO_ADDRESS = os.environ.get("email")
9+
SMTP_SERVER = os.environ.get("smtp_server")
10+
TODAY = str(date.today())
11+
12+
#### ------------------------------------------------- NOTES ----------------------------------------------------------- ####
13+
# Weather data.py pulls the same data from the Day 96 project. Refer to fields values pulled in that file. #
14+
# Ski Resort website (Day 96) lists complete data. #
15+
# This project omits two days of data along with the following entries from the resorts: feels_like, humidity, and clouds. #
16+
# Data omited to cut down on the length of the email that is sent. Currently sitting at about 170 lines of text. #
17+
# Feel free to modify data pulled as well as what data is emailed/nubmer of days looped through. #
18+
#### ------------------------------------------------------------------------------------------------------------------- ####
19+
20+
# Try block first pulls the resort data using the weatherdata.py file. If data is successfuly pulled, body is composed and email is sent.
21+
try:
22+
print("Pulling API data")
23+
resort_data = generate_tables()
24+
25+
# Establish connection
26+
connection = smtplib.SMTP(SMTP_SERVER)
27+
connection.starttls()
28+
connection.login(user=EMAIL, password=APP_PW)
29+
30+
print("Composing email body")
31+
body = "Weather data for local ski & snow resorts over the next three days!! See scripts notes to customize output!\n\n"
32+
# Loops through all resorts returned from the generate table function.
33+
for resort in range(len(resort_data)):
34+
# Resort Name & Website
35+
body += f"{resort_data[resort][0]}\nResort's website: {resort_data[resort][1]}\n------ Weather Data ------\n"
36+
# Returns 3 days of data in 5 hour incriments. Would have been 5 days with additional columns, but decided to omit data so email would not be massive blocks of text.
37+
for index in range(2, len(resort_data[0]) - 16):
38+
# Date, time, and weather data
39+
body += f"{resort_data[0][index][0]} -- Temp: {str(resort_data[resort][index][1])}°F - Weather Conditions: {resort_data[resort][index][4]} - Wind/Gust Speeds: {str(resort_data[resort][index][6])} MPH/{str(resort_data[resort][index][7])} MPH\n"
40+
body += "------------------------\n"
41+
42+
body += "\nHappy adventures!"
43+
44+
print("Sending email")
45+
46+
msg = EmailMessage()
47+
msg.set_content(body)
48+
msg['subject'] = f"Ski & Snow data for {TODAY}"
49+
msg['from'] = EMAIL
50+
msg['to'] = TO_ADDRESS
51+
52+
connection.send_message(msg)
53+
connection.close()
54+
print("SUCCESS: Email sent with weather data.")
55+
56+
# If API call is not successful or body fails to compose properly, except block is executed.
57+
except:
58+
59+
body = "ERROR: Data not retrieved properly from OpenWeather. Verify that body composed properly."
60+
61+
msg = EmailMessage()
62+
msg.set_content(body)
63+
msg['subject'] = f"ERROR: Ski & Snow data for {TODAY}"
64+
msg['from'] = EMAIL
65+
msg['to'] = TO_ADDRESS
66+
67+
connection.send_message(msg)
68+
connection.close()
69+
print("ERROR: Unable to properly compose body. Verify that body composed properly. Check that API data was pulled correctly.")

resort_execute.ps1

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Set-Location # LOCATION OF .PY FILE
2+
Start-Sleep -Seconds 2
3+
python.exe main.py

weatherdata.py

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
import requests, os
2+
from datetime import *
3+
4+
OWM_ENDPOINT = "https://api.openweathermap.org/data/2.5/forecast" # OpenWeather 5 Day 3 hour forecast endpoint
5+
OWM_API_KEY = os.environ.get("OWM_API_KEY")
6+
RESORT_NAMES = ["Mt. Rose Ski Tahoe", "Kirkwood Mountain Resort", "Northstar California Resort", "Palisades Tahoe", "Boreal Mountain Resort", "Heavenly Mountain Resort"]
7+
RESORT_COORDINATES = [
8+
(39.31536205966153, -119.88242696290214), # Mt. Rose (Lat, Long)
9+
(38.685076025688694, -120.06518256903614), # Kirkwood (Lat, Long)
10+
(39.265070549674995, -120.13310469872255), # Northstar (Lat, Long)
11+
(39.19764404248699, -120.23275009165587), # Palisades (Lat, Long)
12+
(39.3363862980587, -120.35044481515166), # Boreal (Lat, Long)
13+
(38.935603234448905, -119.94488547556679), # Heavenly (Lat, Long)
14+
]
15+
RESORT_LINKS = [
16+
"https://skirose.com/", # Mt. Rose
17+
"https://www.kirkwood.com/", # Kirkwood
18+
"https://www.northstarcalifornia.com/", # Northstar
19+
"https://www.palisadestahoe.com/", # Palisades
20+
"https://www.rideboreal.com/", # Boreal
21+
"https://www.skiheavenly.com/", # Heavenly
22+
]
23+
24+
25+
def pull_weather_data():
26+
"""
27+
Function pulls information from OpenWeather using the 3 Hour / 5 Day API endpoint.
28+
Function loops through each entry in RESORT_COORDINATES and creates a dictionary entry using the resort_template dictionary.
29+
Each dictionary is added to resort_list which is then returned.
30+
"""
31+
resort_template = {
32+
"name": "",
33+
"link": "",
34+
"temp": [],
35+
"feels_like": [],
36+
"humidity": [],
37+
"weather_desc": [],
38+
"clouds": [],
39+
"wind_speed": [],
40+
"gusts": [],
41+
"date_time": [],
42+
}
43+
44+
resorts_list = []
45+
46+
for resort_index in range(len(RESORT_NAMES)):
47+
parameters = {
48+
"lat": RESORT_COORDINATES[resort_index][0],
49+
"lon": RESORT_COORDINATES[resort_index][1],
50+
"appid": OWM_API_KEY,
51+
"units": "imperial"
52+
53+
}
54+
55+
response = requests.get(url=OWM_ENDPOINT, params=parameters)
56+
weather_data = response.json()
57+
58+
resort_template["name"] = RESORT_NAMES[resort_index]
59+
resort_template["link"] = RESORT_LINKS[resort_index]
60+
61+
for time_stamp in range(40): # 8 Time stamps per day over 5 days
62+
resort_template["temp"].append(weather_data['list'][time_stamp]['main']['temp'])
63+
resort_template["feels_like"].append(weather_data['list'][time_stamp]['main']['feels_like'])
64+
resort_template["humidity"].append(weather_data['list'][time_stamp]['main']['humidity'])
65+
resort_template["weather_desc"].append(str(weather_data['list'][time_stamp]['weather'][0]['main']) + " - " + str(weather_data['list'][0]['weather'][0]['description']))
66+
resort_template["clouds"].append(weather_data['list'][time_stamp]['clouds']['all'])
67+
resort_template["wind_speed"].append(weather_data['list'][time_stamp]["wind"]["speed"])
68+
resort_template["gusts"].append(weather_data['list'][time_stamp]["wind"]["gust"])
69+
resort_template["date_time"].append(weather_data['list'][time_stamp]["dt_txt"])
70+
71+
resorts_list.append(resort_template)
72+
73+
resort_template = {
74+
"name": "",
75+
"link": "",
76+
"temp": [],
77+
"feels_like": [],
78+
"humidity": [],
79+
"weather_desc": [],
80+
"clouds": [],
81+
"wind_speed": [],
82+
"gusts": [],
83+
"date_time": [],
84+
}
85+
86+
return resorts_list
87+
88+
def generate_tables():
89+
"""
90+
Generate Tables takes the data from pull_weather_data and cleans up the information.
91+
First, the date_time inforamtion is cleaned up and formatted.
92+
Second, the information pull_weather_data is reformatted so that information can be displayed in rows when rendered.
93+
Invididual locations are added to the resort_data list which are then added to the all_resorts list.
94+
"""
95+
raw_resort_list = pull_weather_data()
96+
all_resorts = []
97+
resort_data = []
98+
item_row = []
99+
100+
# Convert time values
101+
for resort_index in range(len(raw_resort_list)):
102+
103+
for datetime_pos in range(len(raw_resort_list[resort_index]['date_time'])):
104+
datetime_str = raw_resort_list[resort_index]['date_time'][datetime_pos]
105+
datetime_object = datetime.strptime( datetime_str, '%Y-%m-%d %H:%M:%S')
106+
formatted_time = datetime_object.strftime('%B %d, %Y @ %I:%M%p')
107+
raw_resort_list[resort_index]['date_time'][datetime_pos] = formatted_time
108+
109+
# Create a new list for each resort. Rows will be list items appended from index of raw data for each key
110+
for resort_index in range(len(raw_resort_list)):
111+
resort_data.append(raw_resort_list[resort_index]["name"])
112+
resort_data.append(raw_resort_list[resort_index]["link"])
113+
114+
for item in range(len(raw_resort_list[0]['temp'])):
115+
item_row.append(raw_resort_list[0]['date_time'][item])
116+
item_row.append(raw_resort_list[0]['temp'][item])
117+
item_row.append(raw_resort_list[0]['feels_like'][item])
118+
item_row.append(raw_resort_list[0]['humidity'][item])
119+
item_row.append(raw_resort_list[0]['weather_desc'][item])
120+
item_row.append(raw_resort_list[0]['clouds'][item])
121+
item_row.append(raw_resort_list[0]['wind_speed'][item])
122+
item_row.append(raw_resort_list[0]['gusts'][item])
123+
resort_data.append(item_row)
124+
item_row = []
125+
all_resorts.append(resort_data)
126+
resort_data = []
127+
128+
return all_resorts

0 commit comments

Comments
 (0)