Tuesday, July 16, 2013

Raspberry PI: Charting Ambient vs Outside Temperature

How to use a Raspberry PI to chart ambient temperature vs outside temperature.  Source code and schematics below.

What you need:
What you get:

Reading the graph above is pretty obvious.  It plots the temperature of the DS18B20 sensor connected to the Raspberry PI vs. the outside temperature that is provided by a local weather forecast feed.  Just for fun, we also display Min and Max temperatures (which can be reset).
The graphing is provided by sen.se.  The sen.se site offers a lot of flexibility with "the internet of things".  sen.se is free.  Sign up and scan the tutorials.  The site is well laid out and the tutorials are very straight forward; you'll be an expert in no time.  Basically, you want to create a "channel" for your Raspberry PI by 'adding a device'.  sen.se will give you a 5 digit channel number for your RasPI and a very long passphrase that will be your personal identifier.  You will need both of these for the source code below.
Next, let's connect the DS18B20 to the Raspberry PI.  The DS18B20 transmits its temperature reading via I2C bus.  Just follow the tutorial at Adafruit.  The connection is simple and looks like this:
Load the Python script below into your Raspberry Pi and run it.  Be certain you enter your personal passphrase identifier and the device channel code that you got earlier from sen.se.  After you run the Python script head back over to sen.se.  You should see that sen.se has detected a 'heartbeat' from your Raspberry PI.  After that, it is just a matter of configuring one of the graphing apps on sen.se.  You can make your sen.se data public or private and there are many many tools to manipulate and display your data.
Good luck!  Python script for the RasPI follows:

# WhiskeyTangoHotel.Com
# June 2013
# Program reads DS18B20 temp sensor and plots value to sen.se
# DS18B20 connections via AdaFruit tutorial
# With thanks to @Rob_Bishop

# This program is feed customized for RasPI(2)

import httplib
import json as simplejson
from random import randint
import time
import os
import glob

# Pass os commands to set up I2C bus 
os.system('modprobe w1-gpio')  
os.system('modprobe w1-therm')

base_dir = '/sys/bus/w1/devices/'
device_folder = glob.glob(base_dir + '28*')[0]
device_file = device_folder + '/w1_slave'

run_number = 0

SENSE_API_KEY = "long sen.se passphase here. note that it is in quotes"
FEED_ID1 = 12345  # five digit sen.se channel code.  note it is NOT in quotes

def read_temp_raw():  #read the DS18B20 function
    f = open(device_file, 'r')
    lines = f.readlines()
    return lines

def read_temp(): #process the raw temp file output and convert to F
    lines = read_temp_raw()
    while lines[0].strip()[-3:] != 'YES':
        lines = read_temp_raw()
    equals_pos = lines[1].find('t=')
    if equals_pos != -1:
        temp_string = lines[1][equals_pos+2:]
        ambC = float(temp_string) / 1000.0
        ambF = ambC * 9.0 / 5.0 + 32.0
        return ambF

def send_to_opensense(data):
#    print  >> fout, "\t=> Sending to OpenSense: %s" % data
# prepare data 
datalist = [{"feed_id" : FEED_ID1, "value" :data['F']},]
headers = {"sense_key": SENSE_API_KEY,"content-type": "application/json"}
conn = httplib.HTTPConnection("api.sen.se")
# format a POST request with JSON content
conn.request("POST", "/events/", simplejson.dumps(datalist), headers)
response = conn.getresponse()
# you may get interesting information here in case it fails
#   print >> fout, response.status, response.reason
#   print >> fout, response.read()

run_number = run_number + 1
ambF = read_temp()
print "RasPI(2) Ambient Run:", run_number, "    ambF:",ambF
data = { 'F' : ambF}