29 July 2019 Tagged in: python | workshop

Weather clock

Notes on how to make a simple ambient weather forcast display.

Weather clock

The "weather clock" is a simple ambient computing device that shows you what the weather will be doing. But its main purpose is to inspire people to make their own ambient and physical computing devices.

I was asked by PJ Evans to help people come up with summer projects at the July 2019 Milton Keynes Raspberry Jam. The idea was that people would come up with ideas, I would spend a "talk" guiding them through how to do it and what kit was needed, and the people would come back at the October Jam to show off their creations. The weather clock was a project I quickly put together to illustrate the sort of thing that would be possible.

The idea

The front of the weather clock

The idea of the weather clock is that it's an ambient smart display that keeps you aware of the wider world, without demanding your interaction or even attention. It's an example of ubiquitous computing, where the intelligence of devices just fades into the background.

You can mount the clock in a deep picture frame or similar and hang near your outside door. The Raspberry Pi reads the three-day weather forecast from the BBC and controls a servo motor to point the arrow towards the day's weather. As you head out, you can glance at the weather clock to see what the weather will be doing, and hence whether you need to take an umbrella or sunscreen.

The distance sensor allows you to see the other days in the forecast. If you're standing over about a metre away, the clock displays today's weather forecast. Get a bit closer and clock displays tomorrow's weather; get closer still and it displays the forecast for the day after tomorrow. The LEDs light up to show you which day's forecast is being displayed.

The parts

The hardware is four main components:

You'll also need:

  • a separate 5v power supply to power the motor.
  • a breadboard, some LEDs, some resistors, and some little jumper wires. The CamJam EduKit 1 gives you most of these, but you may need some more jumper wires and resistors: the Pimoroni Maker Essentials kits are a good starting point.

(You can buy all of these items from The Pi Hut, who sponsor the Milton Keynes Raspberry Jam. No, I don't get a commission on any sales!)

You may need to solder the connection headers on the Servo HAT, and you may find it useful to solder the resistors to the LEDs once you assemble the whole thing in the frame.

You'll also need to get a frame to mount the parts in. If you're prototyping, you can use a piece of cardboard box, like I did.

Schematic layout of the weather clock components

Putting it together

When you're assembling the hardware, do it one component at a time, and write little Python scripts as you go to test that everything is working.

Setting up software

Start by cloning (downloading) the software from the Pi Weather Clock repository on GitHub. (If you want to extend or modify the software, you might want to fork the repository first, then clone your forked repository to your Pi.)

pi@raspberry:~ $ git clone https://github.com/NeilNjae/pi-weather-clock
pi@raspberry:~ $ cd pi-weather-clock

Next, create a virtual environment to contain all the Python packages and libraries you'll need for the clock. (The reason for using a virtual environment is so that the packages you've installed for this project don't interfere with any packages you may install for other projects.)

pi@raspberry:~/pi-weather-clock $ python3 -m venv weather-clock
pi@raspberry:~/pi-weather-clock $ source weather-clock/bin/activate
(weather-clock) pi@raspberry:~/pi-weather-clock $ 

The first line creates the virtual environment: it can take a few minutes. The second line activates the virtual environment, meaning that packages installed here will only be accessible while in this environment. Note that the name of the active environment is at the start of the prompt.

Now, use pip to install the packages listed in requirements.txt:

(weather-clock) pi@raspberry:~/pi-weather-clock $ pip install -r requirements.txt

If you ever want to leave the current environment, use the command:

(weather-clock) pi@raspberry:~/pi-weather-clock $ deactivate

(You can do that from any directory.)

The servo

First thing to get going is the servo.

  1. Turn off the Pi
  2. Add the PWM/Servo HAT
  3. Connect the servo motor to connection 4
  4. Connect the power supply to the HAT
  5. Use blutack or something to add a pointer to the servo axle, just so it's easier to see where it's pointing.
  6. Restart the Pi

Make sure servo connection in the right way around. On my servo, the brown wire is nearest the outside edge of the HAT. When the HAT gets power, a little green LED lights up.

To test it, run the servo-sweep.py script. It should sweep the servo around 180⁰. Then run the servo.py script and enter a number between 1 and 12: the servo should swing around to one of twelve positions. These positions will correspond to the weather symbols on the finished clock.

Run the scripts from the command line like this:

(weather-clock) pi@raspberry:~/pi-weather-clock $ python servo-sweep.py

If something doesn't work, check all the connections, including orientation of plugs.

The distance sensor

Next, wire up the distance sensor. I added the sensor direct to the breadboard, using the +5V and ground lines, and connecting trigger to pin 4. You'll need two resistors on the echo line, to conver the 5V signal to the 3.3V the Pi needs. Any two resistors in a roughly 2:1 ratio will do: I connected a 220Ω resistor to the echo, a 470Ω resistor to ground, and connected pin 17 to the space in between.

To test it, run the distance.py script. It should rapidly print both a number (the distance in metres to the object detected) and the calculated range band. The range band is used to determine which forecast to use.

The LEDs

The LEDs connect to pins 16, 20, and 21. I used 230Ω resistors to limit the current through the LEDs and hence protect the Pi. Connect the shorter (cathode) leg of the LED to one end of the resistor and the other end of the resistor to ground. Connect the lead from the Pi pin to the longer (anode) leg of the LED.

As before, test it with the leds.py script. It will just cycle through the LEDs, lighting each one in turn.

Reading the weather forecast

The final part of the project is the code to read the weather forecast from the BBC. I keep the code simpler by reading the weather from the RSS feeds. I used the three day forecast for Milton Keynes, with code 2642465. (You can find the code for your location from the main weather website, selecting the correct location, and noting the seven digit code in the URL.)

I use the requests library to read the forecast from the website and the Beautiful Soup library to parse the forecast into something a Python script can easily use; both of these were installed with the pip install command above. (The feedparser library in theory is the better solution, but it seemed to fall over parsing the location information in the BBC's forecasts.)

The forecast.py script reads, parses, and the pulls out the correct parts of the forecast. The weather information itself is contained in the three item elements of the RSS feed, one for each day. The title of each item contains, among other things, the weather summary for that day. The description contains more information about the weather, such as temperature and air pressure.

As the feed is RSS and therefore meant to be read by machines, pulling out the right parts of the information is fairly simple. It's implemented in the forecast.py script.

Each item looks like this:

  <title>Today: Sunny, Minimum Temperature: 14°C (58°F) Maximum Temperature: 25°C (77°F)</title>
  <description>Maximum Temperature: 25°C (77°F), Minimum Temperature: 14°C (58°F), Wind Direction: Southerly, Wind Speed: 11mph, Visibility: Moderate, Pressure: 1009mb, Humidity: 61%, UV Risk: 6, Pollution: Low, Sunrise: 05:19 BST, Sunset: 20:59 BST</description>
  <pubDate>Mon, 29 Jul 2019 08:04:08 GMT</pubDate>
  <guid isPermaLink="false">https://www.bbc.co.uk/weather/2642465-0-2019-07-28T21:47:00.000+0000</guid>
  <georss:point>52.0417 -0.7558</georss:point>

The information in both the title and description are presented as a series of terms, separated by commas; each term has a key and a value, separated by a colon. Python's str.split() method allows us to break down the text into these parts.

The get_forecast() procedure does the work. It starts by getting and parsing the forecast RSS feed (with a check to see if the download was successful). It then finds the item elements of the feed and uses str.split() to pull out the parts of the forecast, builing up a Python dict of information as it goes. The result is a list of three dicts (one for each day), with each dict looking like this:

{   'Wind Speed': '10mph',
    'Maximum Temperature': '25°C (77°F)',
    'Pressure': '1009mb',
    'UV Risk': '7',
    'Wind Direction': 'South Westerly',
    'Minimum Temperature': '14°C (58°F)',
    'Visibility': 'Moderate',
    'Humidity': '61%',
    'Pollution': 'Low',
    'Sunrise': '05:19 BST',
    'Summary': 'Sunny',
    'Sunset': '20:59 BST'

The WEATHER_POSITIONS dict maps the summary information into clock positions.

When you run the forecast.py, it should read the forcast, print it out, and then print out the weather summaries and corresponding clock positions. It uses the last_location_refresh variable to track when the forecast was last read. Every ten seconds, the script will refresh the forecast information (the forecast is read much less frequently in the final version).

The finished product

If all those parts are successful, now is the time to put them all together!

You'll need to find some frame for your clock (a cardboard box will do for a quick prototype). You'll need to print a clock face to add to the clock. You can use my clock face, but you may need to move things around depending on the exact range of angle for your servo. You'll need four holes in the clock face: on for the servo motor spindle, where the guide lines meet in the middle, and one each for the day indicator LEDs, next to the text on the clock face.

You can leave the distance sensor and its associated circuitry on the breadboard.

I soldered the resistors directly onto the LEDs and then fixed the LEDs to the display. I twisted the free ends of the resistors together and connected all three to the ground pin on the Raspberry Pi.

The spindle of the servo should go where the guide lines meet on the clock face. Place some kind of clock hand on the servo: I just used an large arrow printed on a piece of card. You'll have to experiment with the correct orientation of the servo so that the position of the clock hand matches the weather it's supposed to be. Use the servo.py script to get things set up.

To start with, use sticky tape and blu-tack to hold components in place. To make things more permanent, you can use a hot glue gun.

The various pieces of code are combined into the clock.py script.

To make the weather clock script run on startup, make the run_weather_clock script executable with the chmod command, the make it run on startup by editing the crontab file:

(weather-clock) pi@raspberry:~/pi-weather-clock $ chmod +x run_weather_clock
(weather-clock) pi@raspberry:~/pi-weather-clock $ sudo crontab -e

When the editor opens, add the line:

@reboot /home/pi/pi-weather-clock/run_weather_clock

Use Ctrl-O to write the changes and Ctrl-X to exit the editor.

Reboot the Pi and the weather clock should start up!


If you want other weather symbols on your clock, you'll need to change the WEATHER_POSITIONS dict in the script and update the clock face. You can use the weather symbol images in the repository.

There's a lot more information in the weather forecast RSS feed than just the summary. Can you add more outputs for things like temperature, wind speed and direction, and so on? Could you have a Pi-powered barometer, showing forecast air pressures?

Rather than having the distance sensor control which day of the forecast is displayed, why not have it display different locations? You'll need to modify the script so that it reads several RSS feeds and picks out the correct forecast depending on the range band.


Weather symbol images by Mels Brushes, from Vectorish (CC BY-NC).

Cover photo by unsplash-logoJonathan Bowers