Browse Source

Merge RF and RFBridge code (#1435)

* Merge RF and RFBridge code

* Keep rfbridge.ino filename

* Corrected #if checks

* Make RF_DEBOUNCE and RF_LEARN_TIMEOUT configurable

* Fix compile warnings with platform_latest
refactor-terminal
Niek van der Maas 6 years ago
committed by Max Prokhorov
parent
commit
d299773913
5 changed files with 77 additions and 305 deletions
  1. +5
    -0
      code/espurna/config/general.h
  2. +1
    -1
      code/espurna/config/progmem.h
  3. +1
    -4
      code/espurna/espurna.ino
  4. +0
    -253
      code/espurna/rf.ino
  5. +70
    -47
      code/espurna/rfbridge.ino

+ 5
- 0
code/espurna/config/general.h View File

@ -1409,8 +1409,13 @@
#define RF_PIN 14
#endif
#ifndef RF_DEBOUNCE
#define RF_DEBOUNCE 500
#endif
#ifndef RF_LEARN_TIMEOUT
#define RF_LEARN_TIMEOUT 60000
#endif
//--------------------------------------------------------------------------------
// Custom RFM69 to MQTT bridge


+ 1
- 1
code/espurna/config/progmem.h View File

@ -97,7 +97,7 @@ PROGMEM const char espurna_modules[] =
#if RFM69_SUPPORT
"RFM69 "
#endif
#if RF_SUPPORT
#if RF_SUPPORT || defined(ITEAD_SONOFF_RFBRIDGE)
"RF "
#endif
#if SCHEDULER_SUPPORT


+ 1
- 4
code/espurna/espurna.ino View File

@ -148,7 +148,7 @@ void setup() {
#if I2C_SUPPORT
i2cSetup();
#endif
#ifdef ITEAD_SONOFF_RFBRIDGE
#if defined(ITEAD_SONOFF_RFBRIDGE) || RF_SUPPORT
rfbSetup();
#endif
#if ALEXA_SUPPORT
@ -166,9 +166,6 @@ void setup() {
#if RFM69_SUPPORT
rfm69Setup();
#endif
#if RF_SUPPORT
rfSetup();
#endif
#if IR_SUPPORT
irSetup();
#endif


+ 0
- 253
code/espurna/rf.ino View File

@ -1,253 +0,0 @@
/*
RF MODULE
Copyright (C) 2016-2018 by Xose Pérez <xose dot perez at gmail dot com>
*/
#if RF_SUPPORT
#include <RCSwitch.h>
RCSwitch * _rfModem;
unsigned long _rf_learn_start = 0;
unsigned char _rf_learn_id = 0;
bool _rf_learn_status = true;
bool _rf_learn_active = false;
#if WEB_SUPPORT
#include <Ticker.h>
Ticker _rfb_sendcodes;
#endif
// -----------------------------------------------------------------------------
// RF
// -----------------------------------------------------------------------------
unsigned long _rfRetrieve(unsigned char id, bool status) {
String code = getSetting(status ? "rfbON" : "rfbOFF", id, "0");
return strtoul(code.c_str(), 0, 16);
}
void _rfStore(unsigned char id, bool status, unsigned long code) {
DEBUG_MSG_P(PSTR("[RF] Storing %d-%s => %X\n"), id, status ? "ON" : "OFF", code);
char buffer[20];
snprintf_P(buffer, sizeof(buffer), PSTR("%X"), code);
setSetting(status ? "rfbON" : "rfbOFF", id, buffer);
}
void _rfLearn(unsigned char id, bool status) {
_rf_learn_start = millis();
_rf_learn_id = id;
_rf_learn_status = status;
_rf_learn_active = true;
}
void _rfForget(unsigned char id, bool status) {
delSetting(status ? "rfbON" : "rfbOFF", id);
// Websocket update
#if WEB_SUPPORT
char wsb[100];
snprintf_P(wsb, sizeof(wsb), PSTR("{\"rfb\":[{\"id\": %d, \"status\": %d, \"data\": \"\"}]}"), id, status ? 1 : 0);
wsSend(wsb);
#endif
}
bool _rfMatch(unsigned long code, unsigned char& relayID, unsigned char& value) {
bool found = false;
DEBUG_MSG_P(PSTR("[RF] Trying to match code %X\n"), code);
for (unsigned char i=0; i<relayCount(); i++) {
unsigned long code_on = _rfRetrieve(i, true);
unsigned long code_off = _rfRetrieve(i, false);
if (code == code_on) {
DEBUG_MSG_P(PSTR("[RF] Match ON code for relay %d\n"), i);
value = 1;
found = true;
}
if (code == code_off) {
DEBUG_MSG_P(PSTR("[RF] Match OFF code for relay %d\n"), i);
if (found) value = 2;
found = true;
}
if (found) {
relayID = i;
return true;
}
}
return false;
}
#if TERMINAL_SUPPORT
void _rfInitCommands() {
settingsRegisterCommand(F("LEARN"), [](Embedis* e) {
if (e->argc < 3) {
DEBUG_MSG_P(PSTR("-ERROR: Wrong arguments\n"));
return;
}
int id = String(e->argv[1]).toInt();
if (id >= relayCount()) {
DEBUG_MSG_P(PSTR("-ERROR: Wrong relayID (%d)\n"), id);
return;
}
int status = String(e->argv[2]).toInt();
_rfLearn(id, status == 1);
DEBUG_MSG_P(PSTR("+OK\n"));
});
settingsRegisterCommand(F("FORGET"), [](Embedis* e) {
if (e->argc < 3) {
DEBUG_MSG_P(PSTR("-ERROR: Wrong arguments\n"));
return;
}
int id = String(e->argv[1]).toInt();
if (id >= relayCount()) {
DEBUG_MSG_P(PSTR("-ERROR: Wrong relayID (%d)\n"), id);
return;
}
int status = String(e->argv[2]).toInt();
_rfForget(id, status == 1);
DEBUG_MSG_P(PSTR("+OK\n"));
});
}
#endif // TERMINAL_SUPPORT
// -----------------------------------------------------------------------------
// WEB
// -----------------------------------------------------------------------------
#if WEB_SUPPORT
void _rfWebSocketSendCode(unsigned char id, bool status, unsigned long code) {
char wsb[100];
snprintf_P(wsb, sizeof(wsb), PSTR("{\"rfb\":[{\"id\": %d, \"status\": %d, \"data\": \"%X\"}]}"), id, status ? 1 : 0, code);
wsSend(wsb);
}
void _rfWebSocketSendCodes() {
for (unsigned char id=0; id<relayCount(); id++) {
_rfWebSocketSendCode(id, true, _rfRetrieve(id, true));
_rfWebSocketSendCode(id, false, _rfRetrieve(id, false));
}
}
void _rfWebSocketOnSend(JsonObject& root) {
char buffer[20];
root["rfbVisible"] = 1;
root["rfbCount"] = relayCount();
_rfb_sendcodes.once_ms(1000, _rfWebSocketSendCodes);
}
void _rfWebSocketOnAction(uint32_t client_id, const char * action, JsonObject& data) {
if (strcmp(action, "rfblearn") == 0) _rfLearn(data["id"], data["status"]);
if (strcmp(action, "rfbforget") == 0) _rfForget(data["id"], data["status"]);
if (strcmp(action, "rfbsend") == 0) _rfStore(data["id"], data["status"], strtoul(data["data"], NULL, 16));
}
#endif
// -----------------------------------------------------------------------------
void rfLoop() {
if (_rfModem->available()) {
static unsigned long last = 0;
if (millis() - last > RF_DEBOUNCE) {
last = millis();
if (_rfModem->getReceivedValue() > 0) {
unsigned long rf_code = _rfModem->getReceivedValue();
DEBUG_MSG_P(PSTR("[RF] Received code: %X\n"), rf_code);
if (_rf_learn_active) {
_rf_learn_active = false;
_rfStore(_rf_learn_id, _rf_learn_status, rf_code);
// Websocket update
#if WEB_SUPPORT
_rfWebSocketSendCode(_rf_learn_id, _rf_learn_status, rf_code);
#endif
} else {
unsigned char id;
unsigned char value;
if (_rfMatch(rf_code, id, value)) {
if (2 == value) {
relayToggle(id);
} else {
relayStatus(id, 1 == value);
}
}
}
}
}
_rfModem->resetAvailable();
}
if (_rf_learn_active && (millis() - _rf_learn_start > RF_LEARN_TIMEOUT)) {
_rf_learn_active = false;
}
}
void rfSetup() {
_rfModem = new RCSwitch();
_rfModem->enableReceive(RF_PIN);
DEBUG_MSG_P(PSTR("[RF] RF receiver on GPIO %u\n"), RF_PIN);
#if WEB_SUPPORT
wsOnSendRegister(_rfWebSocketOnSend);
wsOnActionRegister(_rfWebSocketOnAction);
#endif
#if TERMINAL_SUPPORT
_rfInitCommands();
#endif
// Register loop
espurnaRegisterLoop(rfLoop);
}
#endif

+ 70
- 47
code/espurna/rfbridge.ino View File

@ -1,17 +1,17 @@
/*
ITEAD RF BRIDGE MODULE
RF MODULE
Copyright (C) 2017-2018 by Xose Pérez <xose dot perez at gmail dot com>
Copyright (C) 2016-2018 by Xose Pérez <xose dot perez at gmail dot com>
*/
#ifdef ITEAD_SONOFF_RFBRIDGE
#if defined(ITEAD_SONOFF_RFBRIDGE) || RF_SUPPORT
#include <queue>
#include <Ticker.h>
#if RFB_DIRECT
#if RFB_DIRECT || RF_SUPPORT
#include <RCSwitch.h>
#endif
@ -53,6 +53,7 @@ unsigned char _learnId = 0;
bool _learnStatus = true;
bool _rfbin = false;
#if not RF_SUPPORT
typedef struct {
byte code[RF_MESSAGE_SIZE];
byte times;
@ -60,8 +61,9 @@ typedef struct {
static std::queue<rfb_message_t> _rfb_message_queue;
Ticker _rfb_ticker;
bool _rfb_ticker_active = false;
#endif
#if RFB_DIRECT
#if RFB_DIRECT || RF_SUPPORT
RCSwitch * _rfModem;
bool _learning = false;
#endif
@ -74,21 +76,6 @@ bool _rfb_ticker_active = false;
// PRIVATES
// -----------------------------------------------------------------------------
/*
From an hexa char array ("A220EE...") to a byte array (half the size)
*/
static int _rfbToArray(const char * in, byte * out, int length = RF_MESSAGE_SIZE * 2) {
int n = strlen(in);
if (n > RF_MAX_MESSAGE_SIZE*2 || (length > 0 && n != length)) return 0;
char tmp[3] = {0,0,0};
n /= 2;
for (unsigned char p = 0; p<n; p++) {
memcpy(tmp, &in[p*2], 2);
out[p] = strtol(tmp, NULL, 16);
}
return n;
}
/*
From a byte array to an hexa char array ("A220EE...", double the size)
*/
@ -132,8 +119,8 @@ void _rfbWebSocketOnAction(uint32_t client_id, const char * action, JsonObject&
#endif // WEB_SUPPORT
void _rfbAck() {
#if not RFB_DIRECT
DEBUG_MSG_P(PSTR("[RFBRIDGE] Sending ACK\n"));
#if (not RFB_DIRECT) && (not RF_SUPPORT)
DEBUG_MSG_P(PSTR("[RF] Sending ACK\n"));
Serial.println();
Serial.write(RF_CODE_START);
Serial.write(RF_CODE_ACK);
@ -144,11 +131,11 @@ void _rfbAck() {
}
void _rfbLearn() {
#if RFB_DIRECT
DEBUG_MSG_P(PSTR("[RFBRIDGE] Entering LEARN mode\n"));
#if RFB_DIRECT || RF_SUPPORT
DEBUG_MSG_P(PSTR("[RF] Entering LEARN mode\n"));
_learning = true;
#else
DEBUG_MSG_P(PSTR("[RFBRIDGE] Sending LEARN\n"));
DEBUG_MSG_P(PSTR("[RF] Sending LEARN\n"));
Serial.println();
Serial.write(RF_CODE_START);
Serial.write(RF_CODE_LEARN);
@ -165,6 +152,24 @@ void _rfbLearn() {
}
#if not RF_SUPPORT
/*
From an hexa char array ("A220EE...") to a byte array (half the size)
*/
static int _rfbToArray(const char * in, byte * out, int length = RF_MESSAGE_SIZE * 2) {
int n = strlen(in);
if (n > RF_MAX_MESSAGE_SIZE*2 || (length > 0 && n != length)) return 0;
char tmp[3] = {0,0,0};
n /= 2;
for (unsigned char p = 0; p<n; p++) {
memcpy(tmp, &in[p*2], 2);
out[p] = strtol(tmp, NULL, 16);
}
return n;
}
void _rfbSendRaw(const byte *message, const unsigned char n = RF_MESSAGE_SIZE) {
for (unsigned char j=0; j<n; j++) {
Serial.write(message[j]);
@ -233,7 +238,7 @@ void _rfbSend(byte * code, unsigned char times) {
char buffer[RF_MESSAGE_SIZE];
_rfbToChar(code, buffer);
DEBUG_MSG_P(PSTR("[RFBRIDGE] Enqueuing MESSAGE '%s' %d time(s)\n"), buffer, times);
DEBUG_MSG_P(PSTR("[RF] Enqueuing MESSAGE '%s' %d time(s)\n"), buffer, times);
rfb_message_t message;
memcpy(message.code, code, RF_MESSAGE_SIZE);
@ -248,12 +253,14 @@ void _rfbSend(byte * code, unsigned char times) {
}
#endif // not RF_SUPPORT
#if RF_RAW_SUPPORT
void _rfbSendRawOnce(byte *code, unsigned char length) {
char buffer[length*2];
_rfbToChar(code, buffer, length);
DEBUG_MSG_P(PSTR("[RFBRIDGE] Sending RAW MESSAGE '%s'\n"), buffer);
DEBUG_MSG_P(PSTR("[RF] Sending RAW MESSAGE '%s'\n"), buffer);
_rfbSendRaw(code, length);
}
@ -266,13 +273,13 @@ bool _rfbMatch(char* code, unsigned char& relayID, unsigned char& value, char* b
bool found = false;
String compareto = String(&code[12]);
compareto.toUpperCase();
DEBUG_MSG_P(PSTR("[RFBRIDGE] Trying to match code %s\n"), compareto.c_str());
DEBUG_MSG_P(PSTR("[RF] Trying to match code %s\n"), compareto.c_str());
for (unsigned char i=0; i<relayCount(); i++) {
String code_on = rfbRetrieve(i, true);
if (code_on.length() && code_on.endsWith(compareto)) {
DEBUG_MSG_P(PSTR("[RFBRIDGE] Match ON code for relay %d\n"), i);
DEBUG_MSG_P(PSTR("[RF] Match ON code for relay %d\n"), i);
value = 1;
found = true;
if (buffer) strcpy(buffer, code_on.c_str());
@ -280,7 +287,7 @@ bool _rfbMatch(char* code, unsigned char& relayID, unsigned char& value, char* b
String code_off = rfbRetrieve(i, false);
if (code_off.length() && code_off.endsWith(compareto)) {
DEBUG_MSG_P(PSTR("[RFBRIDGE] Match OFF code for relay %d\n"), i);
DEBUG_MSG_P(PSTR("[RF] Match OFF code for relay %d\n"), i);
if (found) value = 2;
found = true;
if (buffer) strcpy(buffer, code_off.c_str());
@ -305,11 +312,11 @@ void _rfbDecode() {
byte action = _uartbuf[0];
char buffer[RF_MESSAGE_SIZE * 2 + 1] = {0};
DEBUG_MSG_P(PSTR("[RFBRIDGE] Action 0x%02X\n"), action);
DEBUG_MSG_P(PSTR("[RF] Action 0x%02X\n"), action);
if (action == RF_CODE_LEARN_KO) {
_rfbAck();
DEBUG_MSG_P(PSTR("[RFBRIDGE] Learn timeout\n"));
DEBUG_MSG_P(PSTR("[RF] Learn timeout\n"));
#if WEB_SUPPORT
wsSend_P(PSTR("{\"action\": \"rfbTimeout\"}"));
#endif
@ -320,13 +327,13 @@ void _rfbDecode() {
_rfbAck();
_rfbToChar(&_uartbuf[1], buffer);
DEBUG_MSG_P(PSTR("[RFBRIDGE] Received message '%s'\n"), buffer);
DEBUG_MSG_P(PSTR("[RF] Received message '%s'\n"), buffer);
}
if (action == RF_CODE_LEARN_OK) {
DEBUG_MSG_P(PSTR("[RFBRIDGE] Learn success\n"));
DEBUG_MSG_P(PSTR("[RF] Learn success\n"));
rfbStore(_learnId, _learnStatus, buffer);
// Websocket update
@ -347,7 +354,7 @@ void _rfbDecode() {
bool matched = _rfbMatch(buffer, id, status, buffer);
if (matched) {
DEBUG_MSG_P(PSTR("[RFBRIDGE] Matched message '%s'\n"), buffer);
DEBUG_MSG_P(PSTR("[RF] Matched message '%s'\n"), buffer);
_rfbin = true;
if (status == 2) {
relayToggle(id);
@ -365,18 +372,18 @@ void _rfbDecode() {
}
void _rfbReceive() {
#if RFB_DIRECT
#if RFB_DIRECT || RF_SUPPORT
static long learn_start = 0;
if (!_learning && learn_start) {
learn_start = 0;
}
if (_learning) {
if (!learn_start) {
DEBUG_MSG_P(PSTR("[RFBRIDGE] arming learn timeout\n"));
DEBUG_MSG_P(PSTR("[RF] Arming learn timeout\n"));
learn_start = millis();
}
if (learn_start > 0 && millis() - learn_start > RF_LEARN_TIMEOUT) {
DEBUG_MSG_P(PSTR("[RFBRIDGE] learn timeout triggered\n"));
DEBUG_MSG_P(PSTR("[RF] Learn timeout triggered\n"));
memset(_uartbuf, 0, sizeof(_uartbuf));
_uartbuf[0] = RF_CODE_LEARN_KO;
_rfbDecode();
@ -390,7 +397,7 @@ void _rfbReceive() {
last = millis();
unsigned long rf_code = _rfModem->getReceivedValue();
if ( rf_code > 0) {
DEBUG_MSG_P(PSTR("[RFBRIDGE] Received code: %08X\n"), rf_code);
DEBUG_MSG_P(PSTR("[RF] Received code: %08X\n"), rf_code);
unsigned int timing = _rfModem->getReceivedDelay();
memset(_uartbuf, 0, sizeof(_uartbuf));
unsigned char *msgbuf = _uartbuf + 1;
@ -417,7 +424,7 @@ void _rfbReceive() {
yield();
byte c = Serial.read();
//DEBUG_MSG_P(PSTR("[RFBRIDGE] Received 0x%02X\n"), c);
//DEBUG_MSG_P(PSTR("[RF] Received 0x%02X\n"), c);
if (receiving) {
if (c == RF_CODE_STOP && (_uartpos == 1 || _uartpos == RF_MESSAGE_SIZE + 1)) {
@ -453,7 +460,9 @@ void _rfbMqttCallback(unsigned int type, const char * topic, const char * payloa
char buffer[strlen(MQTT_TOPIC_RFLEARN) + 3];
snprintf_P(buffer, sizeof(buffer), PSTR("%s/+"), MQTT_TOPIC_RFLEARN);
mqttSubscribe(buffer);
#if not RF_SUPPORT
mqttSubscribe(MQTT_TOPIC_RFOUT);
#endif
#if RF_RAW_SUPPORT
mqttSubscribe(MQTT_TOPIC_RFRAW);
#endif
@ -469,7 +478,7 @@ void _rfbMqttCallback(unsigned int type, const char * topic, const char * payloa
_learnId = t.substring(strlen(MQTT_TOPIC_RFLEARN)+1).toInt();
if (_learnId >= relayCount()) {
DEBUG_MSG_P(PSTR("[RFBRIDGE] Wrong learnID (%d)\n"), _learnId);
DEBUG_MSG_P(PSTR("[RF] Wrong learnID (%d)\n"), _learnId);
return;
}
_learnStatus = (char)payload[0] != '0';
@ -478,13 +487,17 @@ void _rfbMqttCallback(unsigned int type, const char * topic, const char * payloa
}
bool isRFOut = t.equals(MQTT_TOPIC_RFOUT);
#if not RF_SUPPORT
bool isRFOut = t.equals(MQTT_TOPIC_RFOUT);
#endif
#if RF_RAW_SUPPORT
bool isRFRaw = !isRFOut && t.equals(MQTT_TOPIC_RFRAW);
#else
#elif not RF_SUPPORT
bool isRFRaw = false;
#endif
#if not RF_SUPPORT
if (isRFOut || isRFRaw) {
// The payload may be a code in HEX format ([0-9A-Z]{18}) or
@ -528,6 +541,8 @@ void _rfbMqttCallback(unsigned int type, const char * topic, const char * payloa
}
#endif // not RF_SUPPORT
}
}
@ -588,7 +603,7 @@ void _rfbInitCommands() {
// -----------------------------------------------------------------------------
void rfbStore(unsigned char id, bool status, const char * code) {
DEBUG_MSG_P(PSTR("[RFBRIDGE] Storing %d-%s => '%s'\n"), id, status ? "ON" : "OFF", code);
DEBUG_MSG_P(PSTR("[RF] Storing %d-%s => '%s'\n"), id, status ? "ON" : "OFF", code);
char key[RF_MAX_KEY_LENGTH] = {0};
snprintf_P(key, sizeof(key), PSTR("rfb%s%d"), status ? "ON" : "OFF", id);
setSetting(key, code);
@ -600,6 +615,8 @@ String rfbRetrieve(unsigned char id, bool status) {
return getSetting(key);
}
#if not RF_SUPPORT
void rfbStatus(unsigned char id, bool status) {
String value = rfbRetrieve(id, status);
@ -643,6 +660,7 @@ void rfbStatus(unsigned char id, bool status) {
_rfbin = false;
}
#endif // not RF_SUPPORT
void rfbLearn(unsigned char id, bool status) {
_learnId = id;
@ -684,13 +702,18 @@ void rfbSetup() {
_rfbInitCommands();
#endif
#if RFB_DIRECT
#if RFB_DIRECT || RF_SUPPORT
_rfModem = new RCSwitch();
#if RF_SUPPORT
_rfModem->enableReceive(RF_PIN);
DEBUG_MSG_P(PSTR("[RF] RF receiver on GPIO %u\n"), RF_PIN);
#else
_rfModem->enableReceive(RFB_RX_PIN);
_rfModem->enableTransmit(RFB_TX_PIN);
_rfModem->setRepeatTransmit(6);
DEBUG_MSG_P(PSTR("[RFBRIDGE] RF receiver on GPIO %u\n"), RFB_RX_PIN);
DEBUG_MSG_P(PSTR("[RFBRIDGE] RF transmitter on GPIO %u\n"), RFB_TX_PIN);
DEBUG_MSG_P(PSTR("[RF] RF receiver on GPIO %u\n"), RFB_RX_PIN);
DEBUG_MSG_P(PSTR("[RF] RF transmitter on GPIO %u\n"), RFB_TX_PIN);
#endif
#endif
// Register loop


Loading…
Cancel
Save