├── codesend ├── .DS_Store ├── RFSniffer ├── RFSource ├── .DS_Store ├── RCSwitch.h ├── RCSwitch.o ├── RFSniffer.o ├── codesend.o ├── Makefile ├── RFSniffer.cpp ├── send.cpp ├── codesend.cpp └── RCSwitch.cpp ├── script.js ├── README.md ├── toggle.php └── index.html /codesend: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timleland/rfoutlet/master/codesend -------------------------------------------------------------------------------- /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timleland/rfoutlet/master/.DS_Store -------------------------------------------------------------------------------- /RFSniffer: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timleland/rfoutlet/master/RFSniffer -------------------------------------------------------------------------------- /RFSource/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timleland/rfoutlet/master/RFSource/.DS_Store -------------------------------------------------------------------------------- /RFSource/RCSwitch.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timleland/rfoutlet/master/RFSource/RCSwitch.h -------------------------------------------------------------------------------- /RFSource/RCSwitch.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timleland/rfoutlet/master/RFSource/RCSwitch.o -------------------------------------------------------------------------------- /RFSource/RFSniffer.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timleland/rfoutlet/master/RFSource/RFSniffer.o -------------------------------------------------------------------------------- /RFSource/codesend.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timleland/rfoutlet/master/RFSource/codesend.o -------------------------------------------------------------------------------- /RFSource/Makefile: -------------------------------------------------------------------------------- 1 | all: send codesend RFSniffer 2 | 3 | send: RCSwitch.o send.o 4 | $(CXX) $(CXXFLAGS) $(LDFLAGS) $+ -o $@ -lwiringPi 5 | 6 | codesend: RCSwitch.o codesend.o 7 | $(CXX) $(CXXFLAGS) $(LDFLAGS) $+ -o $@ -lwiringPi 8 | 9 | RFSniffer: RCSwitch.o RFSniffer.o 10 | $(CXX) $(CXXFLAGS) $(LDFLAGS) $+ -o $@ -lwiringPi 11 | 12 | 13 | clean: 14 | $(RM) *.o send codesend servo RFSniffer -------------------------------------------------------------------------------- /script.js: -------------------------------------------------------------------------------- 1 | var toggleOutlet = function(buttonClicked) { 2 | $.post('toggle.php', { 3 | outletId: buttonClicked.attr('data-outletId'), 4 | outletStatus: buttonClicked.attr('data-outletStatus') 5 | }, 6 | function(data, status) { 7 | //alert('Outlet toggled!'); 8 | }); 9 | 10 | }; 11 | 12 | $(function() { 13 | $('.toggleOutlet').click(function() { 14 | toggleOutlet($(this)); 15 | }); 16 | }); -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | #### 433Mhz RF Wireless Power Outlets 2 | 3 | Have you ever wanted to wirelessly control power outlets from your phone using a Raspberry Pi? 4 | 5 | **Blog Post:** [TimLeland.com/wireless-power-outlets](https://timleland.com/wireless-power-outlets/) 6 | 7 | Voice Control Outlets (Follow up Guides) 8 | * [Siri using HomeBridge](https://timleland.com/use-siri-to-control-wireless-power-outlets-homebridge/) 9 | * [Google Home](https://timleland.com/use-google-home-to-control-wireless-power-outlets/) 10 | * [Amazon Echo](https://timleland.com/use-amazon-echo-to-control-wireless-power-outlets/) 11 | 12 | ![Screenshot](http://i0.wp.com/timleland.com/wp-content/uploads/2014/12/15721754859_1301df94c1_o-e1417497266426-225x300.jpg?resize=225%2C300) 13 | 14 | 15 | [Featured in Wired Magazine](http://www.wired.co.uk/magazine/archive/2016/05/how-to/raspberry-pi-power-outlets-tutorial) 16 | ![Screenshot](https://i1.wp.com/timleland.com/wp-content/uploads/2014/12/Wired.jpg?zoom=2&resize=750%2C410&ssl=1) 17 | -------------------------------------------------------------------------------- /RFSource/RFSniffer.cpp: -------------------------------------------------------------------------------- 1 | #include "RCSwitch.h" 2 | #include 3 | #include 4 | 5 | 6 | RCSwitch mySwitch; 7 | 8 | 9 | 10 | int main(int argc, char *argv[]) { 11 | 12 | // This pin is not the first pin on the RPi GPIO header! 13 | // Consult https://projects.drogon.net/raspberry-pi/wiringpi/pins/ 14 | // for more information. 15 | int PIN = 2; 16 | 17 | if(wiringPiSetup() == -1) 18 | return 0; 19 | 20 | mySwitch = RCSwitch(); 21 | mySwitch.enableReceive(PIN); // Receiver on inerrupt 0 => that is pin #2 22 | 23 | 24 | while(1) { 25 | 26 | if (mySwitch.available()) { 27 | 28 | int value = mySwitch.getReceivedValue(); 29 | 30 | if (value == 0) { 31 | printf("Unknown encoding"); 32 | } else { 33 | printf("Received %i\n", mySwitch.getReceivedValue() ); 34 | //Show pulse(Depends on your RF outlet device. You may need to change the pulse on codesend.cpp) 35 | printf("Received pulse %i\n", mySwitch.getReceivedDelay() ); 36 | } 37 | 38 | mySwitch.resetAvailable(); 39 | 40 | } 41 | 42 | 43 | } 44 | 45 | exit(0); 46 | 47 | 48 | } 49 | -------------------------------------------------------------------------------- /RFSource/send.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Usage: ./send 3 | Command is 0 for OFF and 1 for ON 4 | */ 5 | 6 | #include "RCSwitch.h" 7 | #include 8 | #include 9 | 10 | int main(int argc, char *argv[]) { 11 | 12 | /* 13 | output PIN is hardcoded for testing purposes 14 | see https://projects.drogon.net/raspberry-pi/wiringpi/pins/ 15 | for pin mapping of the raspberry pi GPIO connector 16 | */ 17 | int PIN = 0; 18 | char* systemCode = argv[1]; 19 | int unitCode = atoi(argv[2]); 20 | int command = atoi(argv[3]); 21 | 22 | if (wiringPiSetup () == -1) return 1; 23 | printf("sending systemCode[%s] unitCode[%i] command[%i]\n", systemCode, unitCode, command); 24 | RCSwitch mySwitch = RCSwitch(); 25 | mySwitch.enableTransmit(PIN); 26 | 27 | switch(command) { 28 | case 1: 29 | mySwitch.switchOn(systemCode, unitCode); 30 | break; 31 | case 0: 32 | mySwitch.switchOff(systemCode, unitCode); 33 | break; 34 | default: 35 | printf("command[%i] is unsupported\n", command); 36 | return -1; 37 | } 38 | return 0; 39 | } 40 | -------------------------------------------------------------------------------- /toggle.php: -------------------------------------------------------------------------------- 1 | array( 8 | "on" => 349491, 9 | "off" => 349500 10 | ), 11 | "2" => array( 12 | "on" => 349635, 13 | "off" => 349644 14 | ), 15 | "3" => array( 16 | "on" => 349955, 17 | "off" => 349964 18 | ), 19 | "4" => array( 20 | "on" => 351491, 21 | "off" => 351500 22 | ), 23 | "5" => array( 24 | "on" => 357635, 25 | "off" => 357644 26 | ), 27 | ); 28 | 29 | // Path to the codesend binary (current directory is the default) 30 | $codeSendPath = './codesend'; 31 | 32 | // This PIN is not the first PIN on the Raspberry Pi GPIO header! 33 | // Consult https://projects.drogon.net/raspberry-pi/wiringpi/pins/ 34 | // for more information. 35 | $codeSendPIN = "0"; 36 | 37 | // Pulse length depends on the RF outlets you are using. Use RFSniffer to see what pulse length your device uses. 38 | $codeSendPulseLength = "189"; 39 | 40 | if (!file_exists($codeSendPath)) { 41 | error_log("$codeSendPath is missing, please edit the script", 0); 42 | die(json_encode(array('success' => false))); 43 | } 44 | 45 | $outletLight = $_POST['outletId']; 46 | $outletStatus = $_POST['outletStatus']; 47 | 48 | if ($outletLight == "6") { 49 | // 6 is all 5 outlets combined 50 | if (function_exists('array_column')) { 51 | // PHP >= 5.5 52 | $codesToToggle = array_column($codes, $outletStatus); 53 | } else { 54 | $codesToToggle = array(); 55 | foreach ($codes as $outletCodes) { 56 | array_push($codesToToggle, $outletCodes[$outletStatus]); 57 | } 58 | } 59 | } else { 60 | // One 61 | $codesToToggle = array($codes[$outletLight][$outletStatus]); 62 | } 63 | 64 | foreach ($codesToToggle as $codeSendCode) { 65 | shell_exec($codeSendPath . ' ' . $codeSendCode . ' -p ' . $codeSendPIN . ' -l ' . $codeSendPulseLength); 66 | sleep(1); 67 | } 68 | 69 | die(json_encode(array('success' => true))); 70 | ?> 71 | -------------------------------------------------------------------------------- /RFSource/codesend.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "RCSwitch.h" 6 | 7 | #define DEFAULT_PIN 0 8 | #define DEFAULT_PULSE_LENGTH 189 9 | 10 | void printUsage(char *argv[]) { 11 | printf("Usage: %s [-p (default: %i)] [-l (default: %i)].\n", argv[0], DEFAULT_PIN, DEFAULT_PULSE_LENGTH); 12 | } 13 | 14 | int main(int argc, char *argv[]) { 15 | int i; 16 | 17 | char * argumentPIN = NULL; 18 | char * argumentPulseLength = NULL; 19 | 20 | int c; 21 | while ((c = getopt(argc, argv, "p:l:")) != -1) { 22 | switch (c) { 23 | case 'p': 24 | argumentPIN = optarg; 25 | break; 26 | 27 | case 'l': 28 | argumentPulseLength = optarg; 29 | break; 30 | 31 | case '?': 32 | default: 33 | printUsage(argv); 34 | break; 35 | } 36 | } 37 | 38 | 39 | // This PIN is not the first PIN on the Raspberry Pi GPIO header! 40 | // Consult https://projects.drogon.net/raspberry-pi/wiringpi/pins/ 41 | // for more information. 42 | int PIN = DEFAULT_PIN; 43 | 44 | if (argumentPIN != NULL) { 45 | PIN = atoi(argumentPIN); 46 | } 47 | 48 | /* Now set the values of "argc" and "argv" to the values after the 49 | options have been processed, above. */ 50 | argc -= optind; 51 | 52 | if (argc == 0) { 53 | printUsage(argv); 54 | return EXIT_FAILURE; 55 | } 56 | 57 | argv += optind; 58 | 59 | // Parse the first parameter to this command as an integer 60 | int code = atoi(argv[0]); 61 | 62 | if (wiringPiSetup () == -1) { 63 | return EXIT_FAILURE; 64 | } 65 | 66 | // Pulse length depends on the RF outlets you are using. Use RFSniffer to see what pulse length your device uses. 67 | int pulseLength = DEFAULT_PULSE_LENGTH; 68 | 69 | if (argumentPulseLength != NULL) { 70 | pulseLength = atoi(argumentPulseLength); 71 | } 72 | 73 | printf("Sending Code: %i. PIN: %i. Pulse Length: %i\n", code, PIN, pulseLength); 74 | 75 | RCSwitch mySwitch = RCSwitch(); 76 | mySwitch.setPulseLength(pulseLength); 77 | mySwitch.enableTransmit(PIN); 78 | mySwitch.send(code, 24); 79 | 80 | return EXIT_SUCCESS; 81 | } 82 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | RF Outlets 9 | 10 | 15 | 16 | 17 | 18 | 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 | -------------------------------------------------------------------------------- /RFSource/RCSwitch.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | RCSwitch - Arduino libary for remote control outlet switches 3 | Copyright (c) 2011 Suat Özgür. All right reserved. 4 | 5 | Contributors: 6 | - Andre Koehler / info(at)tomate-online(dot)de 7 | - Gordeev Andrey Vladimirovich / gordeev(at)openpyro(dot)com 8 | - Skineffect / http://forum.ardumote.com/viewtopic.php?f=2&t=48 9 | 10 | Project home: http://code.google.com/p/rc-switch/ 11 | 12 | This library is free software; you can redistribute it and/or 13 | modify it under the terms of the GNU Lesser General Public 14 | License as published by the Free Software Foundation; either 15 | version 2.1 of the License, or (at your option) any later version. 16 | 17 | This library is distributed in the hope that it will be useful, 18 | but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 20 | Lesser General Public License for more details. 21 | 22 | You should have received a copy of the GNU Lesser General Public 23 | License along with this library; if not, write to the Free Software 24 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 25 | */ 26 | 27 | #include "RCSwitch.h" 28 | 29 | unsigned long RCSwitch::nReceivedValue = NULL; 30 | unsigned int RCSwitch::nReceivedBitlength = 0; 31 | unsigned int RCSwitch::nReceivedDelay = 0; 32 | unsigned int RCSwitch::nReceivedProtocol = 0; 33 | unsigned int RCSwitch::timings[RCSWITCH_MAX_CHANGES]; 34 | int RCSwitch::nReceiveTolerance = 60; 35 | 36 | RCSwitch::RCSwitch() { 37 | this->nReceiverInterrupt = -1; 38 | this->nTransmitterPin = -1; 39 | RCSwitch::nReceivedValue = NULL; 40 | this->setPulseLength(350); 41 | this->setRepeatTransmit(10); 42 | this->setReceiveTolerance(60); 43 | this->setProtocol(1); 44 | } 45 | 46 | /** 47 | * Sets the protocol to send. 48 | */ 49 | void RCSwitch::setProtocol(int nProtocol) { 50 | this->nProtocol = nProtocol; 51 | if (nProtocol == 1){ 52 | this->setPulseLength(350); 53 | } 54 | else if (nProtocol == 2) { 55 | this->setPulseLength(650); 56 | } 57 | } 58 | 59 | /** 60 | * Sets the protocol to send with pulse length in microseconds. 61 | */ 62 | void RCSwitch::setProtocol(int nProtocol, int nPulseLength) { 63 | this->nProtocol = nProtocol; 64 | if (nProtocol == 1){ 65 | this->setPulseLength(nPulseLength); 66 | } 67 | else if (nProtocol == 2) { 68 | this->setPulseLength(nPulseLength); 69 | } 70 | } 71 | 72 | 73 | /** 74 | * Sets pulse length in microseconds 75 | */ 76 | void RCSwitch::setPulseLength(int nPulseLength) { 77 | this->nPulseLength = nPulseLength; 78 | } 79 | 80 | /** 81 | * Sets Repeat Transmits 82 | */ 83 | void RCSwitch::setRepeatTransmit(int nRepeatTransmit) { 84 | this->nRepeatTransmit = nRepeatTransmit; 85 | } 86 | 87 | /** 88 | * Set Receiving Tolerance 89 | */ 90 | void RCSwitch::setReceiveTolerance(int nPercent) { 91 | RCSwitch::nReceiveTolerance = nPercent; 92 | } 93 | 94 | 95 | /** 96 | * Enable transmissions 97 | * 98 | * @param nTransmitterPin Arduino Pin to which the sender is connected to 99 | */ 100 | void RCSwitch::enableTransmit(int nTransmitterPin) { 101 | this->nTransmitterPin = nTransmitterPin; 102 | pinMode(this->nTransmitterPin, OUTPUT); 103 | } 104 | 105 | /** 106 | * Disable transmissions 107 | */ 108 | void RCSwitch::disableTransmit() { 109 | this->nTransmitterPin = -1; 110 | } 111 | 112 | /** 113 | * Switch a remote switch on (Type C Intertechno) 114 | * 115 | * @param sFamily Familycode (a..f) 116 | * @param nGroup Number of group (1..4) 117 | * @param nDevice Number of device (1..4) 118 | */ 119 | void RCSwitch::switchOn(char sFamily, int nGroup, int nDevice) { 120 | this->sendTriState( this->getCodeWordC(sFamily, nGroup, nDevice, true) ); 121 | } 122 | 123 | /** 124 | * Switch a remote switch off (Type C Intertechno) 125 | * 126 | * @param sFamily Familycode (a..f) 127 | * @param nGroup Number of group (1..4) 128 | * @param nDevice Number of device (1..4) 129 | */ 130 | void RCSwitch::switchOff(char sFamily, int nGroup, int nDevice) { 131 | this->sendTriState( this->getCodeWordC(sFamily, nGroup, nDevice, false) ); 132 | } 133 | 134 | /** 135 | * Switch a remote switch on (Type B with two rotary/sliding switches) 136 | * 137 | * @param nAddressCode Number of the switch group (1..4) 138 | * @param nChannelCode Number of the switch itself (1..4) 139 | */ 140 | void RCSwitch::switchOn(int nAddressCode, int nChannelCode) { 141 | this->sendTriState( this->getCodeWordB(nAddressCode, nChannelCode, true) ); 142 | } 143 | 144 | /** 145 | * Switch a remote switch off (Type B with two rotary/sliding switches) 146 | * 147 | * @param nAddressCode Number of the switch group (1..4) 148 | * @param nChannelCode Number of the switch itself (1..4) 149 | */ 150 | void RCSwitch::switchOff(int nAddressCode, int nChannelCode) { 151 | this->sendTriState( this->getCodeWordB(nAddressCode, nChannelCode, false) ); 152 | } 153 | 154 | /** 155 | * Switch a remote switch on (Type A with 10 pole DIP switches) 156 | * 157 | * @param sGroup Code of the switch group (refers to DIP switches 1..5 where "1" = on and "0" = off, if all DIP switches are on it's "11111") 158 | * @param nChannelCode Number of the switch itself (1..4) 159 | */ 160 | void RCSwitch::switchOn(char* sGroup, int nChannel) { 161 | this->sendTriState( this->getCodeWordA(sGroup, nChannel, true) ); 162 | } 163 | 164 | /** 165 | * Switch a remote switch off (Type A with 10 pole DIP switches) 166 | * 167 | * @param sGroup Code of the switch group (refers to DIP switches 1..5 where "1" = on and "0" = off, if all DIP switches are on it's "11111") 168 | * @param nChannelCode Number of the switch itself (1..4) 169 | */ 170 | void RCSwitch::switchOff(char* sGroup, int nChannel) { 171 | this->sendTriState( this->getCodeWordA(sGroup, nChannel, false) ); 172 | } 173 | 174 | /** 175 | * Returns a char[13], representing the Code Word to be send. 176 | * A Code Word consists of 9 address bits, 3 data bits and one sync bit but in our case only the first 8 address bits and the last 2 data bits were used. 177 | * A Code Bit can have 4 different states: "F" (floating), "0" (low), "1" (high), "S" (synchronous bit) 178 | * 179 | * +-------------------------------+--------------------------------+-----------------------------------------+-----------------------------------------+----------------------+------------+ 180 | * | 4 bits address (switch group) | 4 bits address (switch number) | 1 bit address (not used, so never mind) | 1 bit address (not used, so never mind) | 2 data bits (on|off) | 1 sync bit | 181 | * | 1=0FFF 2=F0FF 3=FF0F 4=FFF0 | 1=0FFF 2=F0FF 3=FF0F 4=FFF0 | F | F | on=FF off=F0 | S | 182 | * +-------------------------------+--------------------------------+-----------------------------------------+-----------------------------------------+----------------------+------------+ 183 | * 184 | * @param nAddressCode Number of the switch group (1..4) 185 | * @param nChannelCode Number of the switch itself (1..4) 186 | * @param bStatus Wether to switch on (true) or off (false) 187 | * 188 | * @return char[13] 189 | */ 190 | char* RCSwitch::getCodeWordB(int nAddressCode, int nChannelCode, boolean bStatus) { 191 | int nReturnPos = 0; 192 | static char sReturn[13]; 193 | 194 | const char* code[5] = { "FFFF", "0FFF", "F0FF", "FF0F", "FFF0" }; 195 | if (nAddressCode < 1 || nAddressCode > 4 || nChannelCode < 1 || nChannelCode > 4) { 196 | return '\0'; 197 | } 198 | for (int i = 0; i<4; i++) { 199 | sReturn[nReturnPos++] = code[nAddressCode][i]; 200 | } 201 | 202 | for (int i = 0; i<4; i++) { 203 | sReturn[nReturnPos++] = code[nChannelCode][i]; 204 | } 205 | 206 | sReturn[nReturnPos++] = 'F'; 207 | sReturn[nReturnPos++] = 'F'; 208 | sReturn[nReturnPos++] = 'F'; 209 | 210 | if (bStatus) { 211 | sReturn[nReturnPos++] = 'F'; 212 | } else { 213 | sReturn[nReturnPos++] = '0'; 214 | } 215 | 216 | sReturn[nReturnPos] = '\0'; 217 | 218 | return sReturn; 219 | } 220 | 221 | 222 | /** 223 | * Like getCodeWord (Type A) 224 | */ 225 | char* RCSwitch::getCodeWordA(char* sGroup, int nChannelCode, boolean bStatus) { 226 | int nReturnPos = 0; 227 | static char sReturn[13]; 228 | 229 | const char* code[6] = { "FFFFF", "0FFFF", "F0FFF", "FF0FF", "FFF0F", "FFFF0" }; 230 | 231 | if (nChannelCode < 1 || nChannelCode > 5) { 232 | return '\0'; 233 | } 234 | 235 | for (int i = 0; i<5; i++) { 236 | if (sGroup[i] == '0') { 237 | sReturn[nReturnPos++] = 'F'; 238 | } else if (sGroup[i] == '1') { 239 | sReturn[nReturnPos++] = '0'; 240 | } else { 241 | return '\0'; 242 | } 243 | } 244 | 245 | for (int i = 0; i<5; i++) { 246 | sReturn[nReturnPos++] = code[ nChannelCode ][i]; 247 | } 248 | 249 | if (bStatus) { 250 | sReturn[nReturnPos++] = '0'; 251 | sReturn[nReturnPos++] = 'F'; 252 | } else { 253 | sReturn[nReturnPos++] = 'F'; 254 | sReturn[nReturnPos++] = '0'; 255 | } 256 | sReturn[nReturnPos] = '\0'; 257 | 258 | return sReturn; 259 | } 260 | 261 | /** 262 | * Like getCodeWord (Type C = Intertechno) 263 | */ 264 | char* RCSwitch::getCodeWordC(char sFamily, int nGroup, int nDevice, boolean bStatus) { 265 | static char sReturn[13]; 266 | int nReturnPos = 0; 267 | 268 | if ( (byte)sFamily < 97 || (byte)sFamily > 112 || nGroup < 1 || nGroup > 4 || nDevice < 1 || nDevice > 4) { 269 | return '\0'; 270 | } 271 | 272 | char* sDeviceGroupCode = dec2binWzerofill( (nDevice-1) + (nGroup-1)*4, 4 ); 273 | char familycode[16][5] = { "0000", "F000", "0F00", "FF00", "00F0", "F0F0", "0FF0", "FFF0", "000F", "F00F", "0F0F", "FF0F", "00FF", "F0FF", "0FFF", "FFFF" }; 274 | for (int i = 0; i<4; i++) { 275 | sReturn[nReturnPos++] = familycode[ (int)sFamily - 97 ][i]; 276 | } 277 | for (int i = 0; i<4; i++) { 278 | sReturn[nReturnPos++] = (sDeviceGroupCode[3-i] == '1' ? 'F' : '0'); 279 | } 280 | sReturn[nReturnPos++] = '0'; 281 | sReturn[nReturnPos++] = 'F'; 282 | sReturn[nReturnPos++] = 'F'; 283 | if (bStatus) { 284 | sReturn[nReturnPos++] = 'F'; 285 | } else { 286 | sReturn[nReturnPos++] = '0'; 287 | } 288 | sReturn[nReturnPos] = '\0'; 289 | return sReturn; 290 | } 291 | 292 | /** 293 | * Sends a Code Word 294 | * @param sCodeWord /^[10FS]*$/ -> see getCodeWord 295 | */ 296 | void RCSwitch::sendTriState(char* sCodeWord) { 297 | for (int nRepeat=0; nRepeatsendT0(); 303 | break; 304 | case 'F': 305 | this->sendTF(); 306 | break; 307 | case '1': 308 | this->sendT1(); 309 | break; 310 | } 311 | i++; 312 | } 313 | this->sendSync(); 314 | } 315 | } 316 | 317 | void RCSwitch::send(unsigned long Code, unsigned int length) { 318 | this->send( this->dec2binWzerofill(Code, length) ); 319 | } 320 | 321 | void RCSwitch::send(char* sCodeWord) { 322 | for (int nRepeat=0; nRepeatsend0(); 328 | break; 329 | case '1': 330 | this->send1(); 331 | break; 332 | } 333 | i++; 334 | } 335 | this->sendSync(); 336 | } 337 | } 338 | 339 | void RCSwitch::transmit(int nHighPulses, int nLowPulses) { 340 | boolean disabled_Receive = false; 341 | int nReceiverInterrupt_backup = nReceiverInterrupt; 342 | if (this->nTransmitterPin != -1) { 343 | if (this->nReceiverInterrupt != -1) { 344 | this->disableReceive(); 345 | disabled_Receive = true; 346 | } 347 | digitalWrite(this->nTransmitterPin, HIGH); 348 | delayMicroseconds( this->nPulseLength * nHighPulses); 349 | digitalWrite(this->nTransmitterPin, LOW); 350 | delayMicroseconds( this->nPulseLength * nLowPulses); 351 | if(disabled_Receive){ 352 | this->enableReceive(nReceiverInterrupt_backup); 353 | } 354 | } 355 | } 356 | /** 357 | * Sends a "0" Bit 358 | * _ 359 | * Waveform Protocol 1: | |___ 360 | * _ 361 | * Waveform Protocol 2: | |__ 362 | */ 363 | void RCSwitch::send0() { 364 | if (this->nProtocol == 1){ 365 | this->transmit(1,3); 366 | } 367 | else if (this->nProtocol == 2) { 368 | this->transmit(1,2); 369 | } 370 | } 371 | 372 | /** 373 | * Sends a "1" Bit 374 | * ___ 375 | * Waveform Protocol 1: | |_ 376 | * __ 377 | * Waveform Protocol 2: | |_ 378 | */ 379 | void RCSwitch::send1() { 380 | if (this->nProtocol == 1){ 381 | this->transmit(3,1); 382 | } 383 | else if (this->nProtocol == 2) { 384 | this->transmit(2,1); 385 | } 386 | } 387 | 388 | 389 | /** 390 | * Sends a Tri-State "0" Bit 391 | * _ _ 392 | * Waveform: | |___| |___ 393 | */ 394 | void RCSwitch::sendT0() { 395 | this->transmit(1,3); 396 | this->transmit(1,3); 397 | } 398 | 399 | /** 400 | * Sends a Tri-State "1" Bit 401 | * ___ ___ 402 | * Waveform: | |_| |_ 403 | */ 404 | void RCSwitch::sendT1() { 405 | this->transmit(3,1); 406 | this->transmit(3,1); 407 | } 408 | 409 | /** 410 | * Sends a Tri-State "F" Bit 411 | * _ ___ 412 | * Waveform: | |___| |_ 413 | */ 414 | void RCSwitch::sendTF() { 415 | this->transmit(1,3); 416 | this->transmit(3,1); 417 | } 418 | 419 | /** 420 | * Sends a "Sync" Bit 421 | * _ 422 | * Waveform Protocol 1: | |_______________________________ 423 | * _ 424 | * Waveform Protocol 2: | |__________ 425 | */ 426 | void RCSwitch::sendSync() { 427 | 428 | if (this->nProtocol == 1){ 429 | this->transmit(1,31); 430 | } 431 | else if (this->nProtocol == 2) { 432 | this->transmit(1,10); 433 | } 434 | } 435 | 436 | /** 437 | * Enable receiving data 438 | */ 439 | void RCSwitch::enableReceive(int interrupt) { 440 | this->nReceiverInterrupt = interrupt; 441 | this->enableReceive(); 442 | } 443 | 444 | void RCSwitch::enableReceive() { 445 | if (this->nReceiverInterrupt != -1) { 446 | RCSwitch::nReceivedValue = NULL; 447 | RCSwitch::nReceivedBitlength = NULL; 448 | wiringPiISR(this->nReceiverInterrupt, INT_EDGE_BOTH, &handleInterrupt); 449 | } 450 | } 451 | 452 | /** 453 | * Disable receiving data 454 | */ 455 | void RCSwitch::disableReceive() { 456 | this->nReceiverInterrupt = -1; 457 | } 458 | 459 | bool RCSwitch::available() { 460 | return RCSwitch::nReceivedValue != NULL; 461 | } 462 | 463 | void RCSwitch::resetAvailable() { 464 | RCSwitch::nReceivedValue = NULL; 465 | } 466 | 467 | unsigned long RCSwitch::getReceivedValue() { 468 | return RCSwitch::nReceivedValue; 469 | } 470 | 471 | unsigned int RCSwitch::getReceivedBitlength() { 472 | return RCSwitch::nReceivedBitlength; 473 | } 474 | 475 | unsigned int RCSwitch::getReceivedDelay() { 476 | return RCSwitch::nReceivedDelay; 477 | } 478 | 479 | unsigned int RCSwitch::getReceivedProtocol() { 480 | return RCSwitch::nReceivedProtocol; 481 | } 482 | 483 | unsigned int* RCSwitch::getReceivedRawdata() { 484 | return RCSwitch::timings; 485 | } 486 | 487 | /** 488 | * 489 | */ 490 | bool RCSwitch::receiveProtocol1(unsigned int changeCount){ 491 | 492 | unsigned long code = 0; 493 | unsigned long delay = RCSwitch::timings[0] / 31; 494 | unsigned long delayTolerance = delay * RCSwitch::nReceiveTolerance * 0.01; 495 | 496 | for (int i = 1; i delay-delayTolerance && RCSwitch::timings[i] < delay+delayTolerance && RCSwitch::timings[i+1] > delay*3-delayTolerance && RCSwitch::timings[i+1] < delay*3+delayTolerance) { 499 | code = code << 1; 500 | } else if (RCSwitch::timings[i] > delay*3-delayTolerance && RCSwitch::timings[i] < delay*3+delayTolerance && RCSwitch::timings[i+1] > delay-delayTolerance && RCSwitch::timings[i+1] < delay+delayTolerance) { 501 | code+=1; 502 | code = code << 1; 503 | } else { 504 | // Failed 505 | i = changeCount; 506 | code = 0; 507 | } 508 | } 509 | code = code >> 1; 510 | if (changeCount > 6) { // ignore < 4bit values as there are no devices sending 4bit values => noise 511 | RCSwitch::nReceivedValue = code; 512 | RCSwitch::nReceivedBitlength = changeCount / 2; 513 | RCSwitch::nReceivedDelay = delay; 514 | RCSwitch::nReceivedProtocol = 1; 515 | } 516 | 517 | if (code == 0){ 518 | return false; 519 | }else if (code != 0){ 520 | return true; 521 | } 522 | 523 | 524 | } 525 | 526 | bool RCSwitch::receiveProtocol2(unsigned int changeCount){ 527 | 528 | unsigned long code = 0; 529 | unsigned long delay = RCSwitch::timings[0] / 10; 530 | unsigned long delayTolerance = delay * RCSwitch::nReceiveTolerance * 0.01; 531 | 532 | for (int i = 1; i delay-delayTolerance && RCSwitch::timings[i] < delay+delayTolerance && RCSwitch::timings[i+1] > delay*2-delayTolerance && RCSwitch::timings[i+1] < delay*2+delayTolerance) { 535 | code = code << 1; 536 | } else if (RCSwitch::timings[i] > delay*2-delayTolerance && RCSwitch::timings[i] < delay*2+delayTolerance && RCSwitch::timings[i+1] > delay-delayTolerance && RCSwitch::timings[i+1] < delay+delayTolerance) { 537 | code+=1; 538 | code = code << 1; 539 | } else { 540 | // Failed 541 | i = changeCount; 542 | code = 0; 543 | } 544 | } 545 | code = code >> 1; 546 | if (changeCount > 6) { // ignore < 4bit values as there are no devices sending 4bit values => noise 547 | RCSwitch::nReceivedValue = code; 548 | RCSwitch::nReceivedBitlength = changeCount / 2; 549 | RCSwitch::nReceivedDelay = delay; 550 | RCSwitch::nReceivedProtocol = 2; 551 | } 552 | 553 | if (code == 0){ 554 | return false; 555 | }else if (code != 0){ 556 | return true; 557 | } 558 | 559 | } 560 | 561 | void RCSwitch::handleInterrupt() { 562 | 563 | static unsigned int duration; 564 | static unsigned int changeCount; 565 | static unsigned long lastTime; 566 | static unsigned int repeatCount; 567 | 568 | long time = micros(); 569 | duration = time - lastTime; 570 | 571 | if (duration > 5000 && duration > RCSwitch::timings[0] - 200 && duration < RCSwitch::timings[0] + 200) { 572 | repeatCount++; 573 | changeCount--; 574 | 575 | if (repeatCount == 2) { 576 | if (receiveProtocol1(changeCount) == false){ 577 | if (receiveProtocol2(changeCount) == false){ 578 | //failed 579 | } 580 | } 581 | repeatCount = 0; 582 | } 583 | changeCount = 0; 584 | } else if (duration > 5000) { 585 | changeCount = 0; 586 | } 587 | 588 | if (changeCount >= RCSWITCH_MAX_CHANGES) { 589 | changeCount = 0; 590 | repeatCount = 0; 591 | } 592 | RCSwitch::timings[changeCount++] = duration; 593 | lastTime = time; 594 | } 595 | 596 | /** 597 | * Turns a decimal value to its binary representation 598 | */ 599 | char* RCSwitch::dec2binWzerofill(unsigned long Dec, unsigned int bitLength){ 600 | static char bin[64]; 601 | unsigned int i=0; 602 | 603 | while (Dec > 0) { 604 | bin[32+i++] = ((Dec & 1) > 0) ? '1' : '0'; 605 | Dec = Dec >> 1; 606 | } 607 | 608 | for (unsigned int j = 0; j< bitLength; j++) { 609 | if (j >= bitLength - i) { 610 | bin[j] = bin[ 31 + i - (j - (bitLength - i)) ]; 611 | }else { 612 | bin[j] = '0'; 613 | } 614 | } 615 | bin[bitLength] = '\0'; 616 | 617 | return bin; 618 | } 619 | 620 | --------------------------------------------------------------------------------