troysquillaci.me

My collection of frivolous fables.

Personal Weather Station

Written on

Weather is fascinating. It profoundly impacts our daily lives and helps carve out the beautiful and diverse environments across Earth. Having studied complex systems at university, I've grown the appreciate the difficulty of weather forecasting. Attempting to accurately predict weather requires lots of data. There are many entities that gather such data – from government agencies using satellites, to private companies with their own proprietary sensor networks.

One particularly awesome and interesting weather source is Weather Underground. The data used by WU is crowd-sourced and publicly available. Anyone with a personal weather station can register their station with WU to share local weather data. WU (and perhaps others) use this data for their own weather forecasts.

Raspberry Pis are wonderful, inexpensive computers that have become incredibly popular over the past several years. I've got many of them serving different purposes around my living space. Creating a personal weather station using a Raspberry Pi is certainly not a novel idea – finding a tutorial on the internet is easy – it's been done many times. However, it's a lot of fun and I've decided to take my own stab at it. This post is not intended to be a tutorial, but rather a high-level overview of the approach that I took.

Hardware List

This Raspberry Pi weather station will be deployed on the patio of my apartment in Phoenix. As most are probably aware, Phoenix gets hot during the summers. Raspberry Pis are durable devices and can withstand large temperature ranges. They've been deployed in Antarctica for research, but can also withstand high temperatures seen in desert climates.

I put mine in a third-party case to protect some of the electrical components. The hot environment will significantly limit the cooling offered by this case, but it's better than nothing.

Imgur

A wireless internet connection is the most convenient option for a device located outdoors. I opted for the Raspberry Pi 3 - Model B thanks to the built-in Wi-Fi capability.

Packed with lots of useful sensors, the Sense HAT is an handy add-on board for the Raspberry Pi. Capturing weather data is possible with the Sense HAT, but temperature radiating from the Raspberry Pi can interfere with readings (due to the close proximity). For this reason, I chose not to use the Sense HAT and instead went got the Adafruit AM2302. This sensor is isolated so readings are more accurate.

Attaching all of the components together is straight-forward. A good pin out for the Raspberry Pi can be found here.

Creating a WU Station

Recall that the goal of the project is to share local weather data from the Raspberry Pi to Weather Underground. Doing this requires a WU account.

Imgur

Once registered, a new weather station can be added here. It will be assigned a Station ID and a Station Key, used by the Raspberry Pi to upload weather data to your account.

Provisioning the Raspberry Pi

Raspbian is the official Debian-based OS for the Raspberry Pi. It comes with lots of built-in goodies. There are different variants (some including desktop environments and additional packages). The requirements for this project made the lite version the obvious choice.

Interacting with the AM2302 sensor requires a Python package distributed by Adafruit. I used pyenv to provision a Python 3.7 virtual environment for this project.

Imgur

Weather Station Code

Now for the fun part, time to write some Python code. The high-level steps are:

  • Allow the user to specify custom run parameters (i.e. station id, station key, interval for reading sensor data).
  • Read the sensor data at the specified interval.
  • Create a payload to upload to WU.
  • Upload the the payload to WU.

This is easy to do in Python, especially with the help of the sensor interface provided by Adafruit.

#!/usr/bin/env python

"""
Author: Troy Squillaci (troysquillaci.me)

Raspberry Pi Weather Station

This simple script enables a Raspberry Pi to be used as a basic weather
station, capable of reporting temperatue and humidity readings to Weather
Underground (https://www.wunderground.com/). This project utilizes the
Adafruit AM2302 (Temperature / Humidity) sensor.
"""

import Adafruit_DHT
import argparse
import datetime
import sys
import time

from urllib.parse import urlencode
from urllib.request import urlopen

WU_URL = "http://weatherstation.wunderground.com/weatherstation/updateweatherstation.php"


def read_sensor():

    """
    Attempt to take a sensor reading, using the read_retry method will attempt
    up to 15 times to get a sensor reading (with two second pauses between
    attempts).
    """

    return Adafruit_DHT.read_retry(sensor, pin)


def to_fahrenheit(temp):

    """
    Converts a temperature in celsius to fahrenheit.
    """

    return (temp * 1.8) + 32


if __name__ == '__main__':

    parser = argparse.ArgumentParser()

    parser.add_argument('-i', '--interval', type=float, required=True,
                        help='interval (in minutes) to read sensor data')
    parser.add_argument('-s', '--station_id', type=str,
                        help='the station id assigned by Weather Underground')
    parser.add_argument('-k', '--station_key', type=str,
                        help='the station key assigned by Weather Underground')
    parser.add_argument('-u', '--upload', action='store_true', default=False,
                        help='upload data to Weather Underground')

    args = parser.parse_args()

    # Specify the correct sensor variant.
    sensor = Adafruit_DHT.AM2302

    # Specify the pin the sensor is connected to on the Raspberry Pi. This can
    # be changed. See https://pinout.xyz/pinout/# for more information.
    pin = 4

    # Used to allow for constant temperature recordings, but only periodic
    # uploads to Weather Underground.
    prev_min = datetime.datetime.now().minute
    prev_min -= 1

    if prev_min == 0:

        prev_min = 59

    while True:

        cur_min = datetime.datetime.now().minute

        # Attempt to read the sensor for humidity and temperature.
        humidity, temperature = read_sensor()

        # Convert the temperature to fahrenheit.
        temperature = to_fahrenheit(temperature)

        print(f'Temperature: {temperature}, Humidity: {humidity}')

        if cur_min != prev_min:

            prev_min = cur_min

            if (cur_min == 0) or ((cur_min % args.interval) == 0):

                if humidity and temperature:

                    # Upload the sensor readings to Weather Underground.
                    if args.upload:

                        print('Uploading data to Weather Underground...')

                        weather_data = {
                            "action": "updateraw",
                            "ID": args.station_id,
                            "PASSWORD": args.station_key,
                            "dateutc": "now",
                            "tempf": str(temperature),
                            "humidity": str(humidity)
                        }

                        try:

                            upload_url = f'{WU_URL}?{urlencode(weather_data)}'

                            response = urlopen(upload_url)
                            print(f'Weather Underground: {response.read()}')
                            response.close()

                        except Exception:

                            print('Exception:', sys.exc_info()[0])
                    else:

                        print('Skipping upload to Weather Underground.')

                else:

                    print('Unable to read sensor data...')

        # Time between samples in minutes, should be somewhat large to avoid
        # reading issue with the Adafruit AM2302 sensor.
        time.sleep(5)

This is all that is needed to get the weather station up and running. For convenience it's worth considering to add a start-up service to launch this program when the Raspberry Pi boots. This source code is on my GitLab.

Deploying

Proper deployment is important to ensure protection of the hardware and accurate sensor readings. Ideally, the location of the weather station should be shaded (never experience direct sunlight) and above the ground by several feet.

Imgur

My patio is shaded throughout most the day. The location on the wall that I mounted the weather station is about six feet above the ground and never experiences direct sunlight. Though, improvements need to be made with regards to how I hung it. Nails and a rubber band do the trick right now.

To Conclude

Making a weather station with a Raspberry Pi was a fun project. In terms of difficultly, I'd consider it easy. Plentiful documentation online made parts of this project a lot easier. Future improvements can be made to the station. Perhaps the inclusion of other weather-related sensors (wind, pressure, etc) would be an interesting problem to tackle.

Imgur

Small projects like this help keep my skills of the trade sharp. Always staying up-to-date with technologies is a cornerstone of being an effective software engineer. Raspberry Pis are awesome devices to play around with from the perspective of someone heavily involved with technology.

This entry is posted in Code.