Control Livolo switches / Livolo switch library

Hi there,

I was looking for a way to control Livolo wireless switches. Seller only told me it was a 433.92 MHz thing, but wonderful RC-Switch wouldn’t read them. I’m not a programmer, so I had to use the most simple approach. That is record command with Audacity, figure out pattern and pulses length, and hardcode it for Arduino.

In case you have the same switches, feel free to use this code to control them. Hardcoded are 11 buttons (0 to 9 plus All off). As Livolo switches are learning, they should be programmable with this commands. Just put switch into learning mode and transmit command you wish.

================================

IMPORTANT UPDATE
Code below is outdated and now it is a mere demo of what I’ve been through.

As of 25.10.2013 code avaliable as a library.

Find latest version of Livolo switch library attached.

================================

LIVOLO REMOTE RECEIVER FOR ARDUINO

Thanks, daleldalel!

LIVOLO REMOTE RECEIVER AND TRANSMITTER FOR RASPBERRY PI

Thanks, platenspeler!

================================

int txPin = 9; // pin connected to RF transmitter
int i; // counter to send command pulses
int pulse; // count pulse repetitions
int incomingByte = 0;   // for incoming serial data

// hard coded commands (see txButton): 1 - pulse start, 2 - zero, 3 - one, 4 - pause, 5 - low
int button1[45]={44, 1, 2, 4, 2, 4, 2, 4, 3, 5, 2, 4, 2, 4, 3, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2};
int button2[43]={43, 1, 2, 4, 2, 4, 2, 4, 3, 5, 2, 4, 2, 4, 3, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 5, 3, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2};
int button3[41]={40, 1, 2, 4, 2, 4, 2, 4, 3, 5, 2, 4, 2, 4, 3, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 5, 3, 5, 3, 4, 2, 4, 2, 4, 2};
int button4[43]={42, 1, 2, 4, 2, 4, 2, 4, 3, 5, 2, 4, 2, 4, 3, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 5, 3, 4, 2, 4, 2, 4, 2};
int button5[43]={42, 1, 2, 4, 2, 4, 2, 4, 3, 5, 2, 4, 2, 4, 3, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 5, 2, 4, 3, 4, 2, 4, 2, 4, 2, 4, 2};
int button6[43]={42, 1, 2, 4, 2, 4, 2, 4, 3, 5, 2, 4, 2, 4, 3, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 5, 3, 4, 2, 4, 2, 4, 2, 4, 2};
int button7[41]={40, 1, 2, 4, 2, 4, 2, 4, 3, 5, 2, 4, 2, 4, 3, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 5, 3, 4, 2, 5, 3, 4, 2, 4, 2};
int button8[43]={42, 1, 2, 4, 2, 4, 2, 4, 3, 5, 2, 4, 2, 4, 3, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 5, 3, 4, 2, 4, 2};
int button9[43]={42, 1, 2, 4, 2, 4, 2, 4, 3, 5, 2, 4, 2, 4, 3, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 5, 2, 4, 2, 4, 3, 4, 2, 4, 2, 4, 2};
int button10[43]={42, 1, 2, 4, 2, 4, 2, 4, 3, 5, 2, 4, 2, 4, 3, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 5, 2, 4, 3, 4, 2, 4, 2, 4, 2};
int button11[41]={40, 1, 2, 4, 2, 4, 2, 4, 3, 5, 2, 4, 2, 4, 3, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 5, 3, 4, 2, 5, 2, 4, 3, 4, 2};

void setup () {

pinMode(txPin, OUTPUT);
     Serial.begin(9600);
     Serial.println("Number = button;  a to press 0;  b to shut off all");

}

    void loop(){
      if (Serial.available() > 0) {
        // read the incoming byte:
        incomingByte = Serial.read();
        switch(incomingByte) {
        case 49:
        txButton(button1);
        Serial.println("Switching on 1");
        break;
        case 50:
        txButton(button2);
        Serial.println("Switching on 2");
        break;
        case 51:
        txButton(button3);
        Serial.println("Switching on 3");
        break;
        case 52:
        txButton(button4);
        Serial.println("Switching on 4");
        break;
        case 53:
        txButton(button5);
        Serial.println("Switching on 5");
        break;
        case 54:
        txButton(button6);
        Serial.println("Switching on 6");
        break;
        case 55:
        txButton(button7);
        Serial.println("Switching on 7");
        break;
        case 56:
        txButton(button8);
        Serial.println("Switching on 8");
        break;
        case 57:
        txButton(button9);
        Serial.println("Switching on 9");
        break;
        case 97:
        txButton(button10);
        Serial.println("Switching on 0");
        break;
        case 98:
        txButton(button11);
        Serial.println("Switching All off");
        break;
        }
      } // end if serial available
    }// end void loop
    
// transmit command. Due to transmitter (or something, I don't know) transmission code should be INVERTED. Ex: one is coded as LOW-delay->HIGH instead of HIGH-delay-LOW
void txButton(int cmd[]) {
Serial.print("Processing. Array size is ");
Serial.println(cmd[0]);
digitalWrite(txPin, HIGH); // not sure if its required, just an attempt to start transmission to enable AGC of the receiver
delay(1000);

for (pulse= 0; pulse <= 100; pulse=pulse+1) { // repeat command 100 times
for (i = 1; i < cmd[0]+1; i = i + 1) { // transmit command

  switch(cmd[i]) {
   case 1: // start
   digitalWrite(txPin, HIGH);
   delayMicroseconds(550);
   digitalWrite(txPin, LOW);
//   Serial.print("s");
   break;
   case 2: // "zero", that is short high spike
   digitalWrite(txPin, LOW);
   delayMicroseconds(110);
   digitalWrite(txPin, HIGH);
//   Serial.print("0");
   break;   
   case 3: // "one", that is long high spike
   digitalWrite(txPin, LOW);
   delayMicroseconds(303);
   digitalWrite(txPin, HIGH);
//   Serial.print("1");
   break;      
   case 4: // pause, that is short low spike
   digitalWrite(txPin, HIGH);
   delayMicroseconds(110);
   digitalWrite(txPin, LOW);
//   Serial.print("p");
   break;      
   case 5: // low, that is long low spike
   digitalWrite(txPin, HIGH);
   delayMicroseconds(290);
   digitalWrite(txPin, LOW);
//   Serial.print("l");   
   break;      
  }
    
  }

} 


}

Parts used: Arduino Uno, OOK/ASK transmitter/receiver, simple circuit to record signals on PC, Audacity, Livolo wireless switches.

Special thanks to Nethomeserver author, RC-Switch author and all that good people who were hacking wireless remotes and shared their findings and ideas.

Livolo.zip (3.34 KB)

int button1[45]={44,

RAM is a precious resource on an AVR. You could easily halve your use of it for these tables (use "byte" instead of "int"), or eliminate it altogether (use PROGMEM)

Thanks for the clue! I was sure, it is not a good code, but it was ok for me as long as it worked. I'll try it with PROGMEM first, and in case I fail, stick to "byte" type.

AWOL: int button1[45]={44,

RAM is a precious resource on an AVR. You could easily halve your use of it for these tables (use "byte" instead of "int"), or eliminate it altogether (use PROGMEM)

dont suppose you have a guide to connecting the ook ask to the arduino?

I searched around but got a lot of unrelated topics when searching for arduino uno ask :P

also, thanks a bunch, if i get this working you've potentially saved me a lot of stressing and having to find an alternative to my nice new glass dimmer switches.

I'm also going to pass on your findings to rfxcom and see if theres any chance of them getting the livolo switches working with the rfxtrx433

spch, thanks a lot for sharing. I've just purchased Livolo switches and am trying to control them from my computer. Can you share the wiring diagrams of your project? Thanks in advance for your help.

thanks a lot i'm trying to control the livolo switches from arduino and your code works great ! can you explain the protocol it's working on ?

Hi, thank you for your works. I have got this remote from livolo. http://www.aliexpress.com/item-img/smart-home-furnishing-life-touch-switches-for-remote-control-VL-RT01/575630281.html

Your works cover button 0 to 10, plus the big "power" button on the top of the remote.

The remote can set scene for a group of lighting switch. Most importantly, the code (0 to 10 button) only give power toggle function, but not power on only function. Under the scene mode, light can be power on only. Can anyone help to study the codes?

I do not have hardware and knowledge to do this myself. If anyone can give me a list of hardware needed. I will also try to learn how to do this.

Thank you

Hi folks,

Sorry for not answering questions in timely manner. I didn't get immediate follow up to this post, so I thought that everyone was quite satisfied with initial idea, or not interested at all.

I'v been a bit busy doing some home automation, mostly light automation, of course (but there is auto music in bathroom and automatic wireless cat feeder. All controlled over internet, as you may have guessed ;)

I did my best to answer your questions by PM. Here is a summary for all.

1) Wiring to control switches is extremely simple. Regarding this code: transmitter DATA to Arduino digital pin 9, GND to GND, VCC to 5V.

2) Wiring to record and analyze raw command includes some additional hardware: http://wiki.nethome.nu/lib/exe/detail.php/upm_scheme.png?id=analyzer%3Ahardware and a PC with your favourite audio recording software (I strongly recommend Audactiy)

Here you connect receiver DATA to RECEIVE point, GND to GND and GND of external 5V DC power supply, VCC to external 5V DC power supply.

MIC output should be connected to MIC in of your PC.

Please note that this does not require Arduino. Only receiver, divider, power supply and PC to record and analyze pulses.

3) I didn't try to break into Livolo protocol. Mostly because I don't have the skills to do so. Sorry guys. But I have two recorded raw samples from two different Livolo remotes. That, I guess, shoud be enough to understand protocol.

Here are download links to WAVs with 11 keypresses (order: 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, All Off). http://yadi.sk/d/oDu5rYb9AEtJq http://yadi.sk/d/psE0boFXAEtFL

4) Here is an automated (sorry) translation of how I did Livolo remote imitation:

http://translate.google.com/translate?sl=auto&tl=en&js=n&prev=_t&hl=en&ie=UTF-8&u=http%3A%2F%2Fmysku.ru%2Fblog%2Faliexpress%2F14127.html

Search for "MANAGEMENT Radio switch" in the text to read about Livolo remote imitation.

So, I guess that's all. I'll try to answer your questions if there are any.

hi thanks for your work,

could you share your latest and impoved code with us?

i copied the codes with audacity , i dont get the same waves, i guess i ll be able to reconstruct the signal thanks to your code

thanks

could you share your latest and impoved code with us?

Hi,

Sure. I was going to, anyway. But I didn’t do anything to transmitting part, sorry. I’ve only optimized for memory.

Here is more neat (as I guess) code that should use far less precious RAM than previous. It’s been cut from working code, that is why here are only few buttons.

#include <avr/pgmspace.h> // needed to use PROGMEM

#define  txPin  8 // pin connected to RF transmitter (pin 8)
byte i; // command pulses counter for Livolo (0 - 100)
byte pulse; // counter for command repeat

// commands stored in PROGMEM arrays (see on PROGMEM use here: http://arduino.cc/forum/index.php?topic=53240.0)
// first array element is length of command
const prog_uchar button1[45] PROGMEM ={44, 1, 2, 4, 2, 4, 2, 4, 3, 5, 2, 4, 2, 4, 3, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2};
const prog_uchar button2[43] PROGMEM ={42, 1, 2, 4, 2, 4, 2, 4, 3, 5, 2, 4, 2, 4, 3, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 5, 3, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2};
const prog_uchar button3[41] PROGMEM ={40, 1, 2, 4, 2, 4, 2, 4, 3, 5, 2, 4, 2, 4, 3, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 5, 3, 5, 3, 4, 2, 4, 2, 4, 2};
const prog_uchar button4[43] PROGMEM ={42, 1, 2, 4, 2, 4, 2, 4, 3, 5, 2, 4, 2, 4, 3, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 5, 3, 4, 2, 4, 2, 4, 2};
const prog_uchar button5[43] PROGMEM ={42, 1, 2, 4, 2, 4, 2, 4, 3, 5, 2, 4, 2, 4, 3, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 5, 2, 4, 3, 4, 2, 4, 2, 4, 2, 4, 2};
const prog_uchar button7[41] PROGMEM ={40, 1, 2, 4, 2, 4, 2, 4, 3, 5, 2, 4, 2, 4, 3, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 5, 3, 4, 2, 5, 3, 4, 2, 4, 2};
const prog_uchar button11[41] PROGMEM ={40, 1, 2, 4, 2, 4, 2, 4, 3, 5, 2, 4, 2, 4, 3, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 5, 3, 4, 2, 5, 2, 4, 3, 4, 2};

// pointers to command arrays
PROGMEM const prog_uchar *buttonPointer[] = {button1, button2, button3, button4, button5, button7, button11};

void setup() {

// sipmle example: send button "button2" once. Note that array elements numbered starting from "0" (so button1 is 0, button2 is 1 and so on)

txButton(1);

}

void loop() {
}

// transmitting part
// zeroes and ones here are not actual 0 and 1. I just called these pulses for my own convenience. 
// also note that I had to invert pulses to get everything working
// that said in actual command "start pulse" is long low; "zero" = short high; "one" = long high; "pause" is short low; "low" is long low.

void txButton(byte cmd) { 
prog_uchar *currentPointer = (prog_uchar *)pgm_read_word(&buttonPointer[cmd]); // current pointer to command array passed as txButton(cmd) argument
byte cmdCounter = pgm_read_byte(&currentPointer[0]); // read array length

for (pulse= 0; pulse <= 180; pulse = pulse+1) { // how many times to transmit a command
for (i = 1; i < cmdCounter+1; i = i + 1) { // counter for reading command array
  byte currentCmd = pgm_read_byte(&currentPointer[i]); // readpulse type from array
  switch(currentCmd) { // transmit pulse
   case 1: // start pulse
   digitalWrite(txPin, HIGH);
   delayMicroseconds(550);
   digitalWrite(txPin, LOW);
   break;
   case 2: // "zero"
   digitalWrite(txPin, LOW);
   delayMicroseconds(110);
   digitalWrite(txPin, HIGH);
   break;   
   case 3: // "one"
   digitalWrite(txPin, LOW);
   delayMicroseconds(303);
   digitalWrite(txPin, HIGH);
   break;      
   case 4: // "pause"
   digitalWrite(txPin, HIGH);
   delayMicroseconds(110);
   digitalWrite(txPin, LOW);
   break;      
   case 5: // "low"
   digitalWrite(txPin, HIGH);
   delayMicroseconds(290);
   digitalWrite(txPin, LOW);
   break;      
  } 
  }
 } 
 digitalWrite(txPin, LOW);
}

Have fun!

spch, quick question, I've done pretty much the same thing with rf remotes but have a problem, if I do a page refresh for whatever reason in the browser, the switches are retriggered again turning them off if they're on and vice versa, are u running your app in a browser and if so have you experienced the same thing and have you been able to correct it, how? Thanks much....

comptrmedic,

I’ve never experienced such an issue. I’m using web server as in RC-Switch example.

There are, however, certain browser issues. For example, when using Chrome, I need to type command two times to get it working (I guess that is the way Chrome’s cache is working). So when I need to use browser, I prefer Firefox over Chrome.

My best guess is that re-triggering happens because of browser’s cache. Try using another browser, or turning off cache (note that this could also slow down your normal browsing). If that doesn’t help, there may be something special about web server that is running on your Arduino.

ps. apart from browsers I use Tasker to for direct HTTP POST requests when I need to trigger a switch or change automation settings. I doesn’t require to load/reload pages and works flawlessly.

Recently I took another look at the waveform of Livolo remote. And as I had some time to spare, that is what I saw.

  1. Each keypress sends remote ID and a command itself (approximately 8000 us, repeated about 100 times or more)
  2. Remote ID is unique to the remote and never changes during transmission
  3. Each command can be represented by 24 pulses: long start pulse plus 23 data pulses (bits). Of that 23 bits 16 are remote ID and the rest are the command.
  4. I’ve compared commands (7 bit) of two remotes, and they look identical.

Regarding pulses to bits conversion. I took for granted that data pulses are:

  1. short highs (I took them as “0”)
  2. long highs and lows (excluding start pulse) (I took them as “1”). Right, “1” is therefore represented either by long high or long low - doesn’t matter

This approach gives exactly 24 pulses (including start) for all avaliable to me commands (buttons 1 to 0). Here is my vision of data packet structure:

Then I thought there must be some kind of a rule which pulses must follow. It looks like:

  1. Each data pulse is followed by short low pulse, excluding two long pulses in a row and single long low pulse which is followed by short high
  2. First long pulse (“1”) is always high, then they are interleaving.

I could have missed something, but first result is simplified code that takes about 200 bytes less memory when compiled for Mega.

Here is an example, which can be further improved (as there is no need to store in command arrays short low pulses):

#include <avr/pgmspace.h> // needed to use PROGMEM

#define  txPin  8 // pin connected to RF transmitter (pin 8)
byte i; // command pulses counter for Livolo (0 - 100)
byte pulse; // counter for command repeat

// commands stored in PROGMEM arrays (see on PROGMEM use here: http://arduino.cc/forum/index.php?topic=53240.0)
// first array element is length of command
const prog_uchar start[30] PROGMEM = {1, 2, 4, 2, 4, 2, 4, 3, 5, 2, 4, 2, 4, 3, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2}; // remote ID - no need to store it with each command
const prog_uchar button1[15] PROGMEM ={14, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2}; // only command bits
const prog_uchar button2[13] PROGMEM ={12, 5, 3, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2};
const prog_uchar button3[11] PROGMEM ={10, 5, 3, 5, 3, 4, 2, 4, 2, 4, 2};
const prog_uchar button4[13] PROGMEM ={12, 4, 2, 4, 2, 5, 3, 4, 2, 4, 2, 4, 2};
const prog_uchar button5[13] PROGMEM ={12, 5, 2, 4, 3, 4, 2, 4, 2, 4, 2, 4, 2};
const prog_uchar button7[11] PROGMEM ={10, 5, 3, 4, 2, 5, 3, 4, 2, 4, 2};
const prog_uchar button11[11] PROGMEM ={10, 5, 3, 4, 2, 5, 2, 4, 3, 4, 2};

// pointers to command arrays
PROGMEM const prog_uchar *buttonPointer[] = {start, button1, button2, button3, button4, button5, button7, button11};

void setup() {

// sipmle example: send button "button2" once. Note that array elements numbered starting from "0" (so button1 is 0, button2 is 1 and so on)
// Serial.begin(9600);


}

void loop() {

txButton(3);
delay(1000);
}

// transmitting part
// zeroes and ones here are not actual 0 and 1. I just called these pulses for my own convenience. 
// also note that I had to invert pulses to get everything working
// that said in actual command "start pulse" is long low; "zero" = short high; "one" = long high; "pause" is short low; "low" is long low.

void txButton(byte cmd) { 
prog_uchar *currentPointer = (prog_uchar *)pgm_read_word(&buttonPointer[cmd]); // current pointer to command array passed as txButton(cmd) argument
byte cmdCounter = pgm_read_byte(&currentPointer[0]); // read array length

prog_uchar *currentPointerStart = (prog_uchar *)pgm_read_word(&buttonPointer[0]); // current pointer to start command array


for (pulse= 0; pulse <= 180; pulse = pulse+1) { // how many times to transmit a command
for (i = 0; i<30; i=i+1) {

byte currentCmd = pgm_read_byte(&currentPointerStart[i]);
sendPulse(currentCmd);
// Serial.print(currentCmd);
// Serial.print(", ");
}


for (i = 1; i < cmdCounter+1; i = i + 1) { // counter for reading command array
  byte currentCmd = pgm_read_byte(&currentPointer[i]); // readpulse type from array

  sendPulse(currentCmd);
//  Serial.print(currentCmd);
// Serial.print(", ");
    }
  }
}

void sendPulse(byte txPulse) {

  switch(txPulse) { // transmit pulse
   case 1: // start pulse
   digitalWrite(txPin, HIGH);
   delayMicroseconds(550);
   digitalWrite(txPin, LOW);
   break;
   case 2: // "zero"
   digitalWrite(txPin, LOW);
   delayMicroseconds(110);
   digitalWrite(txPin, HIGH);
   break;   
   case 3: // "one"
   digitalWrite(txPin, LOW);
   delayMicroseconds(303);
   digitalWrite(txPin, HIGH);
   break;      
   case 4: // "pause"
   digitalWrite(txPin, HIGH);
   delayMicroseconds(110);
   digitalWrite(txPin, LOW);
   break;      
   case 5: // "low"
   digitalWrite(txPin, HIGH);
   delayMicroseconds(290);
   digitalWrite(txPin, LOW);
   break;      
  } 
 digitalWrite(txPin, LOW);
}

Hi spch I am following your post quite sometime after I bought livolo switch and face same problem. It is very useful information in your post and codes are working perfectly. What I am doing right now is, to have more codes ( I wanted around 20 codes to control 20 different switches) by doing try and error method on your codes. I have to admit that it is not successful at all. I cannot get even one more code. Is it possible to get more codes to control livolo switches and how?

Sorry, I am very new to RF and Arduino.

Regards

Hi, winnaing,

I'm new to Arduino/RF too ;)

Lately I've been a bit busy with debugging some pieces of code and other things, but I'm planning to rewrite Livolo code since I've studied waveforms more carefully. You could wait a bit, or modify code yourself. I hope the following information would be of use in case you choose the latter.

The key is that command consists of unique remote ID (never changes) and key code (they appear to be fixed too, but change depending on key pressed). So you only need to change remote ID to get more keys, and there are plenty of these "virtual remotes" as each remote ID is 16 bit. Additionally, it is highly probable that Livolo switches can learn key codes other than I've discovered by recording remotes. So there could be even more remote ID and key code combinations.

But the thing is that changing remote ID (or key code) requires following strict rules, i.e.: pulses must interleave, that is high pulse should be always followed by low pulse; two short pulses are "0" and every single long pulse (apart from start) is "1" or vice versa, it doesn't matter as long as you code them right.

Hi spch

Thanks for your reply. I follow your advice as follow:

1) I changed ID for a few combinations, not successful. 2) Yes, other third party remote can control the Livolo and I try to decode it, also not successful.

Maybe the way I did is not correct. By the way, what is interleave? :roll_eyes:

Regards

Winnaing,

I was pretty sure that I could say “interleaving” to describe a rule of high pulse following low pulse and vice versa. Sorry for bad English, if I got that wrong.

Here is more “user friendly” code. No more strange arrays full of strange numbers :wink: It requires only two values: Remote ID and a keycode of button to “press”.

There are three predefined working Remote IDs (and it is possible to use many more as long as Remote IDs are 16 bit), and 11 predefined buttons (and, maybe, it is possible to use any other as long as keycodes are 7 bit).

Bottom line: it should work. If it doesn’t, please tell me what went wrong and I’ll try to figure out how to fix it.

#define  txPin  8 // pin connected to RF transmitter (pin 8)
byte i; // just a counter
byte pulse; // counter for command repeat
boolean high = true; // pulse "sign"

// keycodes #1: 0, #2: 96, #3: 120, #4: 24, #5: 80, #6: 48, #7: 108, #8: 12, #9: 72; #10: 40, #OFF: 106
// real remote IDs: 6400; 19303
// tested "virtual" remote ID: 8500, other IDs could work too, as long as they do not exceed 16 bit
// known issue: not all 16 bit remote ID are valid
// have not tested other buttons, but as there is dimmer control, some keycodes could be strictly system
// use: sendButton(remoteID, keycode); 
// see void loop for an example of use

void setup() {


}

void loop() {

sendButton(6400, 120); // blink button #3 every 3 seconds using remote with remoteID #6400
delay(3000);

}

void sendButton(unsigned int remoteID, byte keycode) {

  for (pulse= 0; pulse <= 180; pulse = pulse+1) { // how many times to transmit a command
  sendPulse(1); // Start  
  high = true; // first pulse is always high

  for (i = 16; i>0; i--) { // transmit remoteID
    byte txPulse=bitRead(remoteID, i-1); // read bits from remote ID
    selectPulse(txPulse);    
    }

  for (i = 7; i>0; i--) { // transmit keycode
    byte txPulse=bitRead(keycode, i-1); // read bits from keycode
    selectPulse(txPulse);    
    }    
  }
   digitalWrite(txPin, LOW);
}

// build transmit sequence so that every high pulse is followed by low and vice versa

void selectPulse(byte inBit) {
  
      switch (inBit) {
      case 0: 
       for (byte ii=1; ii<3; ii++) {
        if (high == true) {   // if current pulse should be high, send High Zero
          sendPulse(2); 
        } else {              // else send Low Zero
                sendPulse(4);
        }
        high=!high; // invert next pulse
       }
        break;
      case 1:                // if current pulse should be high, send High One
        if (high == true) {
          sendPulse(3);
        } else {             // else send Low One
                sendPulse(5);
        }
        high=!high; // invert next pulse
        break;        
      }
}

// transmit pulses
// slightly corrected pulse length, use old (commented out) values if these not working for you

void sendPulse(byte txPulse) {

  switch(txPulse) { // transmit pulse
   case 1: // Start
   digitalWrite(txPin, HIGH);
   delayMicroseconds(500); // 550
   digitalWrite(txPin, LOW);
   break;
   case 2: // "High Zero"
   digitalWrite(txPin, LOW);
   delayMicroseconds(100); // 110
   digitalWrite(txPin, HIGH);
   break;   
   case 3: // "High One"
   digitalWrite(txPin, LOW);
   delayMicroseconds(300); // 303
   digitalWrite(txPin, HIGH);
   break;      
   case 4: // "Low Zero"
   digitalWrite(txPin, HIGH);
   delayMicroseconds(100); // 110
   digitalWrite(txPin, LOW);
   break;      
   case 5: // "Low One"
   digitalWrite(txPin, HIGH);
   delayMicroseconds(300); // 290
   digitalWrite(txPin, LOW);
   break;      
  } 
}

Hi spch

It is wonderful. All ID key are working. Thank you. :) I try to 'decode' your ID key but still don't understand and no luck. Anyway I try to digest your advice and try to look for other IDs. For the time being, 30 codes are enough for me.

Have you try Koti light switch? see http://www.aliexpress.com/store/529450 The good thing about these switches is that they are bicommunication; ie switch send back the feedback signal. So we know exactly if switch on or off. Whereas Livolo is not. Again, I have checked with supplier. They said their code is propitiatory and do not work with 3rd party RC. I don't have the talent to decode them. So I did not buy. Anybody ever decode them successfully?

Regards

Hello Winnaing,

Glad to know the code is working. Koti switches could use proprietary protocol (Livolo, by the way, does use its own proprietary protocol too) or they can use Z-Wave protocol as store name suggests. In the latter case you don’t need to decode anything as there are Z-wave modules for Arduino.

But if Koti switches use fixed codes just like Livolo, they can be decoded as well.

Thanks for decoding the Livolo protocol and your sketch, I already got it to work with my Livolo switches! I was wondering if there is any way to use the Livolo dimmers with your code?

Regards, Max