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.

791 lines
21 KiB

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