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.

801 lines
20 KiB

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