/* Theengs OpenMQTTGateway - We Unite Sensors in One Open-Source Interface Act as a wifi or ethernet gateway between your BLE/433mhz/infrared IR signal and an MQTT broker Send and receiving command by MQTT Copyright: (c)Florian ROBERT This file is part of OpenMQTTGateway. OpenMQTTGateway is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. OpenMQTTGateway is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "User_config.h" #if defined(ZgatewayRF) || defined(ZgatewayPilight) || defined(ZgatewayRTL_433) || defined(ZgatewayRF2) || defined(ZactuatorSomfy) # ifdef ZradioCC1101 # include # endif # include "TheengsCommon.h" # include "config_RF.h" # ifdef ZgatewayRTL_433 # include extern rtl_433_ESP rtl_433; # endif RFConfig_s RFConfig; void RFConfig_init(); void RFConfig_load(); void initCC1101() { # ifdef ZradioCC1101 //receiving with CC1101 // Loop on getCC1101() until it returns true and break after 10 attempts int delayMS = 16; int delayMaxMS = 500; for (int i = 0; i < 10; i++) { # if defined(RF_MODULE_SCK) && defined(RF_MODULE_MISO) && \ defined(RF_MODULE_MOSI) && defined(RF_MODULE_CS) ELECHOUSE_cc1101.setSpiPin(RF_MODULE_SCK, RF_MODULE_MISO, RF_MODULE_MOSI, RF_MODULE_CS); # endif if (ELECHOUSE_cc1101.getCC1101()) { THEENGS_LOG_NOTICE(F("C1101 spi Connection OK" CR)); ELECHOUSE_cc1101.Init(); ELECHOUSE_cc1101.SetRx(RFConfig.frequency); break; } else { THEENGS_LOG_ERROR(F("C1101 spi Connection Error" CR)); delay(delayMS); } // truncated exponential backoff delayMS = delayMS * 2; if (delayMS > delayMaxMS) delayMS = delayMaxMS; } # endif } void setupCommonRF() { RFConfig_init(); RFConfig_load(); } bool validFrequency(float mhz) { // CC1101 valid frequencies 300-348 MHZ, 387-464MHZ and 779-928MHZ. if (mhz >= 300 && mhz <= 348) return true; if (mhz >= 387 && mhz <= 464) return true; if (mhz >= 779 && mhz <= 928) return true; return false; } int currentReceiver = ACTIVE_NONE; # if !defined(ZgatewayRFM69) && !defined(ZactuatorSomfy) // Check if a receiver is available bool validReceiver(int receiver) { switch (receiver) { # ifdef ZgatewayPilight case ACTIVE_PILIGHT: return true; # endif # ifdef ZgatewayRF case ACTIVE_RF: return true; # endif # ifdef ZgatewayRTL_433 case ACTIVE_RTL: return true; # endif # ifdef ZgatewayRF2 case ACTIVE_RF2: return true; # endif default: THEENGS_LOG_ERROR(F("ERROR: stored receiver %d not available" CR), receiver); } return false; } # endif void disableCurrentReceiver() { THEENGS_LOG_TRACE(F("disableCurrentReceiver: %d" CR), currentReceiver); switch (currentReceiver) { case ACTIVE_NONE: break; # ifdef ZgatewayPilight case ACTIVE_PILIGHT: disablePilightReceive(); break; # endif # ifdef ZgatewayRF case ACTIVE_RF: disableRFReceive(); break; # endif # ifdef ZgatewayRTL_433 case ACTIVE_RTL: disableRTLreceive(); break; # endif # ifdef ZgatewayRF2 case ACTIVE_RF2: disableRF2Receive(); break; # endif default: THEENGS_LOG_ERROR(F("ERROR: unsupported receiver %d" CR), RFConfig.activeReceiver); } } void enableActiveReceiver() { THEENGS_LOG_TRACE(F("enableActiveReceiver: %d" CR), RFConfig.activeReceiver); switch (RFConfig.activeReceiver) { # ifdef ZgatewayPilight case ACTIVE_PILIGHT: initCC1101(); enablePilightReceive(); currentReceiver = ACTIVE_PILIGHT; break; # endif # ifdef ZgatewayRF case ACTIVE_RF: initCC1101(); enableRFReceive(RFConfig.frequency, RF_RECEIVER_GPIO, RF_EMITTER_GPIO); currentReceiver = ACTIVE_RF; break; # endif # ifdef ZgatewayRTL_433 case ACTIVE_RTL: initCC1101(); enableRTLreceive(); currentReceiver = ACTIVE_RTL; break; # endif # ifdef ZgatewayRF2 case ACTIVE_RF2: initCC1101(); enableRF2Receive(); currentReceiver = ACTIVE_RF2; break; # endif case ACTIVE_RECERROR: THEENGS_LOG_ERROR(F("ERROR: no receiver selected" CR)); break; default: THEENGS_LOG_ERROR(F("ERROR: unsupported receiver %d" CR), RFConfig.activeReceiver); } } String stateRFMeasures() { //Publish RTL_433 state StaticJsonDocument jsonBuffer; JsonObject RFdata = jsonBuffer.to(); RFdata["active"] = RFConfig.activeReceiver; # if defined(ZradioCC1101) || defined(ZradioSX127x) RFdata["frequency"] = RFConfig.frequency; if (RFConfig.activeReceiver == ACTIVE_RTL) { # ifdef ZgatewayRTL_433 RFdata["rssithreshold"] = (int)getRTLrssiThreshold(); RFdata["rssi"] = (int)getRTLCurrentRSSI(); RFdata["avgrssi"] = (int)getRTLAverageRSSI(); RFdata["count"] = (int)getRTLMessageCount(); // Capture high water mark of rtl_433_Decoder stack since it can run out and trigger reboot extern TaskHandle_t rtl_433_DecoderHandle; RFdata["rtl433_stack"] = (int)uxTaskGetStackHighWaterMark(rtl_433_DecoderHandle); # endif # ifdef ZradioSX127x RFdata["ookthreshold"] = (int)getOOKThresh(); # endif } # endif RFdata["origin"] = subjectcommonRFtoMQTT; enqueueJsonObject(RFdata); String output; serializeJson(RFdata, output); return output; } void RFConfig_fromJson(JsonObject& RFdata) { bool success = false; if (RFdata.containsKey("frequency") && validFrequency(RFdata["frequency"])) { Config_update(RFdata, "frequency", RFConfig.frequency); THEENGS_LOG_NOTICE(F("RF Receive mhz: %F" CR), RFConfig.frequency); success = true; } if (RFdata.containsKey("active")) { THEENGS_LOG_NOTICE(F("RF receiver active: %d" CR), RFConfig.activeReceiver); Config_update(RFdata, "active", RFConfig.activeReceiver); success = true; } # ifdef ZgatewayRTL_433 if (RFdata.containsKey("rssithreshold")) { THEENGS_LOG_NOTICE(F("RTL_433 RSSI Threshold : %d " CR), RFConfig.rssiThreshold); Config_update(RFdata, "rssithreshold", RFConfig.rssiThreshold); rtl_433.setRSSIThreshold(RFConfig.rssiThreshold); success = true; } # if defined(RF_SX1276) || defined(RF_SX1278) if (RFdata.containsKey("ookthreshold")) { Config_update(RFdata, "ookthreshold", RFConfig.newOokThreshold); THEENGS_LOG_NOTICE(F("RTL_433 ookThreshold %d" CR), RFConfig.newOokThreshold); rtl_433.setOOKThreshold(RFConfig.newOokThreshold); success = true; } # endif if (RFdata.containsKey("status")) { THEENGS_LOG_NOTICE(F("RF get status:" CR)); rtl_433.getStatus(); success = true; } if (!success) { THEENGS_LOG_ERROR(F("MQTTtoRF Fail json" CR)); } # endif disableCurrentReceiver(); enableActiveReceiver(); # ifdef ESP32 if (RFdata.containsKey("erase") && RFdata["erase"].as()) { // Erase config from NVS (non-volatile storage) preferences.begin(Gateway_Short_Name, false); if (preferences.isKey("RFConfig")) { int result = preferences.remove("RFConfig"); THEENGS_LOG_NOTICE(F("RF config erase result: %d" CR), result); preferences.end(); return; // Erase prevails on save, so skipping save } else { THEENGS_LOG_NOTICE(F("RF config not found" CR)); preferences.end(); } } if (RFdata.containsKey("save") && RFdata["save"].as()) { StaticJsonDocument jsonBuffer; JsonObject jo = jsonBuffer.to(); jo["frequency"] = RFConfig.frequency; jo["active"] = RFConfig.activeReceiver; // Don't save those for now, need to be tested # ifdef ZgatewayRTL_433 //jo["rssithreshold"] = RFConfig.rssiThreshold; //jo["ookthreshold"] = RFConfig.newOokThreshold; # endif // Save config into NVS (non-volatile storage) String conf = ""; serializeJson(jsonBuffer, conf); preferences.begin(Gateway_Short_Name, false); int result = preferences.putString("RFConfig", conf); preferences.end(); THEENGS_LOG_NOTICE(F("RF Config_save: %s, result: %d" CR), conf.c_str(), result); } # endif } void RFConfig_init() { RFConfig.frequency = RF_FREQUENCY; RFConfig.activeReceiver = ACTIVE_RECEIVER; RFConfig.rssiThreshold = 0; RFConfig.newOokThreshold = 0; } void RFConfig_load() { # ifdef ESP32 StaticJsonDocument jsonBuffer; preferences.begin(Gateway_Short_Name, true); if (preferences.isKey("RFConfig")) { auto error = deserializeJson(jsonBuffer, preferences.getString("RFConfig", "{}")); preferences.end(); if (error) { THEENGS_LOG_ERROR(F("RF Config deserialization failed: %s, buffer capacity: %u" CR), error.c_str(), jsonBuffer.capacity()); return; } if (jsonBuffer.isNull()) { THEENGS_LOG_WARNING(F("RF Config is null" CR)); return; } JsonObject jo = jsonBuffer.as(); RFConfig_fromJson(jo); THEENGS_LOG_NOTICE(F("RF Config loaded" CR)); } else { preferences.end(); THEENGS_LOG_NOTICE(F("RF Config not found using default" CR)); enableActiveReceiver(); } # else enableActiveReceiver(); # endif } void XtoRFset(const char* topicOri, JsonObject& RFdata) { if (cmpToMainTopic(topicOri, subjectMQTTtoRFset)) { THEENGS_LOG_TRACE(F("MQTTtoRF json set" CR)); /* * Configuration modifications priorities: * First `init=true` and `load=true` commands are executed (if both are present, INIT prevails on LOAD) * Then parameters included in json are taken in account * Finally `erase=true` and `save=true` commands are executed (if both are present, ERASE prevails on SAVE) */ if (RFdata.containsKey("init") && RFdata["init"].as()) { // Restore the default (initial) configuration RFConfig_init(); } else if (RFdata.containsKey("load") && RFdata["load"].as()) { // Load the saved configuration, if not initialised RFConfig_load(); } // Load config from json if available RFConfig_fromJson(RFdata); stateRFMeasures(); } } #endif