Start XBMC from remote

The Android XBMC Remote app has a “Power on” button. This button sends a wake-on-lan (WOL) packet to the XBMC server, so that it can wake up. However, my XBMC server runs all kinds of server stuff, so I don’t want to let it sleep. Still, XBMC uses more than 10% CPU power even when it’s in idle, so I don’t want it running all the time either.

I’ve written a small Python script that executes a command every time it receives a WOL packet. This is then used to start XBMC. Here is the Python source code:


import socket
import struct
import os
import sys
import subprocess

if 'SUDO_UID' not in os.environ:
    raise SystemExit('Run with sudo')

# Try to parse these before spawning another process
uid = int(os.environ['SUDO_UID'])
gid = int(os.environ['SUDO_GID'])

# Let the user know what will happen
cmdargs = sys.argv[1:]
if cmdargs:
    print('Going to call:')
    print('    %s' % ' '.join(cmdargs))
    print('As UID=%i / GID=%i' % (uid, gid))

# Open the port now we still have root rights.
port_nr = socket.getservbyname('discard', 'udp')
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind(('', port_nr))

# Drop root rights and become mortal again.

    while True:
        packet = sock.recv(102)

        padding = struct.unpack('BBBBBB', packet[0:6])
        if padding != 6 * (255, ):
            hexpad = ':'.join(hex(b) for b in padding)
            print('Invalid WOL packet received: %s' % hexpad)

        address = struct.unpack('BBBBBB', packet[6:12])
        mac = ':'.join(hex(a) for a in address)

        if cmdargs:
            print('Starting %s' % (cmdargs, ))
            print('Received WOL from %s' % addr)
except KeyboardInterrupt:

It is a very minimalistic script, that doesn’t even check the MAC address in the WOL packet. If you need it, it’s simple enough to add it in. You need to run it with:

sudo python xbmc

Or with any other command or shell script you want to execute when you receive a Wake-On-Lan magic packet. It needs to be run with sudo because the WOL port is 9, which is lower than 1024 and thus needs root rights to listen on. The command to be executed will be running with the rights of the user running sudo, and not as root:

$ sudo python id
Going to call:
As UID=1000 / GID=1000
Starting ['id']
uid=1000(sybren) gid=1000(sybren) groups=1000(sybren),0(root)</pre>

The script only works on Linux, but I’m sure it can be modified to work on other systems too. That’s up to you, though ;-)

dr. Sybren A. Stüvel
dr. Sybren A. Stüvel
Open Source software developer, photographer, drummer, and electronics tinkerer