§ RaspberryPi Swiss army dashboard, or just a clock

There are so many things you can do with your RaspberryPi (RPi) - one of the simplest and most straightforward ones is to turn it to a clock and calendar display. The interesting thing you can do here is that you can achieve it in a way that is really easily extensible and adaptable to your own particular needs.

What I want to share with you here is a port of a ‘system’ I did more than half a year ago on the remains of one of my laptops. What you get by following the instructions will look more or less like this:

An RPi clockbox

I know - a background picture, clock and date display. Trivial, indeed.

The point is that the picture gets updated as often as you like and is SFW, and the clock and date is the easiest thing you can put there. In fact it’s a web browser showing you a locally-served webpage, powered by some very trivial JavaScript. You can put anything you want there, including a dashboard or a countdown till your taking over the world.

Even though this post is focused on the clock-with-a-picture system I’ll write more about my hardware setup as this may probably be useful to the newcomers. I’ll also write about some of additional ideas for the future on how you can extend it even more.

§ The hardware

For the setup you see in the pictures you’ll need at least:

§ Sidenote 1: USB hubs and power

I would argue strongly that a powered USB hub is a must for the RPi if you want to do more, especially for experimenting. With a powered hub you can plug in not only whatever you want - you can remove one adapter and power the RPi from the hub, and if you get a hub like mine you will even get a nice power on/off button for free (no more plugging/unplugging adapters, yeah).

To make the ‘loop’ you’ll need a normal USB plug to Mini USB plug cable. I use one that I got with my Nokia N900, but you should be able to find one, perhaps on DX. Plus you’ll need to mask the power pins on the cable that connects the powered hub to the RPi - that is the cable you’ll normally plug in into your laptop/desktop to use the hub as per manufacturer instructions. There is no need to mask the data pins on the cable that will go between a hub port and power port of RPi, as RPi doesn’t even have these pins connected there.

The method I use for masking the pins is to cut out a U-shape from a piece of paper/plastic and put it on the pins in the USB plug, then plug it into one of RPi’s USB ports. This is an easy way where you don’t permanently alter anything. I did some photos to help you see what I mean.

First start by selecting some good material. I use some sticky pieces of plastic meant to be used as bookmarks. Select material

Then you need to cut it - the piece should fit inside the USB plug, between the outer metal shield and the plastic piece with four pins. You should also cut out the middle to expose the data pins. It’s very difficult to capture with a camera, but when you put it in the U should cover the pins on the sides (the power pins), but leave the pins in the middle visible (the data pins). Cut to match/fit in

Finally you should get rid of the rest of the material as it will make inserting it only more difficult. I actually cat the rest while I try to keep the piece firmly inside the USB plug - that way I ensure I cut just the right amount. Finished mask

One last note about powered (also called ‘active’) USB hubs: if you want to be able to connect something that really needs power, like a mechanical external USB harddrive, you have to pay attention to the power rating of the hub. It is very easy to buy a hub with whatever number or configuration of ports you want, but finding a hub which can provide a lot of juice is not. What I found to be a good ‘brand’ is LogiLink - I found at least three different configurations of hubs, all having a 5V at 3.5A power supplies - the amperage is very important. At 17.5W the hub was enough to power my WD My Passport external drive (the drive itself doesn’t use any external power supply), RPi, a WiFi-card and a keyboard at the same time.

A picture I found on the Internets, just to help you visually: A LogiLink hub

§ Sidenote 2: Display connection

RPi has two outputs - HDMI and composite. The display I’ve got and use here was marketed as a ‘rear parking-camera’ display, and in fact it’s a very simple 5” LCD with a composite video input (in fact two inputs). All you need to connect such a display to your RPi is any Cinch/RCA cable, or in fact any coaxial cable that will fit will do (it’s just two pin - my test version was connected with a paperclip as I didn’t have any cables around). In fact right now I’m using some audio extension cables for the job.

The display you buy may, or may not as in my case, come with a power adapter - if not then read the description of the display to find the power rating needed, but if it’s marketed as anything meant to be used in a car then it will most probably run on anything that’s around 12V. Just make sure to also check the size of the DC socket/plug to buy an adapter that will fit outright. DX has an abundance of power adapters/supplies.

§ The software

I’m guessing if you have an RPi you’re already running some Linux distro on it. I personally prefer ArchLinux on everything that is not a server, but I will not try to convert you here. If you’re interested though I suggest you check the ArchLinux ARM website - they have an image for the RPi (which, just as Raspbian, is built with hardfp turned on). The rest of this section will be presented in a way that should make it usable on other distros - but you need to know how to install software on your distro and where to look for installed software (i.e. you’ll have to think).

The system depends on the following software (you may have some already installed):

§ Xorg and startup setup

This may be considered a somewhat ‘hacky’ way to do it - but it’s simple and doesn’t interfere with rest of the system (essentially everything is done from your user account). If you dislike that you can always write systemd units (if your distro has systemd, that is). As we go through the scripts and pieces remember to look out for paths and adjust properly.

This should go to your crontab (crontab -e):

@reboot     /usr/bin/xinit -- -nocursor 2>&1 >> /home/drbig/logs/xinit.log
@reboot     /usr/sbin/darkhttpd /home/drbig/www --daemon 2>&1 >/dev/null
@reboot     /home/drbig/saved.rb 2>&1 >> /home/drbig/logs/saved.log &
*/3 * * * *   /home/drbig/getpicture.rb
*/3 * * * *   /usr/bin/xset s reset

We obviously start Xorg, the HTTP daemon and the saving script here. We also say that we want a new picture every 3 minutes, and that we want to reset the screensaver every 3 minutes. The xset s reset bit is the easiest fully reliable way I figured out to keep the display always on. You’ll see in xinitrc that I tried to do it in more civilized way also, however it doesn’t work without this periodic reset.

And then the contents of .xinitrc:

setterm -blank 0 -powerdown 0
xset s off
xset dpms force on
xset s reset
exec uzbl-core http://127.0.0.1:8080/

Here the first four lines try to make the display always on, and the last line fires up uzbl-core.

§ Our index.html and the screen size

Here we do a JavaScript clock and calendar:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <head>
    <meta http-equiv="refresh" content="60">
    <title>Picture Frame</title>
    <style type="text/css">
      body {
        color: white;
        background-color: black;
        font: 64pt Verdana, sans-serif;
        margin: 0px;
        padding: 0px;
      }
      div#frame {
        background-image: url('current.jpg');
        background-repeat: no-repeat;
        background-position: center;
        text-align: center;
        display: block;
        width: 720px;
        height: 576px;
        vertical-align: middle;
        padding: 0px;
        margin: 0px;
        color: white;
        text-shadow: black 0.1em 0.1em 0.2em;
        -webkit-text-stroke: 2px black;
        line-height: 1;
      }
      div#clock {
        font-family: Ubuntu, sans-serif;
        font-weight: bold;
        font-size: 220px;
      }
      div#date {
        font-family: Ubuntu, sans-serif;
        font-size: 64px;
        font-weight: bold;
      }
    </style>
    <script type="text/javascript">
      <!--
function init()
{
  timeDisplay = document.createTextNode("");
  dateDisplay = document.createTextNode("");
  document.getElementById("clock").appendChild(timeDisplay);
  document.getElementById("date").appendChild(dateDisplay);
}

function updateClock()
{
  var days = ['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday'];
  var currentTime = new Date();

  var currentHours = currentTime.getHours();
  var currentMinutes = currentTime.getMinutes();
  var currentSeconds = currentTime.getSeconds();

  // Pad the minutes and seconds with leading zeros, if required
  currentHours = (currentHours < 10 ? "0" : "") + currentHours;
  currentMinutes = (currentMinutes < 10 ? "0" : "") + currentMinutes;
  currentSeconds = (currentSeconds < 10 ? "0" : "") + currentSeconds;

  // Compose the string for display
  var currentTimeString = currentHours + ":" + currentMinutes; // + ":" + currentSeconds;

  // Update the time display
  document.getElementById("clock").innerHTML = currentTimeString;
  document.getElementById("date").innerHTML = currentTime.toLocaleDateString()
    + "</br>" + days[currentTime.getDay()];
}

// -->
</script>
</head>
<body onload="updateClock(); setInterval('updateClock()', 1000)">
  <div id="frame">
    <div id="clock">&nbsp;</div>
    <div id="date">&nbsp;</div>
  </div>
</body>
</html>

What may be important here is the pixel size - I adjusted it to fully fill my display. That resolution will also be needed for the script that gets the picture from the Internet and scales it down appropriately. To get the resolution you need to have Xorg running and set DISPLAY properly (most likely to :0.0). You can then do the following:

[drbig@rpi ~]$ xrandr
xrandr: Failed to get size of gamma for output default
Screen 0: minimum 720 x 576, current 720 x 576, maximum 720 x 576
default connected 720x576+0+0 0mm x 0mm
   720x576         0.0*

The 720x576 is in fact the full PAL resolution without overscan. To disable overscan (and set PAL/NTSC/Secam) you’ll need to edit the config.txt on the /boot partition of your RPi - refer here and/or see the sidenote 4.

§ Getpicture.rb - get us some photos

The following script gets a picture from Flickr, resizes it and puts it where our index.html is looking for. This is actually the updated version - the query string now includes the cluster parameter which I found out, empirically, to be very important to get only good quality photos. If you just go by tag you’re bound to get stuff that’s crappy and totally unrelated to the tag. It seems that for some people any photo taken outdoors is ‘landscape’ - even if the most prominent feature in the photo are boobs of author’s girlfriend/wife/sister.

#!/usr/bin/env ruby
#
# 01.07.2012

%w{ open-uri rubygems json RMagick }.each{|g| require g}

QUERY = 'tags=landscape&clusters=sky-clouds-mountains'

begin
  open("http://api.flickr.com/services/feeds/photos_public.gne?#{QUERY}&format=json") do |d|
    feed = JSON.parse(d.read.match(/.*?(\{.*\})/m)[1])
    x = rand(feed['items'].length)
    link = feed['items'][x]['media']['m'].gsub('_m.', '_b.')
    img = Magick::ImageList.new(link).first
    img = img.resize_to_fill(720, 576)
    img.write('/home/drbig/www/current.jpg')
    File.open('www/current.json', 'w'){|f| f.write(feed['items'][x].to_json)}
    File.open('www/current.htm', 'w') do |f|
      f.write('<html><body>')
      feed['items'][x].each{|k,v| f.write("<b>#{k}:</b> #{v}<br/>")}
      f.write('</body></html')
    end
  end
rescue Exception => e
  # do nothing now
end

You may also notice that we save a bunch more info about the picture - this will be used by the next and last script. Remember to adjust paths and the resize resolution if needed.

§ Saved.rb - in case we like a photo

I had this system running on the other hardware for about half a year, and soon I found out that some of the photos are really nice and would make a great wallpaper - so I decided to add a very simple service to easily save a photo along with some additional information (like a link to the original).

#!/usr/bin/env ruby
#

%w{ fileutils rubygems sinatra }.each{|g| require g}

SRC = '/home/drbig/www'
DST = '/home/drbig/www/saved'
MASK = 'current*'

get '/save' do
  resp = String.new
  stamp = Time.now.strftime("%Y-%m-%d_%H%M%S")
  Dir.chdir(SRC)
  Dir.glob(MASK) do |p|
    _, ext = p.split('.')
    a = File.join(SRC, p)
    b = File.join(DST, stamp + '.' + ext)
    FileUtils.cp(a, b)
    resp += "cp #{a} #{b}\n"
    if params.has_key? 'del'
      FileUtils.rm(a)
      resp += "rm #{a}\n"
    end
  end
  content_type 'text/plain'
  resp
end

To save a photo you just point any browser/wget/curl to http://<your rpi ip>:4567/save, and you find all the saved stuff at http://<your rpi ip>:8080/saved.

§ Sidenote 3: Security

Please remember that nothing here tries to be secure - the system is intended to be used only by the owner and only on a trusted LAN. Anyone who knows the IP and port numbers can view everything and save photos. If this bothers you - feel free to add password protection, SSL certificates and whatnot. You have been warned.

§ Sidenote 4: My config.txt and cmdline.txt

For your curiosity I’m including this two essential config files here.

disable_overscan=1
sdtv_mode=2
gpu_mem_256=160
gpu_mem_512=316
cma_lwm=16
cma_hwm=32
init_emmc_clock=128000000
coherent_pool=2M cma=2M smsc95xx.turbo_mode=N dwc_otg.lpm_enable=0 console=tty1 root=/dev/mmcblk0p2
rootfstype=ext4 elevator=noop ipv6.disable=1 rootwait

§ The results

The results in pictures.

Saved photos listing

Saved photo data

Dark take

Wide take

§ The future

I have a number of ideas related to this, let me call that a ‘content presentation framework’:

RaspberryPi is very cool for doing all sorts of cool stuff. You should experiment too.

comments powered by Disqus
Last update: 2013-02-09. » LINK » TXT » ATOM. Go to the top. Licence CC-BY-NC-SA.
If you find this interesting go ahead and leave a comment or add a star.
Any and all feedback is appreciated!