** Things you need:**
All together not a cheap setup. You can find cheaper and ready solutions on the internet, but of course it is about tinkering ;)
And the python script for controlling the relay or the heater, respectively.
tl;dr: Read out the temperature sensor every X seconds and activate the heater if current temperature is below the target temperature. Ah, and create quite ugly plot.
import time
import os, sys
from datetime import datetime
import RPi.GPIO as GPIO
import matplotlib.pyplot as plt
class SousVide:
'''
target: Float. Target temperature in degree Celsius
interval: Float. Time between measurements in seconds
timeFrame: int. Length of history in view in minutes
'''
def __init__(self, target=50.0, interval=5.0, timeFrame=60):
now = datetime.now().replace(microsecond=0).time()
print "SousVide started at " + str(now)
print "Init target temperature set at " + str(target) + " degree Celsius"
# Set the correct GPIO pin to 'off'
GPIO.setmode(GPIO.BOARD)
GPIO.setup(36, GPIO.OUT)
GPIO.output(36, GPIO.LOW)
# Search for the sensor
busDir = "/sys/bus/w1/devices/"
self.sensDir = ""
try:
for root, dirs, files in os.walk(busDir):
for d in dirs:
if d.startswith('w1_bus_master'):
continue
else:
self.sensDir = busDir + d + "/"
print "Found sensor!"
except Exception as e:
print e
print "Error: Thermo sensor not found."
print "Exiting..."
sys.exit()
# Heater
self.heaterStatus = False
# Temperature
self.interval = interval # in seconds
self.frameSize = int(timeFrame * 60 / self.interval)
self.tempHistory = [1.0] * self.frameSize
self.tempHistoryTime = [str(now)] * self.frameSize
self.heaterHistory = [0] * self.frameSize
self.curTemp = 0.0
self.target = target
# Plotting
self.plotFrameSize = self.frameSize
self.figure, self.ax = plt.subplots()
self.ax2 = self.ax.twinx()
plt.xticks(range(self.plotFrameSize), self.tempHistoryTime, rotation=45)
#plt.locator_params(axis='x', nbins=5)
self.plotLine, = self.ax.plot(range(self.plotFrameSize), self.tempHistory, "r-")
self.plotLineH, = self.ax2.plot(range(self.plotFrameSize), self.heaterHistory, "b-")
plt.title("Temp. History")
plt.grid(True)
self.ax.set_ylabel('Degree (C)')
self.ax.set_xlabel('Time')
self.ax.set_ylim((20,(self.target + 15)))
self.ax2.set_ylabel('Heater (On/Off)')
self.ax2.set_xlabel('Time')
self.ax2.set_ylim([-1,2])
self.ax2.set_yticks(range(4), ["", "Off", "On" , ""])
plt.show(block=False)
print "Initial plot created"
print "Start measuring..."
def getTemp(self):
""" Read sensor data and return temperature float """
sensData = open(self.sensDir + "w1_slave", "r").read()
sensData = sensData.split("\n")[1]
temp = sensData[sensData.find("t=")+2:]
return float(temp)
def plotTemp(self):
plt.xticks(range(self.plotFrameSize), self.tempHistoryTime[-(self.plotFrameSize):], rotation=45)
self.plotLine.set_xdata(range(self.plotFrameSize))
self.plotLine.set_ydata(self.tempHistory[-(self.plotFrameSize):])
self.plotLineH.set_ydata(self.heaterHistory[-(self.plotFrameSize):])
self.figure.canvas.draw()
def enableHeater(self):
GPIO.output(36, GPIO.HIGH)
self.heaterStatus = True
def disableHeater(self):
GPIO.output(36, GPIO.LOW)
self.heaterStatus = False
def cook(self):
try:
while 1:
now = datetime.now().replace(microsecond=0).time()
self.curTemp = self.getTemp() / 1000
print "Temperature is: " + str(self.curTemp) + " C"
self.tempHistory.append(self.curTemp)
self.tempHistoryTime.append(str(now))
if (self.curTemp < self.target) and not self.heaterStatus:
diff = self.target - self.curTemp
print "Temperature difference to target temp. is: " + str(diff)
print ">> Activate heater"
self.enableHeater()
elif (self.curTemp >= self.target) and self.heaterStatus:
diff = self.target - self.curTemp
print "Temperature difference to target temp. is: " + str(diff)
print ">> Deactivate heater"
self.disableHeater()
else:
print ""
self.heaterHistory.append(int(self.heaterStatus))
self.plotTemp()
time.sleep(self.interval)
except KeyboardInterrupt:
GPIO.output(36, GPIO.LOW)
print ""
print "Thanks for cooking with me."
print "Adios!"
GPIO.cleanup()
def brokenPipe(self):
# not sure if this works, not tried yet...
with open('error.log', 'a') as eLog:
elog.write(str(datetime.now()) + "\n")
elog.write("Died at", self.curTemp, "degrees.\n" )
GPIO.output(36, GPIO.LOW)
print ""
print "SSH connection died. Trying not to heat until boiling :("
print "Ciao"
GPIO.cleanup()
# Lets go
sv = SousVide(target=58.0, interval=5.0, timeFrame=60)
sv.cook()
# This is basically just for the case the SSH connection dies...
import atexit
atexit.register(sv.brokenPipe())
https://www.raspberrypi.org/documentation/usage/gpio-plus-and-raspi2/ http://haldean.org/sousvide/ https://willy-tech.de/temperatursensor-an-raspberry-pi/ [German] https://raspberrypi.stackexchange.com/questions/55405/gpio-pin-voltage-is-too-low-to-energize-relay?rq=1 http://www.tacticalcode.de/2012/12/transistor-simpler-schalter-mit-raspberry-pi-gpio.html [German]