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.

205 lines
5.3 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. Module key prefix: rfb (shared with RFBridge)
  5. */
  6. #if RF_SUPPORT
  7. #include <RCSwitch.h>
  8. RCSwitch * _rfModem;
  9. unsigned long _rf_learn_start = 0;
  10. unsigned char _rf_learn_id = 0;
  11. bool _rf_learn_status = true;
  12. bool _rf_learn_active = false;
  13. // -----------------------------------------------------------------------------
  14. // RF
  15. // -----------------------------------------------------------------------------
  16. unsigned long _rfRetrieve(unsigned char id, bool status) {
  17. String code = getSetting(status ? "rfbON" : "rfbOFF", id, "0");
  18. return strtoul(code.c_str(), 0, 16);
  19. }
  20. void _rfStore(unsigned char id, bool status, unsigned long code) {
  21. DEBUG_MSG_P(PSTR("[RF] Storing %d-%s => %X\n"), id, status ? "ON" : "OFF", code);
  22. char buffer[20];
  23. snprintf_P(buffer, sizeof(buffer), PSTR("%X"), code);
  24. setSetting(status ? "rfbON" : "rfbOFF", id, buffer);
  25. }
  26. void _rfLearn(unsigned char id, bool status) {
  27. _rf_learn_start = millis();
  28. _rf_learn_id = id;
  29. _rf_learn_status = status;
  30. _rf_learn_active = true;
  31. }
  32. void _rfForget(unsigned char id, bool status) {
  33. delSetting(status ? "rfbON" : "rfbOFF", id);
  34. // Websocket update
  35. #if WEB_SUPPORT
  36. char wsb[100];
  37. snprintf_P(wsb, sizeof(wsb), PSTR("{\"rfb\":[{\"id\": %d, \"status\": %d, \"data\": \"\"}]}"), id, status ? 1 : 0);
  38. wsSend(wsb);
  39. #endif
  40. }
  41. bool _rfMatch(unsigned long code, unsigned char& relayID, unsigned char& value) {
  42. bool found = false;
  43. DEBUG_MSG_P(PSTR("[RF] Trying to match code %X\n"), code);
  44. for (unsigned char i=0; i<relayCount(); i++) {
  45. unsigned long code_on = _rfRetrieve(i, true);
  46. unsigned long code_off = _rfRetrieve(i, false);
  47. if (code == code_on) {
  48. DEBUG_MSG_P(PSTR("[RF] Match ON code for relay %d\n"), i);
  49. value = 1;
  50. found = true;
  51. }
  52. if (code == code_off) {
  53. DEBUG_MSG_P(PSTR("[RF] Match OFF code for relay %d\n"), i);
  54. if (found) value = 2;
  55. found = true;
  56. }
  57. if (found) {
  58. relayID = i;
  59. return true;
  60. }
  61. }
  62. return false;
  63. }
  64. bool _rfKeyCheck(const char * key) {
  65. return (strncmp(key, "rfb", 3) == 0);
  66. }
  67. // -----------------------------------------------------------------------------
  68. // WEB
  69. // -----------------------------------------------------------------------------
  70. #if WEB_SUPPORT
  71. void _rfWebSocketOnSend(JsonObject& root) {
  72. char buffer[20];
  73. root["rfbVisible"] = 1;
  74. root["rfbCount"] = relayCount();
  75. JsonArray& rfb = root.createNestedArray("rfb");
  76. for (byte id=0; id<relayCount(); id++) {
  77. for (byte status=0; status<2; status++) {
  78. JsonObject& node = rfb.createNestedObject();
  79. snprintf_P(buffer, sizeof(buffer), PSTR("%X"), _rfRetrieve(id, status == 1));
  80. node["id"] = id;
  81. node["status"] = status;
  82. node["data"] = String(buffer);
  83. }
  84. }
  85. }
  86. void _rfWebSocketOnAction(uint32_t client_id, const char * action, JsonObject& data) {
  87. if (strcmp(action, "rfblearn") == 0) _rfLearn(data["id"], data["status"]);
  88. if (strcmp(action, "rfbforget") == 0) _rfForget(data["id"], data["status"]);
  89. if (strcmp(action, "rfbsend") == 0) _rfStore(data["id"], data["status"], data["data"].as<long>());
  90. }
  91. #endif
  92. // -----------------------------------------------------------------------------
  93. void rfLoop() {
  94. if (_rfModem->available()) {
  95. static unsigned long last = 0;
  96. if (millis() - last > RF_DEBOUNCE) {
  97. last = millis();
  98. if (_rfModem->getReceivedValue() > 0) {
  99. unsigned long rf_code = _rfModem->getReceivedValue();
  100. DEBUG_MSG_P(PSTR("[RF] Received code: %X\n"), rf_code);
  101. if (_rf_learn_active) {
  102. _rf_learn_active = false;
  103. _rfStore(_rf_learn_id, _rf_learn_status, rf_code);
  104. // Websocket update
  105. #if WEB_SUPPORT
  106. char wsb[100];
  107. snprintf_P(
  108. wsb, sizeof(wsb),
  109. PSTR("{\"rfb\":[{\"id\": %d, \"status\": %d, \"data\": \"%X\"}]}"),
  110. _rf_learn_id, _rf_learn_status ? 1 : 0, rf_code);
  111. wsSend(wsb);
  112. #endif
  113. } else {
  114. unsigned char id;
  115. unsigned char value;
  116. if (_rfMatch(rf_code, id, value)) {
  117. if (2 == value) {
  118. relayToggle(id);
  119. } else {
  120. relayStatus(id, 1 == value);
  121. }
  122. }
  123. }
  124. }
  125. }
  126. _rfModem->resetAvailable();
  127. }
  128. if (_rf_learn_active && (millis() - _rf_learn_start > RF_LEARN_TIMEOUT)) {
  129. _rf_learn_active = false;
  130. }
  131. }
  132. void rfSetup() {
  133. _rfModem = new RCSwitch();
  134. _rfModem->enableReceive(RF_PIN);
  135. DEBUG_MSG_P(PSTR("[RF] RF receiver on GPIO %u\n"), RF_PIN);
  136. #if WEB_SUPPORT
  137. wsOnSendRegister(_rfWebSocketOnSend);
  138. wsOnActionRegister(_rfWebSocketOnAction);
  139. #endif
  140. // Key Check
  141. settingsRegisterKeyCheck(_rfKeyCheck);
  142. // Register loop
  143. espurnaRegisterLoop(rfLoop);
  144. }
  145. #endif