Refactor RF Configuration Management (#2245)

- Introduced RFConfiguration class to encapsulate RF settings and operations.
- Replaced direct usage of RFConfig structure with iRFConfig instance across multiple files.
- Updated frequency handling in actuatorSomfy, gatewayPilight, gatewayRF, and gatewayRF2 to use iRFConfig.
- Modified webUI to interact with iRFConfig for RF settings management.
- Removed deprecated RFConfig structure and related functions.
- Enhanced JSON handling for RF configuration loading and saving.
- Improved logging for RF configuration operations.
This commit is contained in:
Alessandro Staniscia authored and GitHub committed 2025-12-07 09:56:15 -06:00
1 parent 401be5f10c
commit c6b2aae965
12 files changed
+553 -206

No files matched your search

+5
View File
@@ -17,3 +17,8 @@ sdkconfig.*
__pycache__
*.pem
managed_components
.github/chatmodes
.github/prompts
.github/*instructions.md
+1 -1
View File
@@ -58,7 +58,7 @@ void setupSomfy() {
void XtoSomfy(const char* topicOri, JsonObject& jsonData) {
if (cmpToMainTopic(topicOri, subjectMQTTtoSomfy)) {
THEENGS_LOG_TRACE(F("MQTTtoSomfy json data analysis" CR));
float txFrequency = jsonData["frequency"] | RFConfig.frequency;
float txFrequency = jsonData["frequency"] | iRFConfig.getFrequency();
# ifdef ZradioCC1101 // set Receive off and Transmitt on
disableCurrentReceiver();
ELECHOUSE_cc1101.SetTx(txFrequency);
+38 -150
View File
@@ -29,6 +29,8 @@
# ifdef ZradioCC1101
# include <ELECHOUSE_CC1101_SRC_DRV.h>
# endif
# include <rf/RFConfiguration.h>
# include "TheengsCommon.h"
# include "config_RF.h"
@@ -37,10 +39,28 @@
extern rtl_433_ESP rtl_433;
# endif
RFConfig_s RFConfig;
void RFConfig_init();
void RFConfig_load();
int currentReceiver = ACTIVE_NONE;
extern void enableActiveReceiver();
extern void disableCurrentReceiver();
// Note: this is currently just a simple wrapper used to make everything work.
// It prevents introducing external dependencies on newly added C++ structures,
// and acts as a first approach to mask the concrete implementations (rf, rf2,
// pilight, etc.). Later this can be extended or replaced by more complete driver
// abstractions without changing the rest of the system.
class ZCommonRFWrapper : public RFReceiver {
public:
ZCommonRFWrapper() : RFReceiver() {}
void enable() override { enableActiveReceiver(); }
void disable() override { disableCurrentReceiver(); }
int getReceiverID() const override { return currentReceiver; }
};
ZCommonRFWrapper iRFReceiver;
RFConfiguration iRFConfig(iRFReceiver);
//TODO review
void initCC1101() {
# ifdef ZradioCC1101 //receiving with CC1101
// Loop on getCC1101() until it returns true and break after 10 attempts
@@ -54,7 +74,7 @@ void initCC1101() {
if (ELECHOUSE_cc1101.getCC1101()) {
THEENGS_LOG_NOTICE(F("C1101 spi Connection OK" CR));
ELECHOUSE_cc1101.Init();
ELECHOUSE_cc1101.SetRx(RFConfig.frequency);
ELECHOUSE_cc1101.SetRx(iRFConfig.getFrequency());
break;
} else {
THEENGS_LOG_ERROR(F("C1101 spi Connection Error" CR));
@@ -68,23 +88,10 @@ void initCC1101() {
}
void setupCommonRF() {
RFConfig_init();
RFConfig_load();
iRFConfig.reInit();
iRFConfig.loadFromStorage();
}
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) {
@@ -138,13 +145,13 @@ void disableCurrentReceiver() {
break;
# endif
default:
THEENGS_LOG_ERROR(F("ERROR: unsupported receiver %d" CR), RFConfig.activeReceiver);
THEENGS_LOG_ERROR(F("ERROR: unsupported receiver %d" CR), iRFConfig.getActiveReceiver());
}
}
void enableActiveReceiver() {
THEENGS_LOG_TRACE(F("enableActiveReceiver: %d" CR), RFConfig.activeReceiver);
switch (RFConfig.activeReceiver) {
THEENGS_LOG_TRACE(F("enableActiveReceiver: %d" CR), iRFConfig.getActiveReceiver());
switch (iRFConfig.getActiveReceiver()) {
# ifdef ZgatewayPilight
case ACTIVE_PILIGHT:
initCC1101();
@@ -155,7 +162,7 @@ void enableActiveReceiver() {
# ifdef ZgatewayRF
case ACTIVE_RF:
initCC1101();
enableRFReceive(RFConfig.frequency, RF_RECEIVER_GPIO, RF_EMITTER_GPIO);
enableRFReceive(iRFConfig.getFrequency(), RF_RECEIVER_GPIO, RF_EMITTER_GPIO);
currentReceiver = ACTIVE_RF;
break;
# endif
@@ -177,7 +184,7 @@ void enableActiveReceiver() {
THEENGS_LOG_ERROR(F("ERROR: no receiver selected" CR));
break;
default:
THEENGS_LOG_ERROR(F("ERROR: unsupported receiver %d" CR), RFConfig.activeReceiver);
THEENGS_LOG_ERROR(F("ERROR: unsupported receiver %d" CR), iRFConfig.getActiveReceiver());
}
}
@@ -185,10 +192,13 @@ String stateRFMeasures() {
//Publish RTL_433 state
StaticJsonDocument<JSON_MSG_BUFFER> jsonBuffer;
JsonObject RFdata = jsonBuffer.to<JsonObject>();
RFdata["active"] = RFConfig.activeReceiver;
// load the configuration
iRFConfig.toJson(RFdata);
// load the current state
# if defined(ZradioCC1101) || defined(ZradioSX127x)
RFdata["frequency"] = RFConfig.frequency;
if (RFConfig.activeReceiver == ACTIVE_RTL) {
if (iRFConfig.getActiveReceiver() == ACTIVE_RTL) {
# ifdef ZgatewayRTL_433
RFdata["rssithreshold"] = (int)getRTLrssiThreshold();
RFdata["rssi"] = (int)getRTLCurrentRSSI();
@@ -211,134 +221,12 @@ String stateRFMeasures() {
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<bool>()) {
// 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<bool>()) {
StaticJsonDocument<JSON_MSG_BUFFER> jsonBuffer;
JsonObject jo = jsonBuffer.to<JsonObject>();
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<JSON_MSG_BUFFER> 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<JsonObject>();
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<bool>()) {
// Restore the default (initial) configuration
RFConfig_init();
} else if (RFdata.containsKey("load") && RFdata["load"].as<bool>()) {
// Load the saved configuration, if not initialised
RFConfig_load();
}
iRFConfig.loadFromMessage(RFdata);
// Load config from json if available
RFConfig_fromJson(RFdata);
stateRFMeasures();
}
}
+5 -11
View File
@@ -25,11 +25,11 @@
*/
#ifndef config_RF_h
#define config_RF_h
#pragma once
#include "TheengsCommon.h"
#include <rf/RFConfiguration.h>
#ifdef ZgatewayRF
extern void setupRF();
extern void RFtoX();
extern void XtoRF(const char* topicOri, const char* datacallback);
extern void XtoRF(const char* topicOri, JsonObject& RFdata);
@@ -137,6 +137,9 @@ const char parameters[51][4][24] = {
# define DISCOVERY_TRACE_LOG(...)
# endif
#endif
extern RFConfiguration iRFConfig;
/*-------------------RF topics & parameters----------------------*/
//433Mhz MQTT Subjects and keys
#define subjectMQTTtoRF "/commands/MQTTto433"
@@ -198,13 +201,6 @@ const char parameters[51][4][24] = {
* 4 = ZgatewayRF2
*/
struct RFConfig_s {
float frequency;
int rssiThreshold;
int newOokThreshold;
int activeReceiver;
};
#define ACTIVE_NONE -1
#define ACTIVE_RECERROR 0
#define ACTIVE_PILIGHT 1
@@ -224,8 +220,6 @@ struct RFConfig_s {
# define ACTIVE_RECEIVER ACTIVE_NONE
#endif
extern RFConfig_s RFConfig;
/*-------------------CC1101 DefaultTXPower----------------------*/
//Adjust the default TX-Power for sending radio if ZradioCC1101 is used.
//The following settings are possible depending on the frequency band. (-30 -20 -15 -10 -6 0 5 7 10 11 12) Default is max!
+2 -2
View File
@@ -218,7 +218,7 @@ void XtoPilight(const char* topicOri, JsonObject& Pilightdata) {
const char* protocol = Pilightdata["protocol"];
THEENGS_LOG_NOTICE(F("MQTTtoPilight protocol: %s" CR), protocol);
const char* raw = Pilightdata["raw"];
float txFrequency = Pilightdata["frequency"] | RFConfig.frequency;
float txFrequency = Pilightdata["frequency"] | iRFConfig.getFrequency();
bool success = false;
disableCurrentReceiver();
initCC1101();
@@ -307,7 +307,7 @@ extern void disablePilightReceive() {
};
extern void enablePilightReceive() {
THEENGS_LOG_NOTICE(F("Switching to Pilight Receiver: %F" CR), RFConfig.frequency);
THEENGS_LOG_NOTICE(F("Switching to Pilight Receiver: %F" CR), iRFConfig.getFrequency());
THEENGS_LOG_NOTICE(F("RF_EMITTER_GPIO: %d " CR), RF_EMITTER_GPIO);
THEENGS_LOG_NOTICE(F("RF_RECEIVER_GPIO: %d " CR), RF_RECEIVER_GPIO);
THEENGS_LOG_TRACE(F("gatewayPilight command topic: %s%s%s" CR), mqtt_topic, gateway_name, subjectMQTTtoPilight);
+10 -9
View File
@@ -30,6 +30,7 @@
#ifdef ZgatewayRF
# include "TheengsCommon.h"
# include "config_RF.h"
# ifdef ZradioCC1101
# include <ELECHOUSE_CC1101_SRC_DRV.h>
extern void initCC1101();
@@ -201,12 +202,12 @@ void RFtoX() {
# endif
# ifdef ZradioCC1101 // set Receive off and Transmitt on
RFdata["frequency"] = RFConfig.frequency;
RFdata["frequency"] = iRFConfig.getFrequency();
# endif
mySwitch.resetAvailable();
if (!isAduplicateSignal(MQTTvalue) && MQTTvalue != 0) { // conditions to avoid duplications of RF -->MQTT
if (MQTTvalue != 0 && !isAduplicateSignal(MQTTvalue)) { // conditions to avoid duplications of RF -->MQTT
# if defined(ZmqttDiscovery) && defined(RF_on_HAS_as_DeviceTrigger)
if (SYSConfig.discovery)
announceGatewayTriggerTypeToHASS(MQTTvalue);
@@ -253,8 +254,8 @@ void RFtoX() {
void XtoRF(const char* topicOri, const char* datacallback) {
# ifdef ZradioCC1101 // set Receive off and Transmitt on
disableCurrentReceiver();
ELECHOUSE_cc1101.SetTx(RFConfig.frequency);
THEENGS_LOG_NOTICE(F("[RF] Transmit frequency: %F" CR), RFConfig.frequency);
ELECHOUSE_cc1101.SetTx(iRFConfig.getFrequency());
THEENGS_LOG_NOTICE(F("[RF] Transmit frequency: %F" CR), iRFConfig.getFrequency());
# endif
mySwitch.disableReceive();
mySwitch.enableTransmit(RF_EMITTER_GPIO);
@@ -304,7 +305,7 @@ void XtoRF(const char* topicOri, const char* datacallback) {
pub(subjectGTWRFtoMQTT, datacallback); // we acknowledge the sending by publishing the value to an acknowledgement topic, for the moment even if it is a signal repetition we acknowledge also
}
# ifdef ZradioCC1101 // set Receive on and Transmitt off
ELECHOUSE_cc1101.SetRx(RFConfig.frequency);
ELECHOUSE_cc1101.SetRx(iRFConfig.getFrequency());
mySwitch.disableTransmit();
mySwitch.enableReceive(RF_RECEIVER_GPIO);
# endif
@@ -328,7 +329,7 @@ void XtoRF(const char* topicOri, const char* datacallback) {
* - "length": The number of bits in the RF signal (optional, default is 24).
* - "repeat": The number of times the RF signal should be repeated (optional, default is RF_EMITTER_REPEAT).
* - "txpower": The transmission power for CC1101 (optional, default is RF_CC1101_TXPOWER).
* - "frequency": The transmission frequency for CC1101 (optional, default is RFConfig.frequency).
* - "frequency": The transmission frequency for CC1101 (optional, default is iRFConfig.getFrequency()).
*
* The function logs the transmission details and acknowledges the sending by publishing the value to an acknowledgement topic.
* It also restores the default repeat transmit value after sending the signal.
@@ -349,7 +350,7 @@ void XtoRF(const char* topicOri, JsonObject& RFdata) {
int txPower = RFdata["txpower"] | RF_CC1101_TXPOWER;
ELECHOUSE_cc1101.setPA((int)txPower);
THEENGS_LOG_NOTICE(F("[RF] CC1101 TX Power: %d" CR), txPower);
float txFrequency = RFdata["frequency"] | RFConfig.frequency;
float txFrequency = RFdata["frequency"] | iRFConfig.getFrequency();
ELECHOUSE_cc1101.SetTx(txFrequency);
THEENGS_LOG_NOTICE(F("[RF] Transmit frequency: %F" CR), txFrequency);
# endif
@@ -391,14 +392,14 @@ void disableRFReceive() {
* initializes the RF transmitter on the specified GPIO pin. It also sets the RF frequency
* and logs the configuration details.
*
* @param rfFrequency The frequency for the RF communication in MHz. Default is RFConfig.frequency.
* @param rfFrequency The frequency for the RF communication in MHz. Default is iRFConfig.getFrequency().
* @param rfReceiverGPIO The GPIO pin number for the RF receiver. Default is RF_RECEIVER_GPIO.
* @param rfEmitterGPIO The GPIO pin number for the RF transmitter. Default is RF_EMITTER_GPIO.
*
* @note If RF_DISABLE_TRANSMIT is defined, the RF transmitter will be disabled.
*/
void enableRFReceive(
float rfFrequency = RFConfig.frequency,
float rfFrequency = iRFConfig.getFrequency(),
int rfReceiverGPIO = RF_RECEIVER_GPIO,
int rfEmitterGPIO = RF_EMITTER_GPIO) {
THEENGS_LOG_NOTICE(F("[RF] Enable RF Receiver: %fMhz, RF_EMITTER_GPIO: %d, RF_RECEIVER_GPIO: %d" CR), rfFrequency, rfEmitterGPIO, rfReceiverGPIO);
+3 -3
View File
@@ -150,7 +150,7 @@ void XtoRF2(const char* topicOri, const char* datacallback) {
int txPower = RF_CC1101_TXPOWER;
ELECHOUSE_cc1101.setPA((int)txPower);
THEENGS_LOG_NOTICE(F("[RF] CC1101 TX Power: %d" CR), txPower);
float txFrequency = RFConfig.frequency;
float txFrequency = iRFConfig.getFrequency();
ELECHOUSE_cc1101.SetTx(txFrequency);
THEENGS_LOG_NOTICE(F("[RF] Transmit frequency: %F" CR), txFrequency);
# endif
@@ -252,7 +252,7 @@ void XtoRF2(const char* topicOri, const char* datacallback) {
}
}
# ifdef ZradioCC1101
ELECHOUSE_cc1101.SetRx(RFConfig.frequency); // set Receive on
ELECHOUSE_cc1101.SetRx(iRFConfig.getFrequency()); // set Receive on
# endif
enableActiveReceiver();
}
@@ -273,7 +273,7 @@ void XtoRF2(const char* topicOri, JsonObject& RF2data) { // json object decoding
int txPower = RF2data["txpower"] | RF_CC1101_TXPOWER;
ELECHOUSE_cc1101.setPA((int)txPower);
THEENGS_LOG_NOTICE(F("[RF] CC1101 TX Power: %d" CR), txPower);
float txFrequency = RF2data["frequency"] | RFConfig.frequency;
float txFrequency = RF2data["frequency"] | iRFConfig.getFrequency();
ELECHOUSE_cc1101.SetTx(txFrequency);
THEENGS_LOG_NOTICE(F("[RF] Transmit frequency: %F" CR), txFrequency);
# endif
+2 -2
View File
@@ -327,8 +327,8 @@ void RTL_433Loop() {
}
extern void enableRTLreceive() {
THEENGS_LOG_NOTICE(F("Enable RTL_433 Receiver: %FMhz" CR), RFConfig.frequency);
rtl_433.initReceiver(RF_MODULE_RECEIVER_GPIO, RFConfig.frequency);
THEENGS_LOG_NOTICE(F("Enable RTL_433 Receiver: %FMhz" CR), iRFConfig.getFrequency());
rtl_433.initReceiver(RF_MODULE_RECEIVER_GPIO, iRFConfig.getFrequency());
rtl_433.enableReceiver();
}
+332
View File
@@ -0,0 +1,332 @@
#include "RFConfiguration.h"
#include <config_RF.h>
#ifdef ZgatewayRTL_433
# include <rtl_433_ESP.h>
extern rtl_433_ESP rtl_433;
#endif
// Constructor
RFConfiguration::RFConfiguration(RFReceiver& receiver) : iRFReceiver(receiver) {
reInit();
}
// Destructor
RFConfiguration::~RFConfiguration() {
}
// Getters and Setters
float RFConfiguration::getFrequency() const {
return frequency;
}
void RFConfiguration::setFrequency(float freq) {
frequency = freq;
}
int RFConfiguration::getRssiThreshold() const {
return rssiThreshold;
}
void RFConfiguration::setRssiThreshold(int threshold) {
rssiThreshold = threshold;
}
int RFConfiguration::getNewOokThreshold() const {
return newOokThreshold;
}
void RFConfiguration::setNewOokThreshold(int threshold) {
newOokThreshold = threshold;
}
int RFConfiguration::getActiveReceiver() const {
return activeReceiver;
}
void RFConfiguration::setActiveReceiver(int receiver) {
activeReceiver = receiver;
}
/**
* @brief Initializes the RFConfiguration with default values.
*
* This function sets up the RFConfiguration by assigning default values
* to its members, including frequency, active receiver, RSSI threshold,
* and new OOK threshold. It also clears and shrinks the whiteList and
* blackList containers to ensure they are empty and optimized for memory usage.
*
* @note This function should be called during the initialization phase
* to ensure the RFConfiguration is properly configured.
*/
void RFConfiguration::reInit() {
frequency = RF_FREQUENCY;
activeReceiver = ACTIVE_RECEIVER;
rssiThreshold = 0;
newOokThreshold = 0;
}
/**
* @brief Erases the RF configuration from non-volatile storage (NVS).
*
* This function removes the RF configuration stored in NVS. It checks if
* the configuration exists and, if so, removes it. If the configuration
* is not found, a notice is logged.
*
* @note This function is only available on ESP32 platforms.
*/
void RFConfiguration::eraseStorage() {
#ifdef ESP32
// Erase config from NVS (non-volatile storage)
preferences.begin(Gateway_Short_Name, false);
if (preferences.isKey("RFConfig")) {
int result = preferences.remove("RFConfig");
Log.notice(F("RF config erase result: %d" CR), result);
} else {
Log.notice(F("RF config not found" CR));
}
preferences.end();
#else
Log.warning(F("RF Config Erase not support with this board" CR));
#endif
}
/**
* @brief Saves the RF configuration to non-volatile storage (NVS).
*
* This function serializes the RF configuration data into a JSON object
* and saves it to NVS. The saved configuration includes frequency, active
* receiver, and other relevant parameters.
*
* @note This function is only available on ESP32 platforms.
* @note Ensure that the `JSON_MSG_BUFFER` is large enough to hold the
* serialized configuration data to avoid deserialization errors.
*/
void RFConfiguration::saveOnStorage() {
#ifdef ESP32
StaticJsonDocument<JSON_MSG_BUFFER> jsonBuffer;
JsonObject jo = jsonBuffer.to<JsonObject>();
toJson(jo);
# ifdef ZgatewayRTL_433
// FROM ORIGINAL CONFIGURATION:
// > Don't save those for now, need to be tested
jo.remove("rssithreshold");
jo.remove("ookthreshold");
# 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();
Log.notice(F("RF Config_save: %s, result: %d" CR), conf.c_str(), result);
#else
Log.warning(F("RF Config_save not support with this board" CR));
#endif
}
/**
* @brief Loads the RF configuration from persistent storage and applies it.
*
* This function retrieves the RF configuration stored in non-volatile
* storage (NVS) and applies it to the RF receiver. If the configuration
* is not found, a notice is logged, and the RF receiver is enabled with
* default settings.
*
* @note This function has specific behavior for ESP32 platforms. On ESP32,
* it uses the Preferences library to access stored configuration data.
* For other platforms, it directly enables the active receiver.
*/
void RFConfiguration::loadFromStorage() {
#ifdef ESP32
StaticJsonDocument<JSON_MSG_BUFFER> jsonBuffer;
preferences.begin(Gateway_Short_Name, true);
if (preferences.isKey("RFConfig")) {
auto error = deserializeJson(jsonBuffer, preferences.getString("RFConfig", "{}"));
preferences.end();
if (error) {
Log.error(F("RF Config deserialization failed: %s, buffer capacity: %u" CR), error.c_str(), jsonBuffer.capacity());
return;
}
if (jsonBuffer.isNull()) {
Log.warning(F("RF Config is null" CR));
return;
}
JsonObject jo = jsonBuffer.as<JsonObject>();
fromJson(jo);
Log.notice(F("RF Config loaded" CR));
} else {
preferences.end();
Log.notice(F("RF Config not found using default" CR));
iRFReceiver.enable();
}
#else
iRFReceiver.enable();
#endif
}
/**
* @brief Loads the RF configuration from a JSON object and applies it.
*
* This function takes a JSON object containing RF configuration data and
* applies it to the RF receiver. It also handles the erasure and saving of
* the configuration based on the provided JSON data.
*
* 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)*
*
* @param RFdata A reference to a JsonObject containing the RF configuration data.
*
* The following keys are supported in the JSON object:
* - "init": If true, restores the default RF configuration.
* - "load": If true, loads the saved RF configuration from storage.
* - "erase": If true, erases the RF configuration from storage.
* - "save": If true, saves the current RF configuration to storage.
*
* Logs messages to indicate the success or failure of each operation.
*/
void RFConfiguration::loadFromMessage(JsonObject& RFdata) {
if (RFdata.containsKey("init") && RFdata["init"].as<bool>()) {
// Restore the default (initial) configuration
reInit();
} else if (RFdata.containsKey("load") && RFdata["load"].as<bool>()) {
// Load the saved configuration, if not initialised
loadFromStorage();
}
fromJson(RFdata);
iRFReceiver.disable();
iRFReceiver.enable();
if (RFdata.containsKey("erase") && RFdata["erase"].as<bool>()) {
eraseStorage();
Log.notice(F("RF Config erased" CR));
} else if (RFdata.containsKey("save") && RFdata["save"].as<bool>()) {
saveOnStorage();
Log.notice(F("RF Config saved" CR));
}
}
/**
* @brief Updates the RF configuration from a JSON object.
*
* This function parses the provided JSON object and updates the RF configuration
* based on the keys and values present in the object. It supports updating
* white-list, black-list, frequency, active receiver status, and other RF-related
* parameters depending on the defined preprocessor directives.
*
* @param RFdata A reference to a JsonObject containing the RF configuration data.
*
* The following keys are supported in the JSON object:
* - "white-list": Updates the RF white-list.
* - "black-list": Updates the RF black-list.
* - "frequency": Updates the RF frequency if the value is valid.
* - "active": Updates the active receiver status.
*
* Additional keys supported when ZgatewayRTL_433 is defined:
* - "rssithreshold": Updates the RSSI threshold for RTL_433.
* - "ookthreshold": Updates the OOK threshold for RTL_433 (requires RF_SX1276 or RF_SX1278).
* - "status": Retrieves the current status of the RF configuration.
*
* Logs messages to indicate the success or failure of each update operation.
* If no valid keys are found in the JSON object, an error message is logged.
*/
void RFConfiguration::fromJson(JsonObject& RFdata) {
bool success = false;
if (RFdata.containsKey("frequency") && validFrequency(RFdata["frequency"])) {
Config_update(RFdata, "frequency", frequency);
Log.notice(F("RF Receive mhz: %F" CR), frequency);
success = true;
}
if (RFdata.containsKey("active")) {
Config_update(RFdata, "active", activeReceiver);
Log.notice(F("RF receiver active: %d" CR), activeReceiver);
success = true;
}
#ifdef ZgatewayRTL_433
if (RFdata.containsKey("rssithreshold")) {
Log.notice(F("RTL_433 RSSI Threshold : %d " CR), rssiThreshold);
Config_update(RFdata, "rssithreshold", rssiThreshold);
rtl_433.setRSSIThreshold(rssiThreshold);
success = true;
}
# if defined(RF_SX1276) || defined(RF_SX1278)
if (RFdata.containsKey("ookthreshold")) {
Config_update(RFdata, "ookthreshold", newOokThreshold);
Log.notice(F("RTL_433 ookThreshold %d" CR), newOokThreshold);
rtl_433.setOOKThreshold(newOokThreshold);
success = true;
}
# endif
if (RFdata.containsKey("status")) {
Log.notice(F("RF get status:" CR));
rtl_433.getStatus();
success = true;
}
if (!success) {
Log.error(F("MQTTtoRF Fail json" CR));
}
#endif
}
/**
* @brief Serializes the RFConfiguration object into a JSON object.
*
* This method populates the provided JSON object with the configuration
* details of the RF module, including frequency, RSSI threshold, OOK threshold,
* active receiver status, and ignore list settings. Additionally, it includes
* the white-list and black-list vectors as nested JSON arrays.
*
* @param RFdata A reference to a JsonObject where the RF configuration data
* will be serialized.
*
* JSON Structure:
* {
* "frequency": <float>, // Frequency value
* "rssithreshold": <float>, // RSSI threshold value
* "ookthreshold": <float>, // OOK threshold value
* "active": <bool>, // Active receiver status
* "ignoreWhitelist": <bool>, // Ignore white-list flag
* "ignoreBlacklist": <bool>, // Ignore black-list flag
* "white-list": [<int>, ...], // Array of white-list values
* "black-list": [<int>, ...] // Array of black-list values
* }
*/
void RFConfiguration::toJson(JsonObject& RFdata) {
RFdata["frequency"] = frequency;
RFdata["rssithreshold"] = rssiThreshold;
RFdata["ookthreshold"] = newOokThreshold;
RFdata["active"] = activeReceiver;
// Add white-list vector to the JSON object
JsonArray whiteListArray = RFdata.createNestedArray("white-list");
// Add black-list vector to the JSON object
JsonArray blackListArray = RFdata.createNestedArray("black-list");
}
/**
* @brief Validates if the given frequency is within the acceptable ranges for the CC1101 module.
*
* The CC1101 module supports the following frequency ranges:
* - 300 MHz to 348 MHz
* - 387 MHz to 464 MHz
* - 779 MHz to 928 MHz
*
* @param mhz The frequency in MHz to validate.
* @return true if the frequency is within one of the valid ranges, false otherwise.
*/
bool RFConfiguration::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;
}
+118
View File
@@ -0,0 +1,118 @@
#ifndef RFCONFIG_H
#define RFCONFIG_H
#pragma once
#include <TheengsCommon.h>
#include <rf/RFReceiver.h>
class RFConfiguration {
public:
// Constructor
RFConfiguration(RFReceiver& receiver);
~RFConfiguration();
// Getters and Setters
float getFrequency() const;
void setFrequency(float freq);
int getRssiThreshold() const;
void setRssiThreshold(int threshold);
int getNewOokThreshold() const;
void setNewOokThreshold(int threshold);
int getActiveReceiver() const;
void setActiveReceiver(int receiver);
/**
* Initializes the structure with default values.
*
* @note This function should be called during the initialization phase
* to ensure the structure is properly configured.
*/
void reInit();
/**
* Erases the RF configuration from non-volatile storage (NVS).
*
* @note This function is only available on ESP32 platforms.
*/
void eraseStorage();
/**
* Saves the RF configuration to non-volatile storage (NVS).
*
* @note This function is only available on ESP32 platforms.
*/
void saveOnStorage();
/**
* Loads the RF configuration from persistent storage and applies it.
*
* @note This function has specific behavior for ESP32 platforms. On ESP32,
* it uses the Preferences library to access stored configuration data.
* For other platforms, it directly enables the active receiver.
*/
void loadFromStorage();
/**
* Loads the RF configuration from a JSON object and applies it.
*
* @param RFdata A reference to a JsonObject containing the RF configuration data.
*
* The following keys are supported in the JSON object:
* - "erase": If true, erases the RF configuration from storage.
* - "save": If true, saves the current RF configuration to storage.
*
* Logs messages to indicate the success or failure of each operation.
*/
void loadFromMessage(JsonObject& RFdata);
/**
* Updates the RF configuration from a JSON object.
*
* @param RFdata A reference to a JsonObject containing the RF configuration data.
*
* The following keys are supported in the JSON object:
* - "white-list": Updates the RF white-list.
* - "black-list": Updates the RF black-list.
* - "frequency": Updates the RF frequency if the value is valid.
* - "active": Updates the active receiver status.
*
* Additional keys supported when ZgatewayRTL_433 is defined:
* - "rssithreshold": Updates the RSSI threshold for RTL_433.
* - "ookthreshold": Updates the OOK threshold for RTL_433 (requires RF_SX1276 or RF_SX1278).
* - "status": Retrieves the current status of the RF configuration.
*/
void fromJson(JsonObject& RFdata);
/**
* Serializes the RF configuration to a JSON object.
*
* @param RFdata A reference to a JsonObject where the RF configuration will be serialized.
*/
void toJson(JsonObject& RFdata);
/**
* @brief Validates if the given frequency is within the acceptable ranges for the CC1101 module.
*
* The CC1101 module supports the following frequency ranges:
* - 300 MHz to 348 MHz
* - 387 MHz to 464 MHz
* - 779 MHz to 928 MHz
*
* @param mhz The frequency in MHz to validate.
* @return true if the frequency is within one of the valid ranges, false otherwise.
*/
bool validFrequency(float mhz);
private:
// Reference to the RFReceiver object
RFReceiver& iRFReceiver;
float frequency;
int rssiThreshold;
int newOokThreshold;
int activeReceiver;
};
#endif // RFCONFIG_H
+15
View File
@@ -0,0 +1,15 @@
#ifndef RFRECEIVER_H
#define RFRECEIVER_H
#pragma once
class RFReceiver {
public:
virtual ~RFReceiver() = default;
// Pure virtual methods
virtual void enable() = 0;
virtual void disable() = 0;
virtual int getReceiverID() const = 0;
};
#endif // RFRECEIVER_H
+22 -28
View File
@@ -976,14 +976,13 @@ void handleBL() {
bool update = false;
if (server.hasArg("save")) {
// Default BLE AES Key
if (server.hasArg("bk")) {
WEBtoSYS["ble_aes"] = server.arg("bk");
update = true;
}
// Split Custom BLE AES key pair string add to config
// Split Custom BLE AES key pair string add to config
if (server.hasArg("kp")) {
String kp = server.arg("kp");
while (kp.length() > 0) {
@@ -997,7 +996,7 @@ void handleBL() {
if (kp.indexOf(':') == 12) {
WEBtoSYS["ble_aes_keys"][kp.substring(0, 12)] = kp.substring(13, 45);
}
kp = kp.substring(kpindex+1);
kp = kp.substring(kpindex + 1);
}
}
update = true;
@@ -1013,7 +1012,7 @@ void handleBL() {
}
}
// Build BLE Key Pair string
// Build BLE Key Pair string
std::string aeskeysstring;
JsonObject root = ble_aes_keys.as<JsonObject>();
for (JsonPair kv : root) {
@@ -1204,6 +1203,8 @@ void handleLA() {
}
# elif defined(ZgatewayRTL_433) || defined(ZgatewayPilight) || defined(ZgatewayRF) || defined(ZgatewayRF2) || defined(ZactuatorSomfy)
# include <map>
# include "rf/RFConfiguration.h"
std::map<int, String> activeReceiverOptions = {
{0, "Inactive"},
# if defined(ZgatewayPilight) && !defined(ZradioSX127x)
@@ -1220,16 +1221,7 @@ std::map<int, String> activeReceiverOptions = {
# endif
};
struct RFConfig_s {
float frequency;
int rssiThreshold;
int newOokThreshold;
int activeReceiver;
};
extern RFConfig_s RFConfig;
bool validFrequency(float mhz);
void RFConfig_fromJson(JsonObject& RFdata);
extern RFConfiguration iRFConfig;
bool isValidReceiver(int receiverId) {
// Check if the receiverId exists in the activeReceiverOptions map
@@ -1257,8 +1249,9 @@ String generateActiveReceiverOptions(int currentSelection) {
* T: handleRF Arg: 3, dg=0
* T: handleRF Arg: 4, ar=0
* T: handleRF Arg: 4, save=
*/
* TODO: need a review, it's a bit strance set the config in the iRFConfig attribute and then
* setup a message and finally call the loadFromMessage
*/
void handleRF() {
WEBUI_TRACE_LOG(F("handleRF: uri: %s, args: %d, method: %d" CR), server.uri(), server.args(), server.method());
WEBUI_SECURE
@@ -1273,9 +1266,10 @@ void handleRF() {
if (server.hasArg("save")) {
if (server.hasArg("rf")) {
String freqStr = server.arg("rf");
RFConfig.frequency = freqStr.toFloat();
if (validFrequency(RFConfig.frequency)) {
WEBtoRF["frequency"] = RFConfig.frequency;
float freq = freqStr.toFloat();
if (iRFConfig.validFrequency(freq)) {
iRFConfig.setFrequency(freq);
WEBtoRF["frequency"] = iRFConfig.getFrequency();
update = true;
} else {
THEENGS_LOG_WARNING(F("[WebUI] Invalid Frequency" CR));
@@ -1284,34 +1278,34 @@ void handleRF() {
if (server.hasArg("ar")) {
int selectedReceiver = server.arg("ar").toInt();
if (isValidReceiver(selectedReceiver)) { // Assuming isValidReceiver is a validation function
RFConfig.activeReceiver = selectedReceiver;
WEBtoRF["activereceiver"] = RFConfig.activeReceiver;
iRFConfig.setActiveReceiver(selectedReceiver);
WEBtoRF["activereceiver"] = iRFConfig.getActiveReceiver();
update = true;
} else {
THEENGS_LOG_WARNING(F("[WebUI] Invalid Active Receiver" CR));
}
}
if (server.hasArg("oo")) {
RFConfig.newOokThreshold = server.arg("oo").toInt();
WEBtoRF["ookthreshold"] = RFConfig.newOokThreshold;
iRFConfig.setNewOokThreshold(server.arg("oo").toInt());
WEBtoRF["ookthreshold"] = iRFConfig.getNewOokThreshold();
update = true;
}
if (server.hasArg("rs")) {
RFConfig.rssiThreshold = server.arg("rs").toInt();
WEBtoRF["rssithreshold"] = RFConfig.rssiThreshold;
iRFConfig.setRssiThreshold(server.arg("rs").toInt());
WEBtoRF["rssithreshold"] = iRFConfig.getRssiThreshold();
update = true;
}
if (update) {
THEENGS_LOG_NOTICE(F("[WebUI] Save data" CR));
WEBtoRF["save"] = true;
RFConfig_fromJson(WEBtoRF);
iRFConfig.loadFromMessage(WEBtoRF);
stateRFMeasures();
THEENGS_LOG_TRACE(F("[WebUI] RFConfig end" CR));
}
}
}
String activeReceiverHtml = generateActiveReceiverOptions(RFConfig.activeReceiver);
String activeReceiverHtml = generateActiveReceiverOptions(iRFConfig.getActiveReceiver());
char jsonChar[100];
serializeJson(modules, jsonChar, measureJson(modules) + 1);
@@ -1322,7 +1316,7 @@ void handleRF() {
response += String(script);
response += String(style);
snprintf(buffer, WEB_TEMPLATE_BUFFER_MAX_SIZE, config_rf_body, jsonChar, gateway_name, RFConfig.frequency, activeReceiverHtml.c_str());
snprintf(buffer, WEB_TEMPLATE_BUFFER_MAX_SIZE, config_rf_body, jsonChar, gateway_name, iRFConfig.getFrequency(), activeReceiverHtml.c_str());
response += String(buffer);
snprintf(buffer, WEB_TEMPLATE_BUFFER_MAX_SIZE, footer, OMG_VERSION);
response += String(buffer);