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.

795 lines
20 KiB

7 years ago
  1. /*
  2. RF BRIDGE MODULE
  3. Copyright (C) 2016-2019 by Xose Pérez <xose dot perez at gmail dot com>
  4. */
  5. #if RF_SUPPORT
  6. #include <queue>
  7. #include <Ticker.h>
  8. #if RFB_DIRECT
  9. #include <RCSwitch.h>
  10. #endif
  11. // -----------------------------------------------------------------------------
  12. // DEFINITIONS
  13. // -----------------------------------------------------------------------------
  14. // EFM8 Protocol
  15. #define RF_MESSAGE_SIZE 9
  16. #define RF_MAX_MESSAGE_SIZE (112+4)
  17. #define RF_CODE_START 0xAA
  18. #define RF_CODE_ACK 0xA0
  19. #define RF_CODE_LEARN 0xA1
  20. #define RF_CODE_LEARN_KO 0xA2
  21. #define RF_CODE_LEARN_OK 0xA3
  22. #define RF_CODE_RFIN 0xA4
  23. #define RF_CODE_RFOUT 0xA5
  24. #define RF_CODE_SNIFFING_ON 0xA6
  25. #define RF_CODE_SNIFFING_OFF 0xA7
  26. #define RF_CODE_RFOUT_NEW 0xA8
  27. #define RF_CODE_LEARN_NEW 0xA9
  28. #define RF_CODE_LEARN_KO_NEW 0xAA
  29. #define RF_CODE_LEARN_OK_NEW 0xAB
  30. #define RF_CODE_RFOUT_BUCKET 0xB0
  31. #define RF_CODE_STOP 0x55
  32. // Settings
  33. #define RF_MAX_KEY_LENGTH (9)
  34. // -----------------------------------------------------------------------------
  35. // GLOBALS TO THE MODULE
  36. // -----------------------------------------------------------------------------
  37. unsigned char _uartbuf[RF_MESSAGE_SIZE+3] = {0};
  38. unsigned char _uartpos = 0;
  39. unsigned char _learnId = 0;
  40. bool _learnStatus = true;
  41. bool _rfbin = false;
  42. typedef struct {
  43. byte code[RF_MESSAGE_SIZE];
  44. byte times;
  45. } rfb_message_t;
  46. static std::queue<rfb_message_t> _rfb_message_queue;
  47. #if RFB_DIRECT
  48. RCSwitch * _rfModem;
  49. bool _learning = false;
  50. #endif
  51. bool _rfb_receive = false;
  52. bool _rfb_transmit = false;
  53. unsigned char _rfb_repeat = RF_SEND_TIMES;
  54. // -----------------------------------------------------------------------------
  55. // PRIVATES
  56. // -----------------------------------------------------------------------------
  57. /*
  58. From a byte array to an hexa char array ("A220EE...", double the size)
  59. */
  60. static bool _rfbToChar(byte * in, char * out, int n = RF_MESSAGE_SIZE) {
  61. for (unsigned char p = 0; p<n; p++) {
  62. sprintf_P(&out[p*2], PSTR("%02X"), in[p]);
  63. }
  64. return true;
  65. }
  66. #if WEB_SUPPORT
  67. void _rfbWebSocketSendCodeArray(JsonObject& root, unsigned char start, unsigned char size) {
  68. JsonObject& rfb = root.createNestedObject("rfb");
  69. rfb["size"] = size;
  70. rfb["start"] = start;
  71. JsonArray& on = rfb.createNestedArray("on");
  72. JsonArray& off = rfb.createNestedArray("off");
  73. for (byte id=start; id<start+size; id++) {
  74. on.add(rfbRetrieve(id, true));
  75. off.add(rfbRetrieve(id, false));
  76. }
  77. }
  78. void _rfbWebSocketOnVisible(JsonObject& root) {
  79. root["rfbVisible"] = 1;
  80. }
  81. void _rfbWebSocketOnConnected(JsonObject& root) {
  82. root["rfbRepeat"] = getSetting("rfbRepeat", RF_SEND_TIMES).toInt();
  83. root["rfbCount"] = relayCount();
  84. #if RFB_DIRECT
  85. root["rfbdirectVisible"] = 1;
  86. root["rfbRX"] = getSetting("rfbRX", RFB_RX_PIN).toInt();
  87. root["rfbTX"] = getSetting("rfbTX", RFB_TX_PIN).toInt();
  88. #endif
  89. }
  90. void _rfbWebSocketOnAction(uint32_t client_id, const char * action, JsonObject& data) {
  91. if (strcmp(action, "rfblearn") == 0) rfbLearn(data["id"], data["status"]);
  92. if (strcmp(action, "rfbforget") == 0) rfbForget(data["id"], data["status"]);
  93. if (strcmp(action, "rfbsend") == 0) rfbStore(data["id"], data["status"], data["data"].as<const char*>());
  94. }
  95. bool _rfbWebSocketOnKeyCheck(const char * key, JsonVariant& value) {
  96. return (strncmp(key, "rfb", 3) == 0);
  97. }
  98. void _rfbWebSocketOnData(JsonObject& root) {
  99. _rfbWebSocketSendCodeArray(root, 0, relayCount());
  100. }
  101. #endif // WEB_SUPPORT
  102. /*
  103. From an hexa char array ("A220EE...") to a byte array (half the size)
  104. */
  105. static int _rfbToArray(const char * in, byte * out, int length = RF_MESSAGE_SIZE * 2) {
  106. int n = strlen(in);
  107. if (n > RF_MAX_MESSAGE_SIZE*2 || (length > 0 && n != length)) return 0;
  108. char tmp[3] = {0,0,0};
  109. n /= 2;
  110. for (unsigned char p = 0; p<n; p++) {
  111. memcpy(tmp, &in[p*2], 2);
  112. out[p] = strtol(tmp, NULL, 16);
  113. }
  114. return n;
  115. }
  116. void _rfbSendRaw(const byte *message, const unsigned char n = RF_MESSAGE_SIZE) {
  117. for (unsigned char j=0; j<n; j++) {
  118. Serial.write(message[j]);
  119. }
  120. }
  121. void _rfbSend() {
  122. if (!_rfb_transmit) return;
  123. // Check if there is something in the queue
  124. if (_rfb_message_queue.empty()) return;
  125. static unsigned long last = 0;
  126. if (millis() - last < RF_SEND_DELAY) return;
  127. last = millis();
  128. // Pop the first message and send it
  129. rfb_message_t message = _rfb_message_queue.front();
  130. _rfb_message_queue.pop();
  131. _rfbSend(message.code);
  132. // Push it to the stack again if we need to send it more than once
  133. if (message.times > 1) {
  134. message.times = message.times - 1;
  135. _rfb_message_queue.push(message);
  136. }
  137. yield();
  138. }
  139. void _rfbSend(byte * code, unsigned char times) {
  140. if (!_rfb_transmit) return;
  141. // rc-switch will repeat on its own
  142. #if RFB_DIRECT
  143. times = 1;
  144. #endif
  145. char buffer[RF_MESSAGE_SIZE];
  146. _rfbToChar(code, buffer);
  147. DEBUG_MSG_P(PSTR("[RF] Enqueuing MESSAGE '%s' %d time(s)\n"), buffer, times);
  148. rfb_message_t message;
  149. memcpy(message.code, code, RF_MESSAGE_SIZE);
  150. message.times = times;
  151. _rfb_message_queue.push(message);
  152. }
  153. void _rfbSendRawOnce(byte *code, unsigned char length) {
  154. char buffer[length*2];
  155. _rfbToChar(code, buffer, length);
  156. DEBUG_MSG_P(PSTR("[RF] Sending RAW MESSAGE '%s'\n"), buffer);
  157. _rfbSendRaw(code, length);
  158. }
  159. bool _rfbMatch(char* code, unsigned char& relayID, unsigned char& value, char* buffer = NULL) {
  160. if (strlen(code) != 18) return false;
  161. bool found = false;
  162. String compareto = String(&code[12]);
  163. compareto.toUpperCase();
  164. DEBUG_MSG_P(PSTR("[RF] Trying to match code %s\n"), compareto.c_str());
  165. for (unsigned char i=0; i<relayCount(); i++) {
  166. String code_on = rfbRetrieve(i, true);
  167. if (code_on.length() && code_on.endsWith(compareto)) {
  168. DEBUG_MSG_P(PSTR("[RF] Match ON code for relay %d\n"), i);
  169. value = 1;
  170. found = true;
  171. if (buffer) strcpy(buffer, code_on.c_str());
  172. }
  173. String code_off = rfbRetrieve(i, false);
  174. if (code_off.length() && code_off.endsWith(compareto)) {
  175. DEBUG_MSG_P(PSTR("[RF] Match OFF code for relay %d\n"), i);
  176. if (found) value = 2;
  177. found = true;
  178. if (buffer) strcpy(buffer, code_off.c_str());
  179. }
  180. if (found) {
  181. relayID = i;
  182. return true;
  183. }
  184. }
  185. return false;
  186. }
  187. void _rfbDecode() {
  188. static unsigned long last = 0;
  189. if (millis() - last < RF_RECEIVE_DELAY) return;
  190. last = millis();
  191. byte action = _uartbuf[0];
  192. char buffer[RF_MESSAGE_SIZE * 2 + 1] = {0};
  193. DEBUG_MSG_P(PSTR("[RF] Action 0x%02X\n"), action);
  194. if (action == RF_CODE_LEARN_KO) {
  195. _rfbAck();
  196. DEBUG_MSG_P(PSTR("[RF] Learn timeout\n"));
  197. }
  198. if (action == RF_CODE_LEARN_OK || action == RF_CODE_RFIN) {
  199. _rfbAck();
  200. _rfbToChar(&_uartbuf[1], buffer);
  201. DEBUG_MSG_P(PSTR("[RF] Received message '%s'\n"), buffer);
  202. }
  203. if (action == RF_CODE_LEARN_OK) {
  204. DEBUG_MSG_P(PSTR("[RF] Learn success\n"));
  205. rfbStore(_learnId, _learnStatus, buffer);
  206. // Websocket update
  207. #if WEB_SUPPORT
  208. wsPost([](JsonObject& root) {
  209. _rfbWebSocketSendCodeArray(root, _learnId, 1);
  210. });
  211. #endif
  212. }
  213. if (action == RF_CODE_RFIN) {
  214. /* Look for the code, possibly replacing the code with the exact learned one on match
  215. * we want to do this on learn too to be sure that the learned code is the same if it
  216. * is equivalent
  217. */
  218. unsigned char id;
  219. unsigned char status;
  220. bool matched = _rfbMatch(buffer, id, status, buffer);
  221. if (matched) {
  222. DEBUG_MSG_P(PSTR("[RF] Matched message '%s'\n"), buffer);
  223. _rfbin = true;
  224. if (status == 2) {
  225. relayToggle(id);
  226. } else {
  227. relayStatus(id, status == 1);
  228. }
  229. }
  230. #if MQTT_SUPPORT
  231. mqttSend(MQTT_TOPIC_RFIN, buffer, false, false);
  232. #endif
  233. }
  234. }
  235. bool _rfbCompare(const char * code1, const char * code2) {
  236. return strcmp(&code1[12], &code2[12]) == 0;
  237. }
  238. bool _rfbSameOnOff(unsigned char id) {
  239. return _rfbCompare(rfbRetrieve(id, true).c_str(), rfbRetrieve(id, false).c_str());
  240. }
  241. void _rfbParseRaw(char * raw) {
  242. byte message[RF_MAX_MESSAGE_SIZE];
  243. int len = _rfbToArray(raw, message, 0);
  244. if (len > 0) {
  245. _rfbSendRawOnce(message, len);
  246. }
  247. }
  248. void _rfbParseCode(char * code) {
  249. // The payload may be a code in HEX format ([0-9A-Z]{18}) or
  250. // the code comma the number of times to transmit it.
  251. char * tok = strtok(code, ",");
  252. // Check if a switch is linked to that message
  253. unsigned char id;
  254. unsigned char status = 0;
  255. if (_rfbMatch(tok, id, status)) {
  256. if (status == 2) {
  257. relayToggle(id);
  258. } else {
  259. relayStatus(id, status == 1);
  260. }
  261. return;
  262. }
  263. byte message[RF_MESSAGE_SIZE];
  264. int len = _rfbToArray(tok, message, 0);
  265. if (len) {
  266. tok = strtok(NULL, ",");
  267. byte times = (tok != NULL) ? atoi(tok) : 1;
  268. _rfbSend(message, times);
  269. }
  270. }
  271. //
  272. // RF handler implementations
  273. //
  274. #if !RFB_DIRECT // Default for ITEAD SONOFF RFBRIDGE
  275. void _rfbAck() {
  276. DEBUG_MSG_P(PSTR("[RF] Sending ACK\n"));
  277. Serial.println();
  278. Serial.write(RF_CODE_START);
  279. Serial.write(RF_CODE_ACK);
  280. Serial.write(RF_CODE_STOP);
  281. Serial.flush();
  282. Serial.println();
  283. }
  284. void _rfbLearnImpl() {
  285. DEBUG_MSG_P(PSTR("[RF] Sending LEARN\n"));
  286. Serial.println();
  287. Serial.write(RF_CODE_START);
  288. Serial.write(RF_CODE_LEARN);
  289. Serial.write(RF_CODE_STOP);
  290. Serial.flush();
  291. Serial.println();
  292. }
  293. void _rfbSend(byte * message) {
  294. Serial.println();
  295. Serial.write(RF_CODE_START);
  296. Serial.write(RF_CODE_RFOUT);
  297. _rfbSendRaw(message);
  298. Serial.write(RF_CODE_STOP);
  299. Serial.flush();
  300. Serial.println();
  301. }
  302. void _rfbReceive() {
  303. static bool receiving = false;
  304. while (Serial.available()) {
  305. yield();
  306. byte c = Serial.read();
  307. //DEBUG_MSG_P(PSTR("[RF] Received 0x%02X\n"), c);
  308. if (receiving) {
  309. if (c == RF_CODE_STOP && (_uartpos == 1 || _uartpos == RF_MESSAGE_SIZE + 1)) {
  310. _rfbDecode();
  311. receiving = false;
  312. } else if (_uartpos <= RF_MESSAGE_SIZE) {
  313. _uartbuf[_uartpos++] = c;
  314. } else {
  315. // wrong message, should have received a RF_CODE_STOP
  316. receiving = false;
  317. }
  318. } else if (c == RF_CODE_START) {
  319. _uartpos = 0;
  320. receiving = true;
  321. }
  322. }
  323. }
  324. #else // RFB_DIRECT
  325. void _rfbAck() {}
  326. void _rfbLearnImpl() {
  327. DEBUG_MSG_P(PSTR("[RF] Entering LEARN mode\n"));
  328. _learning = true;
  329. }
  330. void _rfbSend(byte * message) {
  331. if (!_rfb_transmit) return;
  332. unsigned int protocol = message[1];
  333. unsigned int timing =
  334. (message[2] << 8) |
  335. (message[3] << 0) ;
  336. unsigned int bitlength = message[4];
  337. unsigned long rf_code =
  338. (message[5] << 24) |
  339. (message[6] << 16) |
  340. (message[7] << 8) |
  341. (message[8] << 0) ;
  342. _rfModem->setProtocol(protocol);
  343. if (timing > 0) {
  344. _rfModem->setPulseLength(timing);
  345. }
  346. _rfModem->send(rf_code, bitlength);
  347. _rfModem->resetAvailable();
  348. }
  349. void _rfbReceive() {
  350. if (!_rfb_receive) return;
  351. static long learn_start = 0;
  352. if (!_learning && learn_start) {
  353. learn_start = 0;
  354. }
  355. if (_learning) {
  356. if (!learn_start) {
  357. DEBUG_MSG_P(PSTR("[RF] Arming learn timeout\n"));
  358. learn_start = millis();
  359. }
  360. if (learn_start > 0 && millis() - learn_start > RF_LEARN_TIMEOUT) {
  361. DEBUG_MSG_P(PSTR("[RF] Learn timeout triggered\n"));
  362. memset(_uartbuf, 0, sizeof(_uartbuf));
  363. _uartbuf[0] = RF_CODE_LEARN_KO;
  364. _rfbDecode();
  365. _learning = false;
  366. }
  367. }
  368. if (_rfModem->available()) {
  369. static unsigned long last = 0;
  370. if (millis() - last > RF_DEBOUNCE) {
  371. last = millis();
  372. unsigned long rf_code = _rfModem->getReceivedValue();
  373. if ( rf_code > 0) {
  374. DEBUG_MSG_P(PSTR("[RF] Received code: %08X\n"), rf_code);
  375. unsigned int timing = _rfModem->getReceivedDelay();
  376. memset(_uartbuf, 0, sizeof(_uartbuf));
  377. unsigned char *msgbuf = _uartbuf + 1;
  378. _uartbuf[0] = _learning ? RF_CODE_LEARN_OK: RF_CODE_RFIN;
  379. msgbuf[0] = 0xC0;
  380. msgbuf[1] = _rfModem->getReceivedProtocol();
  381. msgbuf[2] = timing >> 8;
  382. msgbuf[3] = timing >> 0;
  383. msgbuf[4] = _rfModem->getReceivedBitlength();
  384. msgbuf[5] = rf_code >> 24;
  385. msgbuf[6] = rf_code >> 16;
  386. msgbuf[7] = rf_code >> 8;
  387. msgbuf[8] = rf_code >> 0;
  388. _rfbDecode();
  389. _learning = false;
  390. }
  391. }
  392. _rfModem->resetAvailable();
  393. }
  394. yield();
  395. }
  396. #endif // RFB_DIRECT
  397. #if MQTT_SUPPORT
  398. void _rfbMqttCallback(unsigned int type, const char * topic, const char * payload) {
  399. if (type == MQTT_CONNECT_EVENT) {
  400. char buffer[strlen(MQTT_TOPIC_RFLEARN) + 3];
  401. snprintf_P(buffer, sizeof(buffer), PSTR("%s/+"), MQTT_TOPIC_RFLEARN);
  402. mqttSubscribe(buffer);
  403. if (_rfb_transmit) {
  404. mqttSubscribe(MQTT_TOPIC_RFOUT);
  405. }
  406. #if !RFB_DIRECT
  407. mqttSubscribe(MQTT_TOPIC_RFRAW);
  408. #endif
  409. }
  410. if (type == MQTT_MESSAGE_EVENT) {
  411. // Match topic
  412. String t = mqttMagnitude((char *) topic);
  413. // Check if should go into learn mode
  414. if (t.startsWith(MQTT_TOPIC_RFLEARN)) {
  415. _learnId = t.substring(strlen(MQTT_TOPIC_RFLEARN)+1).toInt();
  416. if (_learnId >= relayCount()) {
  417. DEBUG_MSG_P(PSTR("[RF] Wrong learnID (%d)\n"), _learnId);
  418. return;
  419. }
  420. _learnStatus = (char)payload[0] != '0';
  421. _rfbLearnImpl();
  422. return;
  423. }
  424. if (t.equals(MQTT_TOPIC_RFOUT)) {
  425. _rfbParseCode((char *) payload);
  426. }
  427. #if !RFB_DIRECT
  428. if (t.equals(MQTT_TOPIC_RFRAW)) {
  429. _rfbParseRaw((char *) payload);
  430. }
  431. #endif
  432. }
  433. }
  434. #endif // MQTT_SUPPORT
  435. #if API_SUPPORT
  436. void _rfbAPISetup() {
  437. apiRegister(MQTT_TOPIC_RFOUT,
  438. [](char * buffer, size_t len) {
  439. snprintf_P(buffer, len, PSTR("OK"));
  440. },
  441. [](const char * payload) {
  442. _rfbParseCode((char *) payload);
  443. }
  444. );
  445. apiRegister(MQTT_TOPIC_RFLEARN,
  446. [](char * buffer, size_t len) {
  447. snprintf_P(buffer, len, PSTR("OK"));
  448. },
  449. [](const char * payload) {
  450. // The payload must be the relayID plus the mode (0 or 1)
  451. char * tok = strtok((char *) payload, ",");
  452. if (NULL == tok) return;
  453. if (!isNumber(tok)) return;
  454. _learnId = atoi(tok);
  455. if (_learnId >= relayCount()) {
  456. DEBUG_MSG_P(PSTR("[RF] Wrong learnID (%d)\n"), _learnId);
  457. return;
  458. }
  459. tok = strtok(NULL, ",");
  460. if (NULL == tok) return;
  461. _learnStatus = (char) tok[0] != '0';
  462. _rfbLearnImpl();
  463. }
  464. );
  465. #if !RFB_DIRECT
  466. apiRegister(MQTT_TOPIC_RFRAW,
  467. [](char * buffer, size_t len) {
  468. snprintf_P(buffer, len, PSTR("OK"));
  469. },
  470. [](const char * payload) {
  471. _rfbParseRaw((char *)payload);
  472. }
  473. );
  474. #endif
  475. }
  476. #endif // API_SUPPORT
  477. #if TERMINAL_SUPPORT
  478. void _rfbInitCommands() {
  479. terminalRegisterCommand(F("LEARN"), [](Embedis* e) {
  480. if (e->argc < 3) {
  481. terminalError(F("Wrong arguments"));
  482. return;
  483. }
  484. int id = String(e->argv[1]).toInt();
  485. if (id >= relayCount()) {
  486. DEBUG_MSG_P(PSTR("-ERROR: Wrong relayID (%d)\n"), id);
  487. return;
  488. }
  489. int status = String(e->argv[2]).toInt();
  490. rfbLearn(id, status == 1);
  491. terminalOK();
  492. });
  493. terminalRegisterCommand(F("FORGET"), [](Embedis* e) {
  494. if (e->argc < 3) {
  495. terminalError(F("Wrong arguments"));
  496. return;
  497. }
  498. int id = String(e->argv[1]).toInt();
  499. if (id >= relayCount()) {
  500. DEBUG_MSG_P(PSTR("-ERROR: Wrong relayID (%d)\n"), id);
  501. return;
  502. }
  503. int status = String(e->argv[2]).toInt();
  504. rfbForget(id, status == 1);
  505. terminalOK();
  506. });
  507. }
  508. #endif // TERMINAL_SUPPORT
  509. // -----------------------------------------------------------------------------
  510. // PUBLIC
  511. // -----------------------------------------------------------------------------
  512. void rfbStore(unsigned char id, bool status, const char * code) {
  513. DEBUG_MSG_P(PSTR("[RF] Storing %d-%s => '%s'\n"), id, status ? "ON" : "OFF", code);
  514. char key[RF_MAX_KEY_LENGTH] = {0};
  515. snprintf_P(key, sizeof(key), PSTR("rfb%s%d"), status ? "ON" : "OFF", id);
  516. setSetting(key, code);
  517. }
  518. String rfbRetrieve(unsigned char id, bool status) {
  519. char key[RF_MAX_KEY_LENGTH] = {0};
  520. snprintf_P(key, sizeof(key), PSTR("rfb%s%d"), status ? "ON" : "OFF", id);
  521. return getSetting(key);
  522. }
  523. void rfbStatus(unsigned char id, bool status) {
  524. String value = rfbRetrieve(id, status);
  525. if (value.length() > 0) {
  526. bool same = _rfbSameOnOff(id);
  527. byte message[RF_MAX_MESSAGE_SIZE];
  528. int len = _rfbToArray(value.c_str(), message, 0);
  529. if (len == RF_MESSAGE_SIZE && // probably a standard msg
  530. (message[0] != RF_CODE_START || // raw would start with 0xAA
  531. message[1] != RF_CODE_RFOUT_BUCKET || // followed by 0xB0,
  532. message[2] + 4 != len || // needs a valid length,
  533. message[len-1] != RF_CODE_STOP)) { // and finish with 0x55
  534. if (!_rfbin) {
  535. unsigned char times = same ? 1 : _rfb_repeat;
  536. _rfbSend(message, times);
  537. }
  538. } else {
  539. _rfbSendRawOnce(message, len); // send a raw message
  540. }
  541. }
  542. _rfbin = false;
  543. }
  544. void rfbLearn(unsigned char id, bool status) {
  545. _learnId = id;
  546. _learnStatus = status;
  547. _rfbLearnImpl();
  548. }
  549. void rfbForget(unsigned char id, bool status) {
  550. char key[RF_MAX_KEY_LENGTH] = {0};
  551. snprintf_P(key, sizeof(key), PSTR("rfb%s%d"), status ? "ON" : "OFF", id);
  552. delSetting(key);
  553. // Websocket update
  554. #if WEB_SUPPORT
  555. wsPost([id](JsonObject& root) {
  556. _rfbWebSocketSendCodeArray(root, id, 1);
  557. });
  558. #endif
  559. }
  560. // -----------------------------------------------------------------------------
  561. // SETUP & LOOP
  562. // -----------------------------------------------------------------------------
  563. void rfbSetup() {
  564. #if MQTT_SUPPORT
  565. mqttRegister(_rfbMqttCallback);
  566. #endif
  567. #if API_SUPPORT
  568. _rfbAPISetup();
  569. #endif
  570. #if WEB_SUPPORT
  571. wsRegister()
  572. .onVisible(_rfbWebSocketOnVisible)
  573. .onConnected(_rfbWebSocketOnConnected)
  574. .onData(_rfbWebSocketOnData)
  575. .onAction(_rfbWebSocketOnAction)
  576. .onKeyCheck(_rfbWebSocketOnKeyCheck);
  577. #endif
  578. #if TERMINAL_SUPPORT
  579. _rfbInitCommands();
  580. #endif
  581. _rfb_repeat = getSetting("rfbRepeat", RF_SEND_TIMES).toInt();
  582. #if RFB_DIRECT
  583. unsigned char rx = getSetting("rfbRX", RFB_RX_PIN).toInt();
  584. unsigned char tx = getSetting("rfbTX", RFB_TX_PIN).toInt();
  585. _rfb_receive = gpioValid(rx);
  586. _rfb_transmit = gpioValid(tx);
  587. if (!_rfb_transmit && !_rfb_receive) {
  588. DEBUG_MSG_P(PSTR("[RF] Neither RX or TX are set\n"));
  589. return;
  590. }
  591. _rfModem = new RCSwitch();
  592. if (_rfb_receive) {
  593. _rfModem->enableReceive(rx);
  594. DEBUG_MSG_P(PSTR("[RF] RF receiver on GPIO %u\n"), rx);
  595. }
  596. if (_rfb_transmit) {
  597. _rfModem->enableTransmit(tx);
  598. _rfModem->setRepeatTransmit(_rfb_repeat);
  599. DEBUG_MSG_P(PSTR("[RF] RF transmitter on GPIO %u\n"), tx);
  600. }
  601. #else
  602. _rfb_receive = true;
  603. _rfb_transmit = true;
  604. #endif
  605. // Register loop only when properly configured
  606. espurnaRegisterLoop(rfbLoop);
  607. }
  608. void rfbLoop() {
  609. _rfbReceive();
  610. _rfbSend();
  611. }
  612. #endif