** 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 ;)

IMG_20170105_220541.jpg

IMG_20161229_172914.jpg

IMG_20170311_190001.jpg

IMG_20170118_170133.jpg

IMG_20170118_170138.jpg

IMG_20170118_180814.jpg

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]

IMG_20170110_190113.jpg