From 9f9fee900841b2062c144b4e4a1010f7d3901f16 Mon Sep 17 00:00:00 2001 From: ffedoroff Date: Fri, 2 Dec 2016 03:19:01 +0600 Subject: [PATCH] add new rfswitch module to handle 433MHZ devices (#1565) --- app/include/user_modules.h | 1 + app/modules/rfswitch.c | 112 ++++++++++++++++++++++++++++++++++++ docs/en/modules/rfswitch.md | 79 +++++++++++++++++++++++++ mkdocs.yml | 1 + 4 files changed, 193 insertions(+) create mode 100644 app/modules/rfswitch.c create mode 100644 docs/en/modules/rfswitch.md diff --git a/app/include/user_modules.h b/app/include/user_modules.h index f34285f7..990138b5 100644 --- a/app/include/user_modules.h +++ b/app/include/user_modules.h @@ -47,6 +47,7 @@ //#define LUA_USE_MODULES_PERF //#define LUA_USE_MODULES_PWM //#define LUA_USE_MODULES_RC +//#define LUA_USE_MODULES_RFSWITCH //#define LUA_USE_MODULES_ROTARY //#define LUA_USE_MODULES_RTCFIFO //#define LUA_USE_MODULES_RTCMEM diff --git a/app/modules/rfswitch.c b/app/modules/rfswitch.c new file mode 100644 index 00000000..81d978b5 --- /dev/null +++ b/app/modules/rfswitch.c @@ -0,0 +1,112 @@ +/* + * https://github.com/ffedoroff/nodemcu-firmware contributed by Roman Fedorov + * + * Module for operate 433/315Mhz devices like power outlet sockets, relays, etc. + * This will most likely work with all popular low cost power outlet sockets + * with a SC5262 / SC5272, HX2262 / HX2272, PT2262 / PT2272, EV1527, + * RT1527, FP1527 or HS1527 chipset. + * + * This module using some code from original rc-switch arduino lib + * https://github.com/sui77/rc-switch/ but unfortunatelly NodeMCU and Arduino + * are not fully compatable, and it cause for full rewrite rc-switch lib into new rfswitch lib. + */ + +#include "module.h" +#include "lauxlib.h" +#include "platform.h" +#include "user_interface.h" + +typedef struct HighLow { + uint8_t high; + uint8_t low; +} HighLow; + +typedef struct Protocol { + int pulseLength; + HighLow syncFactor; + HighLow zero; + HighLow one; + /** @brief if true inverts the high and low logic levels in the HighLow structs */ + bool invertedSignal; +} Protocol; + + +/* Format for protocol definitions: + * {pulselength, Sync bit, "0" bit, "1" bit} + * + * pulselength: pulse length in microseconds, e.g. 350 + * Sync bit: {1, 31} means 1 high pulse and 31 low pulses + * (perceived as a 31*pulselength long pulse, total length of sync bit is + * 32*pulselength microseconds), i.e: + * _ + * | |_______________________________ (don't count the vertical bars) + * "0" bit: waveform for a data bit of value "0", {1, 3} means 1 high pulse + * and 3 low pulses, total length (1+3)*pulselength, i.e: + * _ + * | |___ + * "1" bit: waveform for a data bit of value "1", e.g. {3,1}: + * ___ + * | |_ + * + * These are combined to form Tri-State bits when sending or receiving codes. + */ +static const Protocol proto[] = { + { 350, { 1, 31 }, { 1, 3 }, { 3, 1 }, false }, // protocol 1 + { 650, { 1, 10 }, { 1, 2 }, { 2, 1 }, false }, // protocol 2 + { 100, { 30, 71 }, { 4, 11 }, { 9, 6 }, false }, // protocol 3 + { 380, { 1, 6 }, { 1, 3 }, { 3, 1 }, false }, // protocol 4 + { 500, { 6, 14 }, { 1, 2 }, { 2, 1 }, false }, // protocol 5 + { 450, { 23, 1 }, { 1, 2 }, { 2, 1 }, true } // protocol 6 (HT6P20B) +}; + +/** + * Transmit a single high-low pulse. + */ +void transmit(HighLow pulses, bool invertedSignal, int pulseLength, int pin) { + platform_gpio_write(pin, invertedSignal); + os_delay_us(pulseLength * pulses.high); + platform_gpio_write(pin, !invertedSignal); + os_delay_us(pulseLength * pulses.low); +} + +/** + * Transmit the first 'length' bits of the integer 'code'. The + * bits are sent from MSB to LSB, i.e., first the bit at position length-1, + * then the bit at position length-2, and so on, till finally the bit at position 0. + */ +void send(unsigned long protocol_id, unsigned long pulse_length, unsigned long repeat, unsigned long pin, unsigned long value, unsigned int length) { + platform_gpio_mode(pin, PLATFORM_GPIO_OUTPUT, PLATFORM_GPIO_FLOAT); + Protocol p = proto[protocol_id-1]; + for (int nRepeat = 0; nRepeat < repeat; nRepeat++) { + for (int i = length-1; i >= 0; i--) { + if (value & (1L << i)) + transmit(p.one, p.invertedSignal, pulse_length, pin); + else + transmit(p.zero, p.invertedSignal, pulse_length, pin); + } + transmit(p.syncFactor, p.invertedSignal, pulse_length, pin); + platform_gpio_write(pin, false); + } +} + + +static int rfswitch_send( lua_State *L ) +{ + unsigned int protocol_id = luaL_checkinteger( L, 1 ); + unsigned int pulse_length = luaL_checkinteger( L, 2 ); + unsigned int repeat = luaL_checkinteger( L, 3 ); + unsigned int pin = luaL_checkinteger( L, 4 ); + unsigned long value = luaL_checkinteger( L, 5 ); + unsigned long length = luaL_checkinteger( L, 6 ); + send(protocol_id, pulse_length, repeat, pin, value, length); + return 0; +} + +// Module function map +static const LUA_REG_TYPE rfswitch_map[] = +{ + { LSTRKEY( "send" ), LFUNCVAL( rfswitch_send ) }, + { LNILKEY, LNILVAL } +}; + +NODEMCU_MODULE(RFSWITCH, "rfswitch", rfswitch_map, NULL); diff --git a/docs/en/modules/rfswitch.md b/docs/en/modules/rfswitch.md new file mode 100644 index 00000000..18282072 --- /dev/null +++ b/docs/en/modules/rfswitch.md @@ -0,0 +1,79 @@ +# rfswitch Module +| Since | Origin / Contributor | Maintainer | Source | +| :----- | :-------------------- | :---------- | :------ | +| 2016-12-01 | [Roman Fedorov](https://github.com/ffedoroff) | [Roman Fedorov](https://github.com/ffedoroff) | [rfswitch.c](../../../app/modules/rfswitch.c)| + + +Module for operate 433/315Mhz devices like power outlet sockets, relays, etc. +This will most likely work with all popular low cost power outlet sockets +with a SC5262 / SC5272, HX2262 / HX2272, PT2262 / PT2272, EV1527, +RT1527, FP1527 or HS1527 chipset. + +This module using some code from original [rc-switch](https://github.com/sui77/rc-switch/) arduino lib +but NodeMCU and Arduino are not fully compatible, and it cause +for full rewrite **rc-switch** into this new **rfswitch** lib for NodeMCU with Lua support. + +### Connection of transmitter + +| Transmitter | ESP8266 | comments | +| :----------- | :------- | :------------------------------ | +| vin or + | 3V3 | 3.3 - 5 volts on ESP8266 or other power source | +| ground or - | GND | ground should be connected to ESP8266 and to power source | +| data pin | 6 | almost any pin on ESP8266 | + +You can read more about connection, [here](https://alexbloggt.com/wp-content/uploads/2015/10/nodemcu_433_transmitter.png) or [here](https://alexbloggt.com/funksteckdosensteuerung-mit-esp8266/). + +### Selecting proper protocol +Current library supports **transmitting** using 6 different protocols +and you should use proper one for your needs. +Current lua library rfswitch doesn't support **receiver** functional yet, so you cannot +listen radio air and get protocol details using lua. + +The easiest way to get correct protocol is connect radio receiver to your ESP8266 or [Arduino](https://github.com/sui77/rc-switch/wiki/HowTo_Receive), +then run [ReceiveDemo_Advanced.ino](https://github.com/sui77/rc-switch/blob/master/examples/ReceiveDemo_Advanced/ReceiveDemo_Advanced.ino) +and view output in serial console ([example1](http://www.instructables.com/id/Control-CoTech-Remote-Switch-With-Arduino-433Mhz/?ALLSTEPS), +[example2](http://randomnerdtutorials.com/esp8266-remote-controlled-sockets/)). + +You should get something like this: +``` +Decimal: 11001351 (24Bit) +Binary: 101001111101111000000111 +Tri-State: not applicable +PulseLength: 517 microseconds +Protocol: 5 + +Raw data: 7200,1004,528,504,1048,980,336,1176,356,1176,352,1180,1108,412,356,1172,364,1168,356,1160,1176,1124,412,336,1180,1116,440,328,1188,340,1228,1060,416,1160,380,1160,1108,464,1068,436,328,1232,1060,412,1116,440,1088,428,3024, +``` +More detailed about low level protocol specifications could be found [here](https://github.com/sui77/rc-switch/wiki/KnowHow_LineCoding) +You can visualize a telegram copy the raw data by paste it into [http://test.sui.li/oszi/]() + +## rfswitch.send() +Transmit value ising radio module. + +#### Syntax +`rfswitch.send(protocol_id, pulse_length, repeat, pin, value, length)` + +#### Parameters +- `protocol_id` positive integer value, from 1-6 +- `pulse_length` length of one pulse in microseconds, usually from 100 till 650 +- `repeat` repeat value, usually from 1 till 5. This is synchronous task. +Setting the repeat count to a large value will cause problems. +The recommended limit is about 1-4, if you need more, +then call it asynchronously a few more times (e.g. using [node.task.post](../modules/node/#nodetaskpost)) +- `pin` IO index of pin, example 6 is for GPIO12 [see more](../modules/gpio/) +- `value` positive integer value, this is the primary data which will be sent +- `length` bit length of value, if value length is 3 bytes, then length is 24 + +#### Returns +`nil` + +#### Example +```lua +-- lua transmit radio code using protocol #1 +-- pulse_length 300 microseconds +-- repeat 5 times +-- use pin #7 (GPIO13) +-- value to send is 560777 +-- value length is 24 bits (3 bytes) +rfswitch.send(1, 300, 5, 7, 560777, 24) +``` diff --git a/mkdocs.yml b/mkdocs.yml index c6b81d46..8b05b0d2 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -64,6 +64,7 @@ pages: - 'perf': 'en/modules/perf.md' - 'pwm' : 'en/modules/pwm.md' - 'rc' : 'en/modules/rc.md' + - 'rfswitch' : 'en/modules/rfswitch.md' - 'rotary' : 'en/modules/rotary.md' - 'rtcfifo': 'en/modules/rtcfifo.md' - 'rtcmem': 'en/modules/rtcmem.md'