Friday, January 21, 2011

XBMC and home automation

XBMC short for Xbox Media Center has been the premier open source home entertainment system for a while now. It was originally released to be run on original Microsoft Xboxes that had been soft moded. That seems like so long ago. These days the XBMC dev team are still hard at work, and while recently support for xbmc on the original xbox has stopped (the original xbox really wasn't designed for 1080p quailty video) many other platforms are now supported: 1st gen apple tv, linux, OS X, and windows are the big ones. The team even has a comercial version of their software called BOXEE. And while XBMC can play almost any media you can throw at it, AND has a host of community supported plugins available, the coolest feature is its API. With this we can remotely control a running instance of XBMC from some other device. There are remote control programs for the sony psp, iphone/ipod touch and droid platforms. But we can write our own too.

The first thing we will need to do is get a copy of xbmc up and running. There are plenty of guides for various platforms. I currently run XBMC on an acer revo hooked up to the down stairs TV, on an apple-TV in the bed room, and on the linux server in the office. for simplicities sake, to install xbmc on ubuntu its as easy as

sudo apt-get install xbmc

but for our purposes you'll also want to

sudo apt-get install xbmc-send

xbmc-send is a stand alone command line program that can send commands to a running instance of XBMC.

NOTE: before trying this you will first need to allow you XBMC to recieve remote commands.
System->Network->Services->Allow control of xbmc via HTTP and or UPNP

you also want to enable the option that says "Allow program on other systems to control XBMC"

after you get XBMC installed and configured to your liking grab a terminal and try something like

xbmc-send --host="your host by name or ip" --action="Notification(title, my message)"

and you should see a little notification box pop up in the lower right hand corner(depending on which skin you are using).


there are other ways of gettings these sorts of thing to happen. If you are using a recent version of xbmc you can check out the JSON remote control protocoll. If you are you using versions of xbmc old enough to run on the original xboc you can check out the deperciated http api, for a list of all built in functions take a look at

http://wiki.xbmc.org/?title=List_of_Built_In_Functions

the commands on this list are what we will use with the xbmc-send program.


so where does x10 fit in with all this? Last post I talked up one of the new features of the python driver, that it can recieve commands from other remotes AND sensors

like the one here, for example
http://www.thehomeautomationstore.com/ms14a-w.html
(they are much cheaper on ebay!!!!)

So, lets say you purchased one of these guys and programmed it to be a13

assuming you are redirecting out put from your x10 python driver like we talked about last post you might do something like this...

tail -f liveHouse.log | while read a ;
do [[ if "$a" == +a13* ]] ; then
#put anything you want to happen as a result of tripping the motion sensor, like sending an IM or email or desktop/xbmc notification
xbmc-send --host='my xbmc IP or HostName' --action="Notification(Activity, Motion detected)" ;
fi ;
done

then make some motion in front of your sensor (or you could just turn on a13 from an x10 remote, essentially thats all the sensor does)

and you should see your little message box on the XBMC screen. AWESOME!

you of course don't need XBMC to enjoy this kind of early warning. Mac users have Growl (though I've never played with the API for growl) ubuntu users have a built in notification system called notify-osd. you can access the ubuntu system directly from the command line by doing

sudo apt-get install libnotify-bin

after which you can run a command like

notify-send 'TITLE", "My message"



Wednesday, January 5, 2011

Home Automation Part 2 (Now With Python)

Wow. It has been a while. It can be hard to find time as a student to work on personal projects let alone share them with the world, but I'm happy to report a few improvments on the state of cheap and easy home automation for the DIY minded.

Firstly, incase you didn't know...
Kernel modules are out. User-space python scripts are in.


Mike Lemay, the gentalman who provides the linux kernel module I wrote about last time has released an upgrade as a python module. This is great news! No more recompiling evrytime Canolical releases a kernel update, and no more (ok, well less) worrying about permissions.

And one of the best parts is that we can now use our cm19a to listen for commands from other wireless compliant x10 remotes and sensors!

Things are invoked a little differently now, but with a little bash magic we can massage data flow to work with any preexisting scripts you might have in place from the kernel module version of the driver. IE we'll make our own pseudo device in dev called cm19a0

start out by grabbing the latest python driver from Lemay's site

Following the linux tutorial on Lemay's site
and come back when you get to step 9

...

for step 9 we will be making some named pipes - our pseudo device, and we're going to put them in /dev

so in a terminal with root permissions type
mkfifo /dev/cm19a0
mkfifo /dev/cm19a1

cm19a0 will represent the commands going out from the transceiver
cm19a1 will represent the commands coming in from other x10 remotes and sensors

we're ready to fire up the driver.

as an aside you may have to adjust the permissions of the transceiver device on your system. step 10 on Mikes site will illustrate how to do this manually, but you will have to retype the commands he talks about every time your machine reboots. As an alternative you may want to set up a udev rule. Being able to set up udev rules is an invaluable skill for sysadmins and in general are very handy for keeping track of devices that aren't necessarily "plug n play"

There's plenty of info around the web on the particulars of writing udev rules, but for the bare minimum to get you going here's what you want to do.

gedit /etc/udev/rules.d/95-perso.rules

put this line in the file somewhere

ATTR{manufacturer}=="X10 Wireless Technology Inc", ATTR{product}=="USB Transceiver", GROUP="users", MODE="0666"

save and close

sudo service udev restart

to apply the rules.

95-perso.rules is the rules file that I use. the 95 at the beginning describes the order that udev will apple these rules. for devices like the usb transceiver I find it is best to wait until the system has sorted everything else out, so we make it the last thing the kernel deals with.


Now, in its basic syntax, we invoke the driver by running ( from the directory where the driver is located)

python pycm19a.py < /dev/cm19a0 > /dev/cm19a1

if you are having problems at this point, try going back and following steps 1-9 (or further for your satisfaction).

you should be able to enter a command in a new terminal in the usual fashion

echo +a1 > /dev/cm19a0

looks familiar, right?

now (in a different terminal) type
tail -f /dev/cm19a1

then use one of your remotes or sensors and turn off or on a device

if I turn off the lamp on a1 with mine, I see
...
+a1
...

cool?

and thats all well and good, but for those who want to take things a step farther you might try something like this...


python pycm19a.py < /dev/cm19a0 > /dev/cm19a1 2>>/dev/cm19a1 && cat /dev/cm19a1 | while read a ; do echo "$a : `date`" ; done > cm19a.log &

what does this do?
you may have noticed that commands sent via command line to the driver do not show up with commands from other remotes. so the first thing we want to do is include those commands
(thats the 2>>/dev/cm19a1) we then redirect that entire output again to a loop that appends the date and time each command was recieved or sent into a file called cm19a.log. Pretty neat huh? now you have a running log for your own edification of when any appliance has been turned off or on via any controller.

Ok. Last little tidbit for this post. once you have this command and you throw it in to a bash script to run at reboot. For me I prefer a userspace service.

this little bash script is based on a skeleton that I reuse over and over again for things I want to run as services but only under my normal user space.

copy the following code in to a file called liveHouse. chmod u+x liveHouse then you should be able to ./liveHouse start to start the service ./liveHouse stop to stop it and ./liveHouse to check to see if its running (if its running it will return its process number)



#!/bin/bash

#emulate the stop start action of /etc/init.d with out all the service overhead...

driver='/absolute/path/to/your/driver';
inFile='/dev/cm19a0';
outFile='/dev/cm19a1';
logFile='/absolute/path/to/where/you/want/to/log'
#if no argument is given, return the process number
if [[ $1 == '' ]] ; then
iam=$(ps ax | grep 'pycm19a.py' | grep -v 'grep' | awk '{print $1}');
if [[ $iam == '' ]] ; then
exit 0;
else
echo "$iam";
fi;
elif [[ $1 == 'start' ]] ; then
running=`ps aux | grep "$SHELL $0 start" | grep -v grep | wc -l `
devCheck=`ls -l $inFile $outFile | grep $USER | wc -l`;
if [[ $devCheck == 2 && $running == 2 ]] ; then
#if its not already running start it up
echo "starting liveHouse";
exec python "$driver" < "$inFile" > $outFile 2>>$outFile & cat $outFile | while read a ; do echo "$a : `date`" ; done > $logFile & echo > $inFile &
else
echo "liveHouse is already running or there was a problem with $inFile or $outFile";
exit 0;
fi


elif [[ $1 == 'stop' ]] ; then
echo "Stopping liveHouse";
killMe=$(ps ax | grep 'pycm19a.py' | grep -v 'grep' | awk '{print $1}') ;
kill -9 "$killMe";
fi;



NOTE YOU MAY WANT TO DOUBLE CHECK THE QUOTES ON THIS. THEY MAY NOT HAVE BEEN ENCODED CORRECTLY WHEN I PASTED FROM MY TERMINAL AND IT MAY CAUSE SYNTAX ERRORS IF YOU TRY TO RUN THIS


NEXT POST: throwing XBMC in to the mix!!!