-
Update
11/13/2015 at 19:22 • 0 commentsWell, everything "seems" to be running fine in a test environment, but I have a concern. The red led on the RPI will flash on and off regularly, and goes off completely when the relay is engaged. I read somewhere that flashing means that the voltage is dropping, so I'd imagine that going out completely can't be good. What's strange is that it is working fine...
Also, I think I'm going to move to a solid-state relay. Checking into those now.
No headway at all on the "sexy" case for this project, so everything is just sitting out in the open right now.
-
Python Code
10/26/2015 at 19:22 • 0 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)
-
Getting Close
10/26/2015 at 19:11 • 0 commentsI have the 'basics' of this working together. For now, that means that I can track the temperature, view the current and desired temperature on a 3.5" touchscreen, activate a relay to turn on the burner, and log when the burner is on or off. There's no packaging yet, as I have to figure out some kind of enclosure to put this all together, Here's a shot of all the components wired together (except the relay to the actual burner).
Also, here is the circuit I used to drive the relay and activate the burner.
So far I've had everything running for about 20 hours, and it mimics my regular home thermostat pretty closely.
-
Relay Arrived
10/23/2015 at 14:24 • 0 commentsOk...finally got the relay I'll use to control the heat. I'm doing some testing using a transistor and 5V off of the RPI to power the coil. I'll post the circuit as soon as I finish testing.
As you can see my testing rig is fairly sophisticated :-) I also figured out a number of optimizations related to the display of the graphics, and have re-written the UI. With a few weeks of testing, I've had accurate and quick responses when using the touch screen.
-
The 2nd UI
09/22/2015 at 02:17 • 0 commentsThe second UI was a lot simpler. No rotating sprites, in fact no sprites at all. A simple graphic that is white for showing the current temperature, turns red when adjusting up, and blue when adjusting down. Same as before, tap on the left side of the screen to adjust down, right side to adjust up or center to view current.
Current in center, desired temp in circle at top right.
Temperature adjusted up
Temperature adjusted down
I haven't gotten around to adding the alternate screen to the new design.
My next step is to find a 3.3V or 5V relay that I can easily control via GPIO to turn the furnace on or off.
-
The UI and Python
09/22/2015 at 02:02 • 0 commentsI decided to use Python to code up this project. I'd never used it before, but it seemed pretty straightforward, and there were dozens of examples that I could cut and paste and mould to my needs. I started with the UI and discovered pygame as an easy way to work with graphics and sprites. My first version used sprites to animate the display with counter-rotating circles as the temperature was adjusted. This worked ok, but was a lot of code to get it all to work, and being new at python, my code grew unwieldy. Here's the first UI. Tap on the right to raise temp and left to lower.
It also has a timeout where it reverts to a second screen 30 seconds after adjusting or viewing the temp.
I also started to get worried about response to touch delays, but figured as I got more familiar with the code, I would find some optimizations.
-
The touchscreen and 18B20+
09/21/2015 at 23:03 • 0 commentsThis 3.5" touchscreen is actually my second touchscreen for this project. The first was a 2.8" capacitive touchscreen that required me to solder a header onto it for connection to the RPI. My soldering skills leave a lot to be desired, and I basically ruined the first one. I purchased the second one "fully assembled" so that problem was solved.
The touchscreen plugs directly on to the RPI and breaks out the unused pins on the back. I needed three wires to read the temperature connected to +3.3V, GND and GPIO 4 (data) for the 1-wire to work.
-
Starting the build
09/21/2015 at 22:56 • 0 commentsAll components