Recently it happened frequently that some of our friends needed to take their bikes inside our garden after a nerding night. It was a boring situation where we had to constantly find the remote, open the gate, wait for them to take their bikes and then open again. Well, it wasn’t so boring, but you know, we needed a reason.
So, we tought about our last project where we successfully made arduino talk with Raspy using NRF24L01+ and dumbly toggling lights. This time we decided to go a step further and open our gate using, guess what, our smartphones.
Learning
At first we tried to achieve our goal using the standard RCSwitch library (and sketches) to listen the original remote’s signal, but as you might imagined, we poorly failed.
The wiring was pretty simple:
Keeping in mind that we were working with a fixed combination remote, we initially guessed a number of different problematics, even that our receiver was not operating in the same frequency as the remote. After some attempts (where we’ve found the frequency was right by looking the quartz), we decided to hack a bit the original receiver sketch, forcing the arduino to receive the signals even if they were not conformed to the standard it used to know:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 |
/* Example for receiving http://code.google.com/p/rc-switch/ If you want to visualize a telegram copy the raw data and paste it into http://test.sui.li/oszi/ Need help? http://forum.ardumote.com Edited by hack.lenotta to force it receive to ‘everything’ and included all the files at once. http://hack.lenotta.com */ #include <RCSwitch.h> // Format the output: void output(unsigned long decimal, unsigned int length, unsigned int delay, unsigned int* raw, unsigned int protocol) { if (decimal == 0) { Serial.print("Unknown encoding."); } else { char* b = dec2binWzerofill(decimal, length); Serial.print("Decimal: "); Serial.print(decimal); Serial.print(" ("); Serial.print( length ); Serial.print("Bit) Binary: "); Serial.print( b ); Serial.print(" Tri-State: "); Serial.print( bin2tristate( b) ); Serial.print(" PulseLength: "); Serial.print(delay); Serial.print(" microseconds"); Serial.print(" Protocol: "); Serial.println(protocol); } Serial.print("Raw data: "); for (int i=0; i<= length*2; i++) { Serial.print(raw[i]); Serial.print(","); } Serial.println(); Serial.println(); } static char* bin2tristate(char* bin) { char returnValue[50]; int pos = 0; int pos2 = 0; while (bin[pos] != ' ' && bin[pos+1] != ' ') { if (bin[pos]=='0' && bin[pos+1]=='0') { returnValue[pos2] = '0'; } else if (bin[pos]=='1' && bin[pos+1]=='1') { returnValue[pos2] = '1'; } else if (bin[pos]=='0' && bin[pos+1]=='1') { returnValue[pos2] = 'F'; } else { return "not applicable"; } pos = pos+2; pos2++; } returnValue[pos2] = ' '; return returnValue; } // Make some conversions: static char * dec2binWzerofill(unsigned long Dec, unsigned int bitLength){ static char bin[64]; unsigned int i=0; while (Dec > 0) { bin[32+i++] = (Dec & 1 > 0) ? '1' : '0'; Dec = Dec >> 1; } for (unsigned int j = 0; j< bitLength; j++) { if (j >= bitLength - i) { bin[j] = bin[ 31 + i - (j - (bitLength - i)) ]; }else { bin[j] = '0'; } } bin[bitLength] = ' '; return bin; } //The edited code to force recevining data: RCSwitch mySwitch = RCSwitch(); void setup() { Serial.begin(9600); mySwitch.enableReceive(0); // Receiver on inerrupt 0 => that is pin #2 } void loop() { output(mySwitch.getReceivedValue(), mySwitch.getReceivedBitlength(), mySwitch.getReceivedDelay(), mySwitch.getReceivedRawdata(),mySwitch.getReceivedProtocol()); mySwitch.resetAvailable(); } |
When we’ve uploaded the sketch we were able to see some raw messages. Actually, they were not messages, but these numbers on the serial monitor represent the interval between the changes of state (from 0 to 1 and reverse).
1 2 3 4 5 6 7 8 9 10 11 12 13 |
Unknown encoding.Raw data: 72, Unknown encoding.Raw data: 668, Unknown encoding.Raw data: 124, Unknown encoding.Raw data: 48, Unknown encoding.Raw data: 264, Unknown encoding.Raw data: 12, Unknown encoding.Raw data: 88 |
I suppose these numbers being just a representation of the signal noise. So, while listening with the arduino, we’ve pressed the button on the remote and BABOOM, here is what came out:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
Unknown encoding.Raw data: 204, Unknown encoding.Raw data: 40, Unknown encoding.Raw data: 76, Unknown encoding.Raw data: 11660, Unknown encoding.Raw data: 11668, Unknown encoding.Raw data: 11672,328,648,324,316,668,316,656,644,324,316,660,316,668,316,656,320,652,652,324,652,328,652,320,648, Unknown encoding.Raw data: 11676,324,648,324,316,664,320,652,652,316,320,660,316,664,320,652,320,656,652,324,652,328,652,316,652, Unknown encoding.Raw data: 11676,324,648,324,316,664,320,652,652,316,320,660,316,664,320,652,320,656,652,320,656,324,652,320,652, Unknown encoding.Raw data: 11676,324,648,324,316,664,320,652,652,316,320,660,316,664,320,652,320,652,656,320,652,328,652,316,656, Unknown encoding.Raw data: 11676,324,648,324,316,664,320,652,652,316,320,660,320,660,320,652,320,656,652,320,656,328,652,316,656, Unknown encoding.Raw data: 11672,324,648,324,316,668,316,656,648,316,320,660,316,664,320,652,320,652,652,324,652,328,656,316,652, Unknown encoding.Raw data: 11672,324,652,320,320,664,316,656,648,320,320,660,320,664,316,656,320,656,652,320,656,324,652,316,652, |
A lot of very nice numbers… What helped a lot understand what was going on was the link in the arduino sketch which translate these numbers in a more understandable form (yes, it’s a squared wave):
As you may noticed, the values (in microsecond), except for the first one being really long, are doubles of ~320 µs. I suggest to approximate the unit value (in our case 320 µs ) to the average of one interval, since the signal is surely disturbed by the uninsulated components of the arduino, and because of the usb cable, even by your bad boy computer.
Tuning and Speaking
Once we successfully received the message we had to send it back to the gate. We tried to use the message raughly received by the arduino, but we found out that we had to tune it a bit to make it work, maybe because of some latency or noise.
We setted up a try/guess environment (pic above) with two arduinos, one with the 433 Mhz receiver we’ve setted up earlier and the other one with the twin transmitter module. We kept editing and sending the message untill we obtained the same message on the receiver as we were getting by the original remote.
In this process we’ve found out two important fact:
1- The initial long length (11672 µs in our case) was received completely wrong, while the others were in the range of ±20
2- Our message was not completely transmitted (it was actually missing the last 3~4 intervals)
For the first problem we just tuned it easily with some tries, but the other was a little bit more complicated, which we roughly solved by sending multiple times the last intervals (if you have any better solution feel free to suggest!). Remember that to avoid misinterpretation by the gate receiver, the message has to be sent by the arduino at least 4 times.
Please note that some part of this sketch are taken from another sketch which we don’t remember where we took. If you are the author, please send us a mail with the link to your website and we’ll be glad to write your name and a backlink.
After all the final sketch resulted as following:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 |
/* Transmitter opening fixed combination gates http://hack.lenotta.com CC-BY-SA */ int transmitPin = 2; void setup() { pinMode(transmitPin,OUTPUT); digitalWrite(transmitPin,LOW); } void loop() { turnOn(); } //let’s build our instruments: void customDelay(unsigned long time) { unsigned long end_time = micros() + time; while(micros() < end_time); } //1000=1ms void setStateWithDelay(int pin, int state,int delayTime) { if(state==1) digitalWrite(pin,HIGH); else digitalWrite(pin,LOW); customDelay(delayTime); } void turnOn() { setStateWithDelay(transmitPin,0,10972); setStateWithDelay(transmitPin,1,320); setStateWithDelay(transmitPin,0,630); setStateWithDelay(transmitPin,1,320); setStateWithDelay(transmitPin,0,320); setStateWithDelay(transmitPin,1,630); setStateWithDelay(transmitPin,0,320); setStateWithDelay(transmitPin,1,630); setStateWithDelay(transmitPin,0,630); setStateWithDelay(transmitPin,1,320); setStateWithDelay(transmitPin,0,320); setStateWithDelay(transmitPin,1,630); setStateWithDelay(transmitPin,0,320); setStateWithDelay(transmitPin,1,630); setStateWithDelay(transmitPin,0,320); setStateWithDelay(transmitPin,1,630); setStateWithDelay(transmitPin,0,320); setStateWithDelay(transmitPin,1,630); setStateWithDelay(transmitPin,0,630); setStateWithDelay(transmitPin,1,320); setStateWithDelay(transmitPin,0,630); setStateWithDelay(transmitPin,1,320); setStateWithDelay(transmitPin,0,630); setStateWithDelay(transmitPin,1,320); setStateWithDelay(transmitPin,0,630); setStateWithDelay(transmitPin,1,320); setStateWithDelay(transmitPin,0,630); digitalWrite(transmitPin,LOW); } |
Raspberry Integration
As I said at the beginning, the whole project was meant to give our friends access to their bike with their smartphones, so we decided to use the previous project we made about switching light using a node.js web app.
Sketching
The sketch is pretty easy and it’s a mix from the switching light post and the one we’ve used to open the gate:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 |
/* Hack.lenotta.com Modified code of Getting Started RF24 Library It will open the gate if the message received is 2 Edo */ #include <SPI.h> #include "nRF24L01.h" #include "RF24.h" #include "printf.h" int transmitPin = 2; // // Hardware conf // // Set up nRF24L01 radio on SPI bus plus pins 9 & 10 RF24 radio(9,10); // // Topology // // Radio pipe addresses for the 2 nodes to communicate. const uint64_t pipes[2] = { 0xF0F0F0F0E1LL, 0xF0F0F0F0D2LL }; void setup(void) { // // Print preamble // Serial.begin(57600); pinMode(transmitPin,OUTPUT); digitalWrite(transmitPin,LOW); printf_begin(); printf("nOpen Gate With Arduinonr"); // // Setup and configure rf radio // radio.begin(); radio.setRetries(15,15); radio.openWritingPipe(pipes[0]); radio.openReadingPipe(1,pipes[1]); radio.startListening(); radio.printDetails(); } void openGates(){ for (int i =0; i<20; i++){ gateCode(); } } void customDelay(unsigned long time) { unsigned long end_time = micros() + time; while(micros() < end_time); } //1000=1ms void setStateWithDelay(int pin, int state,int delayTime) { if(state==1) digitalWrite(pin,HIGH); else digitalWrite(pin,LOW); customDelay(delayTime); } void gateCode() { //your decodified gate code goes here, like the following: // setStateWithDelay(transmitPin,0,10972); // setStateWithDelay(transmitPin,1,320); // setStateWithDelay(transmitPin,0,630); // setStateWithDelay(transmitPin,1,320); // setStateWithDelay(transmitPin,0,320); // setStateWithDelay(transmitPin,1,630); // setStateWithDelay(transmitPin,0,320); // setStateWithDelay(transmitPin,1,630); // setStateWithDelay(transmitPin,0,630); // setStateWithDelay(transmitPin,1,320); // setStateWithDelay(transmitPin,0,320); // setStateWithDelay(transmitPin,1,630); // setStateWithDelay(transmitPin,0,320); // setStateWithDelay(transmitPin,1,630); // setStateWithDelay(transmitPin,0,320); // setStateWithDelay(transmitPin,1,630); // setStateWithDelay(transmitPin,0,320); // setStateWithDelay(transmitPin,1,630); // setStateWithDelay(transmitPin,0,630); // setStateWithDelay(transmitPin,1,320); // setStateWithDelay(transmitPin,0,630); // setStateWithDelay(transmitPin,1,320); // setStateWithDelay(transmitPin,0,630); // setStateWithDelay(transmitPin,1,320); // setStateWithDelay(transmitPin,0,630); // // setStateWithDelay(transmitPin,1,320); // setStateWithDelay(transmitPin,0,630); digitalWrite(transmitPin,LOW); } void loop(void) { // if there is data ready if ( radio.available() ) { // Dump the payloads until we've gotten everything unsigned long message; bool done = false; while (!done) { // Fetch the payload, and see if this was the last one. done = radio.read( &message, sizeof(unsigned long) ); if (message == 2){ openGates(); } // Delay just a little bit to let the other unit // make the transition to receiver delay(20); } // First, stop listening so we can talk radio.stopListening(); // Send the final one back. radio.write( &message, sizeof(unsigned long) ); printf("Sent response.nr"); // Now, resume listening so we catch the next packets. radio.startListening(); } } |
Wiring
For the wirings, refer to the following picture:
Node application for Raspberry
Since we recently upgraded all the software, we could easily adapt our previous application to the new shiny remote. Here is the link to the Github repo.
To install it please follow the instruction on the switching light article, in particular the The Node.js Lamp Application section.
Nice work, Have you ever done any work with an RFduino and accelerometer?
Hi, thanks, never done anything with RFduino, sorry!
Hi, I tried your code and I get different values when I press my remote (so not the random noise values). However, running the rc-switch advanced sketch, gives me nothing.
Do you have any pointers on how I could proceed decoding my remote?
Thanks,
Sam
Is it the right rf module for your remote? Same frequency?
which program did you used to create “Squared wave” picture?
Link it’s in the Arduino sketch.
thank you very much dude
I know nothing about how you did it but I appreciate that you do these things and make cheeky videos, Edo.
Xoxo,
Hanna
Hello Edoardo, I’m writing a little course on Arduino. Could I insert your link in my lesson? I have a remote controller with a similar coded transmission but a little different from your so I want to cite you about the use of RCSwitch library to receive raw info and decode it.
Sure, no problem!
Thank you! You can find it in a pair of days at my website clicking on my name 🙂
Hi Guys,
Great project!
I’m new to the programming game but wanted to give this a go.
Would it be feasible to try this using an ‘Onion Omega’ with a transmitter module?!
I can get the gate code from my SDR (software defined radio) USB stick.
I’m only learning c# at the moment, do you think I could use this through Linux to broadcast the code?!
Cheers guys!
John
Hi,
yes , a onion omega is certainly a good solution, wasn’t available at the time of the writing. You would still need a 433 mhz TX module.
C# (Microsoft) on linux is something I wouldn’t dare to try, basically because of compatibility issues you may find.
Since you are managing to do it with an onion, I would suggest to put a little web server on the onion and building some basic RESTful APIs ( example: “http://192.onionIp.10.2/gate0/open”) .
That sounds even better!
Looking forward to working it out!
That link is down though (http://192.onionIp.10.2/gate0/open)
any other suggestions for where to get some example code?!
Hi, and congratulations for this tutorial which permitted me to improve my project (which is almost the same as yours !). Can you tell the brand/reference of your original remote/garage door, so that I may see if mine is compatible with your work ? Because as far as I’ve read, my remote (a came top 432na) does not use the protocol you implement here (or maybe am I just too much tired). Thanks for your reply.
My remote it’s just a common 433Mhz NOT rolling combination model, compatible chinese version 😀
Apparently the solution is to replace ” with ”
Hope this helps other people.
That was supposed to say
replace ” with ‘\’ ie. backslash zero.
Hi! Would you point me to the file and the line of code please? Just so I can correct it if there’s a typo. Many thanks and hope you enjoy it.
I also have the same mistakes at line 54, 67, 89
“empty character constant”
I think the problem are the quotes, but replaces them with those twins, generate more errors … did you find the solution?
Thanks
bye bye
Ok, thanks, I solved,
replace the ‘ ‘ (at line 54, 54, 67, 89) with ‘′
bye bye
I tried compiling the first sketch with Arduino IDE 1.0.5 however I’m getting these errors
Receive.pde:54:22: error: empty character constant
Receive.pde:54:42: error: empty character constant
Receive.pde:67:23: error: empty character constant
Receive.pde:89:20: error: empty character constant
It appears it’s complaining about lines like these
while (bin[pos] != ” && bin[pos+1] != ”) {
Any idea how to fix that ?
Hey… Turn a Space between the ‘ ‘. This fix the Problem in Line 54,67 and 89 🙂
Thank you, I’ve updated the code.
Hello guys, very good article. I have some problems with receiving . I got a lot of noise, i use the same rx tx kit as you 😉 did you notice some problems with it ?
Thank you! Actually nope, no noise, but a lot of things today are running on 433Mhz (radio, weather stations, remote AC switch …).
@disak, I could turn down the noise by using 3.3V instead of 5V on the receiver VCC.
@edoardo, do you have any information on how to tackle a device with a “rolling code”?
No, sorry, I’ve been trying to find it for a long time. If you can find anything please share.
A dirty hack would be to buy a cheap chinese rolling code remote and trigger its button from arduino.