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.

241 lines
6.1 KiB

  1. /*
  2. ITEAD RF BRIDGE MODULE
  3. Copyright (C) 2017 by Xose Pérez <xose dot perez at gmail dot com>
  4. */
  5. #ifdef SONOFF_RFBRIDGE
  6. #define RF_MESSAGE_SIZE 9
  7. #define RF_SEND_TIMES 3
  8. #define RF_SEND_DELAY 50
  9. #define RF_CODE_START 0xAA
  10. #define RF_CODE_ACK 0xA0
  11. #define RF_CODE_LEARN 0xA1
  12. #define RF_CODE_LEARN_KO 0xA2
  13. #define RF_CODE_LEARN_OK 0xA3
  14. #define RF_CODE_RFIN 0xA4
  15. #define RF_CODE_RFOUT 0xA5
  16. #define RF_CODE_STOP 0x55
  17. unsigned char _uartbuf[RF_MESSAGE_SIZE+3] = {0};
  18. unsigned char _uartpos = 0;
  19. unsigned char _learnId = 0;
  20. bool _learnState = true;
  21. // -----------------------------------------------------------------------------
  22. // PRIVATES
  23. // -----------------------------------------------------------------------------
  24. void _rfbAck() {
  25. DEBUG_MSG_P(PSTR("[RFBRIDGE] Sending ACK\n"));
  26. Serial.write(RF_CODE_START);
  27. Serial.write(RF_CODE_ACK);
  28. Serial.write(RF_CODE_STOP);
  29. Serial.flush();
  30. }
  31. void _rfbLearn() {
  32. DEBUG_MSG_P(PSTR("[RFBRIDGE] Sending LEARN\n"));
  33. Serial.write(RF_CODE_START);
  34. Serial.write(RF_CODE_LEARN);
  35. Serial.write(RF_CODE_STOP);
  36. Serial.flush();
  37. }
  38. void _rfbSend(byte * message) {
  39. Serial.write(RF_CODE_START);
  40. Serial.write(RF_CODE_RFOUT);
  41. for (unsigned char j=0; j<RF_MESSAGE_SIZE; j++) {
  42. Serial.write(message[j]);
  43. }
  44. Serial.write(RF_CODE_STOP);
  45. Serial.flush();
  46. }
  47. void _rfbSend(byte * message, int times) {
  48. char buffer[RF_MESSAGE_SIZE];
  49. _rfbToChar(message, buffer);
  50. DEBUG_MSG_P(PSTR("[RFBRIDGE] Sending MESSAGE '%s' %d time(s)\n"), buffer, times);
  51. for (int i=0; i<times; i++) {
  52. if (i>0) {
  53. unsigned long start = millis();
  54. while (millis() - start < RF_SEND_DELAY) delay(1);
  55. }
  56. _rfbSend(message);
  57. }
  58. }
  59. void _rfbDecode() {
  60. byte action = _uartbuf[0];
  61. char buffer[RF_MESSAGE_SIZE * 2 + 1] = {0};
  62. DEBUG_MSG_P(PSTR("[RFBRIDGE] Action 0x%02X\n"), action);
  63. if (action == RF_CODE_LEARN_KO) {
  64. _rfbAck();
  65. DEBUG_MSG_P(PSTR("[RFBRIDGE] Learn timeout\n"));
  66. }
  67. if (action == RF_CODE_LEARN_OK || action == RF_CODE_RFIN) {
  68. _rfbToChar(&_uartbuf[1], buffer);
  69. mqttSend(MQTT_TOPIC_RFIN, buffer);
  70. _rfbAck();
  71. }
  72. if (action == RF_CODE_LEARN_OK) {
  73. // TODO: notify websocket
  74. _rfbStore(_learnId, _learnState, buffer);
  75. DEBUG_MSG_P(PSTR("[RFBRIDGE] Learn success. Storing %d-%s => '%s'\n"), _learnId, _learnState ? "ON" : "OFF", buffer);
  76. }
  77. if (action == RF_CODE_RFIN) {
  78. DEBUG_MSG_P(PSTR("[RFBRIDGE] Forward message '%s'\n"), buffer);
  79. }
  80. }
  81. void _rfbReceive() {
  82. static bool receiving = false;
  83. while (Serial.available()) {
  84. yield();
  85. byte c = Serial.read();
  86. //DEBUG_MSG_P(PSTR("[RFBRIDGE] Received 0x%02X\n"), c);
  87. if (receiving) {
  88. if (c == RF_CODE_STOP) {
  89. _rfbDecode();
  90. receiving = false;
  91. } else {
  92. _uartbuf[_uartpos++] = c;
  93. }
  94. } else if (c == RF_CODE_START) {
  95. _uartpos = 0;
  96. receiving = true;
  97. }
  98. }
  99. }
  100. /*
  101. From an hexa char array ("A220EE...") to a byte array (half the size)
  102. */
  103. bool _rfbToArray(const char * in, byte * out) {
  104. if (strlen(in) != RF_MESSAGE_SIZE * 2) return false;
  105. char tmp[3] = {0};
  106. for (unsigned char p = 0; p<RF_MESSAGE_SIZE; p++) {
  107. memcpy(tmp, &in[p*2], 2);
  108. out[p] = strtol(tmp, NULL, 16);
  109. }
  110. return true;
  111. }
  112. /*
  113. From a byte array to an hexa char array ("A220EE...", double the size)
  114. */
  115. bool _rfbToChar(byte * in, char * out) {
  116. for (unsigned char p = 0; p<RF_MESSAGE_SIZE; p++) {
  117. sprintf(&out[p*2], "%02X", in[p]);
  118. }
  119. return true;
  120. }
  121. void _rfbMqttCallback(unsigned int type, const char * topic, const char * payload) {
  122. if (type == MQTT_CONNECT_EVENT) {
  123. char buffer[strlen(MQTT_TOPIC_RFLEARN) + 3];
  124. sprintf(buffer, "%s/+", MQTT_TOPIC_RFLEARN);
  125. mqttSubscribe(buffer);
  126. mqttSubscribe(MQTT_TOPIC_RFOUT);
  127. }
  128. if (type == MQTT_MESSAGE_EVENT) {
  129. // Match topic
  130. String t = mqttSubtopic((char *) topic);
  131. // Check if should go into learn mode
  132. if (t.startsWith(MQTT_TOPIC_RFLEARN)) {
  133. _learnId = t.substring(strlen(MQTT_TOPIC_RFLEARN)+1).toInt();
  134. if (_learnId >= relayCount()) {
  135. DEBUG_MSG_P(PSTR("[RFBRIDGE] Wrong learnID (%d)\n"), _learnId);
  136. return;
  137. }
  138. _learnState = (char)payload[0] != '0';
  139. _rfbLearn();
  140. }
  141. if (t.equals(MQTT_TOPIC_RFOUT)) {
  142. byte message[RF_MESSAGE_SIZE];
  143. if (_rfbToArray(payload, message)) {
  144. _rfbSend(message, RF_SEND_TIMES);
  145. }
  146. }
  147. }
  148. }
  149. void _rfbStore(unsigned char id, bool status, char * code) {
  150. char key[8] = {0};
  151. sprintf(key, "rfb%d%s", id, status ? "on" : "off");
  152. setSetting(key, code);
  153. }
  154. String _rfbRetrieve(unsigned char id, bool status) {
  155. char key[8] = {0};
  156. sprintf(key, "rfb%d%s", id, status ? "on" : "off");
  157. return getSetting(key);
  158. }
  159. // -----------------------------------------------------------------------------
  160. // PUBLIC
  161. // -----------------------------------------------------------------------------
  162. void rfbState(unsigned char id, bool status) {
  163. String value = _rfbRetrieve(id, status);
  164. DEBUG_MSG_P(PSTR("[RFBRIDGE] Retrieving value for %d-%s => %s\n"), id, status ? "ON" : "OFF", value.c_str());
  165. if (value.length() > 0) {
  166. byte message[RF_MESSAGE_SIZE];
  167. _rfbToArray(value.c_str(), message);
  168. _rfbSend(message, RF_SEND_TIMES);
  169. }
  170. }
  171. void rfbLearn(unsigned char id, bool status) {
  172. _learnId = id;
  173. _learnState = status;
  174. _rfbLearn();
  175. }
  176. void rfbForget(unsigned char id, bool status) {
  177. char key[8] = {0};
  178. sprintf(key, "rfb%d%s", id, status ? "on" : "off");
  179. delSetting(key);
  180. }
  181. // -----------------------------------------------------------------------------
  182. // SETUP & LOOP
  183. // -----------------------------------------------------------------------------
  184. void rfbSetup() {
  185. mqttRegister(_rfbMqttCallback);
  186. }
  187. void rfbLoop() {
  188. _rfbReceive();
  189. }
  190. #endif