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");
}