HomeTutorials › Raspberry Pi Weather Station – Part 4

Raspberry Pi Weather Station – Part 4

We are almost there – in the past three Raspberry Pi Weather Station tutorials we have assembled the weather station electronics, wrote the code to gather data, and set up ThingSpeak to collect and display the data – now we just need to get it outside. In the final part of this tutorial we are going to set up the Pi to run our weather station code automatically, look at how to protect the Pi from the elements, and discuss placement of your weather station and the logistics of it being outside.

Before we get started, you should have completed the previous three sections of this tutorial. This section of the tutorial wont involve much coding, and will be very subjective to your location. We will try to break this down to keep it as simple as possible as always, but if you have specific questions pertaining to this section of the tutorial, please feel free to post them below. We will start by getting the last little bit of coding out of the way by modifying our Pi’s rc.local file to boot the weather code automatically. Next, we will look at protecting the Pi and its sensors, while still maintaining somewhat accurate readings. We will then tackle where to place your weather station and what you need to consider when doing this.



This tutorial requires several items:

  • A completed assembly from Part 1 of this tutorial set
  • Completed code from Part 2 of this tutorial set
  • Completed setup from Part 3 of this tutorial set
  • 1 x Pi 3 / 3+ capable power supply (Or external power supply)
  • A USB Keyboard & Mouse
  • A HDMI compatible monitor
  • Internet access

Step 1 – One last change to our python code


If you don’t already have your project open in the Python editor on the Raspberry Pi, start by opening the terminal again and loading the Python 2 editor using the command:


Open your project file using the “file” menu.

Step 2 – Code Modification

We are going to add one line to the very top of our python script.


import time
from w1thermsensor import W1ThermSensor
import board
import busio
from adafruit_bme280 import basic as adafruit_bme280
i2c = busio.I2C(board.SCL, board.SDA)
import adafruit_ads1x15.ads1015 as ADS
from adafruit_ads1x15.analog_in import AnalogIn
import RPi.GPIO as GPIO
import urllib
import http.client
key = "1Z170TQ59OH6F6JS"

bme = adafruit_bme280.Adafruit_BME280_I2C(i2c)
ads = ADS.ADS1015(i2c)
ads.gain = 1
ds18b20 = W1ThermSensor()
interval = 15  #How long we want to wait between loops (seconds)
windTick = 0   #Used to count the number of times the wind speed input is triggered
rainTick = 0   #Used to count the number of times the rain input is triggered
#Set GPIO pins to use BCM pin numbers
#Set digital pin 17 to an input and enable the pullup 
GPIO.setup(17, GPIO.IN, pull_up_down=GPIO.PUD_UP)
#Set digital pin 23 to an input and enable the pullup 
GPIO.setup(23, GPIO.IN, pull_up_down=GPIO.PUD_UP)
#Event to detect wind (4 ticks per revolution)
GPIO.add_event_detect(17, GPIO.BOTH) 
def windtrig(self):
    global windTick
    windTick += 1
GPIO.add_event_callback(17, windtrig)
#Event to detect rainfall tick
GPIO.add_event_detect(23, GPIO.FALLING)
def raintrig(self):
    global rainTick
    rainTick += 1
GPIO.add_event_callback(23, raintrig)
while True:
    #Pull Temperature from DS18B20
    temperature = ds18b20.get_temperature()
    #Pull temperature from BME280
    case_temp = bme.temperature
    #Pull pressure from BME280 Sensor & convert to kPa
    pressure_pa = bme.pressure
    pressure = pressure_pa / 10
    #Pull humidity from BME280
    humidity = bme.humidity
    #Calculate wind direction based on ADC reading
    chan = AnalogIn(ads, ADS.P0) 
    val = chan.value
    windDir = "Not Connected"
    windDeg = 999
    if 20000 <= val <= 20500:
        windDir = "N"
        windDeg = 0
    if 10000 <= val <= 10500:
        windDir = "NNE"
        windDeg = 22.5
    if 11500 <= val <= 12000:
        windDir = "NE"
        windDeg = 45
    if 2000 <= val <= 2250:
        windDir = "ENE"
        windDeg = 67.5
    if 2300 <= val <= 2500:
        windDir = "E"
        windDeg = 90
    if 1500 <= val <= 1950:
        windDir = "ESE"
        windDeg = 112.5
    if 4500 <= val <= 4900:
        windDir = "SE"
        windDeg = 135
    if 3000 <= val <= 3500:
        windDir = "SSE"
        windDeg = 157.5
    if 7000 <= val <= 7500:
        windDir = "S"
        windDeg = 180
    if 6000 <= val <= 6500:
        windDir = "SSW"
        windDeg = 202.5
    if 16000 <= val <= 16500:
        windDir = "SW"
        windDeg = 225
    if 15000 <= val <= 15500:
        windDir = "WSW"
        windDeg = 247.5
    if 24000 <= val <= 24500:
        windDir = "W"
        windDeg = 270
    if 21000 <= val <= 21500:
        windDir = "WNW"
        windDeg = 292.5
    if 22500 <= val <= 23000:
        windDir = "NW"
        windDeg = 315
    if 17500 <= val <= 18500:
        windDir = "NNW"
        windDeg = 337.5
    #Calculate average windspeed over the last 15 seconds
    windSpeed = (windTick * 1.2) / interval
    windTick = 0
    #Calculate accumulated rainfall over the last 15 seconds
    rainFall = rainTick * 0.2794
    rainTick = 0
    #Print the results
    #print( 'Temperature: ' , temperature)
    #print( 'Humidity:    ' , humidity, '%')
    #print( 'Pressure:    ' , pressure, 'kPa')
    #print( 'Wind Dir:    ' , windDir, ' (', windDeg, ')')
    #print( 'Wind Speed:  ' , windSpeed, 'KPH')
    #print( 'Rainfall:    ' , rainFall, 'mm')
    #print( ' ')

    params = urllib.parse.urlencode({'field1' : temperature, 'field2' : humidity, 'field3' : pressure, 'field4' : windSpeed,
                               'field5' : windDeg, 'field6' : rainFall,'key':key})

    #Configure header / connection address
    headers = {"Content-typZZe": "application/x-www-form-urlencoded","Accept": "text/plain"}
    conn = http.client.HTTPConnection("api.thingspeak.com:80")
    #Try to connect to ThingSpeak and send Data
        conn.request("POST", "/update", params, headers)
        response = conn.getresponse()
        print( response.status, response.reason)
        data = response.read()
    #Catch the exception if the connection fails
        print( "connection failed")

This one line of code isn’t 100% necessary for the method we are using to boot on startup, but in the event you want to make the script executable, it is a good idea to have this little chunk of code in place. It is used to instruct the interpreter which version of python we want to use. Since we have written this in python3 it is a good idea to make sure it runs in the python3 environment.

Once this has been added as shown, save and test it using the F5 key. Once you have confirmed everything still works, we can move on to the next step!

Step 3 – Configure Your Code To Start Automatically

Step 3

Now that our python code is completed, we can close idle and go back to the terminal. We are now going to add an entry to a file that runs as soon as the Pi boots up. This entry is going to tell the Pi to run our Python file – and therefore, our python code will run anytime the pi boots up. That way, if you move your Pi, lose power, etc it will just start back up normally as soon as it gets power again.

To do this we are going to edit the rc.local system file with the built in “nano” text editor. Enter the following command into the terminal:

sudo nano /etc/rc.local

This should open the file in the terminal window.

Step 4 – Remove Some Code

Step 4

Scroll down to the bottom using the arrow keys. We are going to delete the lines circled in the attached image. Be sure to keep the line “exit 0”

Step 5 – Add The Start Command

Step 5

We called our file “weather.py” and saved it in the directory /home/pi/ so we are going to add this line above “exit 0”:

python3 /home/pi/weather.py &

It is important not to forget the “&” at the end of the command. The ampersand is used to fork the process as our script runs indefinitely. Without this, the Pi will not boot as it will wait for our never ending script to end before continuing the boot process.

Step 6 – Save And Reboot

Step 6

Once this is done, press Ctrl+X and then “Y” to save it. Now we should be able to reboot our Pi. Type into the terminal:

sudo reboot

Step 7 – Make Sure It Starts Automatically

While your Pi is rebooting; open up your ThingSpeak channel on another device. We are going to check to make sure our ThingSpeak channel starts receiving data to ensure the program started – remember it will take about 15 seconds from boot up to start sending data. Once we have confirmed data is being sent we can move onto the next step.

Step 8 – Weatherproofing


Before we move the station outside, we need to look at protecting the Pi. This part of the project is probably the most tricky and will require creativity to get accurate results without causing damage to the Pi and the sensor. Our goal is to protect the Pi and Protect the BME280 sensor, but still allow the BME280 to sense the environment accurately. The key issues being that the BME will not tolerate direct contact with water, but we still need it to have air passing over the sensor from the environment.

We wont ever claim our method is best, but to accomplish this we have modified one of our Weatherproof 4×4 Boxes to allow for some airflow. This box is a very tight fit (and wont work if you are planning to use ethernet). Our modification is simple – cut a large hole in the lid of the box (thanks to our neighbours at Industrial Plastics for the nice clean cut!), and cover it with a 3D printed louver panel we quickly threw together and printed. If you are interested in printing it, we have made the file available here. If you are worried about spiders and bugs making a home inside, we recommend installing a piece of window screen between the louver panel and the box, it should keep most things out!

To allow the cables for the sensors and power to get out of the box we have notched the bottom wide enough for all the cabling to fit. It will be sealed later with silicone.

Step 9 – Stevenson Screen


To accurately measure air temperature, the temperature sensor cannot be in direct sunlight. Weather stations will typically have a Stevenson Screen of some sort surrounding the sensor to ensure and accurate reading. We found this awesome little Stevenson Screen on Thingiverse specifically made for the DS18B20 temperature sensor – if you have access to a 3D printer this may be the easiest method!

Step 10 – Moving Out

Now that the weather station is ready to live in the elements, it is time to think about moving this project outside. Weather Underground has excellent information on placing your weather station – we suggest having a read through it as there are a lot of things to consider.


Depending on your location, some of these recommendations may not be reasonable. Also, when locating the station, consider that you will have to get power to your Pi and it will need a reliable WiFi connection.

Step 11 – Mounting The Station


Now that you have found a suitable location to mount your weather station, it is time to figure out how to mount it. Our station is going to live on top of a 4×4 fence post, so we quickly threw together this mounting bracket to hold the sensor mast and the box. We have made the files available for download / modification. Our bracket is designed for a slightly larger diameter mast than the one that ships with the Weather Meters – so we have included the Sketchup File to modify it as well.

Step 12 – Outdoor Power

For our installation power is being provided by an existing 12V power bus, so we will also be adding one of our RTC Power HATs under the weather board. Your solution for powering may vary, but we tend to recommend supplying 12VDC from a power supply in a safe, dry location, and running a 12V line out to the Pi. Why 12V? Well, power adapters are incredibly common, you don’t need to worry about voltage drop, and it is useful for other outdoor projects! Just keep in mind: Once the 12V line gets to the enclosure, it will need to be regulated to 5VDC for the Pi.

If you decide to go with the 12VDC option, a simple Pololu 5V 2.5A Step Down Regulator can be run into one of the extra 5V and Ground pins on the Weather HAT or you can always go with our Raspberry Pi RTC Power HAT if you would like it to fit cleanly to the Pi’s stacking header.

Step 13 – Remote Management

Step 13

One last consideration: If you are working on this project using a Keyboard, Mouse, and monitor it is going to be very difficult to make changes to your Pi once it is living outside. We will want to leverage the remote management capabilities of the Pi! Click the Raspberry Pi logo up in the corner, and open Preferences, and click Raspberry Pi Configuration. Under the tab “Interfaces” you will want to enable VNC (and SSH if you plan to use it as well)

For most users VNC will be more than adequate – this allows you to work on your Raspberry Pi as if you had a keyboard, monitor, and mouse directly plugged in. If you want to look into this more, be sure to check out the VNC Tutorial by the Raspberry Pi Foundation.

Step 14 – Final Setup

Now that everything is running it is time to move it outside! Power it up, double check it is sending out data – you should now have a fully operational weather station!

As of Sept 4th, the station is permanently installed outdoors. Live data can be seen at https://bc-robotics.com/weather.htm

Looking to add more? There are many areas this project can be expanded upon – we suggest looking at Air Quality (particulate and smoke), VOC monitoring, UV rating, Light Level, a Camera, and Ground Temperature – all useful and interesting things to monitor! If you have a question pertaining to this tutorial, or if you would like to share your completed weather station, please feel free to post below!

Have A Question?
If you have any questions, or need further clarification please post in the comments section below; this way future users of this tutorial can see the questions and answers!

Parts Used In This Tutorial:


  1. stefan
    • George
    • Raymond DuDevoir
  2. Gareth
  3. Chuck Harding
      • Chuck Harding
      • Chuck Harding
  4. Ronald Wayman
      • Ronald Wayman
  5. lucas
  6. Jason
      • Jason
  7. Yash Mehta
  8. Kynan
    • William @ BC Robotics

Leave a Reply