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

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