After lovingly crafting your project on a Raspberry Pi, you might want to share it with the world. The easiest way is of course just to publish a list of the commands that you executed to get everything up and running. For complex projects, this list can grow quite long, be intimidating for beginners, and be downright inconvenient to execute. I know I'm not too fond of sitting around babysitting various package to downloads and installations.
A more polished way is to create an installer script - an executable file that handles installing packages and tweaking settings for the user. This is what we'll be working on in this tutorial.
Recently, I published a project which was a Tweeting GIF camera using a Raspberry Pi Zero W. The project was driven by a single Python script, but for the script to run correctly there were quite a few packages to install, and a file to modify - the perfect case-study for writing an installer script. The following is a recount of my thought process in making that particular installer, but the skills are immediately transferrable to other scripting in general.
To keep things as simple as possible, the installer from the project assumes it's being executed on a fresh install of Raspbian Lite.
Let's take a look at the steps that need to be taken to get the project up and running:
- Run update and upgrade (always a good idea if you're going to install some packages)
- Install several packages: python-picamera, graphicsmagick, and python-pip
- Install a python package: twython
- Set up the camera interface. This requires:
- Enabling the interface
- Setting gpu memory allocation
Let's tackle each point in turn.
Running Update and Upgrade
This one's easy, we'll just call:
apt-get update && apt-get upgrade -y
where:
- && allows you to queue commands one after the other,
- -y automatically selects the "yes" option when the user would be prompted to initiate an installation.
Installing the Packages
Recap: the packages to install are:
- python-picamera allows python to interact with the pi-camera (go figure)
- graphicsmagick is a cross-platform package that our project will use to stitch still images into a gif. graphicsmagick sits under the hood of some pretty huge projects like Etsy and Flickr.
- python-pip is a python package manager, it's required to download twython.
- twython is a python package that interacts with the Twitter API, so we can tweet autonomously from our Pi.
We can install multiple packages at the same time just by passing their names as additional arguments to apt-get, so this one's pretty easy too. To spice things up a bit lets throw in a variable (PACKAGES) to make our script a little nicer to look at.
PACKAGES="python-picamera graphicsmagick python-pip"
apt-get install $PACKAGES -y
pip install twython
Configuring the Camera
This is where things start to get a bit interesting. We're no longer just executing basic download commands.
Normally, to enable the camera on the desktop or through SSH, we would be accessing the Raspberry Pi Configuration (desktop GUI) or raspi-config (shell). In these interfaces we'd just be selecting an option to enable the camera - behind the scenes, a file called /boot/config.txt is being modified. There's no reason you couldn't modify this file directly with a text editor.
The parameters that we need to add/modify to /boot/config.txt are:
- start_x=1
- gpu_mem=128
Problem Definition:
- In /boot/config.txt there may or may not be entries for start_x and gpu_mem
- If there is an entry, we want to make sure it's set to the correct value
- If there is no entry, we want to append the file with an entry that sets the parameter to the correct value.
We are going to have to search the contents of /boot/config.txt for the relevant strings, and use some logic to decide what happens if the string is found or not found. Note that the solution presented in this tutorial is still a pretty rudimentary way of configuring the Pi's config variables. If you want to learn more, you could have a dig through the contents of /usr/bin/raspi-config. The areas of interest are the functions set_config_var() and do_camera().
The commands we'll need are grep, which searches a file for a text pattern in a file, and sed which is used for editing data.
We'll use the following if statement to check if "start_x" exists anywhere in the file:
# If a line containing "start_x" exists
if grep -Fq "start_x" "/boot/config.txt"
then # Make sure start_x=1
else
# Append file with "start_x=1"
fi
Where:
- -F searches for a fixed string
- -q runs the program in "quiet mode," i.e., nothing will be displayed on the terminal
- "start_x" is the text we're looking for
- $CONFIG, a variable set to /boot/config.txt, is the file we're looking in.
By default, grep returns the lines that it matches. The if-statement will be true if grep returns anything, and false if it does not.
Now for the sed command. We can modify our if-statement as follows
CONFIG="/boot/config.txt"
# If a line containing "start_x" exists
if grep -Fq "start_x" $CONFIG
then # Make sure start_x=1
sed -i "s/start_x=0/start_x=1/g" $CONFIG
else
# Append file with "start_x=1"
fi
Where:
- the file path is now stored in a variable: $CONFIG
- -i edits a file in-place
- s is the substitute command. We'll substitute an exact piece of text.
- / is a delimiter
- start_x=0 is the text we will replace
- / is a delimiter
- start_x=1 is the text we will use as a substitute
- / is a delimeter
- g sets the command to global - all matches will be substituted
And what if an entry for start_x does not exist? That is the else condition of the if-statement. Here we'll append the file with a piece of text using the >> operator.
CONFIG="/boot/config.txt"
# If a line containing "start_x" exists
if grep -Fq "start_x" $CONFIG
then # Make sure start_x=1
sed -i "s/start_x=0/start_x=1/g" $CONFIG
else
# Append file with "start_x=1"
echo "start_x=1" >> $CONFIG
fi
Where:
- echo displays a line of text
- >> takes the data from echo, and uses it to append the $CONFIG file
That's the start_x case taken care of. The code for gpu_mem is very similar with one small change:
# If a line containing "gpu_mem" exists
if grep -Fq "gpu_mem" $CONFIG
then
# Replace the line
sed -i "/gpu_mem/c\gpu_mem=128" $CONFIG
else
# Append the file
echo "gpu_mem=128" >> $CONFIG
fi
Notice the difference in the sed line. the c\ command is used to change a whole line. We do this because gpu_mem could be set to many different values (8, 16, 32, 64, etc...) so here we're replacing the whole line, just to be certain.
Finally, we can issue a command to reboot the Pi.
A complete copy of the script with additional comments is as follows:
#!/bin/sh # installer.sh will install the necessary packages to get the gifcam up and running with # basic functions # Install packages PACKAGES="python-picamera graphicsmagick python-pip" apt-get update apt-get upgrade -y apt-get install $PACKAGES -y pip install twython ## Enable Camera Interface CONFIG="/boot/config.txt" # If a line containing "start_x" exists if grep -Fq "start_x" $CONFIG then # Replace the line echo "Modifying start_x" sed -i "s/start_x=0/start_x=1/g" $CONFIG else # Create the definition echo "start_x not defined. Creating definition" echo "start_x=1" >> $CONFIG fi # If a line containing "gpu_mem" exists if grep -Fq "gpu_mem" $CONFIG then # Replace the line echo "Modifying gpu_mem" sed -i "/gpu_mem/c\gpu_mem=128" $CONFIG else # Create the definition echo "gpu_mem not defined. Creating definition" echo "gpu_mem=128" >> $CONFIG fi echo "Install complete, rebooting." reboot
And that completes our installer script. Now a user can quickly download the necessary packages and make system configurations just by executing our script.
To be frank, this script is pretty inelegant. Every call to grep or sed access the config file, and the file probably doesn't need to be accessed as many times as this script does - I'm still new to this and just wanted to keep things as clear and methodical as possible. If you have any suggestions for improvements that can be made to the script, we'd love to hear from you in the comments section for this tutorial, or over in our forums.