Table of Contents
Python Libraries
All of our Python modules can be installed directly from the PIP Python repository (PiPy) simply by typing sudo pip install pi–plates from the command line. If you’re installing for the first time then visit our Documentation page to get detailed instructions or execute the following sequence of commands from a terminal window:
1 2 3 |
sudo apt-get update sudo apt-get upgrade sudo pip install pi-plates |
The above installs the Pi-Plate Python libraries into a folder located at /usr/local/lib/python2.7/dist-packages/piplates.
If you need to uninstall the library then simply type sudo pip uninstall pi-plates.
If you want to update a library, the cleanest approach is to run sudo pip uninstall pi-plates from the command line followed by sudo pip install pi-plates.
We also have a set of Python 3 modules that can be downloaded with sudo pip3 install Pi-Plates
In addition to the code below, you can find a number of code snippets in our documentation.
This work is licensed under a Creative Commons Attribution-NonCommercial 4.0 International License.
PIPLATElogger
Go Here to read all about how to download and use our free data logger application, PIPLATElogger.
Object Oriented MOTORplate Demo Using Tkinter
Here is an object oriented Tkinter program we wrote to drive two stepper motors and four DC motors using two MOTORplates. The code has classes for DC motors, stepper motors and the title block. When run, the program puts up the following display:
We wrote this program to provide an easy method to demonstrate all of the capabilities of the MOTORplate as well as to teach ourselves object oriented programming with Python and Tkinter. You can copy and paste the code below or install it directly to your Raspberry Pi using these steps from the command line:
- Download the files from our server with: sudo wget https://pi-plates.com/downloads/MOTORdemo.tar.gz
- Then decompress them into your home directory: sudo tar -xzvf MOTORdemo.tar.gz
The program assumes two MOTORplates attached to the stack at addresses 0 and 1. In our demo, we had two stepper motors connected to the board at address 0 and four DC motors driven by the board at address 1. Besides learning teaching ourselves the basics of object oriented programming, we also learned about manipulating font sizes with the tkFont module. For example, we wanted a large title so we created a bold, 40 point version of the built in Helvetica font with: self.title = tkFont.Font(family=’Helvetica’, size=40, weight=’bold’)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 |
import piplates.MOTORplate as MOTOR import time import os import string from Tkinter import * import tkFont class titleBLOCK: def __init__(self,master,r,c): self.master=master self.tit=Frame(self.master,padx=4,pady=4,bd=2,bg='white',relief='sunken') self.tit.grid(row=r,column=c, columnspan=2,sticky=N+S+W+E) ##Create Fonts self.title = tkFont.Font(family='Helvetica', size=40, weight='bold') self.heading = tkFont.Font(family='Helvetica', size=18, weight='bold') self.logo = PhotoImage(file = '3D-ppLogo.gif') self.pp=Label(self.tit,image=self.logo,anchor="center").grid() self.labelt = Label(self.tit, text="MOTORplate Controller", bg='white',fg='#000666000',padx=4,pady=4,font=self.title,anchor="center") self.labelt.grid(sticky=W+E) #self.pp.bind("<ButtonRelease-1>", self.shutdown) self.close_button = Button(self.tit, text="X", command=root.quit).grid(sticky=E) def shutdown(self,event): print "clicked at", event.x, event.y class stepperGUI: def __init__(self,master,title,stepper,r,c): self.stepState=0 #stopped smColor="yellow" slwidth=30 slength=120 self.mVal=stepper self.master=master self.sm=Frame(self.master,padx=4,pady=4,bd=2,relief='sunken') self.sm.grid(row=r,column=c, rowspan=3, sticky=N+S+W+E) ##Create Fonts self.title = tkFont.Font(family='Helvetica', size=25, weight='bold') self.heading = tkFont.Font(family='Helvetica', size=18, weight='bold') ##Title self.labelt = Label(self.sm, text=title, padx=4,pady=4, bg=smColor, fg='black',font=self.title) self.labelt.grid(row=0,column=0,columnspan=2,sticky=W+E) ##Step Rate Control self.labels = Label(self.sm, text="Step Rate",padx=4,pady=4,font=self.heading) self.labels.grid(row=1,column=0) self.rate=IntVar() self.rate.set(0) self.RateSet=Scale(self.sm,variable=self.rate,from_=2000,to=0,width=slwidth,length=slength) self.RateSet.bind("<ButtonRelease-1>", self.ratedelta) self.RateSet.grid(row=2,column=0,rowspan=2) ##Direction Control self.labeld = Label(self.sm, text="Direction",padx=4,pady=4,font=self.heading) self.labeld.grid(row=1,column=1,sticky=W) self.direction = IntVar() self.direction.set(0) self.cwb = Radiobutton(self.sm, text='Clockwise', variable=self.direction, value=0) self.ccwb = Radiobutton(self.sm, text=' Counter Clockwise', variable=self.direction, value=1) self.direction.set(0) self.cwb.grid(row=2,column=1,sticky=W) self.ccwb.grid(row=3,column=1,sticky=W) ##Acceleration Control self.labela = Label(self.sm, text="Acceleration",padx=4,pady=4,font=self.heading) self.labela.grid(row=4,column=0) self.acc=DoubleVar() self.acc.set(0.0) self.accSet=Scale(self.sm,variable=self.acc,from_=5.0,to=0.0, resolution=0.1,width=slwidth,length=slength) self.accSet.grid(row=5,column=0,rowspan=4) ##Step Size Control rStart = 4 self.labeld = Label(self.sm, text="Step Size",padx=4,pady=4,font=self.heading) self.labeld.grid(row=rStart,column=1,sticky=W) rStart+=1 self.ss = IntVar() self.ss.set(2) # initializing the choice: Full sizes = [ ("Full",0), ("Half",1), ("1/4 - microstep",2), ("1/8 - microstep",3) ] for txt, val in sizes: Radiobutton(self.sm, text=txt, variable=self.ss, value=val).grid(row=rStart+val,column=1,sticky=W) ##Step Count Control self.labelstep = Label(self.sm, text="Step Count",padx=4,pady=4,font=self.heading) self.labelstep.grid(row=9,column=0) self.steps=IntVar() self.steps.set(0) self.StepSet=Scale(self.sm,variable=self.steps,from_=2000,to=0,width=slwidth,length=slength) self.StepSet.grid(row=10,column=0,rowspan=3) ##Jog Button self.startButton=Button(self.sm,text="JOG",fg="black",bg="green",height=3, width=6,command=self.jog) self.startButton.grid(row=10,column=1) ##Move Button self.startButton=Button(self.sm,text="MOVE",fg="white",bg="blue",height=3, width=6,command=self.move) self.startButton.grid(row=11,column=1) ##Stop Button self.stopButton=Button(self.sm,text="STOP",fg="white",bg="red",height=3, width=6,command=self.stop) self.stopButton.grid(row=12,column=1) ##Off Button self.stopButton=Button(self.sm,text="OFF",fg="black",bg="yellow",height=3, width=6,command=self.off) self.stopButton.grid(row=13,column=1) self.stop() #ensure motor is off at start self.off() #ensure motor is off at start def ratedelta(self,val): if (self.stepState==1): MOTOR.stepperRATE(0,self.mVal,self.rate.get()) def jog(self): if (self.direction.get() == 0): dir='cw' else: dir='ccw' MOTOR.stepperCONFIG( 0,self.mVal,dir,self.ss.get(),self.rate.get(),self.acc.get()) MOTOR.stepperJOG(0,self.mVal) self.stepState=1 def move(self): if (self.direction.get() == 0): dir='cw' else: dir='ccw' MOTOR.stepperCONFIG(0,self.mVal,dir,self.ss.get(),self.rate.get(),self.acc.get()) MOTOR.stepperMOVE(0,self.mVal,self.steps.get()) self.stepState=2 def stop(self): MOTOR.stepperSTOP(0,self.mVal) self.stepState=0 def off(self): MOTOR.stepperOFF(0,self.mVal) self.stepState=0 class dcGUI: def __init__(self,master,title,mN,r,c): self.dcState=0 #stopped dcColor="red" slwidth=30 self.mNum=mN self.master=master self.dcm=Frame(master,padx=4,pady=4,bd=2,relief='sunken') self.dcm.grid(row=r,column=c, columnspan=1, rowspan=2, sticky=N+S+W+E) ##Font Setup self.title = tkFont.Font(family='Helvetica', size=25, weight='bold') self.heading = tkFont.Font(family='Helvetica', size=18, weight='bold') ##Title self.labelt = Label(self.dcm, text=title, padx=4,pady=4, fg="white", bg=dcColor, font=self.title) self.labelt.grid(row=0,column=0,columnspan=2,sticky=W+E) #Speed Control self.labels = Label(self.dcm, text="Speed",padx=4,pady=4,font=self.heading) self.labels.grid(row=1,column=0) self.speed=IntVar() self.speed.set(0) self.SpeedSet=Scale(self.dcm,variable=self.speed,from_=100,to=0,width=slwidth) self.SpeedSet.bind("<ButtonRelease-1>", self.speeddelta) self.SpeedSet.grid(row=2,column=0,rowspan=2) ##Direction Control self.labeld = Label(self.dcm, text="Direction",padx=4,pady=4,font=self.heading) self.labeld.grid(row=1,column=1,sticky=W) self.direction = IntVar() self.direction.set(0) self.cwb = Radiobutton(self.dcm, text='Clockwise', variable=self.direction, value=0) self.ccwb = Radiobutton(self.dcm, text=' Counter Clockwise', variable=self.direction, value=1) self.direction.set(0) self.cwb.grid(row=2,column=1,sticky=W) self.ccwb.grid(row=3,column=1,sticky=W) ##Acceleration Control self.labela = Label(self.dcm, text="Acceleration",padx=4,pady=4,font=self.heading) self.labela.grid(row=4,column=0) self.acc=DoubleVar() self.acc.set(0.0) self.accSet=Scale(self.dcm,variable=self.acc,from_=5.0,to=0.0, resolution=0.1,length=100,width=slwidth) self.accSet.grid(row=5,column=0,rowspan=2) ##RPM Display self.rpm=StringVar() self.rpm.set('0') self.labelt = Label(self.dcm, text="RPM",padx=4,pady=4,font=self.heading) self.labelt.grid(row=7,column=0,columnspan=2) self.labelt = Label(self.dcm, textvariable=self.rpm ,padx=4,pady=4,font=self.heading) self.labelt.grid(row=8,column=0,columnspan=2) ##Start Button self.startButton=Button(self.dcm,text="GO",fg="black",bg="green",height=3, width=6,command=self.go) self.startButton.grid(row=5,column=1) ##Stop Button self.stopButton=Button(self.dcm,text="STOP",fg="white",bg="red",height=3, width=6,command=self.stop) self.stopButton.grid(row=6,column=1) self.UpdateRPM() def go(self): if (self.direction.get() == 0): dir='cw' else: dir='ccw' MOTOR.dcCONFIG(1,self.mNum,dir,self.speed.get(),self.acc.get()) MOTOR.dcSTART(1,self.mNum) self.dcState=1 def stop(self): MOTOR.dcSTOP(1,self.mNum) self.dcState=0 def speeddelta(self,val): #print self.dcState,self.speed.get() if (self.dcState): MOTOR.dcSPEED(1,self.mNum,self.speed.get()) def UpdateRPM(self): t=MOTOR.getTACHfine(1,self.mNum) self.rpm.set(str(t*60/300)) self.dcm.after(1000,self.UpdateRPM) MOTOR.RESET(0) MOTOR.RESET(1) root = Tk() root.config(bg="black") root.attributes("-fullscreen", True) swidth=root.winfo_screenwidth() sheight=root.winfo_screenheight() #print tkFont.families() container=Frame(root,bg="white") container.place(relx=0.5, rely=0.5, anchor=CENTER) ma_gui = stepperGUI(container,"Stepper Motor A",'a',1,1) mb_gui = stepperGUI(container,"Stepper Motor B",'b',1,2) m1_gui = dcGUI(container,"DC Motor 1",1,0,0) m2_gui = dcGUI(container,"DC Motor 2",2,2,0) m3_gui = dcGUI(container,"DC Motor 3",3,0,3) m4_gui = dcGUI(container,"DC Motor 4",4,2,3) title = titleBLOCK(container,0,1) root.mainloop() |
Controlling a RELAYplate Remotely with Your Web Browser
Introduction
Ever wanted to remotely control devices and appliances in your home or office simply by going to a webpage and clicking on the screen? This application note explains how to do just that using a Python microframework called “Flask” that will serve up a web page from a Raspberry Pi allowing you to control a RELAYplate. There are a number of ways of doing this but we chose Flask because it is small and it allows us to use a Python program on the backend without too much trouble. Even if you don’t use the code below to control a Pi-Plate, feel free to adapt it to your own application and hopefully, learn from our mistakes. If you want to learn more about Flask, visit the web site: http://flask.pocoo.org/
Getting Started
Before diving into the code it will be necessary to attach a RELAYplate set to address 0 to your Raspberry Pi (RPi). Boot up your RPi and ensure you have all the latest updates with the two ubiquitous commands:
sudo apt-get update
sudo apt-get dist-upgrade
Next we will need to install the Flask framework with:
sudo pip install Flask
On our system, this generated quite a few warnings but it was fully functional after the installation completed.
Download and install the application with:
- Start by going into terminal mode. If you’re in the X window environment you can go to the command line environment by holding down the <CNTL>+<ALT>+F1 buttons or you can click the terminal icon on the task bar.
- Download the files from our server with: sudo wget https://pi-plates.com/downloads/webapp.tar.gz
- Then decompress them into your home directory: sudo tar -xzvf webapp.tar.gz
- Finally change to the webapp folder with: cd webapp
Running the Program
With your RELAYplate attached, run this command:
sudo python control.py
If all goes well, the power light on the RELAYplate will blink three times and you will see the following on your screen:
* Running on http://0.0.0.0:80/ (Press CTRL+C to quit)
Next, figure out what the IP address is of your Raspberry Pi. There are a couple of ways to do this:
- Place your mouse over the network icon on your toolbar. A little box will drop down with your IP address
- Open up a new terminal window and run the command ifconfig. Find your network interface (eth0 or wlan0) and note the four digits after “inet”
Now go to any computer on your home network and open a browser. In the address bar, type the IP address of your Raspberry Pi. For us, the address was 192.168.1.209 so we would type http://192.168.1.209 and hit enter.
If all goes well, you will be presented with a screen that looks something like:
To turn on a relay, click the corresponding green button. To turn off a relay, click the red button. The status of each relay will be updated across the bottom row. To date we have successfully tested this program using the Chrome browser on a PC running Windows 10, an iPhone, an iPad, and a 7" Android tablet.
How It Works
File Structure
The directory and file structure of the website is shown below. Under the top directory of webapp are the two subdirectories of static and templates. The backend program, control.py is saved in the webapp directory. The html file that is served up by Flask is stored in templates. And all of the images displayed by the webpage are stored in the static folder.
webapp
├── control.py
├── static
│ ├── 3D-ppLogoSmall.gif
│ ├── favicon.ico
│ ├── GoSmall.png
│ └── StopSmall.png
└── templates
└── WebPage.html
Frontend
The frontend is the html file that the user sees when the IP address of the RPi is opened in a browser. Since we’re lazy and didn’t want to write our html code from scratch, we used LibreOffice Writer to create a table, filled in the colors and the text we wanted, and then saved it as an html file. We then used the Leafpad text editor to edit and clean up the resulting output. After playing with styles, doing some cleanup, and adding some pictures, the HTML code ended up looking like:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 |
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <html> <head> <meta http-equiv="content-type" content="text/html; charset=utf-8"/> <title></title> <link rel="shortcut icon" href="{{ url_for('static', filename='favicon.ico')}}"> <style type="text/css"> @page { margin: 0.79in } p { margin-bottom: 0.1in; line-height: 120% } td p { margin-bottom: 0in } </style> <style> #p1 { color: white; font-size: 250%; font-family: monospace; font-weight: bold; text-align: center; } #p2 { color: black; font-size: 250%; font-family: monospace; font-weight: bold; text-align: center; } table { border-collapse: collapse; } table, td, th { border: 1px solid black; } </style> </head> <body lang="en-US" dir="ltr"> <table width="1000" cellpadding="0" cellspacing="0" align="center"> <col width="40%"> <col width="60%"> <tr valign="center" height = "140"> <td width="40%" style="border: none; padding: 0in"> <p align="right"><img src="{{ url_for('static',filename="3D-ppLogoSmall.gif") }}" alt="Your LOGO Here" style="width:400px;height:140px;"></p> </td> <td width="60%" style="border: none; padding: 0in"> <p><font size="6" face="Nimbus Sans L, sans-serif"><b>{{ title }}</b></font></p> </td> </tr> </table> <table width="1000" cellpadding="0" cellspacing="0" align="center"> <tr valign="center" height = "80"> <td bgcolor="#993300"> <p id="p1" >{{ labels[0] }}</p> </td> <td bgcolor="#ff0000"> <p id="p1" >{{ labels[1] }}</p> </td> <td bgcolor="#ffcc00"> <p id="p2" >{{ labels[2] }}</p> </td> <td bgcolor="#ffff00"> <p id="p2" >{{ labels[3] }}</p> </td> <td bgcolor="#009900"> <p id="p2" >{{ labels[4] }}</p> </td> <td bgcolor="#0000ff"> <p id="p1" >{{ labels[5] }}</p> </td> <td bgcolor="#6600ff"> <p id="p1" >{{ labels[6] }}</p> </td> </tr> <tr valign="center" height = "80"> <td bgcolor="#993300"> <a href="1on"><p align="center"><img src="{{ url_for('static',filename="GoSmall.png") }}" alt="Go Button" style="width:128px;height:128px;"></p> </a> </td> <td bgcolor="#ff0000"> <a href="2on"><p align="center"><img src="{{ url_for('static',filename="GoSmall.png") }}" alt="Go Button" style="width:128px;height:128px;"></p></a> </td> <td bgcolor="#ffcc00"> <a href="3on"><p align="center"><img src="{{ url_for('static',filename="GoSmall.png") }}" alt="Go Button" style="width:128px;height:128px;"></p></a> </td> <td bgcolor="#ffff00"> <a href="4on"><p align="center"><img src="{{ url_for('static',filename="GoSmall.png") }}" alt="Go Button" style="width:128px;height:128px;"></p></a> </td> <td bgcolor="#009900"> <a href="5on"><p align="center"><img src="{{ url_for('static',filename="GoSmall.png") }}" alt="Go Button" style="width:128px;height:128px;"></p></a> </td> <td bgcolor="#0000ff"> <a href="6on"><p align="center"><img src="{{ url_for('static',filename="GoSmall.png") }}" alt="Go Button" style="width:128px;height:128px;"></p></a> </td> <td bgcolor="#6600ff"> <a href="7on"><p align="center"><img src="{{ url_for('static',filename="GoSmall.png") }}" alt="Go Button" style="width:128px;height:128px;"></p></a> </td> </tr> <tr valign="center" height = "80"> <td bgcolor="#993300"> <a href="1off"><p align="center"><img src="{{ url_for('static',filename="StopSmall.png") }}" alt="Stop Button" style="width:128px;height:128px;"></p> </a> </td> <td bgcolor="#ff0000"> <a href="2off"><p align="center"><img src="{{ url_for('static',filename="StopSmall.png") }}" alt="Stop Button" style="width:128px;height:128px;"></p></a> </td> <td bgcolor="#ffcc00"> <a href="3off"><p align="center"><img src="{{ url_for('static',filename="StopSmall.png") }}" alt="Stop Button" style="width:128px;height:128px;"></p></a> </td> <td bgcolor="#ffff00"> <a href="4off"><p align="center"><img src="{{ url_for('static',filename="StopSmall.png") }}" alt="Stop Button" style="width:128px;height:128px;"></p></a> </td> <td bgcolor="#009900"> <a href="5off"><p align="center"><img src="{{ url_for('static',filename="StopSmall.png") }}" alt="Stop Button" style="width:128px;height:128px;"></p></a> </td> <td bgcolor="#0000ff"> <a href="6off"><p align="center"><img src="{{ url_for('static',filename="StopSmall.png") }}" alt="Stop Button" style="width:128px;height:128px;"></p></a> </td> <td bgcolor="#6600ff"> <a href="7off"><p align="center"><img src="{{ url_for('static',filename="StopSmall.png") }}" alt="Stop Button" style="width:128px;height:128px;"></p></a> </td> </tr> <tr valign="center" height = "80"> <td bgcolor="#993300"> <p id='p1'>{{ status[0] }}</p> </td> <td bgcolor="#ff0000"> <p id='p1'>{{ status[1] }}</p> </td> <td bgcolor="#ffcc00"> <p id='p2'>{{ status[2] }}</p> </td> <td bgcolor="#ffff00"> <p id='p2'>{{ status[3] }}</p> </td> <td bgcolor="#009900"> <p id='p2'>{{ status[4] }}</p> </td> <td bgcolor="#0000ff"> <p id='p1'>{{ status[5] }}</p> </td> <td bgcolor="#6600ff"> <p id='p1'>{{ status[6] }}</p> </td> </tr> </table> </body> </html> |
A quick description of the above:
In the HEAD segment we place a link to our favicon in the static folder and create a couple of paragraph styles and a table style. Then in the body, we start by creating a simple table with our logo on the left and a label on the right that is provided by the backend. Then we draw three tables and populate them with labels provided by the backend, on and off button images stored in the static folder, and switch status provided by the backend.
Now we don't claim to be HTML experts so please forgive us if the above code is less than elegant.
Backend
The backend program is written in Python and can be seen below:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
import piplates.RELAYplate as RELAY from flask import Flask, render_template app = Flask(__name__) ############################################################################## ###################### Set address of RELAYplate below: ###################### ppADDR=0 ############################################################################## ############################################################################## ###### Customize the names of your relays by changing the labels below: ###### labels=['Relay 1','Relay 2','Relay 3','Relay 4','Relay 5','Relay 6','Relay 7'] ############################################################################## ############################################################################## ######## Customize the title of your page by changing the text below: ######## title='Remote RELAYplate Controller' ############################################################################## RELAY.RESET(ppADDR) status = range(7) for i in range(7): status[i]='OFF' @app.route("/") @app.route("/<state>") def update_relay(state=None): if state != None: rly=int(state[0]) #parse relay number action=state[2] #parse action: 'n' for on and 'f' for off if action=='n': RELAY.relayON(ppADDR,rly) if action=='f': RELAY.relayOFF(ppADDR,rly) #Update the relay status mask=1 rstate=RELAY.relaySTATE(ppADDR) for i in range(7): if (rstate & mask) != 0: status[i]='ON' else: status[i]='OFF' mask = mask<<1 template_data = {'status' : status, 'labels' : labels, 'title' : title, } return render_template('WebPage.html', **template_data) if __name__== '__main__': app.run(host='0.0.0.0',port=80) |
In the above we import our modules and then start Flask. After that, we highlight the fields that can be modified and passed to the frontend, initialize some variables, end then define out the page update routine. Whenever the page is refreshed or a hyperlink is clicked by the user, this routine is called. Each hyperlink passes a unique value to this function which is parsed and acted upon. In our case, we parse the relay number followed by the requested action of off or on. After sending the RELAYplate the updated status, we read and save the state of each relay into the status list. This along with the relay labels and and page title are passed to the frontend by the render_template function.
Customization
Want to make your own page or just change the titles to something more descriptive? Then keep reading!
Title
Changing the title is a simple matter of editing the text inside the box in the backend program that looks like:
1 2 3 4 |
############################################################################## ######## Customize the title of your page by changing the text below: ######## title='Remote RELAYplate Controller' ############################################################################## |
Relay Labels
Changing the relay labels can be accomplished by editing the list inside the box in the backend program that looks like:
1 2 3 4 |
############################################################################## ###### Customize the names of your relays by changing the labels below: ###### labels=['Relay 1','Relay 2','Relay 3','Relay 4','Relay 5','Relay 6','Relay 7'] ############################################################################## |
Graphic
This is a little trickier. And while we tried to be clever about it, we ended up having to edit the frontend HTML code to make this work. First, find this line in the frontend code:
1 |
<p align="right"><img src="{{ url_for('static',filename="3D-ppLogoSmall.gif") }}" alt="Your LOGO Here" style="width:400px;height:140px;"></p> |
After the "filename=" statement, type the name of your graphic file. Then, after "style=", type the dimensions of your image. Finally, put your graphic in the static folder. We are embarrassed to admit how long it took us to figure that last part out.
Accessing Your Page When Not on Your Local Network
What if you want to load up your page and turn things off and on but you’re not at home? Maybe you want a light on in the front window or some hot coffee when you get home. There are a few ways to do this. The first of which, and the most complicated, is called port forwarding. We will not be going into to that because every router has its own setup. If you do choose to use port forwarding, just Google your router brand and part number. In most cases the complete instructions will be available.
A second, much easier approach is to use the service provided by Weave (https://www.weaved.com). This is a painless yet powerful way to remotely access your Raspberry Pi without having to deal with the hassle of Port Forwarding. Go to their site and apply for an account and discover how easy it is.
Conclusion
We learned that using Flask allows the Raspberry Pi to be lightweight webserver with a Python backend. We also had to relearn some HTML along the way. Hopefully you can use this code as is and if not, it can be easily modified for your application.
DAQCplate Demonstration Code Written in TKinter
We recently had a booth at Maker Faire where we were demonstrating both the MOTORplate and the DAQCplate. A number of people stopped by to look, ask questions, and even buy our products. Quite a few people also wanted the code we were using to demonstrate the DAQCplate. We wrote a simple Tkinter based Python program that filled the screen with large, attention grabbing characters that displayed things like temperature, range, voltages and so on:
The code to produce the above is shown below. In addition, the code can be downloaded and installed directly onto your Raspberry Pi by executing the following from the command line:
sudo wget https://pi-plates.com/downloads/DAQCdemo.tar.gz
sudo tar -xzvf DAQCdemo.tar.gz
sudo python DAQCdemo.py
Note that this code assumes a DAQCplate set to address 0. In addition, the code was written to read a range sensor on channel 6, a temperature sensor on analog channel 1, potentiometers on 0 and 7, and a scaled value of 12VDC power supply on channel 2. DOUT channels 0-5 are used to drive LEDs and PWM0 drives the speed of a DC fan.
This work is licensed under a Creative Commons Attribution-NonCommercial 4.0 International License.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 |
import piplates.DAQCplate as DAQC import RPi.GPIO as GPIO import time from Tkinter import * import tkFont def task(): global lastT global lastR global lastSW global swMode global GC adata=DAQC.getADCall(0) val=round(DAQC.getADC(0,8),1) Power5Text.set(val) val=round((adata[1]-2.73)*100,2) val=0.2*val+0.8*lastT lastT=val TempText.set(str("{:>3.1f}".format(val))+'C') val=round(adata[2]*12.21/1.636,1) Power12Text.set(val) val=round(adata[0]/4.096*100,1) FanText.set(str(val)+'%') DAQC.setPWM(0,0,int(val*1024/100)) val=DAQC.getRANGE(0,6,'c') if isinstance(val,float): if val>100: val=99.9 else: val=0 val=round(val,1) val=0.8*lastR+0.2*val lastR=val RangeText.set(str("{:>2.1f}".format(val))+'cm') lamp=0 if(DAQC.getDINbit(0,2)==1): lamp=32 sw=DAQC.getSWstate(0) if (sw==1) and (lastSW==0): lastSW=1 swMode = not swMode if swMode: GCmode.set('Binary Code :') else: GCmode.set('Grey Code :') if (sw==0) and (lastSW==1): lastSW=0 val=(int(adata[7]*32/4.096)) if swMode == 0: GCText.set(GC[val]) num=GC[val] else: GCText.set(val) num=val DAQC.setDOUTall(0,(num+lamp)) root.after(100,task) def shutdown(): DAQC.CLOSE() root.destroy() root.quit() root = Tk() root.config(bg="black") root.attributes("-fullscreen", True) #swidth=root.winfo_screenwidth() #sheight=root.winfo_screenheight() ##Create Fonts big = tkFont.Font(family='Helvetica', size=100, weight='bold') title = tkFont.Font(family='Helvetica', size=60, weight='bold') heading = tkFont.Font(family='Helvetica', size=55, weight='bold') normal = tkFont.Font(family='Helvetica', size=20, weight='bold') ##Create Gray Code GC=[0x00,0x01,0x03,0x02,0x06,0x07,0x05,0x04,0x0C,0x0D,0x0F,0x0E,0x0A,0x0B,0x09,0x08,0x18,0x19,0x1B,0x1A,0x1E,0x1F,0x1D,0x1C,0x14,0x15,0x17,0x16,0x12,0x13,0x11,0x10] tf=Frame(root,padx=4,pady=4,bd=2,relief='sunken',bg='#000000888').grid(row=2,column=0,sticky=E+W+N+S) logo = PhotoImage(file = '3D-ppLogo-WIDE.gif') pp=Label(tf,image=logo,bg="White").grid(row=0,column=0,columnspan=2) Label(tf, text="DAQCplate Data Acquisition and Control", bg='White',fg='#000888000',font=title,anchor=CENTER).grid(row=1,column=0,columnspan=2,sticky=E+W) lastSW=1 lastMode=0 swMode=0 lastT=25 TempText=StringVar() TempText.set('25') Label(tf, text="Temperature: ", bg='#000000888',fg='White',font=big,anchor=E).grid(row=2,column=0,sticky=E+W) Label(tf, textvariable=TempText, bg='#000000888',fg='White',font=big,anchor=W).grid(row=2,column=1,sticky=E+W) lastR = 140 RangeText=StringVar() RangeText.set('0.0') Label(tf, text="Range: ", bg='#000888000',fg='White',font=big,anchor=E).grid(row=3,column=0,sticky=E+W) Label(tf, textvariable=RangeText, bg='#000888000',fg='White', font=big,anchor=W).grid(row=3,column=1,sticky=W+E) FanText=StringVar() FanText.set('0.0') Label(tf, text="Fan Speed: ", bg='#888000000',fg='White',font=big,anchor=E).grid(row=4,column=0,sticky=E+W) Label(tf, textvariable=FanText, bg='#888000000',fg='White', font=big,anchor=W).grid(row=4,column=1,sticky=W+E) Power5Text=StringVar() Power12Text=StringVar() GCText=StringVar() GCText.set('0') GCmode=StringVar() GCmode.set('Grey Code :') Label(tf, text="5VDC Voltage: ", bg='#888888000',fg='White',font=heading,anchor=E).grid(row=6,column=0,sticky=E+W) Label(tf, textvariable=Power5Text, bg='#888888000',fg='White', font=heading,anchor=W).grid(row=6,column=1,sticky=W+E) Label(tf, text="12VDC Voltage: ", bg='#888000888',fg='White',font=heading,anchor=E).grid(row=7,column=0,sticky=E+W) Label(tf, textvariable=Power12Text, bg='#888000888',fg='White', font=heading,anchor=W).grid(row=7,column=1,sticky=W+E) Label(tf, textvariable=GCmode, bg='#000888888',fg='White',font=heading,anchor=E).grid(row=5,column=0,sticky=E+W) Label(tf, textvariable=GCText, bg='#000888888',fg='White', font=heading,anchor=W).grid(row=5,column=1,sticky=W+E) close_button = Button(tf, text="X", command=shutdown).grid(row=7,column=1,sticky=E) root.wm_protocol("WM_DELETE_WINDOW", shutdown) root.after(100,task) root.mainloop() |
Although there's little if any commenting, the code should be a good starting point to learn Tkinter.
Remote Data Acquisition and Control Using Weaved and the DAQCplate
Quite often we need to access our computers remotely. But for most of us, this can be difficult to do since it involves having to add port forwarding rules to the firewalls in our routers. Now, thanks to Weaved, it's a cinch to access your Raspberry Pi when you're away from home. Now it's easy to do things remotely like monitor the temperature at home, turn on the crock pot, power up some lights, or check out the activity on a camera module. Remote access can even come in handy when you're traveling and you need to help out one of your customers with a setup issue which happened to us last week.
Let's do something simple like remotely monitoring the temperature of our lab. First connect a DS18B20 temperature sensor to Digital Input 0 on a DAQCplate as described here. Next, click the Weaved image below, sign up for an account, and follow the instructions for installing the SSH service on your Raspberry Pi. Believe us, it won't take long.
After the installation is complete, go back to the Weaved web site and sign in to your account. You will then be directed to a page that displays "Your current list of devices." followed by the options "Connect | Delete". Click on "Connect" and POW, an SSH shell to your RPI will show up in your browser:
How cool is that? You might be typing this at home right now but remember, you can now open a secure shell to your Raspberry Pi from anywhere with an internet connection. OK, we're connected so let's see what the temperature is in the lab. Our DAQCplate is at address 0 and the temperature sensor is on digital input 0 so, we get the following:
It's 70.9F in the lab and while it might be just a touch warm, it doesn't appear that anything is on fire. So there it is, simple remote access to a DAQCplate Pi-Plate using the Weaved service. You might also experiment using their VNC service as well so you can remotely access your x-windows environment.
Driving a Unipolar Stepper Motor with a DAQCplate Pi-Plate
Stepper motors are versatile devices that allow precise and repeatable angular control. They are used in disk drives, translation tables, and 3D printers to name just a few applications. They typically come with two different wiring arrangements. The most common arrangement is four wires that are connected to two coils. This is called a bipolar motor and requires something called an "H" bridge to control. The other arrangement is five or six wires. These are called unipolar motors and they're much easier to drive.
In this example, we will be using four of the seven open collector outputs on a DAQCplate to drive a small, unipolar motor. The motor which can be purchased from Amazon (here) or Adafruit, has the following specifications:
- Unipolar stepper with 0.1" spaced 5-pin cable connector
- 32 steps per revolution
- 1/16.025 geared down reduction
- 5V-12V DC suggested operation
- Weight: 37 g.
- Dimensions: 28mm diameter, 20mm tall not including 9mm shaft with 5mm diameter
- 9" / 23 cm long cable
- Holding Torque @ 12VDC: 250 gram-force*cm, 25 N*mm/ 3.5 oz-force*in
- Shaft: 5mm diameter flattened
The motor is labeled to operate at 12VDC but to make this easy, we're going to start by driving it at 5V. Use the following diagram to make your connections:
The connections all go to the DOUT terminal block and are as follows:
- Motor RED wire: Terminal 10
- Motor BLUE wire: Terminal 2
- Motor PINK wire: terminal 5
- Motor ORANGE wire: terminal 4
- Motor YELLOW wire: terminal 3
- Connect a wire from terminal 1 to terminal 9 - this is IMPORTANT since it shunts the inductive kick generated when a coil is turned off.
Using an ohmmeter, we measured about 100 ohms between the red center tap wire and the blue wire. If we use the 5VDC from the DAQCplate and assume that the "on" voltage of the open collector driver is 1 volt then we can calculate that each driver will have to sink about (5-1)/100 = 40mA. So, no special power supplies should be required for this experiment.
To determine the driving sequence, we referenced this Application Note from SiLabs. Now, open NANO and enter the following lines of code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
import piplates.DAQCplate as DAQC import time delay =0.004 try: while(1): for i in range(0,1000): DAQC.setDOUTall(0,0x0A) time.sleep(delay) DAQC.setDOUTall(0,0x06) time.sleep(delay) DAQC.setDOUTall(0,0x05) time.sleep(delay) DAQCp.setDOUTall(0,0x09) time.sleep(delay) for i in range(0,1000): DAQC.setDOUTall(0,0x09) time.sleep(delay) DAQC.setDOUTall(0,0x05) time.sleep(delay) DAQC.setDOUTall(0,0x06) time.sleep(delay) DAQC.setDOUTall(0,0x0A) time.sleep(delay) except KeyboardInterrupt: time.sleep(.1) DAQC.setDOUTall(0,0) print "Game over, man." |
Save your program as UnipolarTest.py and then run it from the command line with the following statement: sudo python UnipolarTest.py
If everything is correct, you should see your motor shaft rotate counterclockwise for about 16 seconds and then rotate clockwise for 16 seconds. This sequence will repeat until you press <CNTL-C>. While it's running, try grabbing the shaft. and note that while it is a geared down motor it doesn't provide a lot of torque at 5VDC. As an experiment, we disconnected the red wires from terminals 9 and 10 and connected them to a 12VDC power supply. Needless to say, the motor torque was substantially higher.
So, there you go, another example of the possible uses of a DAQCplate!
Interfacing the Pi-Plates DAQCplate with the Spark Core
Introduction
The DAQCplate from Pi-Plates.com is an inexpensive yet powerful solution for expanding the input/output capabilities of the Spark Core. And since Pi-Plates are stackable, it is a simple task to scale up the I/O capabilities of a single Core. All that is required for connectivity are the four SPI signals (signals A2-A5) as well as a single digital output (D6). Power can come from the Core or from the DAQCplate.
Required Components
To build this assembly the following components are required:
- A DAQCplate from Pi-Plates.com
- A Spark Core
- A 5VDC power supply or the USB power supply included with the Core.
- A small protoboard (currently included with the Core Evaluation kit)
- Jumper wires
Connections
The following diagram shows how the DAQCplate and the Core board are connected. This implementation uses an external 5VDC supply that provides power for the Core through the DAQCplate. This approach allows you to drive peripherals with the open collector pins that would pull more than 1 amp. If you’re just playing around, use the USB power supply that came with your Core.
The connections are as follows:
DAQCplate Connections |
Core Connections | ||
Description | Pin Number | Description | Wire Color |
+5VDC | 2 | VIN | RED |
GND | 6 | GND(1) | BLACK |
GND | 9 | GND(2) | BLACK |
3.3VDC | 1 | 3V3 | ORANGE |
MOSI | 19 | A5 | YELLOW |
MISO | 21 | A4 | MAGENTA |
SCK | 23 | A3 | BLUE |
SS | 26 | A2 | GREEN |
ppFRAME | 22 | D6 | VIOLET |
Code
Structure
All Spark applications for the DAQCplate require three files:
- ccp – a lightweight set of library functions
- h – the header file with all of the function prototypes
- ino – your application program
The application program has to have the following structure:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
#include "DAQCplate.h" extern int ppFRAME; //____DAQCplate I/O ports that are initialized below extern int ppCE; // void setup() { SPI.begin(); //\ SPI.setClockDivider(SPI_CLOCK_DIV64); //\\ SPI.setDataMode(SPI_MODE0); //\\\___All of these function are required for //-------initializing the SPI/Pi-Plate interface pinMode(ppFRAME,OUTPUT); ///// pinMode(ppCE,OUTPUT); //// digitalWrite(ppCE,HIGH); /// //initialization for your application variables go below: } void loop() { // Your application code } |
Here’s an example of a program that makes the LEDs on the DAQCplate count in binary. It also reads the value of the 5VDC supply and saves it to an integer variable which is exposed with the name of “Voltage” for external access:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
#include "DAQCplate.h" int adData; extern int ppFRAME; //____DAQCplate I/O ports that are initialized below extern int ppCE; // void setup() { SPI.begin(); //\ SPI.setClockDivider(SPI_CLOCK_DIV64); //\\ SPI.setDataMode(SPI_MODE0); //\\\___All of these function are required for //-------inititaing the DAQCplate interface pinMode(ppFRAME,OUTPUT); ///// pinMode(ppCE,OUTPUT); //// digitalWrite(ppCE,HIGH); /// Spark.variable("Voltage", &adData, INT); //Expose voltage: Test for reading variable } void loop() { byte addr; // declare address of DAQCplate board - values can range from 0 to 7 addr=0; // set address to 0 for (int i=0;i<128;i++) // perform 128 times { setDOUTall(addr,i); // write index value to DAQCplate Digital Output (DOUT) delay(10); // Wait 10msec } adData=getADC(0,8); // Read the power supply voltage (on channel 8 of the ADC) and write to // adData } |
The most recent DAQCplate.cpp and DAQCplate.h library files are available from: https://pi-plates.com/downloads/spark-DAQCplate.zip
Reference
As mentioned earlier, the function library for the DAQCplate is lightweight. However, there are enough calls to access all of the major features. For more information about all of the features of the DAQCplate, visit www.pi-plates.com. Common to all functions is an address argument with most functions requiring at least one parameter.
- void setDOUTall(byte addr, byte value) – write to all 7 open collector channels. The address value (addr) can range from 0 to 7. The value can range from 0 to 127.
- void setDOUTbit(byte addr, byte bit) – set a single open collector bit. The address value (addr) can range from 0 to 7. The bit can range from 0 to 6.
- void clrDOUTbit(byte addr, byte bit) – clear a single open collector bit. The address value (addr) can range from 0 to 7. The bit can range from 0 to 6.
- void toggleDOUTbit(byte addr, byte bit) – toggle a single open collector bit. The address value (addr) can range from 0 to 7. The bit can range from 0 to 6.
- int getADC(byte addr, byte channel) – perform a 10-bit A/D conversion. The address value (addr) can range from 0 to 7. The channel can range from 0 to 8. Note that the A/D range is 0 to 4.097 volts and that channel 8 is the power supply voltage.
- byte getDINall(byte address) – returns an 8-bit number showing the current signal status on the Digital Input block. The address value (addr) can range from 0 to 7.
- byte getDINbit(byte addr, byte bit) – returns the value of a single input bit (0 or 1). The address value (addr) can range from 0 to 7. The bit can range from 0 to 7.
Wrap-up
The Spark Core is a small yet powerful microcontroller that has the potential of becoming the go-to device in the IoT arena. Merging it with a DAQCplate from Pi-Plates using the steps above makes it an even more versatile tool.
Streaming Sensor Data from a DAQCplate Pi-Plate Using InitialState
Introduction
The Pi-Plates DAQCplate Data Acquisition and Control board is an ideal interface between sensors and a Raspberry Pi. With eight analog and eight digital inputs, up to sixteen channels of real world data can be captured by a single DAQCplate Pi-Plate. But, what can you do with that data? You can use it to control a process by turning around and driving the Digital and Analog outputs on the board but chances are you will also want the ability to monitor it. Furthermore, the beauty of small, inexpensive single board computers (SBC) like the Raspberry Pi, is that they can be used in remote locations without a keyboard or a monitor. All they need is a source of power, and a WiFi adapter. Using a SBC in this way is referred to as a “headless” setup.
So that’s our plan: use a headless Raspberry Pi collecting sensor data in a remote location. Our options for viewing the data include:
- Watching individual readings scroll down our screen (boring)
- Saving data to a local file and then viewing the data later using a spreadsheet application or the matplotlib – sounds a lot like work
- Use InitialState to stream our data to the cloud and then look at beautiful plots of it in real time. This is how all the cool kids are doing it these days.
In this article we’re going to use option 3 to monitor two DS18B20 sensors measuring the ambient temperature in a storage closet as well as the temperature in a refrigerator used for keeping solder paste chilled.
Stuff You Need
InitialState Access and Python Library
To begin, head to www.InitialState.com and apply for an account. While you’re waiting for approval, install their python module on your Raspberry Pi. We prefer to use pip since it makes life so easy. Go here to learn more about pip: https://pypi.python.org/pypi/pip. From the command prompt, type:
sudo pip install ISStreamer
Once you have access to the InitialState service, you’re ready to start.
Hardware
To collect the temperature data we will use the following:
- A Raspberry Pi which has been preloaded with the DAQCplate Python module. Go here if you need to perform this step.
- A DAQCplate from Pi-Plates.com
- Two DS18B20 temperature sensors. We got ours here at Amazon.
- Two 4.7K ohm resistors. Available from Radio Shack, Digikey, and Mouser to name a few.
- Hookup wire
- A proto-board for quick and dirty or a PROTOplate for a semi permanent setup.
Build
Hardware
Using the materials called out above, connect the components as shown below:
Note: we were out of luck when we went looking for the 4.7K resistors so ended up putting two 10K resistors in parallel.
Software
First you will need to create a new logging Client Key from your Initial State account. After you’ve done this, use your favorite text editor on your Raspberry Pi (this is Nano for most people) and type in the following program:
1 2 3 4 5 6 7 8 9 10 11 |
import time import piplates.DAQCplate as DAQC from ISStreamer.Streamer import Streamer logger = Streamer(bucket="Lab Temperature Data", client_key = "YourClientKeyHere") logger.log("Lab Temperature Data", "Stream Starting") while(1): tFridge=DAQC.getTEMP(0,1,'f') logger.log("Cooler", tFridge) tAmbient=DAQC.getTEMP(0,0,'f') logger.log("Ambient", tAmbient) time.sleep(300) |
Save the above in your home directory as tempLOG.py, launch your program from the command prompt with the command sudo python tempLOG.py, and verify that no errors occur.
What’s happening in this code? Well first, we import three modules that we will need: time, piplates.DAQCplate and ISStreamer.Streamer. Then we create a stream to the InitialState data logger with:
logger = Streamer(bucket="Lab Temperature Data", client_key = "YourClientKeyHere")
After that, we go into an infinite loop and use DAQC.getTEMP to read the two DS18B20 temp sensors. After each read, we “log” the data along with a label to our log file at InitialState. We sleep for 300 seconds (5 minutes) and then we take another measurement.
Examining the Log Data
You can start looking at your data right away but there won’t be much to see until a few hours have passed. Once you’re ready, log into your Initial State account. After you’ve completed that step you’ll be taken to your own page where you can access and view your log data:
You should have a log file called “Lab Temperature Data”. Click that and then click the button that says “Source.” You will then be presented with some pretty boring lines of raw data from your Raspberry Pi that looks like:
DateTime,SignalSource,OriginalPayload
2014-12-18T15:50:57.837852Z,"Lab Temperature Data","Stream Starting"
2014-12-18T15:50:58.841351Z,Cooler,37.6
2014-12-18T15:50:59.844371Z,Ambient,69.55
2014-12-18T15:56:00.947597Z,Cooler,36.5875
2014-12-18T15:56:01.950743Z,Ambient,68.7625
2014-12-18T16:01:03.052842Z,Cooler,36.5875
2014-12-18T16:01:04.056015Z,Ambient,68.65
2014-12-18T16:06:05.104770Z,Cooler,36.925
2014-12-18T16:06:06.108063Z,Ambient,68.65
2014-12-18T16:11:07.211310Z,Cooler,37.6
2014-12-18T16:11:08.214343Z,Ambient,68.65
2014-12-18T16:16:09.319658Z,Cooler,38.1625
2014-12-18T16:16:10.322882Z,Ambient,68.65
2014-12-18T16:21:11.426134Z,Cooler,38.6125
2014-12-18T16:21:12.429228Z,Ambient,68.65
Not very interesting is it.
Now click the “Wave” button and you should see something much prettier. Here is what I had after about 18 hours of monitoring. To get this plot, I went into the Tools (that little gear icon) and hid the first line labeled “Lab Temperature Data.” Then, while still in Tools, I used the Amplify Signal+ feature to increase the size of each “waveform” until they filled the screen. Then, I clicked on the “Units” button and selected hours. Finally, I dragged to cursors to the beginning and end of the log.
So now we have our pretty plot courtesy of InitialState. The refrigerator data is on the top and the closet temperature is on the bottom. What conclusions can we draw?
- The refrigerator cycles the compressor periodically to maintain the temperature. By dragging the cursors to the appropriate locations we can measure the period of this cooling cycle as 0.6 hours or 36 minutes.
- Also by dragging the cursor we can see that the refrigerator temperature swings from about 36.5 to 38.6 degrees Fahrenheit. This is good for solder paste but not so much for beer.
- We can observe that at about the 11 hour mark, the thermostat in the lab switched to night mode and the closet temperature started to ramp down
- We can observe that about the 18 hour mark, the heat came back on and the closet temperature started ramping back up.
- The most interesting thing though is the fact that the cooler temperature droops a little during the night. This indicates a lack of good temperature regulation and a waste of energy.
There are more toys to play with on your log page. With one of your waveforms selected, click on the “Stats” button. Here’s what we got:
On the left is a detailed histogram of all of the Cooler data as well as some basic statistical values. Here we can see our maximum, minimum, and average values. While the average is 37.28 degrees, the histogram also tells us the values 36.54 to 36.69 occur most frequently – this measurement is called the “mode”. The chart on the right also reflects the mode data.
Wrap Up
In this example we learned how to connect the DS18B20 temperature sensor to a Pi-Plates DAQCplate, how to stream the data to a log file at InitialState.com, and how to manipulate and examine our data after we streamed it.
This is just a simple example of what can be accomplished with these simple components. There’s plenty of other phenomena that can be measured and logged- things like humidity, sound, light, air pressure, resistance, distance, voltage, current, weight, and strain just to name a few.