Files
OpenMQTT-Gateway/main/rf/RFConfiguration.cpp
T
Alessandro Staniscia 98481c5145 [SITE] Renew the web board presentation and the ESP32 web upload + [SYS] Security checks (#2277)
* Refactor GitHub Actions workflows for build, documentation, and linting

- Consolidated build logic into reusable workflows (`task-build.yml` and `task-docs.yml`) to reduce duplication across multiple workflows.
- Introduced `environments.json` to centralize the list of PlatformIO build environments, improving maintainability and clarity.
- Updated `build.yml` and `build_and_docs_to_dev.yml` to utilize the new reusable workflows and environment definitions.
- Enhanced `release.yml` to streamline the release process and integrate documentation generation.
- Created reusable linting workflow (`task-lint.yml`) to standardize code formatting checks across the repository.
- Simplified manual documentation workflow by leveraging the new reusable documentation workflow.
- Improved artifact management and retention policies across workflows.
- Updated dependencies and versions in workflows to ensure compatibility and performance.

CI/CD pipeline agnostic of Workflow Engine and integrated on github actions

- Implemented ci.sh for orchestrating the complete build pipeline.
- Created ci_00_config.sh for centralized configuration of build scripts.
- Created ci_build_firmware.sh for building firmware for specified PlatformIO environments.
- Created ci_prepare_artifacts.sh for preparing firmware artifacts for upload or deployment.
- Created ci_set_version.sh for updating version tags in firmware configuration files.
- Created ci_build.sh to orchestrate the complete build pipeline.
- Created ci_qa.sh for code linting and formatting checks using clang-format.
- Created ci_site.sh for building and deploying VuePress documentation with version management.
- Implemented checks for required tools and dependencies in the new scripts.
- Improved internal scripts for better error handling and logging.

UPDATE the web installer manifest generation and update documentation structure
- Enhanced ci_list-env.sh to list environments from a JSON file.
- Replaced  common_wu.py and gen_wu.py scripts with new npm scripts for site generation and previewing on docsgen/gen_wu.js
- Replaced  generate_board_docs.py with docsgen/generated_board_docs.js
- Added new npm scripts for integration of site generation on build phase.
- Created preview_site.js to serve locally generated site over HTTPS with improved error handling.
- Added new CI environments for CI builds in environments.json.
- Deleted lint.yml as part of workflow cleanup.
- Enhanced task-build.yml to include linting as a job and added support for specifying PlatformIO version.
- Improved task-docs.yml to handle versioning more effectively and added clean option.

Enhance documentation
- ADD CLEAR Mark of development version of site
- Updated README.md to include detailed workflow dependencies and relationships using mermaid diagrams.
- Improved development.md with a quick checklist for contributors and clarified the code style guide.
- Enhanced quick_start.md with tips for contributors and streamlined the workflow explanation.

LINT FIX
- Refined User_config.h for better formatting consistency.
- Adjusted blufi.cpp and gatewayBT.cpp for improved code readability and consistency in formatting.
- Updated gatewaySERIAL.cpp and mqttDiscovery.cpp to enhance logging error messages.
- Improved sensorDS1820.cpp for better logging of device information.

Add security scan workflows for vulnerability detection

Add SBOM generation and upload to release workflow; update security scan summary handling

Add shellcheck suppor + FIX shellcheck warning

Enhance documentation for CI/CD scripts and workflows, adding details for security scanning and SBOM generation processes

Fix formatting and alignment in BLE connection handling

Reviewed the full web board presentation and the ESP32 web upload. The project uses a modern pattern where data is divided from the presentation layer.

- Removed the `generate_board_docs` script.
- Updated the `gen_wu` script in order to generate `boards-info.json`: the fail that containe all information about the configuration
- Created and isolate the file `boards-info.js` to streamline the parsing of PlatformIO dependencies, modules, environments and improve the handling of library information.
- Introduced vuepress component `BoardEnvironmentTable.vue` that render `boards-info.json` as UI card component
- Introduced vuepress component `FlashEnvironmentSelector.vue` that render a selectred environment from  `boards-info.json` and provide esp-web-upload feature on it
- Introduced a new board page `board-selector.md` for improved firmware selection.
- Updated `web-install.md` to enhance the firmware upload process, including a new board environment table.
- Enhanced custom descriptions in `environments.ini` to include HTML links for better user guidance and board image link

Add CC1101 initialization improvements and logging enhancements
Add installation step for PlatformIO dependencies in documentation workflow

Remove ci_set_version.sh script and associated versioning functionality

* Fix comment provisined

Fix PlatformIO version input reference in documentation workflow

Remove outdated Squeezelite-ESP32 installer documentation
2026-03-09 07:47:30 -05:00

335 lines
11 KiB
C++

#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;
THEENGS_LOG_TRACE(F("RFConfiguration reInit: frequency=%F, activeReceiver=%d" CR), frequency, activeReceiver);
}
/**
* @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");
THEENGS_LOG_NOTICE(F("RF config erase result: %d" CR), result);
} else {
THEENGS_LOG_NOTICE(F("RF config not found" CR));
}
preferences.end();
#else
THEENGS_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();
THEENGS_LOG_NOTICE(F("RF Config_save: %s, result: %d" CR), conf.c_str(), result);
#else
THEENGS_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.
*
* @param reinitReceiver If true (default), disables and re-enables the receiver.
* If false, only loads the configuration without reinitialization.
*
* @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(bool reinitReceiver) {
#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>();
fromJson(jo);
THEENGS_LOG_NOTICE(F("RF Config loaded" CR));
} else {
preferences.end();
THEENGS_LOG_NOTICE(F("RF Config not found using default" CR));
}
#endif
// Disable and re-enable the receiver to ensure proper initialization
if (reinitReceiver) {
iRFReceiver.disable();
delay(100);
iRFReceiver.enable();
}
}
/**
* @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 from storage (without receiver reinitialization)
loadFromStorage(false);
}
fromJson(RFdata);
iRFReceiver.disable();
iRFReceiver.enable();
if (RFdata.containsKey("erase") && RFdata["erase"].as<bool>()) {
eraseStorage();
THEENGS_LOG_NOTICE(F("RF Config erased" CR));
} else if (RFdata.containsKey("save") && RFdata["save"].as<bool>()) {
saveOnStorage();
THEENGS_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);
THEENGS_LOG_NOTICE(F("RF Receive mhz: %F" CR), frequency);
success = true;
}
if (RFdata.containsKey("active")) {
Config_update(RFdata, "active", activeReceiver);
THEENGS_LOG_NOTICE(F("RF receiver active: %d" CR), activeReceiver);
success = true;
}
#ifdef ZgatewayRTL_433
if (RFdata.containsKey("rssithreshold")) {
THEENGS_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);
THEENGS_LOG_NOTICE(F("RTL_433 ookThreshold %d" CR), newOokThreshold);
rtl_433.setOOKThreshold(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
}
/**
* @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;
}
/**
* @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;
}