Now that we have all the deployments of our code for the backend cloud services, it’s time to dive into the Raspberry Pi (Pi) device itself. This next set of the book will all revolve around coding to the Raspberry Pi device. We will perform a variety of coding tasks on the Raspberry Pi mostly using libraries, some going bare metal. Much of this is to give a glimpse of how we can create a connected environment between device, cloud, and user.
For this first chapter, our major goal is to just get your Pi up and running. Much of the code will be reused from samples from previous chapters. But we will go over enough to make you feel sure-footed and able to run a basic application on the Pi. In this first chapter, we are going to set up the Raspberry Pi in one of the faster ways possible, get it up and running, and then start coding on it. In the last chapter, we will actually optimize this process using buildroot.
Goals
- 1.
Install Ubuntu Server on our Raspberry Pi and have it working with the local Wi-Fi.
- 2.
A Hello World application that is built targeting the Raspberry Pi and runs on there.
- 3.
The start of the creation of our client application running on the Pi, which we will build up on throughout the rest of the book.
Raspberry Pi
Let’s start with discussing Raspberry Pi itself and what it is. Raspberry Pis are small single-board devices originally developed in the United Kingdom by the Raspberry Pi Foundation. They first came onto the stage in 2012 and were pretty much an instant hit.
Raspberry Pis filled a void for many different groups. For hobbyist, it was the perfect device due to its small cost but powerful enough you could still easily use it as a small server, serving up microservices or other small stand-alone applications. In fact, when we first started writing this book, we thought of targeting a Raspberry Pi device for the deployment server as opposed to the cloud. There are some secure advantages doing this, since you are inside our own network, which would make it harder to hack. You could do more of your own certificate creations. Then of course, there is the cost you would have the one upfront cost of the Pi and not a monthly cost. In addition to the low cost of the Pis, they can easily be put around the house to perform various functions, often to do with either monitoring or voice interaction, which incidentally are the two items we will be using it for as well.
In addition, they can often serve as prototyping for eventual larger more complex projects. At the car startup I worked, they did just that. When you think about it not only from a cost perspective but time perspective, it makes sense. If you have to prototype, you are going to want the results as fast as possible. In addition, while your hardware team is designing and creating the hardware revisions, you will want to start coding some of the higher-level features as soon as possible. Low-level features may not be compatible depending on what you are doing and the devices you are targeting. But giving you quite a bit of a leg up and in a startup-minded development world, minimizing cost till you get investment is always a good thing.
Let’s dive into creating our Raspberry Pi application.
Create Raspberry Pi Image
In the first chapter, we laid out what you needed to purchase to follow along with this book, until this point we haven’t used any of the parts. That all changes, so get your Raspberry Pi kit out. In this section, we are going to unbox it, power it up, and install a base software image on it that will connect to the Internet. This should give us the first step in running our applications on the Pi.
Unbox the Raspberry Pi
Assuming you purchased the Raspberry Pi and accessories we linked to in the first chapter or an equivalent, we will now start to unbox and use it. Let’s start by reviewing everything we need and will be using throughout the chapter.
Raspberry Pi Kit
The Raspberry Pi board
Heat sinks + glue (or sticky tape on the sink)
Power adapter
Case
Some specifics may vary depending on the actual Amazon kit you buy, and even though I’ve supplied the URL, the manufacturer may change the specifics. The basics of what was listed earlier will be in all of them though.
As a reminder, the kit can be purchased at https://amzn.com/B07V5JTMV9 or any equivalent by searching for “Raspberry Pi 4 kit”. This will be the board that we run much of the IoT software.
SD Card
A 32 GB SD card comes with the preceding kit. This will be where we store the operating system and the software for running the IoT device as well as storing any data before it reaches the cloud. Raspberry Pis use a microSD card, meaning it won’t directly fit into your computer even if it has an SD card slot. But the kit contains a USB adapter to read the card. If you have an SD card slot reader on your computer, it may be easier to use a microSD to SD adapter that you can purchase fairly inexpensively here: https://amzn.com/B0047WZOOO.
Debug Cable
Lastly is the debugging cable; this is going to be necessary when we set up the server in the beginning, and it’s just a useful tool to have for any debugging later on that is needed. As a reminder, you can purchase this cable at https://amzn.com/B00QT7LQ88.
Assembling Raspberry Pi
The Raspberry Pi itself is fairly easy to assemble; take the two heat sinks and they will either have a sticky back tape to pull off or glue in the kit. If there is a sticky back tape, take it off and put it on the two silver chips. If there is glue, you first place the glue on the heat sink and then apply the heat sinks directly to the chips.
Once the heat sinks are attached, we can then put the board in the case and snap the top. This gives us a nice little case without anything exposed and will also minimize our risk of touching the board directly and having a static discharge.
![../images/481443_1_En_8_Chapter/481443_1_En_8_Fig1_HTML.jpg](https://imgdetail.ebookreading.net/20201209/5/9781484258606/9781484258606__rust-for-the__9781484258606__images__481443_1_En_8_Chapter__481443_1_En_8_Fig1_HTML.jpg)
Shows the board with the heat sinks attached
![../images/481443_1_En_8_Chapter/481443_1_En_8_Fig2_HTML.jpg](https://imgdetail.ebookreading.net/20201209/5/9781484258606/9781484258606__rust-for-the__9781484258606__images__481443_1_En_8_Chapter__481443_1_En_8_Fig2_HTML.jpg)
Shows the board labeled by items (this is a Pi 3 board but close to the 4)
GPIO – Is an 85 mm general-purpose input/output set of integrated circuits that we will use to integrate with the board. These are unused by default, but we can use them to perform interactions with our board.
Controller – The controller for the USB and Ethernet LAN ports.
USB – On the side, we have two sets of two USB ports.
Ethernet – The bottom is our 10/100 Ethernet LAN port.
Audio – Is a 3.5 mm four-pole video and audio socket.
CSI camera port – A port we can attach our camera to.
HDMI – An HDMI port that will allow us to attach the board to a monitor or TV.
Micro USB power – A 5V micro USB that can be used to power the board.
MicroSD card – On the underside of the board is where we put the card that we will create in a bit.
Wireless – The wireless controller for the board. This runs the 2.4 GHz and 5 GHz 802.11 Wireless LAN and Bluetooth-supported controller.
Processor – The Broadcom BCM283780 Cortex-A57 64-bit SoC 1.4 GHz 1 GB Ram chip.
GPIO
![../images/481443_1_En_8_Chapter/481443_1_En_8_Fig3_HTML.jpg](https://imgdetail.ebookreading.net/20201209/5/9781484258606/9781484258606__rust-for-the__9781484258606__images__481443_1_En_8_Chapter__481443_1_En_8_Fig3_HTML.jpg)
Shows the GPIO layout of the board
You will notice the number 2 and 4 slots are 5V leads. These can be used to power the peripherals on top or be used to actually power the board from an external source like a USB. Another two interesting slots are the 8 and 10. These are the UART slots. UART stands for Universal Asynchronous Receiver/Transmitter and is used to transmit data between devices. The one lead transmits and the other receives serial data. The data is transmitted asynchronously, so that means there is no clock signal to synchronize with. We don’t use these much anymore for modern computers, but they used to be used for mice, printers, and modems before we had USB.
Black cable – Is our ground cable and should be plugged into the 6 pin
White cable – Is our transmitter cable and should be plugged into the 8 pin
Green cable – Is our receiver cable and should be plugged into the 10 pin
![../images/481443_1_En_8_Chapter/481443_1_En_8_Fig4_HTML.jpg](https://imgdetail.ebookreading.net/20201209/5/9781484258606/9781484258606__rust-for-the__9781484258606__images__481443_1_En_8_Chapter__481443_1_En_8_Fig4_HTML.jpg)
Our debug cable attached
You could in addition attach the red cable to the 2 pin, but we are going to just plug the board in since once we get it configured, we won’t need to directly attach again, but in theory we could power the board from our computer.
We now have our board all set up and ready to be used; of course, nothing is on it right now, so let’s take the microSD card format it and put an operating system on top of it.
OS Software
Let’s now get into the nuts and bolts in setting up our Raspberry Pi, getting the operating system software installed. Much like buying your standard desktop computer, there are many variants of operating systems to install. There is the standard Raspbian which is the official operating system for all Raspberry Pis. There is also Mozilla OS, and even Windows has a specialty Windows 10 IoT core dashboard; as you can imagine since you are reading this book, Raspberry Pis are great for IoT devices. We are going to stick with the standard out-of-the-box Raspbian for this application. Performing builds in future chapters is a bit easier using Raspbian as well.
![../images/481443_1_En_8_Chapter/481443_1_En_8_Fig5_HTML.jpg](https://imgdetail.ebookreading.net/20201209/5/9781484258606/9781484258606__rust-for-the__9781484258606__images__481443_1_En_8_Chapter__481443_1_En_8_Fig5_HTML.jpg)
The Raspberry Pi operating system list page
![../images/481443_1_En_8_Chapter/481443_1_En_8_Fig6_HTML.jpg](https://imgdetail.ebookreading.net/20201209/5/9781484258606/9781484258606__rust-for-the__9781484258606__images__481443_1_En_8_Chapter__481443_1_En_8_Fig6_HTML.jpg)
The various Raspbian installs
Our Pi won’t be designed to hook up to a monitor; this is going to run code that we customize for it. For that case, all we need is the “Raspbian Buster Lite” version. Click the Download like for the ZIP version and you should have downloaded a file that looks like 2020-02-13-raspbian-buster-lite.zip; the exact version may differ based on when you have reached this page. Raspbian is a derivation of the 32-bit Debian operating system, so many of the tools we use on Debian, we will use on Raspbian.
Installing the Software
- 1.
Unzip the compressed image.
- 2.
Wipe our microSD card.
- 3.
Install the image onto our microSD card.
Unpack the File
Once the file is downloaded, you can check the sha256sum to ensure the integrity of the download. You can find the shasum on the same link we downloaded and then run sha256sum on the file to verify the file. But assuming it is fine, let’s unzip it like we are doing in Listing 8-1.
Unzipping the Raspbian server
This unzips the file, and you will be left with an image file 2020-02-13-raspbian-buster-lite.img.
Wipe and Initialize the SD Card
Now let’s get the card ready to run the OS on our Pi. The card you bought should come blank, but too often they have drivers or other software on them usually for Windows computers. We want to blank them out and start fresh. The following code will initialize the disk but is specific for macOS using diskutil; the equivalent in Linux will be fdisk (with some slightly different options).
Getting the list of disks attached to the computer
➀ Our main internal disk.
➁ The disk that contains your hard drive OS and so on.
➂ Time Machine drive if you had it attached.
➃ The SD card attached.
The contents of the SD card you have will depend on the exact layout of your disk and what’s default software is on there. Some come completely blank, and others have initialization software. The most important thing is to identify which disk you have; the last thing you want to do is erase another disk. During this process, I recommend also disconnecting any other external drive so as not to confuse yourself since the next few steps are destructive.
It’s somewhat easy to spot the SD card on here by the size; you notice the 128.0 GB which is the size of the SD card I purchased for this. The SD card is on /dev/disk4; you will need this for the rest of the calls we are going to make.
Erasing the SD card with FAT32 on top
Unmount the disk
Install Image
Installing the RasPi image onto the card
dd: bs: illegal numeric value – Adjust your 4m to a smaller value; conversely, one could have a larger value if you get no error. But 4 seemed to be fine for my needs.
dd: unknown operand status – On the 4m, change it to capital M; on Linux it usually wants a capital M and on OSX a lowercase m.
The “conv=sync” at the end is to make sure the writing is absolutely complete and all the buffers flushed. This way, we don’t inject the SD card with some writing still occurring. At this point, our card should have the base Pi image on it.
If you look at your list of volumes, you should have one that is called boot now. This is where the files the Raspberry Pi will boot from. One that will be of importance to us later is the config.txt. We will update it for certain configuration changes later. For now, just put a blank file into the root of the boot volume called ssh (touch /Volumes/boot/ssh if on a Mac). This file being there will allow us later to be able to ssh into the Pi.
Final Setup Steps
![../images/481443_1_En_8_Chapter/481443_1_En_8_Fig7_HTML.jpg](https://imgdetail.ebookreading.net/20201209/5/9781484258606/9781484258606__rust-for-the__9781484258606__images__481443_1_En_8_Chapter__481443_1_En_8_Fig7_HTML.jpg)
The microSD card installed into our Raspberry Pi
- 1.
Determine the serial name for the USB plugged in.
- 2.
Install an application that will allow us virtual terminal access.
Find the USB serial connector
On OSX – brew install screen
On Linux – sudo apt-get install screen
![../images/481443_1_En_8_Chapter/481443_1_En_8_Fig8_HTML.jpg](https://imgdetail.ebookreading.net/20201209/5/9781484258606/9781484258606__rust-for-the__9781484258606__images__481443_1_En_8_Chapter__481443_1_En_8_Fig8_HTML.jpg)
Screen capture from USB cable debug login
In order to log in, you will use the default username pi and the password `raspberry`; after your first login, you should change your password. That initial login screen should look like Listing 8-7.
Login screen on your initial logging to the Raspberry Pi
Checking the connection status of Internet-connected devices
You will notice that while we have a wireless connection with wlan0, we have no actual IP address; that is because we have not configured it to log into your Wi-Fi router.
Set Up Wi-Fi
Let’s set up the wireless router; now these set of instructions will assume you have a password protection on your home router. This will be a two-step process; the first step will be to add a file that contains our wireless SSID and the password. The second step will be to then reboot the Pi to have everything take effect.
Creating our wireless connection file
➀ Is the name of your wireless SSID?
➁ Is the password for your wireless SSID (mine isn’t really just a password; it’s 1-2-3-4)?
At this point, you can reboot the Pi with the command reboot and then log back in. Now when you do ip address, you should see an actual ip address; try performing a ping google.com to verify you are reaching the Internet. Also make note of your IP address; we will use that later.
Contents of wpa-wlan0.conf
OK, so now we have a Pi that has Internet access and importantly local access. Now we will be able to ditch the USB serial cable and log directly onto the board. (Note: The debugging cable can still come in handy, and you don’t have to worry about SSH timeouts either.)
Setup SSH Access
You can now try to SSH into the box on your own; simply type ssh ubuntu@<the ip you wrote down earlier>. We can obviously do this by using the IP address and using the password each time, but this can get quite tedious over time.
Add pi to your /ets/hosts
Now in order to ssh to the box, all we have to do is ssh ubuntu@pi; you can go ahead and try it, but unfortunately, we still have to enter our password, and that can be annoying itself. This will become even more annoying as we make builds and send them to the Pi for testing. Let’s fix this by telling our Pi that the public key from our computer has access to the Ubuntu account on the Pi always. If you use Gitlab or any git instance, you probably have your public key created already. If you have, just skip to “Update Authorized Keys”; if you don’t, read on and we will set up the public key. If you aren’t sure if you have a public key, perform ls ~/.ssh, and if you get no files returned, then you don’t, and we will need to set it up.
Generating a public key on a Linux/OSX is fairly simple and identical; there are luckily built-in commands to create the keys. You can use the command ssh-keygen to generate the key; I would save it in the default location; if not, the rest of the instructions won’t work. But now, you can run cat ~/.ssh/id_rsa.pub and should have your keys installed.
Update Authorized Keys
Run this command from your computer to the Pi
You will have to enter the password one last time in there. But after this is done from your computer, run ssh ubuntu@pi, and you will be able to access your Pi without any password or remembering the IP address each time. Do remember though if the Pi’s IP ever changes, you will have to update your /etc/hosts. Now that we have the Pi ready, let’s start installing software.
Client Application
Now that we have the Pi all set up and we can log onto it, let’s start to get code written to go on the Raspberry Pi device. We are going to write two applications for this section. The first one is a simple hello world, just to see how a simple application works on the Pi. The second will be the start of our full-fledged application.
Hello World Application
Build Hello World and copy it to the Pi
Build our hello world application.
Copy the created target to the Raspberry Pi home directory for Ubuntu.
SSH and run the Hello World on the Pi
Well that didn’t work, did it? This should not seem like too much of a surprise if you understand Rust; like most compiled languages, they are targeted to a platform. We will need to target this for Raspberry Pi.
Cross Compiling
Installing the armv7-unknown-linux-musleabihf target
Defining the linker in .cargo/config
arm – The architecture we are targeting. Raspberry Pis use an ARMv7 development board.
vendor – The vendor, in many cases, is optional; in those cases, it is marked as unknown.
sys – The system we are compiling to, since we are deploying it to an Ubuntu Linux system, “linux”.
abi – The system that indicates the C library we are using for the cross compiling. In our case, it is the Musl GCC cross compiler; if you want more information on this library, you can read about it here: https://wiki.musl-libc.org/getting-started.html.
Defining the linker in .cargo/config
GCC cross compilers for arm
System | Command |
---|---|
OSX | brew install arm-linux-gnueabihf-binutils |
Linux | sudo apt-get install gcc-arm-linux-gnueabi |
Windows | Will need to install the Raspberry Pi tool chain from https://gnutoolchains.com/raspberry/. |
Defining the linker in .cargo/config
Success! You will also notice I compiled for a release profile; I do this because I wanted an optimized build, and also we haven’t defined anything yet for a dev profile (but you could have just as easily removed the --release tag). You will notice this file is located at target/armv7-unknown-linux-musleabihf/release/hello-world vs. our usual target/debug; we can build to multiple targets, and they would each reside in their corresponding directories.
Copying over our Hello World to the Raspberry Pi
Copy over the release to the home directory.
SSH to the Pi.
Run the Hello World app successfully.
Further MUSL libraries that need to be installed
System | Command |
---|---|
OSX | brew install MarioSchwalbe/gcc-musl-cross/gcc-musl-cross |
Linux | sudo apt install musl:i386=1.1.19-1 |
Please note the installation will take some time, so be patient during the download and install process. For OSX, you may add the --verbose flag if you want to make sure your installer is working.
Developing the Client Application
Now that we have our hello world deploying, let’s get to something more complex, the start of our MQ client application. We will be creating two applications on the Raspberry Pi that will learn how to communicate with each other. The first client application will be the rasp-pi-mq, and as the name sounds, this will deal with our MQTT server. We broke these two applications up for a few reasons: one is the resilience we wanted of the MQ application since it has to handle most of the communication with the outside world. And the other reason is for practice of having two applications communicate on the same device together (the techniques here are different than having two microservices communicate with each other). Much of the code we are going to use in this chapter has been created before, so we will only repeat what is necessary (but all of the source code is available for the book on the accompanying site). For our first application, we are going to create an application that runs continuously and sends a heartbeat back to the server at a predefined interval. While this is a simple case, it will give us much of what we need to go with on future chapters.
- 1.
Have the Pi look up a UUID of the device that we will create later at provisioning but will use this for determining uniqueness of a device.
- 2.
Upload all our certificates necessary to communicate to the server.
- 3.
Create a heartbeat to run at interval.
- 4.
Set up to run from the command line.
Create a UUID in /var/uuid
The start of our main method
Creating UUID
Create a UUID in /var/uuid
Retrieving the UUID from the device
➀ Reads the contents of the file into a String.
➀ Parses the string into a Uuid struct.
With the method in our main.rs, we can use the following code to our main() function to capture the UUID:
let uuid = read_device_id().chain_err(|| "No device id file found").unwrap();
Transferring Certificates
Client certificate
Client key
Root certificate
SCP the certificate files to the Pi
Setting Up Arguments
Now that we have our files on board, let’s think about what arguments we are going to need for this application to make it work both now and in the future. We are going to have the server do two things: one contact our endpoints via MQTT for sending and receiving heartbeats and requests. In addition, we will need https endpoints to perform direct queries and to upload and download files.
It’s good to remember the MQ and the HTTPS endpoints work hand in hand; the MQ provides us a way to receive commands from the Web, but to also transmit data when needed too, while the HTTPS is for more immediate queries or pushes of data.
- 1.
MQ client certificate
- 2.
MQ client key
- 3.
Root certificate
- 4.
MQ server address
- 5.
MQ server port
- 6.
HTTPS server
- 7.
HTTPS port
Parsing all the command-line arguments in src/main.rs
Command-line arguments for the Rasp Pi MQ app
Name | Short Value |
---|---|
Client cert | -c |
Client key | -k |
Root CA | -r |
Server | -s |
Port | -p |
Http server | -e |
Http port | -h |
Creating the Heartbeat
Calls the start_heartbeat function in src/main.rs
In here, we are passing a reference to the matches because we will need the matches when we expose other calls. In addition, we clone the Uuid; we are going to have to clone it a few times to use it around, but it’s small so it won’t add much to the stack.
The start_heartbeat function in src/main.rs
The heartbeat::run function in src/heartbeat.rs
➀ Uses the tokio timer.
➁ Uses the MQTT application and Config client we created before.
➂ Sets our interval in seconds; this will set up the interval for one hour.
➃ Starts up our Async via tokio.
➄ Creates our MqttClientConfig object for referencing the data.
➅ Creates an interval that will start immediately.
➆ And will fire every hour.
➇ The task that will be run each hour is sending a message to the heartbeat.
➈ Sends data to the MQ.
Two parts here are interesting; the tokio threading allows for all sorts of options for creating threads. In our case, we are using tokio to run an interval thread that will send every 60 seconds. Remember that the tokio::run is nonblocking; it simply creates a new thread, so this method will return immediately, which is the main reason we need to put the configuration data on the heap so it’s not lost or reborrowed by subsequent calling code.
The other thing is the send method itself. Right now, it’s pretty simple; it just sends an everything is great. And everything is great; from a server perspective, we will assume everything is not so great if we don’t hear back from it every hour. This method will get more interesting as we add on peripherals later in the book, but right now, we have about everything needed to run this application.
Keep Alive
The infinite loop at the end of our main function in src/main.rs
Run from the Command Line
Starts up the Raspberry Pi MQ application specifying our generated certificates
If you see any errors connecting to your server, it’s probably because you don’t have your application running on your desktop or a firewall blocking it. But assuming everything works, we now have our first IoT use case complete. A backend server is running with your device communicating with it.
Summary
This chapter was our first chapter with the Raspberry Pi, and hopefully yours is now running and communicating with the backend servers. Walking through I wanted to get you comfortable with the Pi, the installation of the components, installing the image, and copying over code for execution. In the next chapter, we will create another application that will also run on the Pi. And we will perform more tasks and installation on the Pi; some of it will include removing the SD card and updating the boot partition again.