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.

192 lines
5.1 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. // -----------------------------------------------------------------------------
  64. // WEB
  65. // -----------------------------------------------------------------------------
  66. void _rfWebSocketOnSend(JsonObject& root) {
  67. char buffer[20];
  68. root["rfbVisible"] = 1;
  69. root["rfbCount"] = relayCount();
  70. JsonArray& rfb = root.createNestedArray("rfb");
  71. for (byte id=0; id<relayCount(); id++) {
  72. for (byte status=0; status<2; status++) {
  73. JsonObject& node = rfb.createNestedObject();
  74. snprintf_P(buffer, sizeof(buffer), PSTR("%X"), _rfRetrieve(id, status == 1));
  75. node["id"] = id;
  76. node["status"] = status;
  77. node["data"] = String(buffer);
  78. }
  79. }
  80. }
  81. void _rfWebSocketOnAction(uint32_t client_id, const char * action, JsonObject& data) {
  82. if (strcmp(action, "rfblearn") == 0) _rfLearn(data["id"], data["status"]);
  83. if (strcmp(action, "rfbforget") == 0) _rfForget(data["id"], data["status"]);
  84. if (strcmp(action, "rfbsend") == 0) _rfStore(data["id"], data["status"], strtoul(data["data"], NULL, 16));
  85. }
  86. // -----------------------------------------------------------------------------
  87. void rfLoop() {
  88. if (_rfModem->available()) {
  89. static unsigned long last = 0;
  90. if (millis() - last > RF_DEBOUNCE) {
  91. last = millis();
  92. if (_rfModem->getReceivedValue() > 0) {
  93. unsigned long rf_code = _rfModem->getReceivedValue();
  94. DEBUG_MSG_P(PSTR("[RF] Received code: %X\n"), rf_code);
  95. if (_rf_learn_active) {
  96. _rf_learn_active = false;
  97. _rfStore(_rf_learn_id, _rf_learn_status, rf_code);
  98. // Websocket update
  99. #if WEB_SUPPORT
  100. char wsb[100];
  101. snprintf_P(
  102. wsb, sizeof(wsb),
  103. PSTR("{\"rfb\":[{\"id\": %d, \"status\": %d, \"data\": \"%X\"}]}"),
  104. _rf_learn_id, _rf_learn_status ? 1 : 0, rf_code);
  105. wsSend(wsb);
  106. #endif
  107. } else {
  108. unsigned char id;
  109. unsigned char value;
  110. if (_rfMatch(rf_code, id, value)) {
  111. if (2 == value) {
  112. relayToggle(id);
  113. } else {
  114. relayStatus(id, 1 == value);
  115. }
  116. }
  117. }
  118. }
  119. }
  120. _rfModem->resetAvailable();
  121. }
  122. if (_rf_learn_active && (millis() - _rf_learn_start > RF_LEARN_TIMEOUT)) {
  123. _rf_learn_active = false;
  124. }
  125. }
  126. void rfSetup() {
  127. _rfModem = new RCSwitch();
  128. _rfModem->enableReceive(RF_PIN);
  129. DEBUG_MSG_P(PSTR("[RF] RF receiver on GPIO %u\n"), RF_PIN);
  130. #if WEB_SUPPORT
  131. wsOnSendRegister(_rfWebSocketOnSend);
  132. wsOnActionRegister(_rfWebSocketOnAction);
  133. #endif
  134. // Register loop
  135. espurnaRegisterLoop(rfLoop);
  136. }
  137. #endif