Blog Archive

Wednesday 13 February 2013

Arduino: More RF remote sockets...

This time I've done what I wanted to do in the first place and I have used a cool library to actually send the OOK (on/off key) RF codes from my Arduino to the remote sockets. This works with both the old and new types of Byron/HomeEasy sockets, but not the 'Delta' ones in my post using opto-isolators to 'press' the remote buttons.


The Arduino is equipped with a 433MHz transmitter (like this but which can be had very cheaply from your local Ebay) and is connected to a Linux PC via USB. It accepts instructions via the serial port (USB) and I wrote some simple C programs to allow the Linux box to send the right commands. The web front end, which is optimized for iPhone layouts, utilizes php which calls the C programs. Simple. I also have the C programs in cron to turn things in and off on a schedule. I plan at some point to write a php interface to allow scheduling but that's for (much) later.

The Arduino sketch I wrote needs to send the same remote control codes that the actual remote controls send. To find out which codes to put into the sketch, I used the information from this library (which forms the backbone of my whole project) and used the examples to "sniff" the codes. I basically put the "ShowReceivedCode" sketch onto the Arduino and watched the serial output as I pressed buttons on the remotes. I then copied and pasted these codes into my Arduino sketch.



The capacitor in the photo is links GND and RESET and prevents the Arduino resetting itself when the serial port is opened. The "DATA" pin on the transmitter is connected to Arduino input 11. The empty header is for a receiver, not used in this project except when learning the remote codes. The wire going up and out of the photo is the antenna, approx. 17cm seems a good length and gets me plenty of range in my cheap (cheaply built, it wasn't cheap to buy!) modern house.



Now, the code I put together for my Arduino



#include <OldRemoteReceiver.h>
#include <OldRemoteSwitch.h>
#include <NewRemoteReceiver.h>
#include <NewRemoteTransmitter.h>

int led = 13;

unsigned long HE200unit1on = 1234567890; // code learned  
unsigned long HE200unit1off = 1234567891;
unsigned long HE200unit2on = 1234567892; // heater in living room
unsigned long HE200unit2off = 1234567824;
unsigned long HE200unit3on = 1234567810; //
unsigned long HE200unit3off = 1234567800;
unsigned long HE200unit4on = 1234567884; // 
unsigned long HE200unit4off = 1234567874;
unsigned long HE200unit5on = 1234567830; //
unsigned long HE200unit5off = 1234567836;
unsigned long HE200unit6on = 1234567804; //
unsigned long HE200unit6off = 1234567810;


unsigned long byronD1on = 1234567834;  //BYRON outside socket
unsigned long byronD1off = 1234567840; //BYRON outside socket
unsigned long byronD2on = 1234567816;
unsigned long byronD2off = 1234567830;
unsigned long byronD3on = 1234567800;
unsigned long byronD3off = 1234567898;

//-- NEW TYPE CODDES
unsigned long LightSwitch1_address = 1234567;
unsigned int LightSwitch1_period = 257;
unsigned short LightSwitch1A_unit = 10;
unsigned short LightSwitch1B_unit = 11;

unsigned long LightSwitch2_address = 123456;
unsigned int LightSwitch2_period = 260;
unsigned short LightSwitch2A_unit = 10;


// HE300 remote control. Set 'unit' to "group" to switch on or off the group (all
// switch settings)
unsigned long HE300_address = 1234566;
unsigned int HE300_period = 257;
/*
Switch Set to I : button 1 = unit 0
Switch Set to I : button 2 = unit 1
Switch Set to I : button 3 = unit 2
Switch Set to I : button 4 = unit 3
Switch Set to II : button 1 = unit 4  // Dining Room under cupboard lights
Switch Set to II : button 2 = unit 5
Switch Set to II : button 3 = unit 6
Switch Set to II : button 4 = unit 7
Switch Set to III : button 1 = unit 8
Switch Set to III : button 2 = unit 9
Switch Set to III : button 3 = unit 10
Switch Set to III : button 4 = unit 11
Switch Set to IV : button 1 = unit 12
Switch Set to IV : button 2 = unit 13
Switch Set to IV : button 3 = unit 14
Switch Set to IV : button 4 = unit 15
*/

String input;
char inData[20]; // Allocate some space for the string
char inChar; // Where to store the character read
byte index = 0; // Index into array; where to store the character

void setup() {
  pinMode(led, OUTPUT); 
  Serial.begin(9600);
  Serial.println("Transmitter init...");
  Serial.println("ok");
}

void loop() {
  delay(50);
  while(Serial.available() > 0) // Don't read unless
                                // there you know there is data
   {
       if(index < 8) // One less than the size of the array
       {
           inChar = Serial.read(); // Read a character
           inData[index] = inChar; // Store it
           index++; // Increment where to write next
           inData[index] = '\0'; // Null terminate the string
       }
   }
   input = inData;
   index=0;
   // Now do something with the string (but not using ==)
   // Serial.println(input);

  if(strcmp(inData,"1on") == 0)
    { press(HE200unit1on); }
  else if(strcmp(inData,"1off") == 0)
    { press(HE200unit1off);  }

  else if(strcmp(inData,"2on") == 0)
    { press(HE200unit2on); }
  else if(strcmp(inData,"2off") == 0)
    { press(HE200unit2off);  }

  else if(strcmp(inData,"3on") == 0)
    { press(HE200unit3on); }
  else if(strcmp(inData,"3off") == 0)
    { press(HE200unit3off);  }

  else if(strcmp(inData,"4on") == 0)
    { press(HE200unit4on); }
  else if(strcmp(inData,"4off") == 0)
    { press(HE200unit4off);  }
    
  else if(strcmp(inData,"D1on") == 0)
    { press(byronD1on); }
  else if(strcmp(inData,"D1off") == 0)
    { press(byronD1off);  }
  else if(strcmp(inData,"D2on") == 0)
    { press(byronD2on); }
  else if(strcmp(inData,"D2off") == 0)
    { press(byronD2off);  }
  else if(strcmp(inData,"D3on") == 0)
    { press(byronD3on); }
  else if(strcmp(inData,"D3off") == 0)
    { press(byronD3off);  }

  else if(strcmp(inData,"HII1on") == 0)
    { newpress(HE300_address,HE300_period,4,1);  }
  else if(strcmp(inData,"HII1off") == 0)
    { newpress(HE300_address,HE300_period,4,0);  }
   
  else if(strcmp(inData,"HIII1on") == 0)
    { newpress(HE300_address,HE300_period,8,1);  }
  else if(strcmp(inData,"HIII1off") == 0)
    { newpress(HE300_address,HE300_period,8,0);  }

  else if(strcmp(inData,"LS2on") == 0)
    { newpress(LightSwitch2_address,LightSwitch2_period,10,1);  }
  else if(strcmp(inData,"LS2off") == 0)
    { newpress(LightSwitch2_address,LightSwitch2_period,10,0);  }

  
}
void press(unsigned long button)
{
  digitalWrite(led, HIGH);

  unsigned long sendcode = button;

  Serial.print("sending code ");
  Serial.println(sendcode);

  //transmit the signal on pin 11.
  RemoteSwitch::sendTelegram(sendcode,11);
  Serial.print("1 ");
  RemoteSwitch::sendTelegram(sendcode,11);
  Serial.println("2");
  memset(inData, 0, sizeof(inData));   // empty serial in data (stuff
                                       // sent to the Arduino)
  digitalWrite(led, LOW);
  Serial.println("ok");
  }

void newpress(unsigned long address, unsigned int period, unsigned short unit, int onoroff)
{
  digitalWrite(led, HIGH);
 // delay(500);               
 
  //NewRemoteReceiver::disable();
  // Need interrupts for delay()
  interrupts();
  NewRemoteTransmitter transmitter(address, 11, period);
  
  Serial.print("NEW:sending code ");
  Serial.print(address);
  //transmit the signal on pin 11.
  Serial.println(" sent");
  transmitter.sendUnit(unit, onoroff);
  Serial.print("1 ");
  //delay(150);
  transmitter.sendUnit(unit, onoroff); // sent twice to try to 
                                       // make sure the signal gets through
  Serial.println("2");
  memset(inData, 0, sizeof(inData));   // empty serial in data 
                                       // (stuff sent to the Arduino)
  digitalWrite(led, LOW);
  Serial.println("ok");
}

This is the output from the C code I mentioned. The PHP pages 'exec' this code and this sends text given as a command line argument to the serial port, also specified as an argument.

After compiling, like this

gcc press.c -o press

It should be called something like this

./press /dev/ttyACM0 4on


Here's the main Arduin sketch:


#include <termios.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
//-----------------
int DC(int serial_port_fd, char *msg) {
 int n;
 //usleep(2000000);
 usleep(100000);
 printf("sent %s\n", msg);
 //n = write(serial_port_fd, "rs1on\n", 5); 
 n = write(serial_port_fd, msg, 8); 
 //usleep(250000);
 //printf("sending %s\n", msg);
 //n = write(serial_port_fd, msg, 8); 
  // send the code twice, just to make sure the transmission reaches the receiver
 usleep(1000000);
 return 0;
}
//-----------------
int CLOSE(serial_port_fd){
 struct termios termios_save;
 tcsetattr(serial_port_fd, TCSANOW, &termios_save);
 tcflush(serial_port_fd, TCOFLUSH);
 tcflush(serial_port_fd, TCIFLUSH);
 close(serial_port_fd);
 return 0;
}
//------------------------------------------------------------------------------------------
int main(int argc, char *argv[] )
{
 if ( argc != 3 ) /* argc should be 2 for correct execution */
 {
  printf( "usage: %s port command", argv[0] );
 }
 else
 {
 int serial_port_fd; // = -1;
 char *port = argv[1]; // command line arg 1 needs to be the port device

//printf("%s\n", argv[1]);
//printf("%s\n", argv[2]);

 serial_port_fd = open(port, O_RDWR | O_NOCTTY | O_NDELAY); 
 if(serial_port_fd < 0) {
  printf("could not open port %s\n error: %d\n", port, serial_port_fd);
  return 1;
 }

 struct termios port_settings;      // structure to store the 
                                           // port settings in

 cfsetispeed(&port_settings, B9600);    // set baud rates
 cfsetospeed(&port_settings, B9600);

 port_settings.c_cflag &= ~PARENB;    // set no parity, 
                                             // stop bits, data bits
 port_settings.c_cflag &= ~CSTOPB;
 port_settings.c_cflag &= ~CSIZE;
 port_settings.c_cflag |= CS8;
 
 tcsetattr(serial_port_fd, TCSANOW, &port_settings); // apply the 
                                                            // settings to 
                                                            // the port


 //open the serial port
 DC(serial_port_fd, argv[2]); // send data to port where 
                                     // data is command line arg 2
 CLOSE(serial_port_fd); // close the port
 return 0;
 }
}
..