A Raspberry Pi Kiosk (Shallow Thoughts)

Akkana's Musings on Open Source Computing and Technology, Science, and Nature.

Wed, 12 Feb 2020

A Raspberry Pi Kiosk

After writing a simple kiosk of rotating quotes and images, I wanted to set up a Raspberry Pi to run the kiosk automatically, without needing a keyboard or any on-site configuration.

The Raspbian Desktop: Too Hard to Configure

Unlike my usual Raspberry Pi hacks, the kiosk would need a monitor and a window system. So instead of my usual Raspbian Lite install, I opted for a full Raspbian desktop image.

Mistake. First, the Raspbian desktop is very slow. I intended to use a Pi Zero W for the kiosk, but even on a Pi 3 the desktop was sluggish.

More important, the desktop is difficult to configure. For instance, a kiosk needs to keep the screen on, so I needed to disable the automatic screen blanking. There are threads all over the web asking how to disable screen blanking, with lots of solutions that no longer apply because Raspbian keeps changing where desktop configuration files are stored.

Incredibly, the official Raspbian answer for how to disable screen blanking in the desktop — I can hardly type, I'm laughing so hard — is: install xscreensaver, which will then add a configuration option to turn off the screensaver. (I actually tried that just to see if it would work, but changed my mind when I saw the long list of dependencies xscreensaver was going to pull in.)

I never did find a way to disable screen blanking, and after a few hours of fighting with it, I decided it wasn't worth it. Setting up Raspbian Lite is so much easier and I already knew how to do it. If I didn't, Die Antwort has a nice guide, Setup a Raspberry Pi to run a Web Browser in Kiosk Mode, that uses my preferred window manager, Openbox. Here are my steps, starting with a freshly burned Raspbian Lite SD card.

Set Up Raspbian Lite with Network and SSH

I wanted to use ssh on my home network while debugging, even though the final kiosk won't need a network. The easiest way to do that is to mount the first partition:

sudo mount /dev/sdX1 /mnt
(sdX is wherever the card shows up on your machine, e.g. sdB) and create two files. First, an empty file named ssh
touch /mnt/ssh

Second, create a file named wpa_supplicant.conf with the settings for your local network:

ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev


Then unmount that partition:

sudo umount /mnt

Copy the Kiosk Files into /home/pi

The second partition on a Raspbian card is the root filesystem, including /home/pi, the pi user's home dictory. Mount /dev/sdX2, copy your kiosk code into /home/pi, and chown the code to the pi user. If you don't know what that means or how to do that, you can skip this step and load the code onto the Pi later once it's up and running, over the network or via a USB stick.

Unmount the SD card and move it to the Raspberry Pi.

Raspbian First-boot Configuration

Boot the Pi with a monitor attached, log in as the pi user, run sudo raspi-config, and:

So the installation won't become too bloated, I like to create the file /etc/apt/apt.conf containing:

APT::Install-Recommends "false";
APT::Install-Suggests "false";
(That's the equivalent of the --no-install-recommends in the Die Antwort guide.)

Update the OS, and install the packages needed to run X, the Openbox window manager, a terminal (I used xterm), and a text editor (I used vim; if you're not familiar with Linux text editors, pico is more beginner-friendly). If you're in a hurry, you can skip the update and dist-upgrade steps.

$ sudo apt update
$ sudo apt dist-upgrade
$ sudo apt install xserver-xorg x11-xserver-utils xinit openbox xterm vim

I was surprised how little time this took: even with all of the X dependencies, the whole thing took less than twenty minutes, compared to the several hours it had taken to dist-upgrade all the packages on the full Raspbian desktop.

Install any Kiosk-specific Packages

Install any packages you need to run your kiosk. My kiosk was based on Python 3 and GTK 3:

sudo apt install python3-cairo python3-gi python3-gi-cairo \
         libgirepository-1.0-1 gir1.2-glib-2.0 python3-html2text
(This also pulled in gir1.2-atk-1.0, gir1.2-freedesktop, gir1.2-gdkpixbuf-2.0, gir1.2-pango-1.0, and gir1.2-gtk-3.0, but I don't think I had to specify any of them explicitly.)

Configure Openbox

Create the Openbox configuration directory:

mkdir -p .config/openbox
Create .config/openbox/autostart containing:
# Disable screen saver/screen blanking/power management
xset s off
xset s noblank
xset -dpms

# Start a terminal
xterm &

Save the file, and test to make sure you can run X:

$ startx

You should see a black screen, a mouse pointer, and after a few seconds, a small xterm window in the center of the screen. You can use the xterm to fiddle with things you want to change, or you can right-click anywhere outside the xterm window to get a menu that will let you exit X and go back to the bare console.

Test Your Kiosk

With X running, you can run your kiosk command. Don't change directories first; the pi user will be /home/pi ($HOME) after automatically logging in, so make sure you can run from there. For instance, I can run my kiosk with:

$HOME/src/scripts/quotekiosk.py $HOME/100-min-kiosk/slideshow/* $HOME/100-min-kiosk/quotes/*.html

Once the command works, edit .config/openbox/autostart and add your command at the end, after the xterm line, with an ampersand (&) after it. Keep the xterm line in place so you'll have a way to recover if things go wrong.

Configure X to Start When the Pi User Logs In

You've already set up the Pi user to be logged in automatically when the machine boots, but pi needs to start X upon login. Create the file .bash_profile containing:

[[ -z $DISPLAY && $XDG_VTNR -eq 1 ]] && startx

You should be ready to go. Reboot, and the Pi should boot up in kiosk mode.

Run in a Loop

Everything working? For extra security, you might want to tweak the autostart file to run your kiosk in a loop. That way, even if the kiosk code crashes for some reason, it will be restarted.

while :
    $HOME/src/scripts/quotekiosk.py $HOME/100-min-kiosk/slideshow/* $HOME/100-min-kiosk/quotes/*.html

Don't do this until after you've tested everything else; it's hard to debug with the kiosk constantly popping up on top of other windows.

Get Rid of that Pesky Cursor

You might also want to remove that annoying mouse pointer arrow in the middle of the screen. Editing that startx line you just added to .bash_profile:

[[ -z $DISPLAY && $XDG_VTNR -eq 1 ]] && startx -- -nocursor

This step comes last — because once you've disabled the cursor, it will be difficult to use the machine interactively since you won't be able to see where your mouse is. (If you need to make changes later, you can ssh in from another machine, mount the Raspbian SD card on another machine, or use Ctrl-Alt-F2 to switch to a console window where you can edit files.)

... But It's Still Not Quite Hands-Off

The Pi is now set up to work automatically: just plug it in. The problem was the monitor. Someone contributed a TV, but it turned out to be a "smart TV", and it had its own ideas about what it would connect to. Sometimes the HDMI ports worked, sometimes it refused to display anything, and even when it worked, it randomly brightened and dimmed so that the screen was often too dim to see.

So I contributed my old 20" monitor. Everything worked fine at the demo the night before, and I handed it off to the people who were going to be there early for setup. When I arrived at the Roundhouse the next day, there was my monitor, displaying "No Signal". Apparently, while setting it up, someone had bumped the monitor's "Input Source" button; and of course no one there was up to the task of diagnosing that difficult problem. And no one bothered to call me and ask.

Once I arrived, I pressed the Source button a couple of times and the kiosk display was up and running for the rest of the day. Sigh. I can write kiosk software and set up Raspberry Pis; but predicting potential issues non-technical users might encounter is still beyond me.

[ 11:08 Feb 12, 2020    More tech | permalink to this entry | ]

Comments via Disqus:

blog comments powered by Disqus