/* ITEAD RF BRIDGE MODULE Copyright (C) 2017 by Xose PĂ©rez */ #ifdef SONOFF_RFBRIDGE #define RF_MESSAGE_SIZE 9 #define RF_SEND_TIMES 3 #define RF_SEND_DELAY 50 #define RF_CODE_START 0xAA #define RF_CODE_ACK 0xA0 #define RF_CODE_LEARN 0xA1 #define RF_CODE_LEARN_KO 0xA2 #define RF_CODE_LEARN_OK 0xA3 #define RF_CODE_RFIN 0xA4 #define RF_CODE_RFOUT 0xA5 #define RF_CODE_STOP 0x55 unsigned char _uartbuf[RF_MESSAGE_SIZE+3] = {0}; unsigned char _uartpos = 0; unsigned char _learnId = 0; bool _learnState = true; // ----------------------------------------------------------------------------- // PRIVATES // ----------------------------------------------------------------------------- void _rfbAck() { DEBUG_MSG_P(PSTR("[RFBRIDGE] Sending ACK\n")); Serial.write(RF_CODE_START); Serial.write(RF_CODE_ACK); Serial.write(RF_CODE_STOP); Serial.flush(); } void _rfbLearn() { DEBUG_MSG_P(PSTR("[RFBRIDGE] Sending LEARN\n")); Serial.write(RF_CODE_START); Serial.write(RF_CODE_LEARN); Serial.write(RF_CODE_STOP); Serial.flush(); } void _rfbSend(byte * message) { Serial.write(RF_CODE_START); Serial.write(RF_CODE_RFOUT); for (unsigned char j=0; j0) { unsigned long start = millis(); while (millis() - start < RF_SEND_DELAY) delay(1); } _rfbSend(message); } } void _rfbDecode() { byte action = _uartbuf[0]; char buffer[RF_MESSAGE_SIZE * 2 + 1] = {0}; DEBUG_MSG_P(PSTR("[RFBRIDGE] Action 0x%02X\n"), action); if (action == RF_CODE_LEARN_KO) { _rfbAck(); DEBUG_MSG_P(PSTR("[RFBRIDGE] Learn timeout\n")); } if (action == RF_CODE_LEARN_OK || action == RF_CODE_RFIN) { _rfbToChar(&_uartbuf[1], buffer); mqttSend(MQTT_TOPIC_RFIN, buffer); _rfbAck(); } if (action == RF_CODE_LEARN_OK) { // TODO: notify websocket _rfbStore(_learnId, _learnState, buffer); DEBUG_MSG_P(PSTR("[RFBRIDGE] Learn success. Storing %d-%s => '%s'\n"), _learnId, _learnState ? "ON" : "OFF", buffer); } if (action == RF_CODE_RFIN) { DEBUG_MSG_P(PSTR("[RFBRIDGE] Forward message '%s'\n"), buffer); } } void _rfbReceive() { static bool receiving = false; while (Serial.available()) { yield(); byte c = Serial.read(); //DEBUG_MSG_P(PSTR("[RFBRIDGE] Received 0x%02X\n"), c); if (receiving) { if (c == RF_CODE_STOP) { _rfbDecode(); receiving = false; } else { _uartbuf[_uartpos++] = c; } } else if (c == RF_CODE_START) { _uartpos = 0; receiving = true; } } } /* From an hexa char array ("A220EE...") to a byte array (half the size) */ bool _rfbToArray(const char * in, byte * out) { if (strlen(in) != RF_MESSAGE_SIZE * 2) return false; char tmp[3] = {0}; for (unsigned char p = 0; p= relayCount()) { DEBUG_MSG_P(PSTR("[RFBRIDGE] Wrong learnID (%d)\n"), _learnId); return; } _learnState = (char)payload[0] != '0'; _rfbLearn(); } if (t.equals(MQTT_TOPIC_RFOUT)) { byte message[RF_MESSAGE_SIZE]; if (_rfbToArray(payload, message)) { _rfbSend(message, RF_SEND_TIMES); } } } } void _rfbStore(unsigned char id, bool status, char * code) { char key[8] = {0}; sprintf(key, "rfb%d%s", id, status ? "on" : "off"); setSetting(key, code); } String _rfbRetrieve(unsigned char id, bool status) { char key[8] = {0}; sprintf(key, "rfb%d%s", id, status ? "on" : "off"); return getSetting(key); } // ----------------------------------------------------------------------------- // PUBLIC // ----------------------------------------------------------------------------- void rfbState(unsigned char id, bool status) { String value = _rfbRetrieve(id, status); DEBUG_MSG_P(PSTR("[RFBRIDGE] Retrieving value for %d-%s => %s\n"), id, status ? "ON" : "OFF", value.c_str()); if (value.length() > 0) { byte message[RF_MESSAGE_SIZE]; _rfbToArray(value.c_str(), message); _rfbSend(message, RF_SEND_TIMES); } } void rfbLearn(unsigned char id, bool status) { _learnId = id; _learnState = status; _rfbLearn(); } void rfbForget(unsigned char id, bool status) { char key[8] = {0}; sprintf(key, "rfb%d%s", id, status ? "on" : "off"); delSetting(key); } // ----------------------------------------------------------------------------- // SETUP & LOOP // ----------------------------------------------------------------------------- void rfbSetup() { mqttRegister(_rfbMqttCallback); } void rfbLoop() { _rfbReceive(); } #endif