Fork of the espurna firmware for `mhsw` switches
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

246 lines
6.2 KiB

6 years ago
  1. /*
  2. RF MODULE
  3. Copyright (C) 2016-2018 by Xose Pérez <xose dot perez at gmail dot com>
  4. */
  5. #if RF_SUPPORT
  6. #include <RCSwitch.h>
  7. RCSwitch * _rfModem;
  8. unsigned long _rf_learn_start = 0;
  9. unsigned char _rf_learn_id = 0;
  10. bool _rf_learn_status = true;
  11. bool _rf_learn_active = false;
  12. // -----------------------------------------------------------------------------
  13. // RF
  14. // -----------------------------------------------------------------------------
  15. unsigned long _rfRetrieve(unsigned char id, bool status) {
  16. String code = getSetting(status ? "rfbON" : "rfbOFF", id, "0");
  17. return strtoul(code.c_str(), 0, 16);
  18. }
  19. void _rfStore(unsigned char id, bool status, unsigned long code) {
  20. DEBUG_MSG_P(PSTR("[RF] Storing %d-%s => %X\n"), id, status ? "ON" : "OFF", code);
  21. char buffer[20];
  22. snprintf_P(buffer, sizeof(buffer), PSTR("%X"), code);
  23. setSetting(status ? "rfbON" : "rfbOFF", id, buffer);
  24. }
  25. void _rfLearn(unsigned char id, bool status) {
  26. _rf_learn_start = millis();
  27. _rf_learn_id = id;
  28. _rf_learn_status = status;
  29. _rf_learn_active = true;
  30. }
  31. void _rfForget(unsigned char id, bool status) {
  32. delSetting(status ? "rfbON" : "rfbOFF", id);
  33. // Websocket update
  34. #if WEB_SUPPORT
  35. char wsb[100];
  36. snprintf_P(wsb, sizeof(wsb), PSTR("{\"rfb\":[{\"id\": %d, \"status\": %d, \"data\": \"\"}]}"), id, status ? 1 : 0);
  37. wsSend(wsb);
  38. #endif
  39. }
  40. bool _rfMatch(unsigned long code, unsigned char& relayID, unsigned char& value) {
  41. bool found = false;
  42. DEBUG_MSG_P(PSTR("[RF] Trying to match code %X\n"), code);
  43. for (unsigned char i=0; i<relayCount(); i++) {
  44. unsigned long code_on = _rfRetrieve(i, true);
  45. unsigned long code_off = _rfRetrieve(i, false);
  46. if (code == code_on) {
  47. DEBUG_MSG_P(PSTR("[RF] Match ON code for relay %d\n"), i);
  48. value = 1;
  49. found = true;
  50. }
  51. if (code == code_off) {
  52. DEBUG_MSG_P(PSTR("[RF] Match OFF code for relay %d\n"), i);
  53. if (found) value = 2;
  54. found = true;
  55. }
  56. if (found) {
  57. relayID = i;
  58. return true;
  59. }
  60. }
  61. return false;
  62. }
  63. #if TERMINAL_SUPPORT
  64. void _rfInitCommands() {
  65. settingsRegisterCommand(F("LEARN"), [](Embedis* e) {
  66. if (e->argc < 3) {
  67. DEBUG_MSG_P(PSTR("-ERROR: Wrong arguments\n"));
  68. return;
  69. }
  70. int id = String(e->argv[1]).toInt();
  71. if (id >= relayCount()) {
  72. DEBUG_MSG_P(PSTR("-ERROR: Wrong relayID (%d)\n"), id);
  73. return;
  74. }
  75. int status = String(e->argv[2]).toInt();
  76. _rfLearn(id, status == 1);
  77. DEBUG_MSG_P(PSTR("+OK\n"));
  78. });
  79. settingsRegisterCommand(F("FORGET"), [](Embedis* e) {
  80. if (e->argc < 3) {
  81. DEBUG_MSG_P(PSTR("-ERROR: Wrong arguments\n"));
  82. return;
  83. }
  84. int id = String(e->argv[1]).toInt();
  85. if (id >= relayCount()) {
  86. DEBUG_MSG_P(PSTR("-ERROR: Wrong relayID (%d)\n"), id);
  87. return;
  88. }
  89. int status = String(e->argv[2]).toInt();
  90. _rfForget(id, status == 1);
  91. DEBUG_MSG_P(PSTR("+OK\n"));
  92. });
  93. }
  94. #endif // TERMINAL_SUPPORT
  95. // -----------------------------------------------------------------------------
  96. // WEB
  97. // -----------------------------------------------------------------------------
  98. void _rfWebSocketOnSend(JsonObject& root) {
  99. char buffer[20];
  100. root["rfbVisible"] = 1;
  101. root["rfbCount"] = relayCount();
  102. JsonArray& rfb = root.createNestedArray("rfb");
  103. for (byte id=0; id<relayCount(); id++) {
  104. for (byte status=0; status<2; status++) {
  105. JsonObject& node = rfb.createNestedObject();
  106. snprintf_P(buffer, sizeof(buffer), PSTR("%X"), _rfRetrieve(id, status == 1));
  107. node["id"] = id;
  108. node["status"] = status;
  109. node["data"] = String(buffer);
  110. }
  111. }
  112. }
  113. void _rfWebSocketOnAction(uint32_t client_id, const char * action, JsonObject& data) {
  114. if (strcmp(action, "rfblearn") == 0) _rfLearn(data["id"], data["status"]);
  115. if (strcmp(action, "rfbforget") == 0) _rfForget(data["id"], data["status"]);
  116. if (strcmp(action, "rfbsend") == 0) _rfStore(data["id"], data["status"], data["data"].as<long>());
  117. }
  118. // -----------------------------------------------------------------------------
  119. void rfLoop() {
  120. if (_rfModem->available()) {
  121. static unsigned long last = 0;
  122. if (millis() - last > RF_DEBOUNCE) {
  123. last = millis();
  124. if (_rfModem->getReceivedValue() > 0) {
  125. unsigned long rf_code = _rfModem->getReceivedValue();
  126. DEBUG_MSG_P(PSTR("[RF] Received code: %X\n"), rf_code);
  127. if (_rf_learn_active) {
  128. _rf_learn_active = false;
  129. _rfStore(_rf_learn_id, _rf_learn_status, rf_code);
  130. // Websocket update
  131. #if WEB_SUPPORT
  132. char wsb[100];
  133. snprintf_P(
  134. wsb, sizeof(wsb),
  135. PSTR("{\"rfb\":[{\"id\": %d, \"status\": %d, \"data\": \"%X\"}]}"),
  136. _rf_learn_id, _rf_learn_status ? 1 : 0, rf_code);
  137. wsSend(wsb);
  138. #endif
  139. } else {
  140. unsigned char id;
  141. unsigned char value;
  142. if (_rfMatch(rf_code, id, value)) {
  143. if (2 == value) {
  144. relayToggle(id);
  145. } else {
  146. relayStatus(id, 1 == value);
  147. }
  148. }
  149. }
  150. }
  151. }
  152. _rfModem->resetAvailable();
  153. }
  154. if (_rf_learn_active && (millis() - _rf_learn_start > RF_LEARN_TIMEOUT)) {
  155. _rf_learn_active = false;
  156. }
  157. }
  158. void rfSetup() {
  159. _rfModem = new RCSwitch();
  160. _rfModem->enableReceive(RF_PIN);
  161. DEBUG_MSG_P(PSTR("[RF] RF receiver on GPIO %u\n"), RF_PIN);
  162. #if WEB_SUPPORT
  163. wsOnSendRegister(_rfWebSocketOnSend);
  164. wsOnActionRegister(_rfWebSocketOnAction);
  165. #endif
  166. #if TERMINAL_SUPPORT
  167. _rfInitCommands();
  168. #endif
  169. // Register loop
  170. espurnaRegisterLoop(rfLoop);
  171. }
  172. #endif