Graphing sensor data from a Raspberry Pi

I’m interested in the Internet of Things and thought that the Raspberry Pi would be a good way to explore it. So as a getting starter project I attached a temperature and Humidity sensor to my RPi and set about exploring. The sensor I used is the Bosch BMP180 digital barometer and temperature sensor. This is the successor of the BMP085 and uses I2C to communicate with the host.  BMP180 Datasheet

I purchased it on a small board suitable for breadboarding.

BMP180

To communicate with the BMP180 I used ADAFruit’s BMP085 libraries. They have a fantastic tutorial on how to use it and how to connect the device. AdaFruit BMP085 info

I also found some great data on this device  posted by on his blog at http://blog.bitify.co.uk/

Here is the overall setup. In the picture you can see the RPi is feeding its I2C bus to a breadboard. I am using an external power unit (9V brick feeding regulators with 5V and 3.3V outputs).  In general I am using Arduino sesnor modules setup for 5V whereas the RPi uses 3.3V, so there is a bidirectional level shifter converting between the two voltage rails that you can see to the right by the power supply. On the left is the BMP180 temperature and barometer device… in the center is a real time clock (not being used here) and just off the picture a DHT22 one wire humidity and temperature sensor that will be used in future projects.

BMP180+RPi

Once the sensor was running the next task was to plot the results. At first I used GNUplot on the RPi but that was not a long term solution. After a bit of research I came upon thingspeak, an internet of things platform run by The Mathworks. This seemed ideal as it allows you to set up channels that you can write to as webpages, and it plots them in real time and makes them accessible on the internet. This seemed much easier than setting up a local web server. There are a couple of limitations that seem minor, basically each channel supports up to 8 fields and you can only send data every 15 seconds.

Now the task was to get the information sent to the thingspeak site. I played a bit with the native python libraries (UrlLib) for doing this but they make pretty unreadable code that is hard to debug. Then I stumbled on this fantastic library that made things readable.

http://docs.python-requests.org/en/latest/  by Kenneth Reitz who with his colleagues have done a great job of making this task simpler. With ‘requests’ sending the data to thingspeak became much easier to debug.

Here is the code that I put together. It uses the Adafruit BMP library coupled to “requests” to send to thingspeak.


#!/usr/bin/python
# Original Author : Tony DiCola of Adafruit
# With additions by hobbyistdave  www.hobbyspot.org
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

# Can enable debug output by uncommenting:
#import logging
#logging.basicConfig(level=logging.DEBUG)

import Adafruit_BMP.BMP085 as BMP085
import smbus
import time
import requests  # HTTP for humans by Kenneth Reitz  docs.python-requests.org

# Default constructor will pick a default I2C bus.
#
sensor = BMP085.BMP085()

# You can also optionally change the BMP085 mode to one of BMP085_ULTRALOWPOWER,
# BMP085_STANDARD, BMP085_HIGHRES, or BMP085_ULTRAHIGHRES.  See the BMP085
# datasheet for more details on the meanings of each mode (accuracy and power
# consumption are primarily the differences).  The default mode is STANDARD.

#
sensor = BMP085.BMP085(mode=BMP085.BMP085_ULTRAHIGHRES)

# setup the info needed to send the results to thingspeak

thingspeakurl = "https://api.thingspeak.com/update"   # url for sending updates to thingspeak
apikey = "1234567890123456"     # add your own thingspeak api address for your channel
TempField = "field1"            # temperature field
PressField = "field2"           # pressure field

temperature = sensor.read_temperature()  # Note: fixed an error in the Adafruit module where it incorrectly divides by 10
pressure = sensor.read_pressure()

print " "
print "---------------------------------------------------------"
print "Time          ", time.ctime()
print "Epoch Seconds ", time.time()
print "Temperature   ", temperature
print "Pressure      ", pressure/ 100.
print " "
print "---------------------------------------------------------"
print " "
print "Time            Point  Temp    Pressure        Status    "
print "---------------------------------------------------------"
print " "

while True:

temperature = sensor.read_temperature()
pressure = sensor.read_pressure()

time.sleep(1)

url = thingspeakurl   # the thingsspeak url
payload = {'key' : apikey, 'field1' : temperature , 'field2' : pressure/ 100. }  # set up  the payload

try :
r = requests.get(url, params=payload)   # send the data to thingspeak
print time.time(), "  ", r.text, "   ", temperature ,"   ", pressure / 100.,"      ", r.status_code # print locally
except requests.exceptions as e :
print e # some simple error trapping to avoid the program timing out
except requests.exceptions.ConnectionError as e1 :
print e1 # some simple error trapping if the connection is lost

time.sleep(15) # thingspeak is set to ignore requests that come faster than every 15 seconds

# end of code

Locally on the RPi you get a print out of the temperature and pressure, timestamp, data point number and return code from the server… In the code you can see the apikey (put your own one in there).  The thingspeak website has great instructions for setting their end up.

The key code block shows the elegance of the  “requests” api for handling the http:


url = thingspeakurl   # the thingsspeak url
payload = {'key' : apikey, 'field1' : temperature , 'field2' : pressure/ 100. }  # set up  the payload
r = requests.get(url, params=payload)   # send the data to thingspeak

And published to the cloud you get:

temppandpressure

Which is what I was aiming to achieve.