├── README ├── monitor.py ├── templog.db └── webgui.py /README: -------------------------------------------------------------------------------- 1 | Raspberry Pi Temperature Logger 2 | =============================== 3 | 4 | This repo contains code for a Raspberry Pi temperature logger which uses SQLite to store data read from a DS18B20 sensor. You can see more details here: 5 | http://raspberrywebserver.com/cgiscripting/rpi-temperature-logger/building-an-sqlite-temperature-logger.html 6 | 7 | In webgui.py, there are several lines that contain hardcoded dates so that you can use the script with the sample database provided. There is an equivalent version of each of these lines that uses 'now' instead of a hardcoded timestamp. If you want to view data you've collected yourself, you should uncomment the lines that use 'now', and comment out the lines that have a hardocded date. See webgui.py, lines 45, 117, 122, 127 and 148. 8 | -------------------------------------------------------------------------------- /monitor.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import sqlite3 4 | 5 | import os 6 | import time 7 | import glob 8 | 9 | # global variables 10 | speriod=(15*60)-1 11 | dbname='/var/www/templog.db' 12 | 13 | 14 | 15 | # store the temperature in the database 16 | def log_temperature(temp): 17 | 18 | conn=sqlite3.connect(dbname) 19 | curs=conn.cursor() 20 | 21 | curs.execute("INSERT INTO temps values(datetime('now'), (?))", (temp,)) 22 | 23 | # commit the changes 24 | conn.commit() 25 | 26 | conn.close() 27 | 28 | 29 | # display the contents of the database 30 | def display_data(): 31 | 32 | conn=sqlite3.connect(dbname) 33 | curs=conn.cursor() 34 | 35 | for row in curs.execute("SELECT * FROM temps"): 36 | print str(row[0])+" "+str(row[1]) 37 | 38 | conn.close() 39 | 40 | 41 | 42 | # get temerature 43 | # returns None on error, or the temperature as a float 44 | def get_temp(devicefile): 45 | 46 | try: 47 | fileobj = open(devicefile,'r') 48 | lines = fileobj.readlines() 49 | fileobj.close() 50 | except: 51 | return None 52 | 53 | # get the status from the end of line 1 54 | status = lines[0][-4:-1] 55 | 56 | # is the status is ok, get the temperature from line 2 57 | if status=="YES": 58 | print status 59 | tempstr= lines[1][-6:-1] 60 | tempvalue=float(tempstr)/1000 61 | print tempvalue 62 | return tempvalue 63 | else: 64 | print "There was an error." 65 | return None 66 | 67 | 68 | 69 | # main function 70 | # This is where the program starts 71 | def main(): 72 | 73 | # enable kernel modules 74 | os.system('sudo modprobe w1-gpio') 75 | os.system('sudo modprobe w1-therm') 76 | 77 | # search for a device file that starts with 28 78 | devicelist = glob.glob('/sys/bus/w1/devices/28*') 79 | if devicelist=='': 80 | return None 81 | else: 82 | # append /w1slave to the device file 83 | w1devicefile = devicelist[0] + '/w1_slave' 84 | 85 | 86 | # while True: 87 | 88 | # get the temperature from the device file 89 | temperature = get_temp(w1devicefile) 90 | if temperature != None: 91 | print "temperature="+str(temperature) 92 | else: 93 | # Sometimes reads fail on the first attempt 94 | # so we need to retry 95 | temperature = get_temp(w1devicefile) 96 | print "temperature="+str(temperature) 97 | 98 | # Store the temperature in the database 99 | log_temperature(temperature) 100 | 101 | # display the contents of the database 102 | # display_data() 103 | 104 | # time.sleep(speriod) 105 | 106 | 107 | if __name__=="__main__": 108 | main() 109 | 110 | 111 | 112 | 113 | -------------------------------------------------------------------------------- /templog.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pyplate/rpi_temp_logger/8e87abbff03f2c33821ca9e81c73c717261c6744/templog.db -------------------------------------------------------------------------------- /webgui.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import sqlite3 4 | import sys 5 | import cgi 6 | import cgitb 7 | 8 | 9 | # global variables 10 | speriod=(15*60)-1 11 | dbname='/var/www/templog.db' 12 | 13 | 14 | 15 | # print the HTTP header 16 | def printHTTPheader(): 17 | print "Content-type: text/html\n\n" 18 | 19 | 20 | 21 | # print the HTML head section 22 | # arguments are the page title and the table for the chart 23 | def printHTMLHead(title, table): 24 | print "" 25 | print " " 26 | print title 27 | print " " 28 | 29 | print_graph_script(table) 30 | 31 | print "" 32 | 33 | 34 | # get data from the database 35 | # if an interval is passed, 36 | # return a list of records from the database 37 | def get_data(interval): 38 | 39 | conn=sqlite3.connect(dbname) 40 | curs=conn.cursor() 41 | 42 | if interval == None: 43 | curs.execute("SELECT * FROM temps") 44 | else: 45 | # curs.execute("SELECT * FROM temps WHERE timestamp>datetime('now','-%s hours')" % interval) 46 | curs.execute("SELECT * FROM temps WHERE timestamp>datetime('2013-09-19 21:30:02','-%s hours') AND timestamp<=datetime('2013-09-19 21:31:02')" % interval) 47 | 48 | rows=curs.fetchall() 49 | 50 | conn.close() 51 | 52 | return rows 53 | 54 | 55 | # convert rows from database into a javascript table 56 | def create_table(rows): 57 | chart_table="" 58 | 59 | for row in rows[:-1]: 60 | rowstr="['{0}', {1}],\n".format(str(row[0]),str(row[1])) 61 | chart_table+=rowstr 62 | 63 | row=rows[-1] 64 | rowstr="['{0}', {1}]\n".format(str(row[0]),str(row[1])) 65 | chart_table+=rowstr 66 | 67 | return chart_table 68 | 69 | 70 | # print the javascript to generate the chart 71 | # pass the table generated from the database info 72 | def print_graph_script(table): 73 | 74 | # google chart snippet 75 | chart_code=""" 76 | 77 | """ 94 | 95 | print chart_code % (table) 96 | 97 | 98 | 99 | 100 | # print the div that contains the graph 101 | def show_graph(): 102 | print "

Temperature Chart

" 103 | print '
' 104 | 105 | 106 | 107 | # connect to the db and show some stats 108 | # argument option is the number of hours 109 | def show_stats(option): 110 | 111 | conn=sqlite3.connect(dbname) 112 | curs=conn.cursor() 113 | 114 | if option is None: 115 | option = str(24) 116 | 117 | # curs.execute("SELECT timestamp,max(temp) FROM temps WHERE timestamp>datetime('now','-%s hour') AND timestamp<=datetime('now')" % option) 118 | curs.execute("SELECT timestamp,max(temp) FROM temps WHERE timestamp>datetime('2013-09-19 21:30:02','-%s hour') AND timestamp<=datetime('2013-09-19 21:31:02')" % option) 119 | rowmax=curs.fetchone() 120 | rowstrmax="{0}   {1}C".format(str(rowmax[0]),str(rowmax[1])) 121 | 122 | # curs.execute("SELECT timestamp,min(temp) FROM temps WHERE timestamp>datetime('now','-%s hour') AND timestamp<=datetime('now')" % option) 123 | curs.execute("SELECT timestamp,min(temp) FROM temps WHERE timestamp>datetime('2013-09-19 21:30:02','-%s hour') AND timestamp<=datetime('2013-09-19 21:31:02')" % option) 124 | rowmin=curs.fetchone() 125 | rowstrmin="{0}   {1}C".format(str(rowmin[0]),str(rowmin[1])) 126 | 127 | # curs.execute("SELECT avg(temp) FROM temps WHERE timestamp>datetime('now','-%s hour') AND timestamp<=datetime('now')" % option) 128 | curs.execute("SELECT avg(temp) FROM temps WHERE timestamp>datetime('2013-09-19 21:30:02','-%s hour') AND timestamp<=datetime('2013-09-19 21:31:02')" % option) 129 | rowavg=curs.fetchone() 130 | 131 | 132 | print "
" 133 | 134 | 135 | print "

Minumum temperature 

" 136 | print rowstrmin 137 | print "

Maximum temperature

" 138 | print rowstrmax 139 | print "

Average temperature

" 140 | print "%.3f" % rowavg+"C" 141 | 142 | print "
" 143 | 144 | print "

In the last hour:

" 145 | print "" 146 | print "" 147 | 148 | # rows=curs.execute("SELECT * FROM temps WHERE timestamp>datetime('new','-1 hour') AND timestamp<=datetime('new')") 149 | rows=curs.execute("SELECT * FROM temps WHERE timestamp>datetime('2013-09-19 21:30:02','-1 hour') AND timestamp<=datetime('2013-09-19 21:31:02')") 150 | for row in rows: 151 | rowstr="".format(str(row[0]),str(row[1])) 152 | print rowstr 153 | print "
Date/TimeTemperature
{0}  {1}C
" 154 | 155 | print "
" 156 | 157 | conn.close() 158 | 159 | 160 | 161 | 162 | def print_time_selector(option): 163 | 164 | print """
165 | Show the temperature logs for 166 | 192 | 193 |
""" 194 | 195 | 196 | # check that the option is valid 197 | # and not an SQL injection 198 | def validate_input(option_str): 199 | # check that the option string represents a number 200 | if option_str.isalnum(): 201 | # check that the option is within a specific range 202 | if int(option_str) > 0 and int(option_str) <= 24: 203 | return option_str 204 | else: 205 | return None 206 | else: 207 | return None 208 | 209 | 210 | #return the option passed to the script 211 | def get_option(): 212 | form=cgi.FieldStorage() 213 | if "timeinterval" in form: 214 | option = form["timeinterval"].value 215 | return validate_input (option) 216 | else: 217 | return None 218 | 219 | 220 | 221 | 222 | # main function 223 | # This is where the program starts 224 | def main(): 225 | 226 | cgitb.enable() 227 | 228 | # get options that may have been passed to this script 229 | option=get_option() 230 | 231 | if option is None: 232 | option = str(24) 233 | 234 | # get data from the database 235 | records=get_data(option) 236 | 237 | # print the HTTP header 238 | printHTTPheader() 239 | 240 | if len(records) != 0: 241 | # convert the data into a table 242 | table=create_table(records) 243 | else: 244 | print "No data found" 245 | return 246 | 247 | # start printing the page 248 | print "" 249 | # print the head section including the table 250 | # used by the javascript for the chart 251 | printHTMLHead("Raspberry Pi Temperature Logger", table) 252 | 253 | # print the page body 254 | print "" 255 | print "

Raspberry Pi Temperature Logger

" 256 | print "
" 257 | print_time_selector(option) 258 | show_graph() 259 | show_stats(option) 260 | print "" 261 | print "" 262 | 263 | sys.stdout.flush() 264 | 265 | if __name__=="__main__": 266 | main() 267 | 268 | 269 | 270 | 271 | --------------------------------------------------------------------------------