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.4 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 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.

2 responses to “Today’s weather in my inbox, via Python”

  1. Dimple Aggarwal says:

    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?

  2. Anthony says:

    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!

Leave a Reply

Your email address will not be published. Required fields are marked *