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.

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