├── .gitignore ├── .npmignore ├── CHANGELOG.md ├── README.md ├── binding.gyp ├── externals └── rcswitch-pi │ ├── RCSwitch.cpp │ └── RCSwitch.h ├── img ├── type_a.jpg └── type_b.jpg ├── index.js ├── package.json └── src ├── RCSwitchNode.cpp ├── RCSwitchNode.h └── rcswitch.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | node_modules/ 3 | npm-debug.log -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | img/ -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | All notable changes to this project will be documented in this file. 3 | 4 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 5 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 6 | 7 | ## [Unreleased] 8 | 9 | ## 0.4.0 - 20122-09-01 10 | 11 | ### Changed 12 | - BREAKING: Supported version is now `>= 10.0.0` instead of `>= 0.8.0` (#18) 13 | - BREAKING: The export is not the class instance anymore, but the `RCSwitch` class itself, that you have to instantiate (#14) 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | node-rcswitch 2 | ============= 3 | 4 | [![NPM version](https://badge.fury.io/js/rcswitch.svg)](http://badge.fury.io/js/rcswitch) 5 | 6 | Node bindings for the [rcswitch RaspberryPi port](https://github.com/r10r/rcswitch-pi). 7 | 8 | It should be compatible with all versions of Node.js starting from v10 9 | 10 | ## Requirements 11 | 12 | * Like the C++ version of rcswitch, [WiringPi must be installed](https://projects.drogon.net/raspberry-pi/wiringpi/download-and-install/) in order to compile. 13 | * Both the data and the power Pins of the 315/433Mhz emitter must be connected to the RPi. Note the number of the WiringPi data Pin. (see http://wiringpi.com/pins/) 14 | * The node command must be run with root access 15 | 16 | ## Usage 17 | 18 | ```javascript 19 | const RCSwitch = require('rcswitch'); // Might throw an error if wiring pi init failed, or exit process if no root (must work on that) 20 | 21 | const rcswitch = new RCSwitch(); 22 | 23 | rcswitch.enableTransmit(0); // Use data Pin 0 24 | rcswitch.switchOn("10110", 1); // Switch on the first unit of 10110 (code 1x23x) group 25 | rcswitch.switchOff("11000", 2); // Switch off the second unit of 11000 (code 12xxx) group 26 | ``` 27 | 28 | ## API 29 | 30 | ### Configuration 31 | 32 | #### rcswitch.enableTransmit(`pin`) 33 | 34 | Enable transmission on the given pin (make it an OUTPUT). Must be called before any other functions. 35 | 36 | * `pin` - (Number) data Pin to use following [the WiringPi schema](http://wiringpi.com/pins/) 37 | 38 | Return true if `pin` is an integer, false otherwise. 39 | 40 | #### rcswitch.disableTransmit() 41 | 42 | Disable transmission (set the pin to -1 which disable any following function call). 43 | 44 | Return true. 45 | 46 | ### Type A 47 | 48 | ![Type A switch](https://raw.github.com/marvinroger/node-rcswitch/master/img/type_a.jpg "Type A switch") 49 | 50 | #### rcswitch.switchOn(`group`, `switch`) 51 | 52 | Switch a remote switch on (Type A with 10 pole DIP switches). 53 | 54 | * `group` - (String) code of the switch group (refers to DIP switches 1, 2, 3, 4 and 5 where "1" = on and "0" = off - e.g. if all DIP switches are on it's "11111") 55 | * `switch` - (Number) switch number (can be 1 (if DIP switch A is on), 2 (if DIP switch B is on) and so on until 4) 56 | 57 | Return true. 58 | 59 | #### rcswitch.switchOff(`group`, `switch`) 60 | 61 | Switch a remote switch off (Type A with 10 pole DIP switches). 62 | 63 | * `group` - (String) code of the switch group (refers to DIP switches 1, 2, 3, 4 and 5 where "1" = on and "0" = off - e.g. if all DIP switches are on it's "11111") 64 | * `switch` - (Number) switch number (can be 1 (if DIP switch A is on), 2 (if DIP switch B is on) and so on until 4) 65 | 66 | Return true. 67 | 68 | ### Type B 69 | 70 | ![Type B switch](https://raw.github.com/marvinroger/node-rcswitch/master/img/type_b.jpg "Type B switch") 71 | 72 | #### rcswitch.switchOn(`group`, `switch`) 73 | 74 | Switch a remote switch on (Type B with two rotary/sliding switches). 75 | 76 | * `group` - (Number) group (can be 1, 2, 3, 4) 77 | * `switch` - (Number) switch (can be 1, 2, 3, 4) 78 | 79 | Return true. 80 | 81 | #### rcswitch.switchOff(`group`, `switch`) 82 | 83 | Switch a remote switch off (Type B with two rotary/sliding switches). 84 | 85 | * `group` - (Number) group (can be 1, 2, 3, 4) 86 | * `switch` - (Number) switch (can be 1, 2, 3, 4) 87 | 88 | Return true. 89 | 90 | ### Type C 91 | 92 | #### rcswitch.switchOn(`family`, `group`, `switch`) 93 | 94 | Switch a remote switch on (Type C Intertechno). 95 | 96 | * `family` - (String) familycode (can be a, b, c, d, e, f) 97 | * `group` - (Number) group (can be 1, 2, 3, 4) 98 | * `switch` - (Number) switch (can be 1, 2, 3, 4) 99 | 100 | Return true. 101 | 102 | #### rcswitch.switchOff(`family`, `group`, `switch`) 103 | 104 | Switch a remote switch off (Type C Intertechno). 105 | 106 | * `family` - (String) familycode (can be a, b, c, d, e, f) 107 | * `group` - (Number) group (can be 1, 2, 3, 4) 108 | * `switch` - (Number) switch (can be 1, 2, 3, 4) 109 | 110 | Return true. 111 | 112 | ### Other 113 | 114 | #### rcswitch.send(`code`) 115 | 116 | Send raw code. 117 | 118 | * `code` - (String) code 119 | 120 | Return true. 121 | 122 | #### rcswitch.sendTriState(`code`) 123 | 124 | Send tri-state code. 125 | 126 | * `code` - (String) tri-state code 127 | 128 | Return true. 129 | 130 | This function is useful for eg. micro-electric AS 73 which is also sold as REV Telecontrol in Germany (Version with house code with 6 DIP switches). 131 | 132 | This socket has 10 DIP-Switches. 133 | 134 | The house code uses the first 6 switches, the receiver code is set by the next 4 switches. For the house code, the switch position OFF is represented by F and switch position ON by 0. 135 | 136 | Receiver codes: 137 | 138 | Channel Switches 7-10 139 | * `0FFF` Channel A 140 | * `F0FF` Channel B 141 | * `FFF0` Channel C 142 | * `FF0F` Channel D 143 | 144 | * `FF` or `F0` Button on 145 | * `0F` Button off 146 | 147 | The input string for the function is `[homecode][channel][on/off value]` 148 | e.g. F000000FFFFF for homecode 100000, Channel A and button on. 149 | -------------------------------------------------------------------------------- /binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | 'targets': [ 3 | { 4 | 'target_name': 'rcswitch', 5 | 'defines': [ 'RPI' ], 6 | 'sources': [ 'src/rcswitch.cpp', 'src/RCSwitchNode.cpp', 'externals/rcswitch-pi/RCSwitch.cpp' ], 7 | 'include_dirs': [ '/usr/local/include', ".(at)gmail(dot)com 11 | - Andreas Steinel / A.(at)gmail(dot)com 12 | - Max Horn / max(at)quendi(dot)de 13 | - Robert ter Vehn / .(at)gmail(dot)com 14 | - Johann Richard / .(at)gmail(dot)com 15 | - Vlad Gheorghe / .(at)gmail(dot)com https://github.com/vgheo 16 | 17 | Project home: https://github.com/sui77/rc-switch/ 18 | 19 | This library is free software; you can redistribute it and/or 20 | modify it under the terms of the GNU Lesser General Public 21 | License as published by the Free Software Foundation; either 22 | version 2.1 of the License, or (at your option) any later version. 23 | 24 | This library is distributed in the hope that it will be useful, 25 | but WITHOUT ANY WARRANTY; without even the implied warranty of 26 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 27 | Lesser General Public License for more details. 28 | 29 | You should have received a copy of the GNU Lesser General Public 30 | License along with this library; if not, write to the Free Software 31 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 32 | */ 33 | 34 | #include "RCSwitch.h" 35 | 36 | #ifdef RaspberryPi 37 | // PROGMEM and _P functions are for AVR based microprocessors, 38 | // so we must normalize these for the ARM processor: 39 | #define PROGMEM 40 | #define memcpy_P(dest, src, num) memcpy((dest), (src), (num)) 41 | #endif 42 | 43 | #if defined(ESP8266) || defined(ESP32) 44 | // interrupt handler and related code must be in RAM on ESP8266, 45 | // according to issue #46. 46 | #define RECEIVE_ATTR ICACHE_RAM_ATTR 47 | #else 48 | #define RECEIVE_ATTR 49 | #endif 50 | 51 | 52 | /* Format for protocol definitions: 53 | * {pulselength, Sync bit, "0" bit, "1" bit} 54 | * 55 | * pulselength: pulse length in microseconds, e.g. 350 56 | * Sync bit: {1, 31} means 1 high pulse and 31 low pulses 57 | * (perceived as a 31*pulselength long pulse, total length of sync bit is 58 | * 32*pulselength microseconds), i.e: 59 | * _ 60 | * | |_______________________________ (don't count the vertical bars) 61 | * "0" bit: waveform for a data bit of value "0", {1, 3} means 1 high pulse 62 | * and 3 low pulses, total length (1+3)*pulselength, i.e: 63 | * _ 64 | * | |___ 65 | * "1" bit: waveform for a data bit of value "1", e.g. {3,1}: 66 | * ___ 67 | * | |_ 68 | * 69 | * These are combined to form Tri-State bits when sending or receiving codes. 70 | */ 71 | #if defined(ESP8266) || defined(ESP32) 72 | static const RCSwitch::Protocol proto[] = { 73 | #else 74 | static const RCSwitch::Protocol PROGMEM proto[] = { 75 | #endif 76 | { 350, { 1, 31 }, { 1, 3 }, { 3, 1 }, false }, // protocol 1 77 | { 650, { 1, 10 }, { 1, 2 }, { 2, 1 }, false }, // protocol 2 78 | { 100, { 30, 71 }, { 4, 11 }, { 9, 6 }, false }, // protocol 3 79 | { 380, { 1, 6 }, { 1, 3 }, { 3, 1 }, false }, // protocol 4 80 | { 500, { 6, 14 }, { 1, 2 }, { 2, 1 }, false }, // protocol 5 81 | { 450, { 23, 1 }, { 1, 2 }, { 2, 1 }, true }, // protocol 6 (HT6P20B) 82 | { 150, { 2, 62 }, { 1, 6 }, { 6, 1 }, false } // protocol 7 (HS2303-PT, i. e. used in AUKEY Remote) 83 | }; 84 | 85 | enum { 86 | numProto = sizeof(proto) / sizeof(proto[0]) 87 | }; 88 | 89 | #if not defined( RCSwitchDisableReceiving ) 90 | volatile unsigned long RCSwitch::nReceivedValue = 0; 91 | volatile unsigned int RCSwitch::nReceivedBitlength = 0; 92 | volatile unsigned int RCSwitch::nReceivedDelay = 0; 93 | volatile unsigned int RCSwitch::nReceivedProtocol = 0; 94 | int RCSwitch::nReceiveTolerance = 60; 95 | const unsigned int RCSwitch::nSeparationLimit = 4300; 96 | // separationLimit: minimum microseconds between received codes, closer codes are ignored. 97 | // according to discussion on issue #14 it might be more suitable to set the separation 98 | // limit to the same time as the 'low' part of the sync signal for the current protocol. 99 | unsigned int RCSwitch::timings[RCSWITCH_MAX_CHANGES]; 100 | #endif 101 | 102 | RCSwitch::RCSwitch() { 103 | this->nTransmitterPin = -1; 104 | this->setRepeatTransmit(10); 105 | this->setProtocol(1); 106 | #if not defined( RCSwitchDisableReceiving ) 107 | this->nReceiverInterrupt = -1; 108 | this->setReceiveTolerance(60); 109 | RCSwitch::nReceivedValue = 0; 110 | #endif 111 | } 112 | 113 | /** 114 | * Sets the protocol to send. 115 | */ 116 | void RCSwitch::setProtocol(Protocol protocol) { 117 | this->protocol = protocol; 118 | } 119 | 120 | /** 121 | * Sets the protocol to send, from a list of predefined protocols 122 | */ 123 | void RCSwitch::setProtocol(int nProtocol) { 124 | if (nProtocol < 1 || nProtocol > numProto) { 125 | nProtocol = 1; // TODO: trigger an error, e.g. "bad protocol" ??? 126 | } 127 | #if defined(ESP8266) || defined(ESP32) 128 | this->protocol = proto[nProtocol-1]; 129 | #else 130 | memcpy_P(&this->protocol, &proto[nProtocol-1], sizeof(Protocol)); 131 | #endif 132 | } 133 | 134 | /** 135 | * Sets the protocol to send with pulse length in microseconds. 136 | */ 137 | void RCSwitch::setProtocol(int nProtocol, int nPulseLength) { 138 | setProtocol(nProtocol); 139 | this->setPulseLength(nPulseLength); 140 | } 141 | 142 | 143 | /** 144 | * Sets pulse length in microseconds 145 | */ 146 | void RCSwitch::setPulseLength(int nPulseLength) { 147 | this->protocol.pulseLength = nPulseLength; 148 | } 149 | 150 | /** 151 | * Sets Repeat Transmits 152 | */ 153 | void RCSwitch::setRepeatTransmit(int nRepeatTransmit) { 154 | this->nRepeatTransmit = nRepeatTransmit; 155 | } 156 | 157 | /** 158 | * Set Receiving Tolerance 159 | */ 160 | #if not defined( RCSwitchDisableReceiving ) 161 | void RCSwitch::setReceiveTolerance(int nPercent) { 162 | RCSwitch::nReceiveTolerance = nPercent; 163 | } 164 | #endif 165 | 166 | 167 | /** 168 | * Enable transmissions 169 | * 170 | * @param nTransmitterPin Arduino Pin to which the sender is connected to 171 | */ 172 | void RCSwitch::enableTransmit(int nTransmitterPin) { 173 | this->nTransmitterPin = nTransmitterPin; 174 | pinMode(this->nTransmitterPin, OUTPUT); 175 | } 176 | 177 | /** 178 | * Disable transmissions 179 | */ 180 | void RCSwitch::disableTransmit() { 181 | this->nTransmitterPin = -1; 182 | } 183 | 184 | /** 185 | * Switch a remote switch on (Type D REV) 186 | * 187 | * @param sGroup Code of the switch group (A,B,C,D) 188 | * @param nDevice Number of the switch itself (1..3) 189 | */ 190 | void RCSwitch::switchOn(char sGroup, int nDevice) { 191 | this->sendTriState( this->getCodeWordD(sGroup, nDevice, true) ); 192 | } 193 | 194 | /** 195 | * Switch a remote switch off (Type D REV) 196 | * 197 | * @param sGroup Code of the switch group (A,B,C,D) 198 | * @param nDevice Number of the switch itself (1..3) 199 | */ 200 | void RCSwitch::switchOff(char sGroup, int nDevice) { 201 | this->sendTriState( this->getCodeWordD(sGroup, nDevice, false) ); 202 | } 203 | 204 | /** 205 | * Switch a remote switch on (Type C Intertechno) 206 | * 207 | * @param sFamily Familycode (a..f) 208 | * @param nGroup Number of group (1..4) 209 | * @param nDevice Number of device (1..4) 210 | */ 211 | void RCSwitch::switchOn(char sFamily, int nGroup, int nDevice) { 212 | this->sendTriState( this->getCodeWordC(sFamily, nGroup, nDevice, true) ); 213 | } 214 | 215 | /** 216 | * Switch a remote switch off (Type C Intertechno) 217 | * 218 | * @param sFamily Familycode (a..f) 219 | * @param nGroup Number of group (1..4) 220 | * @param nDevice Number of device (1..4) 221 | */ 222 | void RCSwitch::switchOff(char sFamily, int nGroup, int nDevice) { 223 | this->sendTriState( this->getCodeWordC(sFamily, nGroup, nDevice, false) ); 224 | } 225 | 226 | /** 227 | * Switch a remote switch on (Type B with two rotary/sliding switches) 228 | * 229 | * @param nAddressCode Number of the switch group (1..4) 230 | * @param nChannelCode Number of the switch itself (1..4) 231 | */ 232 | void RCSwitch::switchOn(int nAddressCode, int nChannelCode) { 233 | this->sendTriState( this->getCodeWordB(nAddressCode, nChannelCode, true) ); 234 | } 235 | 236 | /** 237 | * Switch a remote switch off (Type B with two rotary/sliding switches) 238 | * 239 | * @param nAddressCode Number of the switch group (1..4) 240 | * @param nChannelCode Number of the switch itself (1..4) 241 | */ 242 | void RCSwitch::switchOff(int nAddressCode, int nChannelCode) { 243 | this->sendTriState( this->getCodeWordB(nAddressCode, nChannelCode, false) ); 244 | } 245 | 246 | /** 247 | * Deprecated, use switchOn(const char* sGroup, const char* sDevice) instead! 248 | * Switch a remote switch on (Type A with 10 pole DIP switches) 249 | * 250 | * @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") 251 | * @param nChannelCode Number of the switch itself (1..5) 252 | */ 253 | void RCSwitch::switchOn(const char* sGroup, int nChannel) { 254 | const char* code[6] = { "00000", "10000", "01000", "00100", "00010", "00001" }; 255 | this->switchOn(sGroup, code[nChannel]); 256 | } 257 | 258 | /** 259 | * Deprecated, use switchOff(const char* sGroup, const char* sDevice) instead! 260 | * Switch a remote switch off (Type A with 10 pole DIP switches) 261 | * 262 | * @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") 263 | * @param nChannelCode Number of the switch itself (1..5) 264 | */ 265 | void RCSwitch::switchOff(const char* sGroup, int nChannel) { 266 | const char* code[6] = { "00000", "10000", "01000", "00100", "00010", "00001" }; 267 | this->switchOff(sGroup, code[nChannel]); 268 | } 269 | 270 | /** 271 | * Switch a remote switch on (Type A with 10 pole DIP switches) 272 | * 273 | * @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") 274 | * @param sDevice Code of the switch device (refers to DIP switches 6..10 (A..E) where "1" = on and "0" = off, if all DIP switches are on it's "11111") 275 | */ 276 | void RCSwitch::switchOn(const char* sGroup, const char* sDevice) { 277 | this->sendTriState( this->getCodeWordA(sGroup, sDevice, true) ); 278 | } 279 | 280 | /** 281 | * Switch a remote switch off (Type A with 10 pole DIP switches) 282 | * 283 | * @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") 284 | * @param sDevice Code of the switch device (refers to DIP switches 6..10 (A..E) where "1" = on and "0" = off, if all DIP switches are on it's "11111") 285 | */ 286 | void RCSwitch::switchOff(const char* sGroup, const char* sDevice) { 287 | this->sendTriState( this->getCodeWordA(sGroup, sDevice, false) ); 288 | } 289 | 290 | 291 | /** 292 | * Returns a char[13], representing the code word to be send. 293 | * 294 | */ 295 | char* RCSwitch::getCodeWordA(const char* sGroup, const char* sDevice, bool bStatus) { 296 | static char sReturn[13]; 297 | int nReturnPos = 0; 298 | 299 | for (int i = 0; i < 5; i++) { 300 | sReturn[nReturnPos++] = (sGroup[i] == '0') ? 'F' : '0'; 301 | } 302 | 303 | for (int i = 0; i < 5; i++) { 304 | sReturn[nReturnPos++] = (sDevice[i] == '0') ? 'F' : '0'; 305 | } 306 | 307 | sReturn[nReturnPos++] = bStatus ? '0' : 'F'; 308 | sReturn[nReturnPos++] = bStatus ? 'F' : '0'; 309 | 310 | sReturn[nReturnPos] = '\0'; 311 | return sReturn; 312 | } 313 | 314 | /** 315 | * Encoding for type B switches with two rotary/sliding switches. 316 | * 317 | * The code word is a tristate word and with following bit pattern: 318 | * 319 | * +-----------------------------+-----------------------------+----------+------------+ 320 | * | 4 bits address | 4 bits address | 3 bits | 1 bit | 321 | * | switch group | switch number | not used | on / off | 322 | * | 1=0FFF 2=F0FF 3=FF0F 4=FFF0 | 1=0FFF 2=F0FF 3=FF0F 4=FFF0 | FFF | on=F off=0 | 323 | * +-----------------------------+-----------------------------+----------+------------+ 324 | * 325 | * @param nAddressCode Number of the switch group (1..4) 326 | * @param nChannelCode Number of the switch itself (1..4) 327 | * @param bStatus Whether to switch on (true) or off (false) 328 | * 329 | * @return char[13], representing a tristate code word of length 12 330 | */ 331 | char* RCSwitch::getCodeWordB(int nAddressCode, int nChannelCode, bool bStatus) { 332 | static char sReturn[13]; 333 | int nReturnPos = 0; 334 | 335 | if (nAddressCode < 1 || nAddressCode > 4 || nChannelCode < 1 || nChannelCode > 4) { 336 | return 0; 337 | } 338 | 339 | for (int i = 1; i <= 4; i++) { 340 | sReturn[nReturnPos++] = (nAddressCode == i) ? '0' : 'F'; 341 | } 342 | 343 | for (int i = 1; i <= 4; i++) { 344 | sReturn[nReturnPos++] = (nChannelCode == i) ? '0' : 'F'; 345 | } 346 | 347 | sReturn[nReturnPos++] = 'F'; 348 | sReturn[nReturnPos++] = 'F'; 349 | sReturn[nReturnPos++] = 'F'; 350 | 351 | sReturn[nReturnPos++] = bStatus ? 'F' : '0'; 352 | 353 | sReturn[nReturnPos] = '\0'; 354 | return sReturn; 355 | } 356 | 357 | /** 358 | * Like getCodeWord (Type C = Intertechno) 359 | */ 360 | char* RCSwitch::getCodeWordC(char sFamily, int nGroup, int nDevice, bool bStatus) { 361 | static char sReturn[13]; 362 | int nReturnPos = 0; 363 | 364 | int nFamily = (int)sFamily - 'a'; 365 | if ( nFamily < 0 || nFamily > 15 || nGroup < 1 || nGroup > 4 || nDevice < 1 || nDevice > 4) { 366 | return 0; 367 | } 368 | 369 | // encode the family into four bits 370 | sReturn[nReturnPos++] = (nFamily & 1) ? 'F' : '0'; 371 | sReturn[nReturnPos++] = (nFamily & 2) ? 'F' : '0'; 372 | sReturn[nReturnPos++] = (nFamily & 4) ? 'F' : '0'; 373 | sReturn[nReturnPos++] = (nFamily & 8) ? 'F' : '0'; 374 | 375 | // encode the device and group 376 | sReturn[nReturnPos++] = ((nDevice-1) & 1) ? 'F' : '0'; 377 | sReturn[nReturnPos++] = ((nDevice-1) & 2) ? 'F' : '0'; 378 | sReturn[nReturnPos++] = ((nGroup-1) & 1) ? 'F' : '0'; 379 | sReturn[nReturnPos++] = ((nGroup-1) & 2) ? 'F' : '0'; 380 | 381 | // encode the status code 382 | sReturn[nReturnPos++] = '0'; 383 | sReturn[nReturnPos++] = 'F'; 384 | sReturn[nReturnPos++] = 'F'; 385 | sReturn[nReturnPos++] = bStatus ? 'F' : '0'; 386 | 387 | sReturn[nReturnPos] = '\0'; 388 | return sReturn; 389 | } 390 | 391 | /** 392 | * Encoding for the REV Switch Type 393 | * 394 | * The code word is a tristate word and with following bit pattern: 395 | * 396 | * +-----------------------------+-------------------+----------+--------------+ 397 | * | 4 bits address | 3 bits address | 3 bits | 2 bits | 398 | * | switch group | device number | not used | on / off | 399 | * | A=1FFF B=F1FF C=FF1F D=FFF1 | 1=0FF 2=F0F 3=FF0 | 000 | on=10 off=01 | 400 | * +-----------------------------+-------------------+----------+--------------+ 401 | * 402 | * Source: http://www.the-intruder.net/funksteckdosen-von-rev-uber-arduino-ansteuern/ 403 | * 404 | * @param sGroup Name of the switch group (A..D, resp. a..d) 405 | * @param nDevice Number of the switch itself (1..3) 406 | * @param bStatus Whether to switch on (true) or off (false) 407 | * 408 | * @return char[13], representing a tristate code word of length 12 409 | */ 410 | char* RCSwitch::getCodeWordD(char sGroup, int nDevice, bool bStatus) { 411 | static char sReturn[13]; 412 | int nReturnPos = 0; 413 | 414 | // sGroup must be one of the letters in "abcdABCD" 415 | int nGroup = (sGroup >= 'a') ? (int)sGroup - 'a' : (int)sGroup - 'A'; 416 | if ( nGroup < 0 || nGroup > 3 || nDevice < 1 || nDevice > 3) { 417 | return 0; 418 | } 419 | 420 | for (int i = 0; i < 4; i++) { 421 | sReturn[nReturnPos++] = (nGroup == i) ? '1' : 'F'; 422 | } 423 | 424 | for (int i = 1; i <= 3; i++) { 425 | sReturn[nReturnPos++] = (nDevice == i) ? '1' : 'F'; 426 | } 427 | 428 | sReturn[nReturnPos++] = '0'; 429 | sReturn[nReturnPos++] = '0'; 430 | sReturn[nReturnPos++] = '0'; 431 | 432 | sReturn[nReturnPos++] = bStatus ? '1' : '0'; 433 | sReturn[nReturnPos++] = bStatus ? '0' : '1'; 434 | 435 | sReturn[nReturnPos] = '\0'; 436 | return sReturn; 437 | } 438 | 439 | /** 440 | * @param sCodeWord a tristate code word consisting of the letter 0, 1, F 441 | */ 442 | void RCSwitch::sendTriState(const char* sCodeWord) { 443 | // turn the tristate code word into the corresponding bit pattern, then send it 444 | unsigned long code = 0; 445 | unsigned int length = 0; 446 | for (const char* p = sCodeWord; *p; p++) { 447 | code <<= 2L; 448 | switch (*p) { 449 | case '0': 450 | // bit pattern 00 451 | break; 452 | case 'F': 453 | // bit pattern 01 454 | code |= 1L; 455 | break; 456 | case '1': 457 | // bit pattern 11 458 | code |= 3L; 459 | break; 460 | } 461 | length += 2; 462 | } 463 | this->send(code, length); 464 | } 465 | 466 | /** 467 | * @param sCodeWord a binary code word consisting of the letter 0, 1 468 | */ 469 | void RCSwitch::send(const char* sCodeWord) { 470 | // turn the tristate code word into the corresponding bit pattern, then send it 471 | unsigned long code = 0; 472 | unsigned int length = 0; 473 | for (const char* p = sCodeWord; *p; p++) { 474 | code <<= 1L; 475 | if (*p != '0') 476 | code |= 1L; 477 | length++; 478 | } 479 | this->send(code, length); 480 | } 481 | 482 | /** 483 | * Transmit the first 'length' bits of the integer 'code'. The 484 | * bits are sent from MSB to LSB, i.e., first the bit at position length-1, 485 | * then the bit at position length-2, and so on, till finally the bit at position 0. 486 | */ 487 | void RCSwitch::send(unsigned long code, unsigned int length) { 488 | if (this->nTransmitterPin == -1) 489 | return; 490 | 491 | #if not defined( RCSwitchDisableReceiving ) 492 | // make sure the receiver is disabled while we transmit 493 | int nReceiverInterrupt_backup = nReceiverInterrupt; 494 | if (nReceiverInterrupt_backup != -1) { 495 | this->disableReceive(); 496 | } 497 | #endif 498 | 499 | for (int nRepeat = 0; nRepeat < nRepeatTransmit; nRepeat++) { 500 | for (int i = length-1; i >= 0; i--) { 501 | if (code & (1L << i)) 502 | this->transmit(protocol.one); 503 | else 504 | this->transmit(protocol.zero); 505 | } 506 | this->transmit(protocol.syncFactor); 507 | } 508 | 509 | // Disable transmit after sending (i.e., for inverted protocols) 510 | digitalWrite(this->nTransmitterPin, LOW); 511 | 512 | #if not defined( RCSwitchDisableReceiving ) 513 | // enable receiver again if we just disabled it 514 | if (nReceiverInterrupt_backup != -1) { 515 | this->enableReceive(nReceiverInterrupt_backup); 516 | } 517 | #endif 518 | } 519 | 520 | /** 521 | * Transmit a single high-low pulse. 522 | */ 523 | void RCSwitch::transmit(HighLow pulses) { 524 | uint8_t firstLogicLevel = (this->protocol.invertedSignal) ? LOW : HIGH; 525 | uint8_t secondLogicLevel = (this->protocol.invertedSignal) ? HIGH : LOW; 526 | 527 | digitalWrite(this->nTransmitterPin, firstLogicLevel); 528 | delayMicroseconds( this->protocol.pulseLength * pulses.high); 529 | digitalWrite(this->nTransmitterPin, secondLogicLevel); 530 | delayMicroseconds( this->protocol.pulseLength * pulses.low); 531 | } 532 | 533 | 534 | #if not defined( RCSwitchDisableReceiving ) 535 | /** 536 | * Enable receiving data 537 | */ 538 | void RCSwitch::enableReceive(int interrupt) { 539 | this->nReceiverInterrupt = interrupt; 540 | this->enableReceive(); 541 | } 542 | 543 | void RCSwitch::enableReceive() { 544 | if (this->nReceiverInterrupt != -1) { 545 | RCSwitch::nReceivedValue = 0; 546 | RCSwitch::nReceivedBitlength = 0; 547 | #if defined(RaspberryPi) // Raspberry Pi 548 | wiringPiISR(this->nReceiverInterrupt, INT_EDGE_BOTH, &handleInterrupt); 549 | #else // Arduino 550 | attachInterrupt(this->nReceiverInterrupt, handleInterrupt, CHANGE); 551 | #endif 552 | } 553 | } 554 | 555 | /** 556 | * Disable receiving data 557 | */ 558 | void RCSwitch::disableReceive() { 559 | #if not defined(RaspberryPi) // Arduino 560 | detachInterrupt(this->nReceiverInterrupt); 561 | #endif // For Raspberry Pi (wiringPi) you can't unregister the ISR 562 | this->nReceiverInterrupt = -1; 563 | } 564 | 565 | bool RCSwitch::available() { 566 | return RCSwitch::nReceivedValue != 0; 567 | } 568 | 569 | void RCSwitch::resetAvailable() { 570 | RCSwitch::nReceivedValue = 0; 571 | } 572 | 573 | unsigned long RCSwitch::getReceivedValue() { 574 | return RCSwitch::nReceivedValue; 575 | } 576 | 577 | unsigned int RCSwitch::getReceivedBitlength() { 578 | return RCSwitch::nReceivedBitlength; 579 | } 580 | 581 | unsigned int RCSwitch::getReceivedDelay() { 582 | return RCSwitch::nReceivedDelay; 583 | } 584 | 585 | unsigned int RCSwitch::getReceivedProtocol() { 586 | return RCSwitch::nReceivedProtocol; 587 | } 588 | 589 | unsigned int* RCSwitch::getReceivedRawdata() { 590 | return RCSwitch::timings; 591 | } 592 | 593 | /* helper function for the receiveProtocol method */ 594 | static inline unsigned int diff(int A, int B) { 595 | return abs(A - B); 596 | } 597 | 598 | /** 599 | * 600 | */ 601 | bool RECEIVE_ATTR RCSwitch::receiveProtocol(const int p, unsigned int changeCount) { 602 | #if defined(ESP8266) || defined(ESP32) 603 | const Protocol &pro = proto[p-1]; 604 | #else 605 | Protocol pro; 606 | memcpy_P(&pro, &proto[p-1], sizeof(Protocol)); 607 | #endif 608 | 609 | unsigned long code = 0; 610 | //Assuming the longer pulse length is the pulse captured in timings[0] 611 | const unsigned int syncLengthInPulses = ((pro.syncFactor.low) > (pro.syncFactor.high)) ? (pro.syncFactor.low) : (pro.syncFactor.high); 612 | const unsigned int delay = RCSwitch::timings[0] / syncLengthInPulses; 613 | const unsigned int delayTolerance = delay * RCSwitch::nReceiveTolerance / 100; 614 | 615 | /* For protocols that start low, the sync period looks like 616 | * _________ 617 | * _____________| |XXXXXXXXXXXX| 618 | * 619 | * |--1st dur--|-2nd dur-|-Start data-| 620 | * 621 | * The 3rd saved duration starts the data. 622 | * 623 | * For protocols that start high, the sync period looks like 624 | * 625 | * ______________ 626 | * | |____________|XXXXXXXXXXXXX| 627 | * 628 | * |-filtered out-|--1st dur--|--Start data--| 629 | * 630 | * The 2nd saved duration starts the data 631 | */ 632 | const unsigned int firstDataTiming = (pro.invertedSignal) ? (2) : (1); 633 | 634 | for (unsigned int i = firstDataTiming; i < changeCount - 1; i += 2) { 635 | code <<= 1; 636 | if (diff(RCSwitch::timings[i], delay * pro.zero.high) < delayTolerance && 637 | diff(RCSwitch::timings[i + 1], delay * pro.zero.low) < delayTolerance) { 638 | // zero 639 | } else if (diff(RCSwitch::timings[i], delay * pro.one.high) < delayTolerance && 640 | diff(RCSwitch::timings[i + 1], delay * pro.one.low) < delayTolerance) { 641 | // one 642 | code |= 1; 643 | } else { 644 | // Failed 645 | return false; 646 | } 647 | } 648 | 649 | if (changeCount > 7) { // ignore very short transmissions: no device sends them, so this must be noise 650 | RCSwitch::nReceivedValue = code; 651 | RCSwitch::nReceivedBitlength = (changeCount - 1) / 2; 652 | RCSwitch::nReceivedDelay = delay; 653 | RCSwitch::nReceivedProtocol = p; 654 | return true; 655 | } 656 | 657 | return false; 658 | } 659 | 660 | void RECEIVE_ATTR RCSwitch::handleInterrupt() { 661 | 662 | static unsigned int changeCount = 0; 663 | static unsigned long lastTime = 0; 664 | static unsigned int repeatCount = 0; 665 | 666 | const long time = micros(); 667 | const unsigned int duration = time - lastTime; 668 | 669 | if (duration > RCSwitch::nSeparationLimit) { 670 | // A long stretch without signal level change occurred. This could 671 | // be the gap between two transmission. 672 | if (diff(duration, RCSwitch::timings[0]) < 200) { 673 | // This long signal is close in length to the long signal which 674 | // started the previously recorded timings; this suggests that 675 | // it may indeed by a a gap between two transmissions (we assume 676 | // here that a sender will send the signal multiple times, 677 | // with roughly the same gap between them). 678 | repeatCount++; 679 | if (repeatCount == 2) { 680 | for(unsigned int i = 1; i <= numProto; i++) { 681 | if (receiveProtocol(i, changeCount)) { 682 | // receive succeeded for protocol i 683 | break; 684 | } 685 | } 686 | repeatCount = 0; 687 | } 688 | } 689 | changeCount = 0; 690 | } 691 | 692 | // detect overflow 693 | if (changeCount >= RCSWITCH_MAX_CHANGES) { 694 | changeCount = 0; 695 | repeatCount = 0; 696 | } 697 | 698 | RCSwitch::timings[changeCount++] = duration; 699 | lastTime = time; 700 | } 701 | #endif 702 | -------------------------------------------------------------------------------- /externals/rcswitch-pi/RCSwitch.h: -------------------------------------------------------------------------------- 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=46 9 | - Dominik Fischer / dom_fischer(at)web(dot)de 10 | - Frank Oltmanns / .(at)gmail(dot)com 11 | - Max Horn / max(at)quendi(dot)de 12 | - Robert ter Vehn / .(at)gmail(dot)com 13 | 14 | Project home: https://github.com/sui77/rc-switch/ 15 | 16 | This library is free software; you can redistribute it and/or 17 | modify it under the terms of the GNU Lesser General Public 18 | License as published by the Free Software Foundation; either 19 | version 2.1 of the License, or (at your option) any later version. 20 | 21 | This library is distributed in the hope that it will be useful, 22 | but WITHOUT ANY WARRANTY; without even the implied warranty of 23 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 24 | Lesser General Public License for more details. 25 | 26 | You should have received a copy of the GNU Lesser General Public 27 | License along with this library; if not, write to the Free Software 28 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 29 | */ 30 | #ifndef _RCSwitch_h 31 | #define _RCSwitch_h 32 | 33 | #if defined(ARDUINO) && ARDUINO >= 100 34 | #include "Arduino.h" 35 | #elif defined(ENERGIA) // LaunchPad, FraunchPad and StellarPad specific 36 | #include "Energia.h" 37 | #elif defined(RPI) // Raspberry Pi 38 | #define RaspberryPi 39 | 40 | // Include libraries for RPi: 41 | #include /* memcpy */ 42 | #include /* abs */ 43 | #include 44 | #elif defined(SPARK) 45 | #include "application.h" 46 | #else 47 | #include "WProgram.h" 48 | #endif 49 | 50 | #include 51 | 52 | 53 | // At least for the ATTiny X4/X5, receiving has to be disabled due to 54 | // missing libm depencies (udivmodhi4) 55 | #if defined( __AVR_ATtinyX5__ ) or defined ( __AVR_ATtinyX4__ ) 56 | #define RCSwitchDisableReceiving 57 | #endif 58 | 59 | // Number of maximum high/Low changes per packet. 60 | // We can handle up to (unsigned long) => 32 bit * 2 H/L changes per bit + 2 for sync 61 | #define RCSWITCH_MAX_CHANGES 67 62 | 63 | class RCSwitch { 64 | 65 | public: 66 | RCSwitch(); 67 | 68 | void switchOn(int nGroupNumber, int nSwitchNumber); 69 | void switchOff(int nGroupNumber, int nSwitchNumber); 70 | void switchOn(const char* sGroup, int nSwitchNumber); 71 | void switchOff(const char* sGroup, int nSwitchNumber); 72 | void switchOn(char sFamily, int nGroup, int nDevice); 73 | void switchOff(char sFamily, int nGroup, int nDevice); 74 | void switchOn(const char* sGroup, const char* sDevice); 75 | void switchOff(const char* sGroup, const char* sDevice); 76 | void switchOn(char sGroup, int nDevice); 77 | void switchOff(char sGroup, int nDevice); 78 | 79 | void sendTriState(const char* sCodeWord); 80 | void send(unsigned long code, unsigned int length); 81 | void send(const char* sCodeWord); 82 | 83 | #if not defined( RCSwitchDisableReceiving ) 84 | void enableReceive(int interrupt); 85 | void enableReceive(); 86 | void disableReceive(); 87 | bool available(); 88 | void resetAvailable(); 89 | 90 | unsigned long getReceivedValue(); 91 | unsigned int getReceivedBitlength(); 92 | unsigned int getReceivedDelay(); 93 | unsigned int getReceivedProtocol(); 94 | unsigned int* getReceivedRawdata(); 95 | #endif 96 | 97 | void enableTransmit(int nTransmitterPin); 98 | void disableTransmit(); 99 | void setPulseLength(int nPulseLength); 100 | void setRepeatTransmit(int nRepeatTransmit); 101 | #if not defined( RCSwitchDisableReceiving ) 102 | void setReceiveTolerance(int nPercent); 103 | #endif 104 | 105 | /** 106 | * Description of a single pule, which consists of a high signal 107 | * whose duration is "high" times the base pulse length, followed 108 | * by a low signal lasting "low" times the base pulse length. 109 | * Thus, the pulse overall lasts (high+low)*pulseLength 110 | */ 111 | struct HighLow { 112 | uint8_t high; 113 | uint8_t low; 114 | }; 115 | 116 | /** 117 | * A "protocol" describes how zero and one bits are encoded into high/low 118 | * pulses. 119 | */ 120 | struct Protocol { 121 | /** base pulse length in microseconds, e.g. 350 */ 122 | uint16_t pulseLength; 123 | 124 | HighLow syncFactor; 125 | HighLow zero; 126 | HighLow one; 127 | 128 | /** 129 | * If true, interchange high and low logic levels in all transmissions. 130 | * 131 | * By default, RCSwitch assumes that any signals it sends or receives 132 | * can be broken down into pulses which start with a high signal level, 133 | * followed by a a low signal level. This is e.g. the case for the 134 | * popular PT 2260 encoder chip, and thus many switches out there. 135 | * 136 | * But some devices do it the other way around, and start with a low 137 | * signal level, followed by a high signal level, e.g. the HT6P20B. To 138 | * accommodate this, one can set invertedSignal to true, which causes 139 | * RCSwitch to change how it interprets any HighLow struct FOO: It will 140 | * then assume transmissions start with a low signal lasting 141 | * FOO.high*pulseLength microseconds, followed by a high signal lasting 142 | * FOO.low*pulseLength microseconds. 143 | */ 144 | bool invertedSignal; 145 | }; 146 | 147 | void setProtocol(Protocol protocol); 148 | void setProtocol(int nProtocol); 149 | void setProtocol(int nProtocol, int nPulseLength); 150 | 151 | private: 152 | char* getCodeWordA(const char* sGroup, const char* sDevice, bool bStatus); 153 | char* getCodeWordB(int nGroupNumber, int nSwitchNumber, bool bStatus); 154 | char* getCodeWordC(char sFamily, int nGroup, int nDevice, bool bStatus); 155 | char* getCodeWordD(char group, int nDevice, bool bStatus); 156 | void transmit(HighLow pulses); 157 | 158 | #if not defined( RCSwitchDisableReceiving ) 159 | static void handleInterrupt(); 160 | static bool receiveProtocol(const int p, unsigned int changeCount); 161 | int nReceiverInterrupt; 162 | #endif 163 | int nTransmitterPin; 164 | int nRepeatTransmit; 165 | 166 | Protocol protocol; 167 | 168 | #if not defined( RCSwitchDisableReceiving ) 169 | static int nReceiveTolerance; 170 | volatile static unsigned long nReceivedValue; 171 | volatile static unsigned int nReceivedBitlength; 172 | volatile static unsigned int nReceivedDelay; 173 | volatile static unsigned int nReceivedProtocol; 174 | const static unsigned int nSeparationLimit; 175 | /* 176 | * timings[0] contains sync timing, followed by a number of bits 177 | */ 178 | static unsigned int timings[RCSWITCH_MAX_CHANGES]; 179 | #endif 180 | 181 | 182 | }; 183 | 184 | #endif 185 | -------------------------------------------------------------------------------- /img/type_a.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marvinroger/node-rcswitch/39f50a083664d57cc56b1cde82fd77ca69276208/img/type_a.jpg -------------------------------------------------------------------------------- /img/type_b.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marvinroger/node-rcswitch/39f50a083664d57cc56b1cde82fd77ca69276208/img/type_b.jpg -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | var rcswitch = require('bindings')('rcswitch'); 2 | 3 | module.exports = rcswitch.RCSwitch; 4 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "rcswitch", 3 | "version": "0.4.0", 4 | "description": "Control your wireless power outlet sockets with RCSwitch for the Raspberry Pi", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git://github.com/marvinroger/node-rcswitch.git" 12 | }, 13 | "keywords": [ 14 | "rpi", 15 | "raspberrypi", 16 | "rcswitch", 17 | "433", 18 | "rf", 19 | "wireless", 20 | "power", 21 | "outlet" 22 | ], 23 | "engines": { 24 | "node" : ">=10.0.0" 25 | }, 26 | "author": "Marvin Roger (http://www.marvinroger.fr/)", 27 | "license": "GPL-2.0", 28 | "gypfile": true, 29 | "bugs": { 30 | "url": "https://github.com/marvinroger/node-rcswitch/issues" 31 | }, 32 | "homepage": "https://github.com/marvinroger/node-rcswitch", 33 | "dependencies": { 34 | "bindings": "^1.2.1", 35 | "nan": "^2.0.8" 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/RCSwitchNode.cpp: -------------------------------------------------------------------------------- 1 | #include "RCSwitchNode.h" 2 | 3 | Nan::Persistent RCSwitchNode::constructor; 4 | 5 | void RCSwitchNode::Init(v8::Local exports) { 6 | Nan::HandleScope scope; 7 | 8 | if( wiringPiSetup() == -1 ) { 9 | Nan::ThrowTypeError("rcswitch: GPIO initialization failed"); 10 | return; 11 | } 12 | 13 | // Prepare constructor template 14 | v8::Local tpl = Nan::New(New); 15 | tpl->SetClassName(Nan::New("RCSwitch").ToLocalChecked()); 16 | tpl->InstanceTemplate()->SetInternalFieldCount(1); // 1 since this is a constructor function 17 | 18 | Nan::SetAccessor(tpl->InstanceTemplate(), Nan::New("protocol").ToLocalChecked(), GetProtocol); //, SetProtocol); TODO <- Error at compile-time... ? 19 | Nan::SetPrototypeMethod(tpl, "send", Send); 20 | 21 | // Prototype 22 | Nan::SetPrototypeMethod(tpl, "send", Send); 23 | Nan::SetPrototypeMethod(tpl, "enableTransmit", EnableTransmit); 24 | Nan::SetPrototypeMethod(tpl, "disableTransmit", DisableTransmit); 25 | Nan::SetPrototypeMethod(tpl, "switchOn", SwitchOn); 26 | Nan::SetPrototypeMethod(tpl, "switchOff", SwitchOff); 27 | Nan::SetPrototypeMethod(tpl, "sendTriState", SendTriState); 28 | Nan::SetPrototypeMethod(tpl, "enableReceive", EnableReceive); 29 | Nan::SetPrototypeMethod(tpl, "disableReceive", DisableReceive); 30 | Nan::SetPrototypeMethod(tpl, "available", Available); 31 | Nan::SetPrototypeMethod(tpl, "resetAvailable", ResetAvailable); 32 | Nan::SetPrototypeMethod(tpl, "getReceivedValue", GetReceivedValue); 33 | Nan::SetPrototypeMethod(tpl, "getReceivedBitlength", GetReceivedBitlength); 34 | Nan::SetPrototypeMethod(tpl, "getReceivedDelay", GetReceivedDelay); 35 | Nan::SetPrototypeMethod(tpl, "getReceivedProtocol", GetReceivedProtocol); 36 | Nan::SetPrototypeMethod(tpl, "getReceivedRawdata", GetReceivedRawdata); 37 | 38 | constructor.Reset(Nan::GetFunction(tpl).ToLocalChecked()); 39 | Nan::Set(exports, 40 | Nan::New("RCSwitch").ToLocalChecked(), 41 | Nan::GetFunction(tpl).ToLocalChecked()); 42 | 43 | } 44 | 45 | RCSwitchNode::RCSwitchNode() {} 46 | RCSwitchNode::~RCSwitchNode() {} 47 | 48 | void RCSwitchNode::SwitchOp(const Nan::FunctionCallbackInfo& info, bool switchOn) { 49 | Nan::HandleScope scope; 50 | RCSwitchNode* thiz = ObjectWrap::Unwrap(info.Holder()); 51 | 52 | info.GetReturnValue().Set(false); 53 | if(info.Length() == 2) { 54 | v8::Local group = info[0]; 55 | v8::Local swtch = info[1]; 56 | 57 | if(group->IsInt32() && swtch->IsInt32()) { 58 | switchOp2(Nan::To(group).ToChecked(), Nan::To(swtch).ToChecked()); 59 | info.GetReturnValue().Set(true); 60 | } else if(group->IsString() && swtch->IsInt32()) { 61 | Nan::Utf8String sGroup(group); 62 | 63 | if(sGroup.length() >= 5) { 64 | switchOp2(*sGroup, Nan::To(swtch).ToChecked()); 65 | info.GetReturnValue().Set(true); 66 | } 67 | } 68 | } else if(info.Length() == 3) { 69 | v8::Local famly = info[0]; 70 | v8::Local group = info[1]; 71 | v8::Local devce = info[2]; 72 | 73 | if(famly->IsString() && group->IsInt32() && devce->IsInt32()) { 74 | Nan::Utf8String v8str(famly); 75 | 76 | if(v8str.length() > 0) { 77 | switchOp3(*(*v8str), Nan::To(group).ToChecked(), Nan::To(devce).ToChecked()); 78 | info.GetReturnValue().Set(true); 79 | } 80 | } 81 | } 82 | } 83 | 84 | void RCSwitchNode::New(const Nan::FunctionCallbackInfo& info) { 85 | if (info.IsConstructCall()) { 86 | // Invoked as constructor: `new MyObject(...)` 87 | RCSwitchNode* obj = new RCSwitchNode(); 88 | obj->Wrap(info.This()); 89 | info.GetReturnValue().Set(info.This()); 90 | } else { 91 | // Invoked as plain function `MyObject(...)`, turn into construct call. 92 | const int argc = 0; 93 | v8::Local argv[argc]; 94 | v8::Local cons = Nan::New(constructor); 95 | info.GetReturnValue().Set(Nan::NewInstance(cons, argc, argv).ToLocalChecked()); 96 | } 97 | } 98 | 99 | void RCSwitchNode::Send(const Nan::FunctionCallbackInfo& info) { 100 | Nan::HandleScope scope; 101 | 102 | RCSwitchNode* obj = ObjectWrap::Unwrap(info.Holder()); 103 | 104 | Nan::Utf8String v8str(info[0]); 105 | obj->rcswitch.send(*v8str); 106 | 107 | info.GetReturnValue().Set(true); 108 | } 109 | 110 | void RCSwitchNode::SendTriState(const Nan::FunctionCallbackInfo& info) { 111 | Nan::HandleScope scope; 112 | 113 | RCSwitchNode* obj = ObjectWrap::Unwrap(info.Holder()); 114 | 115 | Nan::Utf8String v8str(info[0]); 116 | obj->rcswitch.sendTriState(*v8str); 117 | info.GetReturnValue().Set(true); 118 | } 119 | 120 | // notification.enableTransmit(); 121 | void RCSwitchNode::EnableTransmit(const Nan::FunctionCallbackInfo& info) { 122 | Nan::HandleScope scope; 123 | RCSwitchNode* obj = ObjectWrap::Unwrap(info.Holder()); 124 | 125 | v8::Local pinNr = info[0]; 126 | if(pinNr->IsInt32()) { 127 | obj->rcswitch.enableTransmit(Nan::To(pinNr).ToChecked()); 128 | info.GetReturnValue().Set(true); 129 | } else { 130 | info.GetReturnValue().Set(false); 131 | } 132 | } 133 | 134 | // notification.disableTransmit(); 135 | void RCSwitchNode::DisableTransmit(const Nan::FunctionCallbackInfo& info) { 136 | Nan::HandleScope scope; 137 | 138 | RCSwitchNode* obj = ObjectWrap::Unwrap(info.Holder()); 139 | obj->rcswitch.disableTransmit(); 140 | info.GetReturnValue().Set(true); 141 | } 142 | 143 | void RCSwitchNode::SwitchOn(const Nan::FunctionCallbackInfo& info) { 144 | SwitchOp(info, true); 145 | } 146 | 147 | void RCSwitchNode::SwitchOff(const Nan::FunctionCallbackInfo& info) { 148 | SwitchOp(info, false); 149 | } 150 | 151 | // notification.protocol= 152 | void RCSwitchNode::SetProtocol(v8::Local property, v8::Local value, const Nan::PropertyCallbackInfo& info) { 153 | RCSwitchNode* obj = ObjectWrap::Unwrap(info.Holder()); 154 | 155 | if(value->IsInt32()) 156 | obj->rcswitch.setProtocol(Nan::To(value).ToChecked()); 157 | } 158 | 159 | // notification.protocol 160 | void RCSwitchNode::GetProtocol(v8::Local property, const Nan::PropertyCallbackInfo& info) { 161 | RCSwitchNode* obj = ObjectWrap::Unwrap(info.Holder()); 162 | info.GetReturnValue().Set(Nan::New(obj->rcswitch.getReceivedProtocol())); 163 | } 164 | 165 | // notification.enableReceive(); 166 | void RCSwitchNode::EnableReceive(const Nan::FunctionCallbackInfo& info) { 167 | Nan::HandleScope scope; 168 | RCSwitchNode* obj = ObjectWrap::Unwrap(info.Holder()); 169 | 170 | v8::Local pinNr = info[0]; 171 | if(pinNr->IsInt32()) { 172 | obj->rcswitch.enableReceive(Nan::To(pinNr).ToChecked()); 173 | info.GetReturnValue().Set(true); 174 | } else { 175 | info.GetReturnValue().Set(false); 176 | } 177 | } 178 | 179 | // notification.disableReceive(); 180 | void RCSwitchNode::DisableReceive(const Nan::FunctionCallbackInfo& info) { 181 | Nan::HandleScope scope; 182 | 183 | RCSwitchNode* obj = ObjectWrap::Unwrap(info.Holder()); 184 | obj->rcswitch.disableReceive(); 185 | info.GetReturnValue().Set(true); 186 | } 187 | 188 | // notification.available(); 189 | void RCSwitchNode::Available(const Nan::FunctionCallbackInfo& info) { 190 | Nan::HandleScope scope; 191 | RCSwitchNode* obj = ObjectWrap::Unwrap(info.Holder()); 192 | 193 | info.GetReturnValue().Set(obj->rcswitch.available()); 194 | } 195 | 196 | // notification.resetAvailable(); 197 | void RCSwitchNode::ResetAvailable(const Nan::FunctionCallbackInfo& info) { 198 | Nan::HandleScope scope; 199 | RCSwitchNode* obj = ObjectWrap::Unwrap(info.Holder()); 200 | 201 | obj->rcswitch.resetAvailable(); 202 | info.GetReturnValue().Set(true); 203 | } 204 | 205 | // notification.getReceivedValue(); 206 | void RCSwitchNode::GetReceivedValue(const Nan::FunctionCallbackInfo& info) { 207 | Nan::HandleScope scope; 208 | RCSwitchNode* obj = ObjectWrap::Unwrap(info.Holder()); 209 | 210 | info.GetReturnValue().Set((uint32_t)obj->rcswitch.getReceivedValue()); 211 | } 212 | 213 | // notification.getReceivedBitlength(); 214 | void RCSwitchNode::GetReceivedBitlength(const Nan::FunctionCallbackInfo& info) { 215 | Nan::HandleScope scope; 216 | RCSwitchNode* obj = ObjectWrap::Unwrap(info.Holder()); 217 | 218 | info.GetReturnValue().Set(obj->rcswitch.getReceivedBitlength()); 219 | } 220 | 221 | // notification.getReceivedDelay(); 222 | void RCSwitchNode::GetReceivedDelay(const Nan::FunctionCallbackInfo& info) { 223 | Nan::HandleScope scope; 224 | RCSwitchNode* obj = ObjectWrap::Unwrap(info.Holder()); 225 | 226 | info.GetReturnValue().Set(obj->rcswitch.getReceivedDelay()); 227 | } 228 | 229 | // notification.getReceivedProtocol(); 230 | void RCSwitchNode::GetReceivedProtocol(const Nan::FunctionCallbackInfo& info) { 231 | Nan::HandleScope scope; 232 | RCSwitchNode* obj = ObjectWrap::Unwrap(info.Holder()); 233 | 234 | info.GetReturnValue().Set(obj->rcswitch.getReceivedProtocol()); 235 | } 236 | 237 | // notification.getReceivedRawdata(); 238 | void RCSwitchNode::GetReceivedRawdata(const Nan::FunctionCallbackInfo& info) { 239 | Nan::HandleScope scope; 240 | RCSwitchNode* obj = ObjectWrap::Unwrap(info.Holder()); 241 | 242 | unsigned int* data = obj->rcswitch.getReceivedRawdata(); 243 | v8::Local array = Nan::New(RCSWITCH_MAX_CHANGES); 244 | for (unsigned int i = 0; i < RCSWITCH_MAX_CHANGES; i++) { 245 | Nan::Set(array, i, Nan::New(data[i])); 246 | } 247 | info.GetReturnValue().Set(array); 248 | } 249 | -------------------------------------------------------------------------------- /src/RCSwitchNode.h: -------------------------------------------------------------------------------- 1 | #ifndef RCSWITCHNODE_H 2 | #define RCSWITCHNODE_H 3 | 4 | #include 5 | 6 | #include "../externals/rcswitch-pi/RCSwitch.h" 7 | 8 | class RCSwitchNode : public Nan::ObjectWrap { 9 | public: 10 | static void Init(v8::Local exports); 11 | 12 | private: 13 | RCSwitch rcswitch; 14 | static Nan::Persistent constructor; 15 | explicit RCSwitchNode(); 16 | ~RCSwitchNode(); 17 | 18 | static void SwitchOp(const Nan::FunctionCallbackInfo& info, bool switchOn); 19 | #define switchOp2(p1, p2) { if(switchOn) thiz->rcswitch.switchOn((p1), (p2)); else thiz->rcswitch.switchOff((p1), (p2)); } 20 | #define switchOp3(p1, p2, p3) { if(switchOn) thiz->rcswitch.switchOn((p1), (p2), (p3)); else thiz->rcswitch.switchOff((p1), (p2), (p3)); } 21 | static void New(const Nan::FunctionCallbackInfo& info); 22 | static void Send(const Nan::FunctionCallbackInfo& info); 23 | static void SendTriState(const Nan::FunctionCallbackInfo& info); 24 | static void EnableTransmit(const Nan::FunctionCallbackInfo& info); 25 | static void DisableTransmit(const Nan::FunctionCallbackInfo& info); 26 | static void SwitchOn(const Nan::FunctionCallbackInfo& info); 27 | static void SwitchOff(const Nan::FunctionCallbackInfo& info); 28 | static void EnableReceive(const Nan::FunctionCallbackInfo& info); 29 | static void DisableReceive(const Nan::FunctionCallbackInfo& info); 30 | static void Available(const Nan::FunctionCallbackInfo& info); 31 | static void ResetAvailable(const Nan::FunctionCallbackInfo& info); 32 | static void GetReceivedValue(const Nan::FunctionCallbackInfo& info); 33 | static void GetReceivedBitlength(const Nan::FunctionCallbackInfo& info); 34 | static void GetReceivedDelay(const Nan::FunctionCallbackInfo& info); 35 | static void GetReceivedProtocol(const Nan::FunctionCallbackInfo& info); 36 | static void GetReceivedRawdata(const Nan::FunctionCallbackInfo& info); 37 | 38 | static void SetProtocol(v8::Local property, v8::Local value, const Nan::PropertyCallbackInfo& info); 39 | static void GetProtocol(v8::Local property, const Nan::PropertyCallbackInfo& info); 40 | }; 41 | 42 | #endif 43 | -------------------------------------------------------------------------------- /src/rcswitch.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "RCSwitchNode.h" 3 | 4 | void InitAll(v8::Local exports) { 5 | RCSwitchNode::Init(exports); 6 | } 7 | 8 | NODE_MODULE(rcswitch, InitAll) --------------------------------------------------------------------------------