Today’s weather in my inbox, via Python
In the category of “potentially useful but mostly just a learning exercise,” here’s a Python script that emails me the local weather report twice a day. I loaded it on a Raspberry Pi my family gave me as a gift last year, set up a cron task, and now each day when I wake up I have a forecast waiting in my inbox. Makes me feel special!
The script — compatible with Python 3.6 and Python 2.7 — uses the awesome Requests library to fetch two endpoints from the Weather Underground API. One provides a forecast, and the other offers a summary of yesterday’s weather. For emailing, it uses the standard Python smtplib.
The code’s available on Github, so fork it and make it your own. You’ll need to have the Requests and simplejson libraries installed. Contributions are welcome!
Here’s a quick overview on how to set it up:
First, you’ll need to sign up for a Weather Underground API key. The free developer level has more than enough calls per day for this app, so choose that unless you plan to obsess about the weather in an oversized manner.
The API key and your email parameters go into a settings.py
file:
mail_settings = { 'address': 'anyone@example.com', 'pw': 'your-email-password', 'smtp': 'post.example.com', 'from': 'Mr. Weather Robot' } send_to_addresses = ['someone@example.com', 'someone_else@example.com'] api_key = 'your-wunderground-api-key'
Then, here’s the wx-mail.py
file:
import datetime import smtplib import requests import simplejson as json from email.mime.text import MIMEText from local_settings import mail_settings, send_to_addresses, api_key def fetch_forecast(api_key, request_type): mail_url = 'http://api.wunderground.com/api/' + api_key + '/' +\ request_type + '/forecast/q/VA/Leesburg.json' r = requests.get(mail_url) j = json.loads(r.text) return j def build_html(forecast_json, yesterday_json): # build some HTML snippets to open and close this email html_open = """\ <html> <head></head> <body> """ html_close = """\ </body> </html> """ # let's now build the HTML body contents wxdate = forecast_json['forecast']['txt_forecast']['date'] mail_text = '<h3>Hello, DeBarros family!</h3><p>Here is the ' +\ 'Leesburg, Va., weather forecast as of ' + wxdate + '</p>' forecast_length = len(forecast_json['forecast']['txt_forecast']['forecastday']) - 1 # looping through the JSON object for i in range(0, forecast_length): cast = '<p><b>' +\ forecast_json['forecast']['txt_forecast']['forecastday'][i]['title'] +\ '</b>: ' +\ forecast_json['forecast']['txt_forecast']['forecastday'][i]['fcttext'] +\ '</p>' mail_text += cast # Now, for yesterday's weather summary ... # We'll pull the date and some weather data from the summary API endpoint summary_date = yesterday_json['history']['dailysummary'][0]['date']['pretty'] high_low_temp = yesterday_json['history']['dailysummary'][0]['maxtempi'] +\ ' / ' +\ yesterday_json['history']['dailysummary'][0]['mintempi'] +\ ' degrees Fahrenheit' max_min_humid = yesterday_json['history']['dailysummary'][0]['maxhumidity'] +\ '% / ' +\ yesterday_json['history']['dailysummary'][0]['minhumidity'] + '%' precipitation = yesterday_json['history']['dailysummary'][0]['precipi'] +\ ' inches' max_wind_speed = yesterday_json['history']['dailysummary'][0]['maxwspdi'] +\ ' mph' yesterday_html = """\ <h3>Here's yesterday's weather summary:</h3> <p><b>High/low temperature: </b>""" + high_low_temp + '</p>' +\ '<p><b>Max/min humidity: </b>' + max_min_humid + '</p>' +\ '<p><b>Precipitation: </b>' + precipitation + '</p>' +\ '<p><b>Maximum wind speed: </b>' + max_wind_speed + '</p>' # put it all together html_body = html_open + mail_text + yesterday_html + html_close return html_body def send_email(mail_text): # Set the current time and add that to the message subject cur_date = datetime.date.today().strftime("%B") +\ ' ' + datetime.date.today().strftime("%d") +\ ', ' + datetime.date.today().strftime("%Y") subject = 'Family forecast for ' + cur_date # Set up the message subject, etc. Then send it. COMMASPACE = ', ' msg = MIMEText(mail_text, 'html') msg['Subject'] = subject msg['From'] = mail_settings['from'] msg['To'] = COMMASPACE.join(send_to_addresses) server = smtplib.SMTP(mail_settings['smtp'], 25) server.login(mail_settings['address'], mail_settings['pw']) server.set_debuglevel(1) server.sendmail(mail_settings['address'], send_to_addresses, msg.as_string()) server.quit() if __name__ == "__main__": forecast_json = fetch_forecast(api_key, 'forecast') yesterday_json = fetch_forecast(api_key, 'yesterday') mail_text = build_html(forecast_json, yesterday_json) send_email(mail_text)
The code’s straightforward, but a few things to note:
- The Python standard smtplib provides all you need for sending the email. Check the official docs for examples.
- I’ve gotten into the habit of using the simplejson library for wrangling API response objects, but the standard Python json library works just as well.
Have fun, and may all your coding days be sunny and warm.
hello , i like your code but i’m getting an error in import requests.
i’ve changed it to urllib.request then it is is fine but then it shows an error in r= urllib.request.get() as there is no module get. what should i do now?
Dimple,
I should have made it clear that this code has a dependency on the Requests library: http://docs.python-requests.org/en/latest/user/quickstart/
Also, you will need the simplejson library.
Thanks for pointing that out!
This is an awesome post. Thanks so much! For those using gmail, I was getting an error that I solved in the following way.
After this line…
…add these two lines:
In the settings.py file, use the following:
Hi, Calvin,
Glad you liked this, and thanks for sharing that extra code!