For the wallscreens within the operations department, we currently use Raspberry Pies and provision those using Ansible. We found that the USB sockets on a typical LCD TV do not provide enough power for a Raspberry Pi model 3, so we went for the cheaper – although a little less powerful – model 2. Since we have cabled network in place from before, this does not really pose any limitations.

The Inventory

Raspberry Pi 2 Model B

Chassis For Raspberry Pi 2 Model B

SanDisk Ultra MicroSDHC 8GB (SDHC adapter included)

HDMI Male/HDMI Male cable, 50cm

USB Type A Male/Micro-USB Type B Male cable, 50cm

Cost per unit: NOK 590 (i.e. ~$70/€65)

The Setup

The initial setup uses Raspbian Jessie Lite as the base image. On top of this we install a couple of dependencies to make it run Chromium (the open source/unbranded variant of Google Chrome) in kiosk mode. This gives us a root-filesystem of just under 1.5Gb and operational RAM in the 500Mb range, well within the limits of the 8Gb SD card we got and the 1Gb RAM provided by the board.

The Installation

Download the Raspbian SD image and follow Installing Operating System Images to create a (bootable) SD card from the image. Boot your Raspberry Pi from the created SD card. Make sure it is connected to a network with DHCP enabled. Make a note of the IP address from your Raspberry Pi (it is displayed on-screen and available through bonjour as raspberrypi.local ) and add it to the wallscreens section in your Ansible hosts configuration. [wallscreens] my_wallscreen ansible_host=<ip of raspberry> ansible_user=pi ansible_become=true Copy your (pre-generated) ssh public-key to the system, to allow for key-based authentication. Run the provided playbook to configure it for running Chromium in kiosk mode as its main application. $ ansible-playbook wallscreen.yaml

The Highlights

The ansible playbook contains configuration for setting up the raspberry in its entierty. The following snippets shows some of the more interesting parts of the setup.

The DHCP client is configured to have it set the hostname from DHCP.

/etc/dhcpcd.conf

env force_hostname = YES

The profile allows for booting the system without actually starting Chromium by removing ~pi/.autostart :

[ -f ~/.autostart -a " $( tty ) " == "/dev/tty1" ] && { XAUTHORITY = /tmp/.xauth startx }

~pi/.xinitrc turns off any form of screensaving, starts unclutter to hide the mouse-pointer on inactivity and starts chromium in kiosk-mode with its resolution set to support 1080p:

xset -dpms xset s off xset s noblank unclutter -idle 1 -root & exec chromium-browser --window-size = 1920,1080 --no-first-run --noerrdialogs --kiosk --incognito https://wallscreen.i.bitbit.net/ $( hostname --short )

We serve the content of a wallscreen from an internal webserver. The URI includes the hostname of the system to make it easy to customize the content of each wallscreen.

The system starts up with a regular read-write root filesystem. To prevent filesystem corruption (and to limit the number of writes to the SD card) the root filesystem is mounted read-only during boot in rc.local :

mount -o remount,ro /

A number of directories have tmpfs-backed storage to workaround the read-only property of the main filesystem:

/etc/fstab

tmpfs /tmp tmpfs mode = 1777 0 0 /run/log /var/log none bind 0 0 /tmp /home/pi/.config none bind 0 0

Systemd timers

The screensaver is deactivated on workdays at 07:00 and activated again at 18:00. This is done using systemd-timers. The following snippets configure the timers and the associated services:

/etc/systemd/system/deactivate-screensaver@.service

[ Unit] Description = Stop screensaver [ Service] Type = oneshot User = %I Environment = DISPLAY = :0 Environment = XAUTHORITY = /tmp/.xauth ExecStart = /usr/bin/xset s reset

/etc/systemd/system/deactivate-screensaver.timer

[ Unit] Description = Turn on screen [ Timer] OnCalendar = Mon-Fri 07:00 Unit = deactivate-screensaver@pi.service [ Install] WantedBy = timers.target

/etc/systemd/system/activate-screensaver@.service

[ Unit] Description = Start screensaver [ Service] Type = oneshot User = %I Environment = DISPLAY = :0 Environment = XAUTHORITY = /tmp/.xauth ExecStart = /usr/bin/xset s activate

/etc/systemd/system/activate-screensaver.timer

[ Unit] Description = Turn off screen [ Timer] OnCalendar = Mon-Fri 18:00 Unit = activate-screensaver@pi.service [ Install] WantedBy = timers.target

The Nitty Gritty

The playbook can be used as is. Note that this requires Ansible 2.2 (or later), since this version introduces the systemd module.