rockym93 dot net

archive · tags · feed

Starting XBMC when a Raspberry Pi's HDMI is connected

30 October 201404:54PMcode

So I have a Raspberry Pi hooked up to my TV, and despite dropping more on power supplies and USB hubs than I did on the actual computer (actually not hard considering that it was a gift, but whatever) - I've still been having freezing issues. I eventually figured out that the problem was xbmc, the media player frontend. Essentially, it's a pretty chunky bit of software which was putting the CPU under a constant load of between 60 and 80 percent, which was probably doing bad things to it both temperature and power-draw wise. Anyway, since disabling the xbmc service at boot, it's been up for two days and counting.

This leaves me with a bit of a conundrum though, because I do actually want xbmc to run so that I can watch movies and stuff. The neatest solution is to start xbmc when the TV powers on, and because HDMI is a nifty next-gen standard, it actually signals that kind of thing. More importantly, because the Raspberry Pi is a wonderful bit of hardware with undocumented features coming out of its ears, it actually has very good support for reading these signals. It even comes with a little bit of software to work with them, called tvservice.

So, it's a pretty simple matter to write a bit of glue to watch the output of tvservice, and startup xbmc when the TV powers on. The result is something like this:

#!/usr/bin/python

import subprocess
tvservice = subprocess.Popen(['/opt/vc/bin/tvservice','-M'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
xbmc = 0

while True:
    status = tvservice.stdout.readline()
#   print(status)
    if tvservice.poll() is not None:
        tvservice = subprocess.Popen(['/opt/vc/bin/tvservice','-M'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
    if status == b'[I] HDMI is attached\n':
        xbmc = subprocess.Popen(['/usr/lib/xbmc/xbmc.bin','-l','/run/lirc/lircd'])
        print('HDMI connected. Starting XBMC...', end=" ")
        print('done.')
    if status == b'[I] HDMI cable is unplugged\n' and type(xbmc) == subprocess.Popen:
        print('HDMI disconnected. Stopping XBMC...', end=" ")
        xbmc.terminate()
        print('done.')

A couple of notes. First, it assumes that you'll start the daemon with the TV off, although it shouldn't freak out if you start with it on - it should hopefully detect that and not try to kill something that isn't running. It also should detect if tvservice dies and restart it, though I haven't actually tested that yet.

It's been tested with a grand total of one TV, so the signals that tvservice is generating might need to be modified for different brands.

Also, xbmc apparently usually starts from a useless little shell script which does some logging stuff and some very rudimentary restarting stuff but then just forks off xbmc.bin. This was causing Python to lose track of which process was actually xbmc, so I bypassed it and started xbmc.bin directly. This doesn't seem to have any adverse effects, but if you do need logging you're on your own.

It should be pretty stable, but just in case I recommend running it at startup and with some kind of service management. If you're using systemd, you can use this unit file here, modified from the xbmc one. This also means that you can see when your TV is turned on using the system journal, which is neat, if not especially useful.

[Unit]
Description = Watches for HDMI connection and starts xbmc.
After = remote-fs.target

[Service]
User = xbmc
Group = xbmc
Type = simple
ExecStart = /usr/bin/python /var/lib/xbmc/watchtv.py
Restart = on-failure

[Install]
WantedBy = multi-user.target

On a personal note, this is the first time I've ever written anything which has processes talking to each other, and I'm quite chuffed with how well it works. It's also the first time I've written anything in Python 3 - totally by accident, actually, it's just the version that's included in the version of Linux I use on the Pi. Which I guess is just proof that I should suck it up and convert all my stuff, because apparently the differences aren't all that intimidating. Who knew?

(I went rock climbing today for the first time in a few years, and my forearms hurt so much that typing is a wee bit painful. Sorry if this is a bit terse as a result.)

read the comments

< Outdoors I've been wearing the same shirt since Tuesday... >