X10 in the UK and Europe

Hi
Here is my sketch for X10 control. It does not use any libraries, the commands only need to be sent once and does not use the zero cross method.

The catch is the X10 controller is a CM12U. All I am doing is sending serial commands to the CM12U. I have been using X10 in my house for many years using an Apple Mini with no problems. I wanted to control my house with my Arduino.

I tried many sketches and libraries but could not get any of them to work. Then I tried reading the commands coming from my Apple Mini USB to serial and thought why not use a TTL to serial to send commands to the X10.

When the CM12U is first plugged into a socket it sends out a polling command. Unless you reply to this command it will not respond to any other X10 commands.

/*
  Arduino 1.0.1
 This sketch controls X10 modules using a TTL to RS232 and a UK CM12U X10 controller
 
 
 */


#include <SoftwareSerial.h>	// For the TTL to RS232

#define	A	0x60
#define	B	0xE0	
#define	C	0x20
#define	D	0xA0
#define	E	0x10
#define	F	0x90
#define	G	0x50
#define	H	0xD0
#define	I	0x70
#define	J	0xF0
#define	K	0x30
#define	L	0xB0
#define	M	0x00
#define	N	0x80
#define O	0x40
#define P	0xC0

#define UNIT_1	0x06
#define UNIT_2	0x0E
#define UNIT_3	0x02
#define UNIT_4	0x0A
#define UNIT_5	0x01
#define UNIT_6	0x09
#define UNIT_7	0x05
#define UNIT_8	0x0D
#define UNIT_9	0x07
#define UNIT_10	0x0F
#define UNIT_11	0x03
#define UNIT_12	0x0B
#define UNIT_13	0x00
#define UNIT_14	0x08
#define UNIT_15	0x04
#define UNIT_16	0x0C

#define ALL_UNITS_OFF		0x00
#define ALL_LIGHTS_ON		0x01
#define ON			0x02
#define OFF			0x03
#define DIM			0x04
#define BRIGHT			0x05
#define ALL_LIGHTS_OFF		0x06
#define EXTENDED_CODE		0x07
#define HAIL_REQUEST		0x08
#define HAIL_ACKNOWLEDGE	0x09
#define PRE_SET_DIM_1		0x0A
#define PRE_SET_DIM_2		0x0B
#define EXTENDED_DATA		0x0C
#define STATUS_ON		0x0D
#define STATUS_OFF		0x0E
#define STATUS_REQUEST		0x0F

#define d 600    // 600 ms to 2000 ms delay after first three bytes are sent
#define d2 20    // 20 ms delay waiting for checksum before sending the next three bytes

SoftwareSerial X10Serial(2, 3); // RX, TX to TTL RS232
              
byte incomingByte;     // from the X10 controller or the keyboard
byte Housecode_Devicecode; // for the X10Serial.write third byte
byte Housecode_Function;   // for the X10Serial.write third byte
byte luminance = 0x00;     // brightness and dim value

void setup() {

  Serial.begin(9600);
  X10Serial.begin(4800);    // X10 Baud 4800 8,NONE,1
  delay(d);		    //
  PrintMenu();	    // Print the menu on the screen
}

void loop() {

  CheckX10controller ();  // Check X10 controller
  CheckKeyboard();       // Check keyboard
}

// Read from X10 controller
void CheckX10controller () {

  if (X10Serial.available() > 0) {
    incomingByte = X10Serial.read();

    switch (incomingByte) {

      case ((byte)0xA5):          // Polling. This happens the first time you plug the X10 controller in the socket or after a power cut
      delay(d2);                  // wait 20 ms before sending Acknowledge
      X10Serial.write((byte)0x9B);   // Acknowledge / Clear, This must be cleared or it will not except any other x10 commands
      PowerSupplyRestored();
      break;

      case ((byte)0x5A):          // Polling. this happens after remote wireless button has been pressed.
      delay(d2);                  // wait 20 ms before sending Acknowledge
      X10Serial.write((byte)0xC3);   // Acknowledge / Clear, This must be cleared or it will not except any other x10 commands
      RFrestored();
      break;
    }
  }
}


// Read from Keyboard
void CheckKeyboard() {

  if (Serial.available() > 0) {
    incomingByte = Serial.read();

    switch (incomingByte) {

    case '?':                      		// Keyboard "?"
      PrintMenu();              		// Print help menu
      break;

    case '1':                     		// Keyboard "1"
      X10Command(A+UNIT_1,A+ON, 0x00);	// A1 ON
      break;

    case '2':                      		// Keyboard "2"
      X10Command(A+UNIT_1,A+OFF, 0x00);	// A1 OFF
      break;

    case '3':                     		// Keyboard "3"
      X10Command(A+UNIT_2,A+ON, 0x00);  // A2 ON
      break;

    case '4':                      		// Keyboard "4"
      X10Command(A+UNIT_2,A+OFF, 0x00);	// A2 OFF
      break;

    case 'p':                      		// Keyboard "p"
      PowerSupplyStatus();              // Check X10 Interface power supply
      break;

    case '0':                      		// Keyboard "0" send all units OFF to A ... P
      for (int i = 0x00; i <= 0xF0; i += 0x08) {
        X10Function(i+ALL_UNITS_OFF,0x00);
        delay(300);
      }
      break;

    case 'b':                      		// Keyboard "b" brighten lamp A2
      X10Command(A+UNIT_2, A+BRIGHT, 0x03);
      break;

    case 'd':                    		// Keyboard "d" dim lamp A2
      X10Command(A+UNIT_2, A+DIM, 0x03);
      break;
    }

  }  
}

void X10Command(byte Housecode_Devicecode, byte Housecode_Function, byte luminance) {

  // first three bytes
  X10Serial.write((byte)0x04);                      // start code
  X10Serial.write((byte)Housecode_Devicecode);      // house code and device code
  delay(d2);                                        // short delay to wait for checksum from Interface
  X10Serial.write((byte)0x00);                      // Acknowledge checksum

  delay(d);                                         // long delay Interface ready

  // second three bytes
  X10Serial.write((byte)0x06 + (luminance << 3));  // start code plus bright or dim value. luminance value is shiftbit left by 3
  X10Serial.write((byte)Housecode_Function);       // house and function code. on/off dim/bright
  delay(d2);                                       // short delay to wait for checksum from Interface
  X10Serial.write((byte)0x00);                     // Acknowledge checksum
}

void X10Function(byte Housecode_Function, byte luminance) {

  // second three bytes
  X10Serial.write((byte)0x06 + (luminance << 3));  // start code plus bright or dim value. luminance value is shiftbit left by 3
  X10Serial.write((byte)Housecode_Function);       // house and function code. on/off dim/bright
  delay(d2);                                       // short delay to wait for checksum from Interface
  X10Serial.write((byte)0x00);                     // Acknowledge checksum
}

void PowerSupplyStatus() {

  X10Serial.write((byte)0xEB);                     // send Enable Ring to check power supply
  delay(20);                                       // short to wait for checksum from Interface
  if (X10Serial.read() == ((byte) 0xEB)) {         // checksum should be 0xEB
    PowerSupplyHealthy();                          // X10 controller still mains on 
  }
  else {
    PowerSupplyDown();                            // X10 controller dead 
  }
}

void PowerSupplyHealthy() {
  Serial.println("\nPower Supply Healthy");
}
void PowerSupplyDown() {
  Serial.println("\nPower Supply Down");
}
void PowerSupplyRestored() {
  Serial.println("\nPower Supply Restored");
}
void RFrestored() {
  Serial.println("\nRemote polling Reset"); 
}

void PrintMenu() {
  Serial.println("X10 Menu");
  Serial.println(
  "? Help\n"
    "1 A1 Appliance ON\n"
    "2 A1 Appliance OFF\n"
    "3 A2 Lamp ON\n"
    "4 A2 Lamp OFF\n"
    "b A2 Bright\n"
    "d A2 Dim\n"
    "0 All Units OFF A to P\n"
    "p Check Power Supply");
}

Hi LJRob,

I just bought an arduino and want to use it to control my X10-system, at the end it is the idea to put on an ethernet shield and control my X10 modules via an app on my TAB/mobile.

Your code was very usefull to test my setup. I have some problems however. I'm using the CM11a (belgian version of your CM12u I suppose)

I have my arduino connected to a MAX232 to convert the TTL into RS232. (followed this diagram avrprogrammers.com -)

But I'm not sure about the pin-out of the CM11 module. There is a lot of contradictionary info on the net about this pinning. How did you connect your CM12 to the arduino?

The furthest I got was to request the 'power supply' but there the answer was allways 'power down'.

Any ideas?

Thank you! Dax

Hello Dax

Thank you for your interest of my X10 sketch. I am using a MAX232 to TTL converter like this one
http://www.ebay.co.uk/itm/MAX232-RS232-Serial-To-TTL-Output-Converter-Board-RXD-TXD-RTS-CTS-F-PIC-Atmel-/290712442058?pt=UK_BOI_Electrical_Components_Supplies_ET&hash=item43afcfd4ca

I had to make up a new cable from my CM12 because it came with a female DB9. The RS232 to TTL converter also had a female DB9. I tried using a gender changer but it also needed a nul modem to make it work.

Here's the connections I have used.

Holding the RJ11 with the cable away from you and the locking clip on the top.
From left to right, pins are 1 2 3 4

Signal DB9 Connector RJ11 Connector
SIN Pin 2 Pin 3
SOUT Pin 3 Pin 1
GND Pin 5 Pin 4
RI Pin 9 Pin 2

You don't need to use pin 9 on the DB9.
You may need to swap the wires on pins 2 and 3 on the DB9 if it not work first time.

Im using pins 2 and 3 on my Arduino for software serial for the RS232 to TTL converter, I notice the connection website your using has pins 0 and 1 for the MAX232

Let me know if this works for you,
Thanks.
LJRob.

:slight_smile: :slight_smile: :slight_smile:

Hello LJRob,

Thank you very much for your reply, I just had some time to test it with your explanation of the cabling and it is working very well.

My biggest problem was indeed that I overlooked the RX/TX from/to the arduino, I was using the pins 0 and 1 instead 2 and 3.

Again one step closer to my X10-automation via a smartphone :slight_smile:

Thank you,

Dax

Hi LJRob,

I am newbie in electronics and is learning to do some home automation stuffs with my arduino. How do I hook up the MAX232 to TTL converter to my CM12U x10 controller. Please advise. Thank you very much.

The combo of the below transponder and the bottom firecracker would mqake x10 control super simple. The cm17a firecracker connects to the arduino with three wires and is powered by the arduino.

http://www.x10europe.com/pdf/TM13E.pdf

With all due respect to zoomKat, He has not read the specifications of the european X10 transponder. The firecracker uses 310 MHZ and the european X10 transponder uses 433.92 MHZ. They will not talk to each other. I found this out to my cost by not reading the specs of the firecracker and buying one.

I have not found any articles on the internet about people in Europe using an Arduino with X10 (except for people not able to make them work) So I decided to learn X10 myself and help others by starting this post and freely giving the information I have learned, which is in the first thread of this post.

With all due respect to zoomKat, He has not read the specifications of the european X10 transponder.

True, I just bought off on their "• Compatible with all X10 wireless remotes." The hand held remotes can be hacked, but probably not worth the effort.

Just came across this post - pulled out my old CM12 from storage and it works with the sketch! Time to resurrect the few x10 switches I have.

Note: It didn't work at first - had a look at the CM12 and one of the electrolytics had failed (with the usual tell tale bulge).

Hi gadget

Glad you got the X10 sketch working.

The sketch is just a example of the X10 commands and time delay between the commands.
Im sure you can write a sketch to control what you want in your house.

Thank you for letting me know

LJRob

daxke:
:slight_smile: :slight_smile: :slight_smile:

Hello LJRob,

Thank you very much for your reply, I just had some time to test it with your explanation of the cabling and it is working very well.

My biggest problem was indeed that I overlooked the RX/TX from/to the arduino, I was using the pins 0 and 1 instead 2 and 3.

Again one step closer to my X10-automation via a smartphone :slight_smile:

Thank you,

Dax

Hi LJ, thank for you help, could you, please, send us a pictures or diagram for conexion completed from Arduino to CM11a

Thanks a lot
Regards

Hi I am new to Arduino and am trying to get the sketch working on my Mega 2560 via a max232 module but am getting no joy its probably a long shot as this is quite and old post but here goes anyway.

I have tested the cm12 and it works fine but am not sure why I cant talk to it I have rewired the db9 connector as per instructions and tried swapping pin 2 and 3 as suggested I have the pins on the max232 connected to pins 2 & 3 on the mega but get nothing when I try to poll it the p returns power supply down but I am not sure what that means.

Any help would be gladly received as good information about x10 control seems hard to come by.

Cheers

Ok so after some after much fiddling I got it to work on the Mega, it turns out that you cant use pins 2 and 3 for softwareserial on the Mega as not all pins support change interrupt needed for rx. The same is true for the Leonardo and micro. I moved mine to 50 and 51 as i want to use a network shield to act as a webserver to control the X10 via tablet, smartphone or computer.

More info on softwareserial limitations can be found here https://www.arduino.cc/en/Reference/SoftwareSerial

Maybe this topic is now a bit old, but I have just got my X10 working with a CM12AU controller (yes, I'm in Australia - hence the AU sufix!) via an Arduino Uno and following the great postings here. Just one small issue - the original sketch fails to compile with the following error message:

C:\Users\Mike\Documents\Arduino\X10_CM12AU\X10_CM12AU.ino:13:0: warning: "F" redefined [enabled by default]

#define F 0x90

^

In file included from C:\Program Files\Arduino\hardware\arduino\avr\cores\arduino/Arduino.h:223:0,

from sketch\X10_CM12AU.ino.cpp:1:

C:\Program Files\Arduino\hardware\arduino\avr\cores\arduino/WString.h:38:0: note: this is the location of the previous definition

#define F(string_literal) (reinterpret_cast<const __FlashStringHelper *>(PSTR(string_literal)))

^

(As you can see, I have renamed the sketch X10_CM12AU). I have solved the problem by redefining F as (lower case) f i.e. #define f 0x90 instead of #define F 0x90.

The code compiles and runs perfectly, and I guess if I wanted to use house-code F, I'd just code it as 'f' in the X10Command? (I don't, as it happens!)

But I guess I am curious as to what is causing this error? Any comments gratefully received - and many thanks to LJRob for developing this idea!