#!/usr/bin/python # This script is a continuation of my series of temperature measurements # usinjg the Dallas DS18B20 One-wire temperature sensor. # See my blog for previous versions. # # This version adds graphing the results using RRDtool and PyRRD # # MJL -- www.thepiandi.blogspot.com -- 10/3/2013 import os from datetime import datetime import time import subprocess import sys from Tkinter import Tk from tkFileDialog import asksaveasfilename from LCD_2X16 import * from pyrrd.rrd import DataSource, RRA, RRD from pyrrd.graph import DEF, CDEF, VDEF, LINE, AREA, GPRINT, COMMENT from pyrrd.graph import ColorAttributes from pyrrd.graph import Graph def loadmodules(): """ Checks to see if the 1-wire modules are loaded. If not, loades them.""" err = 'error' while err != '': modloaded = subprocess.Popen(['lsmod'], stdout = subprocess.PIPE, stderr = subprocess.PIPE) out, err = modloaded.communicate() if 'w1_therm' not in out or 'w1_gpio' not in out: print '1-Wire modules had to be loaded. Waiting 10 seconds' print os.system('sudo modprobe w1-gpio') os.system('sudo modprobe w1-therm') time.sleep(10) def read_temp_raw(): """ Uses Popen to open then read contents of w-slave. Returns the contents of the file as a two line list. If the file cannot be read the 1-wire modules are unloaded and loaded again. This is repeated three times until the file is read successfully. After three times, the program is stopped.""" global glitches trials = 3 catdata = subprocess.Popen(['cat', device_file], stdout = subprocess.PIPE, stderr = subprocess.PIPE) out, err = catdata.communicate() while err != "" and trials: print "Got a glitch - trying to recover" trials -= 1 time.sleep(1) os.system('sudo modprobe -r w1-gpio') os.system('sudo modprobe -r w1-therm') time.sleep(1) os.system('sudo modprobe w1-gpio') os.system('sudo modprobe w1-therm') time.sleep(10) glitches += 1 catdata = subprocess.Popen(['cat', device_file], stdout = subprocess.PIPE, stderr = subprocess.PIPE) out, err = catdata.communicate() if trials: out_decode = out.decode('utf-8') lines = out_decode.split('\n') return lines else: raise(IOError) def print2display(temperature, sen): """ Prints the temperature and time to the 16 character by two line LCD display. Also prints to the stdio""" time.sleep(.01) if sen == '0': lcd_byte(LCD_LINE_1, LCD_CMD) # Print to top line string1 = "Brdbd: " + str(temperature) + " degF" time.sleep(.01) lcd_string(string1) if sen =='1': lcd_byte(LCD_LINE_2, LCD_CMD) # Print to bottom line string1 = "Cable: " + str(temperature) + " degF" time.sleep(.01) lcd_string(string1) def check_switch(): """Checks to see if the breadboard switch was pressed. If so it generates a keyboard interrupt as if CTRL-C was pressed. Switch must be held down for at least .2 seconds to be reconized""" input_switch = GPIO.input(SwitchInput) # Look for breadboard switch if not input_switch: time.sleep(.2) input_switch = GPIO.input(SwitchInput) # Look for breadboard switch again if not input_switch: # Must still be pressed print print "Switch Pressed" raise(KeyboardInterrupt) def check_title(title): """Makes sure that all of the space characters are escaped with the backspace character""" cnt_spaces = title.count(' ') title_good = True start_pos = 0 while cnt_spaces: index_space = title.find(' ', start_pos) if title[index_space -1] != '\\': title_good = False start_pos = index_space + 1 cnt_spaces -= 1 return title_good # -------------------------------------------------------------------------------------------------- # Main Program glitches = 0 device_id = ('28-00000400d39d' ,'28-000004986cbb') prompt = 'Enter the measurement time interval in minutes (integer values only): ' prompt1 = 'Enter 0 for sensor on breadboard, 1 for cable sensor, 2 for both: ' prompt2 = 'Enter the maximum number of measurements: ' prompt3 = 'What are we measuring with the breadboard sensor? Default is Breadboard: ' prompt4 = 'What are we measuring with the cable sensor? Default is Cable: ' prompt5 = 'Enter comment if desired (Remember to escape punctuation): ' prompt6 = 'Enter a name for the file. No spaces, extension, or directory: ' prompt7 = 'Enter a title for the graph (Remember to escape spaces and punctuation): ' prompt8 = 'Satisfied with the inputs? Y or N: ' prompt9 = 'OK to proceed? If not, we quit. Y or N: ' prompt10 = 'Graph background color: Enter 0 for black, 1 for white, 2 for both: ' prompt11 = 'Choose height of graph in the range if 100 to 400 pixels: ' short_wait = .1 lcd_byte(0x01, LCD_CMD) # Clear Display loadmodules() # Check to see if 1-Wire modules are loaded. # Operator Inputs good_inputs = False while not good_inputs: # Choose which sensor or both print sensor = '' while sensor != '0' and sensor != '1' and sensor !='2': sensor = raw_input(prompt1) print if sensor == '0': print "You have choosen the breadboard sensor" elif sensor == '1': print "You have choosen the cable sensor" elif sensor == '2': print "You have choosen both sensors" # Legend Titles print if sensor == '0' or sensor == '2': measure_what0 = raw_input(prompt3) if measure_what0 == '': measure_what0 = 'Breadboard' if sensor == '1' or sensor == '2': measure_what1 = raw_input(prompt4) if measure_what1 == '': measure_what1 = 'Cable' # Graph Title print title_good = False while not title_good: title_it = '' while not title_it: title_it = raw_input(prompt7) title_good = check_title(title_it) if not title_good: print "\n\tYou forgot to escape all of the space characters, try again: " # Comment print comment = raw_input(prompt5) cmt = COMMENT(comment) # Graph Colors print background = '' while background != '0' and background != '1' and background !='2': background = raw_input(prompt10) # Height of Graph print how_high = 0 while how_high < 100 or how_high > 400: try: how_high = abs(int(raw_input(prompt11))) except: pass # File names print directory = '/home/pi/Documents/PythonProjects/TempProbe/TempResults/' filename = raw_input(prompt6) graphfile_blk = directory + filename + '_black.png' graphfile_wht = directory + filename + '_white.png' if sensor == '0' or sensor == '2': rrdfile0 = directory + filename + '_bread.rrd' if sensor == '1' or sensor == '2': rrdfile1 = directory + filename + '_cable.rrd' # Maximum number of measurements print max_measurements = 0 while not max_measurements: try: max_measurements = abs(int(raw_input(prompt2))) except: pass # Measurement Interval print measurement_interval = 0 while not measurement_interval: try: measurement_interval = abs(int(raw_input(prompt))) except: pass # Satisfied With The Inputs? print response = "" while response != 'y' and response != 'Y' and response != 'n' and response != 'N': response = raw_input(prompt8) if response == 'Y' or response == 'y': good_inputs = True # Good to Proceed? print proceed = '' while proceed != 'y' and proceed != 'Y' and proceed != 'n' and proceed != 'N': proceed = raw_input(prompt9) print measurement_interval *= 60 start_time = int(time.time() / measurement_interval) * measurement_interval next_meas_time= start_time + measurement_interval # Breadboard RRD Setup if sensor == '0' or sensor == '2': dataSources = [] roundRobinArchives = [] dataSource = DataSource(dsName='Breadboard', dsType='GAUGE', heartbeat=int(1.5 * measurement_interval)) dataSources.append(dataSource) roundRobinArchives.append(RRA(cf='LAST', xff=0.5, steps=1, rows=max_measurements)) breadboard = RRD(rrdfile0, step=measurement_interval, ds=dataSources, rra=roundRobinArchives, start=start_time) breadboard.create(debug=False) # Cable RRD Setup if sensor == '1' or sensor == '2': dataSources = [] roundRobinArchives = [] dataSource = DataSource(dsName='Cable', dsType='GAUGE', heartbeat=int(1.5 * measurement_interval)) dataSources.append(dataSource) roundRobinArchives.append(RRA(cf='LAST', xff=0.5, steps=1, rows=max_measurements)) cable = RRD(rrdfile1, step=measurement_interval, ds=dataSources, rra=roundRobinArchives, start=start_time) cable.create(debug=False) # Breadboard Graph Setup if sensor == '0' or sensor == '2': bread_def = DEF(rrdfile=rrdfile0, vname='Bread_data', dsName='Breadboard', cdef='LAST') bread_line = LINE(defObj=bread_def, color='#00FF00', legend=measure_what0 + ' Temperature') bread_aver = VDEF(vname='Bread_aver', rpn='%s,AVERAGE' % bread_def.vname) bread_val = GPRINT(bread_aver, 'Average ' + measure_what0 + ' Temperature: %6.2lf Degrees F') # Cable Graph Setup if sensor == '1' or sensor == '2': cable_def = DEF(rrdfile=rrdfile1, vname='Cable_data', dsName='Cable', cdef='LAST') cable_line = LINE(defObj=cable_def, color='#FF0000', legend=measure_what1 + ' Temperature') cable_aver = VDEF(vname='Cable_aver', rpn='%s,AVERAGE' % cable_def.vname) cable_val = GPRINT(cable_aver, 'Average ' + measure_what1 + ' Temperature: %6.2lf Degrees F') # Define Graph Colors # black background: black_bkgnd = ColorAttributes() black_bkgnd.back = '#000000' black_bkgnd.canvas = '#333333' black_bkgnd.shadea = '#000000' black_bkgnd.shadeb = '#111111' black_bkgnd.mgrid = '#CCCCCC' black_bkgnd.axis = '#FFFFFF' black_bkgnd.frame = '#0000AA' black_bkgnd.font = '#FFFFFF' black_bkgnd.arrow = '#FFFFFF' # white background: white_bkgnd = ColorAttributes() white_bkgnd.back = '#FFFFFF' white_bkgnd.canvas = '#EEEEEE' white_bkgnd.shadea = '#000000' white_bkgnd.shadeb = '#111111' white_bkgnd.mgrid = '#444444' white_bkgnd.axis = '#000000' white_bkgnd.frame = '#0000AA' white_bkgnd.font = '#000000' white_bkgnd.arrow = '#000000' # Let's make some measurements and graph them try: if proceed == 'N' or proceed == 'n': raise(KeyboardInterrupt) print 'First Measurement Will Be Made At: ' + time.asctime(time.localtime(next_meas_time)) print while max_measurements: time_now = time.time() while time_now < next_meas_time: check_switch() time.sleep(0.5) time_now = time.time() if sensor == '0' or sensor == '2': device_file = '/sys/bus/w1/devices/' + device_id[0] + '/w1_slave' measurement_good = False while measurement_good == False: lines = read_temp_raw() if 'YES' in lines[0]: equals_pos = lines[1].find('t=') if equals_pos != -1: measurement_good = True temp_string = lines[1][equals_pos +2:] Deg_C = float(temp_string)/1000.0 Deg_F = round(Deg_C * 1.8 + 32.0, 1) timenow = datetime.now() print timenow.strftime("%A, %B %d, %I:%M:%S %p") + (", the Breadboard sensor temperature is %3.1f") %(Deg_F) + u"\xB0" +"F" print2display(Deg_F, '0') if measurement_good == False: time.sleep(short_wait) breadboard.bufferValue(next_meas_time, str(Deg_F)) breadboard.update(debug = False) if sensor == '1' or sensor == '2': device_file = '/sys/bus/w1/devices/' + device_id[1] + '/w1_slave' measurement_good = False while measurement_good == False: lines = read_temp_raw() if 'YES' in lines[0]: equals_pos = lines[1].find('t=') if equals_pos != -1: measurement_good = True temp_string = lines[1][equals_pos +2:] Deg_C = float(temp_string)/1000.0 Deg_F = round(Deg_C * 1.8 + 32.0, 1) timenow = datetime.now() print timenow.strftime("%A, %B %d, %I:%M:%S %p") + (", the Cable sensor temperature is %3.1f") %(Deg_F) + u"\xB0" +"F" print2display(Deg_F, '1') if measurement_good == False: time.sleep(short_wait) cable.bufferValue(next_meas_time, str(Deg_F)) cable.update(debug = False) next_meas_time += measurement_interval max_measurements -= 1 gb = Graph(graphfile_blk, start = start_time, end = next_meas_time - measurement_interval, color = black_bkgnd, vertical_label='Degrees\ F', width=600, height=how_high, title=title_it) gw = Graph(graphfile_wht, start = start_time, end = next_meas_time - measurement_interval, color = white_bkgnd, vertical_label='Degrees\ F', width=600, height=how_high, title=title_it) if sensor == '0': gb.data.extend([bread_def, bread_line, bread_aver, bread_val]) gw.data.extend([bread_def, bread_line, bread_aver, bread_val]) if sensor == '1': gb.data.extend([cable_def, cable_line, cable_aver, cable_val]) gw.data.extend([cable_def, cable_line, cable_aver, cable_val]) if sensor == '2': gb.data.extend([bread_def, bread_line, bread_aver]) gb.data.extend([cable_def, cable_line, cable_aver]) gb.data.extend([bread_val, cable_val]) gw.data.extend([bread_def, bread_line, bread_aver]) gw.data.extend([cable_def, cable_line, cable_aver]) gw.data.extend([bread_val, cable_val]) if comment: gb.data.extend([cmt]) gw.data.extend([cmt]) if background == '0' or background == '2': gb.write() if background == '1' or background == '2': gw.write() except(KeyboardInterrupt): print except(IOError): print print 'Three tries and we are out of here' except: print print "Unexpected Error: ", sys.exc_info()[1] print print "See you later, Glitches = %d" % glitches lcd_byte(0x01, LCD_CMD) # Clear Display GPIO.cleanup() print print "start time: ", start_time print "last measurement: ", next_meas_time run_time = next_meas_time - start_time - measurement_interval run_days = run_time / 86400 run_hours = run_time % 86400 / 3600 run_minutes = run_time % 86400 % 3600 / 60 total_measurements = run_time / measurement_interval print print 'Total Run Time: %2d days, %2d hours, %2d minutes' %(run_days, run_hours, run_minutes) print 'Total Number of Measurements Per Device: ' + str(total_measurements) print