header image

Raspberry Pi Kiosk Project

Intro

My wife asked me to get a clock for the kitchen so I went to Amazon and was left with the choice of a crappy analog clock which would break in a couple of years or an overpriced digital one. Then it struck me: I had a 17" monitor in the closet with a VESA mounting backet doing nothing. I'd make a clock with a raspberry pi and it would be able to display more than just the time. Here's what it currently does:

  • Upcoming Google calendar events
  • Countdowns to future events
  • Google maps with traffic layer
  • News stories from the Seattle Times RSS feed
  • Upcoming events from the Stranger events webpage
  • Photos from picasaweb albums
  • Upcoming weather forecasts
  • Current weather radar image
  • Google docs for grocery list, costco list, random announcements
  • Ski and pass conditions at Stevens Pass
  • Webcams
  • Oh, and an analog clock with an alarm when it's time for my son to leave for school.

Here's what it ends up looking like from the kitchen (click to embiggen):

Physical Build

This is a pretty easy build, frankly. I did have to install an outlet and some blocking between the studs so the monitor would have power and be securely mounted. Luckily there was already a wire right behind the wall I was planning to mount this thing on with enough slack in it that I could get a box installed pretty easily. The blocking is a piece of scrap wood with pocket-hole screws attaching it to the studs. I didn't use a 2x4 because it needs to be taller than that to accommodate the VESA mount and I didn't have a 2x6.

I ended up velcroing the monitor's 14 volt power supply and the rpi itself to the back of the monitor, you can see them from the side but it's not too ugly. They're invisible from the front and no one seems to notice this stuff. I used a USB wifi adapter for network and a spare micro USB plug from the phone to power the rpi. Here's what it looks like from the side:

I actually ordered a 1-foot DVI cable and used a spare HDMI->DVI adapter for the video. In retrospect, the short cable doesn't really make the backside of the monitor any cleaner; just go with a long one coiled up. I also bought a 1-foot standard power cable to run the monitor's AC->DC power brick. Again, maybe not necessary.

I wish the monitor had an integrated USB hub and speakers but it has neither requiring me to run the rpi from the other plug in the outlet I installed and meaning that I had to stuff a speaker up behind the monitor if I wanted any sound. I had a speaker they gave out at work (for some reason) so I used that. But it makes for kinda a mess behind the monitor. All invisible from the front, though.

Software Setup

I thought about various ways to do the software and concluded that I'd just run a javascript capable browser in full screen mode and point it at a URL with a periodic refresh via javascript. A separate process would change what was at that URL periodically too.

Unfortunately, there's no stable accellerated X Window server for rpi (yet) so I was concerned with the speed of rendering pictures. The default browser (Epiphany) does ok but I noticed the rpi Chromium port seemed faster at rendering my Google maps and full screen pictures so I went with that.

To boot directly into X and fire up a browser in full screen mode I just chose to not wait for a login in the installer (sudo raspi-config) and then edited /etc/xdg/lxsession/LXDE/autostart. Google is your friend. Here are some links:

On the other side, I wrote a python script responsible for two things: choosing the next page to display and periodically rendering pages. It has one thread devoted to each task:

Chooser thread:
Lists the files in the pages/ directory and chooses one. I have played with various subclasses -- one that does a determinstic rotation and another that does a weighted random distribution. To cut down on I/O to the SD card of the rpi, I only read the contents of the directory once per hour and other times use a memorized list of files to choose from.

Renderer thread:
Periodically allowed to rewrite the files in the pages/ directory; for example, once an hour it fetches the current weather forecast from a website (wunderground) and recreates the page.

I decided to keep the time/date on the top line of each page so the kiosk is useful as a clock no matter what page it's currently displaying. In the end, I also decided to mix in the analog clock page frequently with the chooser thread.

I did have some problems keeping the wifi up and stable on the Rpi. I used a little Edimax USB wifi adapter which turned out to be a Realtek chipset. It worked ok but cut out from time to time. I stole a script to ping a nearby machine and, if it doesn't work, up/down the wifi interface which I then ran in a cronjob which seemed to do the trick:

#!/bin/bash

wlan='wlan0'
pingip='10.0.0.13'

# Perform the network check and reset if necessary
/bin/ping -c 2 -I $wlan $pingip > /dev/null 2> /dev/null
if [ $? -ge 1 ] ; then
    /usr/bin/logger -p daemon.info "Network is DOWN.  Perform a reset."
    echo "Network is DOWN.  Perform a reset."
    /sbin/ifdown $wlan
    sleep 5
    /sbin/ifup --force $wlan
    exit 1
else
    exit 0
fi

Finally, I found a thread about how to turn the monitor on/off with power management commands on the HDMI port and added a cronjob to power off the monitor when no one was around:

#!/bin/bash -e

# Script to enable and disable the HDMI signal of the Raspberry PI
# Inspiration: http://www.raspberrypi.org/forums/viewtopic.php?t=16472&p=176258

CMD="$1"

function on {
    /opt/vc/bin/tvservice --preferred

    # Hack to enable virtual terminal nr 7 again:
    chvt 6
    chvt 7
}

function off {
    /opt/vc/bin/tvservice --off
}

function must_be_root {
    if [ $USER != root ]; then
        echo "ERROR: Script must be executed as the root user"
        exit 1
    fi
}

function main {
    must_be_root
    if [ "$CMD" == "on" ]; then
        on
    elif [ "$CMD" == "off" ]; then
        off
    else
        echo "Usage: $0 "
        exit 1
    fi
    exit 0
}

main

Acknowledgements

Thank you to Toby Pitman for posting this really cool article (and javascript / css / image) explaining how to make a running analog clock webpage. See: http://css-tricks.com/css3-clock

Thank you to Guy Carpenter for putting his gdata Oauth module on github. I stole and and modified it a bit.

I understand the motivation is in keeping user data secure but I do wish that Google had not made the Oauth model for interacting with their APIs so cumbersome. I'd rather hardcode an app-specific password with limited capabilities, thank you. To do what I've done with fetching photos, Google docs, etc... you will need to set up a project on the Google developer console and configure it to request read access to your calendar, docs, photos, etc... basically anything it needs to show on the kiosk. When you fire up the kiosk python script for the first time it will give you a URL to type into your web browser and permit access to your data. If all goes well, you won't have to do it again.

Thanks also to everyone who has taken the time to write up guides for configuring the rpi. It may be old hat for you linux people but I'm a FreeBSD guy which makes figuring out simple things on the pi sometimes more difficult. Especially "pjc" on this thread from whom I stole the script to fix my flaky wifi and "simlun" on this thread.

All of my kiosk code (minus the secret API keys) is available on my local git repository. Hopefully helpful, no warranties, no copyright, use as your own risk. And let me know if you end up using the python code for anything or find any bugs.