Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
Project Chapters
1.
2.
3.
4.
5.
6.
Streaming Temperature
7.
Baking a Turkey
8.
9.
CHAPTER
Getting Your Monitor to Work
I made sure everything was hooked up properly, turned on my monitor and then
powered up the Pi. Andnothing happened. Instead of the beautiful Raspberry
SVG popping up on my screen, I saw a No HDMI Input Detected message. I was
confused. I checked the HDMI cable. I checked that the Pi was actually on.
Everything was good. But everything was not good because the most important
Come to find out, Initial States leader wasnt overly generous the monitor was
probably as old as HDMI itself. And after a bit of research, I realized that Pis tend
to have widespread issues not working with older monitors. But Im an engineer,
and I wasnt going to let that stop me. When rebooting failed, I turned to Google
and found out about a very important config.txt file that was the answer to my
problems.
Problem #1:
The monitor is not working with the Raspberry Pi.
Fix:
Change the config.txt file
Problem #2:
NOOBS, Raspberry Pis out-of-box software that came
preloaded on my SD card
Fix:
I decided that the OS I wanted was Raspbian. So I went and downloaded
just Raspbian (this will work for any other OS too). When I unzipped the
file, I now had access to the config.txt file! If you open it up, youll see that
the entire file is commented out:
Result:
The new uncommented lines worked like a charm. My monitor recognized the Pi
CHAPTER
Taking Control of Your Keyboard Layout
Not to worry, I can tell you whats wrong and how to fix it.
Note: We love Great Britain they gave us the Pi, after all!
Problem #2:
I have no idea how to change the
keyboard layout
Fix:
sudo -s
apt-get install nano
If you dont have it, get it. Its awesome and will let you do this next step.
Just type in:
sudo -s
nano /etc/default/keyboard
Now we can see this little line in your keyboard layout file that says:
XKBLAYOUT=gb
That stands for Great Britain and Unattainable Pipes. Change it to:
XKBLAYOUT=us"
Once the system is back, you can enjoy your proper keyboard layout!
If youd like an example script to type on your newly formatted keyboard, try
our Performance Monitor you can see how hard youre making your little
board work!
CHAPTER
Pressing Buttons to Light Up LEDs
I chose to use a Raspberry Pi for my project, but the basics can be applied to
other single-board computer platforms like BeagleBone Black, PandaBoard,
MinnowBoard, and UDOO, or even Gumstix COM and Arduino if they have been
outfitted to access the internet and can run Python.
Use the Initial State streamer to debug and monitor your code!
My Supplies
I used a Canakit so all of these pieces minus the monitor were included:
WiFi Adapter/Dongle (can use ethernet cord for hard connection instead)
Breadboard
40-pin GPIO Ribbon Cable (can use 5 individual male-to-female jumper cables instead)
40-pin T-Shaped GPIO to Breadboard Interface Board (not necessary if using jumper
cables)
3 220 Ohm Resistors (to use with the LEDs; 180-2K Ohms is generally a safe range)
2 10K Ohm Resistors (to use with the buttons; 5K-100K Ohms is generally a safe
range)
The Raspberry Pi has power, ground, and programmable GPIO pins. These GPIO
pins are how we are going to communicate button presses and when we want the
LEDs to turn on or off. In the graphic below, you can see my breadboard
connections (everything is crowded at the bottom of the board due to the interface
board taking up the top 20 pins). Connection to any GPIO pin will work, but I will use
my numbering for the examples.
The Raspberry Pi has power, ground, and programmable GPIO pins. These GPIO
pins are how we are going to communicate button presses and when we want the
LEDs to turn on or off. In the graphic below, you can see my breadboard
connections (everything is crowded at the bottom of the board due to the interface
board taking up the top 20 pins). Connection to any GPIO pin will work, but I will use
my numbering for the examples.
import RPi.GPIO as GPIO ## Import library that lets you control the Pi's GPIO pins
from time import sleep ## Import time for delays
Sleep is a command that ignores inputs for the specified amount of time. Youll
As you saw earlier, making the Initial State streamer usable is as easy as:
from ISStreamer.Streamer import Streamer
Every time you run a script with a bucket name a new bucket will be created,
even if that bucket name already exists in your log shelf. You can append to the
same bucket by adding the bucket_key parameter (see below). Any stream with
the same bucket_key will go to the same bucket regardless of bucket name.
Its time to set up the GPIO pins. The first phrase keeps the terminal from
alerting us about GPIO pin use (since we know were using them!).
GPIO.BOARD tells the Pi that you will designate pins by their placement (i.e. the
number in the circle) instead of their name (i.e. GPIO 3). If you want to use the
latter convention, simply replace BOARD with BCM.
GPIO.setup lets the Pi know which pins you are using and whether they will
receive input (buttons) or giving output (LEDs). We will set the LEDs initial
states to off.
Now comes the fun part! We need to initialize some of the parameters well
be using later:
And start our While loop! The code within this loop executes whenever a
statement is True. So the first If statement will execute if GPIO pin 16 (or button
1) receives input (is pressed). The increment variable designates whether the
LEDs will turn on or turn off one-by-one. The state is indicative of how many
LEDs are on currently. We also begin to insert streamer statements!
## Define state 1
if (state == 1):
GPIO.output(7, GPIO.LOW) ## LED on
GPIO.output(11, GPIO.HIGH) ## LED off
GPIO.output(13, GPIO.HIGH) ## LED off
prev_input=2 ## Makes all reset button phrases executable
streamer.log("state",state) ## Stream current state
streamer.log("increment",inc) ## Stream current increment
streamer.log("prev_input",prev_input) ## Stream current prev_input
## Define state 2
elif (state == 2):
This next if statement executes whenever GPIO pin 18 (or button 2) is pressed. It
will either turn all of the LEDs on or off depending on their current state.
## If 1 or 2 LEDs are on
if (state == 1 or 2 and prev_input!=1):
GPIO.output(7, GPIO.LOW) ## LED on
GPIO.output(11, GPIO.LOW) ## LED on
GPIO.output(13, GPIO.LOW) ## LED on
prev_input=1 ## Keeps this phrase from executing when all LEDs are already on
state=3 ## Change state to 3
inc=0 ## Change increment to decreasing
streamer.log("state",state) ## Stream current state
streamer.log("increment",inc) ## Stream current increment
streamer.log("prev_input",prev_input) ## Stream current prev_input
#streamer.log("phrase",1) ## used to see when each phrase was executing
## If no LEDs are on
elif (state == 0 and prev_input!=0):
GPIO.output(7, GPIO.LOW) ## LED on
GPIO.output(11, GPIO.LOW) ## LED on
GPIO.output(13, GPIO.LOW) ## LED on
prev_input=1 ## Keeps this phrase from executing immediately after the state is set to 0
state=3 ## Change state to 3
inc=0 ## Change increment to decreasing
streamer.log("state",state) ## Stream current state
streamer.log("increment",inc) ## Stream current increment
streamer.log("prev_input",prev_input) ## Stream current prev_input
#streamer.log("phrase",2) ## used to see when each phrase was executing
## If all LEDs are on
elif (state == 3 and prev_input!=0):
GPIO.output(7, GPIO.HIGH) ## LED off
GPIO.output(11, GPIO.HIGH) ## LED off
GPIO.output(13, GPIO.HIGH) ## LED off
prev_input=0 ## Keeps this phrase from executing immediately after the state is set to 3
state=0 ## Change state to 0
inc=1 ## Change increment to increasing
streamer.log("state",state) ## Stream current state
streamer.log("increment",inc) ## Stream current increment
streamer.log("prev_input",prev_input) ## Stream current prev_input
#streamer.log("phrase",3) ## used to see when each phrase was executing
Now we can run the code! Pressing Button 1 should light the LEDs up one at a
time, while pressing Button 2 should turn them all on if 0, 1, or 2 LEDs were on or
You can also go to your Initial State account to see your new Double Button
LED bucket! After pressing my buttons a few times, this is what I had to look at:
CHAPTER
Pressing Buttons to Make an LED Blink
Just to show you another neat thing youre now capable of, Im going to walk you
through setting up an LED that starts blinking when you press a button. Learning
how to start and stop an action with button presses and make something alternate
states on its own is great for tackling more complex projects!
WiFi Adapter/Dongle (can use ethernet cord for hard connection instead)
Breadboard
40-pin GPIO Ribbon Cable (can use 5 individual male-to-female jumper cables
instead)
40-pin T-Shaped GPIO to Breadboard Interface Board (not necessary if using jumper
cables)
1 220 Ohm Resistors (to use with the LEDs; 180-2K Ohms is generally a safe range)
1 10K Ohm Resistors (to use with the buttons; 5K-100K Ohms is generally a safe
range)
Now for the software part! If you havent installed the Initial State Streamer yet, its
super fast and easy.
Instructions
1.
Create an Access Key in your Initial State account (can do on the landing page
under Streaming Access Keys). If you dont have an account you can sign up at
https://www.initialstate.com/app/#/register!
2. Turn on your device and make sure you have an internet connection.
3. Type this command into the command line:
4.Follow the prompts if you say Y to the Create an example script? prompt,
then you can designate where youd like the script and what youd like to name it.
Your Initial State username and password will also be requested so that it can
autofill your Access Key. If you say n then a script wont be created, but the
streamer will be ready for use.
5. Either use your example script to get your Access Key or create one from
scratch and start streaming!
import RPi.GPIO as GPIO ## Import library that lets you control the Pi's GPIO pins
from time import sleep ## Import time for delays
from ISStreamer.Streamer import Streamer ## Import the Initial State streamer
Designate the name of your stream and which Initial State account it should go to.
## Streamer constructor, this will create a bucket called Button Blink
## you'll be able to see this name in your list of logs on initialstate.com
## your access_key is a secret and is specific to you, don't share it!
streamer = Streamer(bucket_name=Button Blink", access_key="Your Access Key Here")
pinNumLED = 7
pinNumBTN = 16
GPIO.setup(pinNumLED,GPIO.OUT) ## Tells it that pinNumLED will be outputting
GPIO.setup(pinNumBTN,GPIO.IN) ## Tells it that pinNumBTN will be giving input
Run a while loop to check for button presses and either blink or stop the LED when it
detects one. Note that the sleep sometimes causes button presses not to register
while the LED is blinking. Pressing and holding the button for 1 second should do
the trick.
while True:
try:
input = GPIO.input(pinNumBTN)
Pressing Cntl-C will exit the while loop and stream the final message.
streamer.close() makes sure that all of the logs are streamed before the script
finishes.
except KeyboardInterrupt:
break
In Initial State you can see when the button was first pressed and when the LED turns
on and off.
CHAPTER
Using Pi-Plates to Add Functionality
Using Pi-Plates
If you thought that Raspberry Pis were cool, just wait till you see all of the things you
can add to them to expand their functionality. And if you already knew about all of
the things you can add to them, just wait till you see this one!
Pi-Plates are stackable Raspberry Pi add-on circuit boards that come with all sorts of
goodies. The one I have pictures of here is the ppDAQC board, and it comes with 7
digital outputs, 8 analog to digital inputs, 8 digital inputs, 2 analog outputs and 7
indicator LEDs. My other favorite features are the programmable pushbutton and
bicolor LED (but thats just because Im easily entertained).
To show you how easy it is to set this bad boy up, Im going to tell you how right
now. The Pi-Plate just stacks on top of the Pis GPIO pins. It makes use of the
Pis SPI feature, so make sure that its enabled by entering:
sudo nano /etc/modprobe.d/raspi-blacklist.conf
If you dont already have the SPI and GPIO libraries, youll need to update
mkdir python-spi
cd python-spi
wget https://raw.github.com/doceme/py-spidev/master/setup.py
wget https://raw.github.com/doceme/py-spidev/master/spidev_module.c
sudo python setup.py install
Finally, the ppDAQC module needs to be installed. It uses pip, so if you dont already have
that, be sure to run the first line:
Now lets run a Hello World! The guys at Pi-Plates provide a nice beginner
script that outputs Hello World in ASCII through the built-in LEDs. I
thought this was pretty neat, so I also inserted some streamer statements
so I could see the ASCII values of each letter. Want to try out Initial States
data streamer? See how to install it below.
Instructions:
1. Create an Access Key in your Initial State account (can do on the landing page
under Streaming Access Keys). If you dont have an account you can sign up here!
2. Turn on your device and make sure you have an internet connection.
5. Either use your example script to get your Access Key or create one
from scratch and start streaming!
The script is very simple we just import the ppDAQC module, the
ISStreamer module and time. Then we set up the streamer and a while
loop that converts each letter in Hello World into an ASCII value that is
output to the Pi-Plates LEDs.
## Import the Pi-Plates ppDAQC module
import piplates.ppDAQC as ppDAQC
## Import time for delays
import time
## Import the ISStreamer module
from ISStreamer.Streamer import Streamer
## Streamer constructor, this will create a bucket called Computer Performance
## you'll be able to see this name in your list of logs on initialstate.com
## your access_key is a secret and is specific to you, don't share it!
streamer = Streamer(bucket_name="Pi-Plates Hello World",access_key="[Your Access Key]")
msg='Hello World'
msgLen = len(msg)
streamer.close()
The while loop will run until you interrupt it with Ctrl-C.
You can see the Pi-Plates built-in LEDs lit up in the top left corner of the board. On the right you can see how
ASCII value changes with each letter inside of Initial State.
Now youve made your board light up! Lets use my other favorite built-in feature
the programmable button. The Pi-Plate makes it very very easy to turn this button
into the one thing I always wish my Raspberry Pi had a shutdown button!
First you need to install a program that runs in the background of your Pi called
ppPower. This is easy to do with these commands:
wget http://pi-plates.com/downloads/ppPower-1.00.tar.gz
tar -xzf ppPower-1.00.tar.gz
cd ppPower-1.00
sudo ./install-ppPower
Now you just need to reboot your Pi (sudo reboot), and associate the button with this program. Enter Python with sudo python and
Aaaaaaaand it was that easy to set up a functioning shutdown button! It will work
every time you turn on your Pi with the Pi-Plate attached from here on out. The PiPlate even provides a convenient LED indicator that turns orange while the Pi is
shutting down and red when it is safe to remove the power.
To read more about the button and
what this particular Pi-Plate can do,
CHAPTER
Streaming Temperature
Hello World! This is likely the output of the first program you ever wrote when
learning how to code. Setting up a device to stream temperature data is quickly
becoming the de facto Internet of Things (IoT) Hello World! project. If printing
Hello World! the first time was a long, frustrating task, you might have never written
another program. Your first IoT project should only put a big ol smile on your face.
This fun, easy project will introduce you to the wonderful world of IoT data streaming.
A breadboard for wiring up a simple circuit (in the Adafruit Pi starter kit).
The DS18B20 temperature sensor works well with the Raspberry Pi because it has a
digital output, and the Pi has no on-board analog to digital convertors (ADC). Raspbian
includes an interface to read the output of the sensor. We just have to write a little
code to grab and parse out the temperature. Adafruit has a great tutorial here (and
here for the PDF version) for using the DS18B20 that we are simply going to follow and
modify to stream the temperature instead of just outputting it to the screen.
The hardware setup is simple. DS18B20 red wire to 3.3V. Black wire to GND. Blue
wire to a pull-up resistor and to GPIO pin 4 of your Pi.
The output of your temperature sensor is now being written to a file on your Pi. To
find that file,
cd /sys/bus/w1/devices
In this directory, there will be a sub-directory that starts with 28-. What comes after
the 28- is the serial number of your sensor. cd into that directory. Inside this
directory, a file named w1_slave contains the output of your sensor. The contents of
The number after t= is the number we want. This is the temperature in 1/1000
degrees Celsius (in the example above, the temperature is 26.125 C). We just need
a simple program that reads this file and parses out that number. Lucky for us,
Adafruit already created a Python script for us that does just this and outputs the
temperature to the screen. Create a new file on your Pi (e.g. temperature.py) and
os.system('modprobe w1-gpio')
os.system('modprobe w1-therm')
base_dir = '/sys/bus/w1/devices/'
device_folder = glob.glob(base_dir + '28*')[0]
device_file = device_folder + '/w1_slave'
def read_temp_raw():
f = open(device_file, 'r')
lines = f.readlines()
f.close()
return lines
def read_temp():
lines = read_temp_raw()
while lines[0].strip()[-3:] != 'YES':
time.sleep(0.2)
lines = read_temp_raw()
equals_pos = lines[1].find('t=')
if equals_pos != -1:
temp_string = lines[1][equals_pos+2:]
temp_c = float(temp_string) / 1000.0
temp_f = temp_c * 9.0 / 5.0 + 32.0
return temp_c, temp_f
while True:
print(read_temp())
time.sleep(.5)
Run this script (sudo python temperature.py) to see the output of your temperature
This is the point where we deviate from the Adafruit tutorial. Sending temperature to
the screen is boring. We want to stream this data to somewhere we can see not
only the current temperature but a history of captured temperature data (plus, who
wants to read a bunch of temperatures as text; we want a pretty data visualization).
First install the Initial State streamer to give our temperature measurements a
destination to go to (go here for instructions on setting up the Initial State streamer; it
is super easy and takes less than two minutes). We are going to modify the script
above to stream the temperature to our Initial State account instead of outputting it to
the screen. Here are the modifications:
import os
import glob
import time
from ISStreamer.Streamer import Streamer
streamer = Streamer(bucket_name="Temperature Stream", access_key="PUT YOUR ACCESS KEY
HERE")
os.system('modprobe w1-gpio')
os.system('modprobe w1-therm')
base_dir = '/sys/bus/w1/devices/'
device_folder = glob.glob(base_dir + '28*')[0]
device_file = device_folder + '/w1_slave'
def read_temp_raw():
f = open(device_file, 'r')
lines = f.readlines()
f.close()
return lines
def read_temp():
lines = read_temp_raw()
while lines[0].strip()[-3:] != 'YES':
time.sleep(0.2)
lines = read_temp_raw()
equals_pos = lines[1].find('t=')
if equals_pos != -1:
temp_string = lines[1][equals_pos+2:]
temp_c = float(temp_string) / 1000.0
return temp_c
while True:
temp_c = read_temp()
temp_f = temp_c * 9.0 / 5.0 + 32.0
streamer.log("temperature(C)", temp_c)
streamer.log("temperature(F)", temp_f)
time.sleep(.5)
You will need to copy+paste the access key associated with your Initial State
account in between the quotes on line 6 where it says PUT YOUR ACCESS KEY
HERE. You can find your access key under your account settings or on the landing
Run the modified script (sudo python temperature.py or if you want to set
this to run uninterrupted for a long time, you might want to use the nohup
command nohup sudo python temperature.py > tmp.txt &). I put my
temperature sensor on ice then warmed it back up again in my hand to test
it out. Go to your Initial State account and a new log will show up in your
log shelf called Temperature Stream. View this in Waves or Lines to see
your data streaming in real-time. Here is what my data looked like in Lines.
Now that you can capture and stream temperature data, you have the tools to
stream anything you can capture sensor outputs, software variables, hardware
events, button presses, doors opening, your heart rate, gps data, your hamsters
activity, anything.
CHAPTER
Baking a Turkey
e the
r
a
e
Her
s you
e
i
l
p
sup
eed
will n
An internet connected
Raspberry Pi or your singleboard computer of choice
The Vernier Go!Temp probe has a temperature range of -20C 115C (-4F
239F), convenient since we want our turkey to reach an internal temperature of
71C (160F). However, you do not want to expose the plastic base or cord of the
Go!Temp probe to the ovens high temperatures. This is where the thermal shield
tape comes in. Thoroughly wrap all of the probes exposed plastic that will be inside
of the oven in the thermal shield tape to keep it safe. The wrapped, shielded cord
and Go!Temp probe are the only things that will go in the oven with your turkey
(please do not put your Raspberry Pi in the oven).
Plug your Go!Temp probe into your USB port and start your Pi. At a command
prompt, type lsusb to verify that your Pi sees the probe:
pi@raspberrypi ~ $ lsusb
Bus 001 Device 002: ID 0424:9514 Standard Microsystems Corp.
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 001 Device 003: ID 08f7:0002 Vernier EasyTemp/Go!Temp
Bus 001 Device 004: ID 148f:5370 Ralink Technology, Corp. RT5370 Wireless Adapter
Bus 001 Device 005: ID 046d:c534 Logitech, Inc.
That completes the hardware setup. For the software setup, first install the Initial
State streamer (instructions previously laid out in this eBook) to give your captured
temperature readings a destination to go to. Create a new file on your Raspberry Pi
(e.g. turkey_temp.py) and copy+paste the code below into it. You will need to copy
+paste the access key associated with your Initial State account in between the
quotes on line 6 where it says PUT YOUR ACCESS KEY HERE. You can find your
access key under your account settings or on the landing page once you log into
your account. The code below is all of the code that you will need.
# Stream message
streamer.log("Turkey Says", "Gobble Gobble")
targetTemp = 160
targetReached = False
while True:
# Set sample interval to 5 seconds
time.sleep(5.0)
# Average together the three temperature samples and apply transform: C = Average/126.74 - 5.4
cel = (data[2] + data[3] + data[4]) / 3 / 126.74 - 5.4
fahr = (9.0/5.0 * cel) + 32.0
# Adjusted temperature factor determined empirically
fahrAdj = fahr * 1.16
# Stream it
streamer.log("Temperature(F)", fahrAdj)
if fahrAdj > targetTemp and not targetReached:
streamer.log("Turkey Says", "I am cooked!!")
targetReached = True
Line 6 sets up the destination bucket for our data stream. We will name the bucket
Turkey Temperature. Every time you run this script, a new bucket named Turkey
Temperature will be created under your Initial State account (identified by your
access key), and all data generated from that script run will be contained there. Line
9 streams the first message to the newly constructed stream.
Reading the temperature from the Go!Temp probe (lines 16-32) follows the guide
given at http://finninday.net/wiki/index.php/Vernier_Go_Temp_USB_device_in_Linux.
Every five seconds, eight bytes are read from /dev/ldusb0. Within these eight bytes
are three 2-byte temperature readings from the probe. However, these readings
need to be converted to Celsius/Fahrenheit. After testing the conversion equation
given in the finninday.net tutorial, I realized that my Go!Temp required a bit more
calibration tuning to be accurate. I tested the reading on a few different temperatures
and empirically determined the readings were off by a factor of 1.16 (hence the
adjustment on line 32). I recommend doing similar tests on your Go!Temp probe and
adjusting the conversion accordingly.
Streaming the calculated temperature happens on line 35. If you want to change
how often the temperature is captured and streamed, change the sleep time on line
16.
We are ready for a test run. A good test to run is to capture the temperature change
inside your oven when you preheat it. This will ensure that everything is working
before you mess with your turkey. Set your preheat to something less than 115C
(239F). Do not preheat more than 150C (302F) or you will damage your Go!
Temp probe. Be careful to only put the thermally wrapped and shielded portion of
the probe in the oven and start the preheat cycle. Run the python script at the
command prompt (type sudo python turkey_temp.py).
Log into your Initial State account and a new log will pop up in your log shelf called
Turkey Temperature. View this in Waves or Lines to see your temperature changes.
My test run is shown above when I used my ovens fast preheat option. It took my
oven 6.58 minutes to reach 256F where it then settled back to the target 240F. I
found it Interesting that this option overshoots the target then settles back down. I
decided to do a second test run using my ovens normal preheat option for
comparison. This was a much more surprising result.
I learned that my oven is a liar. After 11 minutes, my oven beeped to tell me that it was
preheated to 240F. The temperature reading was only 184F. For the next 10
minutes, it continued to preheat until it stabilized at 230F. Huh? I have a hard enough
time cooking as it is. I do not need any additional help from my oven to sabotage
dinner.
Once everything is working, you are ready to cook. You will want to place the Go!
Temp probe in the thigh of the turkey but do not touch the bone (b/c the bone heats up
faster than the meat). A nice guide on exactly where to place a meat thermometer in a
turkey can be found at http://karyosmond.com/where-do-you-stick-thermometerturkey. Use a small knife or something sharp as a guide for your probe. Did I mention
that the only thing that should be in the oven besides your turkey is the thermally
wrapped portion of your Go!Temp probe and not your Raspberry Pi? Please dont kill a
perfectly good Pi. You are ready to cook and stream. Once you see that your turkey
has reached its target temperature (160F to 175F depending on whose advice you
take), your bird is cooked. Bon Apptit
**Note This tutorial pushes the Go!Temp probe to its temperature limits. If you cook
your turkey at an oven temperature higher than 150C (302F), your Go!Temp probe
may die. Follow all directions and restrictions listed in your Go!Temp probes
instruction manual.
CHAPTER
Running a Shutdown Button
Script at Boot
If you answered yes to any of those questions, this tutorial has got you covered!
boots
this example)
Aaaaaaaand
Use Initial State to track how long you use your Raspberry Pi from boot to
shutdown
I used a Canakit so all of these pieces minus the monitor, keyboard, and mouse were included:
WiFi Adapter/Dongle (can use ethernet cord for hard connection instead)
Breadboard
40-pin GPIO Ribbon Cable (can use 5 individual male-to-female jumper cables
instead)
1 LED (I used Green)
1 220 Ohm Resistors (to use with the LEDs; 180-2K Ohms is generally a safe
range)
1 10K Ohm Resistors (to use with the buttons; 5K-100K Ohms is generally a
safe range)
You want to
connect
import RPi.GPIO as GPIO ## library that lets you control the Pi's GPIO pins
import os ## allows us to talk to the system like in the terminal
from sys import exit ## allows us to use "exit"
from time import sleep ## allows us to use "sleep"
If you havent imported the GPIO module yet, youll need to enter sudo apt-get install
python-rpi.gpio into the terminal and let it install. The only other import that requires
installation is the Initial State streamer. If you havent installed it yet, its super easy and
takes less than 2 minutes (instructions written in earlier tutorials).
Time to initialize some variables. i is going to keep track of how many times the
This while loop will stream a message when it is running and wait for a button
press. The first if statement will keep a status LED blinking as long as the button
has not been pressed. The else statement will run sudo shutdown -h now as if it
had been entered in the command line. You can change this to be a different
command if you want.
Note: Because of the sleep, you may have to press and hold the button
for half a second to make sure the press is picked up.
Adding exit() at the end will stop the script. If you remove it along with prev_input=1,
the LED will resume blinking and you can press the button to execute the same
command again.
exit() ## terminates this script
There are a couple of ways that you can run a script at a certain time or when something
specific happens. A very easy way to do this is with Cron, a tool that comes ready to use
on Unix systems (like the Pi!). Cron allows you to specify minute, hour, day of month,
month of year and day of week. A more advanced method that also allows you greater
freedom to designate when your script is run is by creating an init (initialization) file.
Because I only needed my script to start at boot, I chose to use Cron. While init files do
allow you greater control, they are much more complicated to write. If youd like to use
In your terminal and hitting enter. You will see a file pop up with a lot of comments. At
the bottom of this file youll want to add the line
@reboot sudo python /home/pi/Streamer/offbutton.py
@reboot tells Cron to execute the line following it once the system has booted up. My
file is named offbutton.py and it is located in my Streamer folder. Youll want to replace
those with the name and location of your file. If its just in the main folder on the Pi, its
location is /home/pi/. Whenever you dont want the script to run just comment out the
line with # and save the file.
Note: You do need to reboot the Pi before this new Crontab will take effect.
Since our script also starts at boot, we had to do this anyways!
The first time I ran this script, it worked beautifully. I saw the LED start flashing a bit
after the Pi had started, and when I pressed the button, my Pi safely shutdown. I then
went over to Initial State to make sure that everything was streaming correctly.
Check out my
visualization
As may be able to tell, something funny is going on! It looks like the code is stuck on
iteration 5 for about 90 seconds. But thats strange because I never noticed the LED
blinking irregularly, and I dont even think that it takes the Pi that long to startup. I
consulted Initial States resident expert (our backend developer, David Sulpy), and he
thought that it might be a time stamping issue. I investigated further, and he was right!!
Turns out that most (if not all) computers utilize a Network Time Protocol daemon (NTP)
to synchronize their clocks over a network since theyre generally not very good at
keeping time themselves. The Pi makes use of this to ensure that, after being
shutdown for an unknown amount of time, it displays the correct time. However, this
So, what exactly are we seeing when the iteration counter sticks at 5? We are seeing
that the Pi starts running our script before it has updated its time. That 90 second gap
is not a physical 90 second period but a 90 second difference between the time the Pi
thought it was and the time the NTPD told the Pi it actually is.
Its good to know that something with our streamer isnt broken, but how do we get ride
of that apparent time skip? Well, we can use a python library called psutil to look for the
NTPD process before starting the main part of our script that way we know that the
time has already been updated. If you dont have psutil installed already, install it by
entering
sudo pip install psutil
First, lets import psutil at the beginning with our other imports:
import psutil ## allows us to look at processes on the Pi
Next were going to want to initialize two new parameters: counter to regulate how long
we look for the NTPD process and found_ntpd. Do this before the while loop, where we
initialized i and prev_input.
Now we need to add a new while loop. This loop will look for ntpd in the list of
processes that psutil.process_iter() returns. If it doesnt find NTPD before the counter
reaches 60 (60 seconds based on our sleep time), then found_ntpd will be set to True
so that the next while loop will run. You want to insert the following code before the
previous while loop:
## this while loop looks to see if NTPD has been executed yet
while found_ntpd == False:
## use psutil to iterate through a list of current processes
for proc in psutil.process_iter():
## only execute if "ntpd" is found
if proc.name() == "ntpd":
streamer.log("msg","Found NTPD") ## stream alert that ntpd was found
streamer.log("psutil_msg",proc.status()) ## stream process status of ntpd; "stream name",
value
found_ntpd=True ## change variable to True to exit this loop
## assume that ntpd has already run if not found in 60 seconds
elif counter>=60:
streamer.log"msg","Search for NTPD timeout") ## stream alert that 60 seconds passed
before ntpd was found
found_ntpd=True ## change variable to True to exit this loop
else:
counter = counter + 1 ## add to the counter to track time passed
streamer.log("counter",counter) ## stream current counter value
sleep(1) ## wait for 1 second
import RPi.GPIO as GPIO ## library that lets you control the Pi's GPIO pins
import os ## allows us to talk to the system like in the terminal
from sys import exit ## allows us to use "exit"
from time import sleep ## allows us to use "sleep"
import psutil ## allows us to look at processes on the Pi
## this while loop looks to see if NTPD has been executed yet
while found_ntpd == False:
## use psutil to iterate through a list of current processes
for proc in psutil.process_iter():
## only execute if "ntpd" is found
if proc.name() == "ntpd":
streamer.log("msg","Found NTPD") ## stream alert that ntpd was found
streamer.log("psutil_msg",proc.status()) ## stream process status of ntpd; "stream name",
value
found_ntpd=True ## change variable to True to exit this loop
## assume that ntpd has already run if not found in 60 seconds
elif counter>=60:
streamer.log"msg","Search for NTPD timeout") ## stream alert that 60 seconds passed
before ntpd was found
found_ntpd=True ## change variable to True to exit this loop
else:
counter = counter + 1 ## add to the counter to track time passed
#streamer.log("counter",counter) ## stream current counter value
sleep(1) ## wait for 1 second
## this while loop constantly looks for button input (presses) once NTPD has run or 60 seconds
have passed
while found_ntpd == True:
streamer.log("msg","Ready for button input") ## stream message
## if no button press
if (GPIO.input(16) == False and prev_input!=1):
i=i+1 ## iteration count increases by 1
streamer.log("iteration",(i)) ## stream current iteration
GPIO.output(7,True) ## switch on pin 7 (LED)
sleep(0.5) ## wait for 0.5 second
GPIO.output(7,False) ## switch off pin 7 (LED)
sleep(1) ## wait for 1 second
If you reboot your Pi so that the script starts running again, you should see something
like what I have below:
This time its the counter that shows the time-keeping hiccup. You can see that the NTPD
process is found after about 58 seconds, and then the main portion of our script begins
running. If you comment out streamer.log(counter, counter), the hiccup becomes invisible
and our script only runs once NTP has updated the Pis clock.
A shutdown button is pretty handy, but you could run a number of other useful scripts at
boot (though the Pi cant handle too much!). An interesting application would be
running our monitoring script in the background while you use the Pi and seeing how
much processing power your project takes!
CHAPTER
Building a Mobile GPS Streamer
I decided to apply this awesomeness to Adafruits Ultimate GPS Breakout Board so that I
could take the GPS and the Pi anywhere I wanted.
On the breadboard with the GPIO interface board, you want to connect:
One row of the first button to GPIO 23 (pin 16) and a 10K resistor;
the other end of the resistor should be connected to ground
One row of the second button to GPIO 24 (pin 18) and a 10K
resistor; the other end of the resistor should be connected to
ground
The long leg of the blue LED to a 220 resistor; the other end of the
resistor should be connected to the voltage source
The long leg of the red LED to a 220 resistor; the other end of the
resistor should be connected to the voltage source
Connect RX to the USB cables green line
Now just plug the USB cable into the Pi and youre ready to start in on the
terminal action!
The first thing we need to do is make sure that the Pi recognizes your GPS
through the USB port. It is a ttyUSB device, so entering
ls /dev/ttyUSB*
should return a list of all of these devices. Your USB cable is probably the only
one, so you should see /dev/ttyUSB0 as the output.
sudo lsusb
will show you a list of all USB devices. Your cable will appear as Prolific Technology,
Inc. PL2303 if you purchased the one I listed.
Next we need to install some GPS software that will interpret the data coming from our
GPS. To install the GPS Daemon, enter this into the terminal (make sure your Pi has
internet):
sudo apt-get install gpsd gpsd-clients python-gps
After gpsd has installed, you can check to make sure that your GPS is working/has a
fix by running
sudo gpsd /dev/ttyUSB0 -F /var/run/gpsd.sock
The first time I tried to see my GPS data, cgps kept timing out because I couldnt get a
fix. If youre not sure if your problem is finding a fix or not, run
gpsmon
to see raw GPS data. If $GPRMC has a V following it, then you dont have a fix and
need to move your GPS somewhere less obstructed from the sky. If $GPRMC has an
A following it, then you do have a fix, but a different problem.
You may need to kill and reset gpsd once you get a fix for cgps to work. You can do
this by running
Once cgps is displaying good gps data, youre ready to do something fancy with gpsd
in a script!
Now, since our end goal is to have this all run when the Pi boots up, itd be best if we
didnt have to run sudo gpsd /dev/ttyUSB0 -F /var/run/gpsd.sock to point to the USB
port every time. We can fix this by editing /etc/default/gpsd. Some of these may be
filled in already, but you want it to look like this:
Save it with CTRL-X, and gpsd will automatically look at the USB port for your GPS on
boot.
We do need to install a couple more modules before were ready to write our script.
The GPIO module lets us interface with the Pis GPIO pins so that we can control the
LEDs and sense button inputs. Install it with
I also wanted to know the actual location that my latitude and longitude corresponded
to, so I used a geocoding library called Geopy. Install it with
Lastly, you want to install the Initial State streamer so that you can visualize your GPS
data without needing to look directly into the Pi. Its super easy and takes less than 2
minutes. Instructions are explained earlier in this eBook.
First we need to import everything.
There is some initialization too handling the geocoder, gps, GPIO pins and the
streamer (which I called logger).
This function is to handle unhandled exceptions by turning off the LED and exiting the
script. This way you can know if your GPS script has given up on you!
## this function will handle any exceptions we don't account for below
## the LED will turn off to tell us that the script has exited
def handleTheUnhandled(type, value, traceback):
logger.log("msg","The Unhandled was handled") ## stream that an unexpected exception
occured
GPIO.output(7,GPIO.HIGH) ## turn off the LED
exit() ## exit the script
## when an exception happens that we don't account for, call our script
sys.excepthook = handleTheUnhandled
try:
while True:
gpsd.next()
os.system('clear') ## clear the terminal window to display GPS data
## this is handy to see when making sure the script works
print
print ' GPS reading'
print '----------------------------------------'
print 'latitude ' , gpsd.fix.latitude
print 'longitude ' , gpsd.fix.longitude
print 'time utc ' , gpsd.utc,' + ', gpsd.fix.time
print 'altitude (m)' , gpsd.fix.altitude
print 'eps
' , gpsd.fix.eps
print 'epx
' , gpsd.fix.epx
print 'epv
' , gpsd.fix.epv
print 'ept
' , gpsd.fix.ept
print 'speed (m/s) ' , gpsd.fix.speed
print 'climb
' , gpsd.fix.climb
print 'track
' , gpsd.fix.track
print 'mode
' , gpsd.fix.mode
print
print 'sats
' , gpsd.satellites
## stream whatever you'd like to collect from the gps
logger.log("Latitude",gpsd.fix.latitude)
logger.log("Longitude",gpsd.fix.longitude)
logger.log("Reported Time",gpsd.utc,)
logger.log("Altitude (m)",gpsd.fix.altitude)
logger.log("Climb (m/s)",gpsd.fix.climb)
logger.log("Lat Error",gpsd.fix.epy)
logger.log("Long Error",gpsd.fix.epx)
logger.log("Timestamp Error",gpsd.fix.ept)
logger.log("Speed (m/s)",gpsd.fix.speed)
logger.log("Speed Error",gpsd.fix.eps)
## the geolocator requires a string so we turn lat and long into one
coord=str(gpsd.fix.latitude) + ", " + str(gpsd.fix.longitude)
location=geolocator.reverse(coord,timeout=10) ## reverse geocode coordinates
logger.log("Location",location.address)
## if the geocoder times out, stream a message and keep looping
except GeocoderTimedOut as e:
logger.log("msg","Geocoder Timeout")
pass
## if you press CTRL-C or the systeme exits, print a message and close everything
except (KeyboardInterrupt, SystemExit): #when you press ctrl+c
print "\nKilling Thread..."
GPIO.output(7,GPIO.HIGH) ## turn LED off
logger.close() ## send any messages left in the streamer
gpsd.running = False
gpsd.join() ## wait for the thread to finish what it's doing
print "Done.\nExiting."
exit() ## exit the script
The except statements will let us stop the script while testing it and keep it running if
the geocoder times out.
There is one more script we need if we want to be able to safely shutdown the Pi
without being able to execute the command in the terminal. I discussed this in more
detail in my previous blog post, but I have slightly edited my original script for this use
case. The main difference is the sub.Popen(sudo python /home/pi/navigation.py,
shell=True) line. This runs the navigation script from the offbutton.py script. This was
my solution to wanting to run two scripts at boot, but there are a couple of other ways
to accomplish roughly the same thing.
import RPi.GPIO as GPIO ## library that lets you control the Pi's GPIO pins
import os ## allows us to talk to the system like in the terminal
from sys import exit ## allows us to use "exit"
from time import sleep ## allows us to use "sleep"
import subprocess as sub ## allows us to call another script
## allows us to use the Initial State streamer
from ISStreamer.Streamer import Streamer
## designate bucket name and individual client_key
## a new bucket will be created with every script run
## the client_key tells Initial State which account to send the data to
## specify .ini file location if you are using one that affects the streamer
logger = Streamer(bucket_name="Shutdown", client_key="[Your Client Key Here]",
ini_file_location="/home/pi/isstreamer.ini")
## create files for logging stdout and stderr
#output_file = open("/home/pi/navdebug.out", "w")
#error_file = open("/home/pi/navdebug.err","w")
## add "stdout=output_file,stderr=error_file" to pipe to files
sub.Popen('sudo python /home/pi/navdebug.py', shell=True)
I left the statements I used for debugging commented out in the script in case you might need them. All
that they do is specify files to write the standard output and standard error of the navigation.py script to.
So you have the scripts, but how do we get them to run automatically when the Pi boots up? There are
a couple of ways that you can run a script at a certain time or when something specific happens. A very
easy way to do this is with Cron, a tool that comes ready to use on Unix systems (like the Pi!). Cron
allows you to specify minute, hour, day of month, month of year and day of week. A more advanced
method that also allows you greater freedom to designate when your script is run is by creating an init
(initialization) file.
Because I only needed my script to start at boot, I chose to use Cron. While init files
do allow you greater control, they are much more complicated to write. If youd like to
in your terminal and hitting enter. You will see a file pop up with a lot of
comments. At the bottom of this file youll want to add the line
@reboot sudo python /home/pi/Streamer/offbutton.py
@reboot tells Cron to execute the line following it once the system has booted up. My
file is named offbutton.py and it is located in my Streamer folder. Youll want to
replace those with the name and location of your file. If its just in the main folder on
the Pi, its location is /home/pi/. Whenever you dont want the script to run just
comment out the line with # and save the file.
Note: You do need to reboot the Pi before this new Crontab will take effect.
Since our script also starts at boot, we had to do this anyways!
Now that your scripts will run automatically when you boot the Pi, you have LED status
indicators, and a portable power bank, we are almost ready to hit the ground running. The
only thing that we havent taken care of yet is how to maintain an internet connection.
Its surprisingly easy to get your Pi to automatically connect to a specific WiFi. In my case, I
wanted it to connect to my iPhones hotspot (the ssid will obviously differ). You need to edit /
etc/wpa_supplicant/wpa_supplicant.conf and make this the first network:
network={
ssid="iPhone"
psk="password"
key_mgmt=WPA-PSK
}
Save the file and go to /etc/network/interfaces. If you dont see auto wlan0, add it.
Youre good to go! Just make sure that your phones personal hotspot is turned on and
power on your Pi. I drove around with my Pi running and could see this in Initial States
Waves:
Pretty sweet, huh? A cool addition to this project would be a neat way to bundle all of
the equipment into a case of some sort.
CHAPTER
Building a Hamster Fitness Tracker
10
A laser break beam sensor (such as this sensor from Adafruit https://
www.adafruit.com/product/2122).
A breadboard for wiring up a simple circuit (such as the one found in the
Two pull-up resistors (one 220 ohm resistor and one 10K ohm resistor, also
A hamster cage with a running wheel that is outside the main living area (to
avoid ever shining a laser into your hamsters eyes). Here is an example
cage.
A hamster.
The measurement system is very simple. The laser break beam sensor will be
aimed at a small target on the wheel that will only reflect the beam once per full
rotation of the wheel. The Pi will detect each time the wheel turns a full rotation and
calculate the distance traveled and speed (the distance traveled is simply the
circumference of the wheel). The resulting measurements will be captured and
streamed to a data visualization that you can look at when you wake up each
morning (because your hamster is probably getting his workout on while you sleep at
night).
The laser break beam sensor from Adafruit is a good choice for this project because
of its simplicity to wire up and use. No extra weight will be added to the wheel to
make it harder to spin for your 2 oz. dwarf hamster. Both the laser transmitter and
receiver are built into the same small plastic housing. If the laser beam reflects off of
a target within 1 meter or so, the receiver detects and outputs the break.
This is much better than a traditional laser break sensor that requires a separate
receiver that must be aligned to the laser (like your garage door sensor that can
easily get off track if you touch it). The laser break beam sensor will have three
wires to attach. Attach the red wire to 5V. Attach the black wire to ground. The blue
wire will be the sensor output. Connect this wire to a 10K ohm pull-up resistor and to
an input pin on your Pi as shown below. *Warning* Do not shine the laser into the
living area of your hamster!!! You could cause damage to your hamsters eyes. If
your wheel is inside the cage, consider using a magnetic contact switch instead of a
laser break beam sensor.
The LED will be used to visually indicate that the laser break sensor has detected a
break. This is extremely useful when lining up the laser with the target and making
sure that nothing unwanted is causing a light reflection into the sensor. Initially, I
taped the laser break sensor to the wall, but enough light was reflecting off of the
white wall to cause the sensor to always detect a break.
Having the LED helped me find the best place to mount the sensor. You can hook the input
of the LED directly to the output of the sensor (make sure you have a pull-up or pull-down
resistor on your LED). I hooked my LED up to an output pin on my Pi in case I wanted to use
the LED for something else in the project. Turns out, having the LED blink each time a laser
break is detected is more useful than I anticipated. The entire hardware setup is shown
above.
Create a target on the outside of the wheel for the laser. I used a small piece of masking
tape. Align the laser to the target and make sure no other part of the wheel breaks the laser
when it spins. Keep the laser out of any area that your hamsters eyes can enter!!
For the software setup, first install the Initial State streamer to give your hamster fitness
measurements a destination to go to (go here for instructions on setting up the Initial State
streamer; it is super easy and takes less than two minutes). Create a new file on your
Raspberry Pi (e.g. hamster_fitness.py) and copy+paste the code below into it. You will need
to copy+paste the access key associated with your Initial State account in between the
quotes on line 6 where it says PUT YOUR ACCESS KEY HERE. You can find your access
key under your account settings or on the landing page once you log into your account. The
code below is all of the code that you will need.
# Setup Pins
pinNumLaserBreak = 18
pinNumLED = 4
GPIO.setmode(GPIO.BCM) # numbering scheme that corresponds to breakout board and pin layout
GPIO.setup(pinNumLaserBreak,GPIO.IN)
GPIO.setup(pinNumLED,GPIO.OUT)
# Setup Constants
diameter = 13 # inches
circumference = diameter * math.pi * 0.0000157828283 # miles
distanceTotal = 0
timeNoActivity = 5 # seconds
speed = 0
lastTime = datetime.datetime.now()
while True:
input = GPIO.input(pinNumLaserBreak)
if not input:
if speed == 0:
streamer.log("ZooZoo Says", "It's time to get pumped")
# Calculate stuff
thisTime = datetime.datetime.now()
timeDiff = (thisTime-lastTime).total_seconds()
speed = circumference/(timeDiff/3600) # miles per hour
# Log stuff
streamer.log("Full Rotation", "1")
if speed < 5: # Filter out glitches (rocking on the sensor)
distanceTotal += circumference
streamer.log("Speed(mph)", speed)
streamer.log("Total Distance(miles)", distanceTotal)
Line 6 sets up the destination bucket for our data stream. We will name the bucket
Hamster Fitness Tracker. Every time you run this script, a new bucket named
Hamster Fitness Tracker will be created under your Initial State account (identified by
your access key), and all data generated from that script run will be contained there.
Line 7 streams the first message to the newly constructed stream.
Lines 10-20 setup the constants that we will use. Set the pin numbers according to
how you wired up your sensor input and LED output. Measure the diameter of the
wheel and enter the diameter on line 17. The script above assumes the diameter is
measured in inches and the speed will be calculated in miles/hour. Convert to your
desired units accordingly.
Line 25 checks the sensor output. If the sensor outputs a logic 0 (which means there
was a laser break detected), the distance and speed measurements will be calculated
and streamed. A simple attempt to filter out glitches (e.g. when the wheel stops right on
the target and rocks) happens on line 37. If a speed greater than 5 is detected, this is
assumed to be a glitch and is filtered out of the speed and distance traveled calculation.
Line 42 turns on the LED to indicate a laser break is detected. If the wheel stops right
on the target, all calculations are paused until the break is cleared (lines 46-49).
Lines 51-61 detect if there is no activity on the wheel for x number of seconds (x
specified on Line 20). If there is no activity, the speed is cleared to 0 and message is
output, I need a rest. After a rest has been detected, the first full rotation of the wheel
will stream another message, Its time to get pumped, on line 28.
We are ready to test our setup. Run the script at the command line of your Pi (type
sudo python hamster_fitness.py). Spin your wheel and make sure the LED blinks only
when the laser hits the target on the wheel. After a few spins, log into your Initial State
account and a new log will pop up in your log shelf called Hamster Fitness Tracker.
View this in Waves or Lines to see your hamsters activity. When you are ready to let
this script run for a long time, you might want to use the nohup command (no hangup),
especially if you are sshing into your Pi (e.g. nohup sudo python hamster_fitness.py >
tmp.txt &).
We measured the activity of my daughters hamster, ZooZoo, for the last four days. You can
see a screenshot of all her captured activity over this time in Waves above. At a quick glance,
you can see the big gaps in speed (and flat line of total distance) that correlate to the daylight
hours when she sleeps. Around 10 pm every night, she gets busy. After four days, she ran 12
miles!! If we zoom into one of her many runs, it looks like the following:
This is a 10 minute view of her activity. It is interesting to see the little mini-breaks
that she takes but overall maintains a speed of about 1.15 mph, spiking up to 3.25
mph. We were surprised to see that such a little creature would willingly run so far,
so fast every night. We had to do a little Google research to sanity check our
results. Turns out, hamsters do indeed run 1-5 miles per night, averaging 0.8 to 1.5
mph with spikes up to 5 mph in speed. In the wild, hamsters are always moving
around and burrowing to find food. In a cage with plenty of food, they have to
maintain a significant amount of movement to remain healthy. A hamster that is
sedentary will become paralyzed, making that hamster wheel a pretty important part
of your hamsters environment.
Another interesting observation was the fact that she ran 5 miles the night after we
cleaned her cage and gave her a different type of food. The night before, she ran
1.5 miles. More surprising than any specific observation from this project is the fact
that we were so fascinated by the capture of a hamsters fitness schedule. Capture
your hamsters activity and tell us what you find. We want to compare notes :-).
THANK YOU
We hope you enjoyed these ten
project tutorials! If you have any
questions, dont hesitate to email
us at support@initialstate.com. If
you havent done so already, we
encourage you to sign up for our
free data streaming tier.
initialstate.com/pricing