Browse Source

add new rfswitch module to handle 433MHZ devices (#1565)

ffedoroff 7 years ago
parent
commit
9f9fee9008
4 changed files with 193 additions and 0 deletions
  1. 1 0
      app/include/user_modules.h
  2. 112 0
      app/modules/rfswitch.c
  3. 79 0
      docs/en/modules/rfswitch.md
  4. 1 0
      mkdocs.yml

+ 1 - 0
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

+ 112 - 0
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);

+ 79 - 0
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)
+```

+ 1 - 0
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'