Close

Python Code

A project log for RPI based thermostat

RPI, 18B20+ 1-wire, wifi, touchscreen

robRob 10/26/2015 at 19:220 Comments
#! /usr/bin/env python

import os, sys
import pygame, time
import RPi.GPIO as GPIO
from pygame.locals import *

# Load the thermometer drivers
os.system('modprobe w1-gpio')
os.system('modprobe w1-therm')

# Point to proper device (your number will change)
temp_sensor = '/sys/bus/w1/devices/28-000006f0ac17/w1_slave'

# Setup relay pin
GPIO.setmode(GPIO.BCM)
GPIO.setup(23,GPIO.OUT)
GPIO.output(23,GPIO.LOW)


def load_image(name, colorkey=None):
    fullname = os.path.join('data', name)
    try:
        image = pygame.image.load(fullname).convert_alpha()
    except pygame.error, message:
        print 'Cannot load image:', name
        raise SystemExit, message
    #image = pygame.transform.scale(image,(400,400))
    if colorkey is not None:
        if colorkey is -1:
            colorkey = image.get_at((0,0))
        image.set_colorkey(colorkey, RLEACCEL)
    return image, image.get_rect()

def write_log(rn):
	lfile = open('therm.log','a')
	lfile.write(rn)
	lfile.close()

def temp_raw():
	f = open(temp_sensor,'r')
	lines = f.readlines()
	f.close()
	return lines

def read_temp():
	lines = temp_raw()
	while lines[0].strip()[-3:] != 'YES':
		time.sleep(0.1)
		lines = temp_raw()
	temp_output = lines[1].find('t=')
	if temp_output != -1:
		temp_string = lines[1].strip()[temp_output+2:]
		temp_c = float(temp_string) / 1000.0
		temp_f = int(round(temp_c * 9.0 / 5.0 + 32.0))
		return temp_c, temp_f

def adjust_readout(current_temp, desired_temp, tcolor, ccolor, draw_circle):
	 # Setup for circle
	if draw_circle == True: 
	  circle_temp_font = pygame.font.Font(None, 30)
	  circle_temp_text = circle_temp_font.render(str(desired_temp), 1, tcolor)
	  current_temp_font = pygame.font.Font(None, 18)
	  current_temp_msg = current_temp_font.render("CURRENT",1,tcolor)
	#
	main_temp_font = pygame.font.Font(None, 130)
	main_temp_text = main_temp_font.render(str(current_temp).strip(' '), 1, tcolor)
        background.fill((  0,   0,   0))
	screen.blit(background, (0,0))
	textx = main_temp_text.get_rect(centerx=background.get_width()/2)
	texty = main_temp_text.get_rect(centery=background.get_height()/2)
        screen.blit(main_temp_text, (textx[0],texty[1]))
	#
	if draw_circle == True:
	  screen.blit(circle_temp_text,(400,30))
	  screen.blit(current_temp_msg,(210,198))
	  pygame.draw.circle(screen,ccolor,(411,41),20,1)
	allsprites.draw(screen)
	pygame.display.update()

def alt_display(temperature):
	d = time.strftime('%l:%M%p %z on %b %d, %Y')
	t = str(d[0:5].strip(' '))
	dt = str(d[17:23].strip(' '))
	background.fill((  0,   0,   0))
	screen.blit(background, (0,0))
	font1 = pygame.font.Font(None, 72)
	text1 = font1.render(t, 1, (0, 0, 250))
        textx = text1.get_rect(centerx=background.get_width()/2)
        texty = text1.get_rect(centery=background.get_height()/2)
        screen.blit(text1, (textx[0],texty[1]-5))
	font2 = pygame.font.Font(None, 40)
	text2 = font2.render(dt, 1, (0, 0, 250))
        textx = text2.get_rect(centerx=background.get_width()/2)
        texty = text2.get_rect(centery=background.get_height()/2)
        screen.blit(text2, (textx[0],texty[1]+32))
        font3 = pygame.font.Font(None, 50)
        text3 = font2.render(str(temperature).strip(' '), 1, (0, 0, 250))
        textx = text3.get_rect(centerx=background.get_width()/2)
        texty = text3.get_rect(centery=background.get_height()/2)
        screen.blit(text3, (textx[0],texty[1]-50))
	allsprites.draw(screen)
	pygame.display.update()


class InnerCircle(pygame.sprite.Sprite):
    def __init__(self):
        pygame.sprite.Sprite.__init__(self) #call Sprite intializer
        self.image, self.rect = load_image('c0.png', -1)
        screen = pygame.display.get_surface()
        self.area = screen.get_rect()
	self.rect.center = (self.area[2]/2, self.area[3]/2)
        self.rot = 0
	self.original = self.image

    def once(self):
	center = self.rect.center
        self.rect = self.image.get_rect(center=center)

    def spinl(self):
        center = self.rect.center
        self.rot -= 4
	rotate = pygame.transform.rotate
        self.image = rotate(self.original, self.rot)
        self.rect = self.image.get_rect(center=center)

    def spinr(self):
        center = self.rect.center
        self.rot += 4
	rotate = pygame.transform.rotate
        self.image = rotate(self.original, self.rot)
        self.rect = self.image.get_rect(center=center)

class OuterCircle(pygame.sprite.Sprite):
    def __init__(self):
        pygame.sprite.Sprite.__init__(self) #call Sprite intializer
        self.image, self.rect = load_image('c1.png', -1)
        screen = pygame.display.get_surface()
        self.area = screen.get_rect()
	self.rect.center = (self.area[2]/2, self.area[3]/2)
        self.rot = 0
        self.original = self.image

    def once(self):
	center = self.rect.center
        self.rect = self.image.get_rect(center=center)

    def spinl(self):
        center = self.rect.center
        self.rot -= 4
	rotate = pygame.transform.rotate
        self.image = rotate(self.original, self.rot)
        self.rect = self.image.get_rect(center=center)

    def spinr(self):
        center = self.rect.center
        self.rot += 4
	rotate = pygame.transform.rotate
        self.image = rotate(self.original, self.rot)
        self.rect = self.image.get_rect(center=center)

class TickCircle(pygame.sprite.Sprite):
    def __init__(self):
        pygame.sprite.Sprite.__init__(self) #call Sprite intializer
        self.image, self.rect = load_image('c2.png', -1)
        screen = pygame.display.get_surface()
        self.area = screen.get_rect()
	self.rect.center = (self.area[2]/2, self.area[3]/2)
        self.rot = 0
	self.original = self.image

    def once(self):
	center = self.rect.center
        self.rect = self.image.get_rect(center=center)

    def spinl(self):
        center = self.rect.center
        self.rot -= 4
	rotate = pygame.transform.rotate
        self.image = rotate(self.original, self.rot)
        self.rect = self.image.get_rect(center=center)

    def spinr(self):
        center = self.rect.center
        self.rot += 4
	rotate = pygame.transform.rotate
        self.image = rotate(self.original, self.rot)
        self.rect = self.image.get_rect(center=center)


pygame.init()

# Start initial setup
current_temp = 0 # Current temperature
desired_temp = 0 # Desired temperature
pygame.mouse.set_visible(False)
running = 1
changed = False
counter = 0
heaton = 0
old_temp = 0

# Initial temp readings

desired_temp = read_temp()[1]# Set both variables the same for start 
current_temp = desired_temp

# Basic screen setup
#screen = pygame.display.set_mode((480, 320))
screen = pygame.display.set_mode((480, 320), pygame.FULLSCREEN) 

# Init the sprites for graphics
innercircle = InnerCircle()
outercircle = OuterCircle()
tickcircle = TickCircle()
allsprites = pygame.sprite.RenderPlain((innercircle, outercircle, tickcircle))

# Setup for touchscreen
os.putenv('SDL_FBDEV', '/dev/fb1')
os.putenv('SDL_MOUSEDRV', 'TSLIB')
os.putenv('SDL_MOUSEDEV', '/dev/input/touchscreen')

# Set event to check temp and adjust
pygame.time.set_timer(USEREVENT + 1, 10000) # Custom event
#pygame.time.set_timer(USEREVENT + 2, 10000) # Custom event

# Get sprites ready for screen
innercircle.once()
outercircle.once()
tickcircle.once()

# Build background, text and show it all
background = pygame.Surface(screen.get_size())
background = background.convert()
background.fill((  0,   0,   0))
font = pygame.font.Font(None, 130)
text = font.render(str(current_temp), 1, (0, 0, 250))
textx = text.get_rect(centerx=background.get_width()/2)
texty = text.get_rect(centery=background.get_height()/2)
screen.blit(text, (textx[0],texty[1]))
allsprites.draw(screen)
#pygame.draw.line(screen,(0,0,255),(160,0),(160,320),1)
#pygame.draw.line(screen,(0,0,255),(320,0),(320,320),1)
pygame.display.update()

# Execution Loop
while running:
 for event in pygame.event.get():
    # Exit program stuff
    if event.type == QUIT:
        running = 0
    elif event.type == KEYDOWN and event.key == K_ESCAPE:
        running = 0

    # Get stuff done
    # These are keyboard commands for testing 'a' to lower, 's' to raise
    if event.type == KEYDOWN and event.key == K_a:# Temp adjust down
        desired_temp -= 1
      	for num in range(1,8):
        	innercircle.spinr()
		outercircle.spinl()
		screen.blit(background, (0, 0))
        	allsprites.draw(screen)
        	pygame.display.update()
	adjust_readout(current_temp, desired_temp, (0,0,255),(0,0,255),True)

    if event.type == KEYDOWN and event.key == K_s:# Temp adjust up
        desired_temp += 1
      	for num in range(1,8):
        	innercircle.spinl()
		outercircle.spinr()
		screen.blit(background, (0, 0))
        	allsprites.draw(screen)
        	pygame.display.update()
	adjust_readout(current_temp, desired_temp, (255,0,0),(255,0,0),True)

    # This for the touchscreen
    if (event.type is MOUSEBUTTONDOWN):
	pos = pygame.mouse.get_pos()
	if pos[0] > 160 and pos[0] < 320:# Set default screen
		print "Middle tap", pos
		adjust_readout(current_temp,desired_temp,(0,0,255),(0,0,255), False)

	if pos[0] > 320:# tapped right side of screen
	  changed = True
          desired_temp += 1 # Increment desired temp
       	  for num in range(1,8):
        	innercircle.spinl()
		outercircle.spinr()
		screen.blit(background, (0, 0))
        	allsprites.draw(screen)
        	pygame.display.update()
	  adjust_readout(current_temp, desired_temp, (255,0,0),(255,0,0),True)
	if pos[0] < 160:# tapped left side of screen
	  changed = True
          desired_temp -= 1 # Decrement desired 
      	  for num in range(1,8):
        	innercircle.spinr()
		outercircle.spinl()
		screen.blit(background, (0, 0))
        	allsprites.draw(screen)
        	pygame.display.update()
	  adjust_readout(current_temp, desired_temp, (0,0,255),(0,0,255),True)

    # Timer driven events
    if event.type == (USEREVENT + 1):
	print "Check Temperature"
	print "Desired Temperature: " + str(desired_temp)
	print "Actual Temperature: " + str(read_temp()[1])
	print "Burner: ",heaton
	rn = str(time.strftime('%l:%M%p %z on %b %d, %Y'))
	current_temp = read_temp()[1]

	if current_temp != desired_temp:
	  print "Something Changed"
	  changed = True

	if desired_temp > current_temp:
	  adjust_readout(current_temp, desired_temp, (0,0,255),(255,0,0),True)
	  if heaton == 0: 
	    #close relay
	    GPIO.output(23,GPIO.HIGH)
	    rn = rn + " Current temperature:"+str(current_temp)+" Desired temperature:"+str(desired_temp)+" Heat ON\n"
	    write_log(rn)
	    heaton = 1

	if desired_temp < current_temp:
	  adjust_readout(current_temp, desired_temp, (0,0,255),(0,0,255),True)
	  if heaton == 1:
	    #open relay
	    GPIO.output(23,GPIO.LOW)
	    rn = rn + " Current temperature:"+str(current_temp)+" Desired temperature:"+str(desired_temp)+" Heat OFF\n"
	    write_log(rn)
	    heaton = 0

 	# Temp at desired setting
	if desired_temp == current_temp:
	  if changed == True:
	    rn = rn + " Current temperature:"+str(current_temp)+" Desired temperature:"+str(desired_temp)+" Equality - Heat OFF\n"
	    write_log(rn)
	    # make sure relay is open
	    heaton = 0
	    GPIO.output(23,GPIO.LOW)
	    changed = False
	  counter += 1
	  if counter < 5:
	    alt_display(current_temp)
	    print counter
	  else: 
	    counter = 0
	    print counter
	    adjust_readout(current_temp,desired_temp,(0,0,255),(0,0,255), False)

Discussions