Last year I made the first progress towards a DIY remote for my home automation light switches (using the Everflourish RF based system). The goal was to use the 433.92 MHz radio transmitter and an Arduino to control the switches. Furthermore, the Arduino would receive control commands from my always-on computer, with Bash command line control ('cause that's the way I like it). Finally, a custom Android app was developed as yet another option for remote control. The project is now fully operational, with a few adjustments here and there remaining. The figure below shows a high level overview.

From left to right, the mobile phones run Android apps which present a simple interface to control the lights. Each light can be turned on and off individually, or by some pre-sets (e.g. everything on or off, "good morning", or "movie time"). The application has hard-wired the IP address of my always on server / PC on the local network. There is of course nothing stopping me from connection to a public IP (and port-forward), however, I don't need away-from-home control at this point. The phone app simply sends a "light switch command" to the PC, which forwards it directly to the Arduino (see details below).

In this setup, the server is only a proxy, however, it could of course also be used to implement pre-programmed settings. E.g. daily rhythm commands when we're away on holiday, or other automated functions. Since this box is also my PC, I can also send commands directly to the Arduino over serial /dev/tty; I have some convenience bash-scripts for that. For the phone app, it only does the forwarding on a hard-wired port:

while true; do nc -l 1234 > /dev/ttyUSB0; done

Maybe that bit could be improved in the future. Especially, since there are occasionally a few hiccups in the phone to PC communication. For example, the switch from 3G to local Wifi connection might be delayed as we enter the house, so commands will buffer up, and then suddenly sent en masse. Also, this would be a natural place to expand the system with pre-programmed actions. It should also be noted that to get this to work, I had to enable communication on the port 1234 both on the Wifi router, and the local server firewall.

Finally, the Arduino, connected via USB, accepts the incoming serial messages. The encoding is simple: A two digit code where the first digit is the index of the light, and the second is 0 or 1 for off or on (see the loop() method in the source listing below). So, "11" will turn on the first light, while "10203040" turns off all four lights. (Note that in the code below, to make things clearer for myself, index 0 is skipped).

The code below is all there is the the Arduino part. It hard-codes the Everflourish messages and timings. It should be noted that the messages as found in the previous article, are most likely some form of Manchester code, as there are always pairs of 01 or 10. Thus, the hard-coded messages could have been shortened, but this would have added (a bit) to the complexity of the code, so I left it.

The main loop waits for incoming bytes on the serial USB connection, and sends the according light switch command to the RF transmitter on pin 2. Here there is probably also room for some improvements, to avoid illegal numbers, stuck states, etc. Once a valid code is received, the transmitted signal for that button is repeated four times, just as seen with the original remote control.

(Download source)

#define OUT_PIN 2

// Timings in micro seconds
#define SHORT_UP_0 567
#define LONG_UP_1 1134
#define DOWN_SPACE 680
#define UP_END 15000

const int PREAMBLE = {0x00};
const int OFF[] = {0x55};
const int ON[]  = {0xaa};

const int light_array[][5] = {
  {},
  // main
  {0x65, 0xa9, 0x46, 0x95, 0x67, },
  {0x65, 0xa9, 0x46, 0x96, 0x96, },
  {0x65, 0xa9, 0x46, 0x99, 0xa3, },
  {0x65, 0xa9, 0x46, 0x9a, 0x61, },

  // aux
  {0x65, 0xa9, 0x46, 0x95, 0xaa, },
  {0x65, 0xa9, 0x46, 0x96, 0x53, },
  {0x65, 0xa9, 0x46, 0x99, 0x62, },
  {0x65, 0xa9, 0x46, 0x9a, 0xa1, },
}; 

void setup() {
    Serial.begin(9600);
    Serial.println("setup");

    pinMode(OUT_PIN, OUTPUT);
}

void loop() {
  if (Serial.available() > 1) {
     int light_id = Serial.read() - '0';
     int on = Serial.read() - '0';
     Serial.print(light_id);
     Serial.println(on);
    
     for(int i = 0; i < 5; i++) {     
       send(light_array[light_id], on);
     }
     
     //delay(500);
  }
}
  
void send(const int *light_data, boolean on) {

  digitalWrite(OUT_PIN, LOW);
  delayMicroseconds(LONG_UP_1);
  
  send_bytes(PREAMBLE, 1, 4);
  send_bytes(light_data, 5, 8);
  send_bytes(on ? ON : OFF, 1, 8);

  digitalWrite(OUT_PIN, HIGH);
  delayMicroseconds(DOWN_SPACE);
  
  digitalWrite(OUT_PIN, LOW);
  delayMicroseconds(UP_END);

  digitalWrite(OUT_PIN, HIGH);
}

void send_bytes(const int *bytes, int len_bytes, int len_bits) {
  for(int b = 0; b < len_bytes; b++) {
    int data_byte = bytes[b];
    for(int i = len_bits - 1; i >= 0; i--) {
      digitalWrite(OUT_PIN, HIGH);
      delayMicroseconds(DOWN_SPACE);
    
      digitalWrite(OUT_PIN, LOW);
      int data_bit = ((data_byte >> i) & 1);
      if (data_bit == 0) {
        delayMicroseconds(SHORT_UP_0);
      } else {
        delayMicroseconds(LONG_UP_1);
      }
    }
  }
}