Raspberry Pi – Animated temperature plot

Raspberry pi with realtime temperature plot
Raspberry pi with realtime temperature plot

For the Christmas party yesterday I was asked to bring a large pot. The contents were supposed to be, as is customary in Germany mulled wine (Glühwein). Mulled apple wine in this case. Besides a pot we needed a hotplate which was brought by a colleague. Well, having mulled wine on a hot plate has one risk: You easily run your wine so hot you lose all the precious alcoho l. With it, usually also the fruity part of the flavour is gone. Enter the raspberry pi. I still had a foodsafe temperature sensor from a sous-vide cooking experiment I did recently. A quick search on the internet told me that 65°C was the temperature to go for, warm enough to have the Glühwein feeling, cold enough to preserve alcohol and taste.

In sous vide cooking the task of the raspberry pi is usually exactly this: You put a temperature sensor into a water bath, have the pi heat it to a specific temperature and keep it there for several hours. To do so switch on and off the heating for the water bath in with an appropriate frequency. Some months ago I experimented with sous-vide cooking and used the code I found here. It can be used for keeping Glühwein temperature just as good.

But if you are anything like me, you will find Glühwein of the perfect temperature tasty but not very exciting. What was needed was a display of temperature over time, so the raspberry could show off how it was doing a good job. As prerequisites I installed a current version of python (2.7) and matplotlib on the pi. Before installing matplotlib (you can get a current version using pip) you should check that you have the dev packages and libraries for tk / gtk, otherwise the graphical frontend you need for the realtime display will not be built.

To have the reatime plot display I use two scripts:

  1. A script to periodically fetch the temperature from the temperature sensor (DS18B20) and store it in a file (in this case hardcoded to /home/pi/Desktop/test.txt
    from subprocess import Popen, PIPE, call
    import time
    import re
    import numpy
    def tempdata():
        # Replace 10-000801d31e81 with the address of your DS18B20
        pipe = Popen(["cat","/sys/bus/w1/devices/w1_bus_master1/10-000801d31e81/w1_slave"], stdout=PIPE)
        result = pipe.communicate()[0]
        result_list = result.split("=")
        temp_mC = int(result_list[-1])/1000. # temp in milliCelcius
        if(re.match(".*YES.*",result) and temp_mC!=85.000):
            return temp_mC
        else:
            print result
            print "invalid result"
            return tempdata()
    times=[]
    temps=[]
    while True:
            times.append(time.time())
            temps.append(tempdata())
            print temps[-1]
            numpy.savetxt("/home/pi/Desktop/test.txt",[times,temps])
            time.sleep(5)
    
  2. A script to plot the resulting temperature, nicely and christmassy, with dark picture background and red writing.
    font = {'family' : 'sans serif',
            'weight' : 'bold',
            'size'   : 22
    }
    import matplotlib
    import time
    matplotlib.rc('font', **font)
    matplotlib.use('TKagg') # if this fails install matplotlib AFTER installing tk. And install it using pip.
    
    import matplotlib.pyplot as plt
    import matplotlib.image 
    import numpy as np
    import matplotlib.animation as animation
    #from scipy.imread import imread
    img=matplotlib.image.imread("bg.png") # load background image. 
    limits=[-30,0,10,26] #define plot limits. In this case: -30 to 0 minutes, 10-26°C for the demo picture, there was no Glühwein.
    def main(): # everything in the beginning is just preparation of the plot
        fig = plt.figure(figsize=(8,6),tight_layout=True)
        fig.patch.set_facecolor('black')
        ax=fig.add_subplot(111,aspect=1111)
        for i in ax.spines.keys():
            print i
            ax.spines[i].set_color('red')
        ax.yaxis.label.set_color('red')
        ax.xaxis.label.set_color('red')
        ax.tick_params(axis='x',colors='red')
        ax.tick_params(axis='y',colors='red')
    
        plt.imshow(img, zorder=0, extent=limits,aspect='auto')
        plt.xlim((limits[0],limits[1]))
        plt.ylim((limits[2],limits[3]))
        plt.ylabel("T[$^0$C]")
        plt.xlabel("$T[\mathrm{min}]$")
        plt.grid(color="red")
        theText=plt.text(limits[0]+0.05*(limits[1]-limits[0]),limits[2]+0.05*(limits[3]-limits[2]),"T=$100^\circ$C",size=40,color="red",animated=True)
    
       # secondAxes.set_ylim((55,70))
        thePlot, = plt.plot([], [],color="red",linewidth=4,animated=True)
        plt.draw()
        ani = animation.FuncAnimation(fig, update_plot, frames=xrange(1000),
                                      fargs=(thePlot,theText),blit=True)
        # here we start the animation
        plt.show()
    
    def readRetry(): # reads data from the text file, retries if there are problems
        test=True
        while test:
            try: 
               x,y=np.genfromtxt("/home/pi/Desktop/test.txt")
               test=False
               except ValueError:
                    pass
            except Exception:
               pass
        return (x,y)        
    
    def update_plot(i, thePlot, theText): # this is the function that updates the plot for the "FuncAnimation"
        print i
        time.sleep(.1)
        x,y=readRetry()     
        thePlot.set_data((x-time.time())/60.,y)
        theText.set_text("T=%0.3f" % y[-1])
        return thePlot,theText
    #np.savetxt("test.txt",[[time.time(),time.time()-1000],[65,65]])
    main()
    

Now starting the scripts after one another (and adding your temperature sensor id to the first / your background picture to the second) you will get a nice animated temperature plot. If you press f in the window with the plot, it will go full screen.