Greetings!
I thought I'd share a Proof of Concept for receiving powerline commands from an X10 CM11a serial interface. What it does is recieve commands via CM11a <> TTL shifter <> software serial and print commands to Arduino hardware serial.
This could be modified to control or display commands with your arduino. The CM11a is an RS232 device and there's no need for the "zero-crossing" based PSC05/TW523 module.
You MUST use a ttl level shifter, do NOT connect an RS232 device directly to your arduino.
I hope someone likes this, I could not find any other code to receive commands with CM11a. I'm a hobbyist; the code is what it is. I hope this might inspire someone to make it better.
Thanks, Dan G.
Credits:
- Arduino folks, of course!
- "LJRob" for the initial sketch for sending commands via CM11a
see: Arduino Forum - BroHogan - Parse code at Arduino Playground - ReceiveX10
Arduino IDE 1.0.3
/*
Proof of Concept: CM11a Powerline Command Monitor
Author: Dan G.
Recieve commands via CM11a <> TTL shifter <>
software serial and print commands to Arduino hardware serial.
Since the PSC05/TW523 modules are no longer made. CM11a can be used to receive PLC.
They are much cheaper and available.
Do NOT connect CM11a directly to Arduino, you MUST use TTL level shifter.
Search for "cm11a_protocol.txt" for more details.
Credits:
- Arduino folks, of course!
- "LJRob" for the initial sketch for sending commands via CM11a
see: http://arduino.cc/forum/index.php?topic=136227.0
- BroHogan - Parse code at http://playground.arduino.cc/X10/ReceiveX10
*/
#define ON B10000000 // Bitshifted ON
#define OFF B11000000 // Bitshifted OFF
byte lookup[16] = { // Lookup table for House and Unit Code
//Binary House Unit
B0110, // A 1
B1110, // B 2
B0010, // C 3
B1010, // D 4
B0001, // E 5
B1001, // F 6
B0101, // G 7
B1101, // H 8
B0111, // I 9
B1111, // J 10
B0011, // K 11
B1011, // L 12
B0000, // M 13
B1000, // N 14
B0100, // O 15
B1100, // P 16
};
#include <SoftwareSerial.h> // For the TTL to RS232
SoftwareSerial X10Serial(2, 3); // RX, TX to TTL RS232
byte incomingByte; // Controller status
byte Hc; // Housecode
char chrHc = Hc; // Housecode to char
byte U; // Unit
byte Cmd; // ON or OFF
//Serial buffer
byte serIn; // var that will hold the bytes-in read from the serialBuffer
byte serInString[9]; // CM11a can send up to 10 bytes (program only handles 3 bytes)
int serInIndx = 0; // index of serInString[] in which to insert the next incoming byte
int serOutIndx = 0; // index of the outgoing serInString[] array;
void setup() {
Serial.begin(57600);
X10Serial.begin(4800); // X10 Baud 4800 8,NONE,1
Serial.println("x10 CM11a Ready:");
}
void loop(){
CheckX10controller(); // Check CM11a for data or power failure.
parseX10SerialString();
}
// 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(100); // CM11a is slow; don't write too fast, won't work!
X10Serial.write((byte)0x9B); // Acknowledge / Clear, This must be cleared or it will not except any other x10 commands
delay(60);
Serial.println("Power Supply Restored");
break;
case ((byte)0x5A): // Polling: When powerline command received, CM11a send this byte.
delay(100); // CM11a is slow; don't write too fast, won't work!
X10Serial.write((byte)0xC3); // Send byte, initiate the data transfer.
delay(60);
ReadData();
break;
//default: //Used for testing only
//ReadData(); //Used for testing only
}
}
}
void ReadData() {
int sb;
if(X10Serial.available()) {
while (X10Serial.available()){
sb = X10Serial.read();
serInString[serInIndx] = sb;
serInIndx++;
}
}
}
void parseX10SerialString(){
if( serInIndx > 0) {
//debug Serial.print("Bytes Received: ");
//debug Serial.println(serInString[0]);
if (serInString[1] == 0) {
//debug Serial.print("X10 Address 2nd byte is: ");
//debug Serial.println(serInString[1], HEX);
//debug Serial.print("HcU in BIN: ");
//debug Serial.println(serInString[2], BIN);
Hc = serInString[2] >> 4; // Gets Housecode binary
//debug Serial.print("Hc in BIN: ");
//debug Serial.println(Hc, BIN);
for (byte i=0; i<16; i++){ // use lookup table for Housecode
if (lookup[i] == Hc){
Hc = i+65; // this gives int House 'A' - 'P'
char chrHc = Hc; // Convert int Hc to Char for Serial print
Serial.print("Housecode: ");
Serial.println(chrHc);
break; // stop search when found!
}
}
U = serInString[2] << 4; // Bitshift for Unit
U = U >> 4; // Final "bitdance" for Unit
//debug Serial.print("U in BIN: ");
//debug Serial.println(U, BIN);
for (byte i=0; i<16; i++){ // use lookup table for Unit
if (lookup[i] == U){
U = i+1; // this gives Unit 1-16
Serial.print("Unit: ");
Serial.println(U);
break; // stop search when found!
}
}
}
if (serInString[1] == 1) {
//debug Serial.print("X10 Function 2nd byte is: ");
//debug Serial.println(serInString[1], BIN);
//debug Serial.print("Function: ");
Cmd = serInString[2] << 6; // Bitshift out redundant Housecode
Serial.print("Command: ");
if(Cmd == B10000000)Serial.println("ON ");
if(Cmd == B11000000)Serial.println("OFF ");
//debug Serial.print("binary: ");
//debug Serial.println(Cmd, BIN);
}
}
//reset all the functions to be able to fill the string back with content
serOutIndx = 0;
serInIndx = 0;
}