Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- # Raspberry Pi temperature monitoring script
- # for Python 2
- # Andrew Pattison, 11/10/2012 - 16/2/2015
- import Adafruit_GPIO.I2C as I2C
- import Adafruit_CharLCD as LCD
- import sys
- import syslog
- import subprocess
- import httplib
- import json
- import time
- import signal
- import threading
- import sqlite3
- import os.path
- import datetime
- # log exceptions to stdout
- EXC_STDOUT = True
- # log exceptions to syslog
- EXC_SYSLOG = True
- # special value to indicate invalid temperature
- TEMP_INVALID = 9999
- # i2c address of temperature sensor
- I2C_ADDRESS = 0x48
- # name of hard disk to monitor temperature of
- HDD_NAME = "/dev/disk/by-label/expansion"
- # xively API keys
- XIVELY_KEY = "JR2G_KZu9bdYNC3nsT0TP0x4kPuSAKx5dUFTd0wvZm4vVT0g"
- # xively feed location
- XIVELY_FEED = "/v2/feeds/79499/"
- # xively feed host
- XIVELY_HOST = "api.xively.com"
- # absolute path to directory containing sqlite3 database
- DB_DIR = "/home/pi/temperature/"
- def signal_term_handler(signal, frame):
- # signal handler for SIGTERM
- print "exiting on SIGTERM"
- syslog.syslog("Exiting on SIGTERM")
- # send thread the stop signal
- thread1.stop()
- # wait until thread has stopped
- thread1.join()
- lcdExit()
- sys.exit(0)
- def logMsg(message):
- # log a message to stdout and/or syslog
- # message: the message string
- if EXC_STDOUT: print message
- if EXC_SYSLOG: syslog.syslog(message)
- def logException(name, str1, str2, str3):
- # log an exception
- # name: name of location where exception occurred
- # str1, str2, str3: strings with info about exception
- msgString = "Exception in " + name + ": " + str1 + ", " + str2 + ", " + str3
- logMsg(msgString)
- def turnLCDOff():
- lcd.clear()
- lcd.set_backlight(False)
- def turnLCDOn():
- lcd.clear()
- lcd.set_backlight(True)
- def lcdExit():
- # display an "exiting" message on the LCD for 2 seconds
- # then switch off the display
- lcd.clear()
- lcd.message("Exiting...")
- time.sleep(2)
- turnLCDOff()
- lcdOn = False
- def getCPUTemp():
- try:
- file = open("/sys/class/thermal/thermal_zone0/temp", "r")
- string = file.readline()
- file.close()
- cputemp = float(string)
- cputemp = cputemp / 1000
- # basic sanity check for CPU temperature
- if cputemp < 100:
- return cputemp
- else:
- return TEMP_INVALID
- except Exception:
- logException("getCPUTemp", str(sys.exc_info()[0]), str(sys.exc_info()[1]), str(sys.exc_info()[2]))
- return TEMP_INVALID
- def getHDDTemp(device):
- try:
- s = subprocess.check_output(["/sbin/hdparm","-H",device])
- string2 = str(s)
- # get 3rd line of output
- templine = string2.split('\n')[2]
- # get last 2 characters of line - the temperature
- hddtempstring = templine[-2:]
- # convert to integer
- return int(hddtempstring)
- except Exception:
- logException("getHDDTemp", str(sys.exc_info()[0]), str(sys.exc_info()[1]), str(sys.exc_info()[2]))
- return TEMP_INVALID
- def getI2CTemp(device):
- try:
- rawvalue = device.readS16(0x00, False)
- rawvalue = int(rawvalue * 0.0625)
- rawvaluestring = "{0:b}".format(rawvalue)
- if rawvalue >= 2048:
- # temperature is negative
- tempstring = ""
- # calculate 2s compliment of rawvalue
- # We do it manually since Python's compliment
- # function doesn't do what I expect it to.
- for i in range(len(rawvaluestring)):
- if rawvaluestring[i] == "1":
- tempstring = tempstring + "0"
- else:
- if rawvaluestring[i] == "0":
- tempstring = tempstring + "1"
- negvalue = int(tempstring,2)
- negvalue = negvalue + 1
- negativevalue = negvalue * -0.0625
- return negativevalue
- else:
- # temperature is positive
- positivevalue = rawvalue * 0.0625
- return positivevalue
- except Exception:
- logException("getI2CTemp", str(sys.exc_info()[0]), str(sys.exc_info()[1]), str(sys.exc_info()[2]))
- return TEMP_INVALID
- def sendToXively(data, apiKey, feed):
- try:
- connection = httplib.HTTPConnection(XIVELY_HOST)
- datastring = json.dumps(data)
- header = { "X-ApiKey":apiKey }
- connection.request("PUT", feed, datastring, header)
- return connection.getresponse()
- except Exception:
- logException("sendToXively", str(sys.exc_info()[0]), str(sys.exc_info()[1]), str(sys.exc_info()[2]))
- return 0
- def doesDBExist():
- try:
- return os.path.exists(DB_DIR + "observation.db")
- except Exception:
- logException("doesDBExist", str(sys.exc_info()[0]), str(sys.exc_info()[1]), str(sys.exc_info()[2]))
- return 0
- def createDB(connection):
- try:
- ddl = "CREATE TABLE temperature (datetime CHAR(16), ambient REAL, cpu REAL, hdd REAL, PRIMARY KEY (datetime))"
- connection.execute(ddl)
- except Exception:
- logException("createDB", str(sys.exc_info()[0]), str(sys.exc_info()[1]), str(sys.exc_info()[2]))
- return 0
- def writeRow(connection, values):
- try:
- insert = "INSERT INTO temperature VALUES (" + values + ")"
- print(insert)
- connection.execute(insert)
- connection.commit()
- except Exception:
- logException("writeRow", str(sys.exc_info()[0]), str(sys.exc_info()[1]), str(sys.exc_info()[2]))
- return 0
- class buttonThread(threading.Thread):
- # Buttons on the Adafruit LCD Plate are used for:
- # SELECT: shut down the Pi
- # LEFT : reboot the Pi
- # RIGHT : switch the LCD display on/off
- def __init__(self):
- super(buttonThread, self).__init__()
- self._stop = threading.Event()
- def stop(self):
- self._stop.set()
- def stopped(self):
- return self._stop.isSet()
- def run(self):
- # poll buttons and respond to any that are pressed
- # pressedSelect, pressedLeft and pressedRight are used to indicate that the
- # corresponding button has been pressed AND that we have already carried out
- # the required action. These are then used to stop the script repeatedly carrying
- # out the same action.
- try:
- global lcdOn
- global msgUpdated
- lcdOn = True
- pressedSelect = False
- pressedLeft = False
- pressedRight = False
- msgOld = False
- # take a note of when this thread starts running
- startTime = time.time()
- while True:
- # check if this thread has been signalled to stop and do so
- if self._stop.isSet():
- return()
- # allow 10 seconds for main thread to get first lot of temperatures at startup
- if time.time() - startTime > 10:
- # msgOld is set to indicate that the message is old AND that we have already
- # output an error message on the display.
- # We check that the temperature message is not older than 120 seconds.
- # This handles the case where the main thread hangs.
- if msgOld == False and time.time() - msgUpdated > 120:
- errorMessage = "Temperatures old\n" + time.strftime("%b %d %H:%M:%S")
- logMsg(errorMessage)
- lcd.clear()
- lcd.message(errorMessage)
- msgOld = True
- # check if message we are to display is old (more than 2 minutes old)
- if time.time() - msgUpdated > 120:
- msgOld = True
- else:
- msgOld = False
- if lcd.is_pressed(LCD.SELECT):
- if pressedSelect:
- pass
- else:
- turnLCDOn()
- lcd.clear()
- lcd.message("Shutting down...")
- s = subprocess.check_output(["/sbin/poweroff"])
- lcd.message("\n" + s)
- time.sleep(2)
- turnLCDOff()
- lcdOn = False
- # exit from the thread
- return()
- pressedSelect = True
- else:
- pressedSelect = False
- if lcd.is_pressed(LCD.LEFT):
- if pressedLeft:
- pass
- else:
- turnLCDOn()
- lcd.clear()
- lcd.message("Rebooting...")
- s = subprocess.check_output(["reboot"])
- lcd.message("\n" + s)
- time.sleep(2)
- turnLCDOff()
- lcdOn = False
- # exit from the thread
- return()
- pressedLeft = True
- else:
- pressedLeft = False
- if lcd.is_pressed(LCD.RIGHT):
- if pressedRight:
- pass
- else:
- if lcdOn == True:
- turnLCDOff()
- lcdOn = False
- else:
- turnLCDOn()
- lcdOn = True
- lcd.set_cursor(0,0)
- global lcdMessage
- lcd.message(lcdMessage)
- pressedRight = True
- else:
- pressedRight = False
- # Do nothing for 0.1 seconds.
- # Hopefully this will fix the hangs.
- # It also reduces the CPU usage to around 1%.
- time.sleep(0.1)
- except Exception:
- logException("buttonHandler", str(sys.exc_info()[0]), str(sys.exc_info()[1]), str(sys.exc_info()[2]))
- logMsg("Shutting down button handler thread")
- lcdExit()
- return()
- logMsg("Starting up")
- # insert signal handler
- signal.signal(signal.SIGTERM, signal_term_handler)
- # check to see if database exists
- exists = doesDBExist()
- conn = sqlite3.connect(DB_DIR + "observation.db")
- # if database did not previously exist then we need to
- # create the table to store our data
- if not exists:
- logMsg("Database does not exist, creating")
- createDB(conn)
- lcd = LCD.Adafruit_CharLCDPlate()
- lcd.clear()
- lcd.set_backlight(True)
- lcd.set_cursor(0,0)
- lcdOn = True
- lcdMessage = ""
- thread1 = buttonThread()
- thread1.start()
- # initialise this variable so buttonThread does not throw an exception when it finds
- # that it has not been initialised. This can occur at startup.
- msgUpdated = 0
- while True:
- try:
- cputemp = getCPUTemp()
- hddtemp = getHDDTemp(HDD_NAME)
- device = I2C.get_i2c_device(I2C_ADDRESS)
- i2ctemp = getI2CTemp(device)
- observations = list()
- if cputemp == TEMP_INVALID:
- cpudisplay = "E! "
- else:
- observations.append({ "id":"CPUTemperature", "current_value":"%.2f" % cputemp })
- cpudisplay = "%dC" % cputemp
- if i2ctemp == TEMP_INVALID:
- i2cdisplay = "E! "
- else:
- observations.append({ "id":"RoomTemperature", "current_value":"%.2f" % i2ctemp })
- i2cdisplay = "%.2fC" % i2ctemp
- # HDD temperature is an integer, so don't need to limit to 2 decimal places
- if hddtemp == TEMP_INVALID:
- hdddisplay = "E! "
- else:
- observations.append({ "id":"HDDTemperature", "current_value":str(hddtemp) })
- hdddisplay = "%dC" % hddtemp
- lcdMessage = "Ambient: " + i2cdisplay + " \nCPU: " + cpudisplay + " HD: " + hdddisplay + " "
- # store UNIX timestamp so buttonThread can determine if temperature values are old
- msgUpdated = time.time()
- if lcdOn:
- lcd.set_cursor(0,0)
- lcd.message(lcdMessage)
- upload = { "version": "1.0.0", "datastreams": observations }
- print time.strftime("%c")
- print json.dumps(upload)
- result = sendToXively(upload, XIVELY_KEY, XIVELY_FEED)
- print "HTTP status code from xively server: " + str(result.status)
- if result.status != 200:
- logMsg("Error sending data to xively. HTTP response code: " + str(result.status))
- # get current date and time
- now = datetime.datetime.now()
- # since we are logging temperature once a minute we don't need seconds
- nowstring = now.strftime("'%Y-%m-%d %H:%M'")
- writeRow(conn, nowstring + ", " + "%.2f" % i2ctemp + ", " + str(cputemp) + ", " + str(hddtemp))
- time.sleep(60)
- except KeyboardInterrupt:
- logMsg("Exiting on CTRL+C")
- # send thread the stop signal
- thread1.stop()
- # wait until thread has stopped
- thread1.join()
- lcdExit()
- sys.exit(0)
- except Exception:
- # N.B. we are still within the while loop!
- logException("main", str(sys.exc_info()[0]), str(sys.exc_info()[1]), str(sys.exc_info()[2]))
- syslog.syslog("Pausing for 60 seconds to see if error condition clears...")
- time.sleep(60)
- syslog.syslog("Attempting to continue where I left off...")
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement