TIL: Managing Raspberry Pi software with a bit less pain

For the printer project I'm working on, most of the software behind it runs "in the cloud", but there's some software that needs to run beside each printer, to check for new things to print and manage the process of downloading and sending those things to the printer component itself.

In the current incarnation of the project, this "on the desk" software runs on a small Raspberry Pi computer, which acts as a simple bridge between your Wi-Fi and the printer, funnelling data from our servers to thing that will actually print it out.

Raspberry Pis are fully-fledged little computers in their own right, but they don't typically have any of the peripherals of a computer -- a screen, a keyboard, a mouse -- that would allow you interact with them and do important things like, say, tell it your Wi-Fi network and password. Even the files the Pi uses when its running, stored on a removable SD card, aren't easy to access unless you've got another Linux computer kicking around.

Yes, you can SSH into the little computer and configure it from the command-line, but that only works after Wi-Fi is working (you might even say it's a chicken-and-egg situation).

The first problem to solve is making it easy for my colleagues to set up Wi-Fi. To do this, we can take advantage of what's called the "boot partition". This is a small part of the SD card that pretty much every computer, including Macs and Windows machines, can read and write.

When they plug the SD card into their laptop, they can now run a script from the SD card which asks a few simple questions and writes a magic wpa_supplicant.conf file into this boot partition, which the Pi will use to configure the Wi-Fi the next time it turns on. The script is very simple:

#!/usr/bin/env ruby 

puts "Setting up wifi..."
print "SSID: "
ssid = gets.chomp
print "Password: "
password = gets.chomp

File.open(File.join(File.dirname(__FILE__), "wpa_supplicant.conf"), "w") do |f|
f.puts <<~EOF
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update\config=1
country=US

network={
ssid="#{ssid}"
psk="#{password}"
}
EOF
end

And ever after Wi-Fi is setup, managing the software scripts can become a tangle of scp and rsync commands that are a pain to deal with, even for me. So our second problem is how to make it easier for my colleagues to update the software when we fix bugs, add new features and so on.

The solution here is to put that software into the boot partition too. Updating the software is just a matter of putting the SD card in your computer, copying the new files over, and then putting the card back into the Pi.

til-printer-raspberry-pi-filesystem.png

There are a few other complications (like setting up the software to run when the Pi starts), but as long as that configuration always references the script in the boot volume, it works pretty well.

There are certainly other, more "production" ways of managing software on embedded devices like this, such as Balena OS, but for our current Cosmic needs, this works just fine.