Raspberry Pi Cookbook

Third Edition

Software and Hardware
Problems and Solutions

Dr. Simon Monk

Raspberry Pi Cookbook

by Simon Monk

Copyright © 2020 Simon Monk. All rights reserved.

Printed in the United States of America.

Published by O’Reilly Media, Inc., 1005 Gravenstein Highway North, Sebastopol, CA 95472.

O’Reilly books may be purchased for educational, business, or sales promotional use. Online editions are also available for most titles (http://oreilly.com). For more information, contact our corporate/institutional sales department: 800-998-9938 or corporate@oreilly.com.

Acquisitions Editor: Nancy Davis

Development Editor: Jeff Bleiel

Production Editor: Christopher Faucher

Copyeditor: Octal Publishing, LLC

Proofreader: Arthur Johnson

Indexer: WordCo Indexing Services, Inc.

Interior Designer: David Futato

Cover Designer: Karen Montgomery

Illustrator: Rebecca Demarest

October 2019: Third Edition

Revision History for the Third Edition

2019-10-16: First Release

See http://oreilly.com/catalog/errata.csp?isbn=9781492043225 for release details.

The O’Reilly logo is a registered trademark of O’Reilly Media, Inc. Raspberry Pi Cookbook, the cover image, and related trade dress are trademarks of O’Reilly Media, Inc.

The views expressed in this work are those of the author, and do not represent the publisher’s views. While the publisher and the author have used good faith efforts to ensure that the information and instructions contained in this work are accurate, the publisher and the author disclaim all responsibility for errors or omissions, including without limitation responsibility for damages resulting from the use of or reliance on this work. Use of the information and instructions contained in this work is at your own risk. If any code samples or other technology this work contains or describes is subject to open source licenses or the intellectual property rights of others, it is your responsibility to ensure that your use thereof complies with such licenses and/or rights.

978-1-492-04322-5

[LSI]

Dedication

To my mother, Anne Kemp, whose good cheer and ability to laugh
in the face of adversity is an example to us all.

Preface to the Third Edition

Launched in 2011, the Raspberry Pi has found a role both as a very low-cost Linux-based computer and as a platform for embedded computing. It has proven popular with educators and hobbyists alike.

As of this writing, more than 20 million Raspberry Pis have been sold. The Raspberry Pi 4 with an option of 4 GB of performance makes the Raspberry Pi more than powerful enough to use as a replacement for a desktop computer. The availability of open source software for internet browsing, email, office suites, and photo editing is set to make the Raspberry Pi even more popular.

Even the latest Raspberry Pi 4 still includes the general-purpose input/output (GPIO) pins that allow the hobbyist to add their own electronic contraptions to the Raspberry Pi.

This edition has been thoroughly updated to encompass the new models of Raspberry Pi, as well as the many changes and improvements to its Raspbian operating system. There are also new chapters on sound and home automation.

This book is designed so that you can read it linearly, as you would a regular book, or access recipes at random. You can search the table of contents or index for the recipe that you want and then jump directly to it. If the recipe requires you to know about other things, it will refer you to other recipes, rather like a cookbook might refer you to base sauces before showing you how to cook something fancier.

The world of Raspberry Pi moves quickly. With a large, active community, new interface boards and software libraries are being developed all the time. In addition to examples that use specific interface boards or software, the book also covers basic principles so that you can have a better understanding of how to use new technologies that come along as the Raspberry Pi ecosystem develops.

As you would expect, a large body of code (mostly Python programs) accompanies the book. These programs are all open source and available on GitHub. For most of the software-based recipes, all you need is a Raspberry Pi. I recommend a Raspberry Pi 3 or 4 model B. When it comes to recipes that involve making your own hardware to interface with the Raspberry Pi, I have tried to make good use of ready-made modules as well as solderless breadboard and jumper wires to avoid the need for soldering.

If you want to make breadboard-based projects more durable, I suggest using prototyping boards with the same layout as a half-size breadboard, such as those sold by Adafruit and elsewhere, so that the design can easily be transferred to a soldered solution.

Using This Book

The cookbook style of this book means that it is not a book that you must read in order from front to back. The book is made up of individual recipes grouped into chapters. Where a recipe needs you to have prior knowledge of some other topic, the recipe will send you off to another recipe for that topic.

You will probably find that you jump around from recipe to recipe as you try to get your Raspberry Pi project to do what you want.

I have mapped out a few paths through the book that I think would be useful to different types of readers:

Complete Raspberry Pi beginner

Read most of Chapters 1, 2, and 3—in particular, start with Recipe 1.1, Recipe 1.2, Recipe 1.4, and Recipe 1.6—and then wander at will.

Python learner

If you want to use your Raspberry Pi to learn how to program in Python, work your way through Chapters 4 to 7. You will probably find that you need to jump off to various recipes in earlier chapters.

Electronics hobbyist

If you don’t already have them, you will need to pick up some Python skills by working through Chapters 4 to 7, and then work through Chapter 8 before picking out interesting recipes in the later chapters to start making yourself some interesting Raspberry Pi electronics projects.

Conventions Used in This Book

The following typographical conventions are used in this book:

Italic

Indicates new terms, URLs, email addresses, filenames, and file extensions.

Constant width

Used for program listings, as well as within paragraphs to refer to program elements such as variable or function names, databases, data types, environment variables, statements, and keywords.

Constant width bold

Shows commands or other text that should be typed literally by the user.

Constant width italic

Shows text that should be replaced with user-supplied values or by values determined by context.

Tip

This icon signifies a tip, suggestion, or general note.

Warning

This icon indicates a warning or caution.

Note

This icon points you to the related video for that section.

Using Code Examples

Supplemental material (code examples, etc.) is available for download at https://github.com/simonmonk/raspberrypi_cookbook_ed3.

This book is here to help you get your job done. In general, if example code is offered with this book, you may use it in your programs and documentation. You do not need to contact us for permission unless you’re reproducing a significant portion of the code. For example, writing a program that uses several chunks of code from this book does not require permission. Selling or distributing examples from O’Reilly books does require permission. Answering a question by citing this book and quoting example code does not require permission. Incorporating a significant amount of example code from this book into your product’s documentation does require permission.

We appreciate, but do not require, attribution. An attribution usually includes the title, author, publisher, and ISBN. For example: “Raspberry Pi Cookbook, Third Edition, by Simon Monk (O’Reilly). Copyright 2020 Simon Monk, 978-1-492-04322-5.”

If you feel your use of code examples falls outside fair use or the permission given above, feel free to contact us at permissions@oreilly.com.

O’Reilly Online Learning

Note

For more than 40 years, O’Reilly Media has provided technology and business training, knowledge, and insight to help companies succeed.

Our unique network of experts and innovators share their knowledge and expertise through books, articles, conferences, and our online learning platform. O’Reilly’s online learning platform gives you on-demand access to live training courses, in-depth learning paths, interactive coding environments, and a vast collection of text and video from O’Reilly and 200+ other publishers. For more information, please visit http://oreilly.com.

How to Contact Us

Please address comments and questions concerning this book to the publisher:

O’Reilly Media, Inc.

1005 Gravenstein Highway North

Sebastopol, CA 95472

800-998-9938 (in the United States or Canada)

707-829-0515 (international or local)

707-829-0104 (fax)

We have a web page for this book where we list errata, examples, and any additional information. You can access this page at https://oreil.ly/raspberry-pi-cookbook-3e.

Email bookquestions@oreilly.com to comment or ask technical questions about this book.

For more information about our books, courses, conferences, and news, see our website at http://www.oreilly.com.

Find us on Facebook: http://facebook.com/oreilly

Follow us on Twitter: http://twitter.com/oreillymedia

Watch us on YouTube: http://www.youtube.com/oreillymedia

Acknowledgments

As always, I thank my wife, Linda, for her patience and support.

I also thank the technical reviewers, Duncan Amos and Ian Huntley, for their excellent help and suggestions that have without a doubt contributed greatly to this book.

Thanks also to Jeff Bleiel and all the O’Reilly team and, of course, Bob Russell of Octal Publishing for his diligent copyediting.

Chapter 1. Setup and Management

1.0 Introduction

When you buy a Raspberry Pi, you are essentially buying an assembled printed circuit board. It does not even include a power supply or operating system.

The recipes in this chapter are concerned with getting your Raspberry Pi set up and ready for use.

Because the Raspberry Pi uses standard USB keyboards and mice, most of the setup is pretty straightforward, so you will concentrate only on those tasks that are specific to the Raspberry Pi.

1.1 Selecting a Model of Raspberry Pi

Problem

There are many models of Raspberry Pi, and you are not sure which one to use.

Solution

The decision as to which Raspberry Pi model to use depends very much on what you plan to do with it. Table 1-1 lists some uses and my model recommendations.

Table 1-1. Selecting a model of Raspberry Pi

Usage | Suggested model | Notes
Desktop computer replacement | Raspberry Pi 4 model B (4 GB) | You will need the 4 GB of memory if you are web browsing.
Electronics experimentation | Raspberry Pi 2 or 3 model B | Reasonably up-to-date hardware will minimize software problems. No need for more performance.
Computer vision | Raspberry Pi 4 model B (4 GB) | Maximum performance required.
Home automation | Raspberry Pi 2 or 3 model B | Low-power consumption and more than enough power.
Media center | Raspberry Pi 3 or 4 | For video performance.
Electronic display board | Any model | A model with WiFi, advantageous for remote access.
Embedded electronics project | Raspberry Pi Zero W | Low cost and WiFi enabled for remote access.

If you want a good general-purpose Raspberry Pi, I recommend a Raspberry Pi 3 model B+. With four times as much memory as the original Raspberry Pi and a quad-core processor, it will cope with most tasks much better than the Pi Zero, but it doesn’t get as hot or use as much power as the Raspberry Pi 4. The Raspberry Pi 3 model B+ also has the great advantage of having WiFi and Bluetooth built in, so there’s no need for an extra USB WiFi adapter or Bluetooth hardware.

The Raspberry Pi 4 model B

As of this writing, the Raspberry Pi 4 model B (Figure 1-1) has just been released. This has broken the mold of connector positioning on the Raspberry Pi that has remained the same since the release of the Raspberry Pi B+ in 2014. This means cases designed for the Raspberry Pi B+, 2, and 3 and related models will not fit the Raspberry Pi 4.

Figure 1-1. The Raspberry Pi 4 model B

The new model has also, for the first time, allowed users a choice of memory sizes (1 GB, 2 GB, or 4 GB), with a corresponding price hike for the 2 GB and 4 GB options.

One of the most significant changes is that the micro-USB socket that supplied power to earlier versions has been dropped in favor of the USB-C connector. Also, the single full-sized HDMI connector of the earlier versions has been replaced by a pair of micro-HDMI connectors—so you will need a special HDMI lead or an adapter. And yes, you can connect two monitors at the same time.

Under the hood, the Raspberry Pi is much faster than its predecessors (especially if you go for the 4 GB memory version). In fact, some benchmarks suggest it is three to four times faster than any previous Raspberry Pi. This comes at the cost of the main chip on the board operating much hotter than in earlier versions—hot enough, in fact, to hurt.

If, on the other hand, you are embedding a Raspberry Pi in a project for a single purpose, using a compact Pi Zero W and saving a few dollars might well be an option.

The Raspberry Pi 3 model A+ is essentially a Raspberry Pi 3 model B+ with the Ethernet connector and three of the four USB ports removed. It also has half the memory of a B+. But it is significantly cheaper ($10 cheaper as of this writing). So it is definitely worth considering if you don’t need the extra ports for your project.

Discussion

Figure 1-2 shows the Pi Zero W, the Raspberry Pi 3 B, and the Raspberry Pi 4.

Figure 1-2. From left to right, the Raspberry Pi Zero W, the Raspberry Pi 3 B, and the Raspberry Pi 4 B

As you can see from Figure 1-2, the Pi Zero W is roughly half the size of the Pi 3 B or Pi 4 B, and it has a single micro-USB socket for communication, and a second one for power. The Pi Zero W also saves space by using a mini-HDMI socket and micro-USB on-the-go socket. If you want to connect a keyboard monitor and mouse to a Pi Zero, you will need adapters for both the USB and the HDMI port before you can connect standard peripherals. The Raspberry Pi A+ is larger than the Pi Zero and has full-sized USB and HDMI ports.

Table 1-2 summarizes the differences between all the Raspberry Pi models to date, with the most recently released models toward the top.

Table 1-2. Raspberry Pi models

Model
RAM
Processor
(cores * clock)
USB sockets
Ethernet port
Notes

4 B
1/2/4 MB
4 * 1.5 GHz
4 (2 x USB3)
yes
2 x micro-HDMI video

3 A+
512 MB
4 * 1.4 GHz
1
no
WiFi and Bluetooth

3 B+
1 GB
4 * 1.4 GHz
4
yes
WiFi and Bluetooth

3 B
1 GB
4 * 1.2 GHz
4
yes
WiFi and Bluetooth

Zero W
512 MB
1 * 1 GHz
1 (micro)
no
WiFi and Bluetooth

Zero
512 MB
1 * 1 GHz
1 (micro)
no
Low cost

2 B
1 GB
4 * 900 MHz
4
yes

A+
256 MB
1 * 700 MHz
1
no

B+
512 MB
1 * 700 MHz
4
yes
Discontinued

A
256 MB
1 * 700 MHz
1
no
Discontinued

B rev2

512 MB

1 * 700 MHz

2

yes

Discontinued

B rev1

256 MB

1 * 700 MHz

2

yes

Discontinued

If you have one of the older or discontinued Raspberry Pi models, it is still useful. Those models do not have quite the performance of the latest Raspberry Pi 4, but for many situations, that does not matter.

If you are buying a new Raspberry Pi, I consider the best choice for use as a general-purpose computer to be the Pi 3 B+. If you need maximum power and don’t mind the processor chip becoming hot, consider a Raspberry Pi 4. If you don’t need WiFi or want a smaller device, also consider the 3 B, 2 B, 3 A+, Zero, or Zero W.

See Also

For more information on the Raspberry Pi models, see https://oreil.ly/oY-A_.

The low cost of the Pi Zero and Pi Zero W models makes them ideal for embedding in electronics projects without worrying about the expense. See Recipe 9.21.

1.2 Connecting the System

Problem

You have everything that you need for your Raspberry Pi, and you want to connect it all.

Solution

Unless you are embedding your Raspberry Pi in a project or using it as a media center, you need to attach a keyboard, a mouse, a monitor, and possibly a WiFi dongle, if you have an older Raspberry Pi without built-in WiFi.

Figure 1-3 shows a typical Raspberry Pi system. If you have a Raspberry Pi 4, you could (if you really wanted) connect a second monitor. However, if you have just one monitor, connect it to the micro-HDMI connector closest to the USB-C power connector.

Figure 1-3. A typical Raspberry Pi system

Discussion

The Raspberry Pi is perfectly happy with pretty much any USB keyboard and mouse, wired or wireless.

The Raspberry Pi 4 lets you connect two monitors to your system at the same time. When you do so, you will be able to move your mouse cursor between screens, but Raspbian will need to know where the screens are relative to each other. To enact this, in the Preferences section on the Main menu, open the Screen Configuration tool (Figure 1-4).

Figure 1-4. Arranging multiple screens

You can drag the two boxes labeled HDMI-1 and HDMI-2 around to represent the physical position of the two monitors. So in this case the monitors are side by side, with the monitor connected to HDMI-1 on the left.

If you have an older Raspberry Pi or a model A or A+ and run out of USB sockets, you will also need a USB hub.

See Also

The official Raspberry Pi Quick Start Guide.

1.3 Enclosing a Raspberry Pi

Problem

You need an enclosure for your Raspberry Pi.

Solution

The Raspberry Pi does not come with an enclosure unless you buy one as part of a kit. This makes it a little vulnerable, given that there are bare connections on the underside of the circuit board that could easily be short-circuited if the Raspberry Pi is placed on something metal.

It is a good idea to buy some protection for your Raspberry Pi in the form of a case. If you intend to use the Raspberry Pi’s general-purpose input/output (GPIO) pins (the pins that allow you to connect to external electronics), the PiBow Coupé shown in Figure 1-5 is a beautiful and practical design that is available for both the Raspberry Pi 4 and earlier versions.

Discussion

There is a vast array of case styles to choose from, including the following:

Simple, two-part, click-together plastic boxes

VESA mountable boxes (for attaching to the back of a monitor or TV)

Lego-compatible boxes

3D-printed box designs

Laser-cut, snap-together acrylic designs

Figure 1-5. A Raspberry Pi 2 in a PiBow Coupé

The case you buy is very much a matter of personal taste. However, here are some of the things that you need to consider:

Do you need to have access to the GPIO connector? This is important if you plan to attach external electronics to your Raspberry Pi.

Is the case well ventilated? This is important if you plan to overclock your Raspberry Pi (Recipe 1.14) or run it hard playing videos or games, because these will all generate more heat.

Finally, make sure you get one that fits your model of Raspberry Pi.

If you have access to a 3D printer, you can also print your own case. Search for Raspberry Pi on Thingiverse or MyMiniFactory, and you will find lots of designs.

You will also find heatsink kits that have tiny self-adhesive heatsinks to attach to the chips on the Raspberry Pi. These can be of some use if you are demanding a lot of your Raspberry Pi, say by playing a lot of videos, but generally they are the equivalent of “go-faster” stripes on a car.

If you have a Raspberry Pi 4, you can reduce the temperature by fitting a small fan such as the Pimoroni Fan SHIM as shown in Figure 1-6.

Figure 1-6. The Pimoroni Fan SHIM

See Also

Adafruit has a nice range of Raspberry Pi enclosures.

For an enclosure that also has space for a built-in SSD, see Recipe 1.10.

You will also find many styles of cases at other Raspberry Pi suppliers and on eBay.

1.4 Selecting a Power Supply

Problem

You need to select a power supply for your Raspberry Pi.

Solution

The basic electrical specification for a power supply suitable for a Raspberry Pi is that it provides a regulated 5V DC (direct current).

The amount of current that the power supply must be capable of providing depends both on the model of Raspberry Pi and on the peripherals attached to it. It is worth getting a power supply that can easily cope with the Raspberry Pi, and you should consider 1A to be a minimum for any model of Raspberry Pi.

If you buy your power supply from the same place that you buy the Raspberry Pi, the seller should be able to tell you whether it will work with the Raspberry Pi.

The Raspberry Pi 4 should be used with a 3A power supply. This is in part because its greater processing power than earlier models requires more electrical power, but also because its two USB3 ports are able to supply up to 1.2A to high-power USB peripherals such as external USB drives.

If you are going to be using WiFi or USB peripherals that require significant amounts of power with pre-Raspberry Pi 4 models, you should get a power supply capable of 1.5A or even 2A. Also beware of very low-cost power supplies that might not provide an accurate or reliable 5V.

Discussion

The Raspberry Pi 4 is the first Raspberry Pi to switch to using the more modern USB-C connector. Unlike the micro-USB connector used on earlier boards, this connector is reversable (Figure 1-7).

Figure 1-7. Power and video connections for the Raspberry Pi 3 (top) and 4 (bottom)

In Figure 1-7, you can see the USB-C power connector of a Raspberry Pi 4 below the micro-USB connector of a Raspberry Pi 3. As an aside, you can also see the pair of micro-HDMI video ports that replace the single full-sized HDMI connector.

Whether your Raspberry Pi uses a USB-C connector or a micro-USB connector, the power supply and connectors are actually the same as those found in many smartphone chargers. If they terminate in a micro-USB plug, they are almost certainly 5V (but check). The only question, then, is whether they can supply enough current.

If they can’t, a few bad things can happen:

They might become hot and be a potential fire risk.

They might simply fail.

At times of high load (say, when the Pi is using a WiFi dongle), the voltage might dip and the Raspberry Pi might reset itself.

If you are using a Raspberry Pi 3 or earlier, look for a power supply that says it can supply 1A or more. If it specifies a number of watts (W) rather than A, divide the number of watts by 5 to get the number of amps. So a 5V 10W power supply can supply 2A (2,000mA).

Using a power supply with, say, a maximum current of 2A will not use any more electricity than a 700mA power supply. The Raspberry Pi takes only as much current as it needs.

In Figure 1-8, I measure the current taken by a Raspberry Pi model B and compare it with a Raspberry Pi 2 model B and a Raspberry Pi 4.

Figure 1-8. Raspberry Pi current consumption during booting

The newer Raspberry Pis (starting with the A+ and all the way through to the Pi 4) are far more power-efficient than the original Raspberry Pi 1 models, but when the processor is fully occupied and has a lot of peripherals attached, they can still reach similar current requirements, and, in the case of the Raspberry Pi 4, quite a lot more.

As you can see in Figure 1-8, if your Raspberry Pi is going to be on all the time, a Raspberry Pi 2 (and for that matter a Raspberry Pi 3) will run cooler and use a lot less power than the newest Raspberry Pi 4.

In Figure 1-8, you can see that the current rarely exceeds 700mA. However, the processor isn’t really doing very much here. Were you to start playing HD video, the current would increase considerably. When it comes to power supplies, it’s always better to have something in reserve.

See Also

You can buy a module that will turn off the power when the Raspberry Pi shuts down at http://www.pi-supply.com.

1.5 Selecting an Operating System

Problem

There are a number of different Raspberry Pi operating systems, and you are not sure which one to use.

Solution

The answer to this question depends on what you intend to do with your Raspberry Pi.

For general use as a computer or for using in electronic projects, you should use Raspbian, the standard and official distribution for the Raspberry Pi.

If you plan to use your Raspberry Pi as a media center, there are a number of distributions (versions of Linux) specifically for that purpose (see Recipe 4.1).

In this book, we use Raspbian almost exclusively, although most of the recipes will work with any Debian-based Linux distribution.

Discussion

If you are interested in trying out some different distributions, you can purchase some microSD cards, which are not expensive, and copy the various distributions onto them. If you do this, it is a good idea to keep your files that you don’t want to lose on a USB flash drive plugged into your Raspberry Pi.

Note that if you are using one of the upcoming recipes to write your own SD card, you need to have a computer that has an SD card slot (and an SD-to-microSD adapter), or you can buy an inexpensive USB SD card reader.

See Also

The official list of Raspberry Pi distributions.

1.6 Writing a microSD Card with NOOBS

Problem

You want to write a microSD card using NOOBS (New Out Of the Box Software).

Solution

NOOBS is by far the easiest way to get an operating system onto your Raspberry Pi.

Download the NOOBS archive file (the option NOOBS rather than NOOBS Lite), extract it, and place it on a microSD card. To do this, you will need a computer with an SD card slot or a USB adapter and an SD-to-microSD adapter.

After you have downloaded the NOOBS ZIP file, extract it and copy the folder contents onto the microSD card. Note that if the archive extracts to a folder called NOOBS_v2_9_0 or similar, it is the contents of the folder that should be copied to the root of the microSD card, not the folder itself.

microSD Cards

Not all microSD cards are created equal, and the performance of your Raspberry Pi will be better with a better card. So look for a card specified as being “class 10.”

When it comes to capacity, you should look for cards of at least 16 GB, and really, given the small difference in price, a 32 GB card is the better choice, as it will give you plenty of room for expansion.

Put the microSD card containing the extracted NOOBS files into your Raspberry Pi and then power up your Raspberry Pi. When it boots, a window like the one shown in Figure 1-9 will appear. From this screen, select Raspbian, and then click the Install button.

Figure 1-9 shows the options for a Raspberry Pi 4. If you are using NOOBS on a different Raspberry Pi, you will see a different range of options because only the options that will work with your model of Raspberry Pi will be shown.

Figure 1-9. NOOBS first screen

You will see a warning message that the SD card will be overwritten (which is fine), and then, as the distribution is installed onto the SD card, you will see a progress screen accompanied by helpful information about the distribution (Figure 1-10).

Note this will take quite a long time. At some point, you will also be prompted to connect to your WiFi network.

Figure 1-10. NOOBS overwriting the SD card

When the file copying is complete, you will get the message Image applied successfully. When you press Return, the country information dialog box displays, in which you can chose your location options. Note that the Raspberry Pi, being a British product, this defaults to the UK. The Raspberry Pi will then reboot, and then a few configuration questions will appear. The first (Figure 1-11) prompts you to set the country and other location options.

Figure 1-11. Configuring Raspberry Pi after installation

Clicking Next prompts you to change your password from raspberry to something more secure. You are then asked if you want to check for updates. This requires an internet connection, so it won’t work unless you are connected to your network. If you are connected (either by WiFi or Ethernet), it’s a good idea to check for updates now. If not, you can always check later using Recipe 3.40.

After you are up and running, the first thing you should do is connect your Raspberry Pi to the internet (Recipes 2.1 and 2.5).

Discussion

Unlike full NOOBS, the NOOBS Lite option does not actually contain Raspbian or any other distributions but rather downloads them after the microSD card is installed in the Raspberry Pi. To do this, your Raspberry Pi must have a connection to the internet. The NOOBS Lite installer (Figure 1-12) lets you chose a WiFi network. As soon as you’re connected, the NOOBS Lite installer will download a list of operating systems from which you can choose.

Figure 1-12. The NOOBs Lite installer

One interesting option here is Raspbian Lite. This is a pared-down version of Raspbian intended for use in headless Raspberry Pis (Recipe 1.9).

For NOOBS to install correctly onto a microSD card, the card must be formatted as FAT32. Most SD and microSD cards as supplied are already formatted in FAT32. If you are reusing an old card and need to format it as FAT32, use your operating system’s tool for formatting removable media. Sometimes, an SD card can stubbornly refuse to format; a good trick is to pop it into a digital camera and use the camera’s format option.

The type of microSD card that you get will also affect how fast your Raspberry Pi runs after the operating system is installed. Look for a microSD card described as “class 10.”

See Also

You can find more information on installing an operating system with NOOBS, including information about the different distributions available, at https://oreil.ly/nn9Q-.

If you need more control over what goes onto your SD cards, perhaps because you need to download and run a program automatically after installation, take a look at Recipe 1.8.

To create a headless Raspberry Pi with Raspbian Lite using PiBakery, see Recipe 1.9.

1.7 Installing an Operating System Without NOOBS

Problem

You want to put the operating system for your Raspberry Pi directly onto an SD card or other removable media.

Solution

In general, if you just want to set up a Pi with Raspbian, it’s much easier to follow Recipe 1.6 than this recipe.

However, you might want to write a disk image directly onto an SD card that is ready to run, rather than having to run an installer from the SD card on the Raspberry Pi. This might be because you want to use a nonstandard operating system or, as you will see in this recipe, you want the disk image to be on something other than an SD card—perhaps an external USB drive.

Whatever your reasons, the process of writing the disk image onto the SD card or other media is as follows:

Using a Mac, Windows, or Linux computer (not your Raspberry Pi), download the disk image writing software Etcher.

Still on your computer, download the disk image that you want to install. You will find a selection of official distributions at https://oreil.ly/uzvR3.

Insert the SD card (or whichever medium you want to install the operating system onto) into your computer. It’s also a good idea to disconnect any other removable media so that you don’t accidentally overwrite the wrong device.

Start Etcher (Figure 1-13) and then select the image file. This will have the extension .iso, but you can download it as a ZIP file, which will also work.

Click “Select drive” on Etcher and select the SD card or other removable media. Note that any data on this will be deleted, so be very careful not to select your computer’s main hard disk.

Click Flash and wait while the image file is flashed onto the removable media.

Figure 1-13. Using Etcher to write a disk image

After the SD card or other removable media is prepared, you can connect it to your Raspberry Pi, and when the Raspberry Pi is powered up, it will boot into whatever operating system distribution you installed.

Discussion

Vendors of hardware sometimes offer their own disk image that has support for their hardware built into it. It’s best to avoid using such images because doing so means that you will not get all the benefits of using a standard Raspbian distribution and all the preinstalled software. It also means that if you have a problem with a piece of software, it will be a lot more difficult to find support because you are using a nonstandard distribution.

See Also

For a good example of using this recipe to run Raspbian from a proper disk rather than an SD card, see Recipe 1.10.

1.8 Using PiBakery to Configure and Write an SD Card

Problem

You want to install Raspbian on microSD cards for lots of Raspberry Pis, but you don’t want to have to set up each one individually.

Solution

Download the PiBakery tool created by David Ferguson. This useful piece of software runs on your Mac or Windows computer and allows you to write an SD card (like Recipe 1.6) as well as automate the extra steps that usually follow basic installation, such as setting up your WiFi connection (Recipe 2.5) or changing the network name of your Raspberry Pi (Recipe 2.4).

Begin by downloading PiBakery. When you run the installer (Figure 1-14) you can choose either Raspbian Full or Raspbian Lite, or both. Unless you are thinking of using your Raspberry Pi without a keyboard, mouse, or monitor, you probably just need the Full version. Note the file sizes here—these are big!

Figure 1-14. Installing PiBakery

After you’ve installed PiBakery, run the PiBakery application. This opens a window, which you use to specify how you want the Raspbian microSD card to be configured by dragging blocks onto a canvas. In Figure 1-15, you can see how we have added an On Every Boot block from the Startup category and then added three more blocks connected to each other underneath it.

Figure 1-15. Configuring a microSD card image using PiBakery

The first block ensures that virtual network computing (VNC) (Recipe 2.8) is enabled. The second block sets up the WiFi connection, and the final block illustrates how you can enable the I2C interface (Recipe 9.3) for connecting external electronics.

When you are happy with the settings, insert a microSD card into your computer and then click the Write button. A prompt appears, asking you to select the SD card onto which Raspbian will be installed and to select Rasbian Lite or Raspbian Full (you will want Raspbian Full unless you are planning on making your Raspberry Pi headless—see Recipe 1.9). Clicking Start Write starts the process of installing Raspbian on the microSD card. When that has completed, you can eject the microSD card and put it in your Raspberry Pi, which should then boot up all ready for use, without any further setup being required.

Discussion

PiBakery is great if you have a whole load of Raspberry Pis that you need to set up, perhaps in a classroom setting.

As well as the blocks we used here, there are lots of other blocks that do things like run programs automatically at startup and even download and install packages from the internet.

See Also

In Recipe 1.9, we use PiBakery again to setup a Raspberry Pi as headless (no keyboard, mouse, or monitor).

PiBakery should not be confused with the macOS tool ApplePi-Baker. If you have a Mac, ApplePi-Baker is a great way to back up and restore Raspberry Pi SD cards.

1.9 Using PiBakery to Configure a Headless Raspberry Pi

Problem

You want to set up a Raspberry Pi (perhaps a Raspberry Pi Zero W) without using a keyboard, mouse, or monitor (headless).

Solution

Use PiBakery (Recipe 1.8) to configure the microSD card with Raspbian Lite and WiFi credentials so that you can control your Raspberry Pi remotely using Secure Shell (SSH) (Recipe 2.7).

In this solution, let’s assume that you want to set up a Raspberry Pi Zero W so that it does the following:

Gives itself the network name “PiZero” so that we can find it easily on our network.

Connects to your WiFi and hence to the internet.

Downloads and runs a Python script from the internet.

In reality, you might not need step 3, but it’s useful to know how to do such a thing.

You will also be able to connect to the Pi Zero W using SSH on your regular computer.

Begin by downloading and running PiBakery (see Recipe 1.8).

Next, put together a recipe that looks like Figure 1-16. Don’t forget to put your WiFi settings in. Note that SSH is automatically enabled.

Figure 1-16. Configuring a headless Raspberry Pi using PiBakery

The Python program to be run is from much later in the book (Recipe 10.1) and uses one of the Raspberry Pi’s GPIO pins to blink an LED on and off. To download this file on its own, enter the URL on the “Download file” line, as shown in Figure 1-16 (https://oreil.ly/v86vt).

PiBakery has a feature that allows you to load (import) and save configurations. You can load the configuration settings shown in Figure 1-16 into PiBakery by clicking the Import button and then navigating to the headless_blink.xml file within the folder PiBakery in the downloads for this book. You can find instructions for getting the book’s downloads at Recipe 3.22.

Notice in Figure 1-16 that two boot blocks are used. On the first boot, the hostname is set to piZero and WiFi is configured. The second block runs after subsequent boots, downloads the blink program, and then runs it.

So, after the microSD card has been put into the Pi Zero and booted up for the first time (just leave it to do its thing for a couple of minutes), unplug it and power it back up again. Now, if you have an LED connected to pin 18 (Figure 1-16), it should start blinking.

Discussion

PiBakery is a really neat way of setting up a headless Raspberry Pi. However, as well as setting up a microSD card for first use, you can also modify configurations. So if you power down the Raspberry Pi we set up earlier, remove the SD card, and insert it back into your computer, PiBakery will detect that it has been used on the SD card before and offer to load up the configuration. Because a first boot has already taken place, only the on every boot will be shown. But you can edit this and make changes, or even add more blocks without having to write the SD card again.

See Also

For full documentation on PiBakery, see https://www.pibakery.org.

1.10 Booting from a Real Hard Disk or USB Flash Drive

Problem

Your microSD card is too small and/or you are concerned about your entire operating system running on an SD card.

Solution

You can connect external USB flash drives, USB hard disks, or high-capacity SSDs, and they should be recognized by your Raspberry Pi for storage. However, if you want your Raspberry Pi to be able to boot from the external hard disk rather than just accessing it as a data store, there are a few steps you need to take:

Invest in a Raspberry Pi 4 B with 4 GB of RAM. It’s worth it to have the extra computing power if you are going to add a proper disk. Also, booting from USB only became an option with the Raspberry Pi 3 and subsequent models.

Start by following Recipe 1.7 to install Raspbian on your Pi using a microSD card.

Unless you have just downloaded NOOBS, make sure your Pi is up to date by following Recipe 3.40.

Configure the Raspberry Pi’s hardware so that it will boot from USB. This involves the use of something called the OTP (One Time Programming). As the name suggests, this makes a permanent change to the Raspberry Pi’s hardware, which you cannot then undo. So it’s particularly important to ensure that your Raspberry Pi is up to date (Recipe 3.40) and to be very careful when typing the following command into a Terminal session. Note the use of the | (bar or pipe symbol) in the middle of the command. You will normally find this symbol next to the left Shift key (Shift and backslash - \) on a Windows keyboard and near the Enter key on a Mac keyboard.

Tip

Throughout the book, I use a $ at the start of each line where you are expected to type a command. The response from the command line will not be prefixed by anything; it will appear just as it does on the Raspberry Pi’s screen.

$ echo program_usb_boot_mode=1 | sudo tee -a /boot/config.txt

Shut down your Raspberry Pi (Recipe 1.16) and remove the microSD card.

Attach the USB external disk (or flash drive) to your regular computer and follow Recipe 1.7 to install a disk image on it.

Eject and unplug the USB drive from your regular computer and connect it to your Raspberry Pi.

Power up your Raspberry Pi; it should begin to boot from the USB drive. You will receive a message saying that the root filesystem has been resized, and after a while the usual Pixel desktop interface will appear on the screen.

Discussion

If you want to switch your Raspberry Pi’s main disk to a real disk while at the same time finding a good enclosure for your Raspberry Pi 2 and 3, one really nice solution is the DIY Pi Desktop kit from Element 14. This kit (shown in Figure 1-17) consists of the following:

A USB-to-mSATA (1.8 inch) adapter board that fits on top of your Raspberry Pi

A U-shaped USB connector that connects one of the Raspberry Pi’s USB ports to the USB-to-mSATA interface board

A heatsink for your Raspberry Pi’s processor chip

A stylish and compact case for the Raspberry Pi that includes a push button that acts as a start button to boot the Raspberry Pi

You are also going to need the following items to complete the kit:

A 1.8-inch mSATA disk drive. I would go for an SSD because they are more robust and use less power than a magnetic hard disk.

A good power supply. Because you are now going to need to power both the Raspberry Pi and a USB disk, you might need to upgrade your power supply. Element 14 recommends the use of a 5V 2.5A power supply (see also Recipe 1.4).

Optionally a Pi Camera (Recipe 1.17) if you want your Pi Desktop to have a webcam.

Figure 1-17. Element 14 DIY Pi Desktop kit

The supplied instruction leaflet for assembling the hardware for the kit is easy to follow, but before you get everything boxed up I would strongly recommend following the instructions in “Solution” before you fix the Raspberry Pi into the enclosure, because after it’s in, it’s very difficult to remove the microSD card from the Raspberry Pi.

Note that as of this writing, this case is not available for the Raspberry Pi 4.

See Also

This recipe is based on the Raspberry Pi instructions.

For more information on the DIY Pi Desktop, see https://oreil.ly/WTcyX.

1.11 Connecting a DVI or VGA Monitor

Problem

Your monitor does not have an HDMI connector, but you want to use it with your Raspberry Pi.

Solution

Many people have been caught out by this problem. Fortunately, it is possible to buy adapters for monitors with a DVI or VGA input but no HDMI connectors.

DVI adapters are the simplest and cheapest. They are available for less than $5 if you search for “HDMI male to DVI female converter.”

Discussion

Using VGA adapters is more complex because they require some electronics to convert the signal from digital to analog, so beware of leads that do not contain these. The official converter is called Pi-View and is available wherever the Raspberry Pi is sold. Pi-View has the advantage of having been tested and found to work with Raspberry Pi. You can find cheaper alternatives on the internet, but often these won’t work.

See Also

eLinux has tips on what to look for in a converter.

1.12 Using a Composite Video Monitor/TV

Problem

The text on your low-resolution composite monitor is illegible.

Solution

You need to adjust the resolution of the Raspberry Pi for a small screen.

The Raspberry Pi has two types of video output: (1) HDMI, and (2) composite video from the audio jack, for which you need a special lead. Of these, the HDMI is by far the better-quality option. If you’re intending to use a composite video as your main screen, you might want to think again.

If you are using a composite video screen—say, because you need a really small screen—you need to make a few adjustments to fit the video output to the screen. You need to make some changes to the file /boot/config.txt.

You can edit this file on your laptop or PC by inserting the SD card back into an SD card reader, or you can edit it (without having to remove it from your Raspberry Pi). Editing files on the Raspberry Pi itself is normally done using the nano editor. This is a little tricky, and I suggest you read Recipe 3.7 thoroughly before you try editing your first file. If you are happy to go ahead and edit the file using nano, enter the following command in a Terminal session:

$ sudo nano /boot/config.txt

Note that to save and exit nano, press Ctrl-X, then press Y (to confirm), and then press Enter.

If the text is too small to read, it’s best to remove the SD card from the Raspberry Pi and insert it into your computer. The file will then be in the top-level directory on the SD card, and you can use a text editor on your PC (such as Notepad++) to modify it.

You need to know the resolution of your screen. For a lot of small screens, this will be 320 x 240 pixels. Find the two lines in the file that read as follows:

#framebuffer_width=1280
#framebuffer_height=720

Remove the # from the front of each line and change the two numbers to the width and height of your screen. Removing the # enables the line. In the following example, the lines have been modified to be 320 by 240:

framebuffer_width=320
framebuffer_height=240

Save the file and restart your Raspberry Pi. You should find that everything has become a lot easier to read. You will probably also find that there is a big, thick border around the screen. To adjust this, see Recipe 1.13.

Discussion

There are many low-cost CCTV monitors that can make a great companion for the Raspberry Pi when you’re making something like a retro games console (Recipe 4.4). However, these monitors are often very low resolution.

See Also

For another tutorial on using composite monitors, see this Adafruit tutorial.

Also, see Recipes 1.11 and 1.13 to adjust your picture when you’re using the HDMI video output.

1.13 Adjusting the Picture Size on Your Monitor

Problem

When you first connect a Raspberry Pi to a monitor, you might find that you cannot read some of the text because it extends off the screen, or that the picture isn’t using all the space available on the screen.

Solution

If your problem is that there is a large black border around the picture, you can make the screen fill the whole area of the monitor using the Raspberry Pi’s desktop Configuration tool (Figure 1-18). To open this, go to the Raspberry Pi menu (the one with the Raspberry Pi icon), select Preferences, and then click Raspberry Pi Configuration.

Figure 1-18. Using the Raspberry Pi Configuration tool to control underscan

Click the Disabled radio button next to Underscan. Note that the change will not take effect until you have clicked OK and then rebooted your Raspberry Pi.

If you have the opposite problem and your text extends off the edges of the screen, click Enabled for Underscan.

In a second step, you now need to edit the file /boot/config.txt. You can do this either by removing the SD card and mounting it on your PC or Mac or by editing the SD card on the Raspberry Pi. Editing files on the Raspberry Pi itself is normally done using the nano editor. This is a little tricky; I suggest you read Recipe 3.7 thoroughly before you try editing your first file. If you are happy to go ahead and edit the file using nano, enter the following command in a Terminal session:

$ sudo nano /boot/config.txt

Look for the section dealing with overscan. The four lines you need to change are shown in the middle of Figure 1-19, each beginning with #overscan.

Figure 1-19. Adjusting overscan

For the lines to take effect, you need to enable them by removing the # character from the start of each line.

To save and exit nano, press Ctrl-X, then press Y (to confirm), and then press Enter.

Then, using trial and error, change the settings until the screen fills as much of the monitor as possible. Note that the four numbers should be negative. Try setting them all to –20 to start with. This will decrease the area of the screen that is used.

Discussion

Having to repeatedly restart the Raspberry Pi to see the effects of the changes in resolution is a little tedious. Fortunately, you will need to do this procedure only once. Most monitors and TVs work just fine without any need for underscanning.

See Also

You can also configure underscanning using the raspi-config tool. For more information on this tool, go to http://elinux.org/RPi_raspi-config.

1.14 Maximizing Performance

Problem

Your Raspberry Pi seems to be very slow, so you want to overclock it to make it run faster.

Solution

If you have a Raspberry Pi 2, 3, or 4 with its quad-core processor, you are unlikely to find it to be too slow. However, the older, single-core Raspberry Pis can be pretty sluggish.

You can increase the clock frequency of a Raspberry Pi to make it run a little faster. This will make it consume a bit more power and run a little hotter (see the Discussion section that follows).

The method of overclocking described here is called dynamic overclocking because it automatically monitors the temperature of the Raspberry Pi and drops the clock speed back down if things begin to get too hot. This is called throttling.

The easiest way make your Pi overclock is to use the Raspberry Pi Configuration tool. To open this, go to the Raspberry Pi menu, select Preferences, and then click Raspberry Pi Configuration. Next, click on the Performance tab (Figure 1-20).

Figure 1-20. Configuring overclocking using the Raspberry Pi Configuration tool

The overclock options available to you will vary depending on which model of Raspberry Pi you have. Select one of the options and then click OK. Changes will take effect when you reboot.

If you are running your Raspberry Pi without a monitor (Recipe 1.9), you can still change the overclocking, but you will need to jump around and learn about SSH in Recipe 2.7. After you are able to connect with SSH, run the raspi-config utility by issuing the following command in an SSH Terminal:

$ sudo raspi-config

Select the Overclock option. You are then presented with the options shown in Figure 1-21.

Figure 1-21. Configuring overclocking with the raspi-config tool from the command line

Select an option. If you find that your Raspberry Pi starts to become unstable and hangs unexpectedly, you might need to choose a more conservative option or turn overclocking off by setting it back to None.

Discussion

The performance improvements from overclocking can be quite dramatic. To measure these, I used a Raspberry Pi B, without a case, at an ambient room temperature of 60 degrees (15 degrees C).

The test program was the following Python script. This just hammers the processor (that is, makes it work really hard) and is not really representative of the other things that go on in a computer, such as writing to the SD card, graphics, and so on. However, it does give a good indication of raw CPU performance if you want to test the effect of overclocking on your Raspberry Pi:

import time

def factorial(n):
  if n == 0:
    return 1
  else:
    return n * factorial(n-1)

before_time = time.clock()
for i in range(1, 10000):
  factorial(200)
after_time = time.clock()

print(after_time - before_time)

Note that we are jumping ahead a lot here, so if you are not familiar with Python, come back to this when you have read through Chapter 5.

Check out the results of the test in Table 1-3. The current and temperature were measured using test equipment.

Table 1-3. Overclocking

| Speed test | Current | Temperature (degrees C)
700 MHz | 15.8 seconds | 360mA | 27
1 GHz | 10.5 seconds | 420mA | 30

As you can see, the performance has increased by 33% but at a cost of drawing more current and a slightly higher temperature.

A well-ventilated enclosure will help to keep your Raspberry Pi running at full speed. There have also been some efforts to add water cooling to the Raspberry Pi. Frankly, this is just silly.

See Also

You can find much more information about the raspi-config tool at http://elinux.org/RPi_raspi-config.

1.15 Changing Your Password

Problem

By default, the password for a Raspberry Pi will be raspberry. You want to change this.

Solution

After you install Raspbian onto your SD card, you are prompted to change your password, but you can skip this step. You can change the password any time using the Raspberry Pi Configuration utility. To open this, go to the Raspberry Pi menu, select Preferences, and then click Raspberry Pi Configuration. Click the System tab. There, you will find the Change Password option (Figure 1-22).

Figure 1-22. Changing your password with the Raspberry Pi Configuration tool

Changing your password is one setting for which you do not need to restart your Raspberry Pi for the change to take effect.

Discussion

You can also change the password from a Terminal session simply by using the passwd command, as follows:

$ passwd
Changing password for pi.
(current) UNIX password:
Enter new UNIX password:
Retype new UNIX password:
passwd: password updated successfully

See Also

You can also change your password using the raspi-config tool (see http://elinux.org/RPi_raspi-config).

1.16 Shutting Down Your Raspberry Pi

Problem

You want to shut down your Raspberry Pi.

Solution

In the upper lefthand corner of the desktop, click the Raspberry menu. A dialog box opens, offering three shutdown options (Figure 1-23).

Shutdown

Shuts down the Raspberry Pi. You will need to unplug the power and then plug it back in to get the Raspberry Pi to boot up again.

Reboot

Reboots the Raspberry Pi.

Logout

Logs you out and displays a prompt to enter your login credentials so that you can log back in.

Figure 1-23. Shutting down your Raspberry Pi

You can also reboot using the Terminal by issuing the following command:

$ sudo reboot

You might need to do this after installing some software. When you do reboot, you’ll see the message shown in Figure 1-24, which illustrates the multiuser nature of Linux and warns all users connected to the Pi.

Figure 1-24. Shutting down your Raspberry Pi from the Terminal

Discussion

It is better to shut down your Raspberry Pi as described than to simply pull out the power plug because your Raspberry Pi might be in the middle of writing to the microSD card as you power it down. This could lead to file corruption.

Unlike shutting down most computers, shutting down a Raspberry Pi does not actually turn off the power. It goes into a low-power mode—and it is a pretty low-power device anyway (but the Raspberry Pi hardware has no control over its power supply).

See Also

You can buy a module that will turn off the power when the Raspberry Pi shuts down at https://oreil.ly/Jsx_U.

In Recipe 1.10 you will find an enclosure for Raspberry Pi that includes a power button.

For information on adding a Start button to your Raspberry Pi, see Recipe 12.14.

1.17 Installing the Raspberry Pi Camera Module

Problem

You want to use the Raspberry Pi Camera Module.

Solution

The Raspberry Pi Camera Module (Figure 1-25) is attached to a Raspberry Pi by a ribbon cable.

Figure 1-25. The Raspberry Pi Camera Module

There are actually two basic versions of the Pi Camera: the original version 1 (as shown in Figure 1-25) and the newer higher-resolution version 2.

The ribbon cable attaches to a special connector between the audio and HDMI sockets on a Raspberry Pi 2, 3, or 4. To fit the cable onto your Pi, gently pull up the levers on either side of the connector so that they unlock, and then press the cable into the slot with the shiny metal connector pads of the cable facing away from the Ethernet socket. Press the two levers of the connector back down to lock the cable in place (Figure 1-26).

Figure 1-26. Attaching a Raspberry Pi Camera Module to a Raspberry Pi 3 model B

Warning

The Camera Module packaging states that it is sensitive to static. Before handling it, ground yourself by touching something grounded, like the metal case of a PC.

Note that the Raspberry Pi Zero requires a special cable or adapter because its Camera connector is smaller than that of a full-sized Raspberry Pi (see “Modules”).

The Camera Module requires some software configuration. The easiest way to configure it is to use the Raspberry Pi Configuration tool. To open this, go to the Raspberry Pi main menu, select Preferences, and then click Raspberry Pi Configuration. Click the Interfaces tab, and then set the Camera option to Enabled (Figure 1-27).

Figure 1-27. Enabling the camera using the Raspberry Pi Configuration tool

If you are using your Raspberry Pi remotely using SSH (see Recipe 2.7), you can still enable the camera by using raspi-config. To run raspi-config, enter the following command into a Terminal session:

$ sudo raspi-config

Select Interfacing Options, and you will see the Camera option (Figure 1-28).

Figure 1-28. Enabling the camera by using raspi-config from the command line

Two commands are available for capturing still images and videos: raspistill and raspivid.

To capture a single still image, use the raspistill command, as shown here:

$ raspistill -o image1.jpg

A preview screen displays for about five seconds and then takes a photograph and stores it in the file image1.jpg in the current directory.

To capture video, use the command raspivid:

$ raspivid -o video.h264 -t 10000

The number at the end of the line is the recording duration in milliseconds—in this case, 10 seconds.

Discussion

Both raspistill and raspivid have a large number of options. If you type either command without any parameters, help text displays options that are available.

The camera module is capable of high-resolution stills and video recording.

The Raspberry Pi Camera version 2 has a resolution of 3280 x 2464 pixels and supports 1080p30, 720p60, and 640x480p90 video.

You can also buy a No Infra red (NoIR) version of the camera that has the infrared filter removed from the camera module to allow it to work at night under infrared illumination.

An alternative to the camera module is to use a USB webcam (see Recipe 8.2).

See Also

The RaspiCam documentation includes raspistill and raspivid.

1.18 Using Bluetooth

Problem

You want to use Bluetooth with your Raspberry Pi.

Solution

If you have a Raspberry Pi 3 or 4, the good news is that along with WiFi, you also get Bluetooth hardware. If you have an older Raspberry Pi, you can attach a USB Bluetooth adapter to it. However, in both cases, the software that you need for Bluetooth is now included in Raspbian.

If you have an older Raspberry Pi, be aware that not all Bluetooth adapters are compatible with the Raspberry Pi. Most are, but to be sure, buy one that is advertised as working with the Raspberry Pi. Figure 1-29 shows a Raspberry Pi 2 equipped with both a USB Bluetooth adapter (nearest to the camera) and a USB WiFi adapter.

Figure 1-29. Raspberry Pi 2 with USB Bluetooth and WiFi adapters

Bluetooth features are integrated into the Raspbian Pixel desktop in much the same way as on a Mac. In the upper-right corner of the screen, you will see the Bluetooth icon (circled in (Figure 1-30). Click this to open a menu of Bluetooth options.

Figure 1-30. The Raspbian Bluetooth menu

If you want to connect a Bluetooth peripheral such as a keyboard, click Add Device. The Add New Device dialog box opens, showing a list of available devices with which you can connect, or “pair” (Figure 1-31).

Figure 1-31. Pairing a Bluetooth device

You can then select the device that you want to pair with and then follow the instructions that appear on your Raspberry Pi and the device you are pairing with.

Discussion

You can pair phones, Bluetooth speakers, keyboards, and mice to your Raspberry Pi. I find that connecting a new Bluetooth device doesn’t always work the first time. So if you initially have a problem pairing with a device, try a few more times before you give up.

Most of the time, using the desktop interface to add Bluetooth devices to your Raspberry Pi system is convenient; however, you can also pair Bluetooth devices using the command-line interface.

To run Bluetooth commands from the command line, use the bluetoothctl command:

$ bluetoothctl
[NEW] Controller B8:27:EB:50:37:8E raspberrypi [default]
[NEW] Device 51:6D:A4:B8:D1:AA 51-6D-A4-B8-D1-AA
[NEW] Device E8:06:88:58:B2:B5 si’s keyboard #1
[bluetooth]#

This scans for Bluetooth devices and also provides a pair command that will allow you to pair with the device using its ID—for example:

[bluetooth]# pair E8:06:88:58:B2:B5

See Also

For a list of Bluetooth adapters that are compatible with the Raspberry Pi, see https://oreil.ly/pULy3.

The bluedot software for Android phones allows you to control hardware attached to your Raspberry Pi using Bluetooth and your mobile phone. You will find an example of this in Recipe 10.7.

If you pair your Raspberry Pi with a Bluetooth speaker, you also need to set the speaker to be the output for sound (Recipe 15.2).

Chapter 2. Networking

2.0 Introduction

The Raspberry Pi is designed to be connected to the internet. Its ability to communicate on the internet is one of its key features and opens up all sorts of possible uses, including home automation, web serving, network monitoring, and so on.

The connection can be wired through an Ethernet cable (at least in the case of most models), and newer models generally have built-in WiFi.

Having a connected Raspberry Pi also means that you can connect to it remotely from another computer. This is very useful for situations in which the Raspberry Pi itself is inaccessible and does not have a keyboard, mouse, and monitor attached to it.

This chapter gives you recipes for connecting your Raspberry Pi to the internet and controlling it remotely over a network.

2.1 Connecting to a Wired Network

Problem

You want to connect your Raspberry Pi to the internet using a wired network connection.

Solution

First, if you have a model A or A+ version of a Raspberry Pi (1, 2, or 3), or a Pi Zero, there is no RJ45 connector for Ethernet. In this case, your best option for internet access is to use a wireless USB adapter (see Recipe 2.5).

If you have a model B or B+ Raspberry Pi (1, 2, or 3) then you are in luck; just plug an Ethernet patch cable into its RJ45 socket and then connect the other end to a spare socket on the back of your home router (Figure 2-1).

Figure 2-1. Connecting Raspberry Pi to a home hub

The network LEDs on your Raspberry Pi should immediately begin to flicker as the Raspberry Pi connects to your network.

Discussion

Raspbian is preconfigured to connect to any network using Dynamic Host Configuration Protocol (DHCP). It will automatically be assigned an IP address as long as DHCP is enabled on your network.

If the LEDs blink but you cannot connect to the internet on your Raspberry Pi using a browser, check that DHCP is enabled on your network management console. Look for an option like that shown in Figure 2-2.

Figure 2-2. Enabling DHCP on your home hub

See Also

To connect to a wireless network, see Recipe 2.5.

2.2 Finding Your IP Address

Problem

You want to know the IP address of your Raspberry Pi so that you can communicate with it, whether connecting to it as a web server, exchanging files, or controlling it remotely with SSH (Recipe 2.7) or VNC (Recipe 2.8).

Solution

An IPv4 address (as used for local addresses) is a four-part number uniquely identifying a computer’s network interface within a network. Each part is separated from the next part by a dot.

To find the IP address of your Raspberry Pi, you need to issue this command in a Terminal window:

$ hostname -I
192.168.1.16 fd84:be52:5bf4:ca00:618:fd51:1c .....

The first part of the response is the local IP address of your Raspberry Pi on your home network.

Discussion

A Raspberry Pi can have more than one IP address (i.e., one for each network connection). So if you have both a wired connection and a wireless connection to your Pi, it would have two IP addresses. Normally, however, you would connect it by only one method or the other, not both. To see all the network connections, use the ifconfig command:

$ ifconfig

eth0      Link encap:Ethernet  HWaddr b8:27:eb:d5:f4:8f
          inet addr:192.168.1.16  Bcast:192.168.255.255  Mask:255.255.0.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:1114 errors:0 dropped:1 overruns:0 frame:0
          TX packets:1173 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:76957 (75.1 KiB)  TX bytes:479753 (468.5 KiB)

lo        Link encap:Local Loopback
          inet addr:127.0.0.1  Mask:255.0.0.0
          UP LOOPBACK RUNNING  MTU:16436  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

wlan0     Link encap:Ethernet  HWaddr 00:0f:53:a0:04:57
          inet addr:192.168.1.13  Bcast:192.168.255.255  Mask:255.255.0.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:38 errors:0 dropped:0 overruns:0 frame:0
          TX packets:28 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:6661 (6.5 KiB)  TX bytes:6377 (6.2 KiB)

Looking at the results of running the ifconfig command, you can see that the Pi in question is connected by both a wired connection (eth0) with an IP address of 192.168.1.16 and a wireless connection (wlan0) with an IP address of 192.168.1.13. The lo network interface is a virtual interface that allows the computer to communicate with itself.

See Also

Wikipedia has everything you want to know about IP addresses.

2.3 Setting a Static IP Address

Problem

You want to set the IP address of your Raspberry Pi so that it does not change.

Solution

There are two ways of doing this. One method uses your network controller (your home hub). The second method uses the Raspberry Pi itself.

The method using the network is generally preferable, but the second method, in which the Raspberry Pi determines its own IP address, is worth doing if you intend to move your Raspberry Pi between different networks and want to keep the IP address the same.

All the computers, TVs, phones, and other internet-enabled devices in your home are generally connected to the internet via the hub that links your phone line, 4G, or a fiber-optic cable to your house. All of these devices, whether they connect to the hub by WiFi or via a direct cable connection, are said to be part of your Local Area Network (LAN).

By default, when you connect a new device to your LAN (such as a Raspberry Pi), either by plugging it in with an Ethernet cable or by using WiFi, the LAN controller (your hub) will use a system called DHCP to allocate an IP address for the new device. This address will be allocated from a pool of IP addresses that might range from 192.168.1.2 to 192.168.1.199 (or maybe 10.0.0.2 to 10.0.0.199). In other words, just the last part of the four-part IP address changes for each device connected to the LAN.

When DHCP allocates an IP address to a device, it does so with a lease time, which is how long that device will be guaranteed to keep the IP address without risk of it being allocated to some other device. Generally speaking, the default for this lease time is fairly short; on my hub, it’s a week. This means that the IP address of my Raspberry Pi can change without warning after a week, and if the Pi is being used in a project without keyboard, mouse, and monitor, it can be difficult to find its IP address to allow me to connect to it. This is why I might want to set a static IP address for your Raspberry Pi.

Setting the IP address using the network

One way to ensure that your Raspberry Pi’s IP address doesn’t change is to simply go to your hub control interface and change the DHCP lease time to a much higher value. To access this interface, you will need to use a computer (it could be your Raspberry Pi, but it doesn’t have to be) and go to a specific address that is often written on the hub, described as router address or admin console address. For my router this is http://192.168.1.1. There will also be a username and password to be entered. These are not the same as the WiFi access point name and password. They’re often also written somewhere on the hub and often have default values of admin and password, respectively.

After you are connected, you will need to hunt around your admin console’s various pages for any mention of DHCP settings, which should look something like Figure 2-3.

Figure 2-3. Changing the DHCP lease time

Change the “Lease duration” (or whatever it’s specifically labeled for your hub) to the maximum allowed.

One downside of extending the lease duration like this is that it applies to all the devices on your LAN. So if you have a lot of devices, it’s possible that you might run out of IP addresses because DHCP is unable to reallocate old IP addresses until the lease period has expired.

A better approach is to use something called DHCP reservation. This instructs DHCP to permanently allocate a particular IP address to a particular device. In Figure 2-4, you can see that I have allocated the IP address of 192.168.1.3 to the device raspberrypi-Ethernet (a Raspberry Pi connected by Ethernet cable to the hub).

Figure 2-4. Allocating a DHCP reservation

From now on, whenever that Raspberry Pi is connected to the LAN, it will be assigned the IP address 192.168.1.3, and DHCP will not allocate that IP address to any other device.

Setting the IP address using the Raspberry Pi

The second approach to setting a static IP address for a Raspberry Pi uses the Raspberry Pi itself rather than the LAN. In effect, the Raspberry Pi is requesting, from the hub, the IP address it would like to use.

Allowing your Raspberry Pi to decide its own IP address runs slightly contrary to the way things usually work on a network, where the LAN determines the IP address. The danger is, of course, that the LAN’s DHCP controller has already allocated that IP address to some other computer. Similar problems arise if you have more than one Raspberry Pi, both trying to use the same IP address. IP addresses can’t be shared; in this event, one of the Raspberry Pis won’t connect to the network.

If you want to use the approach described in this section, you need to ensure that your IP address is unique for a particular Raspberry Pi and that you chose a static IP address for your Raspberry Pi that is outside of the DHCP range. For example, looking at Figure 2-3, you can see that the DHCP-allocated IP address range is from 192.168.1.2 to 192.168.1.199. So, if we picked a static IP address of 192.168.1.210, we know it won’t be reallocated. Note that each of the number parts of an IP address is between 0 and 255, so, for example, 192.168.1.300 is not a valid IP address.

Your Raspberry Pi will have a different IP address for each network connection. In this example, we will make the IP address static and the same for both WiFi and Ethernet cable.

To edit this file, type the following command in the Terminal:

$ sudo nano /etc/dhcpcd.conf

First, decide on an IP address to use. You need to pick one that is both unused by any other machine on the network and outside the range of the IP addresses used by DHCP. In this case, I will use 192.168.1.210. Then I’ll modify the contents of the file, adding the following lines to the end of the file:

interface eth0
static ip_address=192.168.1.210/24
static routers=192.168.1.1
static domain_name_servers=192.168.1.1

interface wlan0
static ip_address=192.168.1.210/24
static routers=192.168.1.1
static domain_name_servers=192.168.1.1

Note that, as I mentioned earlier, I have set the same IP address for both network interfaces (Ethernet and WiFi). If both connections are available, the first one to connect will shut the other out from using that IP address. In practice, this means that the Ethernet connection will win because it’s much faster to connect than WiFi.

The IP address used for the routers and domain_name_servers settings is the IP address you use to connnect to your hub’s admin console.

Many hubs use the aforementioned IP addressing range. The address next to the entries routers and domain_name_servers is the same address as you will find written on your hub as its admin console address.

However, if your hub uses the less common addressing format of 10.0.0.1, you will need to change all the instances of 192.168.1 in our earlier example to 10.0.0.

Once the changes are made, save the file by pressing Ctrl-X and then pressing Y. For a guide to using the nano editor, see Recipe 3.7.

You will need to reboot your Raspberry Pi by running sudo reboot before the changes take effect.

Discussion

Networking has changed a lot with different versions of Raspbian. These instructions apply to the latest (as of this writing) version of Raspbian (Buster). If you don’t have the latest version of Raspbian, you should get it, because Raspbian is always evolving and improving. You can learn how to do this in Recipe 3.40. To find out what version of Raspbian you have, see Recipe 3.39.

See Also

Wikipedia has everything you want to know about IP addresses.

2.4 Setting the Network Name of a Raspberry Pi

Problem

You want to change the network name of your Raspberry Pi so that it’s not just called “raspberrypi.”

Solution

There are several ways of doing this. Whichever method you use, make sure that the network name you choose does not contain spaces and contains only letters, numeric digits, and the hyphen (-) character.

In all three methods, you also need to restart your Raspberry Pi for the changes to take effect.

Setting the network name using the Raspberry Pi Configuration tool

Unless you are running your Raspberry Pi headless (without monitor and keyboard attached), the simplest way to set the network name of your Raspberry Pi is to use the Raspberry Pi Configuration tool. To open this, go to the Raspberry Pi menu, select Preferences, and then click Raspberry Pi Configuration. Then click the System tab (Figure 2-5).

Figure 2-5. Changing the Hostname using the Raspberry Pi Configuration tool

Change the name in the Hostname field to your preferred name and then click OK. You are then prompted to reboot so the changes will take effect (Recipe 1.16).

Setting the network name using the command line (the easy way)

You can also change your Raspberry Pi’s network name from the command line using the raspi-config tool. Run the following command in a Terminal session:

$ sudo raspi-config

This opens the raspi-config tool. Use the up/down cursor keys to select Network Options and then press return. This opens a form in which you can enter the new network name (Figure 2-6). Note that this interface uses only the command line, so you can use it from an SSH session (Recipe 2.7).

Figure 2-6. Setting the network name of a Raspberry Pi using raspi-config

Setting the network name using the command line (the hard way)

If you really want to do it the hard way, you can also directly edit the files that control the Raspberry Pi’s network name. There are two files that you need to change.

First, edit the file /etc/hostname. You can do this by opening a Terminal window and typing the command:

$ sudo nano /etc/hostname

Replace raspberrypi with a name of your choice.

Second, open the file /etc/hosts in an editor using the command:

$ sudo nano /etc/hosts

The file will look something like this:

127.0.0.1       localhost
::1             localhost ip6-localhost ip6-loopback
fe00::0         ip6-localnet
ff00::0         ip6-mcastprefix
ff02::1         ip6-allnodes
ff02::2         ip6-allrouters

127.0.1.1       raspberrypi

Change the name at the end of the file (raspberrypi) to your preferred new name.

Discussion

Changing the name of your Pi can be very useful, especially if you have more than one Pi connected to your network.

See Also

See Recipe 2.3 to change the IP address of your Raspberry Pi.

You can also set the network name of your Raspberry Pi using PiBakery—see Recipe 1.8

2.5 Setting Up a Wireless Connection

Problem

You want to connect your Raspberry Pi to the internet using WiFi.

Solution

There are various methods of setting up a WiFi connection with your Raspberry Pi.

Setting up WiFi from the Pixel Desktop

Setting up WiFi in the latest Raspbian is really easy. In the upper-right corner of your screen, click the network icon (the two computers) (Figure 2-7). You are then presented with a list of WiFi networks. Select your network; a prompt appears in which you can enter your Pre Shared Key (password). Enter your password. After a while, the network icon will switch to the standard WiFi symbol, and you will be connected.

Figure 2-7. Connecting to a WiFi network

Setting up WiFi using the command line (the easy way)

This method of setting up WiFi is great if you are setting up your Raspberry Pi so that, after you configure it, you can use it without keyboard and monitor attached. However, you will need to have network access to the Raspberry Pi temporarily connecting it to your hub using an Ethernet cable (Recipe 2.1).

Run the following command to start the raspi-config utility:

$ sudo raspi-config

Then, from the menu that opens, select Network Options (use the cursor keys and press Enter) and then select WiFi (Figure 2-8).

Figure 2-8. Setting up WiFi using raspi-config

A prompt appears, asking for the SSID (WiFi name) and password.

Setting up WiFi using the command line (the hard way)

You can also set up a wireless connection by using the command line to edit the necessary file directly. To do so, edit the file /etc/wpa_supplicant/wpa_supplicant.conf by using the following command:

$ sudo nano /etc/wpa_supplicant/wpa_supplicant.conf

Scroll down to the end of the file and then add the following lines:

network={
        ssid="my wifi name"
        psk="my wifi password"
}

Change the values for ssid and psk to match your WiFi’s name and password, respectively.

For the changes to the file to take effect, reboot your Raspberry Pi.

Discussion

WiFi uses quite a lot of power, so if you find your Pi rebooting unexpectedly or not booting properly, then you might need to use a larger power supply for it. Look for a supply that is 1.5A or higher; if you are using a Raspberry Pi 4 and are hanging high-power USB peripherals on it, use a 3A power supply.

If you are using your Raspberry Pi as a media center (see Recipe 4.1), then there will be a settings page on which you can connect the media center to your network using WiFi.

See Also

For a list of WiFi adapters that are compatible with the Raspberry Pi, go to https://oreil.ly/67Mn1.

For more information on setting up a wired network, see Recipe 2.1.

For information on using the nano editor, see Recipe 3.7.

To set up a WiFi connection using PiBakery, see Recipe 1.8.

2.6 Connecting with a Console Lead

Problem

No network connection is available, but you still want to be able to remotely control your Raspberry Pi from another computer.

Solution

Use a console cable (a special lead that you need to buy separately—see “Miscellaneous”) to connect to a Raspberry Pi.

To use this method, you will need to enable the Serial interface. This means that, at least while you are setting up your Raspberry Pi, you will need to have a keyboard, monitor, and mouse attached.

To enable the Serial interface, go to the Raspberry Pi menu, select Preferences, and then click Raspberry Pi Configuration. Select the Interfaces tab and then click the Enabled button for Serial Port, as shown in Figure 2-9.

Figure 2-9. Enabling the Serial interface using the Raspberry Pi Configuration tool

As with most Raspberry Pi configurations, you can also use the command-line raspi-config tool by running this command in a Terminal session:

$ sudo raspi-config

Select Interfacing Options and then Serial, as shown in Figure 2-10.

Figure 2-10. Enabling the Serial interface using the raspi-config tool

Console cables are great for a Pi that is going to be used headless—that is, without keyboard, mouse, or monitor.

The console cable shown in Figure 2-11 is available from Adafruit.

Figure 2-11. A console cable

Connect the lead as follows and by referring to Figure 2-11.

Connect the red (5V) lead to the 5V pin, one pin to the left of the edge of the GPIO header.

Connect the black (GND) lead to GND on the next pin to the left on the Raspberry Pi.

Connect the white lead (Rx) to Raspberry Pi GPIO 14 (TXD), to the left of the black lead.

Connect the green lead (Tx) to GPIO 15 (RXD), to the left of the white lead on the Raspberry Pi.

If you use a different lead, the wire colors might well be different, so always check the documentation for the lead or elseyou risk damaging your Raspberry Pi.

Note that the USB lead also provides 5V on the red wire, with enough power for the Pi on its own but not with a lot of devices attached.

If you are a Windows or macOS user, you will need to install drivers for the USB lead, which are available here for Windows and here for macOS. Linux users usually don’t need to install any drivers for these leads.

To connect to the Pi from macOS, you will need to run the Terminal and enter the following command:

$ sudo cu -l /dev/cu.usbserial -s 115200

After connecting, press Enter, and the Raspberry Pi login prompt should appear (Figure 2-12). The default username and password are pi and raspberry, respectively.

Figure 2-12. Logging in with a console cable

If you are trying to connect to your Raspberry Pi from a Windows computer, you need to download the terminal software called Putty.

When you run Putty, change the “Connection type” to Serial and set the speed to 115200. You also need to set the “Serial line” to be the COM port in use by the cable. This might be COM7, but if that does not work, check it by using the Windows Device Manager.

When you click Open and press Enter, the Terminal session should start with a login prompt.

Discussion

The console cable can be a very convenient way of using your Pi if you are traveling light, because it provides both power and a way to control the Pi remotely.

The console lead has a chip in the USB end that provides a USB-to-Serial interface. This sometimes (depending on your operating system) requires the installation of drivers on your PC. You should be able to use any USB-to-serial converter as long as it has the necessary drivers for your PC.

Plugging the sockets of the lead into the right places is made easier if you carefully glue (or tape) the four sockets together in the right order so that they fit over the GPIO header in a block.

Finding the right position on the GPIO header is made easier if you use a GPIO template like the Raspberry Leaf (see Recipe 9.1). The Raspberry Pi pinouts are shown in Appendix B.

See Also

You can find out more about using the serial console at this Adafruit tutorial. Adafruit also sells console cables. The lead used here is one supplied by Adafruit (product code 954).

2.7 Controlling the Pi Remotely with SSH

Problem

You want to connect to a remote Pi from another computer by using Secure Shell (SSH).

Solution

Before you can connect to your Raspberry Pi using SSH, you must turn on SSH. On newer versions of Raspbian, you can use the Raspberry Pi Configuration tool (Figure 2-13), which you can find on the Main menu under Preferences. Just select the box for SSH and then click OK. You are then prompted to restart.

If you prefer to use the command line, use the raspi-config application. You can start this at any time by entering the following command in Terminal:

$ sudo raspi-config

Click the Interfaces tab, scroll down to the SSH option, and then click the Enabled button.

Figure 2-13. Turning on SSH using the Raspberry Pi Configuration tool

If you are using macOS or have Linux installed on the computer from which you want to connect your Pi, all you need to do to connect is open a Terminal window and enter the following command:

$ ssh 192.168.1.16 -l pi

Here, the IP address (192.168.1.16) is the IP address of your Pi (see Recipe 2.2). You are then prompted for your password and logged in to the Pi (Figure 2-14).

Figure 2-14. Logging in with SSH

To connect from a Windows computer, you will need to use Putty (Recipe 2.6) to start an SSH session.

Discussion

SSH is a very common way of connecting to remote computers; any commands that you could issue on the Pi itself, you can use from SSH. It is also, as its name suggests, secure because the communication is encrypted.

Perhaps the only drawback is that it is a command-line rather than graphical environment. If you need access to the full Raspberry Pi desktop environment remotely, you need to use VNC (Recipe 2.8) or RDP (Recipe 2.9).

See Also

See also this Adafruit tutorial.

You can also enable SSH using PiBakery.

2.8 Controlling the Pi Remotely with VNC

Problem

You want access to the full Raspbian graphical desktop of your Pi from a PC (Windows or Linux) or macOS, using virtual network computing (VNC).

Solution

Use the preinstalled VNC software on Raspbian. However, to do so, you will first need to configure your Raspberry Pi to turn it on. You can do this using the Raspberry Pi Configuration tool, which you can find in the Preferences section of the Main menu on the Raspberry Pi desktop. Click the Interfaces tab, scroll down to the VNC option, select the Enabled button, and then click OK (Figure 2-15).

Figure 2-15. Turning on the VNC interface

If you don’t mind your virtual screen being very low resolution, you can skip ahead in this recipe to connect to your Raspberry Pi remotely, but in all likelihood, you will want to increase the resolution. To do this, edit the config.txt file by using the following command:

$ sudo nano /boot/config.txt

Find the lines that look like this:

# framebuffer_width=1900
# framebuffer_height=1024

Remove the # character at the beginning of each line to enable the new screen width and height, as shown here:

framebuffer_width=1900
framebuffer_height=1024

You need to reboot for the changes to take effect.

To connect to the Pi from a remote computer, you need to install VNC client software. RealVNC VNC Viewer is a popular choice and is available for Windows, Linux, and macOS.

When you run the client program on macOS or a PC, you will be asked to enter the IP address of the VNC server to which you want to connect (the IP address of your Pi).

You are then prompted for your password (Figure 2-16).

Figure 2-16. Authenticating a VNC connection

The Catchphrase and Signature are security devices designed to alert you if someone is hacking your Raspberry Pi. If either changes when you authenticate another time, your Raspberry Pi might be compromised.

Discussion

Although you can do most things with SSH using the command line, sometimes it is useful to have access to the graphical environment of your Raspberry Pi.

The Raspberry Pi’s VNC server automatically starts when you reboot, as long as the VNC option is enabled.

See Also

See also this Adafruit tutorial.

See also Recipe 2.9.

You can also enable VNC while setting up a new Raspberry Pi using PiBakery.

2.9 Controlling the Pi Remotely Using RDP

Problem

You want access to the full Raspbian graphical desktop of your Pi from a PC or macOS using Microsoft Remote Desktop Protocol (RDP).

Solution

Install the XRDP software on your Raspberry Pi by entering the following commands:

$ sudo apt-get update
$ sudo apt-get install xrdp

After the software is installed, it will automatically start the xrdp service, which ensures that xrdp will automatically start when the Raspberry Pi is rebooted.

If you have Windows 7 or later, it already includes an RDP client for connecting to your Raspberry Pi. To access it, click All Programs on your Start menu, then select Accessories, and then click Remote Desktop Connection. For older versions of Windows, you can download the client from: ModMyPi.

macOS users can download the Microsoft RDP client for macOS from the App Store (it’s free).

A client for Linux machines is available from http://www.rdesktop.org.

When you start your RDP client, you will first need to add a new connection. Enter the IP address of your Raspberry Pi as well as your username and password (Figure 2-17), which are the same as your usual Raspberry Pi login—that is, a username of pi and a password of raspberry, unless you have changed it.

You will probably also want to pick a Resolution and clear the “Start session in full screen” option.

Figure 2-17. Making a new RDP connection with Microsoft remote desktop software

Discussion

RDP does the same job as VNC but works more efficiently and therefore refreshes the contents of the screen more smoothly.

See Also

See also Recipe 2.8.

2.10 File Sharing on a Mac Network

Problem

You want your Raspberry Pi to appear on the list of computers in the macOS Finder so that you can connect to it and browse the filesystem using Finder.

Solution

The macOS operating system includes built-in support for file viewing in Finder over the network (Figure 2-18). However, you must make some configuration changes on your Raspberry Pi for macOS to view network files on your Raspberry Pi.

Figure 2-18. Raspberry Pi in the macOS Finder

You will need to know the IP address of your Raspberry Pi (Recipe 2.2).

On the Raspberry Pi, install netatalk by using the following commands:

$ sudo apt-get update
$ sudo apt-get install netatalk

Next, back on your Mac, in the Finder menu, select Go, click Connect to Server, and then enter afp://192.168.1.210 as the server address (using the IP address for your Raspberry Pi, of course, not the one shown here). Then, click Connect. You are then prompted to log in (Figure 2-19).

Figure 2-19. Connecting to a Raspberry Pi from the macOS Finder

Log in using the name pi and your password, which will be raspberry, unless you have changed it. The Finder should then show you the contents of your home directory on the Raspberry Pi.

There are a few more configuration changes to make on the Raspberry Pi, which will automatically mount your Raspberry Pi on your Mac’s filesystem:

$ sudo apt-get update
$ sudo apt-get install avahi-daemon
$ sudo update-rc.d avahi-daemon defaults

Next, type this command:

$ sudo nano /etc/avahi/services/afpd.service

Paste the following code into the file. This is a lot to type, so if you are reading a paper copy of this book, you can copy and paste it from this web page. Just scroll down until you find this chapter and recipe:

<?xml version="1.0" standalone='no'?><!--*-nxml-*-->
<!DOCTYPE service-group SYSTEM "avahi-service.dtd">
<service-group>
   <name replace-wildcards="yes">%h</name>
   <service>
      <type>_afpovertcp._tcp</type>
      <port>548</port>
   </service>
</service-group>

To set the daemon running so that this happens automatically whenever your Raspberry Pi boots up, type this command:

$ sudo /etc/init.d/avahi-daemon restart

Switch back to your Mac, and you should now see your Raspberry Pi in the Finder.

Discussion

Being able to move files easily between your Mac and your Raspberry Pi is very useful. It means that you can use files on your Pi without having to hook up a separate keyboard, mouse, and monitor.

You can also open files on the Raspberry Pi as if they were on your Mac. This has the advantage that you can edit them using TextMate or your favorite macOS text editor.

If you’re using Windows or Linux, you can also share files by configuring your Raspberry Pi to work as Network Attached Storage (NAS); see Recipe 2.11.

See Also

The instructions here were adapted from this tutorial, which credits Matt Richardson and Shawn Wallace’s book Getting Started with Raspberry Pi (O’Reilly) as the original source.

2.11 Using a Raspberry Pi for Network Attached Storage

Problem

You want to use your Raspberry Pi as Network Attached Storage (NAS) by accessing a large USB drive attached to your Raspberry Pi from computers on your network.

Solution

The solution to this problem is to install and configure Samba. To do this, issue the following commands:

$ sudo apt-get update
$ sudo apt-get install samba
$ sudo apt-get install samba-common-bin

Next, attach the USB hard drive to the Raspberry Pi. It will automatically mount in your /media/pi folder. To check that it’s there, run this command:

$ cd /media/pi
$ ls

The drive should be listed with whatever name you gave it when you formatted it. It will automatically mount itself whenever the Raspberry Pi reboots.

You next need to configure Samba so that the drive can be shared on the network. To do this, you first need to add a Samba user (pi). Enter the following command and type in a password:

$ sudo smbpasswd -a pi
New SMB password:
Retype new SMB password:
Added user pi.

You now need to make some changes to the file /etc/samba/smb.conf, so enter this command:

$ sudo nano /etc/samba/smb.conf

The first line you’re looking for is near the top of the file:

workgroup = WORKGROUP

You only need to change this if you plan to connect from a Windows machine. This should be the name of your Windows workgroup. For Windows XP, the default is MSHOME; for newer versions of Windows, it is HOME (but check on your Windows network). Note that generally connecting to NAS in a mixed network of Macs and Windows PCs (and, for that matter, Linux machines) works just fine.

The next change to be made is further down the file in the Authentication section. Find the following line:

# security = user

Remove the # from the beginning of the line to activate the line and turn security on. Finally, scroll to the end of the file and add the following lines:

[USB]
path = /media/pi/NAS
comment = NAS Drive
valid users = pi
writeable = yes
browseable = yes
create mask = 0777
public = yes

Save the file and then restart Samba by entering the following:

$ sudo /etc/init.d/samba restart

If all is well, your USB drive should now be shared on your network.

Discussion

To connect to the drive on a macOS, select Go, and then, from the Finder menu, click Connect to Server. Next, in the Server Address field, enter smb://raspberrypi/USB. A login dialog box opens, in which you need to change the username to pi (Figure 2-20).

Figure 2-20. Connecting to NAS with the macOS Finder

If you are connecting to NAS from a Windows machine, the exact procedure will vary depending on your version of Windows. However, the basic principle is that at some point you will need to enter the network address, which should be \\raspberrypi\USB (Figure 2-21).

Figure 2-21. Connecting to NAS from Windows

You are then prompted for the username and password before you can use the NAS disk (Figure 2-22). You should only have to do this the first time. After the network place is added, you should be able to navigate directly to it in File Explorer.

Figure 2-22. Browsing NAS on Windows

If you are a Linux user, the following command should mount the NAS drive for you:

$ sudo mkdir /pishare
$ sudo smbmount -o username=pi,password=raspberry //192.168.1.16/USB /pishare

See Also

You might want to change your Raspberry Pi’s network name to something inappropriate like “piNAS” (see Recipe 2.4).

2.12 Network Printing

Problem

You want to print to a network printer from your Raspberry Pi.

Solution

Use Common Unix Printing System (CUPS).

Start by entering the following commands into a Terminal to install CUPS (this can take some time):

$ sudo apt-get update
$ sudo apt-get install cups

Give yourself admin privileges for CUPS by entering the following command:

$ sudo usermod -a -G lpadmin pi

This last command adds the lpadmin group used by CUPS to the user pi so that you have permission to print.

CUPS is configured via a web interface. Start Chromium, and then on the Main menu, in the Internet group (or click on the icon on your desktop), navigate to the address http://localhost:631.

On the Administration tab, choose the Add Printer option. This displays a list of printers that are on the network or are connected directly to the Raspberry Pi’s USB port (Figure 2-23).

Figure 2-23. Discovering printers with CUPS

Follow the series of dialog boxes to set up the printer.

Discussion

When you’re finished, you can test out the printer by firing up LibreOffice. Type some text, and when you go to print it, you should see your newly added printer available for printing (Figure 2-24).

Figure 2-24. The print dialog box

See Also

See also the official CUPS website.

Chapter 3. Operating System

3.0 Introduction

This chapter explores many aspects of the Linux operating system used by the Raspberry Pi. A lot of this involves the use of the command line. If you are used to Windows or macOS, this can come as a bit of a shock. However, when you get used to it, doing things with the command line can be surprisingly effective.

You can accomplish many simple file operations like moving files around, renaming, copying, and deleting files graphically using a more Windows or macOS approach, and this is the subject of our first recipe.

3.1 Browsing Files Graphically

Problem

You want to move files around using a graphical interface like you can on a macOS-based machine or Windows PC.

Solution

Use the File Manager.

You can find this program on your Main menu, in the Accessories group (Figure 3-1).

Using the File Manager, you can drag a file or directory from one directory to another or use the Edit menu to copy a file from one location and paste it to a second. This operates in much the same way as the Windows File Manager or macOS Finder.

Figure 3-1. The File Manager

Discussion

The lefthand side of the File Manager shows the folder structure.

The central area displays the files in the current folder, which you can navigate using the buttons in the toolbar or by typing a location in the file path area at the top.

You can right-click a file to open a menu presenting options you can use on that file (Figure 3-2).

Figure 3-2. Right-clicking a file opens a menu with more options

You can also select more than one file at a time for copying or dragging by holding down the Ctrl key while you select files, or you can select a range of files by selecting one file and then holding down the Shift key while you select the end of the list of files that you want to select.

See Also

See also Recipe 3.5.

3.2 Copying Files onto a USB Flash Drive

Problem

You want to copy a file from your Raspberry Pi onto a USB flash drive.

Solution

Insert the USB flash drive into a USB port, and the dialog shown in Figure 3-3 should appear. Select OK to open it in the File Manager.

Figure 3-3. The removable-media dialog box

The drive will be mounted in /media/pi followed by the name of the flash drive (in my case, UNTITLED). To copy a file from your home folder, drag it onto the folder representing your flash drive, as shown in Figure 3-4.

Figure 3-4. Copying a file by dragging it onto a USB flash drive

Windows, macOS, and Linux all have their own disk formats. The USB flash drive should be formatted as FAT32 or exFAT for maximum compatibility with macOS and Windows computers. exFAT supports larger disk sizes than FAT32.

Discussion

After your USB flash drive is mounted on the Raspberry Pi’s filesystem, you can also copy files using the command line. The following example copies the file test.txt to the flash drive:

$ cd /home/pi
$ cp test.txt /media/pi/UNTITLED/

In this example, cd is the command to change directory, and cp is the copy command. These commands are explained more fully in Recipe 3.4 and Recipe 3.5.

See Also

For general information on using the File Manager, see Recipe 3.1.

To copy files from the command line, see Recipe 3.4.

3.3 Starting a Terminal Session

Problem

When using a Raspberry Pi, you need to issue text commands in a Terminal.

Solution

At the top of the Raspberry Pi desktop, select the Terminal icon (it looks like a black computer monitor), or, on the Start menu in the Accessories group, select the Terminal menu option (Figure 3-5).

Figure 3-5. Opening the Terminal

Discussion

When the Terminal starts, it is set to your home directory (/home/pi).

You can open as many Terminal sessions as you want. It is often useful to have a couple of sessions open in different directories so that you don’t need to constantly switch directories using cd (Recipe 3.4).

When using the Terminal, everything is case sensitive. That is, if you are using a command, you must use the correct case when you’re typing. For example, the ls command that you will meet in the next recipe must be written as lowercase ls and not LS or Ls or lS. Similarly, all filenames are case sensitive, so files named picture.jpg and Picture.jpg are two different files.

See Also

In the next section (Recipe 3.4), you will look at navigating the directory structure using the Terminal.

3.4 Navigating the Filesystem Using a Terminal

Problem

You need to know how to change directory and move about the filesystem using the Terminal.

Solution

The main command used for navigating the filesystem is cd (change directory). After cd, you need to specify the directory that you want to change to. This can be either a relative path to a directory within your current directory or an absolute path to somewhere else on the filesystem.

To see what the current directory is, use the command pwd (print working directory).

Discussion

Try out a few examples. Open a Terminal session, and you should see a prompt like this:

pi@raspberrypi: ~ $

The prompt that you will see after each command (pi@raspberrypi: ~ $) is a reminder of your username (pi) and your computer name (raspberrypi). The ~ character is shorthand for your home directory (/home/pi). So at any point you can change your current directory to your home directory as follows:

$ cd ~

Tip

Throughout the book, I use a $ at the beginning of each line where you are expected to type a command. This is called the prompt. The response from the command line is not prefixed by anything; it appears just as it does on the Raspberry Pi’s screen.

You can confirm that the command did indeed set the directory to the home directory by using the pwd command:

$ pwd
/home/pi

If you want to move up one level in the directory structure, you can use the special value .. (two dots) after the cd command, as shown here:

$ cd ..
$ pwd
/home

As you might have deduced by now, the path to a particular file or directory is made up of words separated by a /. So the very root of the entire filesystem is /, and to access the home directory within /, you would refer to /home/. Then, to find the pi directory within that, you would use /home/pi/. You can omit the final / from a path.

Paths can be absolute (starting with a / and specifying the full path from the root), or they can be relative to the current working directory, in which case they must not start with a /.

You will have full read and write access to the files in your home directory, but when you move into the places where system files and applications are kept, your access to some files will be restricted to read-only. You can override this (Recipe 3.12), but some care is required.

Check out the root of the directory structure by entering the commands cd / and ls, as shown in Figure 3-6.

Figure 3-6. Listing the contents of a directory

The ls command (list) shows us all of the files and directories below (/) the root directory. You will see that there is a home directory listed, which is the directory you have just come from.

Now change into one of those directories by using the commands shown in Figure 3-7.

Figure 3-7. Changing directory and listing the contents

You will see that the files and folders have some color coding. Files are displayed in various colors, whereas directories are dark blue.

Unless you particularly like typing, the Tab key offers a convenient shortcut. If you start typing the name of a file, pressing the Tab key allows the autocomplete feature to attempt to complete the filename. For example, if you’re going to change directory to network, type the command cd netw and then press the Tab key. Because netw is enough to uniquely identify the file or directory, pressing the Tab key will autocomplete it.

If what you have typed is not enough to uniquely identify the file or directory, pressing the Tab key another time will display a list of possible options that match what you have typed so far. So if you had stopped at net and pressed the Tab key, you would see something like Figure 3-8.

Figure 3-8. Autocompletion using the Tab key

You can provide an extra argument after ls to narrow down the things that you want to list. Change directory to /etc and then run the following:

$ ls f*
fake-hwclock.data  fb.modes  fstab  fuse.conf

fonts:
conf.avail  conf.d  fonts.conf  fonts.dtd

foomatic:
defaultspooler  direct  filter.conf

fstab.d:
pi@raspberrypi /etc $

The * character is called a wildcard. In specifying f* after ls, we are saying that we want to list everything that begins with an f.

Helpfully, the results first list all the files within /etc that begin with f, and then the contents of all the directories in that folder beginning with f.

A common use of wildcards is to list all files with a certain extension (e.g., ls *.docx).

A convention in Linux (and many other operating systems) is to prefix files that should be hidden from the user by starting their name with a period. Any so-named files or folders will not appear when you type ls unless you supply ls with the option -a (all).

For example:

$ cd ~
$ ls -a
.                                  Desktop               .pulse
..                                 .dillo                .pulse-cookie
Adafruit-Raspberry-Pi-Python-Code  .dmrc                 python_games
.advance                           .emulationstation     sales_log
.AppleDB                           .fltk                 servo.py
.AppleDesktop                      .fontconfig           .stella
.AppleDouble                       .gstreamer-0.10       stepper.py.save
Asteroids.zip                      .gvfs                 switches.txt.save
atari_roms                         indiecity             Temporary Items
.bash_history                      .local                thermometer.py
.bash_logout                       motor.py              .thumbnails
.bashrc                            .mozilla              .vnc
.cache                             mydocument.doc        .Xauthority
.config                            Network Trash Folder  .xsession-errors
.dbus                              .profile              .xsession-errors.old

As you can see, the majority of the files and folders in your home directory are hidden.

See Also

See also Recipe 3.14.

3.5 Copying a File or Folder

Problem

You want to copy a file using a Terminal session.

Solution

Use the cp command to copy files and directories.

Discussion

You can, of course, copy files by using the File Manager and its copy and paste menu options (Recipe 3.1) or keyboard shortcuts.

The simplest example of copying in a Terminal session is to make a copy of a file within your working directory. The cp command is followed first by the file to copy and then by the name to be given to the new file.

For example, the following example creates a file called myfile.txt and then makes a copy of it with the name myfile2.txt; you can find out more about the trick of creating a file using the > command in Recipe 3.9:

$ echo "hello" > myfile.txt
$ ls
myfile.txt
$ cp myfile.txt myfile2.txt
$ ls
myfile.txt    myfile2.txt

Although in this example both file paths are local to the current working directory, the file paths can be to anywhere in the filesystem where you have write access. The following example copies the original file to an area /tmp, which is a location for temporary files (do not put anything important in that folder):

$ cp myfile.txt /tmp

Note that in this case, the name to be given to the new file is not specified, just the directory where it is to go. This will create a copy of myfile.txt in /tmp with the same name of myfile.tmp.

Sometimes, rather than copying just one file, you might want to copy an entire directory full of files and possibly other directories. To copy a directory and all its contents, you need to use the -r option (for recursive):

$ cp -r mydirectory mydirectory2

Whenever you are copying files or folders, the result of the command will tell you if you do not have permission. If that’s the case, you will need to either change the permissions of the folder into which you are copying (Recipe 3.14) or copy the files with superuser privileges (Recipe 3.12).

See Also

See also Recipe 3.6.

For a useful description of the many optional parameters to the cp command, see https://www.computerhope.com/unix/ucp.htm.

3.6 Renaming a File or Folder

Problem

You need to rename a file by using a Terminal session.

Solution

Use the mv command to rename files and directories.

Discussion

The mv (move) command is used in a similar way to the cp command, except that the file or folder being moved is simply renamed rather than a duplicate being made.

For example, to rename a file from my_file.txt to my_file.rtf, you use the following command:

$ mv my_file.txt my_file.rtf

Changing a directory name is just as straightforward, and you don’t need the recursive -r option you used when copying, because changing a directory’s name implicitly means that everything within it is contained in a renamed directory.

See Also

See also Recipe 3.5.

3.7 Editing a File

Problem

You want to run an editor from the command line to change a configuration file.

Solution

Use the nano editor included with most Raspberry Pi distributions.

Discussion

To use nano, simply type the command nano followed by the file name or path to the file that you want to edit. If the file does not exist, it will be created when you save it. However, this will happen only if you have write permissions in the directory to which you are trying to write the file.

From your home directory, type the command nano my_file.txt to edit or create the file my_file.txt. Figure 3-9 shows nano in action.

Figure 3-9. Editing a file with nano

You cannot use the mouse to position the cursor; you must use the arrow keys instead.

The area at the bottom of the screen lists a number of commands that you can access by holding down the Ctrl key and pressing the letter indicated. Most of these are not that useful. The ones that you are most likely to use are as follows:

Ctrl-X

Exit. You will be prompted to save the file before nano exits.

Ctrl-V

Next page. Think of it as an arrow pointing downward. This allows you to move through a large file one screen at a time.

Ctrl-Y

Previous page.

Ctrl-W

Where is. This allows you to search for a piece of text.

Ctrl-O

Output. This will write the file without exiting the editor.

There are also some fairly crude copy-and-paste options there, but in practice, it’s easier to use the normal clipboard from the menu that you access with a right-click, as demonstrated in Figure 3-10.

Figure 3-10. Using the clipboard in nano

Using this clipboard also allows you to copy and paste text between other windows, such as your browser.

When you’re ready to save your changes to the file and exit nano, use the command Ctrl-X. Type Y to confirm that you want to save the file. nano then displays the filename as the default name to save the file under; press Enter to save and exit.

If you want to abandon the changes you have made, enter N in place of Y.

See Also

Editors are very much a matter of personal taste. Many other editors that are available for Linux will work just fine on Raspberry Pi. The vim (vi improved) editor has many fans in the Linux world. This is also included in the popular Raspberry Pi distributions. It is not, however, an easy editor for the beginner. You can run it in the same way as nano, but you use the command vi instead of nano. You can find details on using vim at https://oreil.ly/y0fym.

3.8 Viewing the Contents of a File

Problem

You want to view the contents of a small file without editing it.

Solution

Use the cat command or the more command to view the file.

For example:

$ more myfile.txt
This file contains
some text

Discussion

The cat command displays the whole contents of the file, even if the contents are longer than will fit on the screen.

The more command displays only one screen of text at a time. Press the space bar to display the next screen.

See Also

You can also use cat to concatenate (join together) a number of files (Recipe 3.32).

Another popular command related to more is less. less is like more except that it allows you to move backward in the file as well as forward.

3.9 Creating a File Without Using an Editor

Problem

You want to create a one-line file without having to use an editor.

Solution

Use the > and echo commands to redirect what you type on the command line to a file.

For example:

$ echo "file contents here" > test.txt
$ more test.txt
file contents here

Warning

The > command overwrites any existing file, so use it with caution.

Discussion

This can be useful for quickly creating a file.

See Also

To use the more command to view files without using an editor, see Recipe 3.8.

To use > to capture other kinds of system output, see Recipe 3.31.

3.10 Creating a Directory

Problem

You want to create a new directory by using the Terminal.

Solution

The mkdir command creates a new directory.

Discussion

To create a directory, use the mkdir command. Try out the following example (note that only the commands are shown, not the responses):

$ cd ~
$ mkdir my_directory
$ cd my_directory
$ ls

You need to have write permissions in the directory within which you are trying to create the new directory.

See Also

For general information on using the Terminal to navigate the filesystem, see Recipe 3.4.

3.11 Deleting a File or Directory

Problem

You want to delete a file or directory using the Terminal.

Solution

The rm (remove) command will delete a file or directory and its contents. You should use this with extreme caution.

Discussion

Deleting a single file is simple and safe. The following example will delete the file my_file.txt from the home directory; you can use the ls command to make sure it’s gone:

$ cd ~
$ rm my_file.txt
$ ls

You need to have write permissions in the directory within which you are trying to carry out the deletion.

You can also use the * wildcard when deleting files. This example deletes all the files that begin with my_file. in the current directory:

$ rm my_file.*

You could also delete all the files in the directory by typing:

$ rm *

If you want to recursively delete a directory (that is, not just the directory itself, but all the files and directories that it contains), you can use the -r option:

$ rm -r mydir

Warning

When deleting files from a Terminal window, remember that you do not have the safety net of a recycle bin from which deleted files can be retrieved. Also, generally speaking, you won’t be given the option to confirm; the files will just immediately be deleted. This can be totally devastating if you combine it with the sudo command (Recipe 3.12).

See Also

See also Recipe 3.4.

If you are concerned about accidentally deleting files or folders, you can force the rm command to confirm by setting up a command alias (Recipe 3.36).

3.12 Performing Tasks with Superuser Privileges

Problem

Some commands don’t work because you have insufficient privileges.

Solution

You need to issue commands with superuser privileges. The sudo (substitute user do) command allows you to perform actions with superuser privileges. Just prefix the command with sudo.

Discussion

Most tasks that you want to perform on the command line can usually be performed without superuser privileges. The most common exceptions to this are when you’re installing new software and editing configuration files. The apt-get command is the principal way of installing new software into Raspbian. You will meet it formally in Recipe 3.17.

Another example requiring superuser privileges is the reboot command. If you try to run it as a normal user, you will receive a number of error messages:

$ reboot
Failed to set wall message, ignoring: Interactive authentication required.
Failed to reboot system via logind: Interactive authentication required.
Failed to open /dev/initctl: Permission denied
Failed to talk to init daemon.

If you issue the same command prefixed with sudo, the command will work just fine:

$ sudo reboot

If you have a whole load of commands to run as superuser and don’t want to have to prefix each command with sudo, you can use the following command:

$ sudo sh
#

Note how the prompt changes from $ to #. All subsequent commands will be run as superuser. When you want to revert to being a regular user, enter the command:

# exit
$

See Also

To understand more about file permissions, see Recipe 3.13.

To install software using apt-get, see Recipe 3.17.

3.13 Understanding File Permissions

Problem

You have seen the strange characters that accompany a filename when it is listed. You would like to know what they all mean.

Solution

To see the permissions and ownership information relating to files and directories, use the ls command with the option -l.

Discussion

Run the command ls -l (the option letter is a lowercase L), and you will see a result like this:

$ ls -l
total 16
-rw-r--r-- 1 pi pi    5 Apr 23 15:23 file1.txt
-rw-r--r-- 1 pi pi    5 Apr 23 15:23 file2.txt
-rw-r--r-- 1 pi pi    5 Apr 23 15:23 file3.txt
drwxr-xr-x 2 pi pi 4096 Apr 23 15:23 mydir

The first line of response from the ls command tells you that there are 16 files in the directory.

Figure 3-11 shows the different sections of the listing information. The first block contains the permissions. In the second block, the number 1 (labeled “Files”) indicates how many files are involved. This field makes sense only if the listing entry is for a directory; if it is a file, it will mostly just be 1. The next two entries (both pi) are the owner and group of the file. The size entry (the fifth block) indicates the size of the file in bytes. The date modified will change every time the file is edited or changed, and the final entry is the actual name of the file or directory.

Figure 3-11. File permissions

The permissions block is split into four sections (Type, Owner, Group, and Other). The first section is the type of the file. If this is a directory, it will be the character d; if it is a file, the entry will just be a -.

The next section comprises three characters that, specify the various owner permissions for the file. Each character is a flag that is either on or off. If the owner has read permissions, there will be an r in the first character position. If the owner has write permissions, there will be a w in the second slot. The third position, which is - in this example, will have an x if the file is executable (a program or script) by the owner.

The third section has the same three flags but for any users in the group. Users can be organized into groups. So, in this case, the file has a user pi and a group ownership of pi. If there were any other users in the group pi, they would have the permissions specified here.

The final section specifies the permissions for users who are neither pi nor in the group pi.

Because most people will only ever use the Raspberry Pi as the user pi, the permissions of most interest are in the first section.

See Also

To change file permissions, see Recipe 3.14.

3.14 Changing File Permissions

Problem

You need to change the permissions of a file.

Solution

You can use the command chmod to modify file permissions.

Discussion

Common reasons why you might want to change file permissions include needing to edit a file that is marked as read-only and giving a file execute permissions so that it can run as a program or script.

The chmod command allows you to add or remove permissions for a file. There are two syntaxes for doing this; one requires the use of octal (base 8), and the other is text based. You will use the easier-to-understand text method.

The first parameter to chmod is the change to make, and the second is the file or folder to which it should apply. This change parameter takes the form of the permission scope (+, -, = for add, remove, and set, respectively) and then the permission type.

For example, the following code will add execute (x) rights for the owner (user) of the file file2.txt:

$ chmod u+x file2.txt

If we now list the directory, we can see that the x permission has been added:

$ ls -l
total 16
-rw-r--r-- 1 pi pi    5 Apr 23 15:23 file1.txt
-rwxr--r-- 1 pi pi    5 Apr 24 08:08 file2.txt
-rw-r--r-- 1 pi pi    5 Apr 23 15:23 file3.txt
drwxr-xr-x 2 pi pi 4096 Apr 23 15:23 mydir

If we wanted to add execute permissions for the group or for other users, we would use g and o, respectively. The letter a adds the permission to everyone.

See Also

For background on file permissions, see Recipe 3.13.

See Recipe 3.15 for changing file ownership.

3.15 Changing File Ownership

Problem

You need to change the ownership of a file.

Solution

You can use the command chown (change owner) to modify the ownership of a file or directory.

Discussion

As we discovered in Recipe 3.13, any file or directory has both an owner and a group associated with it. Because most users of the Raspberry Pi will just have the single user pi, we don’t really need to worry about groups.

Occasionally, you will find files on your system that have been installed with a different user than pi. If this is the case, you can change the ownership of the file by using the chown command.

To change the owner of a file, use chown followed by the new owner and group, separated by a colon, and then the name of the file.

You will probably find that you need superuser privileges to change ownership, in which case you should prefix the command with sudo (Recipe 3.12):

$ sudo chown root:root file2.txt
$ ls -l
total 16
-rw-r--r-- 1 pi   pi      5 Apr 23 15:23 file1.txt
-rwxr--r-- 1 root root    5 Apr 24 08:08 file2.txt
-rw-r--r-- 1 pi   pi      5 Apr 23 15:23 file3.txt
drwxr-xr-x 2 pi   pi   4096 Apr 23 15:23 mydir

See Also

For background on file permissions, see Recipe 3.13.

Also see Recipe 3.14 for changing file permissions.

3.16 Making a Screen Capture

Problem

You want to capture an image of the Raspberry Pi’s screen and save it to a file.

Solution

Use the delightfully named scrot (SCReenshOT) screen capture software.

Discussion

The simplest way to trigger a screen capture is just to enter the command scrot. This will immediately take an image of the primary display and save it in a file named something like 2019-04-25-080116_1024x768_scrot.png within the current directory.

Sometimes you want a screenshot to show a menu being opened or something that generally disappears when the window in which you are interested loses focus. For such situations, you can specify a delay before the capture takes place by using the -d option:

$ scrot -d 5

The delay is specified in seconds.

If you capture the entire screen, you can crop it later with image editing software, such as GIMP (Recipe 4.7). However, it is more convenient to just capture a specific area of the screen in the first place, which you can do by using the -s option.

To use this option, type the following command and then, with the mouse, drag out the area of screen that you want to capture:

$ scrot -s

The filename will include the dimensions in pixels of the image captured.

See Also

The scrot command has a number of other options to control things like using multiple screens and changing the format of the saved file. You can find out more about scrot from its man page by entering the following command:

$ man scrot

Man Pages

Man pages are available for almost all Raspbian commands, and you can see them by entering the command name followed by the command itself. However, a command’s man page is not always very accessible, being a thorough reference for the command rather than a simple guide for how to use the command. So it’s often better just to do an internet search for the command.

3.17 Installing Software with apt-get

Problem

You want to install software using the command line.

Solution

The most frequently used tool for installing software from a Terminal session is apt-get (the Advanced Packaging Tool).

The basic format of the command, which you must run as a superuser, is as follows:

$ sudo apt-get install <name of software>

For example, to install the AbiWord word processing software, you would enter this command:

$ sudo apt-get install abiword

Discussion

The apt-get package manager uses a list of available software. This list is included with the Raspberry Pi operating system distribution that you use but is likely to be out of date. So it is a good idea to always run the following command to update the list before installing new software using apt-get:

$ sudo apt-get update

The list and the software packages for installation are all on the internet, so none of this will work unless your Raspberry Pi has an internet connection.

Tip

If you find that when you update you get an error like E: Problem with MergeList /var/lib/dpkg/status, try running these commands, which will remove the offending file and replace it with a new, empty one:

$ sudo rm /var/lib/dpkg/status
$ sudo touch /var/lib/dpkg/status

The installation process can often take a while because the files must be downloaded and installed. Some installations will also add shortcuts to your desktop, or the program groups on your Start menu.

You can search for software to install by using the command apt-get search followed by a search string such as abiword. This then displays a list of matching packages that you could install.

See Also

See Recipe 3.18 for removing programs that you no longer need so that you can free up space.

See also Recipe 3.21 for downloading source code from GitHub.

3.18 Removing Software Installed with apt-get

Problem

Having installed a whole load of programs using apt-get, you now find that you want to remove some of them.

Solution

The apt-get utility has an option (remove) that will remove a package, but it will remove only those packages that have been installed with apt-get install.

For example, if you wanted to remove AbiWord, you would use the following command:

$ sudo apt-get remove abiword

Discussion

Removing a package like this does not always delete everything, because packages often have prerequisite packages that are installed as well. To remove these, you can use the autoremove option, as shown here:

$ sudo apt-get autoremove abiword
$ sudo apt-get clean

The apt-get clean option will do some further tidying up of unused package installation files.

See Also

See Recipe 3.17 for installing packages using apt-get.

3.19 Installing Python Packages with Pip

Problem

You want to use the pip (Pip Installs Packages) package manager to install Python libraries.

Solution

If you have the latest version of Raspbian, pip will already be installed, and you can run it from the command line, as shown in the example here, which is taken from Recipe 8.1, in which it is used to install the Python library svgwrite:

$ sudo pip install svgwrite

If pip is not installed on your system, you can install it by using this command:

$ sudo apt-get install python-pip

Discussion

Although many Python libraries can be installed using apt-get (see Recipe 3.17), some cannot, and you must use pip instead.

See Also

To install software using apt-get, see Recipe 3.17.

3.20 Fetching Files from the Command Line

Problem

You want to download a file from the internet without using a web browser.

Solution

You can use the wget command to fetch a file from the internet.

For example, the following command fetches the file Pifm.tar.gz from https://www.icrobotics.co.uk:

$ wget http://www.icrobotics.co.uk/wiki/images/c/c3/Pifm.tar.gz
--2013-06-07 07:35:01--  http://www.icrobotics.co.uk/wiki/images/c/c3/Pifm.tar.gz
Resolving www.icrobotics.co.uk (www.icrobotics.co.uk)... 155.198.3.147
Connecting to www.icrobotics.co.uk (www.icrobotics.co.uk)|155.198.3.147|
:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 5521400 (5.3M) [application/x-gzip]
Saving to: `Pifm.tar.gz'

100%[==================================================>] 5,521,400    601K/s

2018-06-07 07:35:11 (601 KB/s) - `Pifm.tar.gz' saved [5521400/5521400]

If your URL contains any special characters, it is a good idea to enclose them in double quotes. This example URL is from Recipe 4.6.

Discussion

You will find instructions for installing software that rely on using wget to fetch files. It is often more convenient to do this from the command line rather than use a browser, find the file, download it, and then copy it to the place you need it.

The wget command takes the URL to download as its argument and downloads it into the current directory. It’s typically used to download an archive file of some type but will also download any web page.

See Also

For more information on installing with apt-get, see Recipe 3.17.

3.21 Fetching Source Code with Git

Problem

Sometimes Python libraries and another software are hosted on the GitHub website or other online Git repository. You need to be able to fetch them onto your Raspberry Pi.

Solution

To use code in Git repositories, you need to use the git clone command to make your own copy of the files.

For example, the following command will download all of the source code examples from this book into a new folder:

$ git clone https://github.com/simonmonk/raspberrypi_cookbook_ed3.git

Along with the URL for the code to clone, there is a web page that you can visit with a browser. If you go to the GitHub web page, you will find a web page that looks like Figure 3-12.

Clicking the “Clone or download” button allows you to copy the repository’s URL and then paste it after the command git in your Terminal session.

Discussion

There is a difference between Git and GitHub. Git is the software and GitHub is one of many websites hosting code that you push to GitHub using Git. In fact you can actually host your own Git repository on a Raspberry Pi if you want to. However, there are benefits to using a Git-based website such as GitHub or GitLab:

Your code is stored in the cloud, so if your disk (or SD card) breaks, you won’t lose the code.

The code is publicly visible, so other people can look at it and use it, and if they find things wrong with it they might even offer up fixes for you.

You can include documentation about your project for all to see in the README file.

Figure 3-12. The GitHub repository page for this book

If you are working on a Raspberry Pi project that you think others might be interested in, I would recommend using GitHub or GitLab to host your code. There is a little bit to learn, but it’s worth the effort.

Another advantage to using Git (whether locally or with a service like GitHub) is that every time you do a chunk of work on a project, you will push that work up to the master copy of your code. This does not replace the code that was already there but is instead stored as a new edition. You can at any time recover earlier versions of the code, should you make a mistake.

I host all of the code from my books and other projects on GitHub. These are the steps I take when I make a new repository:

Go to your home page on GitHub (you’ll need to create an account) and click the + button and select the New Repository option.

Give the repository a name and short description.

Check the option “Initialize this repository with a README.”

Select a license—I select MIT for no better reason than my great respect for that august center of learning, reasoning that if it has a license for sharing my work, it’s probably a good one.

Click “Create repository.”

Now, back on your computer (Raspberry Pi or other), open a command prompt (Recipe 3.3).

Run the command git followed by the URL of the repository. This will create a folder for the project. Any files that you write in this folder will eventually be saved to GitHub.

$ git add .
$ git commit -m "message about what you changed or added"
$ git push

The first of these commands adds all of the changed or new files to the list of files to be committed. The commit command gives you an option to explain what’s new in the changes being committed. Finally, the push command pushes the changes up to GitHub. At this point, you are prompted for your GitHub username and password.

You will find GitHub to be a rich source of Python and other code for use with the Raspberry Pi. This is especially true when it comes to software interfaces to different types of hardware such as displays and sensors.

See Also

Learn more about Git and the Git hosting services GitHub and GitLab.

For information on downloading this book’s program code and other files relating to this book see Recipe 3.22.

3.22 Fetching This Book’s Accompanying Code

Problem

You want to download all the source code and other files relating to this book.

Solution

You can either clone the files from GitHub as described in Recipe 3.21 or, as we will describe here, get the downloads as a single ZIP archive file from GitHub.

A good starting point for getting the book’s downloads is to go to the book’s web page using the browser on your Raspberry Pi. Here, in addition to a link to the book’s code hosted on GitHub, you will find errata and other information about the book.

So whether you begin at the website or directly at the GitHub page, when you click the “Clone or download” button, you will see an option to Download ZIP. You can see this in Figure 3-12 in Recipe 3.21.

Click the Download ZIP option. Chromium saves this to your Downloads folder. Click the down arrow next to the downloaded ZIP file (Figure 3-13) and then select the option “Show in folder.”

Figure 3-13. Downloading a ZIP archive for this book’s files

This opens a File Manager window in the Downloads folder. Find the ZIP file that has just been downloaded (Figure 3-14).

Figure 3-14. Finding the ZIP archive file in Downloads

Double-click the ZIP file to open the Xarchiver tool on the ZIP file (Figure 3-15) and then click the “Extract files” icon.

Figure 3-15. Using the Xarchiver tool to extract the files for this book

In the dialog that appears (Figure 3-16), change the path to which the extracted folder is to be saved to /home/pi and then click Extract.

Figure 3-16. Changing the path for the extracted files

After the files have been extracted, there will be a new folder in your home directory containing all the downloads for the book.

Discussion

If you now use the File Manager to see what’s in your home directory, you will find a folder called raspberry_pi_cookbook_ed3-master (Figure 3-17).

Figure 3-17. The extracted files

The folder PiBakery contains PiBakery configurations from Recipe 1.8. The python folder contains all the Python programs used in the book.

See Also

For more information on using Git and GitHub, see Recipe 3.21.

3.23 Running a Program or Script Automatically on Startup

Problem

You want a program or script to start automatically as your Raspberry Pi boots.

Solution

Modify your rc.local file to run the program you want.

Edit the file /etc/rc.local by using the following command:

$ sudo nano /etc/rc.local

Add the following line after the first block of comment lines that begin with #:

$ /usr/bin/python /home/pi/my_program.py &

It is important to include the & on the end of the command line so that it is run in the background; otherwise your Raspberry Pi will not boot.

Discussion

This way of autorunning a program needs a very careful edit of rc.local, or you can stop your Raspberry Pi from booting.

See Also

A safer way of autorunning a program is detailed in Recipe 3.24.

3.24 Running a Program or Script Automatically as a Service

Problem

You want to arrange for a script or program to start automatically every time the Raspberry Pi reboots.

Solution

Debian Linux, on which most Raspberry Pi distributions are based, uses a dependency-based mechanism for automating the running of commands at startup. This is a little tricky to use and involves creating a configuration file for the script or program that you want to run, which will reside in a folder called init.d.

Discussion

The following example shows you how to run a Python script in your home directory. The script could do anything, but in this case, the script runs a simple Python web server, which is described further in Recipe 7.17.

Here are the steps involved:

Create an init script.

Make the init script executable.

Tell the system about the new init script.

First, create the init script. You need to create this in the folder /etc/init.d/. The script can be called anything, but in this example, we call it my_server.

Create the new file by using nano with the following command:

$ sudo nano /etc/init.d/my_server

Paste the following code into the editor window and save the file. This is a lot to type, so if you are reading a paper copy of this book, you can copy and paste the code from this web page; just scroll down until you find this chapter and recipe:

### BEGIN INIT INFO
# Provides: my_server
# Required-Start: $remote_fs $syslog $network
# Required-Stop: $remote_fs $syslog $network
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Simple Web Server
# Description: Simple Web Server
### END INIT INFO

#! /bin/sh
# /etc/init.d/my_server

export HOME
case "$1" in
  start)
    echo "Starting My Server"
    sudo /usr/bin/python /home/pi/myserver.py  2>&1 &
  ;;
stop)
  echo "Stopping My Server"
  PID=`ps auxwww | grep myserver.py | head -1 | awk '{print $2}'`
  kill -9 $PID
  ;;
*)
  echo "Usage: /etc/init.d/my_server {start|stop}"
  exit 1
;;
esac
exit 0

This is quite a lot of work to automate the running of a script, but most of it is boiler-plate code that is the same for every service. To run a different script, just work your way through the script, changing the descriptions and the name of the Python file that you want to run.

The next step is to make this file executable for the owner, which you do by using this command:

$ sudo chmod +x /etc/init.d/my_server

Now that the program is set up as a service, you can use the following command to test that everything is OK before you set it to autostart as part of the boot sequence:

$ /etc/init.d/my_server start
Starting My Server
Bottle v0.11.4 server starting up (using WSGIRefServer())...
Listening on http://192.168.1.16:80/
Hit Ctrl-C to quit.

Finally, if that runs OK, use the following command to make the system aware of the new service that you have defined:

$ sudo update-rc.d my_server defaults

See Also

For a simpler approach to making a program run automatically, see Recipe 3.23.

For more information on changing file and folder permissions, see Recipe 3.13.

3.25 Running a Program or Script Automatically at Regular Intervals

Problem

You want to run a script once each day or at regular intervals.

Solution

Use the Linux crontab command.

To do this, the Raspberry Pi needs to know the time and date and therefore needs a network connection or a real-time clock; see Recipe 12.13.

Discussion

The command crontab allows you to schedule events to take place at regular intervals. This can be daily or hourly, and you can even define complicated patterns so different things happen on different days of the week. This is useful for backup tasks that you might want to run in the middle of the night.

You can edit the scheduled events by using the following command:

$ crontab -e

If the script or program that you want to run needs to be run by a superuser, prefix all the crontab commands with sudo (Recipe 3.12).

The comment line (starting with a #) indicates the format of a crontab line. The digits are, in order, minute, hour, day of month, month, and day of week and are followed by the command that you want to run.

If there is a * in the relevant position, that means every; if there is a number there instead, the script runs only at that minute/hour/day of the month.

So, to run the script every day at 1 a.m., you would add the line shown in Figure 3-18.

Figure 3-18. Editing crontab

By specifying a range of day numbers say 1–5 (Monday to Friday) in the day of week column, the script will run only at 1am on those days, as demonstrated here:

0 1 * * 1-5 /home/pi/myscript.sh

If your script needs to be run from a particular directory, you can use a semicolon (;) to separate multiple commands, as shown here:

0 1 * * * cd /home/pi; python mypythoncode.py

See Also

You can see the full man page documentation for crontab by entering this command:

$ man crontab

3.26 Finding Things

Problem

You want to find a file that you know is on the system somewhere.

Solution

Use the Linux find command.

Discussion

Starting with a directory specified in the command, the find command will search for a file that you specify and, if it finds the file, display its location.

For example:

$ find /home/pi -name gemgem.py
/home/pi/python_games/gemgem.py

You can start the search at various points on the tree, even at the root of the entire filesystem (/). A search of the entire filesystem will take a lot longer and will also produce error messages. You can redirect these error messages by adding 2>/dev/null to the end of the line.

To search for the file throughout the entire filesystem, use the following command:

$ find / -name gemgem.py 2>/dev/null
/home/pi/python_games/gemgem.py

Note that 2>/dev/null redirects output that would make it difficult to see the file when it was eventually found. You can find out more about redirection in Recipe 3.31.

You can also use wildcards with find as follows:

$ find /home/pi -name match*
/home/pi/python_games/match4.wav
/home/pi/python_games/match2.wav
/home/pi/python_games/match1.wav
/home/pi/python_games/match3.wav
/home/pi/python_games/match0.wav
/home/pi/python_games/match5.wav

See Also

The find command has a number of other advanced features for searching. To see the full man page documentation for find, use this command:

$ man find

3.27 Using the Command-Line History

Problem

You want to be able to repeat commands on the command line without having to type them again.

Solution

Use the up arrow and down arrow keys to select previous commands from the command history, and use the history command with grep to find older commands.

Discussion

You can access the previous command you ran by pressing the up arrow key. Pressing it again will take you to the command before that, and so on. If you overshoot the command you wanted, the down arrow key will take you back in the other direction.

If you want to cancel without running the selected command, use Ctrl-C.

Over time, your command history will grow too large for you to use the arrow keys to find a command that you used ages ago. To find a command from way back, you can use the history command:

$ history
    1  sudo nano /etc/init.d/my_server
    2  sudo chmod +x /etc/init.d/my_server
    3  /etc/init.d/my_server start
    4  cp /media/4954-5EF7/sales_log/server.py myserver.py
    5  /etc/init.d/my_server start
    6  sudo apt-get update
    7  sudo apt-get install bottle
    8  sudo apt-get install python-bottle

This lists all of your command history and is likely to have far too many entries for you to find the command you want. To remedy this, you can pipe (see Recipe 3.33) the history command into the grep command, which will display only results matching a search string. So, for example, to find all the apt-get (Recipe 3.17) commands that you’ve issued, you can use the line:

$ history | grep apt-get
    6  sudo apt-get update
    7  sudo apt-get install bottle
    8  sudo apt-get install python-bottle
   55  history | grep apt-get

Each history item has a number next to it, so if you find the line you were looking for, you can run it using ! followed by the history number, as shown here:

$ !6
sudo apt-get update
Hit http://mirrordirector.raspbian.org wheezy InRelease
Hit http://mirrordirector.raspbian.org wheezy/main armhf Packages
Hit http://mirrordirector.raspbian.org wheezy/contrib armhf Packages
.....

See Also

To find files rather than commands, see Recipe 3.26.

3.28 Monitoring Processor Activity

Problem

The Raspberry Pi can run a bit slow sometimes, so you want to see what’s hogging the processor.

Solution

Use the Task Manager utility, which you’ll find on the Main menu, in the Accessories program group (Figure 3-19).

Figure 3-19. The Task Manager

The Task Manager allows you to see at a glance how much CPU and memory are being used. You can also right-click a process and select the option to kill it from the pop-up menu that appears.

The bar graphs toward the top of the window display the total CPU usage and memory usage. The processes are listed below that, and you can see the CPU share each is taking.

Discussion

If you prefer to do this type of thing from the command line, use the Linux top command to display very similar data about processor and memory usage and which processes are using the most resources (Figure 3-20). You can then use the kill command to kill a process. You will need to do this as a superuser.

In this case, you can see that the top process is a Python program that uses 97% of CPU. The first column shows its process ID (2447). To kill this process, enter this command:

$ kill 2447

It is quite possible to kill some vital operating system process this way, but if you do, powering off your Pi and turning it back on again will restore things to normal.

Figure 3-20. Using the top command to see resource usage

Sometimes you might have a process running that is not immediately visible when you use top. If this is the case, you can search all the processes running by using the ps command and piping (Recipe 3.33) the results to the grep command (Recipe 3.27), which will search the results and highlight items of interest.

For example, to find the process ID for our CPU-hogging Python process, we could run the following command:

$ ps -ef | grep "python"
pi        2447  2397 99 07:01 pts/0    00:00:02 python speed.py
pi        2456  2397  0 07:01 pts/0    00:00:00 grep --color=auto python

In this case, the process ID for the Python program speed.py is 2447. The second entry in the list is the process for the ps command itself.

The killall Command

A variation on the kill command is the killall command. Use this with caution because it kills all processes that match its argument. So, for example, the following command will kill all Python programs running on the Raspberry Pi:

$ sudo killall python

See Also

See also the man pages for top, ps, grep, kill, and killall. You can view these by using the man command followed by the name of the command for which you want information, as shown here:

$ man top

3.29 Working with File Archives

Problem

You have downloaded a compressed file and want to uncompress it.

Solution

Depending on the file type, you will need to use the tar command or the gunzip command.

Discussion

If the file that you want to uncompress just has the extension .gz, you can unzip it using the command:

$ gunzip myfile.gz

You also often find files (called tarballs) that contain a directory that has been archived with the Linux tar utility and then compressed with gzip into a file with a name like myfile.tar.gz.

You can extract the original files and folders out of a tarball by using the tar command:

$ tar -xzf myfile.tar.gz

If the file is a ZIP archive, you can use the File Manager and Xarchiver tools, as shown in Recipe 3.22.

See Also

You can find out more about tar from its man page, which you can access by using the command man tar.

3.30 Listing Connected USB Devices

Problem

You’ve plugged in a USB device and want to make sure Linux recognizes it.

Solution

Use the lsusb command. This lists all of the devices attached to the USB ports on your Raspberry Pi:

$ lsusb
Bus 001 Device 002: ID 0424:9512 Standard Microsystems Corp.
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 001 Device 003: ID 0424:ec00 Standard Microsystems Corp.
Bus 001 Device 004: ID 15d9:0a41 Trust International B.V. MI-2540D [Optical mouse]

Discussion

This command informs you as to whether a device is connected, but it will not guarantee that the device is working correctly. There might be drivers to install or configuration changes to make for the hardware.

See Also

For an example of using lsusb when attaching an external webcam, see Recipe 4.3.

3.31 Redirecting Output from the Command Line to a File

Problem

You want to quickly create a file with some text or record a directory listing into a file.

Solution

Use the > command to redirect output that would otherwise appear in your Terminal after you run the command.

For example, to copy a directory listing into a file called myfiles.txt, do the following:

$ ls > myfiles.txt
$ more myfiles.txt
Desktop
indiecity
master.zip
mcpi

Discussion

You can use the > command on any Linux command that produces output, even if you are running, say, a Python program.

You can also use the opposite (<) command to redirect user input, although this is not nearly as useful as >.

See Also

To use cat command to join together a number of files, see Recipe 3.32.

3.32 Concatenating Files

Problem

You have a number of text files, and you want to join them into one big file.

Solution

Use the cat command to concatenate a number of files into one output file.

For example:

$ cat file1.txt file2.txt file3.txt > full_file.txt

Discussion

Joining files is the real purpose of the cat command. You can supply as many filenames as you like, and they will all be written to the file that you specify. If you do not redirect the output, it will just appear in your Terminal window. If they are big files, this process might take some time!

See Also

See also Recipe 3.8, in which cat is used to display the contents of a file.

3.33 Using Pipes

Problem

You want to use the output of one Linux command as the input to another command.

Solution

Use the pipe command, which is the bar symbol (|) on your keyboard, to pipe the output of one command to another.

For example:

$ ls -l *.py | grep Jun
-rw-r--r-- 1 pi pi 226 Jun  7 06:49 speed.py

This example will find all the files with the extension py that also have Jun in their directory listing, indicating that they were last modified in June.

Discussion

At first sight, this looks rather like output redirection using > (Recipe 3.31). The difference is that > will not work if the target is another program. It will work only for redirecting to a file.

You can chain together as many programs as you like, as shown here, although this isn’t something you will do often:

$ command1 | command2 | command3

See Also

See Recipe 3.28 for an example of using grep to find a process, and Recipe 3.27 to search your command history using pipe and grep.

3.34 Hiding Output to the Terminal

Problem

You want to run a command, but you don’t want the output filling up your screen.

Solution

Redirect the output to /dev/null using >.

For example:

$ ls > /dev/null

The dev directory contains operating system devices, including things like serial ports. Within this directory, a special device (the null device) is defined that simply discards everything sent to it.

Discussion

This example illustrates the syntax but is otherwise pretty useless. A more common use is when you’re running a program and the developer has left a lot of trace messages in its code, which you don’t really want to see. The following example hides superfluous output from the find command (see Recipe 3.36):

$ find / -name gemgem.py 2>/dev/null
/home/pi/python_games/gemgem.py

See Also

For more information about redirecting standard output, see Recipe 3.31.

3.35 Running Programs in the Background

Problem

You want to run a program while also working on some other task.

Solution

Run the program or command in the background using the & command.

For example:

$ python speed.py &
[1] 2528
$ ls

Rather than wait until the program has finished running, the command line displays the process ID (the second number) and immediately allows you to continue with whatever other commands you want to run. You can then use this process ID to kill the background process (Recipe 3.28).

To bring the background process back to the foreground, use the fg command:

$ fg
python speed.py

This reports the command or program that is running and then waits for it to finish.

Discussion

Output from the background process will still appear in the Terminal.

An alternative to putting processes in the background is to just open more than one Terminal window.

See Also

For information on managing processes, see Recipe 3.28.

3.36 Creating Command Aliases

Problem

You want to create aliases (shortcuts) to commands that you use frequently.

Solution

Edit the file ~/.bashrc using nano (Recipe 3.7), and then move to the end of the file and add as many lines as you want, like this:

alias L='ls -a'

This creates an alias called L that, when entered, will be interpreted as the command ls -a.

Save and exit the file using Ctrl-X and Y, and then type the following command to update the Terminal with the new alias:

$ source .bashrc

Discussion

Many Linux users set up an alias for rm like the following so that it confirms deletions:

$ alias rm='rm -i'

This is not a bad idea, as long as you do not forget when you use someone else’s system who doesn’t have this alias set up!

See Also

For more information about rm, see Recipe 3.11.

3.37 Setting the Date and Time

Problem

You want to manually set the date and time on your Raspberry Pi because it does not have an internet connection.

Solution

Use the Linux date command.

The date and time format is MMDDhhmmYYYY, where MM is the month number; DD is the day of the month; hh and mm are the hours and minutes, respectively; and YYYY is the year.

For example:

$ sudo date 010203042019
Wed  2 Jan 03:04:00 GMT 2019

Discussion

If the Raspberry Pi is connected to the internet, as it boots up it will automatically set its own time using an internet time server.

You can also use date to display Coordinated Universal Time (UTC) time by entering date on its own:

$ date
Fri 19 Jul 10:59:08 BST 2019

See Also

If you want your Raspberry Pi to maintain the correct time even when there is no network, you can use a real-time clock (RTC) module (Recipe 12.13).

3.38 Finding Out How Much Room You Have on the SD Card

Problem

You want to know how much free space there is on the SD card.

Solution

Use the Linux df (disk filesystem) command:

$ df -h
Filesystem      Size  Used Avail Use% Mounted on
rootfs          3.6G  1.7G  1.9G  48% /
/dev/root       3.6G  1.7G  1.9G  48% /
devtmpfs        180M     0  180M   0% /dev
tmpfs            38M  236K   38M   1% /run
tmpfs           5.0M     0  5.0M   0% /run/lock
tmpfs            75M     0   75M   0% /run/shm
/dev/mmcblk0p1   56M   19M   38M  34% /boot

The -h option shows the sizes using the kB, MB, and GB symbols rather than the number of bytes.

Discussion

Looking at the first line of the results, you can see that there is 3.6 GB of storage on the SD card, of which 1.7 GB is used.

When you run out of disk space, you are likely to get unexpected bad behavior, such as error messages saying that a file could not be written.

See Also

You can find the man page for df by using the command man df.

3.39 Find Out What Operating System Version You Are Running

Problem

You want to know exactly what version of Raspbian you are running.

Solution

Enter the following command into a Terminal or Secure Shell (SSH) session:

$ cat /etc/os-release
PRETTY_NAME="Raspbian GNU/Linux 9 (stretch)"
NAME="Raspbian GNU/Linux"
VERSION_ID="9"
VERSION="9 (stretch)"
ID=raspbian
ID_LIKE=debian
HOME_URL="http://www.raspbian.org/"
SUPPORT_URL="http://www.raspbian.org/RaspbianForums"
BUG_REPORT_URL="http://www.raspbian.org/RaspbianBugs"
pi@raspberrypi:~ $

Discussion

As you can see from the result in the previous example, the first line tells us all we need to know. In this case, my Raspberry Pi is running Raspbian version 9, which also goes under the nickname stretch.

It can be useful to know what version of Raspbian you are running if you are having problems with a certain piece of software. Often the first question that you will be asked by support is What version of Raspbian are you running?

You might need to know what version of the Linux kernel you have on your Raspberry Pi. You can find this using the following command:

$ uname -a
Linux raspberrypi 4.14.71-v7+ #1145 SMP Fri Sep 21 15:38:35 BST 2018 armv7l GNU/Linux

Here you can see that Raspbian stretch uses v4.14 of the kernel.

See Also

To see how much room you have left on your SD card or other boot disk, see Recipe 3.38.

3.40 Updating Raspbian

Problem

You want to update your Raspberry Pi to the latest version of Raspbian.

Solution

Open a command line by using the Terminal (Recipe 3.3) and enter the following command to update your system to the latest version:

$ sudo apt-get update
$ sudo apt-get dist-upgrade

This will take some time especially if there is a lot to upgrade. Most important, if you have any precious files on your system, I recommend copying them onto a USB flash drive (Recipe 3.2) before upgrading.

Discussion

The first of these commands does not actually update Raspbian; it just updates the apt-get package manager to make it aware of the latest versions of the packages that comprise your operating system and related software.

The command dist-upgrade upgrades the operating system itself. During the process, you will be warned how much disk space will be required, so you should use Recipe 3.38 to check that you have enough room before pressing Y to go ahead with the upgrade.

Keeping your distribution up to date is important for a number of reasons. First, one of the main reasons that the operating system is changed is to fix bugs. So problems during the installation of software often vanish after an update. Second, if you expose your Raspberry Pi to the internet, new versions of Raspbian often patch security vulnerabilities.

See Also

To start again with a completely fresh installation of Raspbian, see Recipe 1.6.

Chapter 4. Software

4.0 Introduction

This chapter contains a number of recipes for using ready-made software on the Raspberry Pi.

Some of the recipes in this chapter are concerned with converting the Raspberry Pi into a single-use appliance, while others use specific pieces of software on a Raspberry Pi.

4.1 Making a Media Center

Problem

You want to convert your Raspberry Pi into a super-duper media center.

Solution

To use your Raspberry Pi as a media center, you should go for the superior performance of the Raspberry Pi 4 B, as video playing is very processor intensive.

You can set up your Raspberry Pi as a media center during the NOOBS (New Out Of the Box Software) installation process (Recipe 1.6). Instead of selecting Raspbian as the distribution to install, select LibreELEC_RPi4 (see Figure 1-9).

LibreELEC is a distribution that optimizes your Raspberry Pi as a media center. It incudes the Kodi media center software, which is based on the XBMC open source project that was originally developed to convert Xbox game consoles into media centers. The code has since been ported to many platforms, including the Raspberry Pi (Figure 4-1).

Figure 4-1. Raspberry Pi as a media center

Raspberry Pi is perfectly capable of playing full HD video as well as streamed music, MP3 files, and internet radio.

Discussion

Kodi is a powerful piece of software with many features. Perhaps the simplest way to check whether it is working is to put some music and/or video files onto a USB flash drive or external USB hard disk and connect it to the Raspberry Pi. You should be able to play them from Kodi.

Since the Raspberry Pi is likely to be sitting near your TV, you might find that your TV has a USB port that can provide enough current to run the Raspberry Pi. If this is the case, you won’t need a separate power supply.

A wireless keyboard and mouse are a good idea because, if you buy them as a pair, they will use a single USB port for the dongle, which avoids the need for wires trailing all over the place. You can also buy minikeyboards with built-in trackpads that are useful in this situation.

A wired network connection is generally higher performance and better than a WiFi connection, but it is not always convenient to have the Pi near an Ethernet socket. If this is the case, you can set up XBMC to use WiFi.

Setting up Kodi is very intuitive, and you can find full instructions on using the software at http://kodi.wiki.

See Also

You can add an infrared (IR) remote to Raspberry Pi to control Kodi.

4.2 Using Office Software

Problem

You need to open word processor and spreadsheet documents on a Raspberry Pi.

Solution

Raspberry Pi is, after all, a Linux computer, and Raspbian includes a collection of LibreOffice programs direct from the Main menu (Figure 4-2).

Figure 4-2. LibreOffice software on Raspbian

Discussion

There is a choice of two word processors, AbiWord and LibreOffice Writer. LibreOffice Writer is part of the popular LibreOffice suite of software that offers a mostly very compatible set of alternatives to the Microsoft Office suite of programs. LibreOffice Writer will open and save Microsoft Word documents and is available for Windows, Mac, and other Linux computers.

A Raspberry Pi 4, 3, or 2 will run office applications much better than an older Raspberry Pi.

See Also

Visit https://www.libreoffice.org for more information on the LibreOffice suite of software.

6.8

If you just want to edit an unformatted text file, you can use the nano editor (Recipe 3.7).

4.3 Making a Webcam Server

Problem

You want to set up a Raspberry Pi as a webcam server.

Solution

You can use either a USB webcam or the Raspberry Pi Camera Module as a webcam that you can access from elsewhere on your network using a browser.

Download the motion software. This will allow you to set up a Raspberry Pi with a USB webcam connected to it so you can connect to a web page and view the webcam.

To install the software, enter the following command in a Terminal window:

$ sudo apt-get update
$ sudo apt-get install motion

You’ll need to make a few configuration changes. First, use the following command to edit the file /etc/motion/motion.conf:

$ sudo nano /etc/motion/motion.conf

This is quite a big configuration file. Near the top of the file, you will find this line:

daemon off

Change the line as follows:

daemon on

The other change is much further down the file. You need to change this line:

webcam_localhost = on

so that it reads like this:

webcam_localhost = off

There is one other file that you need to change. Enter the command:

$ sudo nano /etc/default/motion

Change:

start_motion_daemon=no

to:

start_motion_daemon=yes

Then change:

stream_localhost on

to:

stream_localhost off

To get the web service running, issue the command:

$ sudo service motion start

If you are using the Raspberry Pi Camera Module, there is an extra step. You need to edit the file /etc/modules using the following command:

$ sudo nano /etc/modules

Add the following line to the end of this file, then save and exit nano as usual:

bcm2835-v4l2

Reboot your Raspberry Pi and you should now be able to open your web browser and view the webcam. To do this, you will need to know the IP address of your Raspberry Pi (Recipe 2.2). You can also check that the webcam is working from the browser on your Raspberry Pi by going to http://localhost:8081.

From another computer on the same network, open a browser and go to the URL http://192.168.0.210:8081/. You will need to change the URL to match the IP address of your Raspberry Pi, but keep the :8081 port number on the end of the URL.

If all goes well, you should see something like Figure 4-3.

Figure 4-3. A Raspberry Pi webcam

Discussion

The motion software is really powerful. There are many other settings you can tweak to change how your webcam works.

By default, the webcam will be viewable only from within your network. If you want your webcam to be visible to the entire internet, you need to set up port forwarding on your home hub. This will require you to log in to the admin console for the hub, look for the port forwarding option, and enable it for port 8081 for the IP address of the Raspberry Pi.

You will then be able to view the webcam by using the external IP address allocated by your ISP. This is usually shown on the front page of your admin console. But be aware: unless you pay your ISP for a static IP address, this IP address is likely to change every time you restart your home hub modem.

Services such as No-IP can also be used to provide dynamic domain name service (DNS), so that you can register a domain name that automatically follows changes to your IP address.

See Also

There is thorough documentation on the Motion website.

You can find a list of webcams compatible with the Raspberry Pi at https://oreil.ly/_z4GH.

To fix the IP address of your Raspberry Pi webcam so you can always find it, see Recipe 2.3.

To use a webcam for computer vision projects, see Chapter 8.

See Recipe 3.17 for information on using apt-get.

4.4 Running a Vintage Game Console Emulator

Problem

You want to turn your Raspberry Pi into a vintage game console.

Solution

If you fancy rediscovering your misspent youth and playing Asteroids on an emulator for the Atari 2600 (Figure 4-4), the RetroPie project will appeal to you.

Figure 4-4. Asteroids on the Stella Atari 2600 emulator

Many wonderful projects have been built that create custom consoles and game tables complete with retro games controllers.

Although you can install RetroPie on top of Raspbian, the easiest way to make your own console is to download a ready-made disk image and write it onto an SD card using Recipe 1.7.

Warning

It is worth noting that even though these games are ancient, they are still owned by someone. The ROM image files that you need to play the games on an emulator, although easy to find on the internet, are not necessarily yours to take. So please stick to the law.

Discussion

The emulator uses a surprisingly large amount of the Raspberry Pi’s meager resources, so you might find that you need to use a Raspberry Pi 4, 3, or 2.

In an internet search, you can find many people who have taken this basic setup and added a retro USB controller, like the widely available and quite low-cost controllers, and built the Pi and a monitor into a big arcade-style housing.

You can also buy a kit called the Picade from Pimoroni to make a lovely arcade machine (Figure 4-5).

Figure 4-5. The Pimoroni Picade Kit

See Also

Full RetroPie documentation is available on the RetroPie site.

4.5 Running Minecraft: Pi Edition

Problem

You want to run the popular game Minecraft on your Raspberry Pi.

Solution

Mojang, the original developers of Minecraft, have ported the game to the Raspberry Pi and Minecraft Pi, is preinstalled on the latest Raspbian distribution (Figure 4-6).

Figure 4-6. Minecraft on Raspberry Pi

Discussion

To get Minecraft to fit on the Raspberry Pi, the developers made some shortcuts in the graphics code. This means that you can only play the game directly on the Raspberry Pi with the keyboard, mouse, and monitor connected directly to it. It will not work over a remote virtual network computing (VNC) connection.

The Pi edition of Minecraft is based on the mobile version of Minecraft and lacks some features, most notably Redstone.

See Also

Find out more about the Raspberry Pi port of Minecraft.

Minecraft Pi also includes a Python programming interface, and in Recipe 7.20, we’ll go over how to send commands to Python over a Secure Shell (SSH) connection to do automated building.

4.6 Raspberry Pi Radio Transmitter

Note

Be sure to check out the accompanying video for this recipe.

Problem

You want to convert your Raspberry Pi into a low-powered FM transmitter that will send a radio signal to a normal FM radio receiver (Figure 4-7).

Solution

Back in the early days of the Raspberry Pi, some clever folks at Imperial College, London, created some C code that allows you to do just this. The download even plays the Star Wars theme as a sample. This project will still work if you have an original Raspberry Pi 1. The code has not been updated since for newer versions of Raspberry Pi.

Fortunately, however, the project lives on in an altogether more advanced project called rpitx.

All you need is a short length of wire attached to general-purpose input/output (GPIO) pin 4. A 10 cm female-to-male header lead will work just fine for this. In fact, it should work with the radio right next to your Pi without any kind of antenna—such is the strength of the transmission.

Figure 4-7. Raspberry Pi as an FM transmitter

The first step is to install the rpitx software using the following commands. Note that this installation will change some things about how your Raspberry Pi is configured, including the frequency at which the GPU (graphics process) works. So if this is your main Raspberry Pi, make sure you first back up anything precious. Here’s the code you need:

$ sudo apt-get update
$ git clone https://github.com/F5OEO/rpitx
$ cd rpitx
$ ./install.sh

You will now need to do something else for a good 15 minutes or so while the software installs. You might see what look like error messages and warnings, but these are normal. At the end of the installation, the installer script will ask:

In order to run properly, rpitx need to modify /boot/config.txt. Are you
      sure (y/n)

Press Y, and the script will then confirm the changes it has made with the following message:

Set GPU to 250Mhz in order to be stable

If you need to reverse this change, edit /boot/config.txt by removing the last line that says gpu_freq=250, then reboot.

Next, find yourself an FM radio receiver and tune it to 103.0 MHz. If this frequency is already occupied by some other transmission, pick another frequency and make note of it.

Now run the following command (changing the frequency parameter from 103.0 if you had to change frequency):

sudo ./pifmrds -freq "103.0" -audio src/pifmrds/stereo_44100.wav

If all is well, you should hear the voice of the developer talking about left and right channels.

Discussion

You need to know that this project may not be legal in your country. The power output is higher than that of FM transmitters used with MP3 players.

Were you to put a Raspberry Pi in your vehicle, this would be a great way to output sound through the vehicle’s audio system.

See Also

To learn more about the rpitx project, see https://github.com/F5OEO/rpitx.

4.7 Editing Bitmap Images

Problem

You want to manipulate a photograph or other image.

Solution

Download and run the GNU Image Manipulation Program (GIMP; see Figure 4-8).

Figure 4-8. GIMP on the Raspberry Pi

To install GIMP, open a Terminal session and type the following command:

$ sudo apt-get install gimp

Once GIMP is installed, you’ll find a new entry in your Main menu under the Graphics heading called GNU Image Manipulation Program.

Discussion

Despite being hungry for memory and processor power, GIMP is usable even on a Raspberry Pi 2 B, but there will be much less waiting around if you use a Raspberry Pi 4.

Raspbian also includes a simpler image manipulation program called ImageMagick. You will find this on the Start menu under Graphics. You also can use it from the command line to do things like change the resolution of images. Read more about it on the ImageMagick GitHub repo.

See Also

Find out more from the GIMP website.

GIMP has a lot of features and is a very sophisticated image-editing program, so it does take a little learning. You’ll find an online manual for the software at the GIMP website, under the Docs tab.

For editing vector images, see Recipe 4.8.

For more information on installing with apt-get, see Recipe 3.17.

4.8 Editing Vector Images

Problem

You want to create or edit high-quality vector drawings such as Scalable Vector Graphics (SVG).

Solution

Install Inkscape using the following commands:

$ sudo apt-get update
$ sudo apt-get install inkscape

Once Inkscape is installed, its icon will appear in the Graphics section of your Raspberry Pi Start menu.

Inkscape (Figure 4-9) is the most used open source vector image editor.

Figure 4-9. Inkscape on a Raspberry Pi

Discussion

Inkscape is a very powerful piece of software with very many features that can take some time to master, so don’t be disheartened if it won’t do what you want at first. You will probably need to run through a few tutorials.

Inkscape is another program best run with the extra power of a Raspberry Pi 4, 3, or 2.

See Also

For documentation on Inkscape, visit https://inkscape.org.

For editing bitmap images such as photographs, see Recipe 4.7.

4.9 Internet Radio

Problem

You want to be able to play internet radio on your Raspberry Pi.

Solution

Install the VLC media player by running the following command:

sudo apt-get install vlc

Once it’s installed, you can find VLC in the Sound & Video section of your Main menu.

Run the program and then, on the Media menu, select the Open Network Stream option. This opens a dialog box (see Figure 4-10) in which you can enter the URL of the internet radio station that you want to play.

You will need to plug headphones or amplified speakers into the audio socket on the Raspberry Pi.

Figure 4-10. VLC on a Raspberry Pi

Discussion

You also can run VLC from the command line as follows:

$ vlc http://www.a-1radio.com/listen.pls -I dummy

VLC will probably produce a series of error messages but then play the audio just fine.

See Also

This recipe borrows heavily from this tutorial, in which Jan Holst takes things a step further and adds radio-style controls to the project.

For UK readers, you can find a list of the BBC radio stream URLs online.

Chapter 5. Python Basics

5.0 Introduction

Although many languages can be used to program the Raspberry Pi, Python is the most popular. In fact, the Pi in Raspberry Pi is inspired by the word python.

In this chapter, you’ll find a host of recipes to help you start programming with Raspberry Pi.

5.1 Deciding Between Python 2 and Python 3

Problem

You need to use Python but are unsure which version to use.

Solution

Use both. Use Python 3 until you face a problem that is best solved by reverting to version 2.

Discussion

Although Python’s most recent version, Python 3, has been around for years, you’ll find that a lot of people still use Python 2. In fact, in the Raspbian distribution, both versions are supplied, and version 2 is just called Python, whereas version 3 is called Python 3. And Python 3 is run by using the command python3. The examples in this book are written for Python 3 unless otherwise stated. Most will run on both Python 2 and Python 3 without modification.

This reluctance on the part of the Python community to ditch the older version is largely because Python 3 introduced some changes that broke compatibility with version 2. As a result, some of the huge body of third-party libraries developed for Python 2 won’t work under Python 3.

My strategy is to write in Python 3 whenever possible, reverting Python 2 when I need to because of compatibility problems.

See Also

For a good summary of the Python 2 versus Python 3 debate, see the Python wiki.

5.2 Editing Python Programs with Mu

Problem

You have heard of the Mu editor and want to use it to write your Python programs.

Solution

Mu is preinstalled in the latest versions of Raspbian. You will find it in the Programming section of the Main menu (Figure 5-1).

Figure 5-1. Opening Mu from the Main menu

When you first start Mu, you are prompted to select a mode (Figure 5-2).

Figure 5-2. Selecting a mode for Mu

Select the Python 3 mode and click OK. This opens the Mu editor, so it’s ready for you to start writing some Python.

Let’s try it out. Carefully type the following test into the editor area under the comment “Write your code here :-)”:

for i in range(1, 10):
    print(i)

This short program will count to 9. Don’t worry how it works for now; all will be explained in Recipe 5.21. Note that when you get to the end of the first line and press Enter, the second line with the print statement should indent automatically (Figure 5-3).

Figure 5-3. Editing code in Mu

Before we can run the program we need to save it to a file, so at the top of the Mu window, click the Save button and then enter the filename count.py (Figure 5-4).

Figure 5-4. Saving a file in Mu

Now that the file is saved, run the program by clicking the Run button at the top of the Mu window. This causes the Mu editor screen to split, with the bottom half showing the result of running the program (Figure 5-5).

Figure 5-5. Running the program count.py

If you have already followed Recipe 3.22 and downloaded the files accompanying this book, you can open these directly in Mu using the Open button and then navigating to the folder /home/pi/raspberrypi_cookbook_ed3/python, as shown in Figure 5-6. Note that Mu is Python 3 and there are a few Python programs for this book that work only with Python 2, so check the text of the recipe that the code belongs to if you have problems running it from Mu.

Figure 5-6. Accessing this book’s Python code from Mu

Discussion

Python is unusual for a programming language in that indentation is a fundamental part of the language. Whereas many C-based languages use { and } to delimit a block of code, Python uses the indentation level. So in the preceding example, Python knows that print is to be invoked repeatedly as part of the for loop because it is indented four spaces from the left.

When you’re starting out in Python, it’s not uncommon to see an error such as IndentationError: unexpected indent, which means that something is not indented correctly somewhere. If everything appears to line up, double-check that none of the indents contain tab characters, because Python treats tabs differently.

In selecting Python 3 for our editing mode (Figure 5-2), we ignored the other options for mode. The Adafruit CircuitPython mode allows you to use your Raspberry Pi to program Adafruit’s range of CircuitPython boards, and the BBC micro:bit mode allows you to write MicroPython programs for a BBC micro:bit board. Both of these activities are about using other boards that are not covered in this book; however, it’s good to know that these are an options for using the Raspberry Pi with these microcontrollers.

See Also

As well as using Mu to edit and run Python files, you can also take a lower-tech approach by editing files in nano (Recipe 3.7) and then running them from a Terminal session (Recipe 5.4).

5.3 Using the Python Console

Problem

You want to enter Python commands without writing an entire program. It can be useful to do this to experiment with some features of Python.

Solution

Use the Python console, either within Mu or in a Terminal session. The Python console provides a command line a little like that of Raspbian (Recipe 3.3), but instead of entering operating system commands, you can enter Python commands. If you are using Mu (Recipe 5.2), you can access the Python console by clicking the REPL (Read Eval Print Loop) button at the top of the Mu window (Figure 5-7).

Figure 5-7. Entering commands in the REPL

Ignoring everything except the bottom of Figure 5-7, you can see that there is a command prompt where you can type Python commands. In this case, I have typed the following:

2 + 2

and reassuringly received the answer:

4

Discussion

An alternative to using Mu to run individual Python commands is to start a Python 3 console in a Terminal window by typing the command python3—or to start a Python 2 console, type the command python.

The >>> prompt indicates that you can type Python commands. If you need to type multiline commands, then the console will automatically provide a continuation line indicated by three dots. You still need to indent such lines by four spaces, as shown in the following session:

>>> from time import sleep
>>> while True:
...    print("hello")
...    sleep(1)
...
hello
hello

You need to press Enter twice after your last command for the console to recognize the end of the indented block and run the code.

The Python console also provides a command history so that you can move back and forth through your previous commands using the up arrow and down arrow keys.

When you are finished with the Python console and want to return to the command line, type exit().

See Also

If you have more than a couple of lines that you want to type in, chances are you would be better off using Mu (Recipe 5.2) to edit and run a file.

5.4 Running Python Programs from the Terminal

Problem

Running programs from within Mu (Recipe 5.2) is fine, but sometimes you want to run a Python program from a Terminal window.

Solution

Use the python or python3 command in a Terminal, followed by the filename containing the program you want to run.

Discussion

To run a Python 3 program from the command line, use a command like this:

$ python3 myprogram.py

If you want to run the program using Python 2, change the command python3 to python. In both cases the Python program that you want to run should be in a file with the extension .py.

You can run most Python programs as a normal user; however, some you’ll need to run as superuser. If this is the case for your program, prefix the command with sudo:

$ sudo python3 myprogram.py

In the earlier examples, you need to include python3 in the command to run the program, but you can also add a line to the start of a Python program so that Linux knows it is a Python program. This special line is called a shebang (a contraction of the names of two symbols, “hash” and “interrobang”), and the following single-line example program has it as its first line:

#!/usr/bin/python3
print("I'm a program, I can run all by myself")

Before you can run this directly from the command line, you must give the file write permissions by using the following command (see Recipe 3.14); this assumes the file is called test.py:

$ chmod +x test.py

The parameter +x means to add execute permissions to the file.

Now you can run the Python program test.py by using the single command:

$ ./test.py
I'm a program, I can run all by myself
$

The ./ at the start of the line is needed for the command line to find the file.

See Also

Recipe 3.25 shows you how to run a Python program as a timed event.

To automatically run a program at startup, see Recipe 3.24.

5.5 Assigning Names to Values (Variables)

Problem

You want to give a value a name.

Solution

You assign a value to a name using =.

Discussion

In Python, you don’t have to declare the type of a variable; you can just assign it a value using the assignment operator (=), as shown in the following examples:

a = 123
b = 12.34
c = "Hello"
d = 'Hello'
e = True

You can define character-string constants using either single or double quotes. The logical constants in Python are True and False, and they are case sensitive.

By convention, variable names begin with a lowercase letter, and if the variable name consists of more than one word, the words are joined together with an underscore character. It is always a good idea to give your variables descriptive names so that when you come back to your program after a break, you can work out how it works.

Some examples of valid variable names are x, total, and number_of_chars.

See Also

You also can assign a variable a value that is a list (Recipe 6.1) or a dictionary (Recipe 6.12).

For more information on arithmetic with variables, see Recipe 5.8.

5.6 Displaying Output

Problem

You want to see the value of a variable.

Solution

Use the print command. You can try the following example in the Python console (Recipe 5.3):

>>> x = 10
>>> print(x)
10
>>>

Note that the print command starts a new line to print on.

Discussion

In Python 2, you can use the print command without brackets. However, this is not true in Python 3, so for compatibility with both versions of Python, always use brackets around the value you are printing.

See Also

To read user input, see Recipe 5.7.

5.7 Reading User Input

Problem

You want to prompt the user to enter a value.

Solution

Use the input (Python 3) or raw_input (Python 2) command. You can try the following example in the Python 3 console (Recipe 5.3):

>>> x = input("Enter Value:")
Enter Value:23
>>> print(x)
23
>>>

Discussion

In Python 2, raw_input must be substituted for input in the preceding example.

Python 2 also has an input function, but that function validates the input and attempts to convert it into a Python value of the appropriate type, whereas raw_input does the same thing as input in Python 3 and just returns a string, even if what you typed is a number.

See Also

Find more information on Python 2 input at https://oreil.ly/EhqMt.

5.8 Arithmetic

Problem

You want to do arithmetic in Python.

Solution

Use the +, -, *, and / operators.

Discussion

The most common operators for arithmetic are +, -, *, and /, which are, respectively, add, subtract, multiply, and divide.

You can also group together parts of the expression with parentheses, as shown in the following example, which, given a temperature in degrees Celsius, converts it to degrees Fahrenheit:

>>> tempC = input("Enter temp in C: ")
Enter temp in C: 20
>>> tempF = (int(tempC) * 9) / 5 + 32
>>> print(tempF)
68.0
>>>

Other arithmetic operators include % (modulo remainder) and ** (raise to the power of). For example, to raise 2 to the power of 8, you would write the following:

>>> 2 ** 8
256

See Also

See Recipe 5.7 on using the input command, and Recipe 5.12 on converting the string value from input to a number.

The Math library has many useful math functions that you can use.

5.9 Creating Strings

Problem

You want to create a string variable—that is, a variable that contains text.

Solution

Use the assignment operator (=) and a string constant to create a new string. You can use either double or single quotation marks around the string, but they must match. For example:

>>> s = "abc def"
>>> print(s)
abc def
>>>

Discussion

If including double or single quotes inside a string, pick the type of quotes that you don’t need to use within the contents of the string itself as the beginning and end markers of the string. For example:

>>> s = "Isn't it warm?"
>>> print(s)
Isn't it warm?
>>>

Sometimes you’ll need to include special characters such as tab or newline inside your string. This requires the use of what are called escape characters. To include a tab, use \t, and for a newline, use \n. For example:

>>> s = "name\tage\nMatt\t14"
>>> print(s)
name	age
Matt	14
>>>

See Also

For a full list of escape characters, see the Python Reference Manual.

5.10 Concatenating (Joining) Strings

Problem

You want to join a number of strings together.

Solution

Use the + (concatenate) operator.

For example:

>>> s1 = "abc"
>>> s2 = "def"
>>> s = s1 + s2
>>> print(s)
abcdef
>>>

Discussion

In many languages, you can have a chain of values to concatenate, some of which are strings and some of which are other types such as numbers, and numbers will automatically be converted into strings during the concatenation. This is not the case in Python, and if you try the following command, you will get an error:

>>> "abc" + 23
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Can't convert 'int' object to str implicitly

You need to convert each component that you want to concatenate into a string before concatenating, as shown in this example:

>>> "abc" + str(23)
'abc23'
>>>

See Also

See Recipe 5.11 for more information about converting numbers into strings using the str function.

5.11 Converting Numbers into Strings

Problem

You want to convert a number into a string.

Solution

Use the str Python function.

For example:

>>> str(123)
'123'
>>>

Discussion

A common reason for wanting to convert a number into a string is so you can then concatenate it with another string (Recipe 5.10).

See Also

For the reverse operation of turning a string into a number, see Recipe 5.12.

5.12 Converting Strings into Numbers

Problem

You want to convert a string into a number.

Solution

Use the int or float Python function.

For example, to convert the string -123 into a number, you could use the following:

>>> int("-123")
-123
>>>

This will work on both positive and negative whole numbers.

To convert a floating-point number, use float instead of int:

>>> float("00123.45")
123.45
>>>

Discussion

Both int and float will handle leading zeros correctly and are tolerant of any spaces or other whitespace characters around the number.

You can also use int to convert a string representing a number in a number base other than the default of 10 by supplying the number base as the second argument. The following example converts the string representation of binary 1001 into a number:

>>> int("1001", 2)
9
>>>

This second example converts the hexadecimal number AFF0 into an integer:

>>> int("AFF0", 16)
45040
>>>

See Also

For the reverse operation of turning a number into a string, see Recipe 5.11.

5.13 Finding the Length of a String

Problem

You need to know how many characters there are in a string.

Solution

Use the len Python function.

Discussion

For example, to find the length of the string abcdef, you would use:

>>> len("abcdef")
6
>>>

See Also

The len command also works on lists (Recipe 6.3).

5.14 Finding the Position of One String Within Another

Problem

You need to find the position of one string within another.

Solution

Use the find Python function.

For example, to find the starting position of the string def within the string abcdefghi, you would use:

>>> s = "abcdefghi"
>>> s.find("def")
3
>>>

Note that the character positions start at 0 (not 1), so a position of 3 means the fourth character in the string.

Discussion

If the string you’re looking for doesn’t exist in the string being searched, find returns the value –1.

See Also

The replace function is used to find and then replace all occurrences of a string (Recipe 5.16).

5.15 Extracting Part of a String

Problem

You want to cut out a section of a string between certain character positions.

Solution

Use the Python [:] notation.

For example, to cut out a section from the second character to the fifth character of the string abcdefghi, you would use the following:

>>> s = "abcdefghi"
>>> s[1:5]
'bcde'
>>>

Note that the character positions start at 0 (not 1), so a position of 1 means the second character in the string, and 5 means the sixth; however, the character range is exclusive at the high end. Thus in this example, the letter f is not included.

Discussion

The [:] notation is actually quite powerful. You can omit either argument, in which case the start or end of the string is assumed as appropriate. For example:

>>> s = "abcdefghi"
>>> s[:5]
'abcde'
>>>

and:

>>> s = "abcdefghi"
>>> s[3:]
'defghi'
>>>

You can also use negative indices to count back from the end of the string. This can be useful in situations such as when you want to find the three-letter extension of a file, as in the following example:

>>> "myfile.txt"[-3:]
'txt'

See Also

Recipe 5.10 describes joining strings together rather than splitting them.

Recipe 6.10 uses the same syntax but with lists rather than strings.

Another and more powerful way to manipulate strings is described in Recipe 7.23.

5.16 Replacing One String of Characters with Another Within a String

Problem

You want to replace all occurrences of a string within another string.

Solution

Use the replace function.

For example, to replace all occurrences of X with times, you would use the following:

>>> s = "It was the best of X. It was the worst of X"
>>> s.replace("X", "times")
'It was the best of times. It was the worst of times'
>>>

Discussion

The string you’re searching for must match exactly; that is, the search is case sensitive and will include spaces.

See Also

See Recipe 5.14 for searching a string without performing a replacement.

Another and more powerful way to manipulate strings is described in Recipe 7.23.

5.17 Converting a String to Uppercase or Lowercase

Problem

You want to convert all the characters in a string to uppercase or lowercase letters.

Solution

Use the upper or lower function as appropriate.

For example, to convert aBcDe to uppercase, you would use the following:

>>> "aBcDe".upper()
'ABCDE'
>>>

To convert it to lowercase, use this:

>>> "aBcDe".lower()
'abcde'
>>>

Note that even though upper and lower do not take any parameters, they still need a () on the end.

Discussion

Like most functions that manipulate a string in some way, upper and lower do not actually modify the string but rather return a modified copy of the string.

For example, the following code returns a copy of the string s, but note how the original string is unchanged:

>>> s = "aBcDe"
>>> s.upper()
'ABCDE'
>>> s
'aBcDe'
>>>

To change the value of s to be all uppercase, do the following:

>>> s = "aBcDe"
>>> s = s.upper()
>>> s
'ABCDE'
>>>

See Also

See Recipe 5.16 for replacing text within strings.

5.18 Running Commands Conditionally

Problem

You want to run some Python commands only when some condition is true.

Solution

Use the Python if command.

The following example will print the message x is big only if x has a value greater than 100:

>>> x = 101
>>> if x > 100:
...     print("x is big")
...
x is big

Discussion

After the if keyword, there is a condition. This condition often, but not always, compares two values and gives an answer that is either True or False. If it is True, the subsequent indented lines will all be executed.

It is quite common to want to do one thing if a condition is True and something different if the answer is False. In this case, the else command is used with if, as shown in this example:

x = 101
if x > 100:
    print("x is big")
else:
    print("x is small")

print("This will always print")

You can also chain together a long series of elif (else if) conditions. If any one of the conditions succeeds, that block of code is executed, and none of the other conditions that follow it are tried.

For example:

x = 90
if x > 100:
    print("x is big")
elif x < 10:
    print("x is small")
else:
    print("x is medium")

This example will print x is medium.

See Also

See Recipe 5.19 for more information on different types of comparisons you can make.

5.19 Comparing Values

Problem

You want to compare the values of two quantities.

Solution

Use one of the comparison operators: <, >, <=, >=, ==, or !=.

Discussion

You used the < (less than) and > (greater than) operators in Recipe 5.18. Here’s the full set of comparison operators:

< | Less than
> | Greater than
<= | Less than or equal to
>= | Greater than or equal to
== | Exactly equal to
!= | Not equal to

Some people prefer to use the <> operator in place of !=. Both work the same.

You can test these commands using the Python console (Recipe 5.3), as shown in the following exchange:

>>> 1 != 2
True
>>> 1 != 1
False
>>> 10 >= 10
True
>>> 10 >= 11
False
>>> 10 == 10
True
>>>

A common mistake is to use = (set a value) instead of == (double equals) in comparisons. This can be difficult to spot because if one half of the comparison is a variable, it is perfectly legal syntax and will run, but it will not produce the result you were expecting.

As well as comparing numbers, you can also compare strings by using these comparison operators, as shown here:

>>> 'aa' < 'ab'
True
>>> 'aaa' < 'aa'
False

The strings are compared lexicographically—that is, in the order that you would find them in a dictionary.

This is not quite correct because, for each letter, the uppercase version of the letter is considered less than the lowercase equivalent. Each letter has a value that is its ASCII code, and an uppercase letter has a lower numeric value than the lowercase version of the same letter.

See Also

See also Recipes 5.18 and 5.20.

Another and more powerful way to manipulate strings is described in Recipe 7.23.

5.20 Logical Operators

Problem

You need to specify a complex condition in an if statement.

Solution

Use one of the logical operators: and, or, or not.

Discussion

As an example, you might want to check whether a variable x has a value between 10 and 20. For that, you would use the and operator:

>>> x = 17
>>> if x >= 10 and x <= 20:
...     print('x is in the middle')
...
x is in the middle

You can combine as many and and or statements as you need, and you can also use brackets to group them if the expressions become complicated.

See Also

See Recipes 5.18 and 5.19.

5.21 Repeating Instructions an Exact Number of Times

Problem

You need to repeat some program code an exact number of times.

Solution

Use the Python for command and iterate over a range.

For example, to repeat a command 10 times, use the following example:

>>> for i in range(1, 11):
...     print(i)
...
1
2
3
4
5
6
7
8
9
10
>>>

Discussion

The second parameter in the range command is exclusive; that is, to count up to 10, you must specify a value of 11.

See Also

If the condition for stopping the loop is more complicated than simply repeating the command a certain number of times, see Recipe 5.22.

If you are trying to repeat commands for each element of a list or dictionary, see Recipes 6.7 or 6.15, respectively.

5.22 Repeating Instructions Until Some Condition Changes

Problem

You need to repeat some program code until something changes.

Solution

Use the Python while statement. The while statement repeats its nested commands until its condition becomes false. The following example will stay in the loop until the user enters X for exit:

>>> answer = ''
>>> while answer != 'X':
...     answer = input('Enter command:')
...
Enter command:A
Enter command:B
Enter command:X
>>>

Discussion

Note that the preceding example uses the input command as it works in Python 3. To run the example in Python 2, substitute the command raw_input for input.

See Also

If you just want to repeat some commands a certain number of times, see Recipe 5.21.

If you are trying to repeat commands for each element of a list or dictionary, see Recipes 6.7 or 6.15, respectively.

5.23 Breaking Out of a Loop

Problem

You are in a loop and need to exit the loop if some condition occurs.

Solution

Use the Python break statement to exit either a while or for a loop.

The following example behaves in exactly the same way as the example code in Recipe 5.22:

>>> while True:
...     answer = input('Enter command:')
...     if answer == 'X':
...             break
...
Enter command:A
Enter command:B
Enter command:X
>>>

Discussion

Note that this example uses the input command as it works in Python 3. To run the example in Python 2, substitute the command raw_input for input.

This example behaves in exactly the same way as the example in Recipe 5.22. However, in this case, the condition for the while loop is just True, so the loop will never end unless we use break to exit the loop when the user enters X.

See Also

You can also leave a while loop by using its condition; see Recipe 5.18.

5.24 Defining a Function in Python

Problem

You want to avoid repeating the same code over and over in a program.

Solution

Create a function that groups together lines of code, allowing it to be called from multiple places.

The following example illustrates how to create and then call a function in Python:

def count_to_10():
    for i in range(1, 11):
        print(i)

count_to_10()

This example defines a function using the def command that will print out the numbers 1 to 10 whenever it is called:

count_to_10()

Discussion

The conventions for naming functions are the same as for variables in Recipe 5.5; that is, they should start with a lowercase letter, and if the name consists of more than one word, the words should be separated by underscores.

The example function is a little inflexible because it can only count to 10. If we wanted to make it more flexible—for example, so it could count up to any number—we could include the maximum number as a parameter to the function, as this example illustrates:

def count_to_n(n):
    for i in range(1, n + 1):
        print(i)

count_to_n(5)

The parameter n is included inside the parentheses and then used inside the range command, but not before 1 is added to it.

Using a parameter for the number you want to count up to means that if you usually count to 10 but sometimes count to a different number, you will always have to specify the number. You can, however, specify a default value for a parameter, and hence have the best of both worlds, as shown in this example:

def count_to_n(n=10):
    for i in range(1, n + 1):
        print(i)

count_to_n()

This will now count to 10 unless a different number is specified when you call the function.

If your function needs more than one parameter, perhaps to count between two numbers, the parameters are separated by commas:

def count(from_num=1, to_num=10):
    for i in range(from_num, to_num + 1):
		print(i)

count()
count(5)
count(5, 10)

All these examples are functions that do not return any value; they just do something. If you need a function to return a value, you need to use the return command.

The following function takes a string as an argument and adds the word please to the end of the string:

def make_polite(sentence):
    return sentence + " please"

print(make_polite("Pass the cheese"))

When a function returns a value, you can assign the result to a variable, or, as in this example, you can print out the result.

See Also

To return more than one value from a function, see Recipe 7.3.

Chapter 6. Python Lists and Dictionaries

6.0 Introduction

In Chapter 5, you looked at the basics of the Python language. In this chapter, you look at two key Python data structures: lists and dictionaries.

6.1 Creating a List

Problem

You want to use a variable to hold a series of values rather than just one value.

Solution

Use a list. In Python, a list is a collection of values stored in order so that you can access them by position.

You create a list by using the [ and ] characters to contain its initial contents:

>>> a = [34, 'Fred', 12, False, 72.3]
>>>

Unlike the more rigid arrays in languages like C, you don’t need to specify the size of a list in Python when you declare it. You can also change the number of elements in the list any time you like.

Discussion

As this example illustrates, the items in a list do not need to be all of the same type, although they often are.

To create an empty list that you can add items to later, you can write:

>>> a = []
>>>

See Also

All the recipes between Recipes 6.1 and 6.11 involve the use of lists.

6.2 Accessing Elements of a List

Problem

You want to find individual elements of a list or change them.

Solution

Use the [] notation to access elements of a list by their position in the list.

For example:

>>> a = [34, 'Fred', 12, False, 72.3]
>>> a[1]
'Fred'

Discussion

The list positions (indices) start at 0 for the first element (not at 1).

As well as using the [] notation to read values out of a list, you can also use it to change values at a certain position, as shown here:

>>> a = [34, 'Fred', 12, False, 72.3]
>>> a[1] = 777
>>> a
[34, 777, 12, False, 72.3]

If you try to change (or, for that matter, read) an element of a list using an index that is too large, you will get an Index out of range error:

>>> a[50] = 777
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IndexError: list assignment index out of range
>>>

See Also

All the recipes between Recipes 6.1 and 6.11 involve the use of lists.

6.3 Finding the Length of a List

Problem

You need to know how many elements there are in a list.

Solution

Use the len Python function.

For example:

>>> a = [34, 'Fred', 12, False, 72.3]
>>> len(a)
5

The function len has been in the Python language from version 1 and is rather contrary to the more object-oriented, class-based versions 2 and 3 of Python. For these, it would make more sense for you to be able to write something like:

>>> a = [34, 'Fred', 12, False, 72.3]
>>> a.length() # This example won't work

But you can’t—that’s just how it is with Python.

Discussion

The len command also works on strings (Recipe 5.13).

See Also

All the recipes between Recipes 6.1 and 6.11 involve the use of lists.

6.4 Adding Elements to a List

Problem

You need to add an item to a list.

Solution

Use the append, insert, or extend Python functions.

To add a single item to the end of a list, use append, as shown here:

>>> a = [34, 'Fred', 12, False, 72.3]
>>> a.append("new")
>>> a
[34, 'Fred', 12, False, 72.3, 'new']

Discussion

Sometimes you don’t want to add the new elements to the end of a list, but instead want to insert them at a certain position in the list. For this, use the insert command. The first argument is the index where the item should be inserted, and the second argument is the item to be inserted:

>>> a.insert(2, "new2")
>>> a
[34, 'Fred', 'new2', 12, False, 72.3]

Note how all the elements after the newly inserted element are shifted up one position.

Both append and insert add only one element to a list. The extend function adds all the elements of one list to the end of another:

>>> a = [34, 'Fred', 12, False, 72.3]
>>> b = [74, 75]
>>> a.extend(b)
>>> a
[34, 'Fred', 12, False, 72.3, 74, 75]

See Also

All the recipes between Recipes 6.1 and 6.11 involve the use of lists.

6.5 Removing Elements from a List

Problem

You need to remove an item from a list.

Solution

Use the pop Python function.

The command pop with no parameters removes the last element of a list:

>>> a = [34, 'Fred', 12, False, 72.3]
>>> a.pop()
72.3
>>> a
[34, 'Fred', 12, False]

Discussion

Notice that pop returns the value removed from the list.

To remove an item in a position other than the last element, use pop with a parameter of the position from which the item will be removed:

>>> a = [34, 'Fred', 12, False, 72.3]
>>> a.pop(0)
34

If you use an index position that is beyond the end of the list, you will get an Index out of range error.

See Also

All the recipes between Recipes 6.1 and 6.11 involve the use of lists.

6.6 Creating a List by Parsing a String

Problem

You need to convert a string of words separated by some character into an array of strings, with each string in the array being one of the words.

Solution

Use the split Python string function.

The command split with no parameters separates out the words of a string into individual elements of an array:

>>> "abc def ghi".split()
['abc', 'def', 'ghi']

If you supply split with a parameter, it will split the string, using the parameter as a separator.

For example:

>>> "abc--de--ghi".split('--')
['abc', 'de', 'ghi']

Discussion

This command can be very useful when you are, for example, importing data from a file. The split command can optionally take an argument that is the string to use as a delimiter when you are splitting the string. So if you were to use commas as a separator, you could split the string as follows:

>>> "abc,def,ghi".split(',')
['abc', 'def', 'ghi']

See Also

All the recipes between Recipes 6.1 and 6.11 involve the use of lists.

Another and more powerful way to manipulate strings is described in Recipe 7.23.

6.7 Iterating Over a List

Problem

You need to apply some lines of code to each item of a list in turn.

Solution

Use the for Python language command:

>>> a = [34, 'Fred', 12, False, 72.3]
>>> for x in a:
...     print(x)
...
34
Fred
12
False
72.3
>>>

Discussion

The for keyword is immediately followed by a variable name (in this case, x). This is called the loop variable; it will be set to each element of the list specified after in.

The indented lines that follow will be executed one time for each element in the list. Each time around the loop, x will be given the value of the element in the list at that position. You can then use x to print out the value, as shown in the previous example.

See Also

All the recipes between Recipes 6.1 and 6.11 involve the use of lists.

6.8 Enumerating a List

Problem

You need to run some lines of code for each item in a list in turn, but you also need to know the index position of each item.

Solution

Use the for Python language command along with the enumerate command:

>>> a = [34, 'Fred', 12, False, 72.3]
>>> for (i, x) in enumerate(a):
...     print(i, x)
...
(0, 34)
(1, 'Fred')
(2, 12)
(3, False)
(4, 72.3)
>>>

Discussion

It’s quite common to need to know the position of something in a list while enumerating each of the values. An alternative method is to simply count with an index variable and then access the value by using the [] syntax:

>>> a = [34, 'Fred', 12, False, 72.3]
>>> for i in range(len(a)):
...     print(i, a[i])
...
(0, 34)
(1, 'Fred')
(2, 12)
(3, False)
(4, 72.3)
>>>

See Also

All the recipes between Recipes 6.1 and 6.11 involve the use of lists.

See Recipe 6.7 to iterate over a list without needing to know each item’s index position.

6.9 Sorting a List

Problem

You need to sort the elements of a list.

Solution

Use the sort Python language command:

>>> a = ["it", "was", "the", "best", "of", "times"]
>>> a.sort()
>>> a
['best', 'it', 'of', 'the', 'times', 'was']

Discussion

When you sort a list, you’re actually modifying it rather than returning a sorted copy of the original list. This means that if you also need the original list, you need to use the copy command in the standard library to make a copy of the original list before sorting it:

>>> from copy import copy
>>> a = ["it", "was", "the", "best", "of", "times"]
>>> b = copy(a)
>>> b.sort()
>>> a
['it', 'was', 'the', 'best', 'of', 'times']
>>> b
['best', 'it', 'of', 'the', 'times', 'was']
>>>

The copy module is required to be able to copy objects. You can find out more about modules in Recipe 7.11.

See Also

All the recipes between Recipes 6.1 and 6.11 involve the use of lists.

6.10 Cutting Up a List

Problem

You need to make a sublist of a list, using a range of the original list’s elements.

Solution

Use the [:] Python language construction. The following example returns a list containing the elements of the original list from index position 1 to index position 2 (the number after the : is exclusive):

>>> l = ["a", "b", "c", "d"]
>>> l[1:3]
['b', 'c']

Note that the character positions start at 0 (not at 1), so a position of 1 means the second character in the string, and 3 means the fourth; however, the character range is exclusive at the high end, so the letter d is not included in this example.

Discussion

The [:] notation is actually quite powerful. You can omit either argument, in which case the start or end of the list is assumed as appropriate.

For example:

>>> l = ["a", "b", "c", "d"]
>>> l[:3]
['a', 'b', 'c']
>>> l[3:]
['d']
>>>

You can also use negative indices to count back from the end of the list. The following example returns the last two elements in the list:

>>> l[-2:]
['c', 'd']

Incidentally, l[:-2] returns ['a', 'b'] in the preceding example.

See Also

All the recipes between Recipes 6.1 and 6.11 involve the use of lists.

See Recipe 5.15, in which the same syntax is used for strings.

6.11 Applying a Function to a List

Problem

You need to apply a function to each element of a list and collect the results.

Solution

Use the Python language feature called comprehensions.

The following example converts each string element of the list to uppercase and returns a new list that is the same length as the old one, but with all the strings in uppercase:

>>> l = ["abc", "def", "ghi", "jkl"]
>>> [x.upper() for x in l]
['ABC', 'DEF', 'GHI', 'JKL']

Although it can get confusing, there is no reason why you can’t combine these kinds of statements, nesting one comprehension within another.

Discussion

This is a very concise way of doing comprehensions. The entire expression must be enclosed in brackets ([]). The first element of the comprehension is the code to be evaluated for each element of the list. The rest of the comprehension looks rather like a normal list iteration command (Recipe 6.7). The loop variable follows the for keyword, and the list to be used follows the in keyword.

See Also

All the recipes between Recipes 6.1 and 6.11 involve the use of lists.

6.12 Creating a Dictionary

Problem

You need to create a lookup table in which you associate values with keys.

Solution

Use a Python dictionary.

Lists are great when you need to access a list of items in order or when you always know the index of the element that you want to use. Dictionaries are an alternative to lists for storing collections of data, but they are organized very differently, as shown in Figure 6-1.

Figure 6-1. A Python dictionary

A dictionary stores key/value pairs in such a way that you can use the key to retrieve that value very efficiently and without having to search the entire dictionary.

To create a dictionary, you use the {} notation:

>>> phone_numbers = {'Simon':'01234 567899', 'Jane':'01234 666666'}

Discussion

In this example, the keys of the dictionary are strings, but they do not need to be; they could be numbers or in fact of any data type, although strings are most commonly used.

The values can also be of any data type, including other dictionaries or lists. The following example creates one dictionary (a) and then uses it as a value in a second dictionary (b):

>>> a = {'key1':'value1', 'key2':2}
>>> a
{'key2': 2, 'key1': 'value1'}
>>> b = {'b_key1':a}
>>> b
{'b_key1': {'key2': 2, 'key1': 'value1'}}

When you display the contents of a dictionary, notice that the order of the items in the dictionary might not match the order in which they were specified when the dictionary was created and initialized with some contents:

>>> phone_numbers = {'Simon':'01234 567899', 'Jane':'01234 666666'}
>>> phone_numbers
{'Jane': '01234 666666', 'Simon': '01234 567899'}

Unlike lists, dictionaries have no concept of keeping items in order. Because of the way they are represented internally, the order of a dictionary’s contents will be—for all intents and purposes—random.

The reason the order appears to be random is that the underlying data structure is a hash table. Hash tables use a hashing function to decide where to store each value; the hashing function calculates a numeric equivalent to any object.

You can find out more about hash tables at Wikipedia.

See Also

All the recipes between Recipes 6.12 and 6.15 involve the use of dictionaries.

Dictionaries have much in common with the JSON data structuring language described in Recipe 7.21.

6.13 Accessing a Dictionary

Problem

You need to find and change entries in a dictionary.

Solution

Provide the Python [] notation. Use the key of the entry to which you need access within the brackets, as follows:

>>> phone_numbers = {'Simon':'01234 567899', 'Jane':'01234 666666'}
>>> phone_numbers['Simon']
'01234 567899'
>>> phone_numbers['Jane']
'01234 666666'

Discussion

The lookup process is in one direction only, from key to value.

If you use a key that is not present in the dictionary, you will get a KeyError. For example:

>>> phone_numbers = {'Simon':'01234 567899', 'Jane':'01234 666666'}
>>> phone_numbers['Phil']
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: 'Phil'
>>>

As well as using the [] notation to read values from a dictionary, you can also use it to add new values or overwrite existing ones.

The following example adds a new entry to the dictionary with a key of Pete and a value of 01234 777555:

>>> phone_numbers = {'Simon':'01234 567899', 'Jane':'01234 666666'}
>>> phone_numbers['Pete'] = '01234 777555'
>>> phone_numbers['Pete']
'01234 777555'

If the key is not in use in the dictionary, a new entry is automatically added. If the key is already present, then whatever value was there before will be overwritten by the new value.

This is in contrast to trying to read a value from the dictionary, where an unknown key will cause an error.

See Also

All the recipes between Recipes 6.12 and 6.15 involve the use of dictionaries.

For information on handling errors, see Recipe 7.10.

6.14 Removing Entries from a Dictionary

Problem

You need to remove an item from a dictionary.

Solution

Use the pop command, specifying the key for the item that you want to remove:

>>> phone_numbers = {'Simon':'01234 567899', 'Jane':'01234 666666'}
>>> phone_numbers.pop('Jane')
'01234 666666'
>>> phone_numbers
{'Simon': '01234 567899'}

Discussion

The pop command returns the value of the item removed from the dictionary.

See Also

All the recipes between Recipes 6.12 and 6.15 involve the use of dictionaries.

6.15 Iterating Over Dictionaries

Problem

You need to do something to each of the items in the dictionary in turn.

Solution

Use the for command to iterate over the keys of the dictionary:

>>> phone_numbers = {'Simon':'01234 567899', 'Jane':'01234 666666'}
>>> for name in phone_numbers:
...     print(name)
...
Jane
Simon

Notice how the keys didn’t print in the same order in which they were created. This is a feature of dictionaries. The order of the entries is not remembered.

Discussion

There are a couple of other techniques that you can use to iterate over a dictionary. The following form can be useful if you need access to the values as well as the keys:

>>> phone_numbers = {'Simon':'01234 567899', 'Jane':'01234 666666'}
>>> for name, num in phone_numbers.items():
...     print(name + " " + num)
...
Jane 01234 666666
Simon 01234 567899

See Also

All the recipes between Recipes 6.12 and 6.15 involve the use of dictionaries.

See the for command used elsewhere in Recipes 5.21, 6.7, and 6.11.

Chapter 7. Advanced Python

7.0 Introduction

In this chapter, we’ll explore some of the more advanced concepts in the Python language—in particular, object-oriented Python, reading and writing files, handling exceptions, using modules, and internet programming.

7.1 Formatting Numbers

Problem

You want to format numbers to a certain number of decimal places.

Solution

Apply a format string to the number.

For example:

>>> x = 1.2345678
>>> "x={:.2f}".format(x)
'x=1.23'
>>>

The result returned by the format method is a string, which will be displayed in the Terminal as we are working interactively. However, when using format in a program, it’s most likely to be inside a print statement, like this:

x = 1.2345678
print("x={:.2f}".format(x))

Discussion

The formatting string can contain a mixture of regular text and markers delimited by { and }. The parameters to the format function (there can be as many as you like) will be substituted in place of the marker, according to the format specifier.

In the preceding example, the format specifier is :.2f, which means that the number will be specified with two digits after the decimal place and is a float f.

If you wanted the number to be formatted so that the total length of the number is always seven digits (or padding spaces), you would add another number before the decimal place, like this:

>>> "x={:7.2f}".format(x)
'x=   1.23'
>>>

In this case, since the number is only three digits long, there are four spaces of padding before the 1. If you wanted the padding to take the form of leading zeros, you would use:

>>> "x={:07.2f}".format(x)
'x=0001.23'
>>>

A more complicated example might be to display the temperature in both degrees Celsius and degrees Fahrenheit, as shown here:

>>> c = 20.5
>>> "Temperature {:5.2f} deg C, {:5.2f} deg F.".format(c, c * 9 / 5 + 32)
'Temperature 20.50 deg C, 68.90 deg F.'
>>>

You can also use the format method to display numbers in hexadecimal and binary.

For example:

>>> "{:X}".format(42)
'2A'
>>> "{:b}".format(42)
'101010'

See Also

Formatting in Python involves a whole formatting language.

7.2 Formatting Dates and Times

Problem

You want to convert a date into a string and format it in a certain way.

Solution

Apply a format string to the date object.

For example:

>>> from datetime import datetime
>>> d = datetime.now()
>>> "{:%Y-%m-%d %H:%M:%S}".format(d)
'2015-12-09 16:00:45'
>>>

The result returned by the format method is a string, which will be displayed in the Terminal as we are working interactively. However, when using format in a program, it’s most likely to be inside a print statement, like this:

from datetime import datetime
d = datetime.now()
print("{:%Y-%m-%d %H:%M:%S}".format(d))

Discussion

The Python formatting language includes some special symbols for formatting the date. %y (which gives the year without century as a zero-padded decimal number), %m, and %d correspond to year, month, and day numbers, respectively.

Other symbols useful for formatting the date are %B, which supplies the full name of the month, and %Y, which gives the year in four-digit format, as shown here:

>>> "{:%d %B %Y}".format(d)
'09 December 2015'

See Also

See Recipe 7.1 for formatting of numbers.

Formatting in Python actually involves an entire formatting language. You will find full details of this at http://strftime.org.

7.3 Returning More Than One Value

Problem

You need to write a function that returns more than one value.

Solution

Design your function to return a Python tuple and use the multiple variable assignment syntax. A tuple is a Python data structure that’s a little like a list, except that tuples are enclosed in parentheses rather than brackets. They are also of fixed size.

For example, you could have a function that converts a temperature in Kelvin into both Fahrenheit and Celsius. You can arrange for this function to return the temperature in both these units by separating the multiple return values with commas:

>>> def calculate_temperatures(kelvin):
...     celsius = kelvin - 273
...     fahrenheit = celsius * 9 / 5 + 32
...     return celsius, fahrenheit
...
>>> c, f = calculate_temperatures(340)
>>>
>>> print(c)
67
>>> print(f)
152.6

When you call the function, you just provide the same number of variables before the =, and each of the return values will be assigned to the variable in the same position.

Discussion

Sometimes, when you have just a few values to return, this is the right way to return multiple values. However, if the data is complex, you might find that a neater solution is to use Python’s object-oriented features and define a class that contains the data. That way, you can return an instance of the class rather than a tuple.

See Also

See Recipe 7.4 for information on defining classes.

7.4 Defining a Class

Problem

You need to group related data and functionality into a class.

Solution

Define a class and provide it with the member variables you need.

The following example defines a class to represent an address book entry:

class Person:
    '''This class represents a person object'''

    def __init__(self, name, tel):
        self.name = name
        self.tel = tel

The first line inside the class definition uses triple quotes to denote a documentation string, which should explain the purpose of the class. Although entirely optional, adding a documentation string to a class allows others to see what the class does. This is particularly useful if the class is made available for others to use.

Documentation strings (or doc strings) are not like normal comments because, although they are not active lines of code, they do become associated with the class; thus, at any time, you can read the doc string for a class by using the following command:

Person.__doc__

Inside the class definition is the constructor method, which will be called automatically whenever you create a new instance of the class. A class is like a template, so in defining a class called Person, we do not create any actual Person objects until later:

def __init__(self, name, tel):
    self.name = name
    self.tel = tel

The constructor method must be named as shown, with double underscores on either side of the word init.

Discussion

One way in which Python differs from most object-oriented languages is that you need to include the special variable self as a parameter to all the methods that you define within the class. This is a reference to, in this case, the newly created instance. The variable self is the same concept as the special variable this that you find in Java and some other languages.

The code in this method transfers parameters that were supplied to it into member variables. The member variables do not need to be declared in advance, but they do need to be prefixed by self.

So this line:

self.name = name

creates a variable called name that’s accessible to every member of the class Person and initializes it with the value passed into the call to create an instance, which looks like this:

p = Person("Simon", "1234567")

We can then check that our new Person object, p, has a name of "Simon" by typing the following:

>>> p.name
Simon

In a complex program, it is good practice to put each class in its own file with a filename that matches the class name. This also makes it easy to convert the class into a module (see Recipe 7.11).

See Also

See Recipe 7.5 for information on defining methods.

7.5 Defining a Method

Problem

You need to add some code to a class.

Solution

Functions that are associated with a particular class are called methods.

The following example shows how you can include a method within a class definition:

class Person:
    '''This class represents a person object'''

    def __init__(self, first_name, surname, tel):
        self.first_name = first_name
        self.surname = surname
        self.tel = tel

    def full_name(self):
        return self.first_name + " " + self.surname

The full_name method concatenates the first name and surname attributes of the person, placing a space between them.

Discussion

You can think of methods just as functions that are tied to a specific class and may or may not use member variables of that class in their processing. So, as with a function, you can write whatever code you like in a method and also have one method call another.

See Also

See Recipe 7.4 for information on defining a class.

7.6 Inheritance

Problem

You need a specialized version of an existing class.

Solution

Use inheritance to create a subclass of an existing class and add new member variables and methods.

By default, all new classes that you create are subclasses of object. You can change this by specifying the class you want to use as a superclass in parentheses after the class name in a class definition. The following example defines a class (Employee) as a subclass of Person and adds a new member variable (salary) and an extra method (give_raise):

class Employee(Person):

    def __init__(self, first_name, surname, tel, salary):
        super().__init__(first_name, surname, tel)
        self.salary = salary

    def give_raise(self, amount):
        self.salary = self.salary + amount

Note that the preceding example is for Python 3. For Python 2, you can’t use super the same way. Instead, you must write the following:

class Employee(Person):

    def __init__(self, first_name, surname, tel, salary):
        Person.__init__(self, first_name, surname, tel)
        self.salary = salary

    def give_raise(self, amount):
        self.salary = self.salary + amount

Discussion

In both of these examples, the initializer method for the subclass first uses the initializer method of the parent class (superclass) and then adds the member variable. This has the advantage that you do not need to repeat the initialization code in the new subclass.

See Also

See Recipe 7.4 for information on defining a class.

The Python inheritance mechanism is actually very powerful and supports multiple inheritance, in which a subclass inherits from more than one superclass. For more on multiple inheritance, see the official documentation for Python.

7.7 Writing to a File

Problem

You need to write something to a file.

Solution

Use the open, write, and close functions to open a file, write some data, and then close the file, respectively:

>>> f = open('test.txt', 'w')
>>> f.write('This file is not empty')
>>> f.close()

Discussion

Once you have opened the file, you can make as many writes to it as you like before you close the file. Note that it is important to use close because, although each write should update the file immediately, it might be buffered in memory and data could be lost. It could also leave the file locked so that other programs can’t open it.

The open method takes two parameters. The first is the path to the file to be written. This can be relative to the current working directory or, if it starts with a /, an absolute path.

The second (optional) parameter is the mode in which the file should be opened. If this is omitted, then read-only (r) mode is assumed. To overwrite an existing file or create the file with the name specified if it doesn’t already exist, just use w. Table 7-1 shows the full list of file mode characters. You can combine these using +. So, to open a file in read and binary mode, you would use this:

>>> f = open('test.txt', 'r+b')

Table 7-1. File modes

Mode
Description

r

Read

w

Write

a

Append to the end of an existing file rather than overwriting

b

Binary mode

t

Text mode (default)

+

A shortcut for r+w

Binary mode allows you to read or write binary streams of data, such as images, rather than text.

See Also

To read the contents of a file, see Recipe 7.8. For more information on handling exceptions, see Recipe 7.10.

7.8 Reading from a File

Problem

You need to read the contents of a file into a string variable.

Solution

To read a file’s contents, you need to use the file methods open, read, and close. The following example reads the entire contents of the file into the variable s:

f = open('test.txt')
s = f.read()
f.close()

Discussion

You can also read text files one line at a time using the method readline.

The preceding example will throw an exception if the file does not exist or is not readable for some other reason. You can handle this by enclosing the code in a try/except construction, like so:

try:
    f = open('test.txt')
    s = f.read()
    f.close()
except IOError:
    print("Cannot open the file")

See Also

To write things to a file, and for a list of file open modes, see Recipe 7.7.

To parse JSON data, see Recipe 7.21.

For more information on handling exceptions, see Recipe 7.10.

7.9 Pickling

Problem

You want to save the entire contents of a data structure to a file so that it can be read the next time the program is run.

Solution

Use the Python pickling feature to dump the data structure to file in a format that can be automatically read back into memory as an equivalent data structure later on.

The following example saves a complex list structure to file:

>>> import pickle
>>> mylist = ['some text', 123, [4, 5, True]]
>>> f = open('mylist.pickle', 'wb')
>>> pickle.dump(mylist, f)
>>> f.close()

To unpickle the contents of the file into a new list, use the following:

>>> f = open('mylist.pickle', 'rb')
>>> other_array = pickle.load(f)
>>> f.close()
>>> other_array
['some text', 123, [4, 5, True]]

Discussion

Pickling will work on pretty much any data structure you can throw at it. It does not need to be a list.

The file is saved in a binary format that is not human-readable; you must open the file using the wb (write binary) option when writing the file and with the rb (read binary) option when reading the pickle file.

See Also

To write things to a file and for a list of file open modes, see Recipe 7.7.

7.10 Handling Exceptions

Problem

If something goes wrong while a program is running, you want to catch the error or exception and display a more user-friendly error message.

Solution

Use Python’s try/except construct.

The following example, from Recipe 7.8, catches any problems when opening a file:

try:
    f = open('test.txt')
    s = f.read()
    f.close()
except IOError:
    print("Cannot open the file")

Because you wrapped the potentially error-prone commands to open the file in a try/except construction, any error that occurs will be captured before it displays an error message, allowing you to handle it in your own way. Here, this means displaying the friendly message "Cannot open the file".

Discussion

A common situation in which runtime exceptions can occur, in addition to during file access, is when you are accessing a list and the index you are using is outside the bounds of the list. For example, this happens if you try to access the fifth (index 4) element of a three-element list:

>>> list = [1, 2, 3]
>>> list[4]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IndexError: list index out of range

Errors and exceptions are arranged in a hierarchy, and you can be as specific or general as you like when catching the exceptions.

The class Exception is pretty near the top of that tree (most general) and will catch almost any exception. You can also have separate except sections for catching different types of exception and handling, each in a different way. If you do not specify any exception class, all exceptions will be caught by the except command.

Python also allows you to have else and finally clauses in your error handling:

list = [1, 2, 3]
try:
    list[8]
except:
    print("out of range")
else:
    print("in range")
finally:
    print("always do this")

The else clause will be run if there is no exception, and the finally clause will be run whether there is an exception or not.

Whenever an exception occurs, you can get more information about it by using the Exception object, which is available only if you use the as keyword, as shown in the following example:

>>> list = [1, 2, 3]
>>> try:
...     list[8]
... except Exception as e:
...     print("out of range")
...     print(e)
...
out of range
list index out of range
>>>

This allows you to handle the error in your own way, while keeping hold of the original error message.

See Also

See the official Python documentation for Python exception class hierarchy.

7.11 Using Modules

Problem

You want to use a Python module in your program.

Solution

Use the import command:

import random

Discussion

A large number of modules (sometimes called libraries) are available for Python. Many are included with Python as part of the standard library, and others can be downloaded and installed into Python. Standard Python libraries include modules for random numbers, database access, various internet protocols, object serialization, and many other functions.

One consequence of having so many modules is that there is the potential for conflict—for example, if two modules have a function of the same name. To avoid such conflicts, specify how much of the module is accessible when importing a module.

So if you just use a command like this:

import random

there is no possibility of a conflict because you will only be able to access functions or variables in the module by prefixing them with random (e.g., random.randint). Incidentally, you’ll be meeting the random package in the next recipe.

If, on the other hand, you use the command in the following example, every function of variable in the module will be accessible without your having to add anything in front of it; unless you know what all the functions are in all the modules you are using, there is a much greater chance of conflict:

from random import *

In between these two extremes, you can explicitly specify the components of a module that you need within a program so that they can be conveniently used without any prefix.

For example:

>>> from random import randint
>>> print(randint(1,6))
2
>>>

A third option is to use the as keyword to provide a more convenient or meaningful name for the module when referencing it.

>>> import random as R
>>> R.randint(1, 6)

See Also

For a definitive list of the modules Python includes, see http://docs.python.org/2/library.

7.12 Random Numbers

Problem

You need to generate a random number between a range of numbers.

Solution

Use the random library:

>>> import random
>>> random.randint(1, 6)
2
>>> random.randint(1, 6)
6
>>> random.randint(1, 6)
5

The number generated will be between the two arguments (inclusive)—in this case, simulating a gaming die.

Discussion

The numbers generated are not truly random but are what is known as a pseudorandom number sequence; that is, they are a long sequence of numbers that, when taken in a large enough quantity, show what statisticians call a random distribution. For games, this is perfectly good enough, but if you were generating lottery numbers, you would need to look at special randomizing hardware. Computers are just plain bad at being random; it’s not really in their nature.

A common use of random numbers is to select something at random from a list. You can do this by generating an index position and using that, but there is also a command in the random module specifically for this. Try the following example:

>>> import random
>>> random.choice(['a', 'b', 'c'])
'a'
>>> random.choice(['a', 'b', 'c'])
'b'
>>> random.choice(['a', 'b', 'c'])
'a'

When making random selections like this, it’s not uncommon to prevent choices from repeating. For example, if you have already chosen 'a' at random, it shouldn’t be chosen again.

One way to do this is to take a copy of your list and then, whenever you have selected an item from it, remove that item so that it can’t be chosen again. Here’s how you could do that in a small program that you can find with the book downloads (see Recipe 3.22); this program is ch_07_random.py:

import random
from copy import copy

list = ['a', 'b', 'c']

working_list = copy(list)
while len(working_list) > 0 :
    x = random.choice(working_list)
    print(x)
    working_list.remove(x)

Run the program, and it will display the list items, selected at random, just once:

$ python3 ch_07_random.py
b
c
a

The order is likely to be different each time you run the program.

See Also

See the official reference for the random package for more information on this.

7.13 Making Web Requests from Python

Problem

You need to read the contents of a web page into a string using Python.

Solution

Python has an extensive library for making HTTP requests.

The following Python 3 example reads the contents of the Google home page into the string contents:

import urllib.request
contents = urllib.request.urlopen("https://www.google.com/").read()
print(contents)

Discussion

Having read the HTML, you are then likely to want to search it and extract the parts of the text that you really want. For this, you will need to use the string manipulation functions (see Recipes 5.14 and 5.15).

See Also

For more internet-related examples using Python, see Chapter 16.

When the web request returns JSON data, you can parse it using Recipe 7.21.

7.14 Command-Line Arguments in Python

Problem

You want to run a Python program from the command line and pass it parameters.

Solution

Import sys and use its argv variable, as shown in the following example. This returns an array, the first element of which is the name of the program. The other elements are any parameters (separated by spaces) that were typed on the command line after the program name.

The code for this example and for the other examples in this book can be downloaded in Recipe 3.22; the program is called ch_07_cmdline.py:

import sys

for (i, value) in enumerate(sys.argv):
    print("arg: %d %s " % (i, value))

Running the program from the command line, with some parameters after it, results in the following output:

$ python3 ch_07_cmdline.py a b c
arg: 0 cmd_line.py
arg: 1 a
arg: 2 b
arg: 3 c

Discussion

Being able to specify command-line arguments can be useful for automating the running of Python programs, either at startup (Recipe 3.23) or on a timed basis (Recipe 3.25).

See Also

For basic information on running Python from the command line, see Recipe 5.4.

To print out argv, we used list enumerations (Recipe 6.8).

7.15 Running Linux Commands from Python

Problem

You want to run a Linux command or program from your Python program.

Solution

Use the system command.

For example, to delete a file called myfile.txt in the directory from which you started Python, you could do the following:

import os
os.system("rm myfile.txt")

Discussion

Sometimes rather than just execute a command blindly, as in the preceding example, you need to capture the response of the command. Let’s say you wanted to use the 'hostname' command to find the IP address (see Recipe 2.2) of the Raspberry Pi. In this case, you can use the check_output function in the subprocess library:

import subprocess
ip = subprocess.check_output(['hostname', '-I'])

The variable ip will contain the IP address of the Raspberry Pi. Unlike system, check_output requires the command itself and any parameters to be supplied as separate elements of a list.

See Also

For documentation on the OS library, see https://oreil.ly/1LL8G.

For more information on the subprocess library, see https://oreil.ly/HVBq-.

In Recipe 14.4, you’ll find an example that uses subprocess to display the IP address, hostname, and time of your Raspberry Pi on an LCD screen.

7.16 Sending Email from Python

Problem

You want to send an email message from a Python program.

Solution

Python has a library for the Simple Mail Transfer Protocol (SMTP) that you can use to send emails:

import smtplib

GMAIL_USER = 'your_name@gmail.com'
GMAIL_PASS = 'your_password'
SMTP_SERVER = 'smtp.gmail.com'
SMTP_PORT = 587

def send_email(recipient, subject, text):
    smtpserver = smtplib.SMTP(SMTP_SERVER, SMTP_PORT)
    smtpserver.ehlo()
    smtpserver.starttls()
    smtpserver.ehlo
    smtpserver.login(GMAIL_USER, GMAIL_PASS)
    header = 'To:' + recipient + '\n' + 'From: ' + GMAIL_USER
    header = header + '\n' + 'Subject:' + subject + '\n'
    msg = header + '\n' + text + ' \n\n'
    smtpserver.sendmail(GMAIL_USER, recipient, msg)
    smtpserver.close()

send_email('destination_email_address', 'sub', 'this is text')

To use this example to send an email to an address of your choice, first change the variables GMAIL_USER and GMAIL_PASS to match your email credentials. If you are not using Gmail, you will also need to change the value of SMTP_SERVER and possibly of SMTP_PORT as well.

You also need to change the destination email address in the last line.

Discussion

The send_email method simplifies the use of the smtplib library into a single function that you can reuse in your projects.

Being able to send emails from Python opens up all sorts of project opportunities. For example, you could use a device such as a Passive Infrared (PIR) sensor to send an email when movement is detected.

See Also

For a similar example that uses the IFTTT web service to send emails, see Recipe 16.4.

To perform HTTP requests from the Raspberry Pi, see Recipe 7.13.

For more information on the smtplib, see https://oreil.ly/1BLt2.

For many more internet-related recipes, see Chapter 16.

7.17 Writing a Simple Web Server in Python

Problem

You need to create a simple Python web server, but you don’t want to have to run a full web server stack.

Solution

Use the bottle Python library to run a pure Python web server that will respond to HTTP requests.

To install bottle, use the following command:

$ sudo apt-get install python-bottle

The following Python program (called ch_07_bottle_test.py) simply serves up a message displaying what time the Raspberry Pi thinks it is. As with all the program examples in this book, you can also download it (see Recipe 3.22):

from bottle import route, run, template
from datetime import datetime

@route('/')
def index(name='time'):
    dt = datetime.now()
    time = "{:%Y-%m-%d %H:%M:%S}".format(dt)
    return template('<b>Pi thinks the date/time is: {{t}}</b>', t=time)

run(host='0.0.0.0', port=80)

To start the program, you need to run it with superuser privileges and as Python 2 (not as Python 3):

$ sudo python bottle_test.py

Figure 7-1 shows the page you see if you connect to the Raspberry Pi from a browser anywhere on your network.

Figure 7-1. Browsing to a Python bottle web server

This example requires a little explanation.

After the import commands, the @route command links the URL path / with the handler function that follows it.

That handler function formats the date and time and then returns a string of HTML to be rendered by the browser. In this case, it uses a template into which values can be substituted.

The final run line actually starts the web serving process. Port 80 is the default port for web serving; if you want to use a different port, add the port number with a : after the server address.

Discussion

You can define as many routes and handlers as you like within the program.

bottle is perfect for small, simple web server projects, and because it’s written in Python, it’s very easy to write a handler function to control hardware in response to the user interacting with the page in a browser. You will find other examples using bottle in Chapter 16.

The Raspberry Pi (especially a Raspberry Pi 4) is perfectly capable of running a full web server stack (web server, web framework, and database), a popular example being Apache, PHP, and MySQL. This will never perform as well as proper server hardware, but it can be a great playground for learning how these things work.

See Also

To set up a Raspberry Pi as a LAMP (Linux, Apache, MySQL, and PHP), see https://oreil.ly/MlE00.

For more information, see the bottle documentation.

For more on formatting dates and times in Python, see Recipe 7.2.

For a whole load of internet-related recipes, see Chapter 16.

7.18 Doing Nothing in Python

Problem

You want Python to kill time for a while. You might want to do this, for example, to create a delay between sending messages to the Terminal.

Solution

Use the sleep function in the time library as illustrated in the following code example, ch_07_sleep_test.py. You can find the code for this example, as well as the other code examples in this recipe, with the code downloads for the book (see Recipe 3.22):

import time

x = 0
while True:
    print(x)
    time.sleep(1)
    x += 1

The main loop of the program will delay for one second before printing the next number.

Discussion

The function time.sleep takes a whole number value representing seconds as its parameter. But if you want shorter delays, you can specify decimals. For example, to delay for a millisecond, you would use time.sleep(0.001).

It’s a good idea to put a short delay in any loop that continues indefinitely, or even just continues for more than a fraction of a second, because when sleep is being called, the processor is freed up to allow other processes to do some work.

See Also

For an interesting discussion of how time.sleep can reduce the CPU load of your Python program, see https://oreil.ly/FgpUQ.

7.19 Doing More Than One Thing at a Time

Problem

Your Python program is busy doing one thing, and you want it to do something else at the same time.

Solution

Use the Python threading library.

The following example (ch_07_thread_test.py) sets a thread running that will interrupt the counting of the main thread. As with all the program examples in this book, you can also download it (see Recipe 3.22):

import threading, time, random

def annoy(message):
    while True:
        time.sleep(random.randint(1, 3))
        print(message)

t = threading.Thread(target=annoy, args=('BOO !!',))
t.start()

x = 0
while True:
    print(x)
    x += 1
    time.sleep(1)

The output on the console will look something like this:

$ python3 ch_07_thread_test.py
0
1
BOO !!
2
BOO !!
3
4
5
BOO !!
6
7
8

When you start a new thread of execution using the Python threading library, you must specify a (target) function that is to be run as that thread. In this example, the function, called annoy, contains a loop that will continue indefinitely printing out a message after a random interval of between 1 and 3 seconds. Note that the args parameter is used to pass a string to annoy.

To start the thread actually running, the start method on the Thread class is called. This method has two parameters: the first is the name of the function to run (in this case, annoy), and the second is a tuple that contains any parameters that are to be passed to the function (in this case, 'BOO !!').

You can see that the main thread, which is just happily counting, will be interrupted every few seconds by the thread running in the annoy function.

Discussion

Threads like these are also sometimes called lightweight processes because they are similar in effect to having more than one program or process running at the same time. They do, however, have the advantage that threads running in the same program have access to the same variables, and when the main thread of the program exits, so do any threads that are started in it.

See Also

For a good introduction to threading in Python, see https://pymotw.com/3/threading/.

7.20 Using Python with Minecraft: Pi Edition

Problem

Now that you know some Python, you want to use it with Minecraft.

Solution

Use the Python interface that comes with Minecraft: Pi Edition to interact with Minecraft Pi while it is running.

Although you can switch back and forth between a Terminal session and the Minecraft game, the game will pause each time the window loses focus, so it is a lot easier to connect to the Raspberry Pi by using SSH on a second computer (Recipe 2.7). This has the added benefit that you get to see the Python script in action, live in the game.

As with all the program examples in this book, you can also download the following program (see Recipe 3.22). The file is called ch_07_minecraft_stairs.py.

The program builds a staircase at your current location (Figure 7-2):

from mcpi import minecraft, block
mc = minecraft.Minecraft.create()

mc.postToChat("Lets Build a Staircase!")

x, y, z = mc.player.getPos()

for xy in range(1, 50):
    mc.setBlock(x + xy, y + xy, z, block.STONE)

The Python library comes preinstalled in Raspbian, so if it’s not there, you should probably update your system (Recipe 3.40).

After the library imports, the variable mc is assigned to a new instance of the Minecraft class.

The postToChat method sends a message to the player’s screen telling them that the staircase is about to be built.

The variables x, y, and z are bound to the player’s position, and then the for loop increments both x and y (y is height) repeatedly to build the staircase using the setBlock method (Figure 7-2).

Figure 7-2. Building a staircase in Minecraft Pi with Python

Discussion

The mcpi library does not just allow you to post to chat, find the player’s location, and place a block; it also provides many other methods that allow you to do the following:

Find the ID of the block at the coordinates specified.

Find out who’s playing and teleport them, perhaps?

Set the position of a player.

Get the direction a player is facing.

There is no definitive documentation for the class other than this useful blog post.

See Also

For more information on the Minecraft: Pi Edition, see Recipe 4.5.

7.21 Parsing JSON

Problem

You want to parse data in the popular JSON data structuring language.

Solution

Use the json package, as shown in the following example:

import json

s = '{"books" : [
        {"title" : "Programming Arduino", "price" : 10.95},
        {"title" : "Pi Cookbook", "price" : 19.95}
     ]}'

j = json.loads(s)
print(j['books'][1]['title'])

As with all the program examples in this book, you can also download this program (see Recipe 3.22). The file is called ch_07_parse_json.py.

I have split the JSON string onto multiple lines in the previous example to make it easier to see the structure of the data.

The loads (load string) function parses the string into a data structure stored in the variable j. You can then access the contents of the structure as if it were a combination of Python lists and tables. In this case, the title of element 1 of the books list is printed (Pi Cookbook).

Discussion

If you want to parse the content of a file containing JSON data, you could use Recipe 7.8 to read the file into a string and then use the method just shown. However, it is more efficient, especially for large files, to use the json load (note that it’s load, not loads) directly on the file.

For example, you could create a file called ch_07_example_file.json that contains the following JSON:

{"books" : [
    {"title" : "Programnming Arduino", "price" : 10.95},
    {"title" : "Pi Cookbook", "price" : 19.95}
]}

The following code would read the file and parse it, producing the same result as the first example in this recipe, but the codefetches its JSON from a file (you can find this example in the file ch_07_parse_json_file.py):

import json

file_name = 'ch_07_example_file.json'
json_file = open(file_name)

j = json.load(json_file)
json_file.close()

print(j['books'][1]['title'])

The final example in this recipe deals with parsing data from a web request. Most web service APIs have a JSON interface. The following example uses the APIXU weather service. To use this service, you will need to sign up for an account (a free one will do) at https://www.apixu.com:

import json
import urllib.request

key = 'paste_your_key_here'

response = urllib.request.urlopen('http://api.apixu.com/v1/current.json?key='
                                 + key + '&q=Paris')
j = json.load(response)

print(j['current']['condition']['text'])

When you run the program (ch_07_parse_json_url.py), you should see something like this:

$ python3 ch_07_parse_json_url.py
Partly cloudy

The API actually returns a lot of data. You can see it all if you change the program to include a final line print(j). You can then change how you navigate into the data to get the information you want.

See Also

For reading and writing files, see Recipe 7.8 and Recipe 7.7.

7.22 Creating User Interfaces

Problem

You want to easily create a graphical user interface (GUI) for your Python app.

Solution

Use guizero. Laura Sach and Martin O’Hanlon at the Raspberry Pi Foundation have created a Python library that makes it super easy to design GUIs for your projects.

Originally designed for the Raspberry Pi, guizero is also perfectly happy on most environments that run Python, so you can use it on your PC or Mac as well as on your Raspberry Pi. To install guizero, run the following command from the Terminal:

$ sudo pip3 install guizero

Once installation is complete, you can try out guizero using the example program ch_07_guizero.py that is included with the book downloads (Recipe 3.22):

from guizero import *

def say_hello():
    info("An Alert", "Please don't press this button again")

app = App(title="Pi Cookbook Example", height=200)
button = PushButton(app, text="Don't Press Me", command=say_hello)

app.display()

When you run the program using the following command, a window with a button on it opens on your screen. If you click on the button, an alert message appears (Figure 7-3):

$ python3 ch_07_guizero.py

Figure 7-3. A guizero example program

This example shows how easy it is to hoo a Python function up to a button so that when the button is clicked, the function is run.

The function (say_hello) is defined first in the program. Then a new variable, app, is defined and initialized to be an instance of the class App, with some parameters that specify a title to appear at the top of the window and the window’s height in pixels. Both parameters are optional, and many other available options are defined in the documentation for guizero.

This app variable is then supplied as the first of the parameters to the PushButton that is created on the next line. The button uses the command parameter to specify the function to be run when the button is clicked. Note that when you specify the function to run, you do not put () after it because you are referring to the function, not calling it.

Discussion

This is an introductory example of guizero, just to get you started. The library is by no means just limited to buttons on a screen. The main goal of the library is to allow you to create simple user interfaces with a minimal amount of programming. When you want to start making things a bit more fancy, you can delve into various ways of laying out the widgets (buttons, checkboxes, sliders, etc.) in your window, and changing font sizes and colors. However, as always, start by keeping it simple.

See Also

For full information on guizero, see the excellent documentation at this guizero GitHub site.

guizero is also used in the following recipes: Recipe 10.8, Recipe 10.9, Recipe 10.10.

7.23 Using Regular Expressions to Search for Patterns in Text

Problem

You want to do a complex search, looking for something in a piece of text.

Solution

Use Python’s regular expression (regex) feature. Regular expressions have been around since the early days of computer science, when computer science was a branch of mathematics and benefited from the rigor of the mathematician’s mind.

A regular expression is a way of describing a pattern that occurs in some text. This is similar to Recipe 5.14. However, with regular expressions you can find more flexible wild-card matches, as shown here:

import re

text = "looking forward to finding the word for"
x = re.search("(^|\s)for($|\s)", text)

print(x.span())

As with all the program examples in this book, you can also download this program (see Recipe 3.22).

If you run this program (called ch_07_regex_find.py), you will get the following output:

$ python3 ch_07_regex_find.py
(35, 39)

This indicates that the word for has been found at character position 35 (actually the space before for) in the string. The second value is the end position index. Let’s take a look at how this code works. Notice that the program has ignored the word forward.

First we need to import the re (regular expression) module. Next, we add the variable text that contains the test string that we are going to search within.

We then use the search function to find what we want in the string. The first parameter is the regular expression, and the second is the string to search. In this case, the regular expression is the following string:

"(^|\s)for($|\s)"

Right in the middle of the regular expression is the word for. That’s to be expected, as that’s what we are looking for. To either side of it are expressions in parentheses. Before it we have this:

(^|\s)

The three magic symbols are ^, which means the start of the string; |, which means or; and \s, which means any whitespace character (space or tab). So you can read this section as matching either the start of the string or some whitespace before trying to match for. This ensures that the regular expression does not match words that end in for. That is, for must either come at the start of the string or be preceeded by a space or some other whitespace character.

There is a similar expression after for that must also match:

($|\s)

Here, the new special symbol is $, which indicates the end of the string. In other words, after the letters for, a match will occur only if we are at the end of the string or if there is a space or other whitespace character.

Table 7-2 shows some of the most common regular expression symbols. You can find a complete list on this W3Schools.com page.

Table 7-2. Common regular expression symbols

Special symbol | Meaning
. | Matches any single character.
^ | Matches the beginning of the string.
$ | Matches the end of the string.
\d | Any digit.
\s | Whitespace.
\w | Alphanumeric (digits and uppercase and lowercase letters).
* | Zero or more occurrences of whatever follows it. For example, *\d will match a string of zero or more digits.
+ | One or more occurrences of whatever follows it.
[] | Will match any of the characters it contains. You can also do ranges, such as [a-d]. which will match any of the characters a to d.

The best way to become familiar with regular expressions is to play with an online regular expression tester.

Discussion

It can be tricky tuning a regular expression so that it works just right. An online regular expression tool like the one at https://pythex.org (Figure 7-4) can be a big help in learning how to properly structure and test a regular expression.

The online tester has an area where you can write your regular expression and a test string area where you can put the text that you want to use with your regular expression. The tool then highlights what has matched. In Figure 7-4, the tool has correctly highlighted the word for.

Figure 7-4. The pythex online regular expression tester

See Also

To replace the text you have matched, see Recipe 7.24.

For more details about regular expressions in Python, see this W3Schools.com page on the subject.

7.24 Using Regular Expressions to Validate Data Entry

Problem

You have some text that you want to validate; for example, you want to make sure that the text looks like an email address.

Solution

Use a regular expression (Recipe 7.23).

Regular expressions are mainly used to validate information entered by a user. For example, if you have ever completed an online form that includes your email address, and you typed in something that didn’t look like an email address, the message you received saying that the address wasn’t a valid format probably came from a regular expression validation.

Try out the code in the file ch_07_regex_email.py (all program examples in this book are available for download; see Recipe 3.22):

import re

regex = '^[\w_\.+-]+@[\w_\.-]+\.[\w_-]+$'
while True:
    text = input("Enter an email address: ")
    if re.search(regex, text):
        print("valid")
    else:
        print("invalid")

This program will repeatedly prompt you to enter an email address and then report whether it is valid. An online search will uncover alternative regular expressions for email and for pretty much any other type of validation.

This one looks for one or more alphanumerics (plus _ . + or -), followed by an @ followed by a repeat of that sequence, followed by the sequence again but without a period in the string, which makes sure that the email doesn’t end in a period.

Discussion

If you have a particular validation in mind (for example, a phone number or website), someone will almost certainly have made a regular expression for it. So before writing your own, do an internet search. There is no point in reinventing the wheel.

See Also

For the basics on regular expressions, see Recipe 7.23.

7.25 Using Regular Expressions for Web Scraping

Problem

You want to write a Python program that automatically fetches (scrapes) information from a web page.

Solution

Use regular expressions to match text in the page’s HTML.

Regular expressions are very useful for web scraping. Web scraping means automatically reading things from a web page’s HTML. For example, if I want a Python program to automatically give me the current Amazon ranking of this book, I need to be able to grab the number from the Amazon sales rank (circled in Figure 7-5).

Figure 7-5. Web scraping from Amazon

If I click View Source in my browser and then search for “Sales Rank,” I can find the relevant piece of HTML, which looks like this:

<li id="SalesRank">
<b>Amazon Best Sellers Rank:</b>
#746,779 in Books (<a href="https://www.amazon.com/best-sellers-books-Amazon/zgbs/
books/ref=pd_dp_ts_books_1">See Top 100 in Books</a>)

I can use this as my test text in an online regular expression tester and work on an expression that will extract the Amazon rank. We can assume that this will be everything between # and in Books.

Here is the code for this, which you can also find in the downloads for the book (Recipe 3.22) in the file ch_07_regex_scraping.py:

import re
import urllib.request

regex = '#([\d,]+) in Books'
url = 'https://www.amazon.com/Raspberry-Pi-Cookbook-Software-Solutions/dp/1492043222/'

print("The Amazon rank is.....")
text = urllib.request.urlopen(url).read().decode('utf-8')
print(re.search(regex, text).group())

The output of the file will look something like this:

$ python3 test.py
The Amazon rank is.....
#746,779 in Books

The code first reads the web page contents. The text must then be converted to UTF-8 format (Latin alphabet only) before it can be used with the re regular expression module.

Discussion

Many websites offer APIs (see Recipe 7.21). If the information you’re trying to scrape is available through an API, then that is a much better way of getting it—not least because web scraping is very dependent on the appearance and wording of the page, which means that if the site is revamped, you’ll probably need to come up with a new regular expression.

See Also

To read the contents of a web page, see Recipe 7.13.

For the basics on regular expressions, see Recipe 7.23.

Chapter 8. Computer Vision

8.0 Introduction

Computer vision (CV) allows your Raspberry Pi to “see things.” In practical terms, this means that your Raspberry Pi can analyze an image, looking for items of interest, and can even recognize faces and text.

If you link this with a camera to supply the images, all sorts of possibilities open up.

8.1 Installing SimpleCV

Problem

You want to install SimpleCV computer vision software on your Raspberry Pi.

Solution

To install SimpleCV, first install the prerequisite packages using these commands:

$ sudo apt-get update
$ sudo apt-get install ipython python-opencv python-scipy
$ sudo apt-get install python-numpy python-setuptools python-pip
$ sudo pip install svgwrite

Then install SimpleCV itself using these commands:

$ sudo pip install https://github.com/sightmachine/SimpleCV/zipball/master
  --no-cache-dir
$ pip install 'IPython==4' --force-reinstall

After installation is complete, you can check that everything is working by running this command:

$ simplecv
+-----------------------------------------------------------+
 SimpleCV 1.3.0 [interactive shell] - http://simplecv.org
+-----------------------------------------------------------+
Commands:
    "exit()" or press "Ctrl+ D" to exit the shell
    "clear()" to clear the shell screen
    "tutorial()" to begin the SimpleCV interactive tutorial
    "example()" gives a list of examples you can run
    "forums()" will launch a web browser for the help forums
    "walkthrough()" will launch a web browser with a walkthrough

This opens the SimpleCV console. This is a Python console, with extra features for SimpleCV. To exit this console, enter the command exit().

Discussion

SimpleCV is a Python wrapper around the OpenCV computer vision software. SimpleCV, as the name suggests, simplifies the use of OpenCV. If you want to unleash the full power of OpenCV, take a look at http://opencv.org.

Computer vision is both processor and memory intensive, so although SimpleCV and OpenCV will work on an older Raspberry Pi, they can be frustratingly slow on anything earlier than a Raspberry Pi 2.

See Also

For information on OpenCV, see http://opencv.org.

The home page for the SimpleCV project is http://simplecv.org.

The first recipe in this chapter to use SimpleCV is Recipe 8.4. There you will find useful details for getting started with SimpleCV.

8.2 Setting Up a USB Camera for Computer Vision

Problem

You want to set up a USB webcam for use in computer vision (CV) projects.

Solution

Use a USB webcam that is compatible with the Raspberry Pi (see https://oreil.ly/wrI0U). Choose a good-quality camera. If you are working on a project for which you need the camera close to the subject, select one that has a manual focus option. For getting really close to the subject, a low-cost USB endoscope can be useful.

Depending on your CV project, you might want to set up a well-lighted area. Figure 8-1 shows a simple light box made from a translucent plastic storage box that is illuminated from the sides and top to give even lighting. The webcam is attached to a hole in the top of the box. This arrangement is used in Recipe 8.4.

Figure 8-1. Using a homemade “light box” for even illumination

You can also buy commercial light tents, designed for photography, that work well.

You might need a little trial and error to get your system brightly and evenly illuminated. Shadows can be particularly problematic.

Discussion

You can test out your USB camera from the SimpleCV console. Start SimpleCV and then enter the commands shown in the following in bold:

SimpleCV:1> c = Camera()
VIDIOC_QUERYMENU: Invalid argument
VIDIOC_QUERYMENU: Invalid argument
VIDIOC_QUERYMENU: Invalid argument
VIDIOC_QUERYMENU: Invalid argument
VIDIOC_QUERYMENU: Invalid argument
VIDIOC_QUERYMENU: Invalid argument
VIDIOC_QUERYMENU: Invalid argument

SimpleCV:2> i = c.getImage()
SimpleCV:3> i
SimpleCV:3: <SimpleCV.Image Object size:(640, 480), filename: (None),
at memory location: (0x2381af8)>
SimpleCV:4> i.show()

Don’t worry about the Invalid argument messages.

When you issue the command i.show(), a second window opens, showing the image just captured by the camera.

If you get errors indicating that SimpleCV cannot find a camera connected to your computer, the most likely reason is either that the USB webcam is not compatible with Raspbian or that you have the motion software running from Recipe 4.3. To stop motion, run the following command:

$ sudo /etc/init.d/motion stop

Although you can use the Raspberry Pi Camera Module (Recipe 8.3) with SimpleCV, it has a very short lead to the Raspberry Pi, and you will probably find that you prefer working with a USB webcam.

See Also

To use a Raspberry Pi Camera Module with SimpleCV, see Recipe 8.3.

8.3 Using a Raspberry Pi Camera Module for Computer Vision

Problem

You want to use a Raspberry Pi Camera Module that connects directly to your Raspberry Pi with SimpleCV.

Solution

The Raspberry Pi Camera Module should automatically show up as a camera device once you have followed Recipe 1.17 to install the camera module.

Discussion

Note that in early versions of Raspbian, you had to install a driver to make the camera module available to SimpleCV; if SimpleCV does not detect the camera module, try updating your version of Raspbian to the latest version (Recipe 3.40).

See Also

See Recipe 1.17 for information on installing the Raspberry Pi Camera Module.

See http://picamera.readthedocs.org/ for information on the picamera Python module.

To use a USB camera with SimpleCV, see Recipe 8.2.

8.4 Counting Coins

Problem

You want to use computer vision to count the number of coins in your webcam’s view.

Solution

Use SimpleCV and its findCircle function to provide a real-time count of the number of coins placed within view of the webcam.

This is one use of CV for which you really need good lighting and a camera fixed in position. I used the setup shown in Figure 8-1.

Before writing a Python program that will simply tell you the number of coins your Raspberry Pi can see, you need to experiment with the SimpleCV console to get the parameters for circle recognition accurate.

Start SimpleCV by using the command simplecv and then enter the following commands to start the camera, capture an image, and then display it in a separate window:

SimpleCV:1> c = Camera()
SimpleCV:2> i = c.getImage()
SimpleCV:3> i.show()

This should open up an image of your coins that looks something like Figure 8-2.

Circle detection needs the image to be inverted, or you can use a black background. To invert the image and then display it, run the following commands:

SimpleCV:4> i2 = i.invert()
SimpleCV:5> i2.show()

This command makes an inverted copy of i that looks like Figure 8-3.

Figure 8-2. A basic image of some coins

Figure 8-3. An inverted image of some coins

Your image is now prepared, so the next step is to have SimpleCV search for circles using the findCircle command. This command takes three parameters that you will need to tune to prevent misidentification:

canny

This is the threshold for edge detection. In CV terms, an edge is the line between significant changes in the image pixel colors. The default for this parameter is 100: if you decrease this value, you will find more edges. However, this might not result in more circles being found, because those extra edges might corrupt the good circle shapes. In the case of a coin, the edges could be writing or graphics on the coin.

thresh

Having found edges, the circle detection then needs to decide which are strong enough to represent the circles. Decreasing this value will result in more circles being found.

distance

This parameter sets the required gap (in pixels) between adjacent circles.

Run the following command to find some circles:

SimpleCV:6> coins = i2.findCircle(canny=100, thresh=70, distance=15)
SimpleCV:7> coins
 SimpleCV.Features.Detection.Circle at (237,297),
 SimpleCV.Features.Detection.Circle at (307,323),
 SimpleCV.Features.Detection.Circle at (373,305),
 SimpleCV.Features.Detection.Circle at (305,261),
 SimpleCV.Features.Detection.Circle at (385,253),
 SimpleCV.Features.Detection.Circle at (243,231),
 SimpleCV.Features.Detection.Circle at (307,383),
 SimpleCV.Features.Detection.Circle at (407,371),
 SimpleCV.Features.Detection.Circle at (235,373)]

If you don’t get any coins back, try decreasing the canny and thresh parameters. If you get too many back, increase thresh. We can check that SimpleCV is actually finding coins by superimposing the coin circles onto the original image using the following command:

SimpleCV:8> coins.draw(width=4)
SimpleCV:9> coins.show()

This shows the circles superimposed on the actual coins (Figure 8-4).

Figure 8-4. Coins found!

Try moving the coins around and adding and removing coins before capturing another photo and repeating the steps above to make sure things are reliable. You can tweak the parameters until you get the results you want.

We can bundle the commands that we used in the SimpleCV console into a Python program that will (as fast as the Raspberry Pi can) print out the number of coins detected.

You can find the code for this example as well as the other examples in this recipe with the downloads for the book (see Recipe 3.22). The program is called ch_08_coin_count.py.

Note that this is a Python 2 program, so run it by using the python command, not python3:

from SimpleCV import *

c = Camera()

while True:
    i = c.getImage().invert()
    coins = i.findCircle(canny=100, thresh=70, distance=1)
    print(len(coins))

After the SimpleCV library has been imported, the commands are the same as the ones you typed into the console. The only difference is that rather than displaying the coins, the len function is used to display the count:

$ sudo python ch_08_coin_count.py
9
9
9
10
10

Try adding a coin and moving the coins around to see how well the project works.

Discussion

After the initial delay while the library loads and the camera is set up, I found I could get about two “countings” per second using a Raspberry Pi B+. Using a Raspberry Pi 2, this increased to about five readings per second. A Raspberry Pi 4 is likely to be twice as fast again (or more).

Although not something that you would want to put into a vending machine, an interesting project would be to use the diameter of the coins to identify their monetary value and add up the value of the coins on the table.

You can access the diameter by using the diameter method on one of the coins, like this:

SimpleCV:10> coins[0].diameter()
SimpleCV:11> 60

See Also

For information on installing SimpleCV, see Recipe 8.1.

For information on setting up a camera, see Recipe 8.2.

8.5 Face Detection

Problem

You want to find the coordinates of faces in a photograph or webcam image.

Solution

Use the HAAR-like feature detection in SimpleCV to analyze an image and pick out the faces. HAAR actually stands for High Altitude Aerial Reconnaissance, and we are using some of the features developed for that application here.

If you have not already done so, install SimpleCV (see Recipe 8.1). Open the SimpleCV console and load an image containing faces. You will find a suitable file called faces.jpg in the Python section of the book downloads (see Recipe 3.22). Then run the following commands:

SimpleCV:1> i=Image("faces.jpg")
SimpleCV:2> faces = i.findHaarFeatures('face.xml', min_neighbors=5)
SimpleCV:3> faces.draw(width=4)
SimpleCV:4> i.show()

Note that the faces.jpg file (or whatever image file you use) must be in the same directory as the directory from which you started SimpleCV.

This opens the image viewing window with the faces marked with rectangles, as shown in Figure 8-5.

Discussion

As well as interfacing with a camera, you can also load existing files into SimpleCV. In the previous example, the image i is loaded from the file faces.jpg. The method findHaarFeatures has one mandatory file, which is the type of feature that is being searched for. These features are called haar features and are described by an XML file. SimpleCV comes preloaded with some of these files, but you can also find more specific haar files on the internet.

The second parameter used in this example (min_neighbors) will tune the haar function. Decreasing min_neighbors increases the number of false positives. When you see the false positives, they often have a face-like element to them (mouth, nose, and eyes).

There are many built-in haar features. You can list them all by using the following command:

SimpleCV:3> i.listHaarFeature()
SimpleCV:4> 'fullbody.xml', 'face4.xml', 'face.xml',
'upper_body.xml', 'right_ear.xml', 'eye.xml', 'lower_body.xml',
'two_eyes_small.xml', 'nose.xml', 'face2.xml', 'left_eye.xml',
'right_eye.xml', 'two_eyes_big.xml', 'face3.xml', 'mouth.xml',
'glasses.xml', 'profile.xml', 'left_ear.xml', 'left_eye2.xml',
'upper_body2.xml', 'right_eye2.xml', 'face_cv2.xml'

As you can see, they are all associated with parts of the body.

Finding haar features takes a few seconds, even on a Raspberry Pi 4.

Figure 8-5. Detecting faces

See Also

For information on installing SimpleCV, see Recipe 8.1.

For information on setting up a camera, see Recipe 8.2.

For a trove of interesting haar files, take a look at https://oreil.ly/8LZJr.

8.6 Motion Detection

Problem

You want to use a camera connected to your Raspberry Pi to detect something moving in its field of view.

Solution

Use SimpleCV to detect changes between successive frames from the camera.

The program below compares each captured image with the previous image. It then detects any blobs (areas of similar color) in the difference image, and if there are any larger than MIN_BLOB_SIZE, it prints out a message saying that movement was detected.

You can find the code for this example as well as for the other examples in this recipe with the downloads for the book (see Recipe 3.22). The program is called ch_08_detect_motion.py.

Note that this is a Python 2 program, so run it by using the python command, not python3:

from SimpleCV import *

MIN_BLOB_SIZE = 1000

c = Camera()

old_image = c.getImage()

while True:
    new_image = c.getImage()
    diff = new_image - old_image
    blobs = diff.findBlobs(minsize=MIN_BLOB_SIZE)
    if blobs :
        print("Movement detected")
    old_image = new_image

Discussion

Successive frames of the image might look like Figures 8-6 and 8-7. When the first image is subtracted from the second, the resulting image will look like Figure 8-8. Running blob detection on it will result in the outlined blobs shown in Figure 8-9.

Using a Raspberry Pi 4, the motion detection program will process about ten frames per second.

Figure 8-6. Movement detection frame 1

Figure 8-7. Movement detection frame 2

Figure 8-8. Movement detection, the difference image

Figure 8-9. Movement detection blobs

See Also

For information on installing SimpleCV, see Recipe 8.1. For information on setting up a camera, see Recipe 8.2.

An alternative way to detect movement is to use a Passive Infrared (PIR) sensor; see Recipe 12.9.

8.7 Optical Character Recognition

Problem

You want to be able to convert an image containing text to actual text.

Solution

Use the tesseract Optical Character Recognition (OCR) software to extract text from the image. To install tesseract, run the following commands (you will probably want to copy and paste this from the file long_commands.txt in the book downloads [Recipe 3.22]):

$ sudo apt install tesseract-ocr
$ sudo apt install libtesseract-dev

To try out tesseract, you will need an image file that contains some text. You will find one called ocr_example.tiff with the downloads for the book (see Recipe 3.22). To convert the image to text, run the following command:

$ cd /home/pi/raspberrypi_cookbook_ed3
$ tesseract ocr_test.tiff stdout
Page 1
This is an image

of some text.

If you take a look at the image file ocr_test.tiff, you will see that it is indeed an image containing those words.

Discussion

Although I used a TIFF image, the tesseract library will work with most image types, including PDF, PNG, and JPEG files.

See Also

For more information on the tesseract library, see https://oreil.ly/8EWzZ.

Chapter 9. Hardware Basics

9.0 Introduction

This chapter contains some basic recipes for setting up and using the Raspberry Pi’s general-purpose input/output (GPIO) connector. This connector allows you to connect all sorts of interesting electronics to your Raspberry Pi.

9.1 Finding Your Way Around the GPIO Connector

Problem

You need to connect electronics to the GPIO connector, but first you need to know more about what all the pins do.

Solution

There have actually been three versions of the Raspberry Pi GPIO connector: two 26-pin layouts for the original Raspberry Pi, and one 40-pin layout that came in with the Raspberry Pi “+” models and has been in use ever since.

Figure 9-1 shows the current 40-pin layout, which is the same for all 40-pin GPIO Raspberry Pi models right up to the Raspberry Pi 4.

The top 26 pins are the same as the 26 pins of the original Raspberry Pi model B revision 2. This allows the 40-pin Raspberry Pi models to use hardware and software designed for the earlier 26-pin Raspberry Pi designs. The extra pins of the 40-pin connector are made up of three useful extra GND connections and nine GPIO pins. The ID_SD and ID_SC pins are intended for use in communicating with a special serial memory chip, which can be included on interface boards that conform to the Hardware Attached on Top (HAT) standard and allows the Raspberry Pi to identify the board (see the Discussion section, next).

Figure 9-1. The GPIO pinout (40-pin models)

At the top of the connector, there are 3.3V and 5V power supplies. The GPIO uses 3.3V for all inputs and outputs. Any pin with a number next to it can act as a GPIO pin. Those that have another name after the number also have some other special purpose: 14 TXD and 15 RXD are the transmit and receive pins of the Serial interface; 2 SDA and 3 SCL form the I2C interface; and 10 MOSI, 9 MISO, and 11 SCKL form the SPI interface.

Discussion

Working out which pin is which on a Raspberry Pi is quite error prone if you rely on counting down the pin connector to find the pin you need. A better way of finding the correct pin is to use a GPIO template like the Raspberry Leaf shown in Figure 9-2.

This template fits over the GPIO pins, indicating which pin is which. Other GPIO templates include the Pi GPIO Reference Board.

The HAT standard is an interface standard that you can use with the Raspberry Pi 4, 3, 2, B+, A+, and Zero. This standard does not in any way stop you from just using GPIO pins directly; however, interface boards that conform to the HAT standard can call themselves HATs and differ from regular Raspberry Pi interface boards in that a HAT must contain a little Electrically Erasable Programmable Read-Only Memory (EEPROM) chip that is used to identify the HAT so that ultimately the Raspberry Pi can autoinstall necessary software. As of this writing, HATs have not quite met that level of sophistication, but the idea is a good one. The pins ID_SD and ID_SC are used to communicate with a HAT EEPROM.

See Also

The Raspberry Pi GPIO connector has only digital inputs and outputs; it does not have the analog inputs found on some similar boards. You can get around this short-coming by using a separate analog-to-digital converter (ADC) chip (Recipe 13.6) or by using resistive sensors (Recipe 13.1).

For an example of a HAT, see the Sense HAT described in Recipe 9.16.

Figure 9-2. The Raspberry Leaf GPIO template

9.2 Keeping Your Raspberry Pi Safe When Using the GPIO Connector

Problem

You want to connect external electronics to your Raspberry Pi but don’t want to accidentally damage or break it.

Solution

Obey these simple rules to reduce the risk of damaging your Raspberry Pi when using the GPIO connector:

Do not poke at the GPIO connector with a screwdriver or any metal object when the Pi is powered up.

Do not power the Pi with more than 5V.

Always connect the Raspberry Pi GND pin to the GND connection of whatever device you are attaching.

Do not put more than 3.3V on any GPIO pin being used as an input.

Do not draw more than 16mA per output; keep the total for all outputs below 50mA for an older 26-pin Raspberry Pi, and below 100mA on a 40-pin Raspberry Pi.

When using LEDs, 3mA is enough to light a red LED reasonably brightly with a 470Ω series resistor.

Do not draw more than a total of 250mA from the 5V supply pins.

Discussion

There is no doubt about it: the Raspberry Pi is a little fragile when it comes to adding external electronics. The newer Raspberry Pi models are a bit more robust but still quite easy to break. Exercise caution and check what you have done before you power up the Raspberry Pi, or you run the risk of having to replace it.

See Also

Read this very good discussion of the Raspberry Pi’s GPIO output capabilities.

9.3 Setting Up I2C

Problem

You have an Inter-Integrated Circuit (I2C) device that you want to use with your Raspberry Pi, but you don’t know how.

Solution

In the latest versions of Raspbian, enabling I2C is simply a matter of using the Raspberry Pi Configuration tool that you will find on the Main menu, under Preferences (Figure 9-3). On the Interfaces tab, select the Enabled button for I2C and then click OK. You are then prompted to restart.

Figure 9-3. Enabling I2C using the Pi Configuration tool

On older versions of Raspbian, or if you prefer the command line, the raspi-config tool does the same job.

Start raspi-config using the following command:

$ sudo raspi-config

Then, from the menu that appears, select Interfacing Options and scroll down to I2C (Figure 9-4).

Figure 9-4. Enabling I2C using raspi-config

You are then asked, “Would you like the ARM I2C interface to be enabled?” to which you should respond Yes. You will also be asked if you want the I2C module loading at startup, to which you should also respond Yes.

At this point, you will probably also want to install the Python I2C library by using this command:

$ sudo apt-get install python-smbus

You will then need to reboot the Raspberry Pi for the changes to take effect.

Discussion

Using I2C modules is actually a really good way of interfacing with the Pi. It reduces the number of wires that you need to connect everything (to just four), and there are some really neat I2C modules available.

However, don’t forget to calculate the total of the current used by the I2C modules and make sure that it doesn’t exceed the limits specified in Recipe 9.2.

Figure 9-5 shows a selection of I2C modules available from Adafruit. Other suppliers, such as SparkFun, also have I2C devices. From left to right in the figure, there are LED matrix displays; a four-digit, seven-segment LED display; a 16-channel PWM/servo controller; and a real-time clock module.

Figure 9-5. I2C modules

Other I2C modules include FM radio transmitters, ultrasonic rangefinders, OLED (Organic Light-Emitting Diode) displays, and various types of sensors.

See Also

See some of the I2C recipes in this book, including Recipes 11.3, 14.1, 14.2, and 14.4.

9.4 Using I2C Tools

Problem

You have an I2C device attached to your Raspberry Pi, and you want to confirm that it’s attached and find its I2C address.

Solution

Install and use i2c-tools.

Tip

On newer distributions, you might find that i2c-tools is already installed.

From a Terminal window on your Pi, type the following commands to fetch and install the i2c-tools:

$ sudo apt-get install i2c-tools

Attach your I2C device to the Pi and run the command:

$ sudo i2cdetect -y 1

Note that if you are using a very old Raspberry Pi revision 1 board, you need to change 1 to 0 in the preceding line of code.

If I2C is available, you will see some output like that shown in Figure 9-6, which indicates that two I2C addresses are in use—0x68 and 0x70.

Hexadecimal

Hexadecimal (or just hex) is a way of representing numbers using the number base 16 rather than the number base 10 that we use in everyday life.

In hexadecimal, each digit can have one of sixteen possible values. In addition to the familiar digit values of 0 to 9, hex uses the letters A to F; the letter A represents decimal 10, and F decimal 15.

There is no particular reason to use hex over decimal, except that in the unlikely event that you want to convert a number into binary, it’s much easier to do this from hex than from decimal.

To avoid confusion as to whether a number is being represented in decimal or hex, it is common to prefix hex numbers with 0x. In the preceding example, the hex number 0x68 is (in decimal) 6x16+8 = 104, and 0x70 is (in decimal) 7x16 = 112.

Figure 9-6. i2c-tools

Discussion

i2cDetect is a useful diagnostic tool and one that is worth running the first time you use a new I2C device.

See Also

See some of the I2C recipes in this book, including Recipes 11.3, 14.1, 14.2, and 14.4.

For more information on installing with apt-get, see Recipe 3.17.

9.5 Setting Up SPI

Problem

You have a Serial Peripheral Interface (SPI) bus that you want to use with your Raspberry Pi.

Solution

By default, Raspbian is not configured for the Raspberry Pi’s SPI interface to be enabled. To enable it, the procedure is almost the same as Recipe 9.3. On the Main menu, under Preferences, open the Raspberry Pi Configuration tool (Figure 9-7). Click the Interfaces tab, select the Enabled button for SPI, and click OK.

Figure 9-7. Enabling SPI using the Pi Configuration tool

On older versions of Raspbian, or if you prefer the command line, use the raspi-config command:

$ sudo raspi-config

Select Interfacing Options, followed by SPI, and then respond Yes before rebooting your Raspberry Pi. After the reboot, SPI will be available.

Discussion

SPI allows serial transfer of data between the Raspberry Pi and peripheral devices, such as ADC and port expander chips, among other devices.

You might come across some examples of interfacing to SPI that do not use the SPI interface but instead use an approach called bit banging, in which the RPi.GPIO library is used to interface with the four GPIO pins used by the SPI interface.

You can check that the SPI interface is working by using the following command:

$ ls /dev/*spi*
/dev/spidev0.0 /dev/spidev0.1

If instead of spidev0.0 and spidev0.1 being reported, nothing appears, it means that SPI is not enabled.

See Also

We use an SPI analog-to-digital converter chip in Recipe 13.6.

9.6 Installing PySerial for Access to the Serial Port from Python

Problem

You want to use the serial port (RXD and TXD pins) on the Raspberry Pi using Python.

Solution

First enable the serial port using Recipe 2.6.

Then, install the PySerial library:

$ sudo apt-get install python-serial

Discussion

The library is pretty easy to use. Create a connection by using the following syntax:

ser = serial.Serial(DEVICE, BAUD)

DEVICE is the device for the serial port (/dev/ttyS0) and BAUD is the baud rate as a number, not a string, as shown in the following example:

ser = serial.Serial('/dev/ttyS0', 9600)

After a connection is established, you can send data over serial like this:

ser.write('some text')

Listening for a response normally involves a loop that reads and prints, as illustrated in this example:

while True:
    print(ser.read())

See Also

You will need to use this technique in recipes that connect hardware to the serial port, such as Recipe 12.10.

9.7 Installing Minicom to Test the Serial Port

Problem

You want to send and receive serial commands from a Terminal session.

Solution

Install Minicom:

$ sudo apt-get install minicom

After Minicom is installed, you can start a serial communications session with a serial device connected to the RXD and TXD pins of the GPIO connector by using this command:

$ minicom -b 9600 -o -D /dev/ttyS0

The parameter after -b is the baud rate, and the parameter after -D is the serial port. Remember to use the same baud rate as the one on the device you are communicating with.

This will start a Minicom session. One of the first things you want to do is turn on local Echo so that you can see the command that you are typing. To do this, press Ctrl-A and then Z; you’ll see the command list shown in Figure 9-8. Press E to turn on local Echo.

Figure 9-8. Minicom commands

Now anything you type will be sent to the serial device, and all messages coming from the device will also be displayed.

Discussion

Minicom is a great tool for checking out the messages coming from a serial device or for making sure that it’s working.

See Also

Check out the Minicom documentation.

If you want to write a Python program to handle the serial communications, you will need the Python serial library (Recipe 9.6).

9.8 Using a Breadboard with Jumper Leads

Problem

You want to do some electronic prototyping using your Raspberry Pi and a solderless breadboard.

Solution

Use male-to-female jumper wires and a GPIO pin label template like the Raspberry Leaf (Figure 9-9).

Figure 9-9. Connecting Raspberry Pi to a breadboard using male-to-female jumper wires

Discussion

It’s not always easy to identify the pins that you want on a bare Raspberry Pi board. You can greatly simplify this by printing out a template, like the Raspberry Leaf, to fit over the pins.

It is also useful to have a selection of male-to-male jumper wires for making connections from one part of the breadboard to another.

Female-to-female jumper wires are useful for connecting modules with male header pins directly to the Raspberry Pi, when no other components might warrant the use of a breadboard.

A good way of getting a breadboard, Raspberry Leaf, and set of jumper wires is to buy a starter kit based around a breadboard, like the Electronics Starter Kit for Raspberry Pi from MonkMakes (see Appendix A).

See Also

We fully discuss an example of connecting an LED in Recipe 10.1.

9.9 Using a Breadboard with a Pi Cobbler

Problem

You want to do some electronic prototyping using a Raspberry Pi and a solderless breadboard.

Solution

Use an Adafruit Pi Cobbler, a device that consists of a small printed circuit board (PCB) with header pins that are designed to fit into a solderless breadboard like a dual inline (DIL) package chip. The pins are all labeled, and the PCB has a header socket. The supplied ribbon cable is used to link the Cobbler to the Raspberry Pi (see Figure 9-10).

The Pi Cobbler shown in Figure 9-10 is the 26-pin version of the product. There is also a 40-pin version designed for the newer Raspberry Pis, but this leaves little room on the breadboard for other components, so if you have enough GPIO pins for your project in the top 26 pins of the GPIO connector, it can sometimes be better to use the 26-pin version of the Pi Cobbler, even with a 40-pin Raspberry Pi.

Discussion

A great advantage of the Cobbler is that you can assemble the components onto the breadboard and then plug in the ribbon cable when it’s ready.

Make sure that the red edge of the ribbon cable is toward the SD-card edge of the Raspberry Pi. The cable only fits into the socket on the Pi Cobbler the correct way around.

After you have built your breadboard prototype, you might decide to make a soldered version of the prototype. A great way to do this is to use an Adafruit Perma-Proto board like the ones shown in Figure 9-11.

Figure 9-10. Connecting a Pi to a breadboard using a Pi Cobbler

Figure 9-11. Adafruit Perma-Proto boards

These boards are ready-made PCBs that have the same layout of tracks and holes as a breadboard. This allows you to transfer your breadboard design to the Perma-Proto board without having to redesign it. The board comes complete with a socket to accept the cable and plug of the Cobbler.

See Also

If you want to make a board that will fit directly onto the Raspberry Pi, see Recipe 9.19 and Recipe 9.20.

9.10 Using a Raspberry Squid

Problem

You want to connect an RGB LED to your Raspberry Pi without having to build something on a breadboard.

Solution

Use a Raspberry Squid RGB LED (Figure 9-12).

The Raspberry Squid is an RGB LED with built-in series resistors and female header leads; thus, it can be plugged directly onto the GPIO pins of a Raspberry Pi. The Squid has color-coded leads. The black lead goes to one of the GPIO GND pins, and the red, green, and blue leads go to GPIO pins used for the red, green, and blue channels. The red, green, and blue outputs can be simple digital outputs or pulse-width modulation (PWM) outputs (Recipe 10.3) that allow you to mix different colors.

You can find instructions for making your own Squid, but you can also buy a ready-made Squid.

The gpiozero Python library comes preinstalled on Raspbian and has support for RGB LEDs like the Squid.

Figure 9-12. The Raspberry Squid

As with all the program examples in this book, you can download this program (see Recipe 3.22). The file is called ch_09_squid_test.py. This program tells you pretty much all you need to know about using the Raspberry Squid:

from gpiozero import RGBLED
from time import sleep
from colorzero import Color

led = RGBLED(18, 23, 24)
led.color = Color('red')
sleep(2)
led.color = Color('green')
sleep(2)
led.color = Color('blue')
sleep(2)
led.color = Color('white')
sleep(2)

Having imported the various modules you need, you can create a new RGBLED object, supplying the three pins to be used for its red, green, and blue channels (in this case, 18, 23, and 24). You can then set the color by using the led.color = command, which expects a color.

The color is supplied using the Color class from the colorzero module. This allows you to specify a color by name, as we did here (most work), or by specifying the separate red, green, and blue color values. For example, the following would set the LED to red:

led.color = Color(255, 0, 0)

After the color is set, time.sleep(2) is used to create a two-second delay before the next color change.

Discussion

You do not need to use all three color channels of a Squid, and it can be quite handy to just check that a GPIO pin is turning on and off as you expect before attaching some other electronics to it.

See Also

For information on the Squid Button, see Recipe 9.11.

Recipe 10.10 is an example project that controls an RGB LED (Squid- or breadboard-based).

9.11 Using a Raspberry Squid Button

Problem

You want to connect a push switch to your Raspberry Pi without having to build something on a breadboard.

Solution

Use a Squid Button.

The Squid Button (Figure 9-13) is a push button with female header leads connected to the contacts so that you can plug it directly into the GPIO connector of a Raspberry Pi. The Squid Button also includes a low-value resistor that limits the current that would flow if the Squid Button were to be accidentally connected to a digital output rather than a digital input.

Figure 9-13. A Squid Button

You could use the Squid Button directly with the gpiozero library, as the following example shows. As with all the program examples in this book, you can download it (see Recipe 3.22). The file is called ch_09_button_test.py:

from gpiozero import Button
import time

button = Button(7)

while True:
    if button.is_pressed:
        print(time.time())

The number (in this case, 7) indicates the GPIO pin that the button is connected to. The other pin is connected to GND.

When the button is pressed, the timestamp in seconds is printed.

Discussion

The Squid Button is useful for testing projects that use a digital input, but because the button is suitable for panel mounting, you can also build it into more permanent projects.

See Also

For more information on using switches, see Recipes 12.1, 12.2, 12.3, 12.4, 12.5, and 12.6.

For information on the Squid RGB LED, see Recipe 9.10.

9.12 Converting 5V Signals to 3.3V with Two Resistors

Problem

The Raspberry Pi operates at 3.3V, but you want to know how to connect the 5V output of an external module to a GPIO pin on the Pi without damaging it.

Solution

Use a pair of resistors as a potential divider to reduce the output voltage. Figure 9-14 shows how you might use the 5V serial connection of an Arduino to a Raspberry Pi.

To make this recipe, you will need:

270Ω resistor (see “Resistors and Capacitors” in the Appendix)

470Ω resistor (see “Resistors and Capacitors” in the Appendix)

Figure 9-14. Using resistors to convert a 5V signal to 3.3V

The TXD signal from the Pi is a 3.3V output. This can be connected directly to a 5V input on the Arduino without any problem. The Arduino module will recognize anything over about 2.5V as being high.

The problem arises when you need to connect the 5V output of the Arduino module to the RXD pin of the Pi. You must not connect this directly to the RXD input—the 5V signal could damage the Pi. Instead, the two resistors shown in Figure 9-14 are used.

Discussion

The resistors used here will draw a current of 6mA. Given that the Pi uses a fairly hefty 500mA, this will not noticeably affect the current consumption of the Pi.

If you want to minimize the current used by the potential divider, use larger value resistors, scaled proportionally—for example, 27kΩ and 47kΩ, which will draw a miserly 60µA.

See Also

For more information on connecting Raspberry Pi to Arduino, see Chapter 18.

If you have multiple signals to convert between 3.3V and 5V, it’s probably best to use a multichannel level converter module—see Recipe 9.13.

9.13 Converting 5V Signals to 3.3V with a Level Converter Module

Problem

The Raspberry Pi operates at 3.3V. You want to connect a number of 5V digital pins to GPIO pins on the Pi without damaging it.

Solution

Use a bidirectional level converter module, such as the ones shown in Figure 9-15.

These modules are very easy to use. One side has the power supply at one voltage and a number of channels that can be either inputs or outputs at that voltage. The pins on the other side of the module have a power pin at the second voltage, and all the inputs and outputs on that side are automatically converted to the voltage level for that side.

Figure 9-15. Level converter modules

Discussion

These level converters are available with differing numbers of channels. The two shown in Figure 9-15 have four and eight channels.

You can find sources for such level converters in Appendix A.

See Also

See Recipe 9.12, especially if you have only one or two levels to convert.

Normally 5V logic inputs will accept 3.3V outputs without a problem; however, in some instances, such as when using LED strips (Recipe 14.6), this might not be the case, and thus you could use one of the just-described modules to raise the logic level.

9.14 Powering a Raspberry Pi with Batteries

Problem

You want to attach your Raspberry Pi to a robot and power it using alkaline batteries.

Solution

A typical project using a Raspberry Pi requires 5V at up to about 600mA (see Recipe 1.4). The requirement for 5V is strict. You should not try to power your Pi from more or less than 5V. In practice, this means you are most likely to use a battery at a higher voltage than 5V—say, 9V—and use a voltage regulator to drop the voltage to 5V.

The relatively high power requirement of the Pi makes it unsuitable for powering from a small 9V battery, for example, but a 9V battery pack made up of six AA cells and a voltage regulator would work fine.

Figure 9-16 shows how you can use a voltage regulator (in this case, a 7805) with a battery pack to power a Pi through the 5V pin on the GPIO connector. Note that the 9V battery symbol is a stand-in for a higher-capacity 9V battery pack such as a 6xAA battery holder.

Figure 9-16. Using a voltage regulator and 9V battery to power a Raspberry Pi

The 7805 voltage regulator will get pretty hot. If it becomes too hot, its thermal cutout will kick in and the voltage at its output will drop, probably causing the Pi to reset. A heatsink that clips onto the integrated circuit (IC) will help with this.

Discussion

The 7805 requires the input voltage to be at least 2V above 5V. You can also buy low dropout (LDO) regulators such as the LM2940. The LM2940 has the same pinout as the 7805 but requires the input to be only 0.5V above the 5V output. However, remember that, nominally, 1.5V AA cells soon drop to about 1.2V. So a pack of four of them is unlikely to provide enough voltage for more than a few minutes. A pack of six will be fine.

The preceding example uses a 9V battery pack, but if you want to fit your Raspberry Pi into an automobile or RV’s 12V supply, this recipe will still work. You will also need to use a small monitor that can be powered from direct current (DC). You can find such devices fairly easily because they are commonly used with closed-circuit camera systems.

See Also

Another way to power your Raspberry Pi from a battery is to use a USB battery bank. Make sure that it can cope with 1A or more.

Recipe 9.15 shows you how to power a Raspberry Pi from a LiPo battery pack.

You can also use a RasPiRobot Board to power your Raspberry Pi from batteries; see Recipe 9.18.

9.15 Powering a Raspberry Pi with a LiPo Battery

Problem

You want to attach your Raspberry Pi to a robot and power it from a 3.7V lithium-ion polymer (LiPo) battery.

Solution

Use a boost regulator module (Figure 9-17). The module shown is from SparkFun, but similar, less-expensive designs are available on eBay.

As always with such low-cost purchases from eBay, you should test the module thoroughly before using it. They do not always work exactly as advertised, and quality can be quite variable.

The advantage of this kind of module is that it acts as a voltage regulator to supply 5V to the Pi and also has a USB socket of its own to supply power to its charging circuit. If you plug the Pi’s power adapter into the socket on the charger, the Pi will be powered and the battery charged, allowing you to unplug the USB power and use the Pi on the battery for as long as it has enough power.

With a 1300mA LiPo battery, you can expect the Pi to be powered for two or three hours.

Figure 9-17. Powering a Raspberry Pi with a 3.7V LiPo battery

Discussion

If you plan to handle the charging of the battery elsewhere, you can just go for a boost converter module, without the charger, at a lower cost.

See Also

You can also find ready-made USB LiPo battery banks, often with a high-capacity LiPo battery, that will power your Pi for hours.

9.16 Getting Started with the Sense HAT

Problem

You want to know how to use a Raspberry Pi Sense HAT.

Solution

The Raspberry Pi Sense HAT (Figure 9-18) is a useful and somewhat confusingly named interface board for the Raspberry Pi. Yes, it includes sensors—in fact, it can measure temperature, relative humidity, and atmospheric pressure (Recipe 13.11). It also has an accelerometer, a gyroscope (Recipe 13.15), and a magnetometer (Recipe 13.14) for navigation-type projects. It also has a full-color 8×8 LED matrix display (Recipe 14.3).

Figure 9-18. The Raspberry Pi Sense HAT

The Sense HAT requires a Raspberry Pi with a 40-pin GPIO header, so you will not be able to use it on an older Raspberry Pi with a 26-pin header.

Put the Sense HAT onto your Raspberry Pi before powering it up.

Raspbian already includes all the software that you need for the Sense HAT. The Sense HAT uses I2C, so you need to follow the usual I2C setup (Recipe 9.3).

Discussion

There are more recipes that use the Sense HAT in this book, but for now, you can just check that everything is working by using the following to open a Python console:

$ sudo python3

Then enter the following commands into the Python console:

>>> from sense_hat import SenseHat
>>> hat = SenseHat()
>>> hat.show_message('Raspberry Pi Cookbook')

The LED matrix should then display the message Raspberry Pi Cookbook, scrolling it across the screen.

See Also

See the programming reference for the Sense HAT.

To measure temperature, humidity, and atmospheric pressure, see Recipe 13.11.

To use the Sense HAT’s accelerometer and gyroscope, see Recipe 13.15.

To use the magnetometer to detect north and detect the presence of a magnet, see Recipes 13.14 and 13.17, respectively.

9.17 Getting Started with the Explorer HAT Pro

Problem

You want to know how to get started with the Pimoroni Explorer HAT Pro.

Solution

Plug the HAT into your Raspberry Pi and install the explorerhat Pro Python library.

Figure 9-19 shows a Pimoroni Explorer HAT Pro on a Raspberry Pi B+. Note that this HAT works only on a 40-pin Raspberry Pi.

Figure 9-19. A Pimoroni Explorer HAT Pro

The Explorer HAT Pro has some useful input/output options as well as an area where a small solderless breadboard can be attached. Here are some of its features:

4 LEDs

4 buffered inputs

4 buffered outputs (up to 500mA)

4 analog inputs

2 low-power motor drivers (max 200mA)

4 capacitive touch pads

4 capacitive crocodile clip pads

The Python library for the Explorer HAT Pro is included in Raspbian.

Here’s a little experiment you can try that makes the built-in red LED blink. Open an editor and paste in the following code:

import explorerhat, time

while True:
    explorerhat.light.red.on()
    time.sleep(0.5)
    explorerhat.light.red.off()
    time.sleep(0.5)

As with all the program examples in this book, you can download this program (see Recipe 3.22). The file is called ch_09_explorer_hat_blink.py.

Discussion

The Explorer HAT Pro provides four buffered inputs and outputs—that is, inputs and outputs that are not connected directly to the Raspberry Pi but instead are connected to chips on the Explorer HAT Pro. This means that if you accidentally connect things incorrectly, the Explorer HAT Pro will be damaged rather than your Raspberry Pi.

See Also

You can use the Explorer HAT Pro for capacitive touch sensing (Recipe 13.20).

9.18 Getting Started with a RasPiRobot Board

Problem

You want to know how to use a RasPiRobot Board.

Solution

Figure 9-20 shows the MonkMakes RasPiRobot Board (version 4). The board has a dual-motor controller that can be used for two DC motors or a single stepper motor. It can supply 5V power to the Raspberry Pi by using its built-in switched-mode voltage regulator. The board has two switch inputs, and it provides easy connections to an HC-SR04 rangefinder and the I2C interfaces of the Raspberry Pi.

Figure 9-20. The RasPiRobot Board v4

The RasPiRobot Board v4 has its own Python library that you need to download and install by using the following commands:

$ git clone https://github.com/simonmonk/rrb4.git
$ cd rrb4/python
$ sudo python3 setup.py install

Discussion

Fit your RasPiRobot Board v4 onto your Raspberry Pi and then power up the Raspberry Pi. You can try out a few commands with the RasPiRobot Board using just the Python console without attaching external power or motors to the RasPiRobot Board:

$ sudo python3

When you first power up, you should find that both LEDs on the RasPiRobot Board will be lit. Now enter the following commands, and both LEDs should turn off as the library is initialized:

>>> from raspirobotboard import *
>>> rr = RRB4()

Try turning one of the LEDs on and off using these commands:

>>> rr.set_led1(1)
>>> rr.set_led1(0)

Other commands are available to set the motors (forward, reverse, left, right, and stop). For the full command reference, see https://github.com/simonmonk/rrb4.

See Also

To learn how to use this board to make a roving robot, see Recipe 11.10.

To use the RasPiRobot Board to control a bipolar stepper motor, see Recipe 11.9.

9.19 Using a Pi Plate Prototyping Board

Problem

You want to know how to use a Pi Plate prototyping board.

Solution

The Pi Plate (Figure 9-21) is a prototyping board rather than an interface board like the RasPiRobot Board (Recipe 9.18). In other words, it does not include any electronics—it is designed for you to solder your own components to a prototyping area.

The board has an area where you can use a 16-pin, surface-mount chip and a row of four holes, spaced more widely, where you can solder a screw terminal in place.

The board has screw terminals on two sides that are connected to all of the GPIO pins. You can ignore the prototyping area entirely and just use the screw terminals to attach wires to the GPIO pins.

Figure 9-21. The Pi Plate

Discussion

The board design has a grid of holes at a pitch of the standard 0.1 inch used by most through-hole components, including DIL ICs. You solder components to the board by pushing the leads through the holes at the top and soldering the connections underneath.

The tracks that connect the holes are clearly visible on the top of the board, and the board is divided into several zones. There is an area with central power busses intended for DIL ICs, as well as a general prototyping area and areas for a surface-mount chip and extra screw terminals.

Having soldered the components into place, you will need extra wires to link everything together. You can run these on the bottom or the top of the board, or on both if the design is complicated.

It’s a good idea to plan the layout before you start soldering.

In the following instructions, you will build an RGB LED onto a Pi Plate using the layout shown in Figure 9-22. This recipe is a version of Recipe 10.10, which is the same except that the design is built onto a solderless breadboard.

Figure 9-22. Board layout for an RGB LED on a Pi Plate

The first step is to solder the resistors into place. Bend the leads and push them through the appropriate holes in the board. Then flip the board over and touch the soldering iron to where the leads emerge from the holes for a second or so before applying the solder, which should flow around the leads (Figure 9-23).

Figure 9-23. Soldering a resistor to the Pi Plate

When you have soldered both ends, snip off the excess lead and repeat for the other two resistors (Figure 9-24).

Now solder the LED into place, taking care to get it facing the right way. The longest lead is the common cathode and should be the only LED lead attached to the strip of holes that is not connected to any resistor. Very occasionally, you will find an LED for which the longer lead is not the positive lead. This is often the case with infrared LEDs. If you aren’t sure, check the datasheet for the LED or the supplier’s information page.

Figure 9-24. Resistors soldered to the Pi Plate

You will also need to solder a short length of wire from that row to the GND connection on the Pi Plate (Figure 9-25).

Figure 9-25. Soldering the link wire to the Pi Plate

When the board is complete, it should look like Figure 9-26.

Figure 9-26. The finished RGB LED on a Pi Plate

You can try out the LED using the Python program from Recipe 10.10.

See Also

There is more information about this product at the Adafruit website.

9.20 Making a HAT

Problem

You want to create a prototype Raspberry Pi interface board that conforms to the HAT standard.

Solution

Use a Perma-Proto Pi HAT (Figure 9-27).

Figure 9-27. A Perma-Proto Pi HAT

With the advent of the Raspberry Pi B+ with a 40-pin GPIO header, a new standard for add-on boards for the Raspberry Pi was defined, called HAT (Hardware Attached on Top). You do not need to stick to this standard, especially if you are just making a one-off product for yourself, but if you are designing a product to sell, it might make sense for you to conform to the HAT standard.

The HAT standard defines the size and shape of the PCB and also mandates that the PCB has an Electrically Erasable Programmable Read-Only Memory (EEPROM) chip soldered onto the board. This chip is connected to the ID_SD and ID_SC pins of the GPIO header and in the future will allow some configuration of the Pi and even automatic loading of software to occur when the Raspberry Pi is booted up with a HAT attached.

The prototyping area of the board is made up of some power rails and a breadboard format layout of two rows of five holes plus power rails down both sides of the board.

If you don’t care about programming the EEPROM, you can stop here. However, if you want to add your own custom information onto the HAT’s EEPROM, read on to the Discussion, next.

Discussion

The HAT standard makes a lot of sense. However, as of this writing, Raspbian does not make use of any information written in the HAT’s EEPROM. This is likely to change in the future and leads to the exciting possibility of HATs automatically doing things like enabling I2C and installing Python libraries for their hardware, just by being present on the Raspberry Pi.

To write data into the EEPROM, you first need to enable the hidden I2C port used by the ID_SD and ID_SC pins that are used to read and write to the EEPROM. To do that, you will need to edit /boot/config.txt by adding in or uncommenting the following line:

dtparam=i2c_vc=on

After you do this, reboot your Raspberry Pi; you should then be able to detect that the I2C EEPROM is attached to the I2C bus using i2c tools (Recipe 9.4):

$ i2cdetect -y 0
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: 50 -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --

You can see from the result of the i2cdetect command that the EEPROM has an I2C address of 50. Note that the option -y 0 rather than the usual -y 1 is used because this is not the normal I2C bus on pins 2 and 3, but rather the I2C bus dedicated to the HAT EEPROM.

To read and write the EEPROM, you need to download some tools by using the following commands:

$ git clone https://github.com/raspberrypi/hats.git
$ cd hats/eepromutils
$ make

Writing the EEPROM is a three-step process. First, you must edit the file eeprom_settings.txt. Change at least the product_id, product_version, vendor, and product fields to be your company name and product name. Note that there are lots of other options in this file, which is well documented. They include specifying back-powering options, GPIO pins used, and so on.

Second, after editing the file, run the following command to convert the text file into a file suitable for writing to the EEPROM (rom_file.eep):

$ ./eepmake eeprom_settings.txt rom_file.eep
Opening file eeprom_settings.txt for read
UUID=7aa8b587-9c11-4177-bf14-00e601c5025e
Done reading
Writing out...
Done.

Finally, copy rom_file.eep onto the EEPROM by running the following command:

sudo ./eepflash.sh -w -f=rom_file.eep -t=24c32
This will disable the camera so you will need to REBOOT after this...
This will attempt to write to i2c address 0x50. Make sure there is...
This script comes with ABSOLUTELY no warranty. Continue only if you...
Do you wish to continue? (yes/no): yes
Writing...
0+1 records in
0+1 records out
127 bytes (127 B) copied, 2.52071 s, 0.1 kB/s
Done.
pi@raspberrypi ~/hats/eepromutils $

When writing is complete, you can read the ROM back using these commands:

$ sudo ./eepflash.sh -r -f=read_back.eep -t=24c32
$ ./eepdump read_back.eep read_back.txt
$ more read_back.txt

See Also

See the Raspberry Pi HAT design guide.

There are many ready-made HATs on the market, including the Stepper Motor (Recipe 11.8), Capacitive Touch (Recipe 13.20), and 16-Channel PWM (Recipe 11.1) HATs from Adafruit, as well as the Pimoroni Explorer HAT Pro (Recipe 9.17).

9.21 The Pi Zero and Pi Zero W

Problem

You want to learn more about the Pi Zero and Pi Zero W and how to make use of them in electronics projects.

Solution

The small size and extremely low cost of the Pi Zero make it the ideal choice for embedding in electronics projects. The Pi Zero W adds WiFi and Bluetooth capabilities to the Pi Zero, making it great for small Internet of Things (IoT) projects.

Figure 9-28 shows a Raspberry Pi Zero.

Figure 9-28. The Raspberry Pi Zero

The Pi Zero and Pi Zero W are supplied without header pins attached, so your first job is likely to be to solder pins to it. Suitable header pins are available in Pi Zero starter kits, such as the one supplied by Pi Hut.

It is also possible to buy the Pi Zero W with header pins presoldered, but that is more expensive than the DIY version.

You can also find so-called hammer pins that are tight fitting and do not require soldering.

Discussion

With only one USB connector—and a micro-USB OTG (on the go) connector at that—you will need a USB adapter and USB hub to be able to plug in a USB WiFi dongle, keyboard, and mouse in order to set up the Pi Zero.

These small Raspberry Pis lend themselves well to being set up as headless devices (Recipe 1.9) using PiBakery (Recipe 1.8).

Alternatively, you can use a console cable as described in Recipe 2.6 to set up WiFi by editing /etc/network/interfaces, as described in Recipe 2.5. After that is set up, you can connect to the Pi Zero wirelessly using Secure Shell (SSH) (Recipe 2.7).

See Also

For a comparison of the Raspberry Pi models available, see Recipe 1.1.

Chapter 10. Controlling Hardware

10.0 Introduction

In this chapter, you come to grips with the control of electronics through the Raspberry Pi’s general-purpose input/output (GPIO) connector.

Most of the recipes require the use of a solderless breadboard and male-to-female and male-to-male jumper wires (see Recipe 9.8). To maintain compatibility with older 26-pin Raspberry Pi models, all the breadboard examples here use only the top 26 pins common to both GPIO layouts (see Recipe 9.1).

10.1 Connecting an LED

Problem

You want to know how to connect an LED to the Raspberry Pi.

Solution

Connect an LED to one of the GPIO pins using a 470Ω or 1kΩ series resistor to limit the current. To make this recipe, you will need the following:

Breadboard and jumper wires (see “Prototyping Equipment and Kits”)

470Ω resistor (see “Resistors and Capacitors”)

LED (see “Opto-Electronics”)

Figure 10-1 shows how you can wire this LED using a solderless breadboard and male-to-female jumper leads.

Figure 10-1. Connecting an LED to a Raspberry Pi

Having connected the LED, we need to be able to turn it on and off using commands from Python.

Start a Python console from the Terminal and enter these commands:

$ sudo python3
>>> from gpiozero import LED
>>> led = LED(18)
>>> led.on()
>>> led.off()
>>>

This will turn your LED on after the led.on() command, and off again after the led.off() command.

Discussion

LEDs are a very useful, cheap, and efficient way of producing light, but you do have to be careful how you use them. If they are connected directly to a voltage source (such as a GPIO output) that is greater than about 1.7 volts, they will draw a very large current. This can often be enough to destroy the LED or whatever is providing the current—which is not good if your Raspberry Pi is providing the current.

You should always use a series resistor with an LED because the series resistor is placed between the LED and the voltage source, which limits the amount of current flowing through the LED to a level that is safe for both the LED and the GPIO pin driving it.

Raspberry Pi GPIO pins are guaranteed to provide only about 3mA or 16mA of current (depending on the board and number of pins in use)—see Recipe 9.2. LEDs will generally illuminate with any current greater than 1mA, but they will be brighter with more current. Use Table 10-1 as a guide to selecting a series resistor based on the type of LED; the table also indicates the approximate current that will be drawn from the GPIO pin.

Table 10-1. Selecting series resistors for LEDs and a 3.3V GPIO pin

LED type
Resistor
Current (mA)

Red

470Ω

3.5

Red

1kΩ

1.5

Orange, yellow, green

470Ω

2

Orange, yellow, green

1kΩ

1

Blue, white

100Ω

3

Blue, white

270Ω

1

As you can see, in all cases it is safe to use a 470Ω resistor. If you are using a blue or white LED, you can reduce the value of the series resistor considerably without risk of damaging your Raspberry Pi.

If you want to extend the experiments that you made in the Python console into a program that makes the LED blink on and off repeatedly, you could paste the code that you’ll find in ch_10_led_blink.py into an editor (as with all the program examples in this book, you can download this program [see Recipe 3.22]):

from gpiozero import LED
from time import sleep

led = LED(18)

while True:
    led.on()
    sleep(0.5)
    led.off()
    sleep(0.5)

To run the command, enter the following:

$ python3 ch_10_led_blink.py

The sleep period of 0.5 seconds between turning the LED on and turning it off again makes the LED blink once a second.

The LED class also has a built-in method for blinking, as illustrated by this example:

from gpiozero import LED

led = LED(18)
led.blink(0.5, 0.5, background=False)

The first two parameters to blink are the on time and off time, respectively. The optional background parameter is interesting because if you set this to True, your program will be able to continue running other commands in the background while the LED is blinking.

When you are ready to stop the LED blinking in the background, you can just use led.off(). This technique can greatly simplify your programs. The example in the file ch_10_led_blink_2.py shows this in action:

from gpiozero import LED

led = LED(18)
led.blink(0.5, 0.5, background=True)
print("Notice that control has moved away - hit Enter to continue")
input()
print("Control is now back")
led.off()
input()

When the program starts, the LED will be set blinking in the background and the program is free to move onto the next command and print Notice that control has moved away - hit Enter to continue. The input() command will cause the program to halt and wait for input (you can just press the Enter key). But notice that before you press Enter, the LED is still blinking even though the program has moved on to wait for input.

When you do press Enter again, the led.off() command stops the LED’s background blinking.

See Also

Check out this handy series resistor calculator.

For more information on using a breadboard and jumper wires with the Raspberry Pi, see Recipe 9.8.

See the gpiozero documentation on LEDs.

10.2 Leaving the GPIO Pins in a Safe State

Problem

You want all the GPIO pins to be set to inputs whenever your program exits so that there is less of a chance of an accidental short on the GPIO header, which could damage your Raspberry Pi.

Solution

Whenever you exit a program that uses gpiozero, it will automatically set all the GPIO pins into a safe input state.

Discussion

Earlier methods of accessing the GPIO pins such as the RPi.GPIO library did not automatically set the GPIO pins to be in a safe input state. Instead, they required you to call a cleanup function before exiting the program.

If cleanup was not called or the Pi was not rebooted, pins set to be outputs would remain as outputs after the program has finished. If you were to start wiring up a new project, unaware of this problem, your new circuit might accidentally short a GPIO output to one of the supply voltages or another GPIO pin in the opposite state. A typical scenario in which this might happen would be if you were to connect a push switch, connecting a GPIO pin that you had configured as an output and HIGH to GND.

Fortunately for us, the gpiozero library now takes care of this.

See Also

For more information on exception handling in Python, see Recipe 7.10.

10.3 Controlling the Brightness of an LED

Problem

You want to vary the brightness of an LED from a Python program.

Solution

The gpiozero library has a pulse-width modulation (PWM) feature that allows you to control the power to an LED and its brightness.

To try it out, connect an LED as described in Recipe 10.1 and run this test program (ch_10_led_brightness.py):

from gpiozero import PWMLED

led = PWMLED(18)

while True:
    brightness_s = input("Enter Brightness (0.0 to 1.0):")
    brightness = float(brightness_s)
    led.value = brightness

The program is included in the code download (see Recipe 3.22).

Run the Python program, and you will be able to change the brightness by entering a number between 0.0 (off) and 1.0 (full brightness):

$ python ch_10_led_brightness.py
Enter Brightness (0.0 to 1.0):0.5
Enter Brightness (0.0 to 1.0):1
Enter Brightness (0.0 to 1.0):0

Exit the program by pressing Ctrl-c. Ctrl-c is command line for stop what you are doing; in many situations, it will stop a program entirely.

Note that when controlling an LED’s brightness like this, you must define the LED as being PWMLED and not just LED.

Discussion

PWM is a clever technique by which you vary the length of pulses while keeping the overall number of pulses per second (the frequency in Hz) constant. Figure 10-2 illustrates the basic principle of PWM.

Figure 10-2. Pulse-width modulation

By default, the PWM frequency is 100Hz; that is, the LED flashes 100 times per second. You can change this where you define the PWMLED by supplying an optional parameter:

led = PWMLED(18, frequency=1000)

The value is in Hz, so in this case, the frequency is set to 1,000 Hz (1 kHz).

Table 10-2 compares frequencies specified in the parameter to the actual frequencies on the pin measured with an oscilloscope.

Table 10-2. Requested frequency against actual frequency

Requested frequency
Measured frequency

50 Hz

50 Hz

100 Hz

98.7 Hz

200 Hz

195 Hz

500 Hz

470 Hz

1 kHz

880 Hz

10 kHz

4.2 kHz

You can see that the frequency becomes less accurate as it increases. This means that this PWM feature is no good for audio but plenty fast enough for controlling the brightness of LEDs or the speed of motors. If you want to experiment with this yourself, the program is in the code download and called ch_10_pwm_f_test.py.

See Also

For more information on PWM, see Wikipedia.

Recipe 10.10 uses PWM to change the color of an RGB LED, and Recipe 11.4 uses PWM to control the speed of a DC motor.

For more information on using a breadboard and jumper wires with the Raspberry Pi, see Recipe 9.8. You can also control the brightness of the LED with a slider control—see Recipe 10.9.

10.4 Switching a High-Power DC Device Using a Transistor

Problem

You want to control the current to a high-power, low-voltage DC device such as a 12V LED module.

Solution

These high-power LEDs use far too much current to light directly from a GPIO pin. They also require 12V rather than the 3.3V. To control such a high-power load, you need to use a transistor.

In this case, you will use a high-power type of transistor called a metal–oxide–semiconductor field-effect transistor (MOSFET), which costs less than a dollar but can handle loads up to 30 amps—many times more than is required for the high-power LEDs. The MOSFET used is a FQP30N06L (see “Transistors and Diodes”).

Figure 10-3 shows how you can connect a MOSFET on a breadboard. Make sure that you correctly identify the positive and negative supply leads for the LED module.

Figure 10-3. Controlling large currents with a MOSFET

To make this recipe, you will need the following:

Breadboard and jumper wires (see “Prototyping Equipment and Kits”)

1kΩ resistor (see “Resistors and Capacitors”)

FQP30N06L N-Channel MOSFET or TIP120 Darlington transistor (see “Transistors and Diodes”)

12V power adapter

12V DC LED module

The Python code to turn the LED panel on and off is exactly the same as if we were controlling a single low-power LED without the MOSFET (see Recipe 10.1).

You can also use PWM with the MOSFET to control the brightness of the LED module (see Recipe 10.3).

Discussion

Whenever you need to power anything significant using the GPIO connector, use batteries or an external power adapter. The GPIO connector can supply only relatively low currents (Recipe 9.2). In this case, you’ll use a 12V DC power adapter to provide the power to the LED panel. Pick a power adapter that has sufficient power handling. Thus, if the LED module is 5W, you need at least a 12V 5W power supply (6W would be better). If the power supply specifies a maximum current rather than power, you can calculate its power by multiplying the voltage by the maximum current. For instance, a 500mA 12V power supply can provide 6W of power.

The resistor is necessary to ensure that the peak currents that occur as the MOSFET switches from off to on, and vice versa, do not overload the GPIO pin. The MOSFET switches the negative side of the LED panel, so the positive supply is connected directly to the positive side of the LED panel, and the negative side of the LED panel is connected to the drain of the MOSFET. The source connection of the MOSFET is connected to GND, and the MOSFET’s gate pin controls the flow of current from the drain to the source. If gate voltage is above 2V or so, the MOSFET will turn on, and current flows through both it and the LED module.

The MOSFET used here is an FQP30N06L. The L at the end means that it is a logic-level MOSFET whose gate threshold voltage is suitable for use with 3.3V digital outputs. The non-L version of this MOSFET is also likely to work just fine, but you cannot guarantee that it will, as the specified range of gate threshold voltages is 2V to 4V. Therefore, if you were unlucky and got a MOSFET at the 4V end, it would not switch well.

An alternative to using a MOSFET is to use a power Darlington transistor like the TIP120. This has a compatible pinout with the FQP30N06L, so you can keep the same breadboard layout.

This circuit is suitable for controlling the power to other low-voltage DC devices. The only real exceptions are motors and relays, which require some extra treatment (see Recipe 10.5).

See Also

Check out the datasheet for the MOSFET.

If you would like to create a graphical user interface with which to control your LED module, see Recipe 10.8 for simple on/off control, and Recipe 10.9 for variable control of the brightness with a slider.

10.5 Switching a High-Power Device Using a Relay

Problem

You want to turn devices on and off that might not be suitable for switching with a MOSFET.

Solution

Use a relay and small transistor.

Figure 10-4 shows how you can connect a transistor and relay on a breadboard. Make sure that both the transistor and diode are placed the right way. The diode has a stripe at one end, and the transistor used here has flat one side and one curved side.

To make this recipe, you will need the following:

Breadboard and jumper wires (see “Prototyping Equipment and Kits”)

1kΩ resistor (see “Resistors and Capacitors”)

Transistor 2N3904 (see “Transistors and Diodes”)

1N4001 diode (see “Transistors and Diodes”)

5V relay (see “Miscellaneous”)

Multimeter

You can use the same LED blink program that you used in Recipe 10.1. If all is well, you’ll hear a click from the relay and a beep from the multimeter each time the contacts are closed. However, relays are slow mechanical devices, so don’t try to use them with pulse-width modulation (PWM): it can damage the relay.

Figure 10-4. Using a relay with a Raspberry Pi

Discussion

Relays have been around since the early days of electronics and have the great advantage of being easy to use, plus they’ll work in any situation where a switch would normally work—for example, when you’re switching AC (alternating current), or in situations for which the exact wiring of the device being switched is unknown.

If the relay contacts are asked to exceed their specifications, the relay’s life will be shortened. There will be arcing, and the contacts can eventually fuse together. There is also the possibility of the relay becoming dangerously hot. When in doubt, overspecify the relay contacts.

Figure 10-5 shows the schematic symbol, pin layout, and package of a typical relay.

Figure 10-5. The workings of a relay

A relay is essentially a switch whose contacts are closed when an electromagnet pulls them together. Because the electromagnet and switch are not connected electrically in any way, this protects the circuit driving the relay coil from any high voltages on the switch side.

The downside of relays is that they are slow to operate and will eventually wear out after many hundreds of thousands of operations. This means they are suitable only for slow on/off control, and not for fast switching like PWM.

The coil of a relay requires about 50mA to close the connections. Because a Raspberry Pi GPIO pin is capable of supplying only about 3mA, you need to use a small transistor as a switch. You don’t need to use a high-power MOSFET like you did in Recipe 10.4; you can just use a small transistor instead. This has three connections. The base (middle lead) is connected to the GPIO pin via a 1kΩ resistor to limit the current. The emitter is connected to GND, and the collector is connected to one side of the relay. The other side of the relay is connected to 5V on the GPIO connector. The diode is used to suppress any high-voltage pulses that occur when the transistor rapidly switches the power to the relay’s coil.

Warning

Although relays can be used to switch 110V or 240V AC, this voltage is very dangerous and should not be used on a breadboard. If you want to switch high voltages, use Recipe 10.6 instead.

See Also

For switching direct current (DC) using a power MOSFET, see Recipe 10.4.

10.6 Controlling High-Voltage AC Devices

Problem

You want to switch 110 or 240V alternating current (AC), using a Raspberry Pi.

Solution

Use a PowerSwitch Tail II (see Figure 10-6). This handy device makes it really safe and easy to switch AC equipment on and off from a Raspberry Pi. It has an AC socket on one end and a plug on the other, like an extension cable; the only difference is that the control box in the middle of the lead has three screw terminals. By attaching terminal 2 to GND and terminal 1 to a GPIO pin, the device acts like a switch to turn the appliance on and off.

You can use the same Python code that you did in Recipe 10.1 to use the PowerSwitch Tail, as shown in Figure 10-6.

Discussion

The PowerSwitch Tail uses a relay, but to switch the relay, it uses a component called an opto-isolator, which has an LED shining onto a photo-TRIAC (a high-voltage, light-sensitive switch); when the LED is illuminated, the photo-TRIAC conducts, supplying current to the relay coil.

The LED inside the opto-isolator has its current limited by a resistor so that only 3mA flows through it when you supply it with 3.3V from a GPIO pin.

You will also find devices similar to but less expensive than the PowerSwitch Tail for sale on eBay and Amazon.

See Also

For switching DC using a power MOSFET, see Recipe 10.4; for switching using a relay on a breadboard, see Recipe 10.5.

A 240V version of the PowerSwitch Tail is available as a kit.

Figure 10-6. Using a PowerSwitch Tail with Raspberry Pi

10.7 Controlling Hardware with Android and Bluetooth

Problem

You want to use your Android mobile phone and Bluetooth to interact with your Raspberry Pi.

Solution

Use the free Blue Dot Android app and Python library:

$ sudo pip3 install bluedot

Next, you need to make sure that your Raspberry Pi is discoverable. In the upper-right corner of the Raspberry Pi’s screen, click the Bluetooth icon, and then click Make Discoverable (Figure 10-7).

Figure 10-7. Making your Raspberry Pi discoverable in Bluetooth

Next, you need to pair your Raspberry Pi and phone. Make sure that your phone has Bluetooth turned on, and then click Add New Device on your Raspberry Pi’s Bluetooth menu (Figure 10-8).

Figure 10-8. Pairing your Raspberry Pi and Phone

Find your phone in the list and then click Pair. You then are prompted on your phone to confirm a code to complete the pairing.

When pairing is complete, go to the Play Store app on your phone. Search for and install the Blue Dot app. The app won’t be able to work with your phone until you run a Python program that uses the Python Blue Dot code to listen for commands, so run the following program (ch_10_bluedot.py) on your Raspberry Pi:

from bluedot import BlueDot
bd = BlueDot()
while True:
    bd.wait_for_press()
    print("You pressed the blue dot!")

As with all the program examples in this book, you can download this program (see Recipe 3.22).

Now it’s time to open the Blue Dot app on your phone. When you do this, it provides a list of Blue Dot devices (Figure 10-9).

Figure 10-9. Connecting to your Raspberry Pi with Blue Dot

After you’re connected, the eponymous blue dot will appear, as shown in Figure 10-10.

Figure 10-10. The blue dot

When you tap on the Blue Dot with your finger, your Python program will print out the message: You pressed the blue dot!

$ python3 ch_10_bluedot.py
Server started B8:27:EB:D5:6C:E9
Waiting for connection
Client connected C0:EE:FB:F0:94:8F
You pressed the blue dot!
You pressed the blue dot!
You pressed the blue dot!

Discussion

The big blue dot isn’t just a button; you can also use it as a joystick. You can slide, swipe, and rotate the dot.

The Blue Dot library allows you to link handler functions to events such as swiping and rotating. For more information on this, take a look at the documentation.

See Also

For full information on Blue Dot, see their website.

There is also a Blue Dot Python module that lets you use a second Raspberry Pi as the Blue Dot remote.

See Recipe 1.18 for more information on using Bluetooth with a Raspberry Pi.

10.8 Making a User Interface to Turn Things On and Off

Problem

You want to make an application to run on the Raspberry Pi that has a button for turning things on and off.

Solution

Use guizero to provide the user interface for gpiozero to turn the pin on and off (Figure 10-11).

Figure 10-11. An on/off switch in guizero

If you haven’t already done so, install guizero using the following command:

$ sudo pip3 install guizero

You’ll need to connect an LED or some other kind of output device to GPIO pin 18. Using an LED (Recipe 10.1) is the easiest option for getting started.

As with all the program examples in this book, you can download the code for this recipe (see Recipe 3.22). The file is called ch_10_gui_switch.py and creates the switch shown in Figure 10-11:

from gpiozero import DigitalOutputDevice
from guizero import App, PushButton

pin = DigitalOutputDevice(18)

def start():
    start_button.disable()
    stop_button.enable()
    pin.on()

def stop():
    start_button.enable()
    stop_button.disable()
    pin.off()

app = App(width=100, height=150)
start_button = PushButton(app, command=start, text="On")
start_button.text_size = 30
stop_button = PushButton(app, command=stop, text="Off", enabled=False)
stop_button.text_size = 30
app.display()

Discussion

The example uses a pair of buttons, and when you press one, it disables itself and enables its counterpart. It also uses gpiozero to change the state of the output pin using the on() and off() methods.

This example would work just the same if we used the line pin = LED(18) rather than pin = DigitalOutputDevice(18), but using DigitalOutputDevice keeps things more generic. After all, you could be controlling anything from pin 18, not just an LED.

See Also

You can can also use this program to control a high-power DC device (Recipe 10.4), a relay (Recipe 10.5), or a high-voltage AC device (Recipe 10.6).

For more information on guizero, see Recipe 7.22.

10.9 Making a User Interface to Control PWM Power for LEDs and Motors

Problem

You want to make an application to run on the Raspberry Pi that has a slider to control power to a device using pulse-width modulation (PWM).

Solution

Using the gpiozero and guizero user interface framework, write a Python program that uses a slider to change the PWM duty cycle between 0 and 100% (Figure 10-12).

Figure 10-12. User interface for controlling PWM power

You will need to connect an LED or some other kind of output device to GPIO pin 18 that is capable of responding to a PWM signal. Using an LED (Recipe 10.1) is the easiest option to start with.

Open an editor and paste in the following code (the name of the file is ch_10_gui_slider.py):

from gpiozero import PWMOutputDevice
from guizero import App, Slider

pin = PWMOutputDevice(18)

def slider_changed(percent):
    pin.value = int(percent) / 100

app = App(title='PWM', width=500, height=150)
slider = Slider(app, command=slider_changed, width='fill', height=50)
slider.text_size = 30
app.display()

As with all the program examples in this book, you can download the code for this recipe (see Recipe 3.22).

Run the program using the following command:

$ python3 gui_slider.py

Discussion

The example program uses the Slider class. The command option runs the slider_changed command every time the value of the slider is changed. This updates the value of the output pin. The parameter to the slider_changed function is a string, even though it contains a number between 0 and 100, so int is used to convert it into a number and then the percent value has to be divided by 100 to give a value between 0 and 1 for the PWM output.

See Also

You can use this program to control an LED (Recipe 10.1), a DC motor (Recipe 11.4), or a high-power DC device (Recipe 10.4).

10.10 Changing the Color of an RGB LED

Problem

You want to control the color of an RGB LED.

Solution

Use PWM to control the power to each of the red, green, and blue channels of an RGB LED.

To make this recipe, you will need the following:

Breadboard and jumper wires (see “Prototyping Equipment and Kits”)

Three 470Ω resistors (see “Resistors and Capacitors”)

RGB common cathode LED (see “Opto-Electronics”)

A Perma-Proto (Recipe 9.9) or Pi Plate (see Recipe 9.19) to make a more permanent project (optional)

Figure 10-13 shows how you can connect your RGB LED on a breadboard. Make sure that the LED is the correct way around; the longest lead should be the second lead from the top of the breadboard. This connection is called the common cathode because the negative connections (cathodes) of the red, green, and blue LEDs within the LED case have all their negative sides connected together to reduce the number of pins needed in the package.

Figure 10-13. Using a RGB LED with a Raspberry Pi

An alternative to using a breadboard is to use a Raspberry Squid (see Recipe 9.10).

The upcoming program has three sliders to control the red, green, and blue channels of the LED (Figure 10-14).

Figure 10-14. Using a user interface to control an RGB LED

Open an editor and paste in the following code (the file is called ch_10_gui_slider_RGB.py):

from gpiozero import RGBLED
from guizero import App, Slider
from colorzero import Color

rgb_led = RGBLED(18, 23, 24)

red = 0
green = 0
blue = 0

def red_changed(value):
    global red
    red = int(value)
    rgb_led.color = Color(red, green, blue)

def green_changed(value):
    global green
    green = int(value)
    rgb_led.color = Color(red, green, blue)

def blue_changed(value):
    global blue
    blue = int(value)
    rgb_led.color = Color(red, green, blue)

app = App(title='RGB LED', width=500, height=400)

Slider(app, command=red_changed, end=255, width='fill', height=50).text_size = 30
Slider(app, command=green_changed, end=255, width='fill', height=50).text_size = 30
Slider(app, command=blue_changed, end=255, width='fill', height=50).text_size = 30

app.display()

As with all the program examples in this book, you can download the code for this recipe (see Recipe 3.22).

Discussion

The code is similar in operation to the control for a single PWM channel, described in Recipe 10.9. However, in this case, you need three PWM channels and three sliders, one for each color.

The type of RGB LED used here is a common cathode. If you have the common anode type, you can still use it, but connect the common anode to the 3.3V pin on the GPIO connector. You will then find that the slider becomes reversed, so a setting of 255 becomes off and 0 becomes full on.

When you are selecting an LED for this project, LEDs labeled diffused are best because they allow the colors to be mixed better.

See Also

If you want to control just one PWM channel, see Recipe 10.9.

For another approach to controlling the color of an RGB LED using the Squid RGB LED library, see Recipe 9.10.

10.11 Using an Analog Meter as a Display

Problem

You want to connect an analog panel voltmeter to a Raspberry Pi.

Solution

Assuming you have a 5V voltmeter, you can use a PWM output to drive the meter directly, connecting the negative side of the meter to ground and the positive side to a GPIO pin (Figure 10-15). If the meter is the common 5V kind, you’ll only be able to display voltages up to 3.3V.

If you want to use almost the full range of a 5V voltmeter, you will need a transistor to act as a switch for the PWM signal and a 1kΩ resistor to limit the current to the base of the transistor.

To make this recipe, you will need the following:

5V panel meter (see “Miscellaneous”)

Breadboard and jumper wires (see “Prototyping Equipment and Kits”)

Two 1kΩ resistors (see “Resistors and Capacitors”)

Transistor 2N3904 (see “Transistors and Diodes”)

Figure 10-16 shows the breadboard layout for this.

Figure 10-15. Connecting a voltmeter directly to a GPIO pin

Figure 10-16. Using a 5V panel meter with 3.3V GPIO

Discussion

To test the voltmeter, use the same program as you did for controlling the brightness of the LED in Recipe 10.9.

You will probably notice that the needle gives a steady reading at either end of the scale, but everywhere else it jitters a bit. This is a side effect of the way the PWM signals are generated. For a steadier result, you can use external PWM hardware like the 16-channel module used in Recipe 11.3.

See Also

For more information about how old-fashioned voltmeters work, see Wikipedia.

For more information on using a breadboard and jumper wires with the Raspberry Pi, see Recipe 9.8.

Chapter 11. Motors

11.0 Introduction

In this chapter, you will investigate the use of different types of motors with the Raspberry Pi. This includes DC motors, servo motors and stepper motors.

11.1 Controlling Servo Motors

Problem

You want to use a Raspberry Pi to control the position of a servo motor.

Solution

Use pulse-width modulation (PWM) to control the width of pulses to a servo motor to change its angle. Although this will work, the PWM generated is not completely stable, so there will be a little bit of jitter with the servo. For alternative solutions that produce much more stable pulse timing, see Recipe 11.2 and Recipe 11.3.

If you have an older Raspberry Pi 1, you should also power the servo from a separate 5V power supply because peaks in the load current are very likely to crash or overload the Raspberry Pi. If you have a Raspberry Pi B+ or newer, improvements in the onboard voltage regulation mean that you might get away with powering small servos directly from the 5V pin on the general-purpose input/output (GPIO) port.

Figure 11-1 shows a small 9g servo (see “Miscellaneous”) working quite happily with a Raspberry Pi B+.

Figure 11-1. Direct connection of a small servo to a Raspberry Pi B+

The leads of the servo are usually 5V wire as red, the ground as brown, and the control lead as orange. The 5V and ground leads are connected to the GPIO header 5V and GND pins, and the control lead is connected to pin 18. The connections are made with female-to-male header leads.

If you are using a separate power supply, a breadboard is a good way of keeping all the leads together.

In this case, you will need the following:

5V servo motor (see “Miscellaneous”)

Breadboard and jumper wires (see “Prototyping Equipment and Kits”)

1kΩ resistor (see “Resistors and Capacitors”)

5V 1A power supply or 4.8V battery pack (see “Miscellaneous”)

Figure 11-2 shows the breadboard layout for this.

Figure 11-2. Controlling a servo motor

The 1kΩ resistor is not essential, but it does protect the GPIO pin from unexpectedly high currents in the control signal, which could occur if a fault developed on the servo.

You can, if you prefer, power the servo from a battery pack rather than a power supply. Using a four-cell AA battery holder with rechargeable batteries will provide around 4.8V and will work well with a servo. Using four alkali AA cells to provide 6V will be fine for many servos, but check the datasheet of your servo to make sure it is OK with 6V.

The user interface for setting the angle of the servo is based on the ch_10_gui_slider.py program, which is intended for controlling the brightness of an LED (Recipe 10.9). However, you can modify it so that the slider sets the angle to be between –90 and 90 degrees (Figure 11-3).

Figure 11-3. User interface for controlling a servo motor

Open an editor and paste in the following code (the file is called ch_11_servo.py):

from gpiozero import AngularServo
from guizero import App, Slider

servo = AngularServo(18, min_pulse_width=0.5/1000, max_pulse_width=2.5/1000)

def slider_changed(angle):
    servo.angle = int(angle)

app = App(title='Servo Angle', width=500, height=150)
slider = Slider(app, start=-90, end=90, command=slider_changed, width='fill',
                height=50)
slider.text_size = 30
app.display()

As with all the program examples in this book, you can download this code (see Recipe 3.22).

Note that this program uses a graphical user interface, so you cannot run it from SSH or the Terminal. You must run it from the windowing environment on the Pi itself or via remote control using virtual network computing (VNC) (Recipe 2.8) or Remote Desktop Protocol (RDP) (Recipe 2.9).

The gpiozero class AngularServo takes care of all the pulse generation. It just leaves us to specify the angle to which we want the servo arm to position itself. Pretty much all other software that works with servo motors specifies angles of between 0 and 180 degrees, where 0 is as far as the servo arm can go to one side, 90 is in the middle, and 180 is as far as it can go to the other side. The gpiozero library does things differently, and probably more logically, by referring to the center position as 0 and to the angles on one side as negative and on the other side as positive.

When defining the servo, the first parameter (18 in this case) specifies the control pin for the servo motor. The optional parameters of min_pulse_width and max_pulse_width set the minimum and maximum pulse lengths in seconds. For a typical servo, these values should be 0.5 milliseconds and 2.5 milliseconds. For some reason the default values in gpiozero are 1 and 2 milliseconds; thus the servo motor has a very restricted range unless you set these values as we have here.

Discussion

Servo motors are used in remote control vehicles and robotics. Most servo motors are not continuous; that is, they cannot rotate all the way around but rather can rotate only over an angle range of about 180 degrees.

The position of the servo motor is set by the length of a pulse. The servo expects to receive a pulse at least every 20 milliseconds. If that pulse is high for 0.5 milliseconds, the servo angle will be –90 degrees; if it’s for 1.5 milliseconds, the motor will be at its center position (0 degrees); and if the pulse is high for 2.5 milliseconds, the servo angle will be 90 degrees (Figure 11-4).

Figure 11-4. Servo motor timing pulses

If you have a few servo motors to connect, the MonkMakes ServoSix board (Figure 11-5) makes the wiring easier.

Figure 11-5. Connecting servo motors with the ServoSix board

See Also

If you have a lot of servos to control or require greater stability and precision, you can use a dedicated servo controller module, as described in Recipe 11.3.

See more information in the full documentation of the ServoSix board.

Adafruit has developed another method of servo control.

For an alternative solution that produces much more stable pulse timing using the ServoBlaster device driver software, see Recipe 11.2.

11.2 Controlling Servo Motors Precisely

Problem

The pulse generation function of the gpiozero library is not precise or jitter-free enough for your servo application.

Solution

Install the ServoBlaster device driver.

ServoBlaster and Sound

The ServoBlaster software uses Raspberry Pi hardware that is also involved in generating sound. Thus, you won’t be able to play audio through your Raspberry Pi’s audio jack or HDMI while using ServoBlaster.

The ServoBlaster software created by Richard Hirst uses Raspberry Pi CPU hardware to generate pulses with much more accurate timings than are possible using gpiozero. Install ServoBlaster using the following commands and then reboot your Raspberry Pi:

$ git clone git://github.com/richardghirst/PiBits.git
$ cd PiBits/ServoBlaster/user
$ sudo make
$ sudo make install

You can modify the program from Recipe 11.1 to use the ServoBlaster code. You can find the modified program in the file ch_11_servo_blaster.py. As with all the program examples in this book, you can download it (see Recipe 3.22). This program assumes that the servo control pin is connected to GPIO 18:

import os
from guizero import App, Slider

servo_min = 500  # uS
servo_max = 2500 # uS
servo = 2        # GPIO 18

def map(value, from_low, from_high, to_low, to_high):
  from_range = from_high - from_low
  to_range = to_high - to_low
  scale_factor = float(from_range) / float(to_range)
  return to_low + (value / scale_factor)

def set_angle(angle):
  pulse = int(map(angle+90, 0, 180, servo_min, servo_max))
  command = "echo {}={}us > /dev/servoblaster".format(servo, pulse)
  os.system(command)

def slider_changed(angle):
  set_angle(int(angle))

app = App(title='Servo Angle', width=500, height=150)
slider = Slider(app, start=-90, end=90, command=slider_changed, width='fill',
                height=50)
slider.text_size = 30
app.display()

The user interface code is just the same as Recipe 11.1. The differences are in the set_angle function. The set_angle function first uses a utility function called map that converts the angle into a pulse duration using the constants servo_min and servo_max. Then it constructs a command that will be run as if from the command line. The format of this line starts with the echo command, followed by the servo number to be controlled, an equals sign, and then a pulse duration in microseconds. This string part of the command will be directed to the device /dev/servoblaster. The servo will then adjust its angle.

Killing ServoBlaster

When ServoBlaster, or more specifically, the service servo.d, is running, you will not be able to use the servo pins for anything, and audio on the Raspberry Pi will not work. So when you need to use the pins for something else, use the following commands to disable ServoBlaster and then reboot your Pi:

$ sudo update-rc.d servoblaster disable
$ sudo reboot

When your Raspberry Pi restarts, ServoBlaster will no longer have control of your pins, and you will be able to use sound again on your Pi. You can always turn ServoBlaster back on again using:

$ sudo update-rc.d servoblaster enable
$ sudo reboot

Discussion

The ServoBlaster driver is actually very powerful, and you can configure it to allow you to use pretty much all the GPIO pins to control servos. Its default setup defines eight GPIO pins to act as servo control pins. These are each given a channel number, as shown in Table 11-1.

Table 11-1. Servo channel default pin allocation for ServoBlaster

Servo channel | GPIO pin
0 | 4
1 | 17
2 | 18
3 | 27
4 | 22
5 | 23
6 | 24
7 | 25

Connecting so many servos can result in jumper-lead spaghetti. A board like the MonkMakes ServoSix (Figure 11-5) greatly simplifies the wiring of the servos to your Raspberry Pi.

See Also

More information is available in the full documentation for ServoBlaster.

If you do not need the precise timing of ServoBlaster, the gpiozero library can also generate pulses for your servo, as described in Recipe 11.1.

11.3 Controlling Multiple Servo Motors Precisely

Problem

You need to control lots of servos with high precision and without the loss of sound that comes with using ServoBlaster.

Solution

Although the ServoBlaster code (see Recipe 11.2) allows you to control up to eight servos accurately, it does rather take over your Raspberry Pi’s hardware and disables sound generation.

The alternative to ServoBlaster is to use a servo motor HAT like the one shown in Figure 11-6 that has its own servo controlling hardware, relieving the Raspberry Pi’s hardware.

This Adafruit HAT allows you to control up to 16 servos or PWM channels using the I2C interface of the Raspberry Pi. The servos just plug straight into the HAT.

Power is supplied to the logic circuits of the module from the 3.3V connection of the Raspberry Pi. This is entirely separate from the power supply for the servo motors, which comes from an external 5V power adapter.

You can, if you prefer, power the servos from a battery pack rather than a power supply. Using a four-cell AA battery holder with rechargeable batteries provides around 4.8V and works well with most servos. Using four alkali AA cells to provide 6V will be fine for many servos, but check the datasheet of your servo to make sure it is OK with 6V.

The pin headers for connecting servos are conveniently arranged so that the servo lead fits directly onto the pins. Be careful to get them facing the correct way.

Figure 11-6. Adafruit servo motor HAT

To use the Adafruit software for this module, you will need to set up I2C on the Raspberry Pi (Recipe 9.3).

The software for this board uses some useful software from Adafruit that allows you to use an entire range of their accessory add-on boards.

To install the Adafruit blinka code needed for this board, run the following commands:

$ pip3 install adafruit-blinka
$ sudo pip3 install adafruit-circuitpython-servokit

Open an editor and paste in the following code (the name of the file is ch_11_servo_adafruit.py):

from adafruit_servokit import ServoKit
from guizero import App, Slider

servo_kit = ServoKit(channels=16)

def slider_changed(angle):
    servo_kit.servo[0].angle = int(angle) + 90

app = App(title='Servo Angle', width=500, height=150)
slider = Slider(app, start=-90, end=90, command=slider_changed, width='fill',
                height=50)
slider.text_size = 30
app.display()

As with all the program examples in this book, you can also download this code (see Recipe 3.22).

When you run the program, you will get the same window containing a slider as shown in Figure 11-3. Use this to move the servo arm about. Adafruit’s software is not compatible with Python 2, so you need to run any programs that use the Adafruit software via the python3 command.

Note that this program uses a graphical user interface (GUI), so you can’t run it from SSH or the Terminal; you must run it from the windowing environment on the Pi itself or via remote control using VNC (Recipe 2.8) or RDP (Recipe 2.9):

$ python3 ch_11_servo_adafruit.py

The Adafruit software uses the servo motor angle range of 0 to 180 rather than gpiozero’s –90 to 90 degrees, so to keep the user interface the same, 90 is added to the angle supplied by the slider.

To address a specific servo channel among the 16 available channels, the channel number (between 0 and 15) is specified inside the square brackets in the command servo_kit.servo[0].angle.

Discussion

When selecting a power supply for this module, remember that a standard remote control servo can easily draw 400mA while it’s moving, and more if it’s under load. So if you plan to have a lot of large servos moving at the same time, you will need a big power adapter.

See Also

For information on this Adafruit product, see https://www.adafruit.com/product/2327.

A Servo HAT is great if your Raspberry Pi is close to the servo motors, but if your servos are distant from where you want the Raspberry Pi to be, Adafruit also sells a servo module (product ID 815) that has the same servo controller hardware as the servo HAT but just four pins to connect the I2C interface of the board to the Raspberry Pi’s I2C interface.

11.4 Controlling the Speed of a DC Motor

Problem

You want to control the speed of a DC motor using your Raspberry Pi.

Solution

You can use the same design as Recipe 10.4. It is, however, a good idea to place a diode across the motor to prevent voltage spikes from damaging the transistor or even the Raspberry Pi. The 1N4001 is a suitable diode for this. The diode has a stripe at one end, so make sure that this is facing the proper direction (Figure 11-7).

Figure 11-7. Controlling a high-power motor

You will need the following:

3V to 12V DC motor

Breadboard and jumper wires (see “Prototyping Equipment and Kits”)

1kΩ resistor (see “Resistors and Capacitors”)

MOSFET transistor FQP30N06L (see “Transistors and Diodes”)

Diode 1N4001 (see “Transistors and Diodes”)

Power supply with voltage to match the motor

As with all the program examples in this book, you can also download this program (see Recipe 3.22). The file is called ch_10_gui_slider.py.

Note that this program uses a GUI, so you can’t run it from SSH. You must run it from the windowing environment on the Pi itself or via remote control using VNC (Recipe 2.8) or RDP (Recipe 2.9).

Discussion

If you are using only a low-power DC motor (less than 200mA), you can use a smaller (and cheaper) transistor such as the 2N3904 (see “Transistors and Diodes”). Figure 11-8 shows the breadboard layout to use a 2N3904.

You can probably get away with powering a small motor from the 5V supply line on the GPIO connector. If you find that the Raspberry Pi crashes, use an external power supply, as shown in Figure 11-7.

Figure 11-8. Controlling a low-power motor

See Also

This design controls only the motor’s speed. It can’t control its direction. For that, you need to see Recipe 11.5.

For more information on using a breadboard and jumper wires with the Raspberry Pi, see Recipe 9.8.

11.5 Controlling the Direction of a DC Motor

Problem

You want to control both the speed and direction of a small DC motor.

Solution

Use an H-Bridge chip or module, the most common chip being the L293D. These are low cost and easy to use. Other H-Bridge chips or modules usually use the same pair of control pins for the direction of each motor (see the forthcoming Discussion).

The L293D chip is actually capable of driving two motors without any extra hardware. The Discussion also mentions a few other options for controlling DC motors. To try out the L293D to control a motor, you will need the following:

3V to 12V DC motor

Breadboard and jumper wires (male to female; see “Prototyping Equipment and Kits”)

L293D chip (see “Integrated Circuits”)

Power supply with voltage to match the motor

Figure 11-9 shows the breadboard layout.

Figure 11-9. Using an L293D chip to control a motor

Make sure the chip is facing the proper direction: there is a notch in its top, which is the end that should be at the top of the breadboard.

The test program for this recipe (ch_11_motor_control.py) allows you to enter the letter f or r and then a single digit between 0 and 9. The motor will then either go forward or backward at a speed specified by the digit—0 for stopped, 9 for full speed:

$ python3 ch_11_motor_control.py
Command, f/r 0..9, E.g. f5 :f5
Command, f/r 0..9, E.g. f5 :f1
Command, f/r 0..9, E.g. f5 :f2
Command, f/r 0..9, E.g. f5 :r2

Open an editor and paste in the following code. As with all the program examples in this book, you can also download it (see Recipe 3.22).

This program uses the command line, so you can run it from SSH or the Terminal:

from gpiozero import Motor

motor = Motor(forward=23, backward=24)

while True:
    cmd = input("Command, f/r 0..9, E.g. f5 :")
    direction = cmd[0]
    speed = float(cmd[1]) / 10.0
    if direction == "f":
        motor.forward(speed=speed)
    else:
        motor.backward(speed=speed)

gpiozero conveniently has a class called Motor that we can use to control both the speed and direction of a single DC motor. When you create an instance of the class, you need to specify the forward and backward control pins.

The forward and backward methods of Motor take an optional parameter of speed between 0 and 1, where 1 is full speed.

Discussion

The Motor class of gpiozero hides the complexity of the H-Bridge’s hardware.

Figure 11-10 shows how an H-Bridge works, using switches rather than transistors or a chip. By reversing the polarity across the motor, an H-Bridge also reverses the direction in which the motor turns.

In Figure 11-10, S1 and S4 are closed and S2 and S3 are open. This allows current to flow through the motor, with terminal A being positive and terminal B being negative. If we were to reverse the switches so that S2 and S3 are closed and S1 and S4 are open, B would be positive and A would be negative, and the motor would turn in the opposite direction.

However, you might have spotted a danger with this circuit. If by some chance S1 and S2 are both closed, the positive supply will be directly connected to the negative supply and you will have a short circuit. The same is true if S3 and S4 are both closed at the same time.

Figure 11-10. An H-Bridge

Although you can use individual transistors to make an H-Bridge, it is simpler to use an H-Bridge integrated circuit (IC) such as the L293D. This chip actually has two H-Bridges in it, so you can use it to control two motors. It also has logic to ensure that the equivalent of closing both S1 and S2 cannot happen.

The L293 uses two control pins for each of the two motor control channels: a forward pin and a backward pin. If the forward pin (23) is high and the backward pin (24) is low, the motor will turn in one direction. If those two pins are reversed, the motor will turn in the opposite direction.

As an alternative to using an L293D on a breadboard, very low-cost modules are available from eBay that include a L293D on a printed circuit board (PCB) with screw terminals to attach motors and header pins to link directly to the Raspberry Pi GPIO connector. If you need a higher-power motor controller module, you can find motor controller modules that operate on the same principles but at much higher currents, even up to 20A or more. Pololu has an impressive range of such motor controller boards.

See Also

You also can use the Adafruit Stepper Motor HAT (Recipe 11.8) and RasPiRobot Board (Recipe 11.9) to control the speed and direction of a DC motor.

Check out the L293D datasheet and the SparkFun Motor Driver module product page.

For more information on using a breadboard and jumper wires with the Raspberry Pi, see Recipe 9.8.

11.6 Using a Unipolar Stepper Motor

Problem

You want to drive a five-lead unipolar stepper motor using a Raspberry Pi.

Solution

Use a ULN2803 Darlington driver chip on a breadboard.

Stepper motors fit somewhere between DC motors and servo motors in the world of motor technologies. Like a regular DC motor, they can rotate continuously, but you can also very accurately position them by moving them a step at a time in either direction.

To make this recipe, you will need the following:

5V, five-pin unipolar stepper motor (see “Miscellaneous”)

ULN2803 Darlington driver IC (see “Integrated Circuits”)

Breadboard and jumper wires (see “Prototyping Equipment and Kits”)

Figure 11-11 shows the wiring diagram for using a ULN2803. Note that you can use the chip to drive two such motors. To drive a second stepper motor, you need to connect four more control pins from the GPIO connector to pins 5 to 8 of the ULN2803, and then you connect the second motor’s four pins to pins 11 to 14 of the ULN2803.

Figure 11-11. Using a ULN2803 to control a unipolar stepper motor

The 5V supply from the GPIO connector can work acceptably with a small stepper motor. If you experience problems with the Raspberry Pi crashing or need to use a bigger stepper motor, use a separate supply for the power to the motor (pin 10 of the ULN2803).

Open an editor and paste in the following code (ch_11_stepper.py). This program uses the command line, so you can run it from SSH:

from gpiozero import Motor
import time

coil1 = Motor(forward=18, backward=23, pwm=False)
coil2 = Motor(forward=24, backward=17, pwm=False)

forward_seq = ['FF', 'BF', 'BB', 'FB']
reverse_seq = list(forward_seq) # to copy the list
reverse_seq.reverse()

def forward(delay, steps):
  for i in range(steps):
    for step in forward_seq:
      set_step(step)
      time.sleep(delay)

def backwards(delay, steps):
  for i in range(steps):
    for step in reverse_seq:
      set_step(step)
      time.sleep(delay)

def set_step(step):
  if step == 'S':
    coil1.stop()
    coil2.stop()
  else:
    if step[0] == 'F':
      coil1.forward()
    else:
      coil1.backward()
    if step[1] == 'F':
      coil2.forward()
    else:
      coil2.backward()

while True:
  set_step('S')
  delay = input("Delay between steps (milliseconds)?")
  steps = input("How many steps forward? ")
  forward(int(delay) / 1000.0, int(steps))
  set_step('S')
  steps = input("How many steps backwards? ")
  backwards(int(delay) / 1000.0, int(steps))

As with all the program examples in this book, you can also download this code (see Recipe 3.22).

When you run the program, you are prompted for a delay between steps. This should be 2 or more. You are then prompted for the number of steps in each direction:

$ python3 ch_11_stepper.py
Delay between steps (milliseconds)?2
How many steps forward? 100
How many steps backwards? 100
Delay between steps (milliseconds)?10
How many steps forward? 50
How many steps backwards? 50
Delay between steps (milliseconds)?

This code is explained in the Discussion section that follows, because it helps to know a bit more about how stepper motors work to follow the code.

Discussion

Stepper motors use a cogged rotor with alternating north and south poles and electromagnets to nudge the wheel around a step at a time (Figure 11-12). Note that the colors of the leads will vary.

Energizing the coils in a certain order drives the motor around. The number of steps that the stepper motor has in a 360-degree rotation is actually the number of teeth on the rotor.

Figure 11-12. A stepper motor

The two coils are each controlled by an instance of the gpiozero class Motor and are called coil1 and coil2.

The program uses a list of strings to represent each of the four energization stages that make up a single step:

forward_seq = ['FF', 'BF', 'BB', 'FB']

Each pair of letters indicates the current direction for coil1 and coil2: either Forward or Backward. So, looking for a moment at Figure 11-12 and assuming that the common Red connection is to GND, the letter F for the Pink-Orange coil might make Pink high and Orange low, whereas B would reverse this.

The sequence for rotating the motor in the opposite direction is just the reverse of the sequence for moving forward.

You can use the forward and backward functions in your programs to step the motor back and forth. The first argument to either function is the delay in milliseconds between each part of the step sequence. The minimum value for this depends on the motor you use. If it’s too small, the motor will not turn. Typically, two milliseconds or more will be fine. The second parameter is the number of steps to take:

def forward(delay, steps):
  for i in range(steps):
    for step in forward_seq:
      set_step(step)
      time.sleep(delay)

The forward function has two nested for loops. The outer loop repeats for the number of steps, and the inner one iterates over the sequence of motor activations, calling set_step for each in sequence:

def set_step(step):
  if step == 'S':
    coil1.stop()
    coil2.stop()
  else:
    if step[0] == 'F':
      coil1.forward()
    else:
      coil1.backward()
    if step[1] == 'F':
      coil2.forward()
    else:
      coil2.backward()

The set_step function sets each coil’s polarity, depending on the message supplied as its step argument. The command S stops the power to both coils so that we can avoid using current when the motor isn’t moving. If the first letter is an F, then coil1 is set to forward; otherwise it is set to backward. coil2 is set in the same way but using the second letter of step.

The main loop sets the step to S between moving forward and backward, to deactivate both coils when the motor is not actually turning. Otherwise, one of the coils might be left on, causing the motor to unnecessarily draw current.

See Also

If you have a four-wire bipolar stepper motor, see Recipe 11.7.

For more information, see the Wikipedia article on stepper motors, where you will also see the different types and how they work, as well as find a nice, animated explanation of the activation pattern for driving the motor.

For information on using servo motors, see Recipe 11.1; for information on controlling DC motors, see Recipes Recipe 11.4 and Recipe 11.5.

For more information on using a breadboard and jumper wires with the Raspberry Pi, see Recipe 9.8.

11.7 Using a Bipolar Stepper Motor

Problem

You want to drive a four-lead bipolar stepper motor using a Raspberry Pi.

Solution

Use an L293D H-Bridge driver chip. An H-Bridge is required to drive a bipolar stepper motor because, as the word bipolar suggests, the direction of current across the windings needs to be reversed, rather like driving a DC motor in both directions (see Recipe 11.5).

To make this recipe, you will need the following:

12V, four-pin bipolar stepper motor (see “Miscellaneous”)

L293D H-Bridge IC (see “Integrated Circuits”)

Breadboard and jumper wires (see “Prototyping Equipment and Kits”)

The motor used here, a 12V, is somewhat larger than the previous unipolar stepper motor example. The power for the motor itself is therefore supplied from an external power supply rather than from the Raspberry Pi. See the wiring diagram in Figure 11-13.

Figure 11-13. Using an L293D to control a bipolar stepper motor

Discussion

A bipolar stepper motor is just like the unipolar version shown in Figure 11-12, except that the “Red” central tapping connections to the coils are not present. The same energization pattern will work just as well on both variants, but for a bipolar motor, the direction of the current in the whole of the coil must be reversable; hence, two H-bridges are necessary.

You can use the same ch_11_stepper.py program to control this stepper (see Recipe 11.6). The design uses both H-Bridges of the L293D, so you need one of these chips for each motor that you want to control.

See Also

If the type of stepper motor you have is a five-wire unipolar stepper motor, see Recipe 11.6.

For more information on stepper motors—the different types and how they work—see Wikipedia, where you will also find a nice animated explanation of the activation pattern for driving the motor.

For information on using servo motors, see Recipe 11.1; for information on controlling DC motors, see Recipes Recipe 11.4 and Recipe 11.5.

For more information on using a breadboard and jumper wires with the Raspberry Pi, see Recipe 9.8.

You can also drive a stepper motor by using the RasPiRobot Board (Recipe 11.9).

11.8 Using a Stepper Motor HAT to Drive a Bipolar Stepper Motor

Problem

You want to control multiple bipolar stepper motors using a single interface board.

Solution

Use an Adafruit Stepper Motor HAT.

This board is capable of driving two bipolar stepper motors. Figure 11-14 shows the board with one bipolar stepper motor, with one coil connected to the M1 terminals and the other coil to the M2 terminals. The power for the motors is supplied separately at the screw terminals on the right.

I2C Busses

If you followed Recipe 9.20 to make your own HAT and enabled the I2C bus 0 as described there, you will need to reverse the change to /boot/config.txt because the Adafruit autodetects the I2C bus to use and will detect the wrong one if bus 0 is enabled.

In /boot/config.txt, delete or comment out this line (by putting a # at the beginning of it):

dtparam=i2c_vc=on

After you do this, reboot your Raspberry Pi.

Figure 11-14. Using an Adafruit Stepper Motor HAT to control a bipolar stepper motor

This HAT uses I2C, so make sure that you have I2C enabled (Recipe 9.3).

This board is supported by an excellent Adafruit tutorial.

Discussion

When you run the program supplied in the Adafruit tutorial, the motor begins to turn, and the program loops around four different modes of stepping.

See Also

For a discussion of the HAT standard and how to make your own HAT, see Recipe 9.20.

For more information on using this HAT and its accompanying library, see https://learn.adafruit.com/adafruit-dc-and-stepper-motor-hat-for-raspberry-pi.

To use an L293D to control a stepper motor, see Recipe 11.7; to use a RasPiRobot Board, see Recipe 11.9.

11.9 Using a RasPiRobot Board to Drive a Bipolar Stepper Motor

Note

Be sure to check out the accompanying video for this recipe at http://razzpisampler.oreilly.com.

Problem

You want to control a bipolar stepper motor by using one power supply for both the motor and your Raspberry Pi.

Solution

Use a RasPiRobot Board version 4.

The RasPiRobot Board uses the power supply directly from its screw terminals as the supply to the motor and regulates that same supply down to 5V to drive the Raspberry Pi. So in this case, the 12V power will be supplying both the 12V stepper motor and the Raspberry Pi.

Warning

If you are using one of the first versions of the RasPiRobot Board (version 1 or 2), do not power the Raspberry Pi through its USB connection at the same time, because you power it through the RasPiRobot Board.

There is no problem powering it through both in version 3 or 4 of the board.

Connect the stepper motor and power supply to the RasPiRobot Board as shown in Figure 11-15. TThe wire colors for the Adafruit 12V stepper motor are, in order from the bottommost wire: yellow and red (coil 1), gray and green (coil 2).

Figure 11-15. Using a RasPiRobot Board to control a bipolar stepper motor

Before you can run the program, you will need to install the library for the RaspiRobot Board v4 using the following commands:

$ git clone https://github.com/simonmonk/rrb4.git
$ cd rrb4/python
$ sudo python3 setup.py install

Open an editor and paste in the following code (ch_11_stepper_rrb.py). This program uses the command line, so you can run it from SSH:

from rrb4 import *
import time

rr = RRB4(12.0, 12.0) # battery, motor

try:
    while True:
        delay = input("Delay between steps (milliseconds)?")
        steps = input("How many steps forward? ")
        rr.step_forward(int(delay) / 1000.0, int(steps))
        steps = input("How many steps backwards? ")
        rr.step_reverse(int(delay) / 1000.0, int(steps))

finally:
    GPIO.cleanup()

As with all the program examples in this book, you can also download this code (see Recipe 3.22).

Discussion

You will find that there is a minimum value of "Delay between steps", below which the motor will judder rather than turn.

See Also

You can find full documentation for the RasPiRobot Board and other projects that use it at the RasPiRobot website.

To drive a stepper motor using an L293D H-Bridge driver chip on a breadboard, see Recipe 11.7.

11.10 Building a Simple Robot Rover

Problem

You want to use a Raspberry Pi as the controller for a simple roving robot.

Solution

Use a RasPiRobot Board v4 or other motor controller board as an interface board to the Raspberry Pi to control two motors and a robot chassis kit.

To make this recipe, you will need the following:

RasPiRobot board v4 (see “Modules”)

Chassis and Gearmotor Kit (see “Miscellaneous”)

Four-cell AA battery holder (see “Miscellaneous”)

The first step in building the robot is to assemble the chassis. Most low-cost gearmotor chassis are supplied with a four-cell AA battery holder, so you might not need to buy one separately.

Follow the wiring instructions shown in Figure 11-16.

Figure 11-16. Wiring a roving robot

The battery pack will supply power to the RasPiRobot Board, which in turn supplies 5V to the Raspberry Pi. So only one power supply is required.

The finished rover should look something like Figure 11-17, which also has a rangefinder on the front for good measure.

Figure 11-17. The finished robot

To drive the robot, you are going to use a control program that allows you to steer the rover using keys on a laptop or other computer connected to your Raspberry Pi over SSH. If you have not already done so, set up your Raspberry Pi to use WiFi and SSH, using Recipe 2.5 and Recipe 2.7, respectively.

Open an editor and paste in the following code (ch_11_rover.py):

from rrb4 import *
import sys
import tty
import termios

rr = RRB4(6.0, 6.0) # battery, motor

UP = 0
DOWN = 1
RIGHT = 2
LEFT = 3

print("Use the arrow keys to move the robot")
print("Press Ctrl-C to quit the program")

# These functions allow the program to read your keyboard
def readchar():
    fd = sys.stdin.fileno()
    old_settings = termios.tcgetattr(fd)
    try:
        tty.setraw(sys.stdin.fileno())
        ch = sys.stdin.read(1)
    finally:
        termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
    if ch == '0x03':
        raise KeyboardInterrupt
    return ch

def readkey(getchar_fn=None):
    getchar = getchar_fn or readchar
    c1 = getchar()
    if ord(c1) != 0x1b:
        return c1
    c2 = getchar()
    if ord(c2) != 0x5b:
        return c1
    c3 = getchar()
    return ord(c3) - 65  # 0=Up, 1=Down, 2=Right, 3=Left arrows

# This will control the movement of your robot and display on your screen
try:
    while True:
        keyp = readkey()
        if keyp == UP:
            rr.forward(1)
            print('forward')
        elif keyp == DOWN:
            rr.reverse(1)
            print('backward')
        elif keyp == RIGHT:
            rr.right(1)
            print('clockwise')
        elif keyp == LEFT:
            rr.left(1)
            print('anti clockwise')
        elif keyp == LEFT:
            rr.left(1)
            print('anti clockwise')
        elif ord(keyp) == 3:
            break

except KeyboardInterrupt:
    GPIO.cleanup()

As with all the program examples in this book, you can also download this code (see Recipe 3.22).

To be able to intercept keypresses, this program uses the termios library and the functions readchar and readkey.

After the import commands, a new instance of RRB4 is created. The two parameters to this are the battery voltage and the motor voltage (in this case, 6V and 6V). If your chassis has different voltage motors, change the second parameter.

The main loop just checks for keypresses and then sends the appropriate commands of forward, reverse, left, or right to the RRB4 library.

Discussion

You can make the rover more interesting by adding peripherals to it. You could, for example, attach a webcam and set up web streaming so that your roving robot becomes a roving spycam (Recipe 4.3).

The RRB4 library also supports the HC-SR04 rangefinder, which can be plugged into a socket on the RasPiRobot Board v4. You can use this to detect obstacles. You can find example software for this in the RRB4 library.

See Also

You can find out more about the RasPiRobot board and the RRB4 library on GitHub.

Chapter 12. Digital Inputs

12.0 Introduction

In this chapter, we look at recipes for using digital components such as switches and keypads. This chapter also covers modules that have a digital output that can be connected to a Raspberry Pi general-purpose input/output (GPIO) acting as an input.

Many of the recipes require the use of a solderless breadboard and jumper wires (see Recipe 9.8).

12.1 Connecting a Push Switch

Problem

You want to connect a switch to your Raspberry Pi so that when you press it, some Python code is run.

Solution

Connect a switch to a GPIO pin and use the gpiozero library in your Python program to detect the button press.

To make this recipe, you will need the following:

Breadboard and jumper wires (see “Prototyping Equipment and Kits”)

Tactile push switch (see “Miscellaneous”)

Figure 12-1 shows how to connect a tactile push switch using a breadboard and jumper wires.

Figure 12-1. Connecting a push switch to a Raspberry Pi

An alternative to using a breadboard and tactile switch is to use a Squid Button (Figure 12-2). This is a push switch with female header leads soldered to the end, which you can directly connect to the GPIO connector (Recipe 9.11).

Figure 12-2. A Squid Button

Open an editor and paste in the following code (ch_12_switch.py):

from gpiozero import Button

button = Button(18)

while True:
    if button.is_pressed:
        print("Button Pressed")

As with all the program examples in this book, you can also download this code (see Recipe 3.22).

This is what you will see when you run the program and press the button:

pi@raspberrypi ~ $ python3 ch_12_switch.py
Button Pressed
Button Pressed
Button Pressed
Button Pressed

In fact, the Button Pressed messages will probably go shooting off the bottom of the screen. This is because the program is checking very frequently for the button being pressed. Another problem with this code is that while it is watching for button presses it can’t be getting on with other things.

We can improve on this code, both to do something only once when pressed and to allow other things to be going on until a button is pressed. You will find this in the following code (ch_12_switch_2.py):

from gpiozero import Button
from time import sleep

def do_stuff():
    print("Button Pressed")

button = Button(18)
button.when_pressed = do_stuff

while True:
    print("Busy doing other stuff")
    sleep(2)

When you run this program, you will see output like this:

$ python3 ch_12_switch_2.py
Busy doing other stuff
Busy doing other stuff
Button Pressed
Busy doing other stuff
Busy doing other stuff

When you press the button, the function do_stuff will be run, irrespective of what the program is otherwise doing. This approach is called using interrupts and is often used in programs that need to trigger actions when a button is pressed but also need to be doing other things.

Note that this line

button.when_pressed = do_stuff

includes do_stuff without () on the end. This is because we are referring to the function, not actually calling it until the interrupt occurs.

Discussion

Notice that the switch is wired so that when it is pressed, it connects pin 18, which is configured as an input to GND.

You might expect the push switch to have just two connections, which are either open or closed. Although some of these tactile push switches do have just two connections, most have four. Figure 12-3 shows how these connections are arranged.

Figure 12-3. A tactile push switch

Actually, there are really only two electrical connections because inside the switch package, pins B and C are connected together, as are A and D.

See Also

For more information on using a breadboard and jumper wires with the Raspberry Pi, see Recipe 9.8.

To debounce a switch, see Recipe 12.5.

To use external pull-up or pull-down resistors, see Recipe 12.6.

12.2 Toggling with a Push Switch

Problem

You want to turn something on and off with a push switch so that it toggles between on and off each time you press it.

Solution

Read the last state of the button (that is, whether the button is On or Off) and invert that value each time the button is pressed.

The following example toggles an LED on and off as you press the switch.

To make this recipe, you will need the following:

Breadboard and jumper wires (see “Prototyping Equipment and Kits”)

Tactile push switch (see “Miscellaneous”)

LED (see “Opto-Electronics”)

470Ω resistor (see “Resistors and Capacitors”)

Figure 12-4 shows how to connect a tactile push switch and LED, using a breadboard and jumper wires.

Figure 12-4. Connecting a push switch and LED to a Raspberry Pi

In addition to the male-to-female jumper wires connecting the Raspberry Pi to the breadboard, you also need one male-to-male jumper wire or solid core wire.

Open an editor and paste in the following code (ch_12_switch_on_off.py):

from gpiozero import Button, LED
from time import sleep

led = LED(23)

def toggle_led():
    print("toggling")
    led.toggle()

button = Button(18)
button.when_pressed = toggle_led

while True:
    print("Busy doing other stuff")
    sleep(2)

As with all the program examples in this book, you can also download this code (see Recipe 3.22).

The program is based on ch_12_switch_2.py and again uses interrupts so that the program can be getting on with other things until a button press happens.

When the button is pressed, the function toggle_led is called. This toggles the LED; that is, if it’s on, it turns it off, and if it’s off, it turns it on.

Discussion

Depending on the quality of your switch, you may have noticed that sometimes the LED doesn’t toggle, but that two or more toggling messages appear in the Terminal. This is due to something called switch bounce, which we will discuss further in Recipe 12.5.

See Also

For the documentation on the gpiozero Button class, see https://gpiozero.readthedocs.io/en/stable/api_input.html#button.

12.3 Using a Two-Position Toggle or Slide Switch

Problem

You want to connect a two-position toggle or slide switch to your Raspberry Pi and be able to find the position of the switch in your Python program.

Solution

Use the switch as you would a tactile push switch (Recipe 12.1): just connect the center and one end contact (Figure 12-5).

To make this recipe, you will need the following:

Breadboard and jumper wires (see “Prototyping Equipment and Kits”)

Miniature toggle or slide switch (see “Miscellaneous”)

The same code you used in Recipe 12.1 works with this arrangement.

Figure 12-5. Connecting a slide switch to a Raspberry Pi

Discussion

These type of slide switches are useful because you can see the position they are set to without the need for some additional indicator like an LED. However, they are more fragile and a little more expensive than the tactile push switches that are used more and more in consumer electronics because they can sit behind a nicer-looking plastic button.

See Also

To use a three-position switch with a center-off position, see Recipe 12.4.

12.4 Using a Center-Off Toggle or Slide Switch

Problem

You want to connect a three-position (center-off) toggle switch to your Raspberry Pi and be able to find the position of the switch in your Python program.

Solution

Connect the switch to two GPIO pins, as shown in Figure 12-6, and use the gpiozero library in your Python program to detect the position of the switch.

To make this recipe, you will need the following:

Breadboard and jumper wires (see “Prototyping Equipment and Kits”)

Miniature center-off three-position toggle switch (see “Miscellaneous”)

Figure 12-6. Connecting a three-position switch to a Raspberry Pi

The common (center) connection of the switch is connected to ground, and each of the two ends of the switch are connected to a GPIO pin with the internal pull-up resistor enabled.

Open an editor and paste in the following code (ch_12_switch_3_pos.py):

from gpiozero import Button

switch_top = Button(18)
switch_bottom = Button(23)

switch_position = "unknown"

while True:
    new_switch_position = "unknown"
    if switch_top.is_pressed:
        new_switch_position = "top"
    elif switch_bottom.is_pressed:
        new_switch_position = "bottom"
    else:
        new_switch_position = "center"

    if new_switch_position != switch_position:
        switch_position = new_switch_position
        print(switch_position)

As with all the program examples in this book, you can also download this code (see Recipe 3.22).

Run the program, and as you move the switch from top to center to bottom, the position of the switch is reported every time it changes:

$ python3 ch_12_switch_3_pos.py
center
top
center
bottom

Discussion

The program sets up two inputs as separate buttons.

Inside the loop, both button states are read, and the three conditions of the if, elif, and else structure determine the position of the switch, assigning the value to a variable called new_switch_position. If this differs from the previous value, the switch position is printed.

You will find a wide range of types of toggle switches. Some will be described as DPDT, SPDT, SPST, or SPST, momentary on, and so on. The meaning of these letters is as follows:

D: Double

S: Single

P: Pole

T: Throw

Thus, a DPDT switch is double pole, double throw. The word pole refers to the number of separate switch contacts that are controlled from the one mechanical lever. Thus, a double pole switch can switch two things on and off. A single throw switch can only open or close a single contact (or two contacts if it is double pole). However, a double throw switch can connect the common contact to one of two other contacts.

Figure 12-7 shows the most common types of switches.

Figure 12-7. Types of toggle switches

See Also

For more information on how if statements work, see Recipe 5.18.

For the most basic switch recipe, see Recipe 12.1.

12.5 Debouncing a Button Press

Problem

Sometimes when you press the button on a switch, the expected action happens more than once because the switch contacts bounce. In that case, you want to write code that debounces the switch.

Solution

The gpiozero Button class includes code that deals with bouncing of switch contacts. However, by default this is turned off. You can change it when you create a button instance using the optional bounce_time parameter.

See the Discussion for more information on what is going on with switch bouncing. But the basic idea is that when a switch is pressed, the contacts can bounce, producing false readings of the switch position. The bounce_time parameter determines how long false changes of the switch state should be ignored for.

In Recipe 12.2, for example, you might have noticed that pressing the button often doesn’t seem to toggle the LED. This will happen if you get an even number of bounces when you press the button, so that one bounce turns the LED on and a second bounce immediately turns it off again (within a fraction of a second), with the result that it looks like nothing happened.

You can modify the program ch_12_switch_on_off.py to set the debouncing time by adding the bounce_time optional parameter where you define the button:

from gpiozero import Button, LED
from time import sleep

led = LED(23)

def toggle_led():
    print("toggling")
    led.toggle()

button = Button(18, bounce_time=0.1)
button.when_pressed = toggle_led

while True:
    print("Busy doing other stuff")
    sleep(2)

In this example, the bounce time is set to 0.1 seconds, which should be more than enough time for the switch contacts to settle.

Discussion

Switch bouncing occurs on most switches and can be quite severe on some switches, as the oscilloscope trace in Figure 12-8 shows.

Figure 12-8. Contact bounce with a poor switch

You can see that there is contact bounce both as the switch closes and when it is released. Most switches are not as bad as this one.

See Also

For the basics of connecting a button, see Recipe 12.1.

12.6 Using an External Pull-Up Resistor

Problem

You want to run a long wire from the Raspberry Pi to the switch, but you are getting some false readings on the input pin.

Solution

The Raspberry Pi GPIO pins include pull-up resistors. When a GPIO pin is being used as a digital input, its pull-up resistor will keep the input high (3.3V) until the input is pulled down to GND, perhaps by a switch. In addition, the pull-up resistor can be turned on and off within your Python program.

These internal pull-up resistors are quite weak (about 40kΩ), which means that if you run a long lead to the switch or operate in an electrically noisy environment, you might get false triggerings on the digital input. You can overcome this by turning off the internal pull-up and pull-down resistors and using an external pull-up resistor.

Figure 12-9 shows the use of an external pull-up resistor.

To test out this hardware, you can use the program ch_12_switch.py; see Recipe 12.1.

Discussion

The lower the resistance of the resistor, the longer the range of your switch. However, when you press the button, a current flows from 3.3V through the resistor to ground. A 100Ω resistor draws a current of 3.3V/100Ω = 33mA. This is within the safe limit for the 3.3V supply of 50mA for a Raspberry Pi 1, so don’t use a lower value than this if you have an older Raspberry Pi. If you are using a newer 40-pin GPIO Raspberry Pi, you could drop this value even further, perhaps to 47Ω.

In almost all cases, a 1kΩ resistor will provide a long range with no problems.

Figure 12-9. Using an external pull-up resistor

See Also

For the basics of connecting a button, see Recipe 12.1.

12.7 Using a Rotary (Quadrature) Encoder

Problem

You want to detect rotation by using a rotary encoder (a control that you rotate like a volume knob).

Solution

Use a rotary (quadrature) encoder connected to two GPIO pins, as shown in Figure 12-10.

Figure 12-10. Connecting a rotary encoder

To make this recipe, you will need the following:

Breadboard and jumper wires (see “Prototyping Equipment and Kits”)

Rotary encoder (quadrature type; see “Miscellaneous”)

This type of rotary encoder is called a quadrature encoder, and it behaves like a pair of switches. The sequence in which they open and close as the rotary encoder’s shaft is turned determines the direction of rotation.

The rotary encoder shown in Figure 12-10 has the center lead as the common lead and the two leads on either side as A and B. Not all rotary encoders use this layout, so check the pinout on the datasheet for the rotary encoder that you are using. The issue is often confused further because many rotary encoders include a push switch, which will have a separate pair of contacts.

Open an editor and paste in the following code (ch_12_rotary_encoder.py):

from gpiozero import Button
import time

input_A = Button(18)
input_B = Button(23)

old_a = True
old_b = True

def get_encoder_turn():
    # return -1 (cce), 0 (no movement), or +1 (cw)
    global old_a, old_b
    result = 0
    new_a = input_A.is_pressed
    new_b = input_B.is_pressed
    if new_a != old_a or new_b != old_b :
        if old_a == 0 and new_a == 1 :
            result = (old_b * 2 - 1)
        elif old_b == 0 and new_b == 1 :
            result = -(old_a * 2 - 1)
    old_a, old_b = new_a, new_b
    time.sleep(0.001)
    return result

x = 0

while True:
    change = get_encoder_turn()
    if change != 0 :
        x = x + change
        print(x)

As with all the program examples in this book, you can also download this code (see Recipe 3.22).

The test program simply counts up as you turn the rotary encoder clockwise, and down when you rotate it counterclockwise:

$ python3 ch_12_rotary_encoder.py
1
2
3
4
5
6
7
8
9
10
9
8
7
6
5
4

Discussion

Figure 12-11 shows the sequence of pulses that you will get from the two contacts, A and B. You can see that the pattern repeats itself after four steps (hence the name quadrature encoder).

Figure 12-11. How quadrature encoders work

When rotating clockwise (left to right in Figure 12-11), the sequence will be:

Phase
A
B

1

0

0

2

0

1

3

1

1

4

1

0

When rotating in the opposite direction, the sequence of phases will be reversed:

Phase
A
B

4

1

0

3

1

1

2

0

1

1

0

0

The Python program listed previously implements the algorithm for determining the rotation direction in the function get_encoder_turn. The function will return 0 if there has been no movement, 1 for a rotation clockwise, or -1 for a rotation counterclockwise. It uses two global variables, old_a and old_b, to store the previous states of the switches A and B. By comparing them with the newly read values, it can determine (using a bit of clever logic) which direction the encoder is turning.

The sleep period of one millisecond is to ensure that the next new sample does not occur too soon after the previous sample; otherwise, the transitions can give false readings.

The test program should work reliably no matter how fast you turn the knob on the rotary encoder; however, try to avoid doing anything time consuming in the loop, or you might find that turn steps are missed.

See Also

You can also measure the rotated position of a knob by using a variable resistor with the step response method (Recipe 13.1) or by using an analog-to-digital converter (Recipe 13.6).

12.8 Using a Keypad

Problem

You want to interface a keypad with your Raspberry Pi.

Solution

Keypads are arranged in rows and columns, with a push switch on the intersection of each row or column. To find out which key is pressed, you first connect all the row and column connections to Raspberry Pi GPIO pins. So, for a 4×3 keypad, you will need four + three pins. By scanning each column in turn (setting it to output high) and reading the value of each of the row inputs, you can determine which (if any) key is pressed.

Note that keypads show considerable variation in their pinouts.

To make this recipe, you will need the following:

Breadboard and jumper wires (see “Prototyping Equipment and Kits”)

4×3 keypad (see “Miscellaneous”)

Seven male header pins (see “Miscellaneous”)

Figure 12-12 shows the wiring diagram for the project using the SparkFun keypad listed in “Miscellaneous”. The keypad is supplied without header pins, which you must solder onto the keypad.

Figure 12-12. Keypad wiring diagram

Open an editor and paste in the following code (ch_12_keypad.py).

Warning

Before you run the program, make sure that the row and column pins are correct for the keypad that you are using. If necessary, change the values in the variables rows and cols. If you do not do this, it is possible that pressing a key could short one GPIO output to another, where one is high and the other is low. This would likely damage your Raspberry Pi.

from gpiozero import Button, DigitalOutputDevice
import time

rows = [Button(17), Button(25), Button(24), Button(23)]
cols = [DigitalOutputDevice(27), DigitalOutputDevice(18), DigitalOutputDevice(22)]
keys = [
    ['1', '2', '3'],
    ['4', '5', '6'],
    ['7', '8', '9'],
    ['*', '0', '#']]

def get_key():
    key = 0
    for col_num, col_pin in enumerate(cols):
        col_pin.off()
        for row_num, row_pin in enumerate(rows):
            if row_pin.is_pressed:
                key = keys[row_num][col_num]
        col_pin.on()
    return key

while True:
    key = get_key()
    if key :
        print(key)
    time.sleep(0.3)

When you run the program, you can see each keypress being printed:

$ sudo python3 ch_12_keypad.py
1
2
3
4
5
6
7
8
9
*
0
#

As with all the program examples in this book, you can also download this program (see Recipe 3.22).

There is a push switch at the intersection of every row and column, so that when the switch is pressed, the particular row and column will become connected.

The rows and columns defined here are correct for the SparkFun keypad listed in “Miscellaneous” in Appendix A. The first row is connected to GPIO pin 17, the second to pin 25, and so on. The wiring of the row and column to the keypad connector is illustrated in Figure 12-13.

Figure 12-13. Keypad pin connections

Discussion

The keys variable contains a map of the key name for each row and column position. You can customize this for your keypad.

All the real action takes place in the get_key function. This enables each column in turn by setting it to low. An inner loop then tests each of the rows in turn. If one of the rows is low, the key name corresponding to that row and column is looked up in the keys array. If no keypress is detected, the default value of key (0) is returned.

The main while loop just gets the key value and prints it. The sleep command slows down the output.

See Also

An alternative to adding a keyboard is simply to use a USB keypad; that way you can just catch keystrokes, as described in Recipe 12.11.

12.9 Detecting Movement

Problem

You want to trigger some action in Python when movement is detected.

Solution

Use a Passive Infrared (PIR) motion detector module.

To make this recipe, you will need the following:

Female-to-female jumper wires (see “Prototyping Equipment and Kits”)

PIR motion detector module (see “Modules”)

Figure 12-14 shows how the sensor module is wired. This module expects a power supply of 5V and has an output of 3.3V, making it ideal for use with a Raspberry Pi.

Warning

Make sure that the PIR module you use has a 3.3V output. If it has a 5V output, you will need to use a pair of resistors to reduce it to 3.3V (see Recipe 13.7).

Figure 12-14. Wiring a PIR motion detector

Open an editor and paste in the following code (ch_12_pir.py):

from gpiozero import MotionSensor

pir = MotionSensor(18)

while True:
    pir.wait_for_motion()
    print("Motion detected!")

As with all the program examples in this book, you can also download this program (see Recipe 3.22).

The program simply prints out the state of the GPIO input 18:

$ python3 ch_12_pir.py
Motion Detected
Motion Detected

Discussion

gpiozero provides a class for the PIR sensor, MotionSensor, so we might as well use it. However, this class doesn’t really do anything except monitor the pin in question as a digital input.

When triggered, the output of the PIR sensor will stay high for a little while. You can adjust this using one of the trimpots on its circuit board. The second trimpot (if present) will set the threshold of light level that will disable the sensor. This is useful when the sensor is being used to control a light—turning the light on when detecting movement, but only when it’s dark.

See Also

More information is available in the full documentation for MotionSensor.

You could combine this recipe with Recipe 7.16 to send an email when an intruder is detected, or you could integrate it with If This Then That (IFTTT) to provide a bevy of possible ways of being notified (see Recipe 16.4).

To detect movement using computer vision and a webcam, see Recipe 8.6.

12.10 Adding GPS to the Raspberry Pi

Problem

You want to connect a serial GPS module to a mobile Raspberry Pi and access the data using Python.

Solution

A serial GPS module, with 3.3V output, can be connected directly to Raspberry Pi’s RXD connection. This means that for it to work, you must follow Recipe 2.6. Note that, although you want to enable the serial port hardware, you should not enable the serial console option.

Figure 12-15 shows how the module is wired. The RXD of the Raspberry Pi connects to Tx of the GPS module. The only other connections are for GND and 5V, so we can use three female-to-female headers.

Figure 12-15. Wiring a GPS to a Raspberry Pi

You can see the raw GPS data using Minicom (see Recipe 9.7). Use the following minicom command to see the messages appear once per second on the /dev/ttyS0 device. Older versions of Raspbian associated /dev/ttyAMA0 with the TTL serial port, so if you can’t see the data, try /dev/ttyAMA0 instead of /dev/ttyS0:

$ minicom -b 9600 -o -D /dev/ttyS0
$GPRMC,095509.090,V,,,,,0.00,0.00,040619,,,N*4E
$GPVTG,0.00,T,,M,0.00,N,0.00,K,N*32
$GPGGA,095510.090,,,,,0,0,,,M,,M,,*49

If you don’t see any data, check your connections and make sure that the serial port hardware is enabled. Note that it’s fine to test that the GPS module is basically working indoors without a GPS signal. But if you want to get an actual GPS fix, you might need to take your Raspberry Pi outdoors, or at least have the GPS module right next to a window.

As you can see from the preceding sample, GPS messages require some decoding. The good news is that there is a good suite of tools to help us do this.

Install the following packages:

$ sudo apt-get install gpsd
$ sudo apt-get install gpsd-clients

The more important of these is gpsd. This is a tool that reads GPS data from a serial or USB connection (as well as other sources) and makes it available for client programs to use by providing a local web service on port 2748.

Having installed the software, you now need to make a few configuration changes. Run the following command to edit the config file /etc/default/gpsd:

$ sudo nano /etc/default/gpsd

Delete everything in the file and replace it with the following:

START_DAEMON="true"
USBAUTO="false"
DEVICES="/dev/ttyS0"
GPSD_OPTIONS="-n"
GPSD_SOCKET="/var/run/gpsd.sock"

Save the file and then start the gpsd service running by issuing the following command:

$ sudo gpsd /dev/ttyS0

You can see whether it is working by entering this command:

$ cgps -s

The -s is optional; it just suppresses the display of the raw data (see Figure 12-16).

Figure 12-16. Testing GPS with cgps

Installing gpsd automatically installs a package called python-gps. This is, as you might expect, a Python library for accessing the GPS data in a nice, convenient form. We can use python_gps with a short test program to display just the latitude, longitude, and time.

Open an editor and paste in the following code (ch_12_gps_test.py; do not call the file gps.py, as that will conflict with the Python GPS library):

from gps import *
session = gps()
session.stream(WATCH_ENABLE|WATCH_NEWSTYLE)

while True:
    report = session.next()
    if report.keys()[0] == 'epx' :
        lat = float(report['lat'])
        lon = float(report['lon'])
        print("lat=%f\tlon=%f\ttime=%s" % (lat, lon, report['time']))
        time.sleep(0.5)

As with all the program examples in this book, you can also download this program (see Recipe 3.22).

Run the program (using Python 2, not Python 3), and you should see some trace like this:

$ python ch_12_gps_test.py
lat=53.719513 lon=-2.671245 time=2019-06-04T10:40:54.000Z
lat=53.719513 lon=-2.671247 time=2019-06-04T10:40:55.000Z
lat=53.719513 lon=-2.671247 time=2019-06-04T10:40:56.000Z
lat=53.719513 lon=-2.671248 time=2019-06-04T10:40:57.000Z

Discussion

The program creates a session and then establishes a stream of data to be read. The GPS will repeatedly spit out messages in different formats. The if command selects just the messages you want: those that contain the positional information. The parts of the message are stored in a dictionary from which the fields can be accessed and displayed.

Besides using the GPS data with Python, you can also use the xgps tool to display the GPS data (Figure 12-17). Just enter the following command:

$ xgps

Figure 12-17. Viewing GPS with xgps

This utility requires a display, so you should run it from the Raspberry Pi itself or by using VNC (Recipe 2.8) or RDP (Recipe 2.9).

See Also

You can use the same approach using a USB GPS module.

Find out more about gpsd.

12.11 Intercepting Keypresses

Problem

You want to intercept individual keypresses on a USB keyboard or numeric keypad.

Solution

There are at least two ways to solve this problem. The more straightforward approach is to use the sys.stdin.read function. This has the advantage over the other method of not requiring a graphical user interface (GUI) to be running, so a program using it can be run from an SSH session.

Open an editor, paste in the following code (ch_12_keys_sys.py), run the program, and start pressing some keys:

import sys, tty, termios

def read_ch():
    fd = sys.stdin.fileno()
    old_settings = termios.tcgetattr(fd)
    try:
        tty.setraw(sys.stdin.fileno())
        ch = sys.stdin.read(1)
    finally:
        termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
    return ch

while True:
    ch = read_ch()
    if ch == 'x':
        break
    print("key is: " + ch)

As with all the program examples in this book, you can also download this program (see Recipe 3.22).

The alternative to this is to use pygame. pygame is a Python library intended for writing games, but you also can use it to detect keypresses. You could then use this to perform some action.

The following example program (ch_12_keys_pygame.py) illustrates the use of pygame to print out a message each time a key is pressed. However, it works only if the program has access to the windowing system, so you will need to run it using VNC (Recipe 2.8) or RDP (Recipe 2.9) or run it directly on the Raspberry Pi:

import pygame
import sys
from pygame.locals import *

pygame.init()
screen = pygame.display.set_mode((640, 480))
pygame.mouse.set_visible(0)

while True:
    for event in pygame.event.get():
        if event.type == QUIT:
            sys.exit()
        if event.type == KEYDOWN:
            print("Code: " + str(event.key) + " Char: " + chr(event.key))

This opens a blank Pygame window, and keys will be intercepted only if the Pygame window is selected. The program produces output in the Terminal window from which the program is run.

If you press an arrow key or Shift key with the first stdin read approach, the program will throw an error because those keys don’t have an ASCII value:

$ python3 keys_pygame.py
Code: 97 Char: a
Code: 98 Char: b
Code: 99 Char: c
Code: 120 Char: x
Code: 13 Char:

In this case, Ctrl-C won’t stop this program from running. To stop the program, click the X on the Pygame window.

Discussion

When you are using the pygame approach, other keys have constant values defined for them, which allows you to use the cursor and other non-ASCII keys (like the up arrow key and Home) on the keyboard. This isn’t possible with the other approach.

See Also

Intercepting keyboard events can also be an alternative to using a matrix keypad (Recipe 12.8).

12.12 Intercepting Mouse Movements

Problem

You want to detect mouse movements in Python.

Solution

The solution to this is very similar to that of using pygame to intercept keyboard events (Recipe 12.11).

Open an editor and paste in the following code (ch_12_mouse_pygame.py):

import pygame
import sys
from pygame.locals import *

pygame.init()
screen = pygame.display.set_mode((640, 480))
pygame.mouse.set_visible(0)

while True:
    for event in pygame.event.get():
        if event.type == QUIT:
            sys.exit()
        if event.type == MOUSEMOTION:
            print("Mouse: (%d, %d)" % event.pos)

As with all the program examples in this book, you can also download this program (see Recipe 3.22).

When you run the program, the MOUSEMOTION event is triggered whenever the mouse moves within the pygame window. You can find the coordinates from the pos value of the event. The coordinates are absolute coordinates relative to the upper-left corner of the window:

Mouse: (262, 285)
Mouse: (262, 283)
Mouse: (262, 281)
Mouse: (262, 280)
Mouse: (262, 278)
Mouse: (262, 274)
Mouse: (262, 270)
Mouse: (260, 261)
Mouse: (258, 252)
Mouse: (256, 241)
Mouse: (254, 232)

Discussion

Other events that you can intercept are MOUSEBUTTONDOWN and MOUSEBUTTONUP. These can be used to detect when the left mouse button has been pressed or released.

See Also

You can find the pygame documentation for mouse at the pygame website.

12.13 Using a Real-Time Clock Module

Problem

You want your Raspberry Pi to remember the time, even when it has no network connection.

Solution

Use a real-time clock (RTC) module.

A very common RTC chip is the DS1307. It has an I2C interface, and you can buy it as a ready-to-use module that includes the chip itself, a quartz crystal for it to maintain accurate timekeeping, and a battery holder for a 3V lithium cell.

To make this recipe, you will need the following:

A DS1307 or compatible RTC module (see “Modules”)

Female-to-female jumper wires (see “Prototyping Equipment and Kits”)

Warning

The RTC module that you are using must be 3.3V compatible. That means that its I2C interface either should have no pull-up resistors at all or should pull up to 3.3V and not 5V. When using the Adafruit model here, simply don’t include the two resistors when soldering together the module. If you have a ready-made module, carefully remove any pull-up resistors.

Assemble the RTC module if it is in kit form, remembering to omit pull-up resistors, and then connect the module to the Raspberry Pi, as shown in Figure 12-18.

Figure 12-18. Connecting an RTC module

The DS1307 is an I2C module, so your Raspberry Pi must be set up to work with I2C (see Recipe 9.3). You can check that the device is visible using I2C tools (Recipe 9.4):

$ sudo i2cdetect -y 1
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- 68 -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --

The 68 in the table indicates that the RTC module is connected to the I2C bus at hex address 68. If there is no entry in the I2C table, check your connections to the RTC module and that the pull-up resistors are not fitted.

If you are using one of the original Raspberry Pi model B revision 1 boards, use 0 after the -y option in the preceding line (and in any other references to the I2C channel in the examples that follow). The revision 1 boards are distinctive for having a black audio socket. Also, congratulations: you have one of the first ever Raspberry Pis—a collector’s item.

You now need to run the following commands so that you can use the RTC with a program called hwclock:

$ sudo modprobe rtc-ds1307
$ sudo bash
# echo ds1307 0x68 > /sys/class/i2c-adapter/i2c-1/new_device
# exit
$

Note that sudo bash puts you into superuser mode, and exit takes you back to normal user mode.

You can now access the RTC using the following command:

$ sudo hwclock -r
2000-01-01 00:01:29.385239+0000

As you can see, the clock is not currently set.

To set the time on the RTC module, you first need to make sure that your Raspberry Pi has the correct time. If your Pi is connected to the internet, this should happen automatically. You can check this by using the date command:

$ date
Wed  5 Jun 09:30:05 BST 2019

If the time is wrong, you can also set it manually using date (Recipe 3.37). To transfer the Raspberry Pi system time onto the RTC module, use the following command:

$ sudo hwclock -w

You can then read the time by using the -r option:

$ sudo hwclock -r
2019-06-05 09:30:49.625077+0100

The RTC having the correct time is pointless unless it is used to set the correct system time in Linux when it reboots. To arrange for this to happen, you need to make a few configuration changes.

First, edit /etc/modules (using sudo nano /etc/modules) and add rtc-ds1307 to the end of the list of modules. If you have already added some modules while setting up I2C, SPI, and other options, your file might look something like this (although there might be extra entries that you can leave there):

# /etc/modules: kernel modules to load at boot time.
#
# This file contains the names of kernel modules that should be loaded
# at boot time, one per line. Lines beginning with "#" are ignored.
# Parameters can be specified after the module name.

i2c-dev
rtc-ds1307

Next, you need two commands to run automatically during startup to set the system time. So, edit the file /etc/rc.local using the command sudo nano /etc/rc.local, and just before the final exit 0 line, insert the following two lines:

echo ds1307 0x68 > /sys/class/i2c-adapter/i2c-1/new_device
sudo hwclock -s

When you finish, the file should look something like this:

#
# In order to enable or disable this script, just change the execution
# bits.
#
# By default, this script does nothing.

# Print the IP address
_IP=$(hostname -I) || true
if [ "$_IP" ]; then
  printf "My IP address is %s\n" "$_IP"
fi
echo ds1307 0x68 > /sys/class/i2c-adapter/i2c-1/new_device
sudo hwclock -s
exit 0

Now when you reboot, your Raspberry Pi should set its system time from the RTC. However, if there is an internet connection available, this will take precedence for setting the time.

Discussion

An RTC is not essential for a Raspberry Pi by any means, because a Raspberry Pi that is connected to the internet will automatically connect to a network time server and set its own clock. However, you might not always be using the Pi when connected to a network, in which case a hardware RTC is a good option.

See Also

AB Electronics has a neat RTC that plugs directly into the GPIO socket, as shown in Figure 12-19.

This recipe is based on a tutorial from Adafruit.

Figure 12-19. AB Electronics RTC module

12.14 Giving the Raspberry Pi a Reset Button

Problem

You want a reset button to start up your Raspberry Pi like a typical desktop computer.

Solution

When you are finished using your Raspberry Pi, you should really shut it down; otherwise, it’s possible to corrupt the SD card image, which would mean you’d have to reinstall Raspbian. Having shut down your Raspberry Pi, you can get it to boot up again by unplugging the USB lead and then plugging it back in, but a neater solution is to add a reset button to your Raspberry Pi.

For this recipe, you will need the following:

Two-way ¹⁄₁₀-inch header pins (see “Miscellaneous”)

A recycled PC start button or MonkMakes Squid Button (see “Modules”)

Soldering equipment (see “Prototyping Equipment and Kits”

Most models of Raspberry Pi have a connector just for this purpose. Its location on the board varies, but it’s always labeled RUN. Figure 12-20 shows its position on a Raspberry Pi 4, and Figure 12-21 on a Raspberry Pi 3.

Figure 12-20. Position of the RUN contacts on a Raspberry Pi 4

Figure 12-21. Position of the RUN contacts on a Raspberry Pi 3

The holes for the contacts are one-tenth of an inch apart and are designed to be fitted with standard header pins. Push through the short end of the pins from the top of the board and solder the underside. After you’ve soldered them in place, the Raspberry Pi with RUN header pins should look like Figure 12-22.

Figure 12-22. Pins attached to a Raspberry Pi

Now that the pins are attached, the button connectors can just be pushed over the header pins, as shown in Figure 12-23.

Figure 12-23. A Raspberry Pi complete with reset button

Discussion

To test out your modification, power up your Raspberry Pi and then shut it down by selecting Shutdown from the Raspberry menu (Figure 12-24).

After a while the screen will close down and the Pi will go into a halt mode, where it uses minimal power and is basically on standby.

Now to start your Pi, all you need to do is press the button, and it will boot up!

Figure 12-24. Shutting down the Raspberry Pi

See Also

For more information on shutting down and starting your Raspberry Pi, see Recipe 1.16.

Chapter 13. Sensors

13.0 Introduction

In this chapter, we look at recipes for using sensors of various types that will allow the Raspberry Pi to measure temperature, light, and more.

Unlike boards such as the Arduino and the BeagleBone, the Raspberry Pi lacks analog inputs. This means that for many sensors, it is necessary to use additional analog-to-digital converter (ADC) hardware. Fortunately, this is relatively easy to do. It is also possible to use resistive sensors with a capacitor and a couple of resistors.

Many of the recipes will require the use of a solderless breadboard and male-to-female jumper wires (see Recipe 9.8).

13.1 Using Resistive Sensors

Note

Be sure to check out the accompanying video for this recipe at http://razzpisampler.oreilly.com.

Problem

You want to connect a variable resistor to a Raspberry Pi and measure its resistance so that you can use the position of the variable resistor’s knob in your Python program.

Solution

You can measure resistance on a Raspberry Pi using nothing more than a capacitor, a couple of resistors, and two general-purpose input/output (GPIO) pins. In this case, you will be able to estimate the position of the knob on a small variable resistor (trimpot) by measuring its resistance from its slider contact to one end of the pot.

To make this recipe, you will need the following:

Breadboard and jumper wires (see “Prototyping Equipment and Kits”)

10kΩ trimpot (see “Resistors and Capacitors”)

Two 1kΩ resistors (see “Resistors and Capacitors”)

330nF capacitor (see “Resistors and Capacitors”)

Figure 13-1 shows the arrangement of components on the breadboard.

Figure 13-1. Measuring resistance on a Raspberry Pi

This recipe makes use of a Python library that the author developed to make this approach to using analog sensors easier. To install it, run the following commands:

$ git clone https://github.com/simonmonk/pi_analog.git
$ cd pi_analog
$ sudo python3 setup.py install

Open an editor and paste in the following code (ch_13_resistance_meter.py):

from PiAnalog import *
import time

p = PiAnalog()

while True:
    print(p.read_resistance())
    time.sleep(1)

As with all the program examples in this book, you can also download this program (see Recipe 3.22).

When you run the program, you should see some output like this:

$ python3 resistance_meter.py
5588.419502667787
5670.842306126099
8581.313103654076
10167.614271851775
8724.539614581638
4179.124682880563
267.41950235897957

The reading will vary as you rotate the knob of the trimpot. Ideally, the reading of resistance would vary between 0 and 10,000Ω, but in practice, there will be some error.

Discussion

To explain how we can use the PiAnalog class, I first need to explain how the step response technique for measuring the resistance of the variable resistor works.

Figure 13-2 shows the schematic diagram for the recipe.

This way of doing things is called step response because it works by seeing how the circuit responds from the step change when an output is switched from low to high.

You can think of a capacitor as a tank of electricity, and as it fills with charge, the voltage across it increases. You can’t measure that voltage directly, because the Raspberry Pi doesn’t have an analog-to-digital converter (ADC). However, you can time how long it takes for the capacitor to fill with charge to the extent that it rises above the 1.65V or so that constitutes a high digital input. The speed at which the capacitor fills with charge depends on the value of the variable resistor (Rt). The lower the resistance, the faster the capacitor fills with charge and the voltage rises.

Figure 13-2. Measuring resistance using step response

To be able to get a good reading, you must also be able to empty the capacitor each time before you take a reading. In Figure 13-2, connection A is used to charge the capacitor through Rc and Rt, and connection B is used to discharge (empty) the capacitor through Rd. The resistors Rc and Rd are used to prevent too much current from flowing through the Raspberry Pi’s relatively fragile GPIO pins as the capacitor is charged and discharged.

The steps involved in taking a reading are first to discharge the capacitor through Rd and then to let it charge through Rc and Rt. To discharge it, connection A (GPIO 18) is set to be an input, effectively disconnecting Rc and Rt from the circuit. Connection B (GPIO 23) is then set to be an output and low. This is held there for 100 milliseconds to empty the capacitor.

Now that the capacitor is empty, you can start to allow charge to flow into it by setting connection B to be an input (effectively disconnecting it) and then enabling connection A to be a high output at 3.3V. Capacitor C will now begin to charge through Rc and Rt.

Figure 13-3 shows how a resistor and capacitor in this kind of arrangement charge and discharge as the voltage is toggled between high and low.

You can see that the voltage at the capacitor increases rapidly at first but then trails off as the capacitor becomes full. Fortunately, you are interested in the portion of the curve up until the capacitor reaches about 1.65V, which is a fairly straight line, meaning that the time taken for the voltage across the capacitor to rise to this point is roughly proportional to the resistance of Rt and hence the position of the knob.

This approach is not hugely accurate, but it is very low cost and easy to use. The inaccuracy is largely because capacitors of a suitable value are accurate to only 10%.

Figure 13-3. Charging and discharging a capacitor

See Also

Using a step response works well with all kinds of resistive sensors for light (Recipe 13.2), temperature (Recipe 13.3), and even gas detection (Recipe 13.4).

For more accurate measurements of the trimpot position, see Recipe 13.6, where the pot is used with an ADC.

13.2 Measuring Light

Problem

You want to measure light intensity with a Raspberry Pi and a photoresistor.

Solution

Use the same basic recipe and code as Recipe 13.1, but replace the trimpot with a photoresistor.

To make this recipe, you will need the following:

Breadboard and jumper wires (see “Prototyping Equipment and Kits”)

Photoresistor (see “Resistors and Capacitors”)

Two 1kΩ resistors (see “Resistors and Capacitors”)

330 nF capacitor (see “Resistors and Capacitors”)

All of these parts are included in the Electronics Starter Kit for Raspberry Pi from MonkMakes (see “Prototyping Equipment and Kits”).

Figure 13-4 shows the arrangement of components on the breadboard.

Figure 13-4. Measuring light on a Raspberry Pi

Using the same program as Recipe 13.1 (ch_13_resistance_meter.py), you will see the output vary as you move your hand over the photoresistor to cut out some of the light.

Note that this program needs the PiAnalog library to be installed (see Recipe 13.1).

This solution provides relatively reliable readings of light levels. As an adaptation of the general solution for using resistive sensors (Recipe 13.1), it also copes with measuring a resistance of 0Ω without any risk of damaging the GPIO pins of the Raspberry Pi.

Discussion

A photoresistor is a resistor whose resistance varies depending on the amount of light coming through its transparent window. The brighter the light, the lower the resistance. Typically, the resistance varies from about 1kΩ in bright light up to perhaps 100kΩ in complete darkness.

The sensors can really give only a rough idea of the light level.

See Also

You could also use an ADC with the photoresistor (Recipe 13.6).

13.3 Measuring Temperature with a Thermistor

Problem

You want to measure temperature using a thermistor.

Solution

A thermistor is a resistor whose resistance varies with temperature. Use the step response method (Recipe 13.1) to measure the resistance of the thermistor and then calculate the temperature.

To make this recipe, you will need the following:

Breadboard and jumper wires (see “Prototyping Equipment and Kits”)

1k thermistor (see “Resistors and Capacitors”)

Two 1kΩ resistors (see “Resistors and Capacitors”)

330 nF capacitor (see “Resistors and Capacitors”)

All of these parts are included in the Electronics Starter Kit for Raspberry Pi from MonkMakes (see “Prototyping Equipment and Kits”). When you get your thermistor, make sure that you know its values of Beta and R0 (resistance at 25°C) and that it is a Negative Temperature Coefficient (NTC) device.

Figure 13-5 shows the breadboard layout for this recipe.

Figure 13-5. Breadboard layout for using a thermistor

Note that this program needs the PiAnalog library to be installed (see Recipe 13.1).

Open an editor (nano or IDLE) and paste in the following code (ch_13_thermistor.py):

from PiAnalog import *
import time

p = PiAnalog()

while True:
    print(p.read_temp_c())
    time.sleep(1)

As with all the program examples in this book, you can also download this program (see Recipe 3.22).

When you run the program, you will see a series of temperature measurements in degrees Celsius. To convert to degrees Fahrenheit, change the code p.read_temp_c() to p.read_temp_f():

$ python3 ch_13_thermistor.py
18.735789861164392
19.32060395712483
20.2694035007122
21.03181169007422
21.26640936199749

Discussion

Calculating the temperature from the resistance of the thermistor requires some fairly hairy math using logarithms called the Steinhart-Hart equation. This equation needs to know two things about the thermistor: its resistance at 25°C (called R0) and a constant for the thermistor called Beta, or sometimes just B. If you use a different thermistor, you will need to plug these values into the code when you call read_temp_c. For example:

read_temp_c(self, B=3800.0, R0=1000.0)

Note that a capacitor typically has an accuracy of only 10%, and thermistors are similarly inaccurate in their value of R0, so do not expect massively accurate results.

See Also

To measure temperature using a TMP36, see Recipe 13.9.

To measure temperature using a digital temperature sensor (DS18B20), see Recipe 13.12.

To measure temperature using a Sense HAT, see Recipe 13.11.

13.4 Detecting Methane

Problem

You want to measure gas levels using a methane sensor.

Solution

Low-cost resistive gas sensors are available that can easily be wired to a Raspberry Pi to detect gases such as methane. You can use the step response method that you first used in Recipe 13.1.

To make this recipe, you will need the following:

Breadboard and jumper wires (see “Prototyping Equipment and Kits”)

Methane sensor (see “Modules”)

Two 1kΩ resistors (see “Resistors and Capacitors”)

330 nF capacitor (see “Resistors and Capacitors”)

The sensor contains a heating element that requires 5V at up to 150mA. The Raspberry Pi is capable of providing this as long as its power supply can provide the extra 150mA.

The sensor module has rather thick legs—too thick to fit into breadboard holes. One way around this is to solder short lengths of solid core wire to each lead (Figure 13-6). Another is to buy SparkFun’s gas sensor breakout board.

Figure 13-6. Soldering leads onto the gas sensor

Wire the breadboard as shown in Figure 13-7 if you’re using the SparkFun breakout board, or as shown in Figure 13-8 if you soldered longer leads to the gas sensor.

Note that the direct connection shown in Figure 13-8 uses the same symbol for the breakout board rather than the sensor on its own, but if you look carefully, the connections are to the six sensor pins, not the four pins of the breakout.

Figure 13-7. Connecting a methane gas sensor to a Raspberry Pi (breakout board)

Figure 13-8. Connecting a methane gas sensor to a Raspberry Pi (direct)

You can use the exact same program as Recipe 13.1, and you can test the methane sensor by breathing on it. You should see the readings from the sensor drop when you breathe on it.

Discussion

The obvious use of a methane gas sensor is for novelty fart-detecting projects. A more serious use would be for detecting leaks of natural gas. You could, for instance, imagine a Raspberry Pi home-watch project that monitored the home with various sensors. It could then send you an email while you are on vacation informing you that your house is about to explode. Or maybe not.

These types of sensors (Figure 13-9) use a heating element that warms a resistive surface impregnated with a catalyst sensitive to a particular gas. When the gas is present, the resistance of the catalyst layer changes.

Figure 13-9. A methane gas sensor

Both the heater and the sensing surface are electrically just resistors. So both can be connected either way around.

This particular gas sensor is most sensitive to methane, but it will also detect other gases to a lesser extent. That is why breathing on the sensor alters the reading, as healthy individuals will not normally breathe out methane. The cooling effect of blowing on the element can also have an effect.

See Also

You can find the datasheet for this sensor at http://bit.ly/1gYupsu. This will give you all sorts of useful information about the sensor’s sensitivity to various gases.

There are a range of these low-cost sensors available for sensing different gases. For a list of sensors offered by SparkFun, see the SparkFun website.

13.5 Measuring CO₂ Concentration

Problem

Carbon dioxide (CO₂) concentration is an indicator of air quality. You want to use your Raspberry Pi to measure this quality using a special sensor.

Solution

Use a low-cost (well, relatively low-cost) MH-Z14A CO₂ sensor module, shown connected to a Raspberry Pi in Figure 13-10.

Figure 13-10. An MH-Z14A CO₂ sensor connected to a Raspberry Pi

To make this recipe, you will need the following:

An MH-Z14A CO₂ sensor module (see “Modules”)

Female-to-female jumper wires (see “Prototyping Equipment and Kits”)

Make the following connections between the Z14A sensor and your Raspberry Pi:

Pin 16 of the MH-Z14A to GND on the Raspberry Pi

Pin 17 of the MH-Z14A to 5V on the Raspberry Pi

Pin 18 of the MH-Z14A to GPIO 14 (TXD) on the Raspberry Pi

Pin 19 of the MH-Z14A to GPIO 15 (RXD) on the Raspberry Pi

This sensor uses the serial port. This means that for it to work, you must follow Recipe 2.6. Note that even though you want to enable the serial port hardware, you should not enable the serial console option.

The following test program reads the level of CO₂ from the sensor and reports it once per second (ch_13_co2.py):

import serial, time

request_reading = bytes([0xFF, 0x01, 0x86, 0x00, 0x00, 0x00,
                        0x00, 0x00, 0x79])

def read_co2():
    sensor.write(request_reading)
    time.sleep(0.1)
    raw_data = sensor.read(9)
    high = raw_data[2]
    low = raw_data[3]
    return high * 256 + low;

sensor = serial.Serial('/dev/ttyS0')
print(sensor.name)
if sensor.is_open:
    print("Open")

while True:
    print("CO2 (ppm):" + str(read_co2()))
    time.sleep(1)

As with all the program examples in this book, you can also download this program (see Recipe 3.22).

When the program is run, the CO₂ level should (unless you are in a small, unventilated room) be about 400 ppm. If you breath on the sensor for a few seconds, the readings will slowly begin to rise and then fall back to a normal reading over the next few minutes:

$ python3 ch_13_co2.py
/dev/ttyS0
Open
CO2 (ppm):489
CO2 (ppm):483
CO2 (ppm):483
CO2 (ppm):481
CO2 (ppm):491
CO2 (ppm):517
CO2 (ppm):619
CO2 (ppm):734
CO2 (ppm):896
CO2 (ppm):1367

The sensor uses a request/response communication protocol. So when you want to receive a reading from the sensor, you first need to send the 9-byte message contained in request_reading. The sensor will immediately respond with a 9-byte message. We are interested only in bytes 2 and 3 that contain the high and low bytes of the CO₂ reading in ppm.

Discussion

Normal levels of CO₂ are around 400 to 1,000 ppm. Above that, the air can begin to feel stale, and you might feel drowsy. Studies have shown that high levels of CO₂ because of poor ventilation can result in decreased mental performance.

As a result of running the program overnight, I now leave the window and/or door ajar in my bedroom.

See Also

Learn more about the Z14A protocol.

Find more information about safe levels of CO₂.

13.6 Measuring a Voltage

Problem

You want to measure an analog voltage.

Solution

The Raspberry Pi GPIO connector has only digital inputs. If you want to measure a voltage, you need to use a separate analog-to-digital converter (ADC).

Use the MCP3008 eight-channel ADC chip. This chip actually has eight analog inputs, so you can connect up to eight sensors to one of these and interface to the chip using the Raspberry Pi SPI.

To make this recipe, you will need the following:

Breadboard and jumper wires (see “Prototyping Equipment and Kits”)

MCP3008 eight-channel ADC integrated circuit (IC) (see “Integrated Circuits”)

10kΩ trimpot (see “Resistors and Capacitors”)

Figure 13-11 shows the breadboard layout for using this chip. Make sure that you get the chip facing the proper direction. The little notch in the package should be toward the top of the breadboard.

Figure 13-11. Using an MCP3008 ADC IC with a Raspberry Pi

The variable resistor has one end connected to 3.3V and the other to ground, which allows the middle connection to be set to any voltage between 0 and 3.3V.

Before trying the program, make sure you have SPI enabled (Recipe 9.5).

Open an editor and paste in the following code (ch_13_adc_test.py):

from gpiozero import MCP3008
import time

analog_input = MCP3008(channel=0)

while True:
    reading = analog_input.value
    voltage = reading * 3.3
    print("Reading={:.2f}\tVoltage={:.2f}".format(reading, voltage))
    time.sleep(1)

As with all the program examples in this book, you can also download this program (see Recipe 3.22).

When you run the program, you should see output like this:

$ python3 ch_13_adc_test.py
Reading=0.60 Voltage=2.00
Reading=0.54 Voltage=1.80
Reading=0.00 Voltage=0.00
Reading=0.00 Voltage=0.00
Reading=0.46 Voltage=1.53
Reading=0.99 Voltage=3.28

The readings from the MCP3008 channel are between 0 and 1. You can convert these into a voltage by multiplying by 3.3 (the supply voltage).

Discussion

The MCP3008 has 10-bit ADCs, so when you take a reading, it gives you a number between 0 and 1023. The MCP3008 class converts this into a voltage reading by multiplying the reading by the voltage range (3.3V) and then dividing it by 1,024.

You can combine any of the following recipes that use the MCP3008 to allow readings to be taken from up to eight sensors.

You can also use resistive sensors with the MCP3008 by combining them with a fixed-value resistor and arranging them as a voltage divider (see Recipe 13.7 and Recipe 13.8).

See Also

If you’re just interested in detecting the turning of a knob, you can use a rotary encoder instead of a pot (Recipe 12.7).

You can also detect the position of a pot without the use of an ADC chip by using the step response method (Recipe 13.1).

Check out the datasheet for the MCP3008.

The Explorer HAT Pro from Pimoroni also has an ADC (Recipe 9.17).

13.7 Reducing Voltages for Measurement

Problem

You want to measure a voltage, but it is higher than the 3.3V possible using an MCP3008 (Recipe 13.6).

Solution

Use a pair of resistors to act as a voltage divider to reduce the voltage to a suitable range.

To try this recipe, you will need the following:

Breadboard and jumper wires (see “Prototyping Equipment and Kits”)

MCP3008 eight-channel ADC IC (see “Integrated Circuits”)

10kΩ resistor (see “Resistors and Capacitors”)

3.3kΩ resistor (see “Resistors and Capacitors”)

9V battery and clip lead

Figure 13-12 shows the arrangement for this, using a breadboard. The setup will measure the voltage of the battery.

Figure 13-12. Reducing the voltage of analog inputs

Warning

Never use this recipe to measure high-voltage AC, or any type of AC, for that matter. It is for low-voltage DC only.

Open an editor and paste in the following code (ch_13_adc_scaled.py):

from gpiozero import MCP3008
import time

R1 = 10000.0
R2 = 3300.0
analog_input = MCP3008(channel=0)

while True:
    reading = analog_input.value
    voltage_adc = reading * 3.3
    voltage_actual =  voltage_adc / (R2 / (R1 + R2))
    print("Battery Voltage=" + str(voltage_actual))
    time.sleep(1)

As with all the program examples in this book, you can also download this program (see Recipe 3.22).

The program is very similar to that of Recipe 13.6. The main difference is the scaling, using the values of the two resistors. The values of these two resistors are held in the variables R1 and R2.

When you run the program, the battery voltage is displayed:

$ sudo python adc_scaled.py
Battery Voltage=8.62421875

Warning

Read the discussion carefully before attaching anything higher than 9V, or you might destroy the MCP3008.

Discussion

This arrangement of resistors is called a voltage divider or sometimes a potential divider (Figure 13-13). The formula for calculating the output voltage, given the input voltage and the values of the two resistors, is as follows:

Vout = Vin * R2 / (R1 + R2)

Figure 13-13. A voltage divider

This means that if R1 and R2 were both the same value (say, 1kΩ), Vout would be half of Vin.

When choosing R1 and R2, you also need to consider the current flowing through R1 and R2. This will be Vin/(R1 + R2). In the preceding example, R1 is 10kΩ and R2 is 3.3kΩ, so the current flowing will be 9V/13.3kΩ = 0.68mA. This is low but still enough to eventually drain the battery, so do not leave it connected all the time.

See Also

To avoid the math, you can use an online resistor calculator.

The voltage divider is also used to convert resistance to voltage when using a resistive sensor with an ADC (Recipe 13.8).

13.8 Using Resistive Sensors with an ADC

Problem

You have a resistive sensor that you wish to use with an MCP3008 ADC chip.

Solution

Use a potential divider with one fixed resistor and the resistive sensor to convert the resistance of the sensor into a voltage that can be measured with the ADC.

As an example, you can remake the light sensor project of Recipe 13.2 to use the MCP3008 instead of the step response technique.

To try this recipe, you will need the following:

Breadboard and jumper wires (see “Prototyping Equipment and Kits”)

MCP3008 eight-channel ADC IC (see “Integrated Circuits”)

10kΩ resistor (see “Resistors and Capacitors”)

Photoresistor (see “Resistors and Capacitors”)

Figure 13-14 shows the arrangement for this, using a breadboard.

Figure 13-14. Using a photoresistor with an ADC

You can use the exact same program as Recipe 13.6 (ch_13_adc_test.py). Covering up the light sensor with your hand changes the readings. You also need to set up SPI on your Raspberry Pi, so if you haven’t already done so, follow Recipe 9.5:

$ python3 ch_13_adc_test.py
Reading=0.60 Voltage=2.00
Reading=0.54 Voltage=1.80

These readings can be quite a bit different, depending on your photoresistor, but the important thing is that the figure changes as the light level changes.

Discussion

The choice of fixed-value resistor is not very critical. If the value is too high or too low, you will find that the range of readings is rather narrow. Select a resistor value somewhere between the minimum and maximum resistance of the sensor. You might need to experiment with a few resistors before deciding on one that suits your sensor over the range of readings you’re interested in. If in doubt, start with 10kΩ and see how that works.

You can swap out the photoresistor for pretty much any resistive sensor. So, for instance, you could use the gas sensor from Recipe 13.4.

See Also

To measure light intensity without the complication of an ADC, see Recipe 13.2.

For an example of using more than one channel of the ADC at a time, see Recipe 13.13.

13.9 Measuring Temperature with an ADC

Problem

You want to measure temperature using a TMP36 and an analog-to-digital converter (ADC).

Solution

Use an MCP3008 ADC chip.

However, unless you need more than one analog channel, you should consider using the DS18B20 digital temperature sensor, which is more accurate and doesn’t require a separate ADC chip (Recipe 13.12).

To try this recipe, you will need the following:

Breadboard and jumper wires (see “Prototyping Equipment and Kits”)

MCP3008 eight-channel ADC IC (see “Integrated Circuits”)

TMP36 temperature sensor (see “Integrated Circuits”)

Figure 13-15 shows the arrangement for this, using a breadboard.

Figure 13-15. Using a TMP36 with an ADC

Make sure that you get the TMP36 facing the proper direction. One side of the package is flat, whereas the other is curved.

You will need to set up SPI on your Raspberry Pi, so if you haven’t already done so, follow Recipe 9.5.

Open an editor and paste in the following code (ch_13_adc_tmp36.py):

from gpiozero import MCP3008
import time

analog_input = MCP3008(channel=0)

while True:
    reading = analog_input.value
    voltage = reading * 3.3
    temp_c = voltage * 100 - 50
    temp_f = temp_c * 9.0 / 5.0 + 32
    print("Temp C={:.2f}\tTemp F={:.2f}".format(temp_c, temp_f))
    time.sleep(1)

As with all the program examples in this book, you can also download this program (see Recipe 3.22).

The program is based on that of Recipe 13.6. A little bit of additional math calculates the temperature in degrees Celsius and Fahrenheit:

$ python3 ch_13_adc_tmp36.py
Temp C=18.64        Temp F=65.55
Temp C=20.25        Temp F=68.45
Temp C=23.47        Temp F=74.25
Temp C=25.08        Temp F=77.15

Discussion

The TMP36 outputs a voltage that is proportional to the temperature. According to the datasheet for the TMP36, the temperature in degrees Celsius is calculated as the voltage (in volts) × 100 – 50.

The TMP36 is fine for measuring the approximate temperature but is specified as having an accuracy of only 2°C. This will only get worse if you attach long leads to it. To some extent, you can calibrate an individual device, but for better accuracy, use a DS18B20 (Recipe 13.12), which has a stated accuracy of 0.5% over a temperature range of –10 to +85°C. Being a digital device, it should not suffer any loss of accuracy when attached to long leads.

See Also

Take a look at the TMP36 datasheet.

To measure temperature using a thermistor, see Recipe 13.3.

To measure temperature using a digital temperature sensor (DS18B20), see Recipe 13.12.

To measure temperature using a Sense HAT, see Recipe 13.11.

13.10 Measuring the Raspberry Pi CPU Temperature

Problem

You want to know just how hot your Raspberry Pi’s CPU is getting.

Solution

Use the os library to access the temperature sensor built into the Broadcom chip.

Open an editor and paste in the following code (ch_13_cpu_temp.py):

import os, time

while True:
    dev = os.popen('/opt/vc/bin/vcgencmd measure_temp')
    cpu_temp = dev.read()
    print(cpu_temp)
    time.sleep(1)

As with all the program examples in this book, you can also download this program (see Recipe 3.22).

When you run this program, it reports the temperature. Note that the message printed is actually a string with temp= before the temperature and 'C after it:

$ python3 ch_13_cpu_temp.py
temp=33.6'C
temp=33.6'C

Discussion

If you want the temperature as a number rather than a string, you need to chop off the extra text and then convert the number to a float. You can find an example program for this in ch_13_cpu_temp_float.py:

import os, time

while True:
    dev = os.popen('/opt/vc/bin/vcgencmd measure_temp')
    cpu_temp_s = dev.read()[5:-3] # top and tail string
    cpu_temp = float(cpu_temp_s)
    print(cpu_temp)
    time.sleep(1)

See Also

For more information on chopping up strings, see Recipe 5.15.

To measure temperature using a thermistor, see Recipe 13.3.

To measure temperature using a TMP36, see Recipe 13.9.

To measure temperature using a digital temperature sensor (DS18B20), see Recipe 13.12.

To measure temperature using a Sense HAT, see Recipe 13.11.

13.11 Measuring Temperature, Humidity, and Pressure with a Sense HAT

Problem

You want to measure temperature, humidity, and pressure, but you don’t really want to have to attach three separate sensors.

Solution

Use a Raspberry Pi Sense HAT (Figure 13-16). That way, you get all of those sensors plus some extras, like a display.

Figure 13-16. A Sense HAT

The Sense Hat software comes preinstalled on Raspbian.

Open an editor and paste in the following code (ch_13_sense_hat_thp.py):

from sense_hat import SenseHat
import time

hat = SenseHat()

while True:
    t = hat.get_temperature()
    h = hat.get_humidity()
    p = hat.get_pressure()
    print('Temp C:{:.2f} Hum:{:.0f} Pres:{:.0f}'.format(t, h, p))
    time.sleep(1)

As with all the program examples in this book, you can also download this program (see Recipe 3.22).

When you run the program, the Terminal displays something like this:

$ python3 ch_13_sense_hat_thp.py
Temp C:27.71 Hum:56 Pres:1005
Temp C:27.60 Hum:55 Pres:1005

The temperature is in degrees C, the humidity is the percentage of relative humidity, and the atmospheric pressure is in millibars.

Discussion

You will find that the temperature readings from the Sense HAT are on the high side. This is because the temperature sensor is built into the humidity sensor and is on the Sense HAT PCB. The Sense HAT generates very little heat (unless you use the display), but the Raspberry Pi under the Sense HAT does get warm and will increase the temperature of the HAT. The best way to avoid this problem is to use a 40-way ribbon cable to move the Sense HAT away from the Raspberry Pi. There are also attempts to adjust the readings by using the temperature reading of the Raspberry Pi, and you can follow a discussion on that at http://bit.ly/1OfEEWf. Personally, I feel that these compensation attempts are probably very specific to the users posting and are unlikely to produce reliable results.

As well as reading the temperature from the humidity sensor, the pressure sensor also has a temperature sensor built in that you can read like this:

t = hat.get_temperature_from_pressure()

It is unclear from the documentation as to whether this reading is any more accurate than using the humidity sensor, but for my setup, it reported temperatures about 1 degree Celsius lower than the humidity sensor.

See Also

To get started with the Sense HAT, see Recipe 9.16.

The programming reference for the Sense HAT is available here.

The Sense HAT also has an accelerometer, a gyroscope (Recipe 13.15), and a magnetometer (Recipe 13.14) for navigation-type projects. It also has a full-color 8×8 LED matrix display (Recipe 14.3).

13.12 Measuring Temperature Using a Digital Sensor

Problem

You want to measure temperature using an accurate digital sensor.

Solution

Use the DS18B20 digital temperature sensor. This device is more accurate than the TMP36 used in Recipe 13.9, and it uses a digital interface, so it doesn’t require an ADC chip.

Although the interface to this chip is called one-wire, this just refers to the data pin. You do need at least one other wire to connect to a one-wire device.

To make this recipe, you will need the following:

Breadboard and jumper wires (see “Prototyping Equipment and Kits”)

DS18B20 temperature sensor (see “Integrated Circuits”)

4.7kΩ resistor (see “Resistors and Capacitors”)

Fit the components onto the breadboard as shown in Figure 13-17. Make sure that you get the DS18B20 facing the proper direction.

Figure 13-17. Connecting a DS18B20 to a Raspberry Pi

The latest version of Raspbian has support for the one-wire interface used by the DS18B20, but you do need to enable it using the Raspberry Pi Configuration tool (Figure 13-18).

Figure 13-18. Enabling the one-wire interface

Open an editor and paste in the following code (ch_13_temp_DS18B20.py):

import glob, time

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:
    temp_c, temp_f = read_temp()
    print('Temp C={:.2f}\ttemp F={:.2f}'.format(temp_c, temp_f))
    time.sleep(1)

As with all the program examples in this book, you can also download it (see Recipe 3.22).

When the program is run, it reports the temperature once per second in both degrees Celsius and degrees Fahrenheit:

$ python3 ch_13_temp_DS18B20.py
temp C=25.18   temp F=77.33
temp C=25.06   temp F=77.11
temp C=26.31   temp F=79.36
temp C=28.87   temp F=83.97

Discussion

At first sight, the program looks a little odd. The interface to the DS18B20 uses a file-like interface. The file interface for the device will always be in the folder /sys/bus/w1/devices/, and the name of the file path will start with 28, but the rest of the file path will be different for each sensor.

The code assumes that there will be only one sensor and finds the first folder starting with 28. To use multiple sensors, use different index values inside the square brackets.

Within that folder will be a file called w1_slave, which is opened and read to find the temperature.

The sensor actually returns strings of text like this:

81 01 4b 46 7f ff 0f 10 71 : crc=71 YES
81 01 4b 46 7f ff 0f 10 71 t=24062

The remainder of the code extracts the temperature part of this message. This appears after t= and is the temperature in one-thousandths of a degree Celsius.

The read_temp function calculates the temperature in both degrees Celsius and degrees Fahrenheit and returns both values.

In addition to the basic chip version of the DS18B20, you can also buy a version encapsulated in a rugged and waterproof probe.

See Also

To find out about logging readings, see Recipe 13.23.

This recipe is heavily based on this Adafruit tutorial.

Take a look at the datasheet for the DS18B20.

To measure temperature using a thermistor, see Recipe 13.3.

To measure temperature using a TMP36, see Recipe 13.9.

To measure temperature using a Sense HAT, see Recipe 13.11.

13.13 Measuring Acceleration with an MMA8452Q Module

Problem

You want to connect a triple-axis accelerometer to a Raspberry Pi.

Solution

Use an I2C accelerometer chip to measure the X, Y, and Z analog outputs.

To try this recipe, you will need the following:

Breadboard (see “Prototyping Equipment and Kits”)

Four female-to-female jumper wires (see “Prototyping Equipment and Kits”)

MMA8452Q triple-axis accelerometer (see “Modules”)

Figure 13-19 shows the arrangement for this, using a breadboard. It uses three channels of the ADC to measure the X, Y, and Z acceleration forces.

Figure 13-19. Using a triple-axis I2C accelerometer

You will need to enable I2C on your Raspberry Pi, so if you have not already done so, follow Recipe 9.3.

Open an editor and paste in the following code (ch_13_i2c_acc.py):

import smbus
import time

bus = smbus.SMBus(1)

i2c_address = 0x1D
control_reg = 0x2A

bus.write_byte_data(i2c_address, control_reg, 0x01) # Start
bus.write_byte_data(i2c_address, 0x0E, 0x00) # 2g range

time.sleep(0.5)

def read_acc():
    data = bus.read_i2c_block_data(i2c_address, 0x00, 7)
    x = (data[1] * 256 + data[2]) / 16
    if x > 2047 :
        x -= 4096
    y = (data[3] * 256 + data[4]) / 16
    if y > 2047 :
        y -= 4096
    z = (data[5] * 256 + data[6]) / 16
    if z > 2047 :
        z -= 4096
    return (x, y, z)

while True:
    print("x={:.6f}\ty={:.6f}\tz={:.6f}".format(x, y, z))
    time.sleep(0.5)

As with all the program examples in this book, you can also download this program (see Recipe 3.22).

The program reads the three forces and prints them out:

$ python3 ch_13_i2c_acc.py
x=-933.000000 y=251.000000 z=-350.000000
x=-937.000000 y=257.000000 z=-347.000000
x=-933.000000 y=262.000000 z=-350.000000
x=-931.000000 y=259.000000 z=-355.000000
x=-1027.000000 y=-809.000000 z=94.000000

Tilt the accelerometer in various directions to see how the readings change. A reading of 0 indicates no net force. Positive values (up to 2047 for 2g) indicate force in one direction and negative in the opposite. You can see that the Z force is close to –1023 (1g).

Discussion

You might need to change the I2C address of your device. You can check this by wiring it up and then running the following command:

$ sudo i2cdetect -y 1
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- 1d -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --

As you can see, in this case, the module that I used has an I2C address of 1d. Thus, that is what the variable i2c_address is set to in the program.

Referring to the preceding Python code, the device has a control register to which a command 1 must be written to start the device running. A configuration command of 1 is then written to a control register (control_reg) to set the acceleration range of the device to a maximum of 2g. These parameters are specified in the datasheet for the MMA8452Q.

When a reading is required, the I2C bus is read and the data bytes split into the three X, Y, and Z acceleration readings.

The most common use for an accelerometer is to detect tilt. This works because the Z-axis force is dominated by the pull of gravity (Figure 13-20).

When the accelerometer is tilted in one direction, some of that vertical force of gravity becomes active on another axis of the accelerometer.

Figure 13-20. Detecting tilt with an accelerometer

We can use this principle to detect when the tilt is past a certain threshold. The following program (ch_13_i2c_acc_tilt.py) illustrates this point:

import smbus
import time

bus = smbus.SMBus(1)

i2c_address = 0x1D
control_reg = 0x2A

bus.write_byte_data(i2c_address, control_reg, 0x01) # Start
bus.write_byte_data(i2c_address, 0x0E, 0x00) # 2g range

time.sleep(0.5)

def read_acc():
    data = bus.read_i2c_block_data(i2c_address, 0x00, 7)
    x = (data[1] * 256 + data[2]) / 16
    if x > 2047 :
        x -= 4096
    y = (data[3] * 256 + data[4]) / 16
    if y > 2047 :
        y -= 4096
    z = (data[5] * 256 + data[6]) / 16
    if z > 2047 :
        z -= 4096
    return (x, y, z)

while True:
    x, y, z = read_acc()
    if x > 400:
        print("Left")
    elif x < -400:
        print("Right")
    elif y > 400:
        print("Back")
    elif y < -400:
        print("Forward")
    time.sleep(0.2)

When you run the program, you will begin to see direction messages:

$ python3 ch_13_i2c_acc_tilt.py
Left
Left
Right
Forward
Forward
Back
Back

You could use this to control a roving robot or a motorized pan-tilt head with a webcam attached.

See Also

To find out more about the MMA8452Q, see https://www.nxp.com/docs/en/data-sheet/MMA8452Q.pdf.

The Sense HAT includes an accelerometer (Recipe 13.15).

13.14 Finding Magnetic North with the Sense HAT

Problem

You want to use a Sense HAT to detect magnetic north.

Solution

Use the Python library for the built-in three-axis magnetometer in the Sense HAT.

First follow Recipe 9.16 to install the Sense HAT library.

Open an editor and paste in the following code (ch_13_sense_hat_compass.py):

from sense_hat import SenseHat
import time

sense = SenseHat()

while True:
    bearing = sense.get_compass()
    print('Bearing: {:.0f} to North'.format(bearing))
    time.sleep(0.5)

As with all the program examples in this book, you can also download this program (see Recipe 3.22).

When you run this program, you will see a series of bearing readings:

$ python3 ch_13_sense_hat_compass.py
Bearing: 138 to North
Bearing: 138 to North

Discussion

The compass will be sensitive to other nearby sources of magnetic field, so you might find it difficult to get accurate bearings.

See Also

You can find documentation for Sense HAT at https://github.com/RPi-Distro/python-sense-hat and http://pythonhosted.org/sense-hat/api.

To use the Sense HAT to detect a magnet, see Recipe 13.17.

13.15 Using the Inertial Management Unit of the Sense HAT

Problem

You want more accurate orientation information from your Raspberry Pi than the accelerometer from Recipe 13.13 provides.

Solution

Use the Inertial Management Unit (IMU) of the Sense HAT. This unit includes a three-axis accelerometer like the one in Recipe 13.13, but it also has a three-axis gyroscope and a magnetometer. The readings from these different sensors are combined to let you get a more accurate orientation for the Sense HAT, expressed as pitch, roll, and yaw (as shown in Figure 13-21).

Figure 13-21. Pitch, roll, and yaw

Pitch, roll, and yaw are three terms that come from aviation. They are relative to the axis of the plane’s flight. The pitch is the angle to the horizontal. The roll is the degree of rotation around the plane’s axis of flight (imagine one wing going up and the other down), and yaw is the rotation on the horizontal axis (think changing bearing).

Open an editor and paste in the following code (ch_13_sense_hat_orientation.py):

from sense_hat import SenseHat

sense = SenseHat()

sense.set_imu_config(True, True, True)

while True:
    o = sense.get_orientation()
    print("p: {:.0f}, r: {:.0f}, y: {:.0f}".format(o['pitch'], o['roll'],
o['yaw']))

As with all the program examples in this book, you can also download this program (see Recipe 3.22).

The function set_imu_config specifies which of the compass, gyroscope, and accelerometer (in that order) should be used to measure the orientation. Setting all three to True will mean that all are used to make the measurement.

When you run the program, you will see output similar to this:

$ python3 ch_13_sense_hat_orientation.py
p: 1, r: 317, y: 168
p: 1, r: 318, y: 169

Try tilting the Sense HAT and Raspberry Pi forward toward the USB ports, and you should see the value of pitch increase.

Discussion

An accelerometer measures forces on a stationary mass and can therefore measure the degree of tilt by calculating how much of the force supplied by gravity (Z-axis) influences the force measured on the X- and Y- axes.

A gyroscope is different. It measures the force on moving masses (vibrating back and forth) as those masses turn relative to the path of the movement, using a force called the Coriolis effect.

See Also

For more information on the Sense HAT’s IMU, see https://oreil.ly/Tr8YV.

To measure temperature, humidity, and atmospheric pressure, see Recipe 13.11.

The IMU of the Sense HAT can also be used to make a compass and detect the presence of a magnet (Recipe 13.17).

To find out more about gyroscopes and the Coriolis effect, see https://oreil.ly/TXHIz.

13.16 Sensing a Magnet with a Reed Switch

Problem

You want to detect the presence of a magnet.

Solution

Use a reed switch (Figure 13-22). It works just like a regular switch except it activates only when a magnet is near. Figure 13-23 shows how a reed switch works.

Figure 13-22. A reed switch

Figure 13-23. How a reed switch works

The two reed contacts are encased in a a glass tube. When a magnet is placed near the reed switch, the reeds are pulled together and make contact.

You can use any of the regular switch recipes in Chapter 12 with a reed switch, starting with Recipe 12.1.

Discussion

Reed switches are a low-tech way of detecting a magnet. They have been around since the 1930s and are extremely reliable. They are also commonly used in security systems where a plastic-encased reed switch is placed on a door frame, with a fixed magnet in another plastic enclosure on the door itself. When the door opens, the reed switch contacts open, triggering the alarm.

See Also

To detect a magnet using the magnetometer of the Sense HAT, see Recipe 13.17.

13.17 Sensing a Magnet with the Sense HAT

Problem

You want to detect the presence of a magnet, using a Sense Hat with built-in magnetometer and a Python program.

Solution

Use the Sense HAT’s Python library to interface with its magnetometer.

Open an editor and paste in the following code (ch_13_sense_hat_magnet.py):

from sense_hat import SenseHat
import time

hat = SenseHat()
fill = (255, 0, 0)

while True:
    reading = int(hat.get_compass_raw()['z'])
    if reading > 200:
        hat.clear(fill)
        time.sleep(0.2)
    else:
        hat.clear()

As with all the program examples in this book, you can also download this program (see Recipe 3.22).

When the magnet draws close to the Sense HAT, the LEDs will all turn red for one-fifth of a second.

Discussion

It doesn’t matter which axis of the compass data you use; all three will be greatly disrupted by the presence of a fixed magnet.

See Also

To detect a magnet using a reed switch, see Recipe 13.16.

For other ways to use the Sense HAT display, see Recipe 14.3.

13.18 Measuring Distance Using Ultrasound

Problem

You want to measure distance using an ultrasonic rangefinder.

Solution

Use a low-cost HC-SR04 rangefinder. This device needs two GPIO pins: one to trigger the pulse of ultrasound and the other to monitor how long it takes for the echo to return.

To make this recipe, you will need the following:

Breadboard and jumper wires (see “Prototyping Equipment and Kits”)

HC-SR04 rangefinder (eBay)

470Ω resistor (see “Resistors and Capacitors”)

270Ω resistor (see “Resistors and Capacitors”)

Fit the components onto the breadboard as shown in Figure 13-24. The resistors are necessary to reduce the echo output of the rangefinder from 5V to 3.3V (see Recipe 9.12).

Open an editor and paste in the following code (ch_13_ranger.py):

from gpiozero import DistanceSensor
from time import sleep

sensor = DistanceSensor(echo=18, trigger=17)
while True:
    cm = sensor.distance * 100
    inch = cm / 2.5
    print("cm={:.0f}\tinches={:.0f}".format(cm, inch))
    sleep(0.5)

As with all the program examples in this book, you can also download this program (see Recipe 3.22).

Figure 13-24. Connecting an SR04 rangefinder to a Raspberry Pi

The operation of the program is described in the Discussion. When the program is run, it reports the distance in both centimeters and inches once per second. Use your hand or some other obstacle to change the reading:

$ python3 ch_13_ranger.py
cm=154.7   inches=61.8
cm=12.9	   inches=5.1
cm=14.0	   inches=5.6
cm=20.2	   inches=8.0

Discussion

Although there are a number of ultrasonic rangefinders available, the type used here is easy to use and low cost. It works by sending a pulse of ultrasound and then measuring the amount of time taken for the echo to be received. One of the round ultrasonic transducers on the front of the device is the transmitter, and the other is the receiver.

This process is controlled from the Raspberry Pi. The difference between this type of device and more expensive models is that the more expensive versions include their own microcontroller, which carries out all the necessary timing and provides an I2C or Serial interface to return a final reading.

When you are using one of these sensors with a Raspberry Pi, the trig (trigger) input of the rangefinder is connected to a GPIO output, and the echo output of the rangefinder is connected to a GPIO input on the Raspberry Pi after having its voltage range lowered from 5V to a safe 3.3V.

Figure 13-25 shows an oscilloscope trace of the sensor in action. The top (red) trace is connected to trig, and the bottom (yellow) trace is connected to echo. You can see that first the trig pin is taken high for a short pulse. There is then a short delay before the echo pin goes high. This stays high for a period that is proportional to the distance from the sensor.

Figure 13-25. The oscilloscope trace for trigger and echo

This program makes use of the DistanceSensor class of the gpiozero library, which takes care of the pulse generation and measurement for us.

This method of measuring distance is not terribly accurate because temperature, pressure, and relative humidity all alter the speed of sound and hence the distance readings.

See Also

Take a look at the datasheet for the ultrasonic rangefinder.

The documentation for the DistanceSensor class is available here.

13.19 Measuring Distance Using a Time-of-Flight Sensor

Problem

You want to measure distance without using ultrasound (perhaps you have animals who would be frightened by ultrasound, or you want to measure distance more accurately).

Solution

Use a VL53L1X I2C Time-of-Flight (ToF) sensor. These sensors are more expensive than their ultrasound equivalents. However, because they use light rather than sound, they are more accurate.

The most common of these devices is the VL53L1X, and it’s available as a low-cost module from eBay as well as from other suppliers. The Pimoroni device we are using here has the advantage that it is compatible with the Pimoroni Breakout Garden system and can therefore be plugged in without any soldering. Figure 13-26 shows the ToF sensor and Breakout Garden.

Figure 13-26. A VL53L1X ToF sensor and Pimoroni Breakout Garden

To make this project, you will need either:

Pimoroni Breakout Garden (see “Prototyping Equipment and Kits”)

Pimoroni VL53L1X Distance Sensor (see “Modules”)

or:

Generic VL53L1X Distance Sensor Module (see “Modules”)

Four male-to-female jumper wires (see “Prototyping Equipment and Kits”)

Connecting this I2C device to a Raspberry Pi is just like connecting any other. The device will work at 3V, so as well as connecting 3V and GND, you should connect the SDA pin of the sensor to the SDA pin of the Raspberry Pi (also called GPIO 2) and the SCL pin of the sensor to the SCL pin of the Raspberry Pi (GPIO 3).

If you chose to use the Breakout Garden, just make sure you place the sensor in the appropriate orientation (see Figure 13-26), and if you are using jumper wires, connect the devices as follows:

The VCC pin of the VL53L1X to 3V on the Raspberry Pi

The GND pin of the VL53L1X to GND on the Raspberry Pi

The SDA pin of the VL53L1X to GPIO 2 (SDA) on the Raspberry Pi

The SCL pin of the VL53L1X to GPIO 3 (SCL) on the Raspberry Pi

The VL53L1X uses I2C, so you need to enable this, following Recipe 9.3. After you’ve enabled it, you will also need to run the following commands to install the software for the VL53L1X:

$ sudo pip3 install smbus2
$ sudo pip3 install vl53l1x

The test program for this recipe (ch_13_tof.py) prints the distance measurement in millimeters once per second:

import VL53L1X, time

tof = VL53L1X.VL53L1X(i2c_bus=1, i2c_address=0x29)
tof.open()
tof.start_ranging(1) # Start range1=Short 2=Medium 3=Long

while True:
    mm = tof.get_distance() # Grab the range in mm
    print("mm=" + str(mm))
    time.sleep(1)

As with all the program examples in this book, you can also download this program (see Recipe 3.22).

Note that if your device has a different I2C address, you might need to change 0x29 to the address of your device.

Discussion

The VL53L1X ToF sensor is an amazing little device that contains a low-power infrared laser and receiver as well as all the electronics needed to communicate over I2C.

The module works on a similar principle to that of the ultrasonic range-finder of Recipe 13.18, except that instead of gauging distance by measuring the time it takes for sound to travel to a target and back as a reflection, the ToF sensor measures the time it takes for a pulse of laser light to bounce back from a target.

See Also

To measure distance using ultrasonics, see Recipe 13.18.

See the datasheet for the VL53L1X.

13.20 Capacitive Touch Sensing

Problem

You want to provide a touch interface to your Raspberry Pi.

Solution

Use an Adafruit Capacitive Touch HAT (Figure 13-27).

Touch sensors are a lot of fun and are great for educational use. You can attach anything that conducts even just a little bit of electricity—including fruit. A popular project is to construct a fruit keyboard using alligator clips to attach a variety of fruits and vegetables to the sense terminals on the board. Then, as you touch the different items of fruit, different sounds are made.

The Adafruit Capacitive Touch HAT uses the Raspberry Pi’s I2C interface. You also need SPI tools installed, so if you have not already done so, follow Recipe 9.3 and Recipe 9.5.

Figure 13-27. An Adafruit Capacitive Touch HAT attached to an apple

To install the Python library for the HAT, run the following command:

$ sudo pip3 install adafruit-circuitpython-mpr121

Note that the first time I ran this command I received error messages, but just running the command for a second time installed correctly.

To test out the Capacitive Touch HAT, run the following program (ch_13_touch.py):

import time
import board
import busio
import adafruit_mpr121
i2c = busio.I2C(board.SCL, board.SDA)
mpr121 = adafruit_mpr121.MPR121(i2c)

while True:
    if mpr121[0].value:
        print("Pin 0 touched!")

As with all the program examples in this book, you can also download this program (see Recipe 3.22).

When you touch the pad labeled 0, you should see output like this:

$ python3 ch_13_touch.py
Pin 0 touched!
Pin 0 touched!

You can either just touch the connection pads or connect the pads to a piece of fruit using an alligator clip, as shown in Figure 13-27.

Discussion

The Adafruit Capacitive Touch HAT has 12 touch contacts. If you need only a few touch contacts, you can use the Pimoroni Explorer HAT Pro, which has four alligator-clip–compatible contacts (Figure 13-28).

Figure 13-28. The Explorer HAT Pro with fruit

To use the Explorer HAT Pro’s touch contacts, first follow Recipe 9.17 to install the library for the HAT.

In addition to the four terminals on the side, designed for alligator clips, there are four touch switches labeled 1 to 4 that also use the touch interface.

See Also

More information is available in the Adafruit Touch HAT documentation and the Explorer HAT Pro documentation.

13.21 Reading Smart Cards with an RFID Reader/Writer

Problem

You want to read from and write to Radio-Frequency Identification (RFID) smart cards.

Solution

Get a low-cost RC-522 RFID card reader/writer and use the SimpleMFRC522 Python library.

For this recipe, you will need the following:

RC-522 card reader; this is often sold with a selection of RFID tags to use (see “Modules”)

Seven female-to-female jumper wires (see “Prototyping Equipment and Kits”)

You can buy a kit containing these items (along with extra cards, an instruction book, and other useful items) in the form of the MonkMakes Clever Card Kit.

Figure 13-29 shows the RC-522 wired up to a Raspberry Pi. The RC-522 uses the Raspberry Pi’s SPI interface, so you will need to follow Recipe 9.5.

Figure 13-29. Connecting a Raspberry Pi and RC-522

Table 13-1 shows the connections you need to make using the jumper wires, with suggested colors for the leads to make it easy to identify which lead is which.

Table 13-1. Connecting a Raspberry Pi and an RFID Reader/Writer

Lead color
RC-522 pin
Raspberry Pi pin

Orange
SDA
GPIO8

Yellow

SCK
SCKL / GPIO11

White
MOSI
MOSI / GPIO10

Green
MISO
MISO/GPIO9

IRQ pin not used

Blue
GND
GND

Gray
RST
GPIO25

Red
3.3V
3.3V

Note that, although the RC-522 pin has some pins marked SDA and SCL as if the device were using I2C, in this recipe the device uses the Raspberry Pi’s SPI interface.

To use the module, first fetch the Clever Card Kit software using the commands that follow. This will install all of the prerequisite software needed for the RC-522. You will need to reboot when it’s done installing:

$ wget http://monkmakes.com/downloads/mmcck.sh
$ chmod +x mmcck.sh
$ ./mmcck.sh

To test the reader, run the program in the clever_card_kit directory called 01_read.py:

$ cd clever_card_kit/
pi@raspberrypi:~/clever_card_kit $ python3 01_read.py
Hold a tag near the reader
894922433952

894922433952

894922433952

When you hold a card next to the RC-522, the RFID tag inside the card’s unique number will be printed out. When you’ve had enough of reading cards, hit Ctrl-c. Here’s the code:

import RPi.GPIO as GPIO
import SimpleMFRC522

reader = SimpleMFRC522.SimpleMFRC522()

print("Hold a tag near the reader")

try:
    while True:
        id, text = reader.read()
        print(id)
        print(text)

finally:
    print("cleaning up")
    GPIO.cleanup()

The RPi.GPIO is imported merely so that it can be used to cleanup the GPIO pins when the program exits. The function call reader.read() will wait for an RFID tag to come near the reader/writer and return the card’s unique number (id) and any text message stored on the card (text).

You cannot change the unique number assigned to each tag during manufacture, but you can store small amounts of data on a card. To do this, use the program 02_write.py:

$ python3 02_write.py
New Text: Raspberry Pi
Now scan a tag to write
written
894922433952
Raspberry Pi
New Text:

Having written some text onto the card, you can check whether it’s there by using 01_read.py. Here’s the code for 02_write.py:

import RPi.GPIO as GPIO
import SimpleMFRC522

reader = SimpleMFRC522.SimpleMFRC522()

try:
    while True:
        text = input('New Text: ')
        print("Now scan a tag to write")
        id, text = reader.write(text)
        print("written")

        print(id)
        print(text)
finally:
    print("cleaning up")
    GPIO.cleanup()

The code is pretty self-explanatory.

Discussion

RFID tags are available in all sorts of shapes and sizes. But there are a number of different standards used that operate at different frequencies and use different communication protocols, so when looking for cards to work with the RC-522, look for cards described as 13.56 MHz. The SimpleMFRC522 code is also a bit fussy about the cards it will work with, so if you plan to use it, also look for tags described as being Mifare 1k compatible.

Because of the differences between what cards can store in their memory and how they store it, it’s often better not to rely on storing data on the tag but rather to use the card’s unique ID. You can then store data against that unique key. The programs 05_launcher_setup.py and 05_launcher.py in the clever_card_kit directory show how you can use this approach using table data stored in a pickle file (see Recipe 7.9).

See Also

More information is available in the full documentation of SimpleMFRC522 code.

13.22 Displaying Sensor Values

Problem

You have a sensor wired to your Raspberry Pi, and you want a big digital display of the reading on the screen.

Solution

Use the guizero library to open a window, and write the reading on it with a large font (Figure 13-30).

Figure 13-30. Displaying a sensor reading using guizero

This example uses data from the ToF rangefinder of Recipe 13.19. So complete that recipe first if you want to try out this example. Alternatively, most of the other sensor recipes in this chapter could be adapted to work with this recipe.

Test out the recipe by opening an editor and pasting in the following code (ch_13_gui_sensor_reading.py):

import VL53L1X, time
from guizero import App, Text

tof = VL53L1X.VL53L1X(i2c_bus=1, i2c_address=0x29)
tof.open()
tof.start_ranging(1)

def update_reading():
    mm = tof.get_distance()
    reading_text.value = str(mm)

app = App(width=300, height=150)
reading_text = Text(app, size=100)
reading_text.repeat(1000, update_reading)
app.display()

As with all the program examples in this book, you can also download this program (see Recipe 3.22).

The function update_reading gets a new reading from the rangefinder (or whatever sensor you have chosen to use) and sets the value of reading_text to be that value (as a string).

To ensure that the readings are updated automatically, the repeat method is called on reading_text with a first parameter of the number of milliseconds between updates (in this case, 1000) and a second parameter of the function to call (update_reading).

Discussion

Although this recipe uses a distance sensor, it works equally well with the other sensor recipes in this chapter. You just need to change the method of obtaining a reading from the sensor.

See Also

For information on formatting numbers to a certain number of decimal places, see Recipe 7.1.

For an example of displaying sensor data in a web browser rather than an application window, see Recipe 16.2.

13.23 Logging to a USB Flash Drive

Problem

You want to log data measured with a sensor onto a USB flash drive.

Solution

Write a Python program that writes the data to a file on a USB flash drive. By writing the file in comma-separated values (CSV) format, you can import it directly into a spreadsheet, including Gnumeric on the Raspberry Pi (Recipe 4.2).

The example program will log temperature readings recorded from your Raspberry Pi’s CPU (see Recipe 13.10).

Open an editor and paste in the following code (ch_13_temp_log.py):

import os, glob, time, datetime

log_period = 10 # seconds

logging_folder = glob.glob('/media/*')[0]
dt = datetime.datetime.now()
file_name = "temp_log_{:%Y_%m_%d}.csv".format(dt)
logging_file = logging_folder + '/' + file_name

def read_temp():
    dev = os.popen('/opt/vc/bin/vcgencmd measure_temp')
    cpu_temp = cpu_temp_s = dev.read()[5:-3] # top and tail string
    return cpu_temp

def log_temp():
    temp_c = read_temp()
    dt = datetime.datetime.now()
    f = open(logging_file, 'a')
    line = '\n"{:%H:%M:%S}","{}"'.format(dt, temp_c)
    f.write(line)
    print(line)
    f.close()

print("Logging to: " + logging_file)
while True:
    log_temp()
    time.sleep(log_period)

As with all the program examples in this book, you can also download this program (see Recipe 3.22).

The program is set to log the temperature every 10 minutes (600 seconds). You can alter this by changing the value of log_period.

You need to run this program using sudo to allow access to the flash drive:

$ sudo python3 ch_13_temp_log.py
Logging to: /media/pi/temp_log_2019_06_17.csv

"13:01:28","41.9"
"13:01:38","41.9"
"13:01:48","41.3"

When logging starts, the path to the logging file on the flash drive is displayed.

Note that, to speed things up, the logging period was set to 10 seconds.

Discussion

When you plug a USB flash drive into a Raspberry Pi, it automatically installs it under /media/pi. If there is more than one removable drive attached to your Raspberry Pi, the program uses the first folder it finds inside /media. The name of the logging file is constructed from the current date.

If you open the file in a spreadsheet you will be able to edit it directly. Your spreadsheet might ask you to specify the separator for the data, which will be a comma.

Figure 13-31 shows a set of data captured using this recipe, and the resulting file has been opened with the Gnumeric spreadsheet running on the Raspberry Pi.

Figure 13-31. Charting data

See Also

This program could easily be adapted for use with any of the other sensors used in this chapter.

For an example of logging sensor data to a web service, see Recipe 16.7.

Chapter 14. Displays

14.0 Introduction

Although the Raspberry Pi can use a monitor or TV as a display, it is often nice to use a smaller, more specialized display with it. In this chapter, we explore a range of different displays that can be attached to a Raspberry Pi.

Some of the recipes require the use of a solderless breadboard and male-to-female jumper wires (see Recipe 9.8).

14.1 Using a Four-Digit LED Display

Note

Be sure to check out the accompanying video for this recipe at http://razzpisampler.oreilly.com.

Problem

You want to display a four-digit number in an old-fashioned, seven-segment LED display.

Solution

Attach an Inter-Integrated Circuit (I2C) LED module, such as the model shown in Figure 14-1, to a Raspberry Pi using female-to-female jumper wires.

Figure 14-1. Seven-segment LED display with a Raspberry Pi

To make this recipe, you will need the following:

Four female-to-female jumper wires (see “Prototyping Equipment and Kits”)

Adafruit 4×7-segment LED with I2C backpack (see “Modules”)

The connections between the Raspberry Pi and the module are as follows:

VCC (+) on the display to 5V on the Raspberry Pi general-purpose input/output (GPIO) connector

GND (-) on the display to GND on the Raspberry Pi GPIO connector

SDA (D) on the display to GPIO 2 (SDA) on the Raspberry Pi GPIO connector

SCL (C) on the display to GPIO 3 (SCL) on the Raspberry Pi GPIO connector

Note that Adafruit also supplies a jumbo-sized LED display. You can connect this to the Raspberry Pi using the just-listed connections, but the larger display has two positive power pins: one for the logic (V_IO) and one for the display (5V). This is because, being a large display, it requires more current. Fortunately, the Raspberry Pi can supply enough power for it. You can use an extra female-to-female jumper wire to connect this extra pin to the second 5V pin on the GPIO connector.

For this recipe to work, you will also need to set up your Raspberry Pi for I2C, so follow Recipe 9.3 first.

Enter these commands to install the Adafruit code to support this display:

$ cd /home/pi
$ git clone https://github.com/adafruit/Adafruit_Python_LED_Backpack.git
$ cd Adafruit_Python_LED_Backpack
$ sudo python setup.py install

The Adafruit library includes examples, and it’s one of these that we will use to illustrate the use of the display. Run the program using the command below and the display should show the time. Note that this code is Python 2 only, so use the python (not python3) command:

$ cd examples
$ sudo python ex_7segment_clock.py

Discussion

If you open the example file ex_7segment_clock.py in an editor, you’ll see that the key commands are the following:

from Adafruit_LED_Backpack import SevenSegment

This imports the library code into your program. You then need to create a instance of SevenSegment using the next line of code. The address supplied as an argument is the I2C address (see Recipe 9.4).

Every I2C slave device has an address number. The LED board has three pairs of solder pads on the back that can be bridged with solder if you want to change the address. This is essential if you need to operate more than one I2C device from a single Raspberry Pi. This is why we specify an address of 0x70 in the following line:

segment = SevenSegment.SevenSegment(address=0x70)

To actually set the contents of a particular digit, use a line like this one:

segment.set_digit(0, int(hour / 10))

The first argument (0) is the digit position. Note that these positions are 0, 1, 3, and 4. Position 2 is reserved for the two dots in the center of the display.

The second argument is the number to display.

See Also

Find out more about the Adafruit library.

Recipe 14.2 uses the same Adafruit software for a matrix display.

14.2 Displaying Messages on an I2C LED Matrix

Problem

You want to control the pixels of a multicolor LED matrix display.

Solution

Use an I2C LED module, such as the model shown in Figure 14-2, attached to a Raspberry Pi using female-to-female jumper wires.

Figure 14-2. LED matrix display with a Raspberry Pi

To make this recipe, you will need the following:

Four female-to-female jumper wires (see “Prototyping Equipment and Kits”)

Adafruit bicolor LED square-pixel matrix with I2C backpack (see “Modules”)

The connections between the Raspberry Pi and the module are as follows:

VCC (+) on the display to 5V on the Raspberry Pi GPIO connector

GND (-) on the display to GND on the Raspberry Pi GPIO connector

SDA (D) on the display to GPIO 2 (SDA) on the Raspberry Pi GPIO connector

SCL (C) on the display to GPIO 3 (SCL) on the Raspberry Pi GPIO connector

For this recipe to work, you will also need to set up your Raspberry Pi for I2C, so follow Recipe 9.3 first.

The display uses the same library as Recipe 14.1. To install it, run the following commands:

$ cd /home/pi
$ git clone https://github.com/adafruit/Adafruit_Python_LED_Backpack.git
$ cd Adafruit_Python_LED_Backpack
$ sudo python setup.py install

Run the example program using:

$ cd examples
$ sudo python bicolor_matrix8x8_test.py

Discussion

The program demonstrates the versatility of the Adafruit library. It starts by iterating through all of the colors for each pixel in turn. The first part of the code is listed here, with some of the comments removed:

import time
from PIL import Image
from PIL import ImageDraw
from Adafruit_LED_Backpack import BicolorMatrix8x8

display = BicolorMatrix8x8.BicolorMatrix8x8()

for c in [BicolorMatrix8x8.RED, BicolorMatrix8x8.GREEN, BicolorMatrix8x8.YELLOW]:
    # Iterate through all positions x and y.
    for x in range(8):
        for y in range(8):
            # Clear the display buffer.
            display.clear()
            # Set pixel at position i, j to appropriate color.
            display.set_pixel(x, y, c)
            # Write the display buffer to the hardware.  This must be called to
            # update the actual display LEDs.
            display.write_display()
            # Delay for a quarter second.
            time.sleep(0.25)

The code is well explained in its accompanying comments.

See Also

You can find out more about this product at http://www.adafruit.com/products/902.

14.3 Using the Sense HAT LED Matrix Display

Problem

You want to display messages and graphics, using the display of a Sense HAT.

Solution

Follow Recipe 9.16 and install the software that the Sense HAT needs and then use the library commands to display text.

The program ch_14_sense_hat_clock.py illustrates this by repeatedly displaying the date and time in a scrolling message:

from sense_hat import SenseHat
from datetime import datetime
import time

hat = SenseHat()
time_color = (0, 255, 0) # green
date_color = (255, 0, 0) # red

while True:
    now = datetime.now()
    date_message = '{:%d %B %Y}'.format(now)
    time_message = '{:%H:%M:%S}'.format(now)

    hat.show_message(date_message, text_colour=date_color)
    hat.show_message(time_message, text_colour=time_color)

As with all the program examples in this book, you can also download this program (see Recipe 3.22).

Discussion

Two colors are defined so that the date and time parts of the message can be displayed in different colors. These colors are then used as an optional parameter to show_message.

Other optional parameters to show_message are:

scroll_speed

This is actually the delay between each scrolling step rather than the speed. So a higher value makes the scrolling slower.

back_colour

This sets the background color. Note the British spelling of “colour,” with a “u.”

You can use the display for a lot more than just displaying scrolling text. Starting at its most basic, you can set individual pixels using set_pixel, set the orientation of the display using set_rotation, and display an image (albeit a small one) with load_image. The example that follows, which you can find in ch_13_sense_hat_taster.py, illustrates these function calls. As with all the program examples in this book, you can download them (see Recipe 3.22).

The image must be just 8×8 pixels, but you can use most common graphics formats, such as .jpg and .png, and the bit depth will be handled automatically:

from sense_hat import SenseHat
import time

hat = SenseHat()

red = (255, 0, 0)

hat.load_image('small_image.png')
time.sleep(1)
hat.set_rotation(90)
time.sleep(1)
hat.set_rotation(180)
time.sleep(1)
hat.set_rotation(270)
time.sleep(1)

hat.clear()
hat.set_rotation(0)
for xy in range(0, 8):
    hat.set_pixel(xy, xy, red)
    hat.set_pixel(xy, 7-xy, red)

Figure 14-3 shows the Sense HAT displaying a crude image.

Figure 14-3. A Sense HAT displaying an “image”

See Also

For full documentation on the Sense HAT, see https://pythonhosted.org/sense-hat/api/.

For information on formatting dates and times, see Recipe 7.2.

Other recipes that use the Sense HAT are Recipes 9.16, 13.11, 13.14, 13.15, and 13.17.

14.4 Displaying Messages on an Alphanumeric LCD HAT

Problem

You have a few lines of text that you want to display neatly on an LCD display.

Solution

Use a Pimoroni Displayotron HAT attached to your Raspberry Pi, as shown in Figure 14-4.

Figure 14-4. A Displayotron LCD HAT

This HAT requires both I2C and SPI to be enabled, so if you have not already done so, follow Recipe 9.3 and Recipe 9.5.

Then fetch the code for its accompanying library from GitHub and install it by using the following commands:

$ curl -sS get.pimoroni.com/displayotron | bash

This command will ask you if want to install the examples and documentation. Be warned: the whole thing takes quite some time to install.

By way of example, the following program (ch_14_displayotron_ip.py) finds the hostname and IP address of your Raspberry Pi and displays them, along with the time. If all is well, the backlit LED will be green, but if the network connection is down, the backlight will turn red:

import dothat.lcd as lcd
import dothat.backlight as backlight
import time
from datetime import datetime
import subprocess

while True:
    lcd.clear()
    backlight.rgb(0, 255, 0)
    try:
        hostname = subprocess.check_output(['hostname']).split()[0]
        ip = subprocess.check_output(['hostname', '-I']).split()[0]
        t = '{:%H:%M:%S}'.format(datetime.now())
        lcd.write(hostname)
        lcd.set_cursor_position(0, 1)
        lcd.write(ip)
        lcd.set_cursor_position(0, 2)
        lcd.write(t)
    except:
        backlight.rgb(255, 0, 0)
    time.sleep(1)

As with all the program examples in this book, you can also download this program (see Recipe 3.22).

Discussion

The test program imports the necessary libraries, including subprocesses (see Recipe 7.15), which will be used to find the IP address (see Recipe 2.2) of the Raspberry Pi and its hostname.

Here are the main methods in the library:

lcd.clear

Clears the display of any text

lcd.set_cursor_position

Sets the position for new text to be written to the column and row specified as its two parameters

lcd.write

Adds the text supplied as its parameter to the current cursor position

backlight.rgb

Sets the red, green, and blue values of the backlight (0 to 255)

You can find the examples that are supplied by Pimoroni in two subdirectories, basic and advanced, within the directory /home/pi/Pimoroni/displayotron/examples/dothat.

See Also

You can find out more about this HAT on Pimoroni’s product page.

14.5 Using an OLED Graphical Display

Problem

You want to attach a graphical OLED (Organic LED) display to your Raspberry Pi.

Solution

Use an OLED display based on the SSD1306 driver chip, using an I2C interface (Figure 14-5).

Figure 14-5. An I2C OLED display

To make this recipe, you will need the following:

Four female-to-female jumper wires (see “Prototyping Equipment and Kits”)

I2C OLED display 128×64 pixels (see “Modules”)

The connections between the Raspberry Pi and the module are as follows:

VCC on the display to 5V on the Raspberry Pi GPIO connector

GND on the display to GND on the Raspberry Pi GPIO connector

SDA on the display to GPIO 2 (SDA) on the Raspberry Pi GPIO connector

SCL on the display to GPIO 3 (SCL) on the Raspberry Pi GPIO connector

For this recipe to work, you will also need to set up your Raspberry Pi for I2C, so follow Recipe 9.3 first.

Adafruit has a library for these displays, which you can install by using these commands:

$ git clone https://github.com/adafruit/Adafruit_Python_SSD1306.git
$ cd Adafruit_Python_SSD1306
$ sudo python3 setup.py install

This library uses the Python Image Library (PIL), which you can install by using the following command:

$ sudo pip3 install pillow

The code example ch_14_oled_clock.py displays the time and date on the OLED display:

import Adafruit_SSD1306
from PIL import Image, ImageDraw, ImageFont
import time
from datetime import datetime

# Set up display
disp = Adafruit_SSD1306.SSD1306_128_64(rst=None, i2c_address=0x3C)
small_font = ImageFont.truetype('FreeSans.ttf', 12)
large_font = ImageFont.truetype('FreeSans.ttf', 33)
disp.begin()
disp.clear()
disp.display()
# Make an image to draw on in 1-bit color.
width = disp.width
height = disp.height
image = Image.new('1', (width, height))
draw = ImageDraw.Draw(image)

# Display a message on 3 lines, first line big font
def display_message(top_line, line_2):
    draw.rectangle((0,0,width,height), outline=0, fill=0)
    draw.text((0, 0),  top_line, font=large_font, fill=255)
    draw.text((0, 50),  line_2, font=small_font, fill=255)
    disp.image(image)
    disp.display()

while True:
    now = datetime.now()
    date_message = '{:%d %B %Y}'.format(now)
    time_message = '{:%H:%M:%S}'.format(now)
    display_message(time_message, date_message)
    time.sleep(0.1)

As with all the program examples in this book, you can also download this program (see Recipe 3.22).

Every I2C slave device has an address, which is set in the line:

disp = Adafruit_SSD1306.SSD1306_128_64(rst=None, i2c_address=0x3C)

This is fixed at 3C (hex) for many of the low-cost I2C modules but may vary, so you should check any documentation that comes with the device or use I2C tools (Recipe 9.4) to list all the I2C devices attached to the bus so that you can see the address of your display.

The preceding code example uses a technique called double buffering. This involves preparing what is to be displayed and then switching it onto the image in one go. This prevents the display from flickering.

You can see the code for this in the display_message function. This first draws onto the image a blank rectangle the entire size of the display. It then draws the text onto the image and then sets the display content to be image using disp.image(image). The display isn’t actually updated until the function disp.display() is called.

To be able to use text of different sizes, a TrueType font is used. This font is already on the Raspberry Pi, but to be able to use it, you need to copy it into the current directory using the following command:

$ cp /usr/share/fonts/truetype/freefont/FreeSansBold.ttf

Discussion

Small OLED displays are cheap, don’t use much current, and have high resolution despite their diminutive size. They are replacing LCD displays in many consumer products.

See Also

The instructions here are for four-pin I2C interfaces. If you really want to use the SPI interface, take a look at Adafruit’s tutorial on this.

14.6 Using Addressable RGB LED Strips

Problem

You want to connect an RGB LED strip (NeoPixels) to your Raspberry Pi.

Solution

Use an LED strip based on the WS2812 RGB LED chips on your Raspberry Pi.

Using these LED strips (Figure 14-6) can be really easy, with a direct connection to the Raspberry Pi and power for the LEDs supplied by the Raspberry Pi’s 5V supply. This is the “Happy Day” scenario that should work just fine, but do see the Discussion for providing external power so that your LED strip use is trouble free.

Don’t Power the LEDS from the Pi’s 3.3V Supply

Although it might be tempting to power the LEDs from the 3.3V supply pin on the GPIO connector, do not do this—it can supply only low currents (see Recipe 9.2). Using this pin could easily damage your Raspberry Pi.

Figure 14-6. An LED strip of 10 LEDs

The LED strip used in Figure 14-6 is cut from a reel. In this case, there are 10 LEDs. Because each LED can use up to 60mA, 10 is probably a sensible limit for the number of LEDs that can be used without arranging for a separate power supply for the LED strip (see the Discussion section).

To connect the strip to the Raspberry Pi, jumper wires with female connectors on one end were cut and the wire ends soldered to the three connections on the LED strip (see Recipe 9.2): GND, DI (Data In), and 5V. These can then be attached to GPIO pins GND, GPIO 18, and 5V, respectively.

Notice that the LED strip has a right-facing arrow printed on it (Figure 14-7). Make sure that when you solder leads to the LED strip, you start from the cut end to the left of the arrow.

Figure 14-7. An LED strip close-up

We are going to use the Adafruit software to control our addressable LEDs. To install it, run the following commands:

$ pip3 install adafruit-blinka
$ sudo pip3 install rpi_ws281x adafruit-circuitpython-neopixel

The following example program (ch_14_neopixel.py) will set the LED red in successive positions along the strip:

import time
import board
from neopixel import NeoPixel

led_count = 5
red = (100, 0, 0)
no_color = (0, 0, 0)

strip = NeoPixel(board.D18, led_count, auto_write=False)

def clear():
    for i in range(0, led_count):
        strip[i] = no_color
    strip.show()

i = 0
while True:
    clear()
    strip[i] = red
    strip.show()
    time.sleep(1)
    i += 1
    if i >= led_count:
        i = 0

As with all the program examples in this book, you can also download this program (see Recipe 3.22).

Run the program with Python 3 and use the sudo command like this:

$ sudo python3 ch_14_neopixel.py

If you have a different number of LEDs in your strip, modify led_count. The rest of the constants do not need to be changed.

You can use only GPIOs 10, 12, 18, and 21 with NeoPixels. If you want to use a different GPIO pin, change board.D18 to whichever pin you are using.

You can set the color of each of the LEDs independently. The colors are set as a tuple of red, green, and blue intensities. The changes to the LED colors are not actually updated until the method show is called.

Discussion

Each LED in the strip can use a maximum of about 60mA. They will do this only if all three color channels (red, green, and blue) are at maximum brightness (255). If you plan to use a lot of LEDs, you will need to use a separate 5V power supply sufficient to supply all the LEDs in your strip. Figure 14-8 shows how you would wire up a separate power supply. A female direct current (DC) jack-to-screw terminal adapter (see “Prototyping Equipment and Kits”) makes it easy to connect an external power supply to a breadboard.

Figure 14-8. Powering an LED strip with an external power supply

See Also

NeoPixels are also available in ring format, such as this display: https://www.adafruit.com/product/1586.

You can read more about the Adafruit approach to NeoPixels here.

14.7 Using the Pimoroni Unicorn HAT

Problem

You want an RGB LED matrix display for your Raspberry Pi.

Solution

Use a Pimoroni Unicorn HAT to provide an 8x8 LED matrix (Figure 14-9).

Start by installing the Unicorn HAT software from Pimoroni:

$ curl https://get.pimoroni.com/unicornhat | bash

You will be asked several times to confirm various bits of software to install and finally to reboot your Raspberry Pi.

Figure 14-9. The Pimoroni Unicorn HAT on a Raspberry Pi 3

When you’ve completed the installation, here’s a colorful program (ch_14_unicorn.py) to run on it. It will repeatedly set the color of a random pixel to a random color. Run the program using the sudo command:

import time
import unicornhat as unicorn
from random import randint

unicorn.set_layout(unicorn.AUTO)
unicorn.rotation(0)
unicorn.brightness(1)
width, height = unicorn.get_shape()

while True:
    x = randint(0, width)
    y = randint(0, height)
    r, g, b = (randint(0, 255), randint(0, 255), randint(0, 255))
    unicorn.set_pixel(x, y, r, g, b)
    unicorn.show()
    time.sleep(0.01)

time.sleep(1)

As with all the program examples in this book, you can also download this program (see Recipe 3.22).

Discussion

The Unicorn HAT makes a very convenient way to attach a matrix of addressable LEDs. You will also find other chains of addressable LEDs laid out in various configurations, including matrices with even more LEDs on them. Generally, such matrices of addressable LEDs are actually arranged electrically as a long chain of LEDs.

See Also

For more information on addressable (NeoPixel) LEDs, see Recipe 14.6.

14.8 Using an ePaper Display

Problem

You want to use your Raspberry Pi to control an ePaper display.

Solution

Attach an Inky pHAT or Inky wHAT module to your Raspberry Pi (Figure 14-10). Download the Pimoroni software for this using the command:

$ curl https://get.pimoroni.com/inky | bash

If (when prompted) you accept the option to fetch examples and documentation, this will take quite some time to install.

As an example program (ch_14_phat.py), let’s have the Inky pHAT display the Raspberry Pi’s IP address:

from inky import InkyPHAT
from PIL import Image, ImageFont, ImageDraw
from font_fredoka_one import FredokaOne
import subprocess

inky_display = InkyPHAT("red")
inky_display.set_border(inky_display.WHITE)

img = Image.new("P", (inky_display.WIDTH, inky_display.HEIGHT))
draw = ImageDraw.Draw(img)
font = ImageFont.truetype(FredokaOne, 22)

message = str(subprocess.check_output(['hostname', '-I'])).split()[0][2:]
print(message)

w, h = font.getsize(message)
x = (inky_display.WIDTH / 2) - (w / 2)
y = (inky_display.HEIGHT / 2) - (h / 2)

draw.text((x, y), message, inky_display.RED, font)
inky_display.set_image(img)
inky_display.show()

As with all the program examples in this book, you can also download this program (see Recipe 3.22).

Figure 14-10. The Pimoroni Inky pHAT attached to a Raspberry Pi 3

Discussion

You won’t be playing any video games on these displays because they take a few seconds to update, but after they update, the ePaper keeps whatever you have drawn on it even when the power is removed. Pimoroni sells small displays like the Inky pHAT used here, and also a display twice the size that is pretty much as big as the Raspberry Pi (Inky wHAT).

See Also

More information is available in the full documentation of Inky pHAT.

Chapter 15. Sound

15.0 Introduction

In this chapter, you learn how to use sound with your Raspberry Pi. There are recipes both for playing sounds in various ways—using loudspeakers or a buzzer—and for using a microphone to record sounds.

15.1 Connecting a Loudspeaker

Problem

You want to play sounds from your Raspberry Pi.

Solution

Attach a powered speaker such as the one shown in Figure 15-1.

Having attached the speaker to the audiovisual socket, you will also need to configure the Raspberry Pi to play through the audiovisual jack, not HDMI, using Recipe 15.2.

Figure 15-1. Attaching a rechargeable amplified speaker to a Raspberry Pi

An alternative to using a general-purpose speaker like the one shown in Figure 15-1 is to use a speaker kit designed specifically for the Raspberry Pi, such as the MonkMakes Speaker Kit for Raspberry Pi, shown in Figure 15-2.

Figure 15-2. The MonkMakes amplified speaker and a Raspberry Pi

This speaker is connected using the audio lead supplied with the kit, and the speaker uses the Raspberry Pi’s 5V power supply, connected using the female-to-female leads.

Raspbian comes with a handy program to test that your speaker is working. Type the following command in the Terminal:

$ speaker-test -t wav -c 2

speaker-test 1.1.3

Playback device is default
Stream parameters are 48000Hz, S16_LE, 2 channels
WAV file(s)
Rate set to 48000Hz (requested 48000Hz)
Buffer size range from 256 to 32768
Period size range from 256 to 32768
Using max buffer size 32768
Periods = 4
was set period_size = 8192
was set buffer_size = 32768
 0 - Front Left
 1 - Front Right
Time per period = 2.411811
 0 - Front Left
 1 - Front Right

When you run this command, you will hear a voice saying front left, front right, and so on. This is designed to test a stereo audio setup.

Discussion

As well as connecting amplified loudspeakers of various types, you can also directly connect a pair of headphones to a Raspberry Pi’s audio socket.

By default, a Raspberry Pi’s output is set to be via the HDMI cable. So if your Pi is connected to a TV or a monitor with built-in speakers, all you need to do to hear sounds from your Raspberry Pi is to turn up the volume on your TV or monitor.

However, if you are using the Raspberry Pi without a monitor, or your monitor does not have speakers, you can follow this recipe.

See Also

To specify where sound is output, see Recipe 15.2.

To play a test sound, see Recipe 15.4.

To pair your Raspberry Pi with a Bluetooth speaker, see Recipe 1.18.

For more information on the Speaker Kit for Raspberry Pi, see https://oreil.ly/Q73vu.

15.2 Controlling Where Sound Is Output

Problem

You want to control which of several output options the Raspberry Pi will use when making sounds.

Solution

The simplest way to set the audio output is to use the selector available when you right-click the Speaker icon in the upper-right corner of your desktop (Figure 15-3).

Figure 15-3. Changing the audio output device

Note that the entry Comiso M20 in Figure 15-3 is for a Bluetooth speaker that has already been paired with the Raspberry Pi (see Recipe 1.18).

Discussion

If you are running your Raspberry Pi headless (without a monitor), you can still control where the sound is output on your Raspberry Pi using the raspi-config command-line utility.

Open a Terminal session and enter the following command:

$ sudo raspi-config

Then select the option Advanced, followed by Audio. You can then select the option you want, as shown in Figure 15-4.

Figure 15-4. Using raspi-config to change the audio output device

See Also

To learn about connecting a speaker to your Raspberry Pi, see Recipe 15.1.

For more sound input and output options, you can use the Audio Device Settings tool; see Recipe 15.5.

15.3 Playing Sound from the Command Line

Problem

You want to be able to play a sound file from the Raspberry Pi’s command line.

Solution

Use the built-in OMXPlayer software from the command line. To try this out, locate the file called school_bell.mp3 in this book’s downloads in the python directory. You can play this license-free sound using the following command:

$ omxplayer -o local /home/pi/raspberrypi_cookbook_ed3/python/school_bell.mp3

This will play the sound file through the headphone jack. If you would rather play the sound through the HDMI connection, you can use -o hdmi instead of -o local.

Discussion

The OMXPlayer will play most types of sound files, including MP3, WAV, AIFF, AAC, and OGG. However, if you want to play only uncompressed WAV files, you can also use the lighter-weight aplay command:

$ aplay school_bell.wav

See Also

You can read more about the OMXPlayer here.

Documentation for aplay is available here.

15.4 Playing Sound from Python

Problem

You want to play a sound file from your Python program.

Solution

If you need to play the sound from a Python program, you can use the Python subprocess module (ch_15_play_sound.py), as shown here:

import subprocess

sound_file = '/home/pi/raspberrypi_cookbook_ed3/python/school_bell.mp3'
sound_out = 'local'

subprocess.run(['omxplayer', '-o', sound_out, sound_file])

As with all the program examples in this book, you can also download this program (see Recipe 3.22).

Discussion

You can also play sounds using the pygame library (ch_15_play_sound_pygame.py), as illustrated here:

import pygame

sound_file = '/home/pi/raspberrypi_cookbook_ed3/python/school_bell.wav'

pygame.mixer.init()
pygame.mixer.music.load(sound_file)
pygame.mixer.music.play()

while pygame.mixer.music.get_busy() == True:
    continue

The sound file must be either an OGG file or an uncompressed WAV file. I found that the sound would play only through the HDMI channel.

See Also

To play sounds directly from the command line, see Recipe 15.3.

You also can use pygame for intercepting keypresses (Recipe 12.11) and mouse movements (Recipe 12.12).

15.5 Using a USB Microphone

Problem

You want to connect a microphone to your Raspberry Pi to capture sound.

Solution

Use a USB microphone like the one shown in Figure 15-5, or something a bit more substantial and of better quality.

These devices come in various shapes and sizes. Some fit directly into the USB socket; others have a USB lead attached to them; and some are part of a headset.

Having plugged in your USB microphone, check that Raspbian is aware of it by running this command, which lists available devices from which you can record:

$ arecord -l
**** List of CAPTURE Hardware Devices ****
card 1: H340 [Logitech USB Headset H340], device 0: USB Audio [USB Audio]
  Subdevices: 1/1
  Subdevice #0: subdevice #0

Figure 15-5. Attaching a USB microphone to a Raspberry Pi

In this case, I’m using a microphone that’s part of a Logitech USB headset with microphone. This is card 1, subdevice 0. We will need this information when we come to recording sounds.

To make the microphone active, you need to open the Audio Device Settings from the Preferences menu on your Raspberry Pi desktop. Then select your USB mic device from the “Sound card” list, as shown in Figure 15-6.

Figure 15-6. Selecting the microphone as an audio device

Next, click the Select Controls button and check the Microphone box. This adds a slider that allows you to control the gain of the microphone, and a red button at the bottom to turn it on and off (Figure 15-7).

Figure 15-7. Adding a gain control for the microphone

Adjust the microphone gain slider up to about the 75% level.

You can now try to make a recording from the command line and then play it back. To record, use the following command:

$ arecord -D plughw:1,0 -d 3 test.wav

The -D parameter specifies the device pluginhw:1,0, which refers to the card number (1) and subdevice (0) that we discovered earlier.

To play back the sound you have just recorded, use the following:

$ aplay test.wav
Playing WAVE 'test.wav' : Unsigned 8 bit, Rate 8000 Hz, Mono

You can interrupt the sound playing by using Ctrl-C.

Discussion

I have had mixed results with the tiny push-in microphones like the one shown in Figure 15-5. Some work and some don’t. So, if you have followed the instructions here and you still can’t get your microphone to record anything, try a different one.

The arecord command has optional parameters that allow you to control the sample rate and format of the audio you record. So, for example, if you want to record at 16,000 samples a second rather than the default of 8,000, use the following command:

$ arecord -r 16000 -D plughw:1,0 -d 3 test.wav

When you come to play back the sound, aplay will automatically detect the sample rate, so you can just do this:

$ aplay test.wav
Playing WAVE 'test.wav' : Unsigned 8 bit, Rate 16000 Hz, Mono

See Also

For ways of attaching a speaker to your Raspberry Pi, see Recipe 15.1.

For other methods of playing a sound file, see Recipe 15.3 and Recipe 15.4.

15.6 Making a Buzzing Sound

Problem

You want to make a buzzing sound with the Raspberry Pi.

Solution

Use a piezo-electric buzzer connected to a general-purpose input/output (GPIO) pin.

Most small piezo buzzers work just fine using the arrangement shown in Figure 15-8. The one I used is an Adafruit-supplied component (see “Miscellaneous”). You can connect the buzzer pins directly to the Raspberry Pi using female-to-female headers (see “Prototyping Equipment and Kits”).

These buzzers use very little current. However, if you have a large buzzer or just want to play it safe, put a 470Ω resistor between the GPIO pin and the buzzer lead.

Figure 15-8. Connecting a piezo buzzer to a Raspberry Pi

Paste the following code into an editor (ch_15_buzzer.py):

from gpiozero import Buzzer

buzzer = Buzzer(18)

def buzz(pitch, duration):
    period = 1.0 / pitch
    delay = period / 2
    cycles = int(duration * pitch)
    buzzer.beep(on_time=period, off_time=period, n=int(cycles/2))

while True:
    pitch_s = input("Enter Pitch (200 to 2000): ")
    pitch = float(pitch_s)
    duration_s = input("Enter Duration (seconds): ")
    duration = float(duration_s)
    buzz(pitch, duration)

As with all the program examples in this book, you can also download this program (see Recipe 3.22). When you run the program, it first prompts you for the pitch in Hz and then for the duration of the buzz in seconds:

$ python3 ch_15_buzzer.py
Enter Pitch (2000 to 10000): 2000
Enter Duration (seconds): 20

Discussion

Piezo buzzers don’t have a wide range of frequencies, nor is the sound quality remotely good. However, you can vary the pitch a little. The frequency generated by the code is not very accurate, and you might hear a bit of warbling.

The program works by using the gpiozero Buzzer class to toggle the GPIO pin 18 on and off, with a short delay in between. The delay is calculated from the pitch. The higher the pitch (frequency), the shorter the delay needs to be.

See Also

You can find the datasheet for the piezo buzzer here.

For better audio output options, see Recipe 15.1

Chapter 16. The Internet of Things

16.0 Introduction

The Internet of Things (IoT) is the rapidly growing network of devices (things) connected to the internet. That doesn’t just mean more and more computers using browsers, but actual appliances and wearable and portable technology. This includes all sorts of home automation, from smart appliances and lighting to security systems and even internet-operated pet feeders, as well as lots of less practical but fun projects.

In this chapter, you learn how your Raspberry Pi can participate in the IoT in various ways.

16.1 Controlling GPIO Outputs Using a Web Interface

Problem

You want to control general-purpose input/output (GPIO) outputs using a web interface to your Raspberry Pi.

Solution

Use the bottle Python web server library (Recipe 7.17) to create an HTML web interface to control the GPIO port.

To make this recipe, you will need the following:

Breadboard and jumper wires (see “Prototyping Equipment and Kits”)

Three 1kΩ resistors (see “Resistors and Capacitors”)

Three LEDs (see “Opto-Electronics”)

Tactile push switch (see “Miscellaneous”)

Figure 16-1 shows the breadboard layout for this.

Figure 16-1. The breadboard layout controlling GPIO outputs from a web page

An alternative to using a breadboard is to attach a Raspberry Squid and Squid Button (see Recipe 9.10 and Recipe 9.11). You can plug these directly into the GPIO pins of the Raspberry Pi, as shown in Figure 16-2.

Figure 16-2. Raspberry Squid and Squid Button

To install the bottle library, see Recipe 7.17.

Open an editor and paste in the following code (ch_16_web_control.py):

from bottle import route, run
from gpiozero import LED, Button

leds = [LED(18), LED(23), LED(24)]
switch = Button(25)

def switch_status():
    if switch.is_pressed:
        return 'Down'
    else:
        return 'Up'

def html_for_led(led_number):
    i = str(led_number)
    result = " <input type='button'
         onClick='changed(" + i + ")' value='LED " + i
         + "'/>"
    return result

@route('/')
@route('/<led_number>')
def index(led_number="n"):
    if led_number != "n":
        leds[int(led_number)].toggle()
    response = "<script>"
    response += "function changed(led)"
    response += "{"
    response += "  window.location.href='/' + led"
    response += "}"
    response += "</script>"

    response += '<h1>GPIO Control</h1>'
    response += '<h2>Button=' + switch_status() + '</h2>'
    response += '<h2>LEDs</h2>'
    response += html_for_led(0)
    response += html_for_led(1)
    response += html_for_led(2)
    return response

run(host='0.0.0.0', port=80)

As with all the program examples in this book, you can also download this program (see Recipe 3.22).

You must run the program as a superuser, using Python 2:

$ sudo python ch_13_web_control.py

If it starts correctly, you should see a message like this:

Bottle server starting up (using WSGIRefServer())...
Listening on http://0.0.0.0:80/
Hit Ctrl-C to quit.

If you see error messages, make sure that you are running the program with python, not python3, and are using the sudo command.

Open a browser window from any machine on your network, even the Raspberry Pi itself, and navigate to the IP address of the Raspberry Pi (see Recipe 2.2). The web interface shown in Figure 16-3 should appear.

Figure 16-3. A web interface to GPIO

If you click one of the three LED buttons at the bottom of the screen, you should find that the appropriate LED toggles on and off.

Also, if you hold down the button as you reload the web page, you should see that the text next to Button says Down rather than Up.

Discussion

To understand how the program works, we first need to look at how a web interface works. All web interfaces rely on a server somewhere (in this case, a program on the Raspberry Pi) responding to requests from a web browser.

When the server receives a request, it looks at the information that comes with the request and formulates some HyperText Markup Language (HTML) in response.

If the web request is just to the root page (for my Raspberry Pi, the root page is http://192.168.1.8/), led_number will be given a default value of n. However, if we were to browse the URL http://192.168.1.8/2, the 2 on the end of the URL would be assigned to the led_number parameter.

The led_number parameter is then used to determine that LED 2 should be toggled.

To be able to access this LED-toggling URL, we need to arrange things so that when the button for LED 2 is pressed, the page is reloaded with this extra parameter on the end of the URL. The trick here is to include a JavaScript function in HTML that is returned to the browser. When the browser runs this function, it causes the page to be reloaded with the appropriate extra parameter.

This all means that we have a rather mind-bending situation in which the Python program is generating code in JavaScript to be run later by the browser. The lines that generate this JavaScript function are as follows:

    response = "<script>"
    response += "function changed(led)"
    response += "{"
    response += "  window.location.href='/' + led"
    response += "}"
    response += "</script>"

We need to also generate the HTML that will eventually call this script when a button is pressed. Rather than repeat the HTML for each of the web page buttons, this is generated by the function html_for_led:

def html_for_led(led):
    i = str(led)
    result = " <input type='button' onClick='changed(" + i + ")'
    value ='LED " + i + "'/>"
    return result

This code is used three times, once for each button, and links a button press with the changed function. The function is also supplied with the LED number as its parameter.

The process of reporting the state of the push button tests to see whether the button is pressed and reports the appropriate HTML.

See Also

For more information on using bottle, see the bottle documentation.

16.2 Displaying Sensor Readings on a Web Page

Problem

You want to display sensor readings from your Raspberry Pi on a web page that automatically updates.

Solution

Use the bottle web server and some fancy JavaScript to automatically update your display.

The example shown in Figure 16-4 displays the Raspberry Pi’s CPU temperature using its built-in sensor.

Figure 16-4. Displaying the Raspberry Pi CPU temperature

To install the bottle library, see Recipe 7.17.

There are four files for this example, and all of them are contained in the folder ch_16_web_sensor:

web_sensor.py

Contains the Python code for the bottle server

main.html

Contains the web page that will be displayed in your browser

justgage.1.0.1.min.js

A third-party JavaScript library that displays the temperature meter

raphael.2.1.0.min.js

A library used by the justgage library

To run the program, change directory to ch_16_web_sensor.py and then run the Python program using the following:

$ sudo python web_sensor.py

As with all the program examples in this book, you can also download this program (see Recipe 3.22).

Then open a browser, either on the same Raspberry Pi or on any computer on the same network as the Raspberry Pi, and enter the IP address of the Raspberry Pi into the browser’s address bar. The page shown in Figure 16-4 should appear.

Discussion

The main program (web_sensor.py) is actually quite concise:

import os, time
from bottle import route, run, template

def cpu_temp():
    dev = os.popen('/opt/vc/bin/vcgencmd measure_temp')
    cpu_temp = dev.read()[5:-3]
    return cpu_temp

@route('/temp')
def temp():
    return cpu_temp()

@route('/')
def index():
    return template('main.html')

@route('/raphael')
def index():
    return template('raphael.2.1.0.min.js')

@route('/justgage')
def index():
    return template('justgage.1.0.1.min.js')

run(host='0.0.0.0', port=80)

The function cpu_temp reads the temperature of the Raspberry Pi’s CPU, as described in Recipe 13.10.

Four routes are then defined for the bottle web server. The first (/temp) returns a string containing the CPU temperature in degrees C. The root route (/) returns the main HTML template for the page (main.html). The other two routes provide access to copies of the raphael and justgage JavaScript libraries.

The file main.html mostly contains the JavaScript to render the user interface:

<html>
<head>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"
type="text/javascript" charset="utf-8"></script>
<script src="raphael"></script>
<script src="justgage"></script>

<script>
function callback(tempStr, status){
if (status == "success") {
    temp = parseFloat(tempStr).toFixed(2);
    g.refresh(temp);
    setTimeout(getReading, 1000);
}
else {
    alert("There was a problem");
    }
}

function getReading(){
    $.get('/temp', callback);
}
</script>
</head>

<body>
<div id="gauge" class="200x160px"></div>

<script>
var g = new JustGage({
    id: "gauge",
    value: 0,
    min: 10,
    max: 60,
    title: "CPU Temp 'C"
});
getReading();
</script>

</body>
</html>

The jquery, raphael, and justgage libraries are all imported (jquery from https://developers.google.com/speed/libraries/#jquery, and the other two from local copies).

Getting a reading from the Raspberry Pi to the browser window is a two-stage process. First, the function getReading is called. This sends a web request with the route /temp to web_sensor.py and specifies a function called callback to be run when the web request completes. The callback function is then responsible for updating the justgage display before setting a timeout to call getReading again after a second.

See Also

For an example of using a Python app to display sensor values in an application rather than a web page, see Recipe 13.22.

The justgage library has all sorts of useful options for displaying sensor values. See http://justgage.com/ for more information.

16.3 Getting Started with Node-RED

Problem

You want to create simple IoT workflows, such as sending a tweet when a button is pressed on your Raspberry Pi.

Solution

Use the Node-RED system that is preinstalled on Raspbian. Use the following example to start a Node-RED server running:

$ node-red-pi --max-old-space-size=256

Then connect to the server using a browser. This can be on the Raspberry Pi itself, in which case you can connect to the URL http: //127.0.0.1:1880/—or if you are connecting from another computer on your network, change 127.0.0.1 to the local IP address of your Raspberry Pi. Figure 16-5 shows the sort of thing you can expect to see in your browser when you connect to the Node-RED server.

Figure 16-5. The Node-RED web interface

The idea behind Node-RED is that you draw your program (called a flow) rather than write code. To do this, you drag nodes onto the editor area and then connect them together. For example, Figure 16-5 shows a minimal flow with two Raspberry Pi pins linked together. One pin acts as an input and might be connected to a switch (let’s pick GPIO 25 as an example), and the other is connected to an LED (let’s assume GPIO 18). You can accomplish this using a Squid LED and button as in Recipe 16.1.

The node on the left, labeled PIN 22 is the input (connected to the switch on GPIO 25), and PIN 12 the output (connected to the LED on GPIO 18). Node-RED uses the pin positions rather than the GPIO names.

To create this flow in your editor, scroll down the list of nodes on the left until you get to the Raspberry Pi section. Drag the “rpi gpio” node with the Raspberry Pi icon on its left to the editor area. This will be the input. Double-click it to open the window shown in Figure 16-6. Select “22 - GPIO25” and then click Done.

Figure 16-6. Selecting GPIO 25 in Node-RED

Next, select the other “rpi gpio” node type (with the Raspberry Pi symbol on the right) and drag it to the editor area, and then double-click it to open the window shown in Figure 16-6; this time select “12 - GPIO18,” and then click Done.

Link the two nodes together by dragging out from the round connector on the right of the input node, so that the flow looks like Figure 16-5.

Assuming that you have a push switch and LED connected to your Raspberry Pi, you can now run this flow by clicking on the Deploy button. The LED should light, and when you press the button the LED should turn off. The logic of this is inverted, but let’s leave that for now. We revisit this in the next chapter, where you learn a lot more about Node-RED.

This is all very neat, but as yet it does not have much to do with the IoT. This is where some of the other node types of Node-RED come into play. If you look up and down the list, you will find all sorts of nodes, including the Tweet node. You can connect this node as a second output to the PIN 22 node, so that the flow now looks like Figure 16-7. Double-click the Tweet node to configure it with your Twitter credentials. Now when you press the button, a tweet will be sent.

Figure 16-7. Sending tweets from Node-RED

Discussion

Node-RED is an extremely powerful system, and consequently, becoming familiar with all its features and its odd quirks will take some time. As well as creating direct flows like the one we made here, you can also introduce switching code (like an if statement) and functions that transform the messages being passed between the nodes.

We have only just touched on Node-RED here; if you want to learn more, I suggest working through the documentation mentioned in the See Also section and much of Chapter 17.

Having played with Node-RED and decided that you like it, you may well want to ensure that it starts automatically whenever your Raspberry Pi reboots by issuing the following commands:

$ sudo systemctl enable nodered.service
$ sudo systemctl start nodered.service

See Also

More information is available in the full documentation on using Node-RED on the Raspberry Pi.

Here are some good video introductions to Node-RED: https://oreil.ly/uxGHZ and https://oreil.ly/ZSDNi.

16.4 Sending Email and Other Notifications with IFTTT

Problem

You want a flexible way for your Raspberry Pi to send notifications through email, Facebook, Twitter, or Slack.

Solution

Have your Raspberry Pi send requests to the If This Then That (IFTTT) Maker channel to trigger configurable notifications.

This recipe is illustrated with an example that sends you an email when the CPU temperature of your Raspberry Pi exceeds a threshold.

You need to create an account with IFTTT before you can begin using it, so visit www.ifttt.com and sign up.

The next step is to create a new IFTTT Applet. An Applet is like a rule, such as When I get a web request from a Raspberry Pi, send an email. Click the “Create an Applet” button. This will prompt you to first enter the THIS part of the recipe and later the THAT part.

In this case, the IF THIS part (the trigger) is going to be the receipt of a web request from your Raspberry Pi, so click THIS and then enter Webhooks into the search field to find the Webhooks channel. Select the Webhooks channel, and when prompted, select the option “Receive a web request.” This opens the form shown in Figure 16-8.

Figure 16-8. The “Receive a web request” trigger form

In the Event Name field, enter the text cpu_too_hot and then click “Create trigger.”

This will now move you to the THAT portion of the recipe, the action, and you will need to select an action channel. There are many options, but for this example you will use the Email channel, so in the search field, type Email and then select the Email channel.

Having selected the Email channel, select the action “Send me an email,” which displays the form shown in Figure 16-9.

Figure 16-9. Completing the action fields in IFTTT

Change the text so that it appears as shown in Figure 16-9. Note that the special values OccurredAt and Value1 will both be surrounded by {{ and }}. These values are called ingredients and are variable values that will be taken from the web request and substituted into the email subject and body.

Click “Create action” and then Finish to complete the recipe creation.

One final piece of information that we need is the API (application programming interface) key for the Webhooks channel. This is so that other people can’t bombard you with emails about their Raspberry Pi’s CPU temperature.

To find this key on the IFTTT website, click the Services tab on the My Applets page and then find Webhooks. On the Webhooks page, click Documentation, and a page like Figure 16-10 displays; here you can see your key (which is intentionally obscured in this figure). You will need to paste this key into the code that follows Figure 16-10, in the line KEY = 'your_key_here'.

Figure 16-10. Finding your API key

The Python program to send the web request is called ch_16_ifttt_cpu_temp.py:

import time, os
import requests

MAX_TEMP = 37.0
MIN_T_BETWEEN_WARNINGS = 60 # Minutes

EVENT = 'cpu_too_hot'
BASE_URL = 'https://maker.ifttt.com/trigger/'
KEY = 'your_key_here'

def send_notification(temp):
    data = {'value1' : temp}
    url = BASE_URL + EVENT + '/with/key/' + KEY
    response = requests.post(url, json=data)
    print(response.status_code)

def cpu_temp():
    dev = os.popen('/opt/vc/bin/vcgencmd measure_temp')
    cpu_temp = dev.read()[5:-3]
    return float(cpu_temp)

while True:
    temp = cpu_temp()
    print("CPU Temp (C): " + str(temp))
    if temp > MAX_TEMP:
        print("CPU TOO HOT!")
        send_notification(temp)
        print("No more notifications for: " + str(MIN_T_BETWEEN_WARNINGS) +
              " mins")
        time.sleep(MIN_T_BETWEEN_WARNINGS * 60)
    time.sleep(1)

As with all the program examples in this book, you can also download this program (see Recipe 3.22).

I have left the MAX_TEMP deliberately low for testing purposes. If you live somewhere hot, you will want to bump this number up to 60 or 70.

Paste the key into ch_16_ifttt_cpu_temp.py on the line that starts KEY= and then run the program using:

$ python3 ch_16_ifttt_cpu_temp.py

You can increase your CPU temperature by playing a video or temporarily wrapping your Raspberry Pi in Bubble Wrap. When the event is triggered, you should receive an email that looks like Figure 16-11. Notice how the values have been substituted into the email (again, the obscuring is intentional).

Figure 16-11. A notification email

Discussion

Most of the action for this program takes place in the send_notification function. This function first constructs a URL that includes the key and request parameter value1 (containing the temperature) and then uses the Python requests library to send the web request to IFTTT.

The main loop continually checks the CPU temperature against the MAX_TEMP; if the temperature exceeds MAX_TEMP, the web request is sent, and a long sleep is started as specified by MIN_T_BETWEEN_WARNINGS. The sleep prevents your inbox from being flooded with notifications.

As an alternative to using IFTTT, you could, of course, just send an email directly using Recipe 7.16. However, by using IFTTT to send the messages, you are not restricted to email notifications—you could use any of the action channels available in IFTTT without having to write any code.

See Also

To send an email directly from Python, see Recipe 7.16.

The code to measure the CPU temperature is described in Recipe 13.10.

16.5 Sending Tweets Using ThingSpeak

Problem

You want to automatically send tweets from your Raspberry Pi—for example, to irritate people by telling them the temperature of your CPU.

Solution

You could just use Recipe 16.4 and change the action channel to be Twitter. However, the ThingSpeak service is an alternative way of doing this.

ThingSpeak is similar to IFTTT but is aimed squarely at IoT projects. It allows you to create channels that can store and retrieve data using web requests, and it also has a number of actions, including ThingTweet, which provides a web services wrapper around Twitter. This is easier to use than the Twitter API, which requires you to register your application with Twitter.

Start by visiting https://thingspeak.com and signing up. Note that this also involves creating a MATLAB account for no particularly good reason.

Next, select the ThingTweet action from the Apps menu. You are prompted to log in to Twitter, and then your action will become activated (Figure 16-12).

Figure 16-12. The ThingTweet action

The Python program to send the web request that triggers the tweet is called ch_16_send_tweet.py.

import time, os
import requests

MAX_TEMP = 37.0
MIN_T_BETWEEN_WARNINGS = 60 # Minutes

BASE_URL = 'https://api.thingspeak.com/apps/thingtweet/1/statuses/update/'
KEY = 'your_key_here'

def send_notification(temp):
    status = 'Thingtweet: Raspberry Pi getting hot. CPU temp=' + str(temp)
    data = {'api_key' : KEY, 'status' : status}
    response = requests.post(BASE_URL, json=data)
    print(response.status_code)

def cpu_temp():
    dev = os.popen('/opt/vc/bin/vcgencmd measure_temp')
    cpu_temp = dev.read()[5:-3]
    return float(cpu_temp)

while True:
    temp = cpu_temp()
    print("CPU Temp (C): " + str(temp))
    if temp > MAX_TEMP:
        print("CPU TOO HOT!")
        send_notification(temp)
        print("No more notifications for: " + str(MIN_T_BETWEEN_WARNINGS) +
              " mins")
        time.sleep(MIN_T_BETWEEN_WARNINGS * 60)
    time.sleep(1)

As with all the program examples in this book, you can also download this program (see Recipe 3.22).

As with Recipe 16.4, you need to paste your key from Figure 16-12 into the code before you run the program. Run and test the program in the same way you did in Recipe 16.4.

Discussion

The code is very similar to Recipe 16.4. The main difference is in the function send_notification, which constructs the tweet and then sends the web request with the message as the parameter status.

See Also

More information is available in the full documentation of the ThingSpeak service.

In Recipe 16.6, you use the popular CheerLights, implemented in ThingSpeak; in Recipe 16.7, you learn how to use ThingSpeak to collect sensor data.

16.6 CheerLights

Problem

You want to hook your Raspberry Pi up to an RGB LED and participate in the popular CheerLights project.

CheerLights is a web service that, when anyone sends a tweet to @cheerlights containing the name of a color, will record that color as being the CheerLights color. Around the world, many people have CheerLights projects that use a web service to request the last color and set their lighting to that color. So when anyone tweets, everyone’s lights change color.

Solution

Use a Raspberry Squid RGB LED connected to your Raspberry Pi (Figure 16-13) and run the test program called ch_16_cheerlights.py (shown after Figure 16-13).

Figure 16-13. A CheerLights display

from gpiozero import RGBLED
from colorzero import Color
import time, requests

led = RGBLED(18, 23, 24)
cheerlights_url = "http://api.thingspeak.com/channels/1417/field/2/last.txt"

while True:
    try:
        cheerlights = requests.get(cheerlights_url)
        c = cheerlights.content
        print(c)
        led.color = Color(c)
    except Exception as e:
        print(e)
    time.sleep(2)

As with all the program examples in this book, you can also download this program (see Recipe 3.22).

When you run the program, your LED should immediately set itself to a color. It will probably change color after a while when someone tweets; if it doesn’t, try tweeting a message such as “@cheerlights red,” and the color of your LED and the rest of the world’s LEDs should change. Valid color names for CheerLights are red, green, blue, cyan, white, oldlace, purple, magenta, yellow, orange, and pink.

Discussion

The code just sends a web request to ThingSpeak, which returns a string of colors as a 6-digit hexadecimal number. This is then used to set the LED color.

The try/except code is used to ensure that the program does not crash if there is a temporary network outage.

See Also

CheerLights uses ThingSpeak to store the last color in a channel. In Recipe 16.7, a channel is used to record sensor data.

If you don’t have a Squid, you can use an RGB on a breadboard (see Recipe 10.10), or you can even adapt Recipe 14.6 to control an entire LED strip.

16.7 Sending Sensor Data to ThingSpeak

Problem

You want to log sensor data to ThingSpeak and then see charts of the data over time.

Solution

Log in to ThingSpeak, and from the Channels drop-down, select My Channels. Next, create a new channel by completing the top of the form, as shown in Figure 16-14.

You can leave the rest of the form blank. When you have finished editing, click Save Channel at the bottom of the page. Click the API Keys tab to find a summary of the web requests that you can use, along with keys for the channel you just created (Figure 16-15).

Figure 16-14. Creating a channel in ThingSpeak

Figure 16-15. Getting data into a ThingSpeak channel

You will need to copy your API key (Write key) as the value for KEY in the program that follows.

To send data to the channel, you must send a web request. The Python program to send the web request is called ch_16_thingspeak_data.py:

import time, os
import requests

PERIOD = 60 # seconds
BASE_URL = 'https://api.thingspeak.com/update.json'
KEY = 'your key here'

def send_data(temp):
    data = {'api_key' : KEY, 'field1' : temp}
    response = requests.post(BASE_URL, json=data)

def cpu_temp():
    dev = os.popen('/opt/vc/bin/vcgencmd measure_temp')
    cpu_temp = dev.read()[5:-3]
    return float(cpu_temp)

while True:
    temp = cpu_temp()
    print("CPU Temp (C): " + str(temp))
    send_data(temp)
    time.sleep(PERIOD)

As with all the program examples in this book, you can also download this program (see Recipe 3.22).

Run the program. On the ThingSpeak channel page, on the Private View tab, you should see a graph like the one shown in Figure 16-16.

Figure 16-16. Charting the sensor data

This will update every minute as each new reading arrives.

Discussion

The variable PERIOD is used to determine the time interval after each sending of the temperature. This period is in seconds.

The send_data function constructs the web request, supplying the temperature in a parameter called field1.

If your data might be something of public interest—say, accurate environmental readings—you might want to make the channel public so that anyone can make use of it. This probably isn’t the case for your Pi’s CPU temperature.

See Also

For an example of exporting sensor data into a spreadsheet, see Recipe 13.23.

For an explanation of the code that reads the CPU temperature, see Recipe 13.10.

16.8 Responding to Tweets Using Dweet and IFTTT

Problem

You want your Raspberry Pi to perform some action in response to a certain hashtag or mention in a tweet.

Recipe 16.6 does this, but it does it very inefficiently because it relies on you continually polling with web requests to see whether the color has changed.

Solution

An efficient mechanism for monitoring tweets that does not rely on polling is to use IFTTT (see Recipe 16.4) to spot tweets of interest and then send a web request to a service called Dweet that can push notifications to a Python program running on your Raspberry Pi (Figure 16-17).

For example, you could flash an LED for 10 seconds every time there is a mention of your username on Twitter by using a Raspberry Squid or an LED attached to a breadboard.

As far as the hardware goes, this recipe just requires some electronics that do something noticeable when GPIO 18 goes high. This could be one channel of a Raspberry Squid (see Recipe 9.10) or a single LED attached to breadboard (see Recipe 10.1) or, for ultimate flexibility, a relay (see Recipe 10.5). Using a relay would allow you to create a project like Bubblino, the bubble-blowing Arduino bot.

Figure 16-17. IFTTT, Dweet, and Python, working together

The first step is to log in to IFTTT (see Recipe 16.4) and then create a new Applet. Choose an action channel of “New Mention of You” and then click “Create trigger.” For the recipe’s action channel, select Webhooks, and then select the action “Make a web request” and complete the fields, as shown in Figure 16-18.

The URL includes a request parameter with the ingredient of “text.” This will contain the body of the tweet. Although this will not be used other than to print it in the console, you might have the message displayed on an LCD screen for a more sophisticated project, so it is useful to know how to pass data from a tweet to the Python program.

Finally, click “Create recipe” to take the IFTTT recipe live.

The dweet.io web service operates rather like Twitter for IoT things. It has a web interface that allows you to both post and listen for dweets. Dweet does not require an account or any login details to make use of it; you can just have one thing (IFTTT, in this case) send a message to Dweet and have another thing (your Raspberry Pi Python program) wait for a notification from the service that something you are interested in has happened. In this case, the token that links the two is tweet_about_me. This is not very unique, and if several people are trying out this example from the book at the same time, you will all get one another’s messages. To avoid this, use a more unique token (say, by adding a random string of letters and numbers to the message).

Figure 16-18. Completing the “Make a web request” action channel in IFTTT

To access Dweet from your Python program, you need to install the dweepy library by using the following command:

$ sudo pip3 install dweepy

The program for this recipe is called ch_16_twitter_trigger.py:

import time
import dweepy
from gpiozero import LED

KEY = 'tweet_about_me'
led = LED(18)

while True:
    try:
        for dweet in dweepy.listen_for_dweets_from(KEY):
            print('Tweet: ' + dweet['content']['text'])
            led.on()
            time.sleep(10)
            led.off()
    except Exception:
        pass

As with all the program examples in this book, you can also download this program (see Recipe 3.22).

After it’s running, try mentioning yourself in a tweet, and the LED should light for 10 seconds.

Discussion

The program uses the listen_for_dweets_from method to leave an open connection to the dweet.io server, listening for any push messages from the server as a result of a dweet arriving from IFTTT in response to a tweet. The try/except block ensures that if there is any communication outage, the program will just start the listening process again.

See Also

For a similar project using a different approach, see Recipe 16.6.

Chapter 17. Home Automation

17.0 Introduction

As a low-cost and low-power device, a Raspberry Pi makes a great home automation hub that you can leave running without fear of huge electricity bills. For the recipes described in this chapter, you don’t need the power of a Raspberry Pi 4. In fact, a Raspberry Pi 2 or 3 will be plenty fast enough and will run cooler and use less electricity than a Raspberry Pi 4.

We start with Message Queuing Telemetry Transport (MQTT), the basic communication mechanism for most home automation systems, and then move on to look at using Node-RED (which you first met in Chapter 16) as a basis for home automation.

Strictly speaking, home automation is all about making your home smarter and more able to do things for itself—for example, to turn on a light for a set amount of time when movement is detected, or to automatically turn everything off at bedtime. But most people who are interested in home automation are also interested in remote control of the parts of their home that have been automated. We also look at remote control by smartphone in this chapter.

17.1 Making a Raspberry Pi into a Message Broker with Mosquitto

Problem

You want to make your Raspberry Pi a hub for your home automation system.

Solution

Install the Mosquitto software so that your Raspberry Pi can act as an MQTT broker.

Run the following commands to install Mosquitto and start it as a service so that it automatically starts when your Raspberry Pi reboots:

$ sudo apt-get update
$ sudo apt install -y mosquitto mosquitto-clients
$ sudo systemctl enable mosquitto.service

You can check to see whether everything is working by running the following command:

$ mosquitto -v
1562320464: mosquitto version 1.4.10 (build date Wed, 13 Feb 2019 00:45:38 +0000)
            starting
1562320464: Using default config.
1562320464: Opening ipv4 listen socket on port 1883.
1562320464: Error: Address already in use
$

The Error message is not really an error; it just means that Mosquitto is already running because we started it as a service.

Discussion

MQTT is a way of passing messages between one program and another. It has two parts:

Server

The central place where the passing of messages is controlled and messages are routed to the right recipient.

Client

A program that sends and receives messages to and from the server. There will normally be more than one client in a system.

Messages are passed using what is called a publish and subscribe model. That is, a client that has something interesting to say (e.g., a sensor reading) tells the server by publishing the temperature reading. Every few seconds, the client might take another reading and publish that, too.

Messages have a topic and a payload. In a system for automating lights, the topic might be bedroom_light and the payload on or off.

You can try this out by opening two Terminals at the same time. One Terminal will act as the publisher and the other as a subscriber. You can see this in action in Figure 17-1.

Figure 17-1. Two clients communicating using MQTT

Let’s break this down. The Terminal on the left is the subscriber, and here we issue the command:

$ mosquitto_sub -d -t pi_mqtt
Client mosqsub/2007-raspberryp sending CONNECT
Client mosqsub/2007-raspberryp received CONNACK
Client mosqsub/2007-raspberryp sending SUBSCRIBE (Mid: 1, Topic: pi_mqtt, QoS: 0)
Client mosqsub/2007-raspberryp received SUBACK
Subscribed (mid: 1): 0

The mosquitto_sub command subscribes the client. The -d option specifies debug mode, which just means you will see a lot more output about what the client and server are doing; this is useful while you are making sure everything is working. The -t pi_mqtt specifies a topic that the client is interested in as pi_mqtt.

The debug trace shows that the client is connecting to the server without problems and that the client has requested to subscribe and the server has acknowledged the subscription.

Leave this Terminal session running and open a second Terminal session to act as a client that’s going to publish something on the topic pi_mqtt. Enter the following command in this new Terminal window:

$ mosquitto_pub -d -t pi_mqtt -m "publishing hello"
Client mosqpub/2199-raspberryp sending CONNECT
Client mosqpub/2199-raspberryp received CONNACK
Client mosqpub/2199-raspberryp sending PUBLISH (d0, q0, r0, m1, 'pi_mqtt',
                                                ... (16 bytes))
Client mosqpub/2199-raspberryp sending DISCONNECT

Again, the -d and -t options specify debug mode and the topic, but this time there is an extra option of -m, which specifies a message to include in the publication. So if the publisher were a sensor, the message might be the sensor reading.

As soon as the mosquitto_pub command is sent, text like the following will appear in the first Terminal window (the subscriber):

Client mosqsub/5170-raspberryp received PUBLISH (d0, q0, r0, m0, 'pi_mqtt',
	... (16 bytes))
publishing hello

See Also

For information on Mosquitto, see https://mosquitto.org.

For other MQTT recipes in this chapter, see Recipe 17.2 and Recipe 17.5.

17.2 Using Node-RED with an MQTT Server

Problem

You want to combine Node-RED with an MQTT server to be able, for instance, to control a general-purpose input/output (GPIO) pin in response to MQTT message publications.

Solution

Use a Node-RED “mqtt” node and an “rpi gpio” node in a Node-RED flow like the one shown in Figure 17-2.

After you deploy this, you will be able to turn GPIO 18 on and off by sending mosquitto_pub commands. For testing purposes, attach an LED or Raspberry Squid LED to pin 18 (Recipe 10.1).

The flow refers to kitchen lights, as this example pretends that GPIO 18 is being used with something like a PowerSwitch Tail (Recipe 10.6) to switch lighting on and off.

Let’s build the example up one node at a time.

Figure 17-2. A Node-RED MQTT and GPIO workflow

Start by adding an “mqtt” node from the “input” category of Node-RED. Double-click the node to edit it (Figure 17-3).

Figure 17-3. Editing the “mqtt” node

Notice that the Server field just has the option to “Add new mqtt-broker.” We will return to this in a moment. For now, specify a topic (kitchen_lights) and give the node a meaningful name. The QoS field allows you to set the quality of service and determines how persistent the MQTT server is at getting messages to their intended destination. Level 2 means guaranteed delivery.

We now need to define an MQTT server for Node-Red, so click the Edit button next to the Server field. This opens the window shown in Figure 17-4.

Figure 17-4. Adding an MQTT server to Node-RED

Give the server a name and enter “localhost” in the Server field. We can do this because Node-RED and the MQTT server are running on the same Raspberry Pi.

Now we can add the “rpi-gpio out” node. You will find this in the Raspberry Pi section. After you have added it to the flow, open it (Figure 17-5).

Select “12 - GPIO 18” and give the node a name before clicking Done. Drag the connector from the “mqtt in” node to the Raspberry Pi GPIO node so that the flow looks like Figure 17-2.

Click the Deploy button and then open a Terminal session on the Raspberry Pi to test the flow.

Figure 17-5. Editing the GPIO output node

Type the following command in the Terminal window to publish a request to turn on the light:

$ mosquitto_pub -d -t kitchen_lights -m 1

The LED on pin 18 should light. Then, to turn off the LED, send:

$ mosquitto_pub -d -t kitchen_lights -m 0

Discussion

This recipe works only if the Raspberry Pi happens to be right next to the thing you want to control. In reality, you are more likely to want to use a wireless switch.

It is, however, useful to know how to control GPIO pins through MQTT and Node-RED.

Node-RED has the ability to import and export flows as JSON text. All the flows used in this chapter are available on the book’s GitHub pages at https://oreil.ly/WWdcW.

To import one of these flows into Node-RED, visit the GitHub page and then click the recipe number corresponding to the flow that you want to import. For example, in Figure 17-6, I have clicked recipe_17_10.json.

Figure 17-6. Selecting the JSON for a flow from GitHub

Select the whole of the line in the code area and copy it to your clipboard. Then switch back to your Node-RED web page and select the Import → Clipboard option from the Node-RED menu, as shown in Figure 17-7.

Note that when copying the code from GitHub, clicking the Raw button just above the code can make it easier to select all of the code for copying.

Then paste the code you copied from GitHub into the window shown in Figure 17-8 and select “new flow.”

Figure 17-7. Selecting the “Import from Clipboard” option

Figure 17-8. Pasting the flow code into the “Import nodes” dialog box

When you click Import, the flow appears in a new tab (Figure 17-9).

Figure 17-9. A newly imported flow

See Also

To see how you can control a WiFi switch using MQTT, see Recipe 17.5. To see a similar recipe that uses Node-RED instead, see Recipe 17.6.

Read more about MQTT QoS levels.

For more information see the full documentation on Node-RED.

17.3 Flashing a Sonoff WiFi Smart Switch for MQTT Use

Problem

You want to use a WiFi smart switch with your Raspberry Pi.

Solution

Flash new firmware (Tasmota) onto a low-cost Sonoff WiFi switch, configure the switch through a web interface, and then control it using MQTT.

The Sonoff web switches (shown in Figure 17-10) offer an extremely low-cost way of turning lighting and other appliances on and off wirelessly.

Figure 17-10. The Sonoff WiFi switch

However, the firmware preinstalled on the Sonoff switches is proprietary and relies on servers in China for communication to the internet. If you would prefer to have local control of your device and actually improve over the original firmware, you should follow this recipe to flash new open source firmware onto your Sonoff.

You can do all of this from your Raspberry Pi, but you will need a few things:

A Sonoff web switch (see “Modules”)

A row of four header pins (see “Miscellaneous”)

Four female-to-female jumper wires (see “Prototyping Equipment and Kits”)

Soldering equipment and solder (see “Prototyping Equipment and Kits”)

You will also need a Raspberry Pi 2 or later because earlier Raspberry Pis are not able to provide enough current at 3.3V to power the Sonoff.

Danger: High Voltage

Switching alternating current (AC) using a Sonoff requires the connection of live wires to the Sonoff’s screw terminals. This is electrician’s work and should be done only by someone qualified to do so.

Flash the Sonoff fresh out of its box, before it is wired into your household electricity. You can configure it without connecting it to an AC supply. The Raspberry Pi will power it.

Before you connect your Sonoff to AC, take it apart because you are going to need to solder a strip of four header pins into the holes supplied on the Sonoff’s circuit board. Figure 17-11 shows the position of the holes and also marks off the roles of the four header pins we are interested in. In fact, they are a Serial interface to the Sonoff.

Figure 17-11. Inside a Sonoff WiFi switch

Note that there are four pins and five holes on the Sonoff PCB (printed circuit board), so make sure that you attach header pins to the correct holes.

When you have soldered the header pins into place, the Sonoff should look like Figure 17-12.

Figure 17-12. The Sonoff with header pins attached

You now need to connect the header pins on the Sonoff to the GPIO pins on your Raspberry Pi as follows (use Figure 17-11 as a reference). Because this might cause unexpected resets of your Raspberry Pi, make these connections with your Raspberry Pi powered off.

Sonoff 3.3V to Raspberry Pi 3.3V

Sonoff RXD to Raspberry Pi TXD

Sonoff TXD to Raspberry Pi RXD

Sonoff GND to Raspberry Pi GND

Figure 17-13 shows a Raspberry Pi connected to the Sonoff.

Figure 17-13. Flashing a Sonoff with a Raspberry Pi 2

Raspberry Pi Reboot

Note that when the Sonoff is powered from the Raspberry Pi in this way, it can cause the Raspberry Pi to reset. This is particularly true when putting the Sonoff into flash mode because this starts the WiFi hardware.

Unexpected restarts can leave your SD card corrupted, so be sure to adhere to the following procedure for putting the Sonoff into flash mode while the Raspberry Pi is powered but shutdown so as to avoid any problems with unexpected resets.

Changing the firmware (flashing) the Sonoff requires a piece of Python software called esptool. To download it onto your Raspberry Pi, run the following command:

$ git clone https://github.com/espressif/esptool.git
$ cd esptool

Having downloaded the software, we also need to get hold of the replacement Tasmota firmware to flash onto the Sonoff. To do this, run the following command from within the esptool directory:

$ wget https://github.com/arendst/Sonoff-Tasmota/releases/download/v6.6.0/sonoff-basic.bin

This will fetch a file called sonoff-basic.bin.

The remainder of the process is as follows:

Shut down your Raspberry Pi using this command:

$ sudo shutdown now

Leave the power connected to your Raspberry Pi. It’s now in standby mode.

Put the Sonoff into flash mode.

At the moment, the LED on your Sonoff will probably be happily flashing away. Ironically, when we put it into flash mode, the LED will stop flashing and be unlit. To put the Sonoff into flash mode, you must press the Sonoff’s push switch (Figure 17-11) as the Sonoff is powered up and then release it after a few seconds.

To do this, unplug the 3.3V female-to-female jumper wire at one end (I found the Raspberry Pi end easier to unplug) and then press and hold down the Sonoff’s push switch. Next, reattach the jumper wire and then release the switch. The Sonoff’s LED should no longer be blinking. It’s now in flash mode, ready to receive a new program.

Boot your Raspberry Pi.

To get your Raspberry Pi out of shutdown mode, you need to reset it. You can’t do this by cycling the power, because that would take the Sonoff out of flash mode. So instead follow Recipe 12.14. If you don’t want to actually add a reset button to your Raspberry Pi, you can just use a paper clip bent to the right shape to connect the two reset contacts described in Recipe 12.14.

Erase the Sonoff.

After your Raspberry Pi has booted up, change directory to esptools and then run the command to erase the Sonoff. You should see messages in the Terminal like those shown here:

$ cd /home/pi/esptools
$ python3 esptool.py --port /dev/ttyS0 erase_flash
esptool.py v2.7-dev
Serial port /dev/ttyUSB0
Connecting....
Detecting chip type... ESP8266
Chip is ESP8266EX
Features: WiFi
Crystal is 26MHz
MAC: 5c:cf:7f:3b:69:c4
Uploading stub...
Running stub...
Stub running...
Erasing flash (this may take a while)...
Chip erase completed successfully in 3.1s
Hard resetting via RTS pin...

Shut down your Raspberry Pi and again put the Sonoff into flash mode by repeating steps 2 and 3.

Flash the Tasmota software onto the Sonoff.

Change directory to esptools and then run the command to flash the sonoff-basic.bin file that you fetched earlier onto the Sonoff:

$ cd /home/pi/esptools
$ python3 esptool.py --port /dev/ttyS0 write_flash
  -fs 1MB -fm dout 0x0 sonoff-basic.bin
esptool.py v2.7-dev
Serial port /dev/ttyUSB0
Connecting....
Detecting chip type... ESP8266
Chip is ESP8266EX
Features: WiFi
Crystal is 26MHz
MAC: 5c:cf:7f:3b:69:c4
Uploading stub...
Running stub...
Stub running...
Configuring flash size...
Compressed 432432 bytes to 300963...
Wrote 432432 bytes (300963 compressed) at 0x00000000 in 27.6 seconds
  (effective 125.5 kbit/s)...
Hash of data verified.

Leaving...
Hard resetting via RTS pin...

Discussion

When all of this is complete, you can disconnect the jumper wires and get a qualified person to install your Sonoff so that it is supplied from AC and ready to switch whatever you have in mind for it to switch. However, it might be wise to do a bit more testing of the newly flashed Sonoff before putting it somewhere inaccessible. So you can, if you prefer, power the Sonoff from your Raspberry Pi by leaving the 3.3V and GND jumpers in place. The relay will not switch when powered just from the Raspberry Pi, but the LED will light when the Sonoff is switched on.

In addition to the Sonoff model that I used here, there are many other types of models, including some that look like regular light switches but contain a WiFi module.

See Also

For more information on Tasmota, see https://github.com/arendst/Sonoff-Tasmota.

Having flashed your Sonoff, follow the next recipe (Recipe 17.4) to configure it.

17.4 Configuring a Sonoff WiFi Smart Switch

Problem

You need to join your Sonoff WiFi switch to your home WiFi network.

Solution

First, flash the Tasmota firmware onto your Sonoff using Recipe 17.4. If you have the Tasmota firmware on your Sonoff and it’s powered up, either using the 3.3V supply of your Raspberry Pi (Pi 2 or later) or in situ with an AC supply, you can now configure the Sonoff by connecting to the wireless access point that it will be running. At the time of writing, you won’t be able to do this with your Raspberry Pi, because after you join it, the wireless access point does not trigger the welcome page for the access point to be opened in the same way as it does if you connect using a Mac or Windows PC. So connect to the WiFi access point called something like Sonoff-2500 on your PC or Mac, or even on your smartphone (Figure 17-14).

Figure 17-14. Joining a Sonoff to a WiFi network

You actually have the option to enter credentials for two wireless access points. But assuming you have just one, either use the “Scan for wifi networks” link at the top of the page or else just enter your access point name in the AP1 SSId field and your password in the AP1 Password field and then click Save.

The Sonoff will reboot, and if you entered the access point credentials correctly, it will reboot connecting to your network.

Now you have the problem of finding the Sonoff’s IP address. A tool like Fing for Android phones or Discovery for iOS will do this. As you can see from Figure 17-15, in my case, the Sonoff has been assigned the IP address 192.168.1.84.

Figure 17-15. Finding the Sonoff’s IP address

Discussion

Now that the Sonoff is connected to your network, it will change mode, and rather than run an entire access point, it will instead run a web server on your network from which you can manage the device. To connect to this web page, enter the IP address of the Sonoff into a browser on any machine connected to the network. You should see something like Figure 17-16.

Figure 17-16. The Sonoff’s web page

Click the Toggle button to turn the Sonoff’s LED on and off. Note that if the Sonoff is actually wired into your house, rather than being powered from your Raspberry Pi, it will turn whatever it was connected to on and off.

See Also

To see how you can configure these switches to work with MQTT and Node-RED, see Recipe 17.5.

17.5 Using Sonoff Web Switches with MQTT

Problem

You want to be able to control your newly flashed Sonoff web switch using MQTT.

Solution

First make sure that you have followed Recipe 17.3 and Recipe 17.4 to flash new firmware onto your Sonoff device and configure it to connect to your WiFi network.

To control the Sonoff switch using MQTT, you need to configure the Sonoff using its web interface. Enter the IP address of your Sonoff (see Recipe 17.4) into your browser and click the Configuration button. This opens the menu shown in Figure 17-17.

Figure 17-17. The Sonoff Tasmota configuration menu

Click the Configure MQTT option to open the MQTT configuration page, shown in Figure 17-18.

Figure 17-18. The Sonoff Tasmota MQTT configuration menu

This is where we configure the Sonoff as a client to an MQTT server (see Recipe 17.1) and specify how it will subscribe, so that when we publish a command (say, to turn on), it understands the command.

To do this, you need to change some of the fields in the configuration form:

Change the Host field to be the IP address of your Raspberry Pi running the MQTT server.

Change the Client field to “sonoff_1”. We’ve added a “_1” in case we end up with multiple Sonoff devices that we need to distinguish. You can also use a more meaningful name here if you like—perhaps “bedroom_1_sonoff” if that’s where the Sonoff is going to be installed.

The User and Password fields are not used, because our MQTT server does not have any security configured. This is not as reckless as it sounds, as no one can do anything unless they are already inside your network. So it does not matter what you put in these fields.

Change the Topic to be “sonoff_1” again because you might end up with multiple Sonoff switches.

Leave the “Full topic” field unchanged.

Click Save to save the changes, and the Sonoff will reboot itself for the changes to take effect.

Discussion

You can test this MQTT interface from a Terminal. Enter the following command, and the Sonoff’s LED should light:

$ mosquitto_pub -t cmnd/sonoff_1/power -m 1

Enter this command to turn the switch off again:

$ mosquitto_pub -t cmnd/sonoff_1/power -m 0

If this doesn’t work, add the -d option to the commands to check that the Mosquitto client commands are connecting to the MQTT server.

See Also

We build on the work of this recipe in Recipe 17.6 to control the switch using Node-RED.

17.6 Using Flashed Sonoff Switches with Node-RED

Problem

You want to use a flashed Sonoff web switch with Node-RED.

Solution

Follow Recipe 17.5 to get your Sonoff working with MQTT, and then use a Node-RED MQTT node in a flow like that shown in Figure 17-19.

If you want to import the flow rather than build it up from scratch, you can find it at https://oreil.ly/vdZSb. Follow the instructions in the Discussion section of Recipe 17.2 to import the flow.

Figure 17-19. A Node-RED flow for a delay timer

This flow assumes that there is a push button attached to the Raspberry Pi’s GPIO 25, and that when it’s pressed, the Sonoff will be switched on for 10 seconds before being switched off again.

The push button is set up the same way as the button we used in Recipe 16.3 and needs a hardware switch connected to GPIO 25 (see Recipe 12.1).

You will find the Trigger nodes in the Function section of Node-RED. We need two of these, so drag them out to the flow. Figure 17-20 shows the settings for the “On trigger” node.

Figure 17-20. Configuring the “On trigger” node

This Trigger node is configured to send a 1 when triggered, wait for a quarter of a second (for debouncing), and then do nothing further. It’s given the name “On trigger.”

The “Off trigger” is different from the “On trigger,” because we need it to delay for 10 seconds before sending a 0 to the Sonoff. Figure 17-21 shows the settings for this.

Figure 17-21. Configuring the “Off trigger” node

Finally, add an “mqtt” node from the Output section. Open this to configure it (Figure 17-22).

The Server field will prompt you to add a new MQTT server and enter its details, including its name (I used MyHomeAutomation) and the IP address (localhost) and port (1880).

Figure 17-22. Configuring the “mqtt out” node

Change the Topic and Name fields, as shown in Figure 17-22. You can now connect everything as shown in Figure 17-19 and deploy the flow.

When you press the button, the Sonoff should turn on and then turn itself off again after 10 seconds.

Discussion

This recipe shows just how far you can go with Node-RED without having to write any actual code. By thinking of the automation as a flow of messages, Node-RED provides a really nice way of programming.

To use a motion sensor to switch the lights on for a predetermined period of time, you could replace the switch with a Passive Infrared (PIR) motion sensor (see Recipe 12.9).

See Also

For full documentation on Node-RED, see https://nodered.org/docs/.

17.7 The Node-RED Dashboard

Problem

You want to be able to turn things on and off from your smartphone.

Solution

Install the Node-RED Dashboard extension, add some user interface (UI) controls to a flow, and then visit the Dashboard from your phone’s browser.

To install the Node-RED Dashboard, run the following commands:

$ sudo systemctl stop nodered.service
$ apt-get update
$ cd ~/.node-red
$ sudo apt-get install npm
$ npm install node-red-dashboard
$ sudo systemctl start nodered.service

When you’ve finished installing the Dashboard, you will end up with a new section of control nodes in Node-RED (Figure 17-23).

Figure 17-23. Node-RED Dashboard nodes

We can use the button node to replace the physical button that we used in Recipe 17.6 with a button on a web page. The flow for this is shown in Figure 17-24. If you want to import the flow rather than build it up from scratch, you can find the flow at https://oreil.ly/0YSDh. Follow the instructions in the Discussion section of Recipe 17.2 to import the flow.

Figure 17-24. A flow for a push-button timer

The trigger button is the same as the “Off trigger” in Recipe 17.6, and the “Sonoff_1” node is the same as the same node in Recipe 17.6. However, the Raspberry Pi GPIO node is replaced by a Dashboard button node.

Because you might need quite a few controls to remotely control your home automation system, Dashboard controls are collected into a group, and groups are themselves collected into tabs. You can define your own groups and tabs when you add a new node from the Dashboard category. This happens when you edit the node (Figure 17-25).

Figure 17-25. Configuring the Lights On Button node

In Figure 17-25 you can see that the Group is set to Lights in the tab [Home]. To get to this point, I had to click on “Add new UI group.” This in turn asked me to “Add a new tab.” Once you have created a tab and group, these will become defaults. You don’t have to create them every time.

Note that the Payload is set to 1 to turn the light on, and it’s connected directly to the “mqtt” node.

You can now deploy the workflow.

To try out the new flow, open a browser on your phone (or any computer on your network) and enter your Raspberry Pi’s IP address with :1880/ui on the end. For my Raspberry Pi, the full URL is http://192.168.1.77:1880/ui. The screen should look something like Figure 17-26.

Figure 17-26. A push button on the Node-RED Dashboard

When you click the button on your phone, the Sonoff should turn on for 10 seconds.

Discussion

Even though it’s quite useful to be able to turn the light on for a preset timed period, it would also be useful to have an override on/off switch. In Figure 17-27, a switch has been added. This flow is also available on GitHub at https://oreil.ly/G6m8e.

Figure 17-27. Adding an on/off switch to the flow

You also can connect this to the “Sonoff_1” MQTT node so that it as well as the push button can be used to turn the light on and off. Figure 17-28 shows the settings for the Lights On/Off switch.

Figure 17-28. The settings for the Lights On/Off switch

When the flow is deployed, the UI will display the extra switch (Figure 17-29) automatically when you go back to the ui web page on your phone (something like http://192.168.1.77:1880/ui but with your Node-RED server’s IP address).

Figure 17-29. A web interface for controlling lights

See Also

For the full documentation on Node-RED, see https://nodered.org/docs.

17.8 Scheduled Events with Node-RED

Problem

You want to use Node-RED to do something at a certain time—for example, to turn out all the lights at 1 a.m. every night.

Solution

Use the Node-RED inject node.

The flow shown in Figure 17-30 is based on the flows of Recipe 17.6. If you want to import the flow rather than build it up from scratch, you can find it at https://oreil.ly/EVCiX. Follow the instructions in the Discussion section of Recipe 17.2 to import the flow.

Figure 17-30. Using an inject node to schedule actions

A dashboard switch is used to turn the Sonoff (assumed to be switching a light) on and off, but in addition, there is an inject node (Auto Off) that is configured to inject a message of 0 to the “Sonoff_1” MQTT node. Figure 17-31 shows the configuration for the inject node.

Figure 17-31. Configuring a Node-RED inject node as a timed event

Discussion

If you had a number of Sonoff switches connected to appliances all around your house, one inject node could turn them all off by fanning out the message, as shown in Figure 17-32.

Figure 17-32. Switching off multiple devices

See Also

For full documentation on Node-RED, see https://nodered.org/docs/.

17.9 Publishing MQTT Messages from a Wemos D1

Problem

You want to be able to publish MQTT messages using a low-cost programmable WiFi board, perhaps because a button is pressed.

Solution

Use a low-cost ESP8266-based board like the Wemos D1 with customized software. Figure 17-33 shows a Wemos D1 with a Squid Button attached to one of its GPIO pins, powered by a USB power bank.

When the button is pressed, a message will be published to an MQTT server.

Figure 17-33. A Wemos D1 and Squid Button

To make this recipe, you will need the following:

A Wemos D1 mini (see “Modules”)

A Raspberry Squid Button (see “Modules”)

A USB power bank or other means of powering the Wemos D1

To be able to program the Wemos D1 from your Raspberry Pi, you need to install the Arduino integrated development environment (IDE) on your Raspberry Pi (Recipe 18.1) and then add support for the ESP8266 using Recipe 18.11.

Connect the Squid Button or other switch between the Wemos pin named D6 and GND.

Before you can use the sketch (the name for Arduino programs), you need to install an MQTT library into the Arduino IDE, so download the library as a ZIP file using the following commands:

$ cd /home/pi
$ wget https://github.com/knolleary/pubsubclient/archive/master.zip

Next, open the Arduino IDE, and then from the Sketch->Include Library menu, select Add ZIP Library. Navigate to the file master.zip that you just downloaded, and the library will be installed.

The Arduino program for this is available as part of the downloads for the book (see Recipe 3.22). You will find it in the folder called ch_17_web_switch, inside a folder at the same level as the python folder called arduino.

Open the sketch in the Arduino IDE by clicking ch_17_web_switch.ino. Set the board type to Wemos D1 and the serial port to /dev/ttyUSB0 (see Recipe 18.11).

Before uploading the sketch to the Arduino, you need to make a few changes to the code. Look for these lines near the top of the sketch:

const char* ssid = "your wifi access point name";
const char* password = "your wifi password";
const char* mqtt_server = "your MQTT IP address";

Replace the placeholder text for ssid, password, and mqtt_server with the appropriate values for your setup.

Then click the upload button in the Arduino IDE.

After you’ve programmed it, the Wemos does not need to be connected to your Raspberry Pi, so if you want, you can power it by some other means, such as a USB power bank. However, the sketch prints out useful debug information, so it’s worth staying tethered to your Raspberry Pi until you know everything is working. To see this information, open the Arduino IDE’s serial console (see Recipe 18.2), which should look something like Figure 17-34.

Figure 17-34. Using the Arduino serial monitor to view the Wemos output

To test the recipe, start a Terminal session on your Raspberry Pi and run the following command to subscribe to button presses:

$ mosquitto_sub -d -t button_1
Client mosqsub/5007-raspberryp sending CONNECT
Client mosqsub/5007-raspberryp received CONNACK
Client mosqsub/5007-raspberryp sending SUBSCRIBE (Mid: 1, Topic: button_1,
                                                  QoS: 0)
Client mosqsub/5007-raspberryp received SUBACK
Subscribed (mid: 1): 0
Client mosqsub/5007-raspberryp received PUBLISH (d0, q0, r0, m0, 'button_1', ...
                                                 (16 bytes))
Button 1 pressed

Now every time you press the button, the message Button 1 pressed should appear in the Terminal.

Discussion

This is a book about Raspberry Pi, not Arduino, so we won’t go through the Arduino C code in any detail.

The code is based on the example sketch called mqtt_basic in the library PubSubClient. As well as the constants at the top of the file for your WiFi credentials, the lines

const char* topic = "button_1";
const char* message = "Button 1 pressed";

might also be of interest. They determine the MQTT topic to be used and the message to accompany published events. You could program an entire series of Wemos buttons with different topics and messages.

See Also

To use your newly configured Wemos with Node-RED, see Recipe 17.10.

You will learn much more about devices like the Wemos in Chapter 18.

17.10 Using a Wemos D1 with Node-RED

Problem

You want to include a Wemos D1, with a button attached, in a Node-RED flow.

Solution

As an example, we can use the Wemos WiFi button from Recipe 17.9 in a Node-RED flow to toggle a Sonoff web switch (Recipe 17.4) on and off.

Figure 17-35 shows the Node-RED flow for this. If you want to import the flow rather than build it up from scratch, you can find the flow at https://oreil.ly/aIdtv. Follow the instructions in the Discussion section of Recipe 17.2 to import the flow.

Figure 17-35. A Node-RED flow for a WiFi light switch

To make this recipe, you will benefit from having already tried all the previous recipes in this chapter, as well as Recipe 18.11.

The Button 1 MQTT node subscribes to messages from the Wemos D1. Figure 17-36 shows the settings for this node.

Figure 17-36. Configuring the Button 1 node

The important thing here is that the Topic is set to “button_1.” The Trigger node works in the same way as in Recipe 17.6. The Trigger node is more interesting because this node remembers a value, which can be a 1 or a 0, and flips this value each time a message passes through it. This has to be done as a general function with a little bit of JavaScript code that remembers the state and toggles it. Figure 17-37 shows the node’s configuration including the code. This is a useful function that you will probably find yourself reusing in other projects.

Figure 17-37. The Toggle function

Discussion

Node-RED is a powerful way to quickly put together a home automation system. If you are used to a conventional programming language, this way of doing things takes a little getting used to; however, when you’ve mastered it, you won’t want to go back to writing reams of code.

There are lots of other interesting nodes in Node-RED’s palette, so take some time to explore them. Hovering over a node will display details about what it does, and you can follow this up by dragging the node onto a flow and trying it out.

See Also

For full documentation on Node-RED, see https://nodered.org/docs.

Chapter 18. Arduino and Raspberry Pi

18.0 Introduction

Although a Raspberry Pi is ideal for projects that need a network connection or a graphical user interface (GUI), the low-power general-purpose input/output (GPIO) and lack of any analog inputs puts it at a disadvantage to microcontroller boards such as the Arduino (Figure 18-1). Fortunately, it is possible to have the best of both worlds by connecting an Arduino to a Raspberry Pi and allowing the Arduino to interface with external electronics.

Arduino boards are superficially a little like a Raspberry Pi in that they are small and essentially are computers. However, Arduino boards are very different from the Raspberry Pi in a number of respects:

They do not have any interface to keyboard, mouse, or screen.

They have just 2 KB of RAM and 32 KB of flash memory for storing programs.

Their processor runs at just 16 MHz, compared with the Raspberry Pi 4’s 1.2 GHz.

This might lead you to wonder why you would use such an apparently feeble board rather than the Raspberry Pi directly.

The answer is that Arduino boards, the most common being the Arduino Uno, are better than the Raspberry Pi at interfacing with external electronics in several ways. For example, Arduino boards have the following features:

Fourteen digital inputs/outputs (I/Os), like the Raspberry Pi’s GPIO pins, but each pin can provide up to 40 mA, compared with the original Raspberry Pi’s 3 mA. This enables them to power more devices without the need for extra electronics.

Six analog inputs. This makes connecting analog sensors much easier (see Recipe 18.7).

Six pulse-width modulation (PWM) outputs. These outputs are hardware-timed and produce a much more accurate PWM signal than can be achieved with the Raspberry Pi, making them a lot better for controlling servo motors.

A huge range of plug-in shields (the Arduino name for Hardware Attached on Top [HAT] add-ons) for everything from motor control to LCD displays of various sorts.

Figure 18-1. An Arduino Uno board

In many ways, using a Raspberry Pi with an Arduino to handle all the low-level stuff is a good combination, playing to the strengths of both boards.

As well as official Arduino boards, there are also very popular Arduino-compatible boards with built-in WiFi that are based on the ESP8266 and ESP32 and are low cost and great for Internet of Things (IoT) projects (Chapter 16) and home automation (Chapter 17).

18.1 Programming an Arduino from Raspberry Pi

Note

Be sure to check out the accompanying video for this recipe at http://razzpisampler.oreilly.com.

Problem

You want to run the Arduino integrated development environment (IDE) on a Raspberry Pi so that you can write and upload programs onto an Arduino.

Solution

The Arduino IDE is available for the Raspberry Pi. It is a little bit slow but usable. You will definitely want to use the superior speed of the Raspberry Pi 2, 3, or 4 when using the Arduino IDE.

Use these commands to install the Arduino IDE:

$ wget http://downloads.arduino.cc/arduino-1.8.5-linuxarm.tar.xz
$ tar -x -f arduino-1.8.5-linuxarm.tar.xz
$ cd arduino-1.8.5/
$ ./install.sh

You can now connect your Arduino Uno to your Raspberry Pi through its USB cable. From the Tools menu, select Board, and set the board type to Arduino Uno. Then, from the Serial Port option, select /dev/ttyACM0 (Figure 18-2).

To upload a test program that will make the LED on the Arduino blink, select the File menu, click Examples, and then Basic, and then click Blink. On the toolbar, click the right arrow to start the compile and upload process. If all is well, you should see a Done Uploading message in the status area at the bottom of the IDE window.

Discussion

To get the most out of using an Arduino with your Raspberry Pi, you need to learn a little Arduino programming. You might find the book Programming Arduino: Getting Started with Sketches (McGraw-Hill/Education/TAB), by yours truly, helpful.

You can, however, make use of an Arduino without needing to write any code on the Arduino side, using a project called PyFirmata. Recipe 18.3 explains how to use PyFirmata.

Figure 18-2. Selecting the serial port in the Arduino IDE

See Also

The Arduino website has many useful resources and a very responsive forum.

18.2 Communicating with an Arduino by Using the Serial Monitor

Problem

You want to display messages sent from an Arduino.

Solution

The Arduino IDE includes a feature called the serial monitor, which allows you both to send text messages to the Arduino and to see messages from the Arduino over the USB cable.

To try this out, you first need to write a very short Arduino sketch (programs are called sketches in the Arduino world). This sketch will just repeat a message, sending it every second.

The Arduino sketch is listed here. You can also find it in the arduino folder of the book’s code, ch_18_serial_test (see Recipe 3.22).

If you would prefer to write the code yourself, use File → New to create a new sketch, and copy the following text into it before uploading it to the Arduino:

void setup()
{
  Serial.begin(9600);
}

void loop()
{
  Serial.println("Hello Raspberry Pi");
  delay(1000);
}

As soon as the sketch is uploaded to the Arduino, it will start sending the message “Hello Raspberry Pi” over serial. You won’t see this until you open the serial monitor (Figure 18-3) by clicking the icon that looks like a magnifying glass on the right side of the Arduino IDE’s toolbar.

Figure 18-3. Viewing messages with the serial monitor

The serial monitor has a drop-down list in the lower-right corner, where you can select the baud rate (speed of communication). If this isn’t already set to 9600, change it to that value.

Discussion

In Recipe 18.10, we look at writing your own custom code to communicate with Python programs running on the Raspberry Pi so that you don’t need to have the Arduino IDE running.

A more generic approach is to use something called PyFirmata, which avoids the need for any programming on the Arduino. See Recipe 18.3 for details.

See Also

Arduino is quite easy to learn; here are some links to books and online resources to get you started:

Programming Arduino: Getting Started with Sketches (Mcgraw-Hill Education/TAB) by Simon Monk

The official Getting Started with Arduino Guide

The Adafruit Arduino lesson series

Arduino Cookbook (O’Reilly) by Michael Margolis

18.3 Setting Up PyFirmata to Control an Arduino from a Raspberry Pi

Problem

You want to use an Arduino as an interface board for your Raspberry Pi.

Solution

We will use two programs to achieve this link: PyFirmata on the Raspberry Pi and Firmata on the Arduino.

Connect the Arduino to a USB socket of the Raspberry Pi so that the computer can communicate with and send power to the Arduino.

Next, install the Firmata sketch onto the Arduino and the PyFirmata program onto your Raspberry Pi. This entails installing the Arduino IDE, so if you haven’t already done so, follow Recipe 18.1.

The Arduino IDE includes Firmata, so all you need to do to install Firmata onto your Arduino board is to upload a sketch. You will find the sketch at File → Examples → Firmata → StandardFirmata.

After Firmata is installed, the Arduino waits for communication from the Raspberry Pi.

Now you need to install PyFirmata, the other half of the link. This requires the use of the PySerial library, so follow Recipe 9.6 to install this.

You can now download and install PyFirmata by using this command:

$ sudo pip3 install pyfirmata

You can try out the pyfirmata library from the Python console. Enter the following commands in turn to switch on the built-in LED on Arduino pin 13 (marked with an L) and then turn it off again:

$ python3
Python 3.5.3 (default, Sep 27 2018, 17:25:39)
[GCC 6.3.0 20170516] on linux
Type "help", "copyright", "credits", or "license" for more information.
>>> import pyfirmata
>>> import pyfirmata
>>> board = pyfirmata.Arduino('/dev/ttyACM0')
>>> pin13 = board.get_pin('d:13:o')
>>> pin13.write(1)
>>> pin13.write(0)
>>> board.exit()

Discussion

The preceding code first imports the PyFirmata library and then makes an instance of Arduino called board, using the USB interface (/dev/ttyACM0) as its parameter. You can then reference one of the Arduino pins (in this case, 13) and set it to be a digital output. The d is for digital, 13 is the pin number, and o is for output.

To set the output pin high, use write(1), and to set it low, use write(0). You can also use True and False in place of 1 and 0.

Figure 18-4 shows an Arduino with the rows of connections down both sides of the board.

Figure 18-4. I/O pins on an Arduino Uno

You can use the pins at the top marked 0 to 13 as digital inputs or outputs. Some of these pins are also used for other things. Pins 0 and 1 are used as a Serial interface and are in use when the USB port is being used, and pin 13 is attached to the on-board LED marked with an L (just under the GND and 13 connections). The digital I/O pins 3, 5, 6, 9, 10, and 11 have a ~ symbol next to them that indicates that they can be used for PWM output (see Recipe 10.3).

On the other side of the board, there is a set of connectors that supplies power at 5V and 3.3V, as well as six analog inputs marked A0 to A5.

An Arduino Uno on its own uses about 50 mA, which, given that the Raspberry Pi itself is probably using about 10 times that, makes it perfectly possible to power the Arduino from the USB connection of the Raspberry Pi. However, if you start attaching a lot of external electronics to the Arduino, and the current consumption increases, you might want to power the Arduino from its own power adapter by using the DC barrel socket. This will accept 7V to 12V DC.

The only real downside of using Firmata is that, because all instructions have to come from the Raspberry Pi, it doesn’t make much use of Arduino’s ability to run independently. For advanced projects, you will probably end up writing your own Arduino code that receives instructions from the Raspberry Pi and/or sends messages to the Raspberry Pi while it gets on with other tasks.

See Also

The following recipes look at using the full range of Arduino pin features with PyFirmata: 18.4, 18.5, 18.6, 18.7, and 18.8.

You can find the official PyFirmata documentation at PyFirmata’s GitHub page.

18.4 Writing Digital Outputs on an Arduino from a Raspberry Pi

Problem

You want to control Arduino digital outputs from Python on a Raspberry Pi.

Solution

In Recipe 18.3, you flashed the built-in LED (labeled with an L) on the Arduino board. Here, you build on this to attach an external LED and write a short Python program to make it blink.

To make this recipe, you will need the following:

Arduino Uno (see “Modules”)

Breadboard and jumper wires (see “Prototyping Equipment and Kits”)

270Ω resistor (see “Resistors and Capacitors”)

LED (see “Opto-Electronics”)

As an alternative to using a breadboard and an LED, you could plug in one color channel of a Squid RGB LED (Recipe 9.10).

Connect the breadboard to the Arduino, as shown in Figure 18-5.

Figure 18-5. Wiring diagram for an Arduino and an LED

If you haven’t already done so, follow Recipe 18.3 to set up PyFirmata.

The Python script that follows makes the LED blink at a rate of about 1 Hz.

You can find this program in the Python section of the book downloads, where it is called ch_18_ardu_flash.py (see Recipe 3.22):

import pyfirmata
import time

board = pyfirmata.Arduino('/dev/ttyACM0')
led_pin = board.get_pin('d:10:o')

while True:
    led_pin.write(1)
    time.sleep(0.5)
    led_pin.write(0)
    time.sleep(0.5)

Discussion

This is very similar to connecting an LED to a Raspberry Pi (Recipe 10.1). However, since Arduino outputs can supply a lot more current than Raspberry Pi outputs, you can use a smaller value resistor and make the LED a bit brighter. Arduino Uno outputs are also 5V rather than 3.3V.

If you want the user interface (UI) to control the LED like you set it up to do in Recipe 10.8 (and as shown in Figure 18-6), it’s pretty straightforward to modify the code. You can find the modified program, called ch_18_ardu_gui_switch.py, in the book’s downloads. Remember, this will not work from the Secure Shell (SSH) command line. You need to have access to the Raspberry Pi’s graphical environment so that you can see the UI.

Figure 18-6. A UI for turning things on and off

See Also

For controlling an LED directly from a Raspberry Pi, see Recipe 10.1.

18.5 Using PyFirmata with TTL Serial

Problem

You want to use PyFirmata over the serial connection (RXD and TXD on the GPIO connector) rather than by USB.

Solution

Use a level converter to connect the RXD pin of the Raspberry Pi to the Tx pin of the Arduino, and the TXD pin of the Raspberry Pi to the Rx pin of the Arduino.

To make this recipe, you will need the following:

Arduino Uno (see “Modules”)

Breadboard and jumper wires (see “Prototyping Equipment and Kits”)

270Ω and 470Ω resistors (see “Resistors and Capacitors”) or a four-way bidirectional level converter (see “Modules”)

If you are using the level converter module (rather than making your own level converter), connect the breadboard as shown in Figure 18-7.

Figure 18-7. Wiring diagram, using a level converter module for serial communication with an Arduino

If, on the other hand, you are using the pair of resistors, connect the breadboard as shown in Figure 18-8.

The Arduino Rx input is fine with just 3.3V from the Raspberry Pi TXD pin; however, the 5V coming from the Arduino Tx pin must be dropped to the 3V expected by the Raspberry Pi.

You will need to set up PyFirmata (see Recipe 18.3). The Arduino side of the project remains exactly the same as Recipe 18.4, where USB is used instead of the serial connection. There is one change that you need to make to the Python program running on the Raspberry Pi: change the device name from /dev/ttyACM0 to /dev/ttyS0 because the serial port has a different device name from the USB interface.

Figure 18-8. Wiring diagram, using a pair of resistors for serial communication with an Arduino

The following Python script makes the LED blink at a rate of about 1 Hz (you can find the code in ch_18_ardu_flash_ser.py [see Recipe 3.22]):

import pyfirmata
import time

board = pyfirmata.Arduino('/dev/ttyS0')
led_pin = board.get_pin('d:13:o')

while True:
    led_pin.write(1)
    time.sleep(0.5)
    led_pin.write(0)
    time.sleep(0.5)

Discussion

The level conversion is necessary because the Raspberry Pi serial port connections, RXD and TXD, operate at 3.3V, whereas the Arduino Uno operates at 5V. Although it is OK for the 5V Arduino to use a 3.3V signal, the reverse is not true, and a 5V signal connected to the 3.3V RXD pin is likely to damage the Raspberry Pi.

See Also

You can also easily adapt the other examples that use PyFirmata (Recipes 18.5 through 18.8) to use a serial rather than a USB connection, simply by changing the device name in the Python program.

18.6 Reading Arduino Digital Inputs Using PyFirmata

Problem

You want to read Arduino digital inputs from Python on a Raspberry Pi.

Solution

Use PyFirmata to read a digital input on the Arduino.

To make this recipe, you will need the following:

Arduino Uno (see “Modules”)

Breadboard and jumper wires (see “Prototyping Equipment and Kits”)

1kΩ resistor (see “Resistors and Capacitors”)

Tactile push switch (see “Miscellaneous”)

Connect the breadboard, fastening the components to the Arduino as shown in Figure 18-9. If you prefer, you could also use a Squid Button switch instead of a breadboard (Recipe 9.11).

If you haven’t already done so, follow Recipe 18.3 to set up PyFirmata.

The following Python script prints out a message every time the switch is pressed (you can find the program in the Python section of this book’s downloads, where it is called ch_18_ardu_switch.py [see Recipe 3.22]):

import pyfirmata
import time

board = pyfirmata.Arduino('/dev/ttyACM0')
switch_pin = board.get_pin('d:4:i')
it = pyfirmata.util.Iterator(board)
it.start()
switch_pin.enable_reporting()

while True:
    input_state = switch_pin.read()
    if input_state == False:
        print('Button Pressed')
        time.sleep(0.2)

Figure 18-9. Wiring diagram for an Arduino and a push switch

When you run it, nothing happens for a second or two while the Firmata sketch starts and establishes communication with the Raspberry Pi. But after it starts, a message appears each time you press the button:

$ sudo python ardu_switch.py
Button Pressed
Button Pressed
Button Pressed

Discussion

PyFirmata uses the concept of an Iterator to monitor the Arduino input pin. The reasons for this are bound up in the implementation of Firmata. This means that you can’t simply read the value of an Arduino input pin on demand; instead, you need to create a separate Iterator thread that manages the reading of the switch by using these commands:

it = pyfirmata.util.Iterator(board)
it.start()

You then also need to enable reporting for the pin you are interested in by using the following command:

switch_pin.enable_reporting()

A side effect of this mechanism is that when you press Ctrl-C to exit the program, it won’t exit properly. There is no nice way to kill the Iterator thread other than to open another Terminal window or SSH session and kill the process (Recipe 3.28).

If the only Python process running is this program, you can kill it by using this command:

$ sudo killall python

Simply disconnecting the Arduino from the Raspberry Pi, which will break the communication link, will also cause the Python program to exit.

See Also

This is very similar to connecting a switch directly to a Raspberry Pi (Recipe 12.1), and if you have just one switch, there is no real benefit in using an Arduino like this.

18.7 Reading Arduino Analog Inputs Using PyFirmata

Problem

You want to read Arduino analog inputs from Python on a Raspberry Pi.

Solution

Use PyFirmata to read an analog input on the Arduino.

To make this recipe, you will need the following:

Arduino Uno (see “Modules”)

Breadboard and jumper wires (see “Prototyping Equipment and Kits”)

10kΩ trimpot (see “Resistors and Capacitors”)

Connect the breadboard to the Arduino as shown in Figure 18-10.

Figure 18-10. Wiring diagram for an Arduino and a trimpot

If you haven’t already done so, follow Recipe 18.3 to set up PyFirmata.

The following Python script will display both the raw reading from the analog input and the voltage at the analog input (you can find the program in the Python section of this book’s downloads, where it is called ch_18_ardu_adc.py [see Recipe 3.22]):

import pyfirmata
import time

board = pyfirmata.Arduino('/dev/ttyACM0')
analog_pin = board.get_pin('a:0:i')
it = pyfirmata.util.Iterator(board)
it.start()
analog_pin.enable_reporting()

while True:
    reading = analog_pin.read()
    if reading != None:
        voltage = reading * 5.0
        print("Reading=%f\tVoltage=%f" % (reading, voltage))
        time.sleep(1)

The analog reading will be a value between 0.0 and 1.0:

$ sudo python ardu_adc.py
Reading=0.000000    Voltage=0.000000
Reading=0.165200    Voltage=0.826000
Reading=0.784000    Voltage=3.920000
Reading=1.000000    Voltage=5.000000

Discussion

The program is very similar to that of Recipe 18.6. You must use an Iterator, and the same problems of stopping the program apply.

The if statement is needed because if the first read is made before the actual reading from the analog input has happened, the read will return None rather than a number. The if statement effectively causes the program to ignore any null readings.

See Also

To use digital inputs, see Recipe 18.6.

18.8 Analog Outputs (PWM) with PyFirmata

Problem

You want to control the brightness of an LED by using PWM through an Arduino.

Solution

Use PyFirmata to send commands to an Arduino to generate a PWM signal on one of its outputs.

To make this recipe, you will need the following:

Arduino Uno (see “Modules”)

Breadboard and jumper wires (see “Prototyping Equipment and Kits”)

270Ω resistor (see “Resistors and Capacitors”)

LED (see “Opto-Electronics”)

Connect the breadboard to the Arduino as shown in Figure 18-11.

If you haven’t already done so, follow Recipe 18.3 to set up PyFirmata.

Figure 18-11. Wiring diagram for Arduino PWM control of an LED

The following Python script prompts you to enter a value for the PWM power and then set the LED brightness accordingly (you can find the program in the Python section of this book’s downloads, where it is called ch_18_ardu_pwm.py [see Recipe 3.22]):

import pyfirmata

board = pyfirmata.Arduino('/dev/ttyACM0')
led_pin = board.get_pin('d:10:p')

while True:
    duty_s = input("Enter Brightness (0 to 100):")
    duty = int(duty_s)
    led_pin.write(duty / 100.0)

With the value entered as 100, the LED should be at full brightness. The brightness decreases as the number decreases:

$ python3 ch_18_ardu_pwm.py
Enter Brightness (0 to 100):100
Enter Brightness (0 to 100):50
Enter Brightness (0 to 100):10
Enter Brightness (0 to 100):5

Discussion

The sketch for this is actually very straightforward. You define the output as PWM output using this command:

led_pin = board.get_pin('d:10:p')

The p is for PWM. But remember, this works only on Arduino pins marked with a ~ symbol.

We can also modify the slider control (Figure 18-12) so that it will operate through PyFirmata. You can download this sketch as ch_18_ardu_gui_slider.

Figure 18-12. A user interface for controlling LED brightness

See Also

Although an Arduino can deliver 40 mA to an output—roughly 10 times the current available on a Raspberry Pi GPIO pin—that’s still not enough to directly drive a motor or high-power LED module. To do that, you would need to use the circuit described in Recipe 11.4, modified to use an Arduino output pin rather than a Raspberry Pi GPIO pin.

18.9 Controlling a Servo Using PyFirmata

Problem

You want to control the position of a servo motor by using an Arduino.

Solution

Use PyFirmata to send commands to an Arduino to generate the pulses necessary to control the position of a servo motor.

To make this recipe, you will need the following:

Arduino Uno (see “Modules”)

Breadboard and jumper wires (see “Prototyping Equipment and Kits”)

1kΩ resistor (see “Resistors and Capacitors”)

LED (see “Opto-Electronics”)

Connect the breadboard as shown in Figure 18-13.

Figure 18-13. Wiring diagram for an Arduino controlling a servo motor

If you have not already done so, follow Recipe 18.3 to set up PyFirmata.

The following Python script prompts you to enter a value for the servo’s angle and then set the arm of the servo motor accordingly (you can find the program in the Python section of this book’s downloads, where it is called ch_18_ardu_servo.py [see Recipe 3.22]):

import pyfirmata

board = pyfirmata.Arduino('/dev/ttyACM0')
servo_pin = board.get_pin('d:11:s')

while True:
    angle_s = input("Enter Angle (0 to 180):")
    angle = int(angle_s)
    servo_pin.write(angle)

With the value entered as 0, the servo should be at one end of its travel. Changing this to 180 sends it to the other end, and 90 puts it somewhere in the middle:

$ python3 ch_18_ardu_servo.py
Enter Angle (0 to 180):0
Enter Angle (0 to 180):180
Enter Angle (0 to 180):90

Discussion

The sketch for this is actually very straightforward. You define the output as a servo output by using this command:

servo_pin = board.get_pin('d:11:s')

The s is for servo. This can be used on any of the Arduino digital pins.

If you’ve built Recipe 11.1, you might notice that, by comparison, there is no jitter of the servo when used with an Arduino in this way.

See Also

The straight Raspberry Pi–only solution to using a servo motor is described in Recipes 11.1, 11.2, and 11.3.

18.10 Using Small Arduino Boards with a Raspberry Pi

Problem

You want to use an Arduino board with a Raspberry Pi, but you would like something more compact.

Solution

Use one of the small breadboard-friendly Arduino boards.

Figure 18-14 shows an Arduino Pro Mini board. Boards like this have the great advantage that they can be plugged directly into the breadboard along with other components needed for the project. The Pro Mini board is also available in a 3.3V version, which avoids any need for level conversion when you’re using it with a Raspberry Pi.

Figure 18-14. An Arduino Pro Mini and programming interface

Discussion

Some of these boards, such as the Pro Mini shown in Figure 18-14, require a USB programming interface. You can program them from the Raspberry Pi, or from another computer if that proves problematic.

In addition to official Arduino boards, you can also find many low-cost clones that would make a great companion to the Raspberry Pi.

See Also

WiFi-enabled boards are ideal for IoT and home automation; see Recipe 18.11.

Here are some other boards to consider:

Teensy

Arduino Micro

Arduino Nano

18.11 Using Small WiFi-Enabled Arduino-Compatibles (ESP8266)

Problem

You want to be able to program an ESP8266 WiFi-enabled board like the Wemos D1 Mini from your Raspberry Pi.

Solution

Install board support for the ESP8266 into your Arduino IDE on your Raspberry Pi and then program the board using a USB lead.

The ESP8266 WiFi-enabled microcontroller chip has found its way onto many low-cost boards. One of the most popular of these is the Wemos D1 (Figure 18-15).

Figure 18-15. The Wemos D1 Mini

This board is similar to the Arduino Pro Mini and even costs about the same, but it includes a USB programming interface and WiFi hardware, making it a tremendous value for the money. To add support for it to the Arduino IDE, you need to do the following.

Assuming that you have followed Recipe 18.1 and installed the Arduino IDE (version 1.8.5 or later) on your Raspberry Pi (Raspberry Pi 3 or 4 preferred for speed), open the Preferences option from the File menu, and then click the button at the end of the Additional Boards Manager URLs line (Figure 18-16).

Figure 18-16. Adding a URL to the Boards Manager URL

Then, in the text area that appears for Additional Boards Manager URLs, enter the URL http://arduino.esp8266.com/stable/package_esp8266com_index.json and click OK, and then, OK again to close the Preferences panel.

For the second part of the installation, open the Boards Manager from the Tools → Board menu. In the Search area, enter esp8266 (Figure 18-17).

Figure 18-17. Searching for ESP8266 boards in the Boards Manager.

This should find the board type of esp8266 by ESP8266 Community. Select this board type and then click Install.

This adds new board types to your Boards menu, including the Wemos D1 and lots of other ESP8266-based boards.

Discussion

You can test this out by connecting a Wemos D1 Mini to your Raspberry Pi with a USB lead and then loading the Arduino Blink sketch from the File → Examples → 01.Basics menu.

Select a board type of WeMos D1 R1 (Figure 18-18), make sure the port is set to /dev/ttyUSB0, and then click the upload button. When the compile and upload process has finished, the LED built into the Wemos D1 should begin to blink.

Figure 18-18. Selecting a board type of WeMos R1

The compiler has to do a lot more work compiling for the ESP8266, and you will notice that, even on a Raspberry Pi 4, it takes quite a long time to finish. If you want to speed things up, you can follow the aforementioned steps and add ESP8266 support to your laptop or desktop computer.

See Also

The ESP8266 chip used in the Wemos D1 Mini is a very close relative of the chip used in the Sonoff web switch from Recipe 17.3, and the Sonoff can (if you really want to do so) be reprogrammed as if it were a D1 Mini.

For more conventional small Arduinos, see Recipe 18.10.

Appendix A. Parts and Suppliers

Parts

The following tables will help you to find the parts used in this book. Where possible, I have listed product codes for a few suppliers.

There are now many electronic component suppliers that cater to the maker and electronics hobbyist. Some of the most popular are listed in Table A-1.

Table A-1. Parts suppliers

Supplier
Website
Notes

Adafruit

http://www.adafruit.com

Good for modules

Digi-Key

http://www.digikey.com

Wide range of components

Mouser

http://www.mouser.com

Wide range of components

Seeed Studio

http://www.seeedstudio.com

Interesting low-cost modules

SparkFun

http://www.sparkfun.com

Good for modules

MonkMakes
http://www.monkmakes.com
Electronics kits for Raspberry Pis, etc.

Pimoroni

https://shop.pimoroni.com

UK-based retailer and manufacturer of interesting HATs

Pololu
https://www.pololu.com
Great for motor controllers and robots

CPC

http://cpc.farnell.com

UK based; wide range of components

Farnell

http://www.farnell.com

International; wide range of components

Cool Components

https://coolcomponents.co.uk

Wide range of accessories for Raspberry Pi

The other great source of components is eBay.

Searching for components can be time consuming and difficult. The Octopart component search engine can be very helpful in tracking down parts. MonkMakes, Adafruit, and SparkFun all have packs of components to get you started.

Prototyping Equipment and Kits

Many of the hardware projects in this book use jumper wires of various sorts. Male-to-female leads (to connect the Raspberry Pi general-purpose input/output [GPIO] connector to a breadboard) and male-to-male (to make connections on the breadboard) are particularly useful. Female-to-female are occasionally useful for connecting modules directly to GPIO pins. You rarely need leads longer than 3 inches (75 mm). Table A-2 lists some jumper wire and breadboard specifications, along with their suppliers.

A handy way to get started with a breadboard, jumper wires, and some basic components is to buy a starter kit, like the Electronics Starter Kit for Raspberry Pi from MonkMakes.

Table A-2. Prototyping equipment and kits

Description
Suppliers

M-M jumper wires

SparkFun: PRT-08431; Adafruit: 759

M-F jumper wires

SparkFun: PRT-09140; Adafruit: 825

F-F jumper wires

SparkFun: PRT-08430; Adafruit: 794

Half-size breadboard

SparkFun: PRT-09567; Adafruit: 64

Pi Cobbler

Adafruit: 1105

Raspberry Leaf (26-pin)
Adafruit: 1772

Raspberry Leaf (40-pin)
Cool Components: 3408

Electronics Starter Kit for Raspberry Pi
Amazon; monkmakes.com

Adafruit Perma-Proto for Pi (half breadboard)
Adafruit: 1148

Adafruit Perma-Proto for Pi (full breadboard)
Adafruit: 1135

Adafruit Perma-Proto HAT
Adafruit: 2314

DC barrel jack-to-screw terminal adapter (female)
Adafruit: 368

Pimoroni Breakout Garden HAT
Pimoroni

Basic soldering kit
Adafruit: 136

Resistors and Capacitors

Table A-3 shows resistors and capacitors used in this cookbook and some suppliers.

Table A-3. Resistors and capacitors

Part
Suppliers

270Ω 0.25W resistor

Mouser: 293-270-RC

470Ω 0.25W resistor

Mouser: 293-470-RC

1kΩ 0.25W resistor

Mouser: 293-1K-RC

3.3kΩ 0.25W resistor

Mouser: 293-3.3K-RC

4.7kΩ 0.25W resistor

Mouser: 293-4.7K-RC

10kΩ trimpot

Adafruit: 356; SparkFun: COM-09806; Mouser: 652-3362F-1-103LF

Photoresistor

Adafruit: 161; SparkFun: SEN-09088

330 nF capacitor

Mouser: 80-C330C334K5R

Thermistor T0 of 1k Beta 3800 NTC
Mouser: 871-B57164K102J (Note: Beta is 3730)

Transistors and Diodes

Table A-4 lists transistors and diodes used in this cookbook and some suppliers.

Table A-4. Transistors and diodes

Part
Suppliers

FQP30N06L N-Channel logic level MOSFET transistor

Mouser: 512-FQP30N06L; Sparkfun: COM-10213

2N3904 NPN bipolar transistor

SparkFun: COM-00521; Adafruit: 756

1N4001 diode

Mouser: 512-1N4001; SparkFun: COM-08589; Adafruit: 755

TIP120 Darlington transistor
Adafruit: 976; CPC: SC10999

2N7000 MOSFET transistor
Mouser: 512-2N7000; CPC: SC06951

Integrated Circuits

Table A-5 lists integrated circuits used in this cookbook and some suppliers.

Table A-5. Integrated circuits

Part
Suppliers

7805 voltage regulator

SparkFun: COM-00107; Adafruit: 2164; Mouser: 511-L7805CV, CPC: SC10586

L293D motor driver

SparkFun: COM-00315; Adafruit: 807; Mouser: 511-L293D; CPC: SC10241

ULN2803 Darlington driver IC

SparkFun: COM-00312; Adafruit: 970; Mouser: 511-ULN2803A; CPC: SC08607

DS18B20 temperature sensor

SparkFun: SEN-00245; Adafruit: 374; Mouser: 700-DS18B20; CPC: SC10426

MCP3008 eight-channel ADC IC

Adafruit: 856; Mouser: 579-MCP3008-I/P; CPC: SC12789

TMP36 temperature sensor

SparkFun: SEN-10988; Adafruit: 165; Mouser: 584-TMP36GT9Z; CPC: SC10437

Opto-Electronics

Table A-6 lists opto-electronic components used in this cookbook and some suppliers.

Table A-6. Opto-electronics

Part
Suppliers

5 mm red LED

SparkFun: COM-09590; Adafruit: 299

RGB common cathode LED

SparkFun: COM-11120; eBay

TSOP38238 IR sensor

SparkFun: SEN-10266; Adafruit: 157

Modules

Table A-7 lists modules used in this cookbook and some suppliers.

Table A-7. Modules

Part
Suppliers

Raspberry Pi Camera Module

Adafruit: 3099; Cool Components: 1932

Arduino Uno

SparkFun: DEV-11021; Adafruit: 50; CPC: A000066

Level converter, four-way

SparkFun: BOB-12009; Adafruit: 757

Level converter, eight-way

Adafruit: 395

LiPo boost converter/charger

SparkFun: PRT-14411

PowerSwitch Tail

Amazon

16-channel servo controller

Adafruit: 815

Motor driver 1A dual

SparkFun: ROB-14451

RasPiRobot board v4

Amazon

Pi Plate

Adafruit: 801

PIR motion detector

Adafruit: 189

Ultimate GPS

Adafruit: 746

Methane sensor

SparkFun: SEN-09404

Gas sensor breakout board

SparkFun: BOB-08891

ADXL335 triple-axis accelerometer

Adafruit: 163

4x7-segment LED with I2C backpack

Adafruit: 878

Bicolor LED square-pixel matrix with I2C backpack

Adafruit: 902

Freetronics Arduino LCD shield

freetronics.com

RTC module

Adafruit: 3296

16x2 HD44780 compatible LCD module

SparkFun: LCD-00255; Adafruit: 181

Sense HAT
Adafruit: 2738

Adafruit Capacitive Touch HAT
Adafruit: 2340

Stepper Motor HAT
Adafruit: 2348

16-Channel PWM HAT
Adafruit: 2327

Pimoroni Explorer HAT Pro
pimoroni.com; Adafruit: 2427

Squid Button
monkmakes.com; Amazon

Raspberry Squid RGB LED
monkmakes.com; Amazon

I2C OLED display 128x64 pixels
eBay—search for: I2C OLED Arduino

MMA8452Q triple-axis accelerometer breakout
SparkFun: SEN-12756

MH-Z14A CO2 sensor module
eBay—search for: MH-Z14A

RC-522 RFID module
eBay—search for: RC-522

MonkMakes Clever Card Kit for Raspberry Pi
http://www.monkmakes.com/cck

Pimoroni VL53L1X distance sensor
https://shop.pimoroni.com/products/vl53l1x-breakout or eBay—search for: VL53L1X

Sonoff Basic WiFi Switch
https://www.itead.cc/smart-home.html

Raspberry Pi Zero Camera Adapter
Adafruit: 3157

Wemos D1 Mini
eBay—search for: Wemos D1 Mini

Miscellaneous

Table A-8 lists miscellaneous tools and components used in this cookbook and some suppliers.

Table A-8. Miscellaneous

Part
Suppliers

1200mAh LiPo battery

Adafruit: 258

5V relay

SparkFun: COM-00100

5V panel meter

SparkFun: TOL-10285

Standard servo motor

SparkFun: ROB-09065; Adafruit: 1449

9g mini servo motor
Adafruit: 169

5V 2A power supply

Adafruit: 276

Low-power 6V DC motor

Adafruit: 711

0.1-inch header pins

SparkFun: PRT-00116; Adafruit: 392

5V, 5-pin unipolar stepper motor

Adafruit: 858

12V, 4-pin bipolar stepper motor

Adafruit: 324

Chassis and Gearmotor Kit

eBay—search for: 2WD Smart Robot Car Chassis

4xAA battery holder
Adafruit: 830

6xAA battery holder
Adafruit: 248

Tactile push switch

SparkFun: COM-00097; Adafruit: 504

Miniature slide switch

SparkFun: COM-09609; Adafruit: 805

Rotary encoder

Adafruit: 377

4×3 keypad

SparkFun: COM-14662

Piezo buzzer

SparkFun: COM-07950; Adafruit: 160

Reed switch

Adafruit: 375

Console lead
Adafruit: 954

Appendix B. Raspberry Pi Pinouts

Raspberry Pi 4/3/2 model B, B+, A+, Zero

Figure B-1 shows the pinout for the current 40-pin general-purpose input/output (GPIO) Raspberry Pi.

Figure B-1. 40-pin Raspberry Pi GPIO pinout

Raspberry Pi model B revision 2, A

If you have a Raspberry Pi, it is most likely to be a model B revision 2 board, as shown in Figure B-2.

Figure B-2. Raspberry Pi model B revision 2 and model A GPIO pinout

Raspberry Pi model B revision 1

The very first released version of the Raspberry Pi model B (revision 1) has some minor pinout differences to the revision 2 that followed. This is the only version of the Raspberry Pi that is not compatible with later pinouts. The incompatible pins that changed are highlighted in bold in Figure B-3.

Figure B-3. Raspberry Pi model B revision 1 GPIO pinout

Index

Symbols

$ prompt, Discussion

& command, Solution

* (wildcard), Discussion, Solution

. (period), Discussion

/ (in paths), Discussion

= (assignment) operator (Python), Solution

[:] notation (Python), Solution, Problem

[] notation (Python), Solution, Discussion, Solution

ǀ (pipe command), Problem

A

acceleration measurement

Inertial Management Unit and, Problem-See Also

MMA8452Q module for, Problem-See Also

Adafruit Capacitive Touch HAT, Solution-See Also

Adafruit Pi Cobbler, Problem-See Also

Adafruit servo motor HAT, Solution-Discussion

Adafruit Stepper Motor HAT, Problem-See Also

addressable RGB LED strips, Problem-See Also

aliases, Problem

alkaline batteries, Problem-See Also

analog inputs, Problem-See Also

analog volt meter, as display, Problem-See Also

analog-to-digital converter (ADC)

temperature measurement with, Problem-See Also

using resistive sensors with, Problem-See Also

voltage measurement with, Solution-See Also

Android, controlling hardware with, Problem-See Also

AngularServo class (gpiozero), Solution

append function (Python), Solution

ApplePi-Baker, See Also

apt-get package

installing software with, Problem

removing software installed with, Problem

Arduino, Introduction-See Also

advantages of, Introduction

analog outputs (PWM) with PyFirmata, Problem-See Also

as interface board for Raspberry Pi, Problem-See Also

communicating via the serial monitor, Problem

controlling a servo using PyFirmata, Problem-See Also

converting 5V signals to 3.3V with two resistors, Problem

MQTT and, Solution-Discussion

programming from Raspberry Pi, Programming an Arduino from Raspberry Pi

PyFirmata setup, Problem-See Also

Raspberry Pi boards compared to, Introduction

reading analog inputs with PyFirmata, Problem-See Also

reading digital inputs using PyFirmata, Problem-See Also

using PyFirmata with TTL serial, Problem-See Also

using small boards with a Raspberry Pi, Problem

using small WiFi-enabled Arduino-compatibles, Problem-See Also

writing digital outputs from a Raspberry Pi, Problem-See Also

Arduino integrated development environment (IDE), Programming an Arduino from Raspberry Pi

Arduino Pro Mini board, Solution

arithmetic, in Python, Problem

assignment (=) operator (Python), Solution

Atari 2600 emulator, Solution-See Also

audio (see sound)

autocomplete, Discussion

B

batteries

powering a Raspberry Pi with a LiPo battery, Problem

powering a Raspberry Pi with alkaline batteries, Problem-See Also

bipolar stepper motors

basics, Problem-See Also

driving with RasPiRobot Board, Using a RasPiRobot Board to Drive a Bipolar Stepper Motor-See Also

driving with Stepper Motor HAT, Problem-See Also

bit banging, Discussion

bitmap images, Problem-See Also

blinking LEDs, Discussion

Bluedot (Android app), Solution-See Also

Bluetooth

controlling hardware with, Problem-See Also

setup, Problem-See Also

boost regulator module, Solution

bottle library (Python), Solution, Solution, Solution-Discussion

breadboard

connecting to GPIO using jumper leads, Problem-See Also

sources for, Prototyping Equipment and Kits

using with Pi Cobbler, Problem-See Also

break statement (Python), Solution

Button class (gpiozero), Solution

buzzer, Problem-See Also

C

camera, Problem

(see also computer vision)

setting up a USB camera for computer vision, Problem-See Also

webcam server software, Problem-See Also

camera module, installing, Problem-See Also

capacitive touch sensing, Problem-See Also

capacitors

basics, Discussion

sources for, Resistors and Capacitors

carbon dioxide, measuring concentration of, Problem-See Also

cases (enclosures), Problem-See Also

cat command, Discussion, Solution

cd command, Solution

center-off toggle switch, Problem-See Also

Cheerlights, Problem-See Also

chmod command, Solution

chown command, Solution

class

defining, Problem-See Also

inheritance, Problem

methods and, Problem

Cobbler (Adafruit Pi Cobbler), Problem-See Also

coins, counting, Problem-See Also

command line

command aliases, Problem

fetching files from, Problem

playing sound from, Problem

redirecting output to a file, Problem

repeating commands with history, Problem

running Python programs from, Problem, Problem

setting network name from, Setting the network name using the command line (the easy way)-See Also

setting up WiFi from, Setting up WiFi using the command line (the easy way)

common cathode LED, Solution

Common Unix Printing System (CUPS), Problem-See Also

comparing values, Problem-See Also

comprehensions, Solution

compressed files, Problem

computer vision (CV), Introduction-See Also

counting coins, Problem-See Also

face detection, Problem-See Also

installing SimpleCV, Problem

motion detection, Problem-See Also

OCR, Problem

Raspberry Pi Camera Module for, Problem

setting up a USB camera for, Problem-See Also

concatenation

files, Problem

strings, Problem

conditions, Problem

console cable, Problem-See Also

console, Python, Problem-See Also

copy command (Python), Discussion

copying files or folders, Problem-See Also

counting coins, Problem-See Also

cp command, Solution

CPU (central processing unit)

displaying temperature readings on web page, Problem-See Also

monitoring usage of, Problem-See Also

temperature measurement for, Problem

crontab command, Solution

D

Darlington transistor, Discussion

dashboard, Node-RED, Problem-See Also, Problem-See Also

data entry, regex for validation of, Problem

data structure, pickling, Problem

date

formatting in Python, Problem

setting, Problem

DC motor

controlling direction of, Problem-See Also

controlling speed of, Problem

debouncing, Problem-See Also

df command, Solution

DHCP reservation, Setting the IP address using the network

dictionary, in Python, Problem-See Also

accessing, Problem

creating, Problem

iterating over, Problem

removing entries from, Problem

digital inputs, Introduction-See Also

debouncing a button press, Problem-See Also

detecting movement, Problem

GPS, Problem-See Also

intercepting keypresses, Problem

intercepting mouse movements, Problem

keypad for, Problem-See Also

push switch connection, Problem-See Also

reading Arduino inputs with PyFirmata, Problem-See Also

real-time clock module for, Problem-See Also

reset button, Problem-See Also

rotary (quadrature) encoder, Problem-See Also

three-position (center-off) toggle or slide switch, Problem-See Also

toggling with push switch, Problem-See Also

two-position toggle or slide switch, Problem

using an external pull-up resistor, Problem

digital temperature sensor, Problem-See Also

diodes, sources for, Transistors and Diodes

directory, creating, Problem

displays, Introduction-See Also

addressable RGB LED strips, Problem-See Also

analog volt meter, Problem-See Also

ePaper display, Problem-See Also

four-digit LED, Using a Four-Digit LED Display-See Also

I2C LED matrix, Problem

OLED graphical display, Problem-See Also

Pimoroni Unicorn HAT, Problem-See Also

Sense HAT LED matrix display, Problem-See Also

text on alphanumeric LCD HAT, Problem-See Also

dist-upgrade command, Discussion

distance measurement

time-of-flight sensor for, Problem-See Also

ultrasound for, Problem-See Also

double buffering, Solution

DS1307 RTC chip, Solution-Discussion

DS18B20 sensor, Solution, Solution-Discussion

DVI monitor, connecting, Problem

Dweet, Problem-See Also

Dynamic Host Configuration Protocol (DHCP), Discussion, Solution-Setting the IP address using the Raspberry Pi

dynamic overclocking, Solution

E

editing a file, Problem-See Also

EEPROM (Electrically Erasable Read-Only Memory) chip, Solution-Discussion

Element 14 Pi Desktop kit, Discussion-See Also

email

IFTTT for sending, Problem-See Also

sending from Python, Problem-See Also

enclosures (cases), Problem-See Also

enumerate command (Python), Solution

enumerating, Problem

ePaper display, Problem-See Also

error handling, Problem

escape characters (Python), Discussion

ESP8266 Wi-Fi enabled board, Problem-See Also

Etcher, Solution

exception handling, Problem

Explorer HAT Pro, Problem-See Also

extend function (Python), Discussion

F

face detection, Problem-See Also

Facebook notifications, Problem-See Also

fg command, Solution

file archives, uncompressing, Problem

File Manager, Solution-Discussion

file permissions, Problem-See Also

basics, Problem-See Also

changing, Problem

files

browsing graphically, Problem-See Also

changing ownership, Problem

concatenating, Problem

copying, Problem-See Also

copying onto a USB flash drive, Problem-See Also

creating without using editor, Problem

deleting with Terminal, Problem

editing, Problem-See Also

fetching from command line, Problem

finding, Problem

reading from, Problem

redirecting command line output to a file, Problem

renaming, Problem

uncompressing, Problem

viewing contents of, Problem

writing to, Problem

filesystem navigation, Problem-See Also

find command, Solution

find function (Python), Solution

Firmata, Problem-See Also

firmware, Problem-See Also

flash drive (see USB flash drive)

flashing, of Sonoff WiFi Smart Switch for MQTT use, Problem-See Also

float function (Python), Solution

FM radio transmitter, Raspberry Pi Radio Transmitter-See Also

folders

copying, Problem-See Also

deleting with Terminal, Problem

renaming, Problem

for command (Python), Solution, Solution, Solution

format method (Python), Solution

formatting

dates/times, Problem

numbers, Problem

four-digit LED display, Using a Four-Digit LED Display-See Also

FQP30N06L MOSFET, Solution-See Also

function

applying to list, Problem

defining in Python, Problem

returning more than one value, Problem

G

game console emulator, Problem-See Also

gas detection/measurement

carbon dioxide concentration, Problem-See Also

methane detection, Problem-See Also

general-purpose input/output (GPIO) connector

basics, Introduction-See Also

controlling hardware through, Introduction-See Also

converting 5V signals to 3.3V with level converter module, Problem

converting 5V signals to 3.3V with two resistors, Problem

leaving pins in safe state, Problem

LED connections, Problem-See Also

output control using a web interface, Problem-See Also

pinouts, Problem-See Also, Raspberry Pi 4/3/2 model B, B+, A+, Zero-Raspberry Pi model B revision 1

safely connecting external electronics to Raspberry Pi, Problem

git clone command, Solution

git, fetching source code with, Problem-See Also

GNU image manipulation program (GIMP), Problem-See Also

gpiozero

leaving GPIO pins in safe state, Solution

PWM feature, Solution-See Also

GPS, Problem-See Also

graphical user interface (GUI)

browsing files with, Problem-See Also

Python, Problem-See Also

guizero library

displaying values, Solution

GUI design with, Solution-See Also

on/off switch interface with, Solution

H

H-Bridge chip, Solution-Discussion, Solution

HAAR (High Altitude Aerial Reconnaissance), Solution

hard disk, booting from, Problem-See Also

hardware

analog meter as display, Problem-See Also

basics, Introduction-See Also

changing color of RGB LEDs with PWM, Problem-See Also

controlling, Introduction-See Also

controlling with Android and Bluetooth, Problem-See Also

converting 5V signals to 3.3V with level converter module, Problem

converting 5V signals to 3.3V with two resistors, Problem

Explorer HAT Pro basics, Problem-See Also

I2C setup, Problem-See Also

i2c-tools, Problem-See Also

leaving GPIO pins in safe state, Problem

LED brightness control, Problem-See Also

LED connections, Problem-See Also

making a user interface to control PWM power for LEDs and motors, Problem-See Also

making a user interface to turn things on and off, Problem

minicom installation, Problem

Perma-Proto Pi HAT, Problem-See Also

Pi Plate prototyping board, Problem-See Also

Pi Zero/Pi Zero W, Problem

powering a Raspberry Pi with a LiPo battery, Problem

powering a Raspberry Pi with alkaline batteries, Problem-See Also

PySerial installation, Problem

Raspberry Squid Button, Problem

Raspberry Squid RGB LED, Problem-See Also

RasPiRobot Board basics, Problem-See Also

safely connecting external electronics to Raspberry Pi, Problem

Sense HAT basics, Problem

SPI setup, Problem-See Also

switching a high-power DC device using a transistor, Problem-See Also

switching a high-power device using a relay, Problem-See Also

switching high-voltage AC devices, Problem

using a breadboard with jumper leads, Problem-See Also

using a breadboard with Pi Cobbler, Problem-See Also

hash table, Discussion

HAT (Hardware Attached on Top) standard

about, Discussion

Raspberry Pi B+ and, Solution

hexadecimal notation, Solution

high-voltage AC devices

connecting Sonoff to, Solution

switching with PowerSwitch Tail II, Problem

history command, Solution

home automation, Introduction-See Also

flashing a Sonoff WiFi Smart Switch for MQTT use, Problem-See Also

making Raspberry Pi into a message broker with Mosquitto, Problem-See Also

Node-RED dashboard for, Problem-See Also

publishing MQTT messages from a Wemos D1, Problem-See Also

scheduled events with Node-RED, Problem-See Also

Sonoff WiFi Smart Switch configuration, Problem-See Also

using flashed Sonoff switches with Node-RED, Problem-See Also

using Node-RED with an MQTT server, Problem-See Also

using Sonoff web switches with MQTT, Problem-See Also

using Wemos D1 with Node-RED, Problem-See Also

HTTP requests, Problem

humidity measurement, Problem-See Also

I

I2C LED matrix display, Problem

i2c-tools, Problem-See Also

if command (Python), Problem

if statements, Problem

ifconfig command, Discussion

IFTTT (If This Then That)

for sending email and other notifications, Problem-See Also

responding to tweets with, Problem-See Also

import command (Python), Solution

indentation, in Python code, Discussion

Inertial Management Unit (IMU), Problem-See Also

inheritance, Problem

Inkscape, Problem

Inky pHAT, Solution-See Also

input command (Python 3), Solution

inputs, digital (see digital inputs)

insert command (Python), Discussion

int function (Python), Solution

integrated circuits, sources for, Integrated Circuits

Inter-Integrated Circuit (I2C)

i2c-tools, Problem-See Also

setup, Problem-See Also

Inter-Integrated Circuit (I2C) LED module, Solution-Discussion

interface board (Perma-Proto Pi HAT), Problem-See Also

Internet of Things (IoT), Introduction-See Also

Cheerlights, Problem-See Also

displaying sensor readings on web page, Problem-See Also

GPIO output control using a web interface, Problem-See Also

home automation (see home automation)

IFTTT for email and other notifications, Problem-See Also

Node-RED for simple workflows, Problem-See Also

responding to tweets using Dweet and IFTTT, Problem-See Also

sending sensor data to ThingSpeak, Problem-See Also

ThingSpeak for sending tweets, Problem-See Also

internet radio, Problem-See Also

IP address

finding, Problem

setting static address, Problem-See Also

IPv4 address, Solution

iterating

over a dictionary, Problem

over a list, Problem

Iterator thread (PyFirmata), Discussion

J

JSON, parsing data in, Problem-See Also

jumper wires, sources for, Prototyping Equipment and Kits

K

keypad, using, Problem-See Also

keypresses, intercepting, Problem

kill command, Discussion

killall command, Discussion

Kodi media center software, Solution-See Also

L

L293D H-Bridge chip, Solution-Discussion, Solution

LCD HAT display, Problem-See Also

lease time, Solution

LED display, four-digit, Using a Four-Digit LED Display-See Also

LED matrix display, Problem

LEDs

blinking, Discussion

changing color with PWM, Problem-See Also

Cheerlights and, Problem-See Also

connecting to Raspberry Pi, Problem-See Also

controlling brightness of, Problem-See Also

controlling brightness with PWM through an Arduino, Problem-See Also

layout on Pi Plate, Discussion-Discussion

making a user interface to control PWM power for, Problem-See Also

Raspberry Squid, Problem-See Also

switching high-power LEDs using a transistor, Problem-See Also

len function (Python), Solution, Solution

level converter module, Problem

libraries, Python, Problem

LibreELEC, Solution

LibreOffice software, Problem

light, measuring, Problem-See Also

lightweight processes, Discussion

Linux, Solution

(see also operating system)

controlling Pi remotely with SSH, Solution

NAS connection, Discussion

pipe command (ǀ), Problem

running commands from Python, Problem

lists, in Python, Introduction-See Also

accessing elements, Problem

adding elements to, Problem

applying function to, Problem

creating, Problem

creating by parsing a string, Problem

creating sublists, Problem

enumerating, Problem

finding length of, Problem

iterating over a list, Problem

removing elements from, Problem

sorting, Problem

lithium-ion polymer (LiPo) battery, Problem

LM2940 voltage regulator, Discussion

logging

sending sensor data to ThingSpeak, Problem-See Also

to USB flash drive, Problem

logical operators, Problem

loop variable, Discussion

loop, exiting, Problem

loudspeaker, connecting, Problem-See Also

low dropout (LDO) voltage regulators, Discussion

lower function (Python), Solution

ls command, Discussion, Solution

lsusb command, Solution

M

macOS

connecting to Pi with console lead, Solution

controlling Pi remotely with SSH, Solution

file sharing on a Mac network, Problem-See Also

NAS connection, Discussion

macOS Finder, Problem-See Also

magnetic north, detecting, Problem

magnets

sensing with reed switch, Problem

sensing with Sense HAT, Problem

man pages, See Also

MCP3008 ADC chip, Solution-Discussion, Problem-See Also

media center software, Problem-See Also

Message Queuing Telemetry Transport (MQTT) (see MQTT)

methane detection, Problem-See Also

method, defining in Python, Problem

microphone, Problem-See Also

microSD card

configuring headless Raspberry Pi with PiBakery, Problem-See Also

recommended capacity, Solution

using PiBakery to configure/write, Problem-See Also

writing using NOOBS, Problem-See Also

(see also SD card)

Minecraft Pi, Problem, Problem

Minicom, Problem

mkdir command, Solution

MMA8452Q accelerometer module, Problem-See Also

modules, Python, Problem

modules, sources for, Modules

monitor

adjusting picture size, Problem-See Also

connecting DVI or VGA, Problem

modifying resolution, Problem-See Also

MonkMakes RasPiRobot Board (see RasPiRobot Board)

more command, Discussion

MOSFET (metal-oxide-semiconductor field-effect transistor), Solution-See Also

Mosquitto, Problem-See Also

motion detection

computer vision for, Problem-See Also

digital input from, Problem

motors, Introduction-See Also

bipolar stepper motors, Problem-See Also

building a simple robot rover, Problem-See Also

controlling DC motor direction, Problem-See Also

controlling DC motor speed, Problem

controlling multiple servo motors precisely, Problem-See Also

controlling servo motor position, Problem-See Also

controlling single servo motor precisely, Problem-See Also

driving bipolar stepper motor with RasPiRobot Board, Using a RasPiRobot Board to Drive a Bipolar Stepper Motor-See Also

making a user interface to control PWM power for, Problem-See Also

stepper motor control with Stepper Motor HAT, Problem-See Also

unipolar stepper motors, Problem-See Also

mouse, intercepting movements of, Problem

MQTT (Message Queuing Telemetry Transport)

basics, Discussion-Discussion

flashing a Sonoff WiFi Smart Switch for MQTT use, Problem-See Also

making Raspberry Pi into a message broker with Mosquitto, Problem-See Also

publishing MQTT messages from a Wemos D1, Problem-See Also

using Node-RED with an MQTT server, Problem-See Also

using Sonoff web switches with, Problem-See Also

Mu editor, Problem-See Also

mv command, Solution

N

nano editor, Solution-See Also

network name, setting, Problem-See Also

Networked Attached Storage (NAS), Problem-See Also

networking, Introduction-See Also

connecting to a wired network, Problem-See Also

connecting with a console cable, Problem-See Also

controlling Pi remotely with RDP, Problem

controlling Pi remotely with SSH, Problem-See Also

controlling Pi remotely with VNC, Problem-See Also

file sharing on a Mac network, Problem-See Also

finding IP address, Problem

printing, Problem-See Also

setting a static IP address, Problem-See Also

setting network name of a Raspberry Pi, Problem-See Also

using a Raspberry Pi for Networked Attached Storage, Problem-See Also

wireless connection setup, Problem-See Also

Node-RED

basics, Solution

dashboard for home automation, Problem-See Also

for simple IoT workflows, Problem-See Also

scheduled events with, Problem-See Also

using flashed Sonoff switches with, Problem-See Also

using Wemos D1 with, Problem-See Also

using with an MQTT server, Problem-See Also

NOOBS (New Out of the Box Software), Problem-See Also

NOOBS Lite, Discussion

notifications, IFTTT for sending, Problem-See Also

numbers

converting strings to, Problem

converting to strings, Problem

formatting (Python), Problem

O

OLED graphical display, Problem-See Also

OMXPlayer software, Solution

OpenCV, Discussion

operating system, Introduction-See Also

browsing files graphically, Problem-See Also

changing file ownership, Problem

command aliases, Problem

command-line history, Problem

concatenating files, Problem

copying file or folder, Problem-See Also

copying files onto a USB flash drive, Problem-See Also

creating directory, Problem

creating file without using editor, Problem

deleting file/directory, Problem

determining free space on SD card, Problem

determining version of, Problem

editing a file, Problem-See Also

fetching files from command line, Problem

fetching source code with git, Problem-See Also

fetching this books accompanying code, Problem-See Also

file permissions, Problem-See Also

finding files, Problem

hiding output to the terminal, Problem

installing Python packages with pip, Problem

installing with NOOBS, Problem-See Also

installing without NOOBS, Problem

listing connected USB devices, Problem

making a screen capture, Problem

monitoring processor activity, Problem-See Also

navigating filesystem with Terminal, Problem-See Also

performing tasks with superuser privileges, Problem

pipes, Problem

redirecting output from command line to a file, Problem

removing software installed with apt-get, Problem

renaming file or folder, Problem

running a program or script automatically as a service, Problem-See Also

running a program or script automatically at regular intervals, Problem

running a program or script automatically on startup, Problem

running programs in the background, Problem

selecting, Problem

setting date and time, Problem

software installation with apt-get, Problem

starting a Terminal session, Problem-See Also

uncompressing files, Problem

updating, Problem

viewing contents of file, Problem

optical character recognition (OCR), Problem

opto-electronics, sources for, Opto-Electronics

opto-isolator, Discussion

Organic LED (OLED) graphical display, Problem-See Also

orientation sensing, Problem-See Also

overclocking, Problem-See Also

ownership of files, changing, Problem

P

parts, sources for, Parts-Miscellaneous

Passive Infrared (PIR) motion detector, Solution

passwd command, Discussion

password, changing, Problem-See Also

Perma-Proto Pi HAT, Problem-See Also

photoresistors, Problem-See Also

Pi Cobbler, Problem-See Also

Pi Desktop, Discussion-See Also

Pi Plate prototyping board, Problem-See Also

Pi Zero, Problem

Pi Zero W, Solution, Problem

Pi-View, Discussion

PiBakery

configuring headless Raspberry Pi with, Problem-See Also

configuring SD card with, Problem-See Also

PiBow Coupé, Solution

PiCade, Discussion

pickling, Problem

piezo-electric buzzer, Problem-See Also

Pimoroni Displayotron HAT, Solution-See Also

Pimoroni Explorer HAT Pro, Problem-See Also

Pimoroni Unicorn HAT, Problem-See Also

pinouts, Problem-See Also, Raspberry Pi 4/3/2 model B, B+, A+, Zero-Raspberry Pi model B revision 1

pip package manager, Problem

pipe command (ǀ), Problem

pitch, Solution

pop function (Python), Solution, Solution

port forwarding, Discussion

potential divider, Discussion

power supplies, Problem-See Also

powering a Raspberry Pi with a LiPo battery, Problem

powering a Raspberry Pi with alkaline batteries, Problem-See Also

PowerSwitch Tail II, Problem

pressure measurement, Problem-See Also

print command (Python), Solution

printing, network, Problem-See Also

privileges, superuser, Problem

processor, monitoring, Problem-See Also

prototyping board

Perma-Proto Pi HAT, Problem-See Also

Pi Plate, Problem-See Also

sources for, Prototyping Equipment and Kits

pseudorandom number sequence, Discussion

pull-up resistor, Problem

pulse-width modulation (PWM)

analog outputs with PyFirmata, Problem-See Also

changing color of RGB LED with, Problem-See Also

controlling LED brightness with, Solution-See Also

controlling servo motor position with, Problem-See Also

for analog volt meter display, Problem-See Also

making a user interface to control PWM power for LEDs and motors, Problem-See Also

push switch

connecting, Problem-See Also

debouncing a button press, Problem-See Also

reset button, Problem-See Also

Squid Button, Problem

toggling with, Problem-See Also

pwd command, Discussion

PyFirmata

analog outputs with, Problem-See Also

reading Arduino analog inputs with, Problem-See Also

reading Arduino digital inputs with, Problem-See Also

servo control with, Problem-See Also

setup, Problem-See Also

using with TTL serial, Problem-See Also

pygame

keypress detection with, Solution

mouse motion detection with, Solution

playing sounds with, Discussion

PySerial, Problem

Python

advanced concepts, Introduction-See Also

arithmetic, Problem

assigning names to values, Problem

basics, Introduction-See Also

command-line arguments in, Problem

comparing values, Problem-See Also

concatenation of strings, Problem

console, Problem-See Also

controlling Arduino digital outputs on a Raspberry Pi, Problem-See Also

converting a string to uppercase or lowercase, Problem

converting numbers to strings, Problem

converting strings to numbers, Problem

defining a class, Problem-See Also

defining a function, Problem

defining a method, Problem

dictionaries, Problem-See Also

displaying output, Problem

doing more than one thing at a time, Problem-See Also

editing programs with Mu, Problem-See Also

exception handling, Problem

exiting a loop, Problem

extracting part of a string, Problem

finding length of a string, Problem

finding position of one string within another, Problem

formatting dates/times, Problem

formatting numbers, Problem

indentation, Discussion

inheritance, Problem

installing libraries with pip, Problem

lists, Introduction-See Also

logical operators, Problem

Minecraft Pi edition and, Problem

modules, Problem

parsing JSON, Problem-See Also

pickling, Problem

playing sound from, Problem

PySerial for serial port access, Problem

random number generation, Problem

reading from a file, Problem

reading user input, Problem

regular expressions for data entry validation, Problem

regular expressions for pattern searches, Problem-See Also

regular expressions for web scraping, Problem

repeating instructions an exact number of times, Problem

replacing one string of characters within another within a string, Problem

returning more than one value, Problem

running commands conditionally, Problem

running Linux commands from, Problem

sending email from, Problem-See Also

sleep function, Problem

string variables, Problem

terminal, Problem

threading, Problem-See Also

user interfaces for, Problem-See Also

version 2 versus version 3, Problem

web requests, Problem

web server, Problem

writing to a file, Problem

Q

quadrature encoder, Problem-See Also

R

radio transmitter, Raspberry Pi Radio Transmitter-See Also

radio, internet, Problem-See Also

Radio-Frequency Identification (RFID) reader/writer, Problem-See Also

random number generation, Python, Problem

Raspberry Pi (generally)

Arduino and (see Arduino)

Bluetooth setup, Problem-See Also

booting from real hard disk or USB flash drive, Problem-See Also

camera module installation, Problem-See Also

cases for, Problem-See Also

changing password, Problem-See Also

connecting a DVI or VGA monitor, Problem

connecting the system, Problem-See Also

CPU temperature measurement, Problem

enclosures for, Problem-See Also

GPIO connector (see general-purpose input/output (GPIO) connector)

maximizing performance, Problem-See Also

model selection, Problem-See Also

models based on usage, Solution

monitor picture size adjustment, Problem-See Also

operating system (see operating system)

power supplies, Problem-See Also

setup and management, Introduction-See Also

(see also setup)

shutting down, Problem-See Also

summary of differences between models, Discussion

using PiBakery to configure a headless Raspberry Pi, Problem-See Also

using PiBakery to configure and write an SD card, Problem-See Also

writing a microSD card using NOOBS, Problem-See Also

Raspberry Pi 3 model B, Solution

Raspberry Pi 4, Solution

Raspberry Pi 4 model A+, pinout for, Raspberry Pi 4/3/2 model B, B+, A+, Zero

Raspberry Pi 4 model B

basics, Solution

pinout, Raspberry Pi 4/3/2 model B, B+, A+, Zero

Raspberry Pi 4 model B+, pinout for, Raspberry Pi 4/3/2 model B, B+, A+, Zero

Raspberry Pi 4 model Zero, pinout for, Raspberry Pi 4/3/2 model B, B+, A+, Zero

Raspberry Pi Camera Module, Problem

Raspberry Pi Configuration tool, setting network name with, Setting the network name using the Raspberry Pi Configuration tool

Raspberry Pi model B rev. 1, pinout for, Raspberry Pi model B revision 1

Raspberry Pi model B rev. 2, pinout for, Raspberry Pi model B revision 2, A

Raspberry Pi Sense HAT (see Sense HAT)

Raspberry Squid Button, Problem

Raspberry Squid RGB LED, Problem-See Also, Problem-See Also

Raspbian, Problem

(see also operating system)

determining version of, Problem

updating, Problem

RasPiRobot Board

basics, Problem-See Also

driving bipolar stepper motor with, Using a RasPiRobot Board to Drive a Bipolar Stepper Motor-See Also

RaspiRobot Board

for robot rover, Problem-See Also

raw_input command (Python 2), Solution

real-time clock (RTC) module, Problem-See Also

reboot command, Discussion

reed switch, magnet sensing with, Problem

regular expressions (regex)

for data entry validation, Problem

for pattern searches, Problem-See Also

for web scraping, Problem

relays, Problem-See Also

Remote Desktop Protocol (RDP), Problem

renaming files or folders, Problem

replace function (Python), See Also, Solution

reset button, Problem-See Also

resistive sensors, Using Resistive Sensors-See Also, Problem-See Also

resistors

converting 5V signals to 3.3V with, Problem

sources for, Resistors and Capacitors

using an external pull-up resistor, Problem

values for LED connection, Discussion

resolution, monitor, Problem-See Also

RFID reader/writer, Problem-See Also

RGB LED strips, Problem-See Also

RGB LEDs

changing color with PWM, Problem-See Also

Cheerlights and, Problem-See Also

layout on Pi Plate, Discussion-Discussion

matrix display, Problem-See Also

Raspberry Squid, Problem-See Also

rm command, Solution

robot rover, Problem-See Also

roll, Solution

rotary (quadrature) encoder, Problem-See Also

rptix project, Raspberry Pi Radio Transmitter-See Also

S

screen capture, Problem

scrot command, Solution

SD card

configuring headless Raspberry Pi with PiBakery, Problem-See Also

determining free space on, Problem

installing operating system without NOOBS, Problem

recommended capacity, Solution

using PiBakery to configure/write, Problem-See Also

writing using NOOBS, Problem-See Also

searches, regular expressions for, Problem-See Also

Secure Shell (SSH), Problem-See Also

self variable (Python), Discussion

Sense HAT

basics, Problem

Inertial Management Unit, Problem-See Also

magnet sensing with, Problem

magnetic north detection with, Problem

temperature/humidity/pressure measurement with, Problem-See Also

Sense HAT LED matrix display, Problem-See Also

sensors, Introduction-See Also

acceleration measurement with MMA8452Q module, Problem-See Also

carbon dioxide concentration, Problem-See Also

CPU temperature measurement, Problem

displaying readings on web page, Problem-See Also

displaying values, Problem

distance measurement with time-of-flight sensor, Problem-See Also

distance measurement with ultrasound, Problem-See Also

Inertial Management Unit, Problem-See Also

light measurement, Problem-See Also

logging to USB flash drive, Problem

magnet sensing with reed switch, Problem

magnet sensing with Sense HAT, Problem

magnetic north detection with Sense HAT, Problem

methane detection, Problem-See Also

reducing voltages for voltage measurement, Problem-See Also

resistive, Using Resistive Sensors-See Also

resistive sensors with ADC, Problem-See Also

sending data to ThingSpeak, Problem-See Also

smartcard reading with RFID reader/writer, Problem-See Also

temperature measurement, Problem-See Also

temperature measurement of CPU, Problem

temperature measurement with an ADC, Problem-See Also

temperature measurement with digital sensor, Problem-See Also

temperature/humidity/pressure measurement with Sense HAT, Problem-See Also

touch interface with capacitive touch sensing, Problem-See Also

voltage measurement, Problem-See Also

serial connection, PyFirmata with, Problem-See Also

serial monitor (Arduino), Problem

Serial Peripheral Interface (SPI), Problem-See Also

serial port

PySerial installation for access to, Problem

testing with minicom, Problem

servo motors

controlling a single motor precisely, Problem-See Also

controlling multiple motors precisely, Problem-See Also

controlling position with an Arduino using PyFirmata, Problem-See Also

controlling position with PWM, Problem-See Also

ServoBlaster, Solution-See Also

setup, Raspberry Pi, Introduction-See Also

Bluetooth, Problem-See Also

booting from real hard disk or USB flash drive, Problem-See Also

camera module installation, Problem-See Also

connecting a DVI or VGA monitor, Problem

connecting the system, Problem-See Also

enclosure, Problem-See Also

maximizing performance, Problem-See Also

model selection, Problem-See Also

models based on usage, Solution

monitor picture size adjustment, Problem-See Also

operating systems, Problem

password change, Problem-See Also

power supplies, Problem-See Also

shutting down, Problem-See Also

using PiBakery to configure a headless Raspberry Pi, Problem-See Also

using PiBakery to configure and write an SD card, Problem-See Also

writing a microSD card using NOOBS, Problem-See Also

shutting down, Problem-See Also

signal conversion

with level converter module, Problem

with two resistors, Problem

Simple Mail Transfer Protocol (SMTP), Solution

SimpleCV, Problem

(see also computer vision (CV))

Slack, Problem-See Also

sleep function (Python), Problem, Solution

slide switch

three-position (center-off), Problem-See Also

two-position, Problem

smartcard, reading with RFID reader/writer, Problem-See Also

smtplib library (Python), Solution

software (generally)

installing with apt-get, Problem

removing software installed with apt-get, Problem

software (ready-made for Raspberry Pi), Introduction-See Also

bitmap image editor, Problem-See Also

internet radio, Problem-See Also

media center, Problem-See Also

Minecraft Pi edition, Problem

office software, Problem

radio transmitter, Raspberry Pi Radio Transmitter-See Also

vector image editor, Problem

vintage game console emulator, Problem-See Also

webcam server, Problem-See Also

Sonoff WiFi Smart Switch

configuring, Problem-See Also

controlling with MQTT, Problem-See Also

flashing for MQTT use, Problem-See Also

using flashed switches with Node-RED, Problem-See Also

sort command (Python), Solution

sorting, Problem

sound, Introduction-See Also

buzzer, Problem-See Also

loudspeaker connection, Problem-See Also

output options, Problem

playing from command line, Problem

playing from Python, Problem

USB microphone connection, Problem-See Also

source code, fetching with git, Problem-See Also

speakers, connecting, Problem-See Also

split function (Python), Solution

spreadsheet software, Problem

Squid, Problem-See Also

Squid Button, Problem

Squid RGB LED, Problem-See Also

static IP address

setting, Problem-See Also

setting using Raspberry Pi itself, Setting the IP address using the Raspberry Pi

setting using the network, Setting the IP address using the network-Setting the IP address using the network

step response, Discussion-See Also

Stepper Motor HAT, Problem-See Also

stepper motors

bipolar, Problem-See Also

controlling with Stepper Motor HAT, Problem-See Also

driving with RasPiRobot Board, Using a RasPiRobot Board to Drive a Bipolar Stepper Motor-See Also

unipolar, Problem-See Also

str function (Python), Solution

string variables, Problem

strings

concatenation, Problem

converting numbers to, Problem

converting to numbers, Problem

converting to uppercase or lowercase, Problem

creating a list by parsing, Problem

extracting part of, Problem

finding length of, Problem

finding position of one string within another, Problem

replacing one string of characters within another within a string, Problem

sublists, Problem

superuser privileges, Problem

suppliers, for parts, Parts-Miscellaneous

switch, Problem

(see also digital inputs; push switch; toggle switch)

debouncing, Problem-See Also

making a user interface to turn things on and off, Problem

system command (Python), Solution

T

Tab key, autocomplete with, Discussion

temperature measurement

digital sensor for, Problem-See Also

for CPU, Problem

Sense HAT, Problem-See Also

thermistor for, Problem-See Also

TMP36 and ADC for, Problem-See Also

Terminal

creating directory with, Problem

deleting file/directory, Problem

hiding output to, Problem

navigating filesystem with, Problem-See Also

running Python programs from, Problem

starting a session, Problem-See Also

tesseract (OCR software), Problem

text commands, Problem-See Also

text display, LCD HAT for, Problem-See Also

thermistor, Problem-See Also

ThingSpeak

sending sensor data to, Problem-See Also

sending tweets with, Problem-See Also

thread library (Python), Solution-See Also

threads, Problem-See Also

three-position (center-off) switch, Problem-See Also

throttling, Solution

time

formatting in Python, Problem

real-time clock module, Problem-See Also

setting, Problem

time-of-flight (ToF) sensor, Problem-See Also

time.sleep function (Python), Discussion

TMP36 sensor, Problem-See Also

toggle switch

three-position (center-off), Problem-See Also

two-position, Problem

types of, Discussion

toggling, push switch for, Problem-See Also

top command, Discussion

touch interface, Problem-See Also

transistor

sources for, Transistors and Diodes

switching high-power LEDs with, Problem-See Also

try/except construct (Python), Solution

tuple, Solution

tweets

responding using Dweet and IFTTT, Problem-See Also

ThingSpeak for sending, Problem-See Also

Twitter

IFTTT for sending notifications, Problem-See Also

sending tweets using ThingSpeak, Problem-See Also

U

ULN2803 Darlington driver chip, Solution

ultrasonic rangefinder, Problem-See Also

unipolar stepper motors, Problem-See Also

updating Raspbian, Problem

upper function (Python), Solution

USB camera, Problem-See Also

USB devices, listing, Problem

USB flash drive

booting from, Problem-See Also

copying files onto, Problem-See Also

formatting, Solution

logging to, Problem

USB keyboard, intercepting keypresses from, Problem

USB microphone, Problem-See Also

user interface

browsing files with, Problem-See Also

Python, Problem-See Also

to control PWM power for LEDs and motors, Problem-See Also

to turn things on and off, Problem

V

values

assigning to variables, Problem

comparing, Problem-See Also

displaying, Problem

returning more than one value, Problem

variable resistor, as sensor, Using Resistive Sensors-See Also

variables

assigning values to, Problem

displaying value of, Problem

vector images, Problem

VGA monitor, Problem

vim editor, See Also

vision (see computer vision)

VL53L1X I2C ToF sensor, Solution-See Also

VLC media player, Solution

VNC (Virtual Network Computing), controlling Pi remotely with, Problem-See Also

volt meter, analog, as display, Problem-See Also

voltage conversion

converting 5V signals to 3.3V with two resistors, Problem

with level converter module, Problem

voltage divider, Discussion

voltage measurement

ADC for, Problem-See Also

reducing voltages for, Problem-See Also

voltage regulator, Solution

W

web interface

displaying sensor readings on web page, Problem-See Also

GPIO output control with, Problem-See Also

web requests, Python, Problem

web scraping, Problem

web server, Python, Problem

webcam server setup, Problem-See Also

Wemos D1

publishing MQTT messages from, Problem-See Also

using with Node-RED, Problem-See Also

Wemos D1 Mini, Problem-See Also

wget command, Solution

while statement (Python), Solution

WiFi connection setup, Problem-See Also

Windows

connecting to Pi with console lead, Solution

controlling Pi remotely with SSH, Solution

NAS connection, Discussion

wired networks, connecting to, Problem-See Also

word processing software, Problem

Y

yaw, Solution

About the Author

Dr. Simon Monk (Preston, UK) has a degree in cybernetics and computer science and a PhD in software engineering. Simon spent several years as an academic before he returned to the industry, cofounding the mobile software company Momote Ltd. Simon divides his time between writing books and designing products for MonkMakes (the company his wife, Linda, runs). You can find out more about his books at http://www.simonmonk.org or follow him on Twitter @simonmonk2.

Colophon

The animal on the cover of Raspberry Pi Cookbook is a Eurasian sparrowhawk (Accipiter nisus), which also goes by the name northern sparrowhawk, or simply sparrowhawk. This small bird of prey is found throughout the Old World. Adult males have bluish-gray upper plumage and orange-barred underparts; females and younger birds are all brown with brown-barred underparts. Females are up to 25% larger than males.

The sparrowhawk specializes in preying on woodland birds but can be found in many habitats, hunting garden birds in towns or cities. Males favor hunting smaller birds—tits, finches, and sparrows; females tend to catch thrushes and starlings and are capable of killing birds weighing up to 18 ounces or more.

Eurasian sparrowhawks breed in nests that are built with twigs and can measure up to two feet across. Afterward, four or five pale blue, brown-spotted eggs are laid. Success of breeding relies on females maintaining a high weight; it’s the male’s duty to deliver food to its mate during the nesting period. After 33 days, the chicks hatch, and they fledge after 24 to 28 days.

A juvenile sparrowhawk has a 34% chance of surviving its first year. After that, its chance of survival more than doubles, with 69% of adults surviving from one year to the next. The typical lifespan of these birds is four years, with mortality being greater for young males than for young females. The use of organochlorine insecticides to treat seeds before sowing has been known to incapacitate or kill sparrowhawks; those affected lay fragile-shelled eggs that break during incubation. Despite a sharp population decline after WWII, the sparrowhawk has become the most common bird of prey in Europe—due to the banning of such chemicals. While its convervation status is currently classified as of Least Concern, many of the animals on O’Reilly covers are endangered; all of them are important to the world.

Color illustration by Karen Montgomery, based on a black and white engraving from Cassell’s Natural History. The cover fonts are Gilroy Semibold and Guardian Sans. The text font is Adobe Minion Pro; the heading font is Adobe Myriad Condensed; and the code font is Dalton Maag’s Ubuntu Mono.