Build Your Own Weather Station

Photo of Raspberry Pi

Made by Raspberry Pi

About the project

The original Weather Station kit is a HAT for the Raspberry Pi that allows it to collect weather data using a variety of sensors. It is designed to be used in schools to enable students to create their own weather station, and has a range of resources to support its use.

Project info

Items used in this project

Hardware components

Raspberry Pi 3 Model B Raspberry Pi 3 Model B x 1
Sparkfun Atmospheric Sensor Breakout - Bme280 (qwiic) Sparkfun Atmospheric Sensor Breakout - Bme280 (qwiic) x 1
High Temp Waterproof Ds18b20 Digital Temperature Sensor - 3m Long High Temp Waterproof Ds18b20 Digital Temperature Sensor - 3m Long x 1
4.7 Kohms 2w 350v 4.7 Kohms 2w 350v x 2
Screw Type, 5.00 , Horizontal, 2 Poles, Cui Blue, Philip's Head Screw, Pcb Mount Screw Type, 5.00 , Horizontal, 2 Poles, Cui Blue, Philip's Head Screw, Pcb Mount x 5
Half-size Breadboard Half-size Breadboard x 1
Hook-up Wire - Black (22 Awg) Hook-up Wire - Black (22 Awg) x 1
Weather Station Kit With Anemometer/wind Vane/rain Bucket Weather Station Kit With Anemometer/wind Vane/rain Bucket x 1
Rj11 Breakout Board Rj11 Breakout Board Optional x 1
Mcp3008 - 8-channel 10-bit Adc With Spi Interface Mcp3008 - 8-channel 10-bit Adc With Spi Interface x 1
Junction Box Enclosure Junction Box Enclosure x 1

View all

Software apps and online services

Oracle Raspberry Pi Weather Station software Oracle Raspberry Pi Weather Station software git clone

Hand tools and fabrication machines

A soldering iron, solder, and safety equipment A soldering iron, solder, and safety equipment x 1
Solid core wire (22 AWG) Solid core wire (22 AWG) x 1
An Adafruit Perma-Proto HAT for Pi Mini Kit An Adafruit Perma-Proto HAT for Pi Mini Kit x 1
General prototyping tools: side-cutters, wire strippers. screwdrivers, etc. General prototyping tools: side-cutters, wire strippers. screwdrivers, etc. x 1
3D printer 3D printer x 1


What you will need

There are many different sensors available that you could use to make weather measurements. You don’t have to use the exact same hardware that is described here to build your weather station, but if you choose different components, you will probably need to also find (or write) a Python library that works with them.

The specific sensors and components here were chosen after considering a number of factors:

  • Availability
  • Cost
  • Linux/Python support
  • Reliability
  • Accuracy
  • Ease of use

This does not mean that the components chosen are the cheapest, most accurate, and easiest to use. Rather they are balanced for all these factors. For example, in some cases accuracy has been sacrificed in favour of ease of use.

When selecting the components for your weather station, you should make choices based on what is most important for your particular project. We always like to hear about alternative builds, so please post your designs in the Weather station forum.


  • A Raspberry Pi, either one that has built-in wireless connectivity or has a a WiFi dongle
  • A BME280 pressure, temperature, and humidity sensor
  • A DS18B20 digital thermal probe (with 1m lead)
  • Two 4.7 KOhm resistors
  • Some 5mm-pitch PCB mount screw terminal blocks
  • A breadboard, some jumper wires
  • An anemometer, wind vane, and rain gauge
  • Two RJ11 breakout boards (optional)
  • A MCP3008 analogue-to-digital convertor integrated circuit
  • Weatherproof enclosures; recommended products are this 75x75x37mm box for the BME280 and this larger 150x110x70mm box for the Pi and a soldered HAT; if you’re sticking with a less durable breadboard-only solution, then you may need a larger enclosure such as this 190x140x70mm one


  • The Oracle Raspberry Pi Weather Station software. You don’t need to install it, but you’ll use some of the Python programs. Clone the GitHub repository by opening a Terminal window and typing:
  1. git clone
  • The BME280 Python library:
  1. sudo pip3 install RPi.bme280
  • The MariaDB database server software:
  1. sudo apt-get install -y mariadb-server mariadb-client libmariadbclient-dev
  2. sudo pip3 install mysqlclient

Additional resources

If you are going to construct a permanent Weather HAT for your Pi, you may also need:

Humidity, temperature and pressure

The BME280 sensor is a digital sensor that can measure temperature, humidity, and atmospheric pressure. It is available in a number of breakout boards from popular manufacturers such as Adafruit and SparkFun. This guide assumes you have the Adafruit package, but the instructions should be applicable to most versions. One thing to check is that the I2C address is correct: for the Adafruit models it is 0x77 (as shown in the code below), but other versions can have different addresses (0x76 is a common alternative).

Wiring up the sensor

  • Connect up the sensor to your Pi as shown in the diagram above.


17 (3V3)Vin

6 (Gnd)Gnd



Some other breakout boards may have other pins (such as SDO or CSB), but those are not generally needed.

  • Open IDLE.

Opening IDLE3

IDLE is Python’s Integrated Development Environment, which you can use to write and run code.

To open IDLE, go to the menu and choose Programming.You should see two versions of IDLE - make sure you click on the one that says Python 3 (IDLE).

To create a new file in IDLE, you can click on File and then New File in IDLE’s menu bar.This will open a second window in which you can write your code.

  • Create a new Python file, save it as /home/pi/weather-station/bme280,  and add the following code to it:
  1. import bme280
  2. import smbus2
  3. from time import sleep
  5. port = 1
  6. address = 0x77 # Adafruit BME280 address. Other BME280s may be different
  7. bus = smbus2.SMBus(port)
  9. bme280.load_calibration_params(bus,address)
  11. while True:
  12. bme280_data = bme280.sample(bus,address)
  13. humidity = bme280_data.humidity
  14. pressure = bme280_data.pressure
  15. ambient_temperature = bme280_data.temperature
  16. print(humidity, pressure, ambient_temperature)
  17. sleep(1)
  • Now test the code: while the code is running, exhale onto the sensor. You should see the humidity values (and possibly the temperature values) increase. When you’ve finished testing, terminate the code by typing ctrl+c in the Python shell.

Once you’re happy that the sensor is recording sensible values, you can go on to modify the program so that it is ready to be used as part of the whole weather station operation later.

  • Replace the while True loop with a function called read_all() that returns the humidity, pressure, and temperature readings, in that order.

Ground temperature

The BME280 will report the air temperature, but this can be significantly warmer than the ground, particularly if it is frosty. A thermal probe stuck into the soil is a useful supplemental temperature measurement and can be used to indicate the presence of ice/frost in winter. The Dallas DS18B20 temperature sensor comes in many forms including a waterproof thermal probe version, and this is the sensor used on the Oracle Raspberry Pi Weather Station.

Wiring up the sensor

  • Normally the DS18B20 comes with three bare wires, so the easiest way to prototype and test the sensor is to use PCB mount screw terminal blocks that can also be plugged into breadboards. Add your DS18B20 to your circuit as shown in the diagram below. Note that you are setting up 3.3V and Ground rails along the side of the breadboard. These will be used later when you add extra sensors into the circuit.

  • Open the file /boot/config.txt:
  1. sudo nano /boot/config.txt
  • Edit it by adding the line below at the bottom:
  1. dtoverlay=w1-gpio

  • Then open /etc/modules.
  1. sudo nano /etc/modules
  • Add the lines below at the bottom of the file:
  1. w1-gpio
  2. w1-therm

  • Reboot the Raspberry Pi.

  • Open the file /home/pi/weather-station/ in IDLE and run it. You should see the temperature printed out in the Python shell window.

  • Put the probe into a glass of cold water and re-run the program. The new temperature reported should be lower (unless you were working in a very cold room in the first place!).


  • If you are unable to take readings from the DS18B20 sensor, check that the wires from the probe are securely connected to the screw terminals and that you have modified the /etc/modules and /boot/config.txt correctly.

  • Open a terminal window and type:
  1. ls /sys/bus/w1/devices/

You should see two files listed. If these are not shown, then recheck your wiring.

Air quality

The original Oracle Raspberry Pi Weather Station kit used a Figaro TGS2600 sensor for air quality measurements. The batch of devices installed on the Weather Station HAT have worked well, but we’ve noticed that many of the ones we’ve tested recently have been very difficult to calibrate and have produced contradictory readings. They’re fine if you want to detect a general change in the local gases (for example to build a fart detector), but we do not currently recommend them for use in a custom weather station.

We are continuing to evaluate low-cost air quality sensors and will update this guide as soon as we find one we’re happy with.

Active mechanical sensors

So far, all the sensors you’ve used have been passive electronic sensors that just sit there and make measurements of their surroundings. However, to measure things like rainfall and wind speed/direction, you’ll need to use active mechanical devices that physically interact with the environment.

The original Oracle Weather Station kit used popular wind and rain sensors that are used in many consumer weather stations. These are the recommended sensors to use, as they are robust and reliable. Their data sheet gives more information about the sensors’ size and construction.


These sensors usually come with RJ11 connectors (they look like a standard telephone jack), which are sturdy and therefore difficult to accidentally dislodge, so your weather station will remain operational even in blustery conditions.

When it comes to connecting them to your Pi, you have three options:

  1. Chop off the male RJ11 connectors and connect the wires using screw terminals or by soldering.
  2. Use female RJ11 connectors — these are quite fiddly to use with breadboards, but can provide a very sturdy connection if used with a printed circuit board (PCB) as part of a permanent weather station.
  3. Use RJ11 breakout boards:

  • These can be really helpful for prototyping, but the larger ones can be too bulky for long-term deployment.

  • Smaller ones often come with solderable pins that can be used with stripboard or a prototyping HAT to make a durable connection. In the coming steps the assembly instructions for creating a permanent hardware solution will use these smaller breakout boards.

Wind speed

A typical anemometer has three arms with scoops on the end that catch the wind and cause the arms to spin. If you were to dismantle one of the anemometers used by the original Oracle Weather Stations, you would find a small magnet attached to the underside.

At two points of the magnet’s rotation, it triggers a clever piece of electronics called a reed switch, pictured below.

The reed switch has two metal contacts inside it that contact each other when under the influence of a magnet. Therefore, electronically, this switch works in exactly the same way as a button connected to the Raspberry Pi: when the anemometer spins, its magnet passes the reed switch, causing it to form a closed circuit momentarily. Therefore, you can use the number of signals from the reed switch to calculate how fast the anemometer spins.

Whenever the reed switch is triggered, it produces a signal you can detect via a GPIO pin. For each full rotation of the anemometer, the sensor will produce two detectable signals. By counting and timing these signals, you can calculate the speed of the wind.

There are many ways of doing this with Python. One approach is to treat the sensor like a button and then use the gpiozero library to count the number of times it has been ‘pressed’.

Consumer anemometers normally have two wires. Connect one to a ground pin and the other to GPIO 5. If you’re using the RJ11 connectors, the anemometer uses the middle two wires of the cable, which are normally pins 3 and 4 on RJ11 breakout boards.

With the anemometer added, your circuit should look like this:

  • Open IDLE, create a new Python file, and save it as /home/pi/weather-station/
  • Add the lines below to use GPIOzero’s Button functions and set up a Button on GPIO 5. Also create a variable called wind_count to store the number of rotations.

  1. from gpiozero import Button
  3. wind_speed_sensor = Button(5)
  4. wind_count = 0
  • Now define a function that will be run whenever the pin is activated by a spin of the anemometer.
  1. def spin():
  2. global wind_count
  3. wind_count = wind_count + 1
  4. print("spin" + str(wind_count))
  6. wind_speed_sensor.when_pressed = spin
  • Save and run your code. Test it by manually turning the arms of the anemometer. In the Python shell, you should see your code being triggered and the count variable incrementing twice very rotation.

Now you can count the signals from the anemometer, you can use this data to calculate the wind speed.

Calculating wind speed

The anemometer produces two signals per spin, so you can count the number of full rotations of the sensor by halving the number of detected inputs. This can then be used to calculate the wind speed:

speed = distance / time

To calculate speed, you need to know the distance travelled in a certain amount of time. Measuring time is fairly straightforward, and you can count the number of signals over the course of a fixed time period, for example five seconds.

The distance travelled by one of the cups will be equal to the number of rotations multiplied by the distance around the edge of the circle (circumference):

speed = (rotations * circumference) / time

The circumference can be calculated as long as you know either the radius or diameter of the circle.

You can discover the radius of the circle made by the anemometer by measuring the distance from the centre to the edge of one of the cups. Once you know the radius, you can find the circumference with the formula 2 * pi * radius. Don’t forget that a whole rotation generates two signals, so you’ll need to halve the number of signals detected:

speed = ( (signals/2) * (2 * pi * radius) ) / time

The radius for the recommended anemometers used by the original Oracle Weather Station is 9.0cm, and that is the figure that will be used in the code examples that follow. Don’t forget to change this value if your anemometer has different dimensions!

To implement this formula in Python, you can use the math library. For example, if you measured 17 signals from your anemometer in 5 seconds, your wind speed could be calculated like this:

  1. import math
  3. radius_cm = 9.0
  4. wind_interval = 5
  5. wind_count = 17
  7. circumference_cm = (2 * math.pi) * radius_cm
  8. rotations = count / 2.0
  9. dist_cm = circumference_cm * rotations
  10. speed = dist_cm / wind_interval
  12. print(speed)
  • Remove (or comment out) the line in the spin function that prints out the wind_count value.
  • Now use this formula to modify your code so that it also calculates the speed of the wind in centimetres per second (cm/s).

I need a hint

Measurement units

Currently, the code calculates the wind speed in cm/s. However, this is not particularly useful — a more practical unit would be kilometres per hour (km/h).

  • Modify your code to return the wind speed in km/h.

I need a hint


Most anemometers will have a specification that includes calibration data to help you test the accuracy of your sensor. The data sheet  for the recommended anemometers says that one rotation a second should equate to 2.4 km/h. So in the example interval of five seconds, five spins (ten signals) should equal the same 2.4 km/h wind speed.

  • Run your program and spin the anemometer five times within the first five seconds. What wind speed value is reported?

You’ll probably find that the value doesn’t match the specification. This loss of accuracy is due to something called the anemometer factor, and is a result of some of the wind energy being lost when the arms turn. To compensate for this, you can multiply the reading generated by your program by an adjustment factor.

For the recommended anemometers, this factor equals 1.18.

Update the final line in your calculate_speed function to multiply your speed in km/h by 1.18.

I need a hint

  • You’ll need to alter the final print  line of your code so that it now shows the output in the correct units.
  • Re-run the code, and this time you should get a value closer to 2.4 km/h.
  • When you assemble the complete weather station, it will be useful to be able to reset your wind_count variable to zero, so add a function that does that now:
  1. def reset_wind():
  2. global wind_count
  3. wind_count = 0

Wind gusts

Weather reports and forecasts will normally report the wind speed along with wind gust information. A wind gust is a brief increase in wind speed that can occur whenever the wind is blowing. Gusts are more noticeable as the wind speed increases. This is because the force exerted by the wind increases rapidly as the wind speed increases.

Gusts normally occur because the air is not able to move along the ground at a constant speed. Obstacles such as vegetation, buildings, and elevation changes causes surface friction, which will slow the wind down in some places more than others. Air closer to the ground suffers from this phenomenon more than air higher up. This creates a more turbulent wind flow along the ground, which leads to gusts. A typical wind gust lasts less than 20 seconds.

Storing wind readings

When your weather station is fully operational, you can record the maximum wind speed during a given period (the gust) as well as the average speed. You can do this by constantly taking wind speed measurements for five seconds, and temporarily storing them to be processed every few minutes. To do this, we will use a Python data structure called a list.

  • Open IDLE, and open the file /home/pi/weather-station/ file that you created in the last step.
  • Add a line at the very top to import the statistics library
  1. import statistics
  • Then add this line, which creates an empty list called store_speeds, below the import lines:
  1. store_speeds = []
  • Now modify the while True loop so that it contains a sub-loop that continually takes wind speed readings and adds them to this list. You can then use statistics.mean to calculate the mean value of readings in the store_speeds list.
  1. while True:
  2. start_time = time.time()
  3. while time.time() - start_time <= wind_interval:
  4. reset_wind()
  5. time.sleep(wind_interval)