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.

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