We've all been there. "I'm going to get this Raspberry Pi to try out. They look kinda cool." And then, like tribbles on an Enterprise, suddenly you have Kubernetes clusters and NFS servers and Tor proxies. Maybe even a hotel booking system!
Pis cover the desk. They spill out onto the floor. Carrier boards for Raspberry Pi compute modules installed into lunchboxes litter the shelves.
…or maybe that's just me?
I'll bet if you have one Raspberry Pi, you've got at least two others, though, and gosh darn it, they all look the same.
This was the situation I found myself in recently while testing a network filesystem (NFS) server I set up on one of my Raspberry Pis. I needed to plug in a USB hard drive, but … to which one? Ol' Lingonberry Pi was the chosen host, and I was SSH'd into her, but which actual, physical RPi was she? There was no way of knowing…
Or was there?
At a previous job, I sometimes worked on servers in our data centers, and some of them had a neat feature: an ID button on the front of the server that, when pressed, started an LED flashing on the front and back of the server. If I needed to deal with the other side of the server, I could press the ID button, then walk allllll the way around to the other side of the rack, and easily find the right server.
I needed something like this to find Lingonberry.
There aren't any buttons on the Pis, but there are LEDs, and after a quick Google search, I learned that one of them is controllable. Cue maniacal laughter.
There are three important bits to know. First, the LED path: on Raspberry Pis, at least those running Ubuntu 20.04, the front (and user-controllable) LED is found at /sys/class/leds/led0
. If you navigate to it, you'll find it is a symlink to a directory that has a number of files in it. The two important files are trigger
and brightness
.
The trigger
file controls what lights up the LED. If you cat
that file, you will find a list:
none usb-gadget usb-host rc-feedback rfkill-any
rfkill-none kbd-scrolllock kbd-numlock kbd-capslock
kbd-kanalock kbd-shiftlock kbd-altgrlock kbd-ctrllock
kbd-altlock kbd-shiftllock kbd-shiftrlock kbd-ctrlllock
kbd-ctrlrlock timer oneshot disk-activity disk-read
disk-write ide-disk mtd nand-disk heartbeat backlight
gpio cpu cpu0 cpu1 cpu2 cpu3 default-on input panic
mmc1 [mmc0] bluetooth-power rfkill0
unimac-mdio--19:01:link unimac-mdio--19:01:1Gbps
unimac-mdio--19:01:100Mbps unimac-mdio--19:01:10Mbps
The item in brackets indicates what triggers the LED; in the example above, it's [mmc0]
—the disk activity for when the SD card plugged into the Raspberry Pi. The trigger file isn't a normal file, though. Rather than editing it directly, you change the trigger by echoing one of the triggers into the file.
To identify Lingonberry, I needed to temporarily disable the [mmc0]
trigger, so I could make the LED work how I wanted it to work. In the script, I disabled all the triggers by echoing "none" into the trigger file:
# You must be root to do this
$ echo none >trigger
$ cat trigger
[none] usb-gadget usb-host rc-feedback rfkill-any rfkill-none kbd-scrolllock kbd-numlock kbd-capslock kbd-kanalock kbd-shiftlock kbd-altgrlock kbd-ctrllock kbd-altlock kbd-shiftllock kbd-shiftrlock kbd-ctrlllock kbd-ctrlrlock timer oneshot disk-activity disk-read disk-write ide-disk mtd nand-disk heartbeat backlight gpio cpu cpu0 cpu1 cpu2 cpu3 default-on input panic mmc1 mmc0 bluetooth-power rfkill0 unimac-mdio--19:01:link unimac-mdio--19:01:1Gbps unimac-mdio--19:01:100Mbps unimac-mdio--19:01:10Mbps
In the contents of the trigger file above, you can see [none]
is now the selected trigger. Now the LED is off and not flashing.
Next up is the brightness
file. You can control whether the LED is on (1) or off (0) by echoing either 0 or 1 into the file. Alternating 1 and 0 will make the LED blink, and doing it with a one-second sleep in the middle produces a regular on/off blink unlike any of the activity that would otherwise trigger the LED. This is perfect for identifying the Raspberry Pi.
Finally, if you do not set the trigger file back to a trigger, it remains off. That's not what you want most of the time—it's better to see the disk activity. This means you have to make sure that any script you write will reset the trigger when it's finished or interrupted. That calls for a signal trap. A trap will capture the SIGINT
or SIGTERM
(or other) signals and execute some code before quitting. This way, if the script is interrupted—say if you press CTRL+C to stop it—it can still reset the trigger.
With this newfound knowledge, I was able to bang out a script (available under the MIT License) pretty quickly and toss it onto my Raspberry Pis:
#!/bin/bash
set -o errexit
set -o nounset
trap quit INT TERM
COUNT=0
if ! [ $(id -u) = 0 ]; then
echo "Must be run as root."
exit 1
fi
LED="/sys/class/leds/led0"
if [[ ! -d $LED ]]
then
echo "Could not find an LED at ${LED}"
echo "Perhaps try '/sys/class/leds/ACT'?"
exit 1
fi
function quit() {
echo mmc0 >"${LED}/trigger"
}
echo -n "Blinking Raspberry Pi's LED - press CTRL-C to quit"
echo none >"${LED}/trigger"
while true
do
let "COUNT=COUNT+1"
if [[ $COUNT -lt 30 ]]
then
echo 1 >"${LED}/brightness"
sleep 1
echo 0 >"${LED}/brightness"
sleep 1
else
quit
break
fi
done
This script checks that the LED control directory exists, disables the [mmc0]
trigger, and then starts a loop blinking the LED on and off every second. It also includes a trap to catch INT
and TERM
signals and resets the trigger. I copied this script onto all my Raspberry Pis, and any time I need to identify one of them, I just run it. It worked perfectly to identify Ol' Lingonberry, so I could set up the disks for the NFS server, and I've used it a number of times since then.
One thing to note—the path to the LED might be different in other distributions. There are also other LEDs in the /sys/class/leds
directory, but they are not controllable by the user; they are hooked into different bits of the firmware of the Raspberry Pi.
Do you have any cool Raspberry Pi tricks? Let me know in the comments! I'm always interested in learning what other people do with their infestation of Pis!
4 Comments