In the past two Raspberry Pi Weather Station Tutorials we have build the hardware to monitor several weather parameters and written the code to collect the information. In the third part of our four part tutorial we are going to figure out how to log our weather station’s data and display it on live updating graphs using a free web-based data service called ThingSpeak. ThingSpeak stores any data you send it and logs the time it receives it. Their service also allows you to create visualizations and data analysis – a very powerful tool! We are just going to touch on a few of the capabilities, so don’t be afraid to play around with ThingSpeak!
Overview:
Before we get started, you should have completed the previous two sections of this tutorial. Going forwards there are a few different things we need to do to get our data over to ThingSpeak. As always, we will break it down into a bunch of easier steps. We will start by creating an account with ThingSpeak, next we will gather the account information required to send data to ThingSpeak, we will then modify the code we wrote in the last part of the tutorial to send the data, test the connection and ensure the sent data is being received by ThingSpeak, and finally, take a quick look at the graph configuration and other features available.
This tutorial requires several items:
Before we modify any of our code, or send anything anywhere, we need to go and create a free account at ThingSpeak. Jump on over to their site and generate an account.
Once your account is verified, log in.
Now that we have an account set up we need to create a new channel to host and display our data. A ThingSpeak channel can have up to 8 different parameters sent to it. Since we only have 6 data parameters we are sending out, we will only need one channel for this project. Go ahead and click the “New Channel” button.
We are going to fill out each of the fields as shown. It is important that each field is the correct parameter – so field 1 needs to be temperature, field 2 needs to be humidity, etc. Aside from that: feel free to give your channel and appropriate name and fill out whatever information you want to share about your project. Once you are done, click Save at the bottom and your channel will be created.
The API key is a unique key – this is used to identify data being sent to ThingSpeak as yours – it can be thought of as a unique, somewhat secure address. Don’t share this key – bored people could use this to send false data to your channel. Copy this key down; we are going to need it in the next steps as we write the Python code to send our data to ThinkSpeak.
Changing gears, we are now going to start modifying the code we wrote on the Raspberry Pi in the last tutorial. 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:
idle3
Open your project file using the “file” menu.
Our program already reads the sensors and collects the data, but to get this to ThingSpeak we will need to do a little bit more coding. ThinkSpeak accepts data in a few different ways – the easiest of which is a simple HTTP POST. This is basically a web address with your data tagged on the end that we will send every time we want to update the channel with new data (so every 15 seconds). Assembling the HTTP POST in Python is quite easy. We will just have to include one more libraries and add a bit more code to take care of it. We will also disable our print function we used to display our data at the end of our original code as we don’t need it anymore.
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 requests
key = "1GAFNXQBV532Q097" #Insert your ThingSpeak Key here
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
GPIO.setmode(GPIO.BCM)
#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:
time.sleep(interval)
#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
## Comment this section out, no longer needed
#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( " ")
#Configure Parameters to Send
params = {'field1':temperature,'field2':humidity,'field3':pressure,'field4':windSpeed,'field5': windDeg,'field6':rainFall}
#Configure header
headerSt = {'Content-Type': 'application/json'}
#Send Data
conn = requests.post('http://api.thingspeak.com/update?api_key=' + key, json = params, headers = headerSt )
print(conn) #Print the result
conn.close()
Let’s try it out – press “F5” and it should prompt you to save it. After saving it should run, and in the Python Shell window you should see it print “200 OK” – this means data has been successfully sent to ThingSpeak. It will continue to post data every 15 seconds.
If you see “connection failed”: double check you have input your API key correctly and check your internet connection is up on the Raspberry Pi!
Each of the graphs can be configured by clicking the “pencil” logo in the top right corner of the graph. Add the title, X & Y axis labels, change the colors as you see fit. We also recommend setting the minimum value to zero on the wind speed and rainfall graphs to improve the auto formatting of the graph.
There are quite a few other options available as well – you can graph over much longer periods of time, thin the data reporting on the graph out, and even change the type of graph.
To host graphs (and other visualizations) on external sites, ThingSpeak provides code that can be pasted into the HTML of your website. The code can be found by clicking the “chat bubble” logo in the top right of any graph or display widget. You can even create a basic HTML file containing all of these code snippets and host it on your own computer (or the Raspberry Pi itself) to create a basic weather dashboard!
We are barely scratching the surface of what is possible with ThingSpeak – there are a lot of opportunities to improve how data is displayed and analyzed. You can even go ahead and generate additional information from your data like windchill, humidity, high/low temperature maximums, and others within the MATLAB Analysis tools. The Gauge Widget allows you to create dynamic gauges that display your data. Be sure to have a look through the tutorials on the ThingSpeak website to see all of the possibilities!
We are getting close to the end of this four part tutorial; in the final part we will look at getting the weather station outside running 24/7. There is a lot to consider when placing sensors outdoors. We will also look at keeping your hardware safe, power and internet connectivity, locating the station to get the best readings, things you can do to improve the accuracy of your sensors, and how to get your weather program to run whenever the Pi boots up. Ready to take on the last step? Jump over to Part 4 now!
8 thoughts on “Raspberry Pi Weather Station – Part 3”
mike87
mmmk have to ask.. how’d you get those wicked gauges in the last pic?
Chris @ BCR
Good question Mike – there are two types of gauge you can create – the ones i have used are the “old” style Google Gauge. The other option is the MATLAB visualization gauge. The MATLAB are very easy to setup and can be found with the big green MATLAB Visualization button.
The Google Gauges require HTML / CSS / Javascript to configure them so it is a bit involved. To find them: On the top blue bar on the ThingSpeak website, click on the “Apps” tab and then “Plugins”
When the next page loads, click the “New” button and select “Google Gauge” – the next page will have the code preloaded for a basic gauge. You will have to add your API Key, pull the value and play around with the configuration.
Hopefully that helps!
Adrian
Great project. Is there an alternative method to send the data to a MYSQL database and then use weewx to display it?
Dave
Great project ! thanks ! I am new to IOT and python.
In the “Current weather conditions” section above, how do you put metric name in the Gauge ?
regards
izzi
Great project! Is there anyway to convert the data for streaming to audio/midi within the code? A bit new to python so any help is appreciated 🙂
Scott
I’m not getting hte “200 OK” message and nothing is showing up in the ThingSpeak website. There is data showing in the terminal every “X” seconds.
There are no error messages showing to advise there is a problem uploading to ThingSpeak.
Chris @ BCR
Is the interval set to at least 15 seconds?
Fabio
Great! Now I’d like to have the value of wind gust. Is it possible to have necessary code for this option?