Add cloud bridge and provisioning support for ESP32 gateway

- Introduced DaliCloudBridge for MQTT communication with backend.
- Added GatewayProvisioningStore for persisting cloud connection settings using NVS.
- Updated CMakeLists.txt to include new source files.
- Enhanced README.md with usage examples and configuration details.
This commit is contained in:
Tony
2026-03-31 08:44:30 +08:00
parent 7e8ac7f566
commit a8a82f9627
8 changed files with 531 additions and 0 deletions
+127
View File
@@ -0,0 +1,127 @@
#include "gateway_provisioning.hpp"
#ifdef ESP_PLATFORM
extern "C" {
#include "esp_log.h"
#include "nvs.h"
#include "nvs_flash.h"
}
namespace {
constexpr const char* kTag = "gateway_provision";
constexpr const char* kKeyBrokerURI = "broker_uri";
constexpr const char* kKeyDeviceID = "device_id";
constexpr const char* kKeyUsername = "username";
constexpr const char* kKeyPassword = "password";
constexpr const char* kKeyTopicPrefix = "topic_prefix";
constexpr const char* kKeyQos = "qos";
esp_err_t writeString(nvs_handle_t handle, const char* key, const std::string& value) {
return nvs_set_str(handle, key, value.c_str());
}
esp_err_t readString(nvs_handle_t handle, const char* key, std::string* value) {
size_t required = 0;
esp_err_t err = nvs_get_str(handle, key, nullptr, &required);
if (err != ESP_OK) {
return err;
}
std::string buf(required, '\0');
err = nvs_get_str(handle, key, buf.data(), &required);
if (err != ESP_OK) {
return err;
}
if (!buf.empty() && buf.back() == '\0') {
buf.pop_back();
}
*value = buf;
return ESP_OK;
}
} // namespace
esp_err_t GatewayProvisioningStore::save(const GatewayCloudConfig& config) const {
nvs_handle_t handle;
esp_err_t err = nvs_open(nvsNamespace_.c_str(), NVS_READWRITE, &handle);
if (err != ESP_OK) {
ESP_LOGE(kTag, "nvs_open(save) failed: %s", esp_err_to_name(err));
return err;
}
err = writeString(handle, kKeyBrokerURI, config.brokerURI);
if (err == ESP_OK) err = writeString(handle, kKeyDeviceID, config.deviceID);
if (err == ESP_OK) err = writeString(handle, kKeyUsername, config.username);
if (err == ESP_OK) err = writeString(handle, kKeyPassword, config.password);
if (err == ESP_OK) err = writeString(handle, kKeyTopicPrefix, config.topicPrefix);
if (err == ESP_OK) err = nvs_set_i32(handle, kKeyQos, config.qos);
if (err == ESP_OK) err = nvs_commit(handle);
nvs_close(handle);
if (err != ESP_OK) {
ESP_LOGE(kTag, "save failed: %s", esp_err_to_name(err));
}
return err;
}
esp_err_t GatewayProvisioningStore::load(GatewayCloudConfig* config) const {
if (config == nullptr) {
return ESP_ERR_INVALID_ARG;
}
nvs_handle_t handle;
esp_err_t err = nvs_open(nvsNamespace_.c_str(), NVS_READONLY, &handle);
if (err != ESP_OK) {
return err;
}
err = readString(handle, kKeyBrokerURI, &config->brokerURI);
if (err == ESP_OK) err = readString(handle, kKeyDeviceID, &config->deviceID);
if (err == ESP_OK) err = readString(handle, kKeyUsername, &config->username);
if (err == ESP_OK) err = readString(handle, kKeyPassword, &config->password);
esp_err_t topicErr = readString(handle, kKeyTopicPrefix, &config->topicPrefix);
if (topicErr != ESP_OK) {
config->topicPrefix = "devices";
}
int32_t qos = 1;
esp_err_t qosErr = nvs_get_i32(handle, kKeyQos, &qos);
if (qosErr == ESP_OK) {
config->qos = qos;
} else {
config->qos = 1;
}
nvs_close(handle);
return err;
}
esp_err_t GatewayProvisioningStore::clear() const {
nvs_handle_t handle;
esp_err_t err = nvs_open(nvsNamespace_.c_str(), NVS_READWRITE, &handle);
if (err != ESP_OK) {
return err;
}
err = nvs_erase_all(handle);
if (err == ESP_OK) {
err = nvs_commit(handle);
}
nvs_close(handle);
return err;
}
#else
esp_err_t GatewayProvisioningStore::save(const GatewayCloudConfig& config) const {
(void)config;
return -1;
}
esp_err_t GatewayProvisioningStore::load(GatewayCloudConfig* config) const {
(void)config;
return -1;
}
esp_err_t GatewayProvisioningStore::clear() const { return -1; }
#endif