Sunday, July 20, 2008

CM15A X10 Home Automation with Linux

A lot of the information and source code is slightly out of date on the topic of X10 on Linux. Certain changes in the latest kernels prevent the code from compiling out of the box. The machine I did this on is Kubuntu with the 2.6.24-16 kernel. Neil Cherry did a lot of good work on this subject. His page is full of a lot of detail that you probably think you don't need. Read through it anyway if you are actually trying to get the CM15A working in Linux.

First you will need the driver and the daemon. Download and unpack both. To get either to compile you need to change a few lines and comment out some others. You have to do the same thing in both packages. Find the line that reads, "#include linux/config.h" and change it to "#include linux/autoconf.h" Then comment out any line that starts with "MODULE_PARM". Next, in the cm15a-driver package in the cm15a.c file find the usb_class_driver struct and comment out the line that begins with "mode:" and do the same for the line in the next struct that begins with "owner:". Save everything and then run ./configure;make;make install.

Once everything is installed you'll need to run these commands:

mkdir /dev/usb
mknod --mode=a=rw /dev/usb/iplc0 c 180 240

then go into ./iplc/driver/linux-2.6/ and run:

insmod iplc.ko

then into cm15a-driver/driver/linux-2.6/ and run:

insmod cm15a.ko

That should be it. Here is a simple perl script that will turn on or off A1 depending on which line is uncommented.

#!/usr/bin/perl
use Fcntl;

sysopen( cm15a, "/dev/usb/iplc0", O_RDWR |O_NOCTTY | O_NONBLOCK )
|| die "Cannot find $!";
syswrite cm15a, pack( "CC", 4, 0x66), 2;
sleep 1;

# Turns on
syswrite cm15a, pack( "CC", 6, 0x62 ), 2;

# Turns off
#syswrite cm15a, pack( "CC", 6, 0x63 ), 2;
close( CM15A );

Now for some explanation of the script. The sysopen line creates a pointer of "cm15a" to the device file we made earlier. This gives perl an easy name to send future data. The first syswrite line is what tells the cm15a what device we are sending a signal to. In this case it is A1. We have to wait about 1 second because an ACK packet is sent back. The next syswrite sends the 'turn on' signal and the commented out syswrite sends 'turn off'. The last line closes the pointer for a graceful exit. The '4' part of the syswrite is what tells the unit that you are sending a Unit address (A1, C3, etc). The '6' means you are sending a Function code (on, off, dim, etc). Below is a cheet sheet for the A codes. If you look on Neil Cherry's page you'll see his chart of whole break down of the codes. The codes are not in binary order and seemed to have been chosen randomly. I made this just to help myself out and not have to decifer the right code everytime I'm writing a script. For the other house codes like B and up, just change the 6 to whatever Neil's chart says it should be.

A1 0x66
A2 0x6E
A3 0x62
A4 0x6A
A5 0x61
A6 0x69
A7 0x65
A8 0x6D
A9 0x67
A10 0x6F
A11 0x63
A12 0x6B
A13 0x60
A14 0x68
A15 0x64
A16 0x6C

I hope this helps!