Adapting to a small touchscreen monitor with PiMenu

Lead Image © Noppadol Anaporn,

New Face

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

(this requires Git installed on Raspberry Pi).

PiMenu consists of three key parts: the Python script that draws the GUI, the pimenu.yaml configuration file that defines menu items, and the Bash shell script that performs actions based on arguments received from

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.

Putting PiMenu to Practical Use

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 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 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 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

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]

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).

Figure 1: PiMenu tiled interface in action.

Going Further

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.

Buy this article as PDF

Express-Checkout as PDF

Pages: 4

Price $2.95
(incl. VAT)

Buy Raspberry Pi Geek

Get it on Google Play

US / Canada

Get it on Google Play

UK / Australia

Related content