New Face
Use PiMenu to build a menu-based graphical interface optimized for small LCD touchscreens.
Use PiMenu to build a menu-based graphical interface optimized for small LCD touchscreens.
Adding a small LCD touchscreen to Raspberry Pi seems like a terrific idea (see the "Choosing a Touchscreen" box) – until you realize that the default desktop environment is not optimized for tiny displays. The tendency of programmers to design for an old-style computer desktop means launching applications and performing actions on a tiny touchscreen is often fiddly at best. In most cases, though, you might just be using the touchscreen for a few specific tasks, and building your own graphical interface might seem like too much trouble.
Choosing a Touchscreen
Several LCD touchscreens for Raspberry Pi are available on the market. The PiTFT 2.8-inch 320x240 panel from Adafruit [3] is available through several web stores. You can also buy a stylish PiTFT Pibow case [4] for it. You'll find a wealth of documentation on installing and using PiTFT on Adafruit's website [5]. RPI-Display from Watterott [6] is another good option – especially if you are based in Europe. Watterott also sells an enclosure for the Raspberry Pi and RPI-Display combo [7], and all the required software (including an SD card image) is available in the RPi-Display GitHub repository [8]. It's also possible to find a decent touchscreen for Raspberry Pi on eBay, but make sure it comes with the required software.
Enter PiMenu [1] – a simple solution written in Python and TkInter that lets you build tile-based graphical interfaces with consummate ease. PiMenu was originally designed by Andreas Gohr of DokuWiki fame for his paper backup project [2]. Thanks to its simplicity and versatility, however, PiMenu can be easily adapted for any other project requiring a simple graphical interface.
Better still, PiMenu relies on components that are installed by default on Raspbian. You only need to add the python-yaml package using the
sudo apt-get install python-yaml
command to make PiMenu work on Raspberry Pi. Then, grab the latest release of PiMenu as a ZIP archive from the project's GitHub repository, or clone the repository using
git clone https://github.com/splitbrain/pimenu.git
(this requires Git installed on Raspberry Pi).
PiMenu consists of three key parts: the pimenu.py
Python script that draws the GUI, the pimenu.yaml
configuration file that defines menu items, and the pimenu.sh
Bash shell script that performs actions based on arguments received from pimenu.py
.
For each menu item specified in the pimenu.yaml
configuration file, PiMenu draws a tile, and the main script automatically resizes tiles to fit them in the window. The tiled interface is inspired by the Windows 8 design, which actually works pretty well on Raspberry Pi. In the pimenu.yaml
file, you can specify a hierarchy of menu items, so you can create a rather elaborate menu structure.
I don't travel as much as I would like to, but when I do, I take a lot of photos. And I always wanted to build a Raspberry Pi-based backup device to keep my precious snapshots safe while I'm traveling. PiMenu was the missing piece required to bring this idea to fruition. Ideally, the Raspberry Pi-based backup box should perform several tasks, such as transferring photos directly from a camera or a card reader and backing up the transferred photos to a USB storage device.
The first order of business is to edit the pimenu.yaml
file to include the required menu items (Listing 1). Each menu item in the configuration file has four properties: mandatory name
and label
as well as optional color
and icon
. The icon
refers to the name of the appropriate icon in the GIF format stored in the ico
directory (e.g., icon: "menu"
points to the ico/menu.gif
graphics file).
Listing 1
PiMenu Configuration
01 # Menu configuration 02 --- 03 - 04 name: "Menu" 05 label: "Menu" 06 color: "#FF851B" 07 icon: "menu" 08 items: 09 - 10 name : "Camera" 11 label: "Camera" 12 color: "#3D9970" 13 icon : "camera" 14 - 15 name : "USB" 16 label: "USB" 17 color: "#39CCCC" 18 icon : "usb" 19 - 20 name : "Backup" 21 label: "Backup" 22 color: "#7FDBFF" 23 icon : "backup" 24 - 25 name: "Exit" 26 label: "Exit" 27 color: "#85144B" 28 icon: "exit"
The additional items
property can be used to specify sub-items. In this case, the Menu
item contains three sub-items: Camera
, USB
, and Backup
. Note that the menu items and sub-items must be indented properly using spaces (not tabs) and separated with the "-
" separator.
The pimenu.py
Python script not only draws the interface using the configuration from the pimenu.yaml
file, but it also reads the names of the menu tiles when pressed and executes the pimenu.sh
Bash shell script. This is where all the action happens. You can configure the script to perform actions based on the name of the pressed tile. One way is to configure the script to read the name of the pressed tile and then use a case
conditional statement to perform the desired actions.
To obtain the name of the pressed tile, you can use the echo "$*"
command. However, this command returns the names of all menu items if the pressed tile resides somewhere down the menu hierarchy. For example, if you press the Backup tile, the returned result will be Menu Backup. Because pimenu.sh
needs only the name of the pressed tile, you can use the awk tool to extract it from the result returned by the echo "$*"
command and assign the obtained value to the key
variable:
key=$(echo "$*" | awk 'NF>1{print $NF}')
This variable can then be used in the case
statement as shown in Listing 2. I'll take a closer look at what each part of the case
statement actually does.
Listing 2
pimenu.sh
01 #!/bin/bash 02 key=$(echo "$*" | awk 'NF>1{print $NF}') 03 case $key in 04 Camera) 05 ps aux | grep -ie gphoto2 | awk '{print $2}' | xargs kill -9 06 cd 07 if [ ! -d "PHOTOS" ]; then 08 mkdir PHOTOS 09 fi 10 cd PHOTOS 11 gphoto2 --get-all-files --new --filename "%Y%m%d-%H%M%S.%C" 12 ;; 13 USB) 14 cd 15 if [ ! -d "PHOTOS" ]; then 16 mkdir PHOTOS 17 fi 18 USB_MOUNT_POINT=$(find /media/ -mindepth 1 -maxdepth 1 -not -empty -type d | \ sed 's/ /\\ /g') 19 exiftool -r -d /home/pi/PHOTOS/%Y%m%d-%H%M%S.%%e '-FileName<DateTimeOriginal' \ $USB_MOUNT_POINT >> /home/pi/transfer.log 20 ;; 21 Backup) 22 cd 23 if [ ! -d "PHOTOS" ]; then 24 exit 1 25 fi 26 USB_MOUNT_POINT=$(find /media/ -mindepth 1 -maxdepth 1 -type d | sed 's/ /\\ /g') 27 eval rsync -avhz /home/pi/PHOTOS/ $USB_MOUNT_POINT/ --log-file=/home/pi/backup.log 28 ;; 29 '') 30 ps aux | grep -ie pimenu | awk '{print $2}' | xargs kill -9 31 ;; 32 esac 33 sleep 3
When the Camera tile press is detected, the script kills all running gphoto2 processes using
ps aux | grep -ie gphoto2 | awk '{print $2}' | xargs kill -9
This ensures that no ghoto2 processes keep the connected camera busy, thus preventing the transfer of photos from it. To keep things tidy, the script transfers all photos into the separate ~/PHOTOS
directory, and the if
conditional statement creates the directory if it doesn't already exist. Finally,
gphoto2 --get-all-files --new --filename "%Y%m%d-%H%M%S.%C"
downloads photos from the camera and renames them on the fly using the defined renaming pattern in quotation marks.
The part of the script that transfers files from the connected USB storage device or card reader does two things. First, it uses
USB_MOUNT_POINT=$(find /media/ -mindepth 1 -maxdepth 1 -not \ -empty -type d | sed 's/ /\\ /g')
to obtain the mountpoint of the USB device. It does so by using the find
tool, which looks for non-empty folders in the media
directory. The sed
tool in turn applies proper escaping if the obtained path contains white spaces (e.g., /media/NIKON D90/DCIM/100NCD90/
becomes /media/NIKON\ D90/DCIM/100NCD90/
). This command assumes that there is only one USB storage device or card reader connected to Raspberry Pi at the time.
To back up the transferred photos to an external storage device connected to the USB port of Raspberry Pi, the script features two commands: The first one obtains the mountpoint of the USB device, and the second command uses the rsync
tool to copy the photos.
Tapping on the tile with no sub-tiles returns an empty result, so the final part of the case
statement closes PiMenu by killing all running pimenu
processes if the $key
value is empty – that is, the '')
condition.
With PiMenu configured and ready to go, you have only two things left to do: Install the required packages and provide a way to launch PiMenu without using the keyboard. To install the packages, run the following commands:
sudo apt-get update sudo apt-get install gphoto2 libimage-exiftool-perl rsync
To launch PiMenu without resorting to the keyboard, you can create a desktop shortcut. To do this, use the
nano Desktop/pimenu.desktop
command to create the pimenu.desktop
file and open it for editing. Paste the following snippet into it:
[Desktop Entry] Name=PiMenu Comment=PiMenu Exec=/home/pi/pimenu/pimenu.py Icon=lxterminal Terminal=false MultipleArgs=false Type=Application StartupNotify=true
After you save the file, double-tap on the created PiMenu desktop shortcut, and you should see the PiMenu in all its tiled glory (Figure 1).
With minimal tweaking, you can improve the described project and put it to other uses. For example, you can easily extend PiMenu's configuration to include cloud backup (e.g., using rsync
via SSH), preview photos downloaded from the camera or a card reader, and much more. You can easily modify the project to use Raspberry Pi as a backup device not only for photos but also for files and documents in general.
You can also adapt PiMenu to entirely different uses altogether. For example, you can turn your Raspberry Pi into an Internet radio device that lets you choose stations via the touch-screen menu, or you can build a simple launcher that opens specific applications. In other words, if you have a Raspberry Pi with an LCD touchscreen, PiMenu can prove to be an indispensable ingredient for making the combo useful.
Infos
Pages: 4
Price $15.99
(incl. VAT)