Arduino -> X10 Wireless

After a few bonehead mistakes I have the Arduino interfaced to a CM17A "FireCracker".

The CM17A is a "serial" dongle that sends RF signals to X10 receivers which in turn send signals down the house wiring to control lights and appliances. It's relatively cheap (about 10USD on eBay).

After interfacing through a MAX3232 a nice surprise was that I didn't need it. So its just 3 wires from the Arduino to the RTS, DTR, and GND pins on a DB9 plugged into the CM17A.

For some, this might be a good safe way to control Mains. As I write, my whole house is blinking!

/* Arduino Interface to the CM17A Wireless X10 dongle. BroHogan 7/19/08
 * The CM17A gets it power and data using only the RTS, CTS, & Gnd lines.
 * A MAX232 is not req. (0/+5V work OK) If MAX232 IS used reverse all HIGHs & LOWS
 * Signal      RTS DTR        Standby | '1' | Wait | '0' | Wait | '1' | Wait...
 * Reset        0   0         _____________________       _____________________
 * Logical '1'  1   0   RTS _|                     |_____|
 * Logical '0'  0   1         ________       ___________________       ________
 * Standby      1   1   DTR _|        |_____|                   |_____|
 *
 * MINIMUM time for the '1', '0' and 'Wait' states is 0.5ms.
 * At least one signal must be high to keep CM17A powered while transmitting.
 * Each xmit is 40 bits -> "Header" 16 bits,  "Data" 16 bits, "Footer" 8 bits
 * CONNECTION: RTS -> DB9 pin 7.  DTR -> DB9 pin 4. Gnd. -> DB9 pin 7.
 */

#define RTS_pin 2                     // RTS line for C17A - DB9 pin 7
#define DTR_pin 3                     // DTR line for C17A - DB9 pin 4
#define BIT_DELAY 1                    // ms delay between bits (0.5ms min.)
#define ON     0                       // command for ON
#define OFF    1                       // command for OFF
#define BRIGHT 2                       // command for 20% brighten
#define DIM    3                       // command for 20% dim

unsigned int houseCode[16] = {
  0x6000,  // A
  0x7000,  // B
  0x4000,  // C
  0x5000,  // D
  0x8000,  // E
  0x9000,  // F
  0xA000,  // G
  0xB000,  // H
  0xE000,  // I
  0xF000,  // J
  0xC000,  // K
  0xD000,  // L
  0x0000,  // M
  0x1000,  // N
  0x2000,  // O
  0x3000,  // P
};

unsigned int deviceCode[16] = {
  0x0000,  // 1
  0x0010,  // 2
  0x0008,  // 3
  0x0018,  // 4
  0x0040,  // 5
  0x0050,  // 6
  0x0048,  // 7
  0x0058,  // 8
  0x0400,  // 9
  0x0410,  // 10
  0x0408,  // 11
  0x0418,  // 12
  0x0440,  // 13
  0x0450,  // 14
  0x0448,  // 15
  0x0458,  // 16
};

unsigned int cmndCode[] = {
  0x0000,  // ON
  0x0020,  // OFF
  0x0088,  // 20% BRIGHT (0x00A8=5%)
  0x0098,  // 20% DIM    (0x00B8=5%)
};

void setup() {
  pinMode(RTS_pin,OUTPUT);             // onboard LED
  pinMode(DTR_pin,OUTPUT);             // output pin of touch sensor
}

void loop(){   // Sample Commands
  delay(2000);
  xmitCM17A('D',4,OFF);
  xmitCM17A('D',5,ON);
  xmitCM17A('D',5,DIM);
  xmitCM17A('D',5,DIM);
  xmitCM17A('D',5,DIM);
  xmitCM17A('D',5,DIM);
  xmitCM17A('D',5,DIM);
  xmitCM17A('D',5,OFF);
  xmitCM17A('D',4,ON);
} 

void xmitCM17A(char house, byte device, byte cmnd){
  unsigned int dataBuff = 0;
  byte messageBuff[5];

  // Build Message by ORing the parts together. No device if Bright or Dim
  if(cmnd == ON | cmnd == OFF){
    dataBuff = (houseCode[house-'A'] | deviceCode[device-1] | cmndCode[cmnd]);
  }
  else dataBuff = houseCode[house-'A'] | cmndCode[cmnd];

  // Build a string for the whole message . . .
  messageBuff[0] = 0xD5;               // Header byte 0 11010101 = 0xD5 
  messageBuff[1] = 0xAA;               // Header byte 1 10101010 = 0xAA 
  messageBuff[2] = dataBuff >> 8;      // MSB of dataBuff
  messageBuff[3] = dataBuff & 0xFF;    // LSB of dataBuff
  messageBuff[4] = 0xAD;               // Footer byte 10101101 = 0xAD

    // Now send it out to CM17A . . .
  digitalWrite(DTR_pin,LOW);             // reset device - both low is power off
  digitalWrite(RTS_pin,LOW);
  delay(BIT_DELAY);

  digitalWrite(DTR_pin,HIGH);             // standby mode - supply power
  digitalWrite(RTS_pin,HIGH);
  delay(35);                           // need extra time for it to settle

  for (byte i=0;i<5;i++){
    for( byte mask = 0x80; mask; mask >>=1){
      if( mask & messageBuff[i]) digitalWrite(DTR_pin,LOW);  // 1 = RTS HIGH/DTR-LOW
      else digitalWrite(RTS_pin,LOW);                        // 0 = DTR-HIGH/RTS-LOW
      delay(BIT_DELAY);                // delay between bits

      digitalWrite(DTR_pin,HIGH);      // wait state between bits
      digitalWrite(RTS_pin,HIGH);
      delay(BIT_DELAY);
    }  
  }
  delay(1000);                         // wait required before next xmit
}

Enjoy :slight_smile:

Good. As soon as I get my ATmega168 with the Arduino bootloader burned, I am going to work in a project to use TM751 transceiver's daughter board as a universal wireless receiver. I already did it with a PIC12F629.

CM17A and TM751 daughter board with Arduino is the perfect and complete X10 wireless solution.

Nice work! Minor typo, you have GND on the DB9 going to pin 4, I believe you mean 5? Anyway, that works for me!

Note that the Firecracker has both a female and male side. The female side is the one meant to plug in the PC, that's the side I used as the input, and pin 1 is on the upper right, with pin 5 going to the left. Might not be so obvious if you don't have a PC right in front of you!.

This is a better (and cheaper) solution than the older X10 arduino library using the TW523 unit (actually I had the 1132b). I wasn't able to get that working reliably.

Thanks,
Harry

Harry,
Thanks for pointing out that typo. If I put it on the Playground, I'll correct it there. (Enjoyed your blog, BTW)
I should also include this reference - ftp://ftp.x10.com/pub/manuals/cm17a_protocol.txt.

(There are also a lot of "PC" CM17A applications out there, but the only one I found for a micro which was in ASM and used a MAX232.)

jcgalvezv, I'm curious, so you remove the daughter board from the TM751 receiver and use the digital outputs on it?

Thank you both for your feedback.

jcgalvezv, I'm curious, so you remove the daughter board from the TM751 receiver and use the digital outputs on it?

Correct. I also removed the 7805 regulator since I didn't need it.

jcgalvezv, this comment re the TM751 is intriguing. If I understand correctly, you want to open a TM751, and use the daughterboard along with the Firecracker as an RF link. You're not really intending to use X-10 at all?

I can see why this could work, but why is it desirable? Why not use one of the RX433/TX434 family, or Zigbee or Bluetooth? It's not like X10 component reliability or quality anything to write home about, and I don't think it would be cheaper than '433 family and it certainly wouldn't approach the reliability of the latter, I would think.

I must be missing some advantage - I have several TM751s so if there's a cool use for them I'm overlooking, I'm interested!

-harry

Hi Harry:

jcgalvezv, this comment re the TM751 is intriguing. If I understand correctly, you want to open a TM751, and use the daughterboard along with the Firecracker as an RF link. You're not really intending to use X-10 at all?

No, I want to have a completely wireless X10 system. Firecracker to send commands and TM751 daughter board to receive commands sent from all the motion sensors and remote controls directly to the microcontroller. TM751 daughter board has the capability to receive commands from all the house codes.

Juan C.

Ok, that makes sense, and I concur that is a good way to go.

I worked on something similar some years back:

http://hawiki.pbwiki.com/X10RfConfiguration

100% wireless X10 worked a lot better for, I used this configuration for 2+ years.

-harry

Harry:

I am looking for a better DIY antena for my TM751 daughter board. Do you know about any good one?

Juan C.

This is now on the Playground . . .
http://www.arduino.cc/playground/X10/CM17A

I'm using this in an audio project of mine:

Imgur

a digital volume control for hifi/stereo using a lcd display, IR receiver, rotary encoder, PGA style volume control chip and some input/output device select relays.

the x10/firecracker thing was unexpected but now, when I switch off a main speaker amp and switch on my dedicated headphones amp (yes, they are 2 different boxes) I can power the unused one down via x10 devices and power the other one up the same way (via another device address).

your code came in useful - and it took all of 5 minutes to solder into a spare firecracker (I had no db9's) and download your code to test it. when I heard a relay CLICK! loud in the other room, I knew it was working :wink:

good stuff, many thanks!

/bryan

@linux-works

Very happy to hear that the driver came in handy for you. :slight_smile:

Although not perfect, that old X10 stuff can really come in handy for dealing with mains power. (Sometimes, "Perfect is the enemy of the good.")

FYI, I just posted this . . .
http://www.arduino.cc/playground/X10/ReceiveX10
if it gives you any ideas.

Thanks!