Enhance DaliCloudBridge: add support for LTE UART transport and extend configuration options

Signed-off-by: Tony <tonylu@tony-cloud.com>
This commit is contained in:
Tony
2026-05-27 15:20:16 +08:00
parent 2d100ec7ed
commit f18f7570ed
4 changed files with 420 additions and 13 deletions
+1 -1
View File
@@ -19,7 +19,7 @@ idf_component_register(
"src/gateway_cloud.cpp" "src/gateway_cloud.cpp"
"src/gateway_provisioning.cpp" "src/gateway_provisioning.cpp"
INCLUDE_DIRS "include" INCLUDE_DIRS "include"
REQUIRES mqtt cjson nvs_flash REQUIRES mqtt cjson nvs_flash esp_driver_uart
) )
set_property(TARGET ${COMPONENT_LIB} PROPERTY CXX_STANDARD 17) set_property(TARGET ${COMPONENT_LIB} PROPERTY CXX_STANDARD 17)
+32
View File
@@ -4,10 +4,14 @@
#include "dali_comm.hpp" #include "dali_comm.hpp"
#include <atomic> #include <atomic>
#include <functional>
#include <string> #include <string>
#include <vector>
#ifdef ESP_PLATFORM #ifdef ESP_PLATFORM
#include "esp_event_base.h" #include "esp_event_base.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "mqtt_client.h" #include "mqtt_client.h"
#endif #endif
@@ -17,22 +21,35 @@ struct GatewayCloudConfig {
std::string username = "device"; std::string username = "device";
std::string password; std::string password;
std::string topicPrefix = "devices"; std::string topicPrefix = "devices";
std::string cemiTransport = "mqtt";
bool lteUartEnabled = false;
int lteUartPort = -1;
int lteTxPin = -1;
int lteRxPin = -1;
int lteBaudrate = 115200;
int lteRxBufferSize = 2048;
int lteTxBufferSize = 2048;
int qos = 1; int qos = 1;
}; };
// DaliCloudBridge bridges MQTT cloud topics and local DALI frames. // DaliCloudBridge bridges MQTT cloud topics and local DALI frames.
class DaliCloudBridge { class DaliCloudBridge {
public: public:
using CemiDownlinkHandler = std::function<bool(const uint8_t* data, size_t len)>;
explicit DaliCloudBridge(DaliComm& comm); explicit DaliCloudBridge(DaliComm& comm);
bool start(const GatewayCloudConfig& config); bool start(const GatewayCloudConfig& config);
void stop(); void stop();
bool isConnected() const; bool isConnected() const;
bool lteUartActive() const;
DaliBridgeEngine& bridge() { return bridge_; } DaliBridgeEngine& bridge() { return bridge_; }
const DaliBridgeEngine& bridge() const { return bridge_; } const DaliBridgeEngine& bridge() const { return bridge_; }
void setCemiDownlinkHandler(CemiDownlinkHandler handler);
bool publishStatus(const std::string& status); bool publishStatus(const std::string& status);
bool publishRegister(const std::string& payloadJson); bool publishRegister(const std::string& payloadJson);
bool publishCemiFrame(const uint8_t* data, size_t len);
private: private:
#ifdef ESP_PLATFORM #ifdef ESP_PLATFORM
@@ -44,19 +61,34 @@ class DaliCloudBridge {
#endif #endif
bool handleDownlink(const std::string& payload); bool handleDownlink(const std::string& payload);
bool handleCemiDownlink(const uint8_t* payload, size_t len);
bool publishJSON(const std::string& topic, const std::string& payloadJson); bool publishJSON(const std::string& topic, const std::string& payloadJson);
bool publishBytes(const std::string& topic, const uint8_t* data, size_t len, int qos);
bool startLteUart();
void stopLteUart();
bool publishLteUartBytes(const uint8_t* data, size_t len);
void lteUartLoop();
std::string topicDown() const; std::string topicDown() const;
std::string topicUp() const; std::string topicUp() const;
std::string topicStatus() const; std::string topicStatus() const;
std::string topicRegister() const; std::string topicRegister() const;
std::string topicCemiDown() const;
std::string topicCemiUp() const;
std::string topicCemiStatus() const;
DaliComm& comm_; DaliComm& comm_;
DaliBridgeEngine bridge_; DaliBridgeEngine bridge_;
GatewayCloudConfig config_; GatewayCloudConfig config_;
CemiDownlinkHandler cemi_downlink_handler_;
std::atomic<bool> connected_{false}; std::atomic<bool> connected_{false};
std::atomic<bool> lte_uart_started_{false};
std::atomic<bool> lte_uart_stop_requested_{false};
std::atomic<uint32_t> cemi_sequence_{0};
#ifdef ESP_PLATFORM #ifdef ESP_PLATFORM
static void lteUartTaskEntry(void* arg);
esp_mqtt_client_handle_t client_ = nullptr; esp_mqtt_client_handle_t client_ = nullptr;
TaskHandle_t lte_uart_task_ = nullptr;
#endif #endif
}; };
+342 -12
View File
@@ -1,16 +1,26 @@
#include "gateway_cloud.hpp" #include "gateway_cloud.hpp"
#include <algorithm>
#include <array>
#include <cctype>
#include <cstring> #include <cstring>
#include <sstream> #include <sstream>
#include <vector>
#ifdef ESP_PLATFORM #ifdef ESP_PLATFORM
extern "C" { extern "C" {
#include "cJSON.h" #include "cJSON.h"
#include "driver/uart.h"
#include "esp_log.h" #include "esp_log.h"
} }
namespace { namespace {
constexpr const char* kTag = "dali_cloud_bridge"; constexpr const char* kTag = "dali_cloud_bridge";
constexpr std::array<uint8_t, 4> kCemiEnvelopeMagic{'D', 'K', 'C', '1'};
constexpr uint8_t kCemiDirectionDown = 1;
constexpr uint8_t kCemiDirectionUp = 2;
constexpr size_t kCemiEnvelopeHeaderSize = 14;
constexpr size_t kMaxCemiEnvelopeSize = kCemiEnvelopeHeaderSize + 255 + 4096;
std::string jsonEscape(const std::string& value) { std::string jsonEscape(const std::string& value) {
std::string out; std::string out;
@@ -143,20 +153,139 @@ bool isKnownBridgeRequestKey(const char* key) {
return false; return false;
} }
std::string lowerCopy(const std::string& value) {
std::string out(value);
std::transform(out.begin(), out.end(), out.begin(), [](unsigned char ch) {
return static_cast<char>(std::tolower(ch));
});
return out;
}
bool cemiUsesMqtt(const GatewayCloudConfig& config) {
const std::string mode = lowerCopy(config.cemiTransport);
return mode.empty() || mode == "mqtt" || mode == "hybrid" ||
mode == "mqtt_lte_uart" || mode == "both";
}
bool cemiUsesLteUart(const GatewayCloudConfig& config) {
if (config.lteUartEnabled) {
return true;
}
const std::string mode = lowerCopy(config.cemiTransport);
return mode == "lte_uart" || mode == "serial_lte" || mode == "uart" ||
mode == "hybrid" || mode == "mqtt_lte_uart" || mode == "both";
}
void writeBe16(uint8_t* data, uint16_t value) {
data[0] = static_cast<uint8_t>((value >> 8) & 0xff);
data[1] = static_cast<uint8_t>(value & 0xff);
}
void writeBe32(uint8_t* data, uint32_t value) {
data[0] = static_cast<uint8_t>((value >> 24) & 0xff);
data[1] = static_cast<uint8_t>((value >> 16) & 0xff);
data[2] = static_cast<uint8_t>((value >> 8) & 0xff);
data[3] = static_cast<uint8_t>(value & 0xff);
}
uint16_t readBe16(const uint8_t* data) {
return static_cast<uint16_t>((static_cast<uint16_t>(data[0]) << 8) | data[1]);
}
void consumeCemiSerialBuffer(std::vector<uint8_t>* buffer,
const std::function<bool(const uint8_t*, size_t)>& handler) {
if (buffer == nullptr) {
return;
}
while (buffer->size() >= kCemiEnvelopeHeaderSize) {
auto magic = std::search(buffer->begin(), buffer->end(), kCemiEnvelopeMagic.begin(),
kCemiEnvelopeMagic.end());
if (magic == buffer->end()) {
buffer->clear();
return;
}
if (magic != buffer->begin()) {
buffer->erase(buffer->begin(), magic);
}
if (buffer->size() < kCemiEnvelopeHeaderSize) {
return;
}
const size_t session_len = (*buffer)[10];
const size_t cemi_len = readBe16(buffer->data() + 11);
const size_t frame_len = kCemiEnvelopeHeaderSize + session_len + cemi_len;
if (frame_len > kMaxCemiEnvelopeSize || cemi_len == 0) {
buffer->erase(buffer->begin());
continue;
}
if (buffer->size() < frame_len) {
return;
}
handler(buffer->data(), frame_len);
buffer->erase(buffer->begin(), buffer->begin() + static_cast<std::ptrdiff_t>(frame_len));
}
if (buffer->size() > kMaxCemiEnvelopeSize) {
buffer->erase(buffer->begin(), buffer->end() - static_cast<std::ptrdiff_t>(kCemiEnvelopeHeaderSize));
}
}
std::vector<uint8_t> buildCemiEnvelope(uint8_t direction, uint32_t sequence,
const uint8_t* data, size_t len) {
if (data == nullptr || len == 0 || len > 4096) {
return {};
}
std::vector<uint8_t> out(kCemiEnvelopeHeaderSize + len);
std::copy(kCemiEnvelopeMagic.begin(), kCemiEnvelopeMagic.end(), out.begin());
out[4] = direction;
out[5] = 0;
writeBe32(&out[6], sequence);
out[10] = 0;
writeBe16(&out[11], static_cast<uint16_t>(len));
out[13] = 0;
std::memcpy(out.data() + kCemiEnvelopeHeaderSize, data, len);
return out;
}
std::vector<uint8_t> decodeCemiEnvelope(const uint8_t* payload, size_t len) {
if (payload == nullptr || len < kCemiEnvelopeHeaderSize ||
std::memcmp(payload, kCemiEnvelopeMagic.data(), kCemiEnvelopeMagic.size()) != 0 ||
payload[4] != kCemiDirectionDown) {
return {};
}
const size_t session_len = payload[10];
const size_t cemi_len = readBe16(&payload[11]);
if (len != kCemiEnvelopeHeaderSize + session_len + cemi_len || cemi_len == 0) {
return {};
}
const uint8_t* cemi = payload + kCemiEnvelopeHeaderSize + session_len;
return std::vector<uint8_t>(cemi, cemi + cemi_len);
}
} // namespace } // namespace
#endif #endif
DaliCloudBridge::DaliCloudBridge(DaliComm& comm) : comm_(comm), bridge_(comm) {} DaliCloudBridge::DaliCloudBridge(DaliComm& comm) : comm_(comm), bridge_(comm) {}
bool DaliCloudBridge::start(const GatewayCloudConfig& config) { bool DaliCloudBridge::start(const GatewayCloudConfig& config) {
#ifdef ESP_PLATFORM
stop();
#endif
config_ = config; config_ = config;
if (config_.brokerURI.empty() || config_.deviceID.empty()) { const bool mqtt_requested = cemiUsesMqtt(config_) && !config_.brokerURI.empty() &&
!config_.deviceID.empty();
const bool lte_uart_requested = cemiUsesLteUart(config_);
if (!mqtt_requested && !lte_uart_requested) {
return false; return false;
} }
#ifdef ESP_PLATFORM #ifdef ESP_PLATFORM
if (client_ != nullptr) { bool started = false;
stop(); if (lte_uart_requested) {
started = startLteUart() || started;
}
if (!mqtt_requested) {
connected_.store(started);
return started;
} }
esp_mqtt_client_config_t mqttCfg = {}; esp_mqtt_client_config_t mqttCfg = {};
@@ -168,7 +297,7 @@ bool DaliCloudBridge::start(const GatewayCloudConfig& config) {
client_ = esp_mqtt_client_init(&mqttCfg); client_ = esp_mqtt_client_init(&mqttCfg);
if (client_ == nullptr) { if (client_ == nullptr) {
ESP_LOGE(kTag, "esp_mqtt_client_init failed"); ESP_LOGE(kTag, "esp_mqtt_client_init failed");
return false; return started;
} }
esp_mqtt_client_register_event(client_, MQTT_EVENT_ANY, &DaliCloudBridge::mqttEventHandler, esp_mqtt_client_register_event(client_, MQTT_EVENT_ANY, &DaliCloudBridge::mqttEventHandler,
@@ -177,17 +306,20 @@ bool DaliCloudBridge::start(const GatewayCloudConfig& config) {
ESP_LOGE(kTag, "esp_mqtt_client_start failed"); ESP_LOGE(kTag, "esp_mqtt_client_start failed");
esp_mqtt_client_destroy(client_); esp_mqtt_client_destroy(client_);
client_ = nullptr; client_ = nullptr;
return false; return started;
} }
return true; return true;
#else #else
(void)config; (void)config;
(void)mqtt_requested;
(void)lte_uart_requested;
return false; return false;
#endif #endif
} }
void DaliCloudBridge::stop() { void DaliCloudBridge::stop() {
#ifdef ESP_PLATFORM #ifdef ESP_PLATFORM
stopLteUart();
connected_.store(false); connected_.store(false);
if (client_ != nullptr) { if (client_ != nullptr) {
esp_mqtt_client_stop(client_); esp_mqtt_client_stop(client_);
@@ -197,7 +329,15 @@ void DaliCloudBridge::stop() {
#endif #endif
} }
bool DaliCloudBridge::isConnected() const { return connected_.load(); } bool DaliCloudBridge::isConnected() const {
return connected_.load() || lte_uart_started_.load();
}
bool DaliCloudBridge::lteUartActive() const { return lte_uart_started_.load(); }
void DaliCloudBridge::setCemiDownlinkHandler(CemiDownlinkHandler handler) {
cemi_downlink_handler_ = std::move(handler);
}
bool DaliCloudBridge::publishStatus(const std::string& status) { bool DaliCloudBridge::publishStatus(const std::string& status) {
std::string payload = "{\"type\":\"status\",\"status\":\"" + status + "\"}"; std::string payload = "{\"type\":\"status\",\"status\":\"" + status + "\"}";
@@ -208,6 +348,148 @@ bool DaliCloudBridge::publishRegister(const std::string& payloadJson) {
return publishJSON(topicRegister(), payloadJson); return publishJSON(topicRegister(), payloadJson);
} }
bool DaliCloudBridge::publishCemiFrame(const uint8_t* data, size_t len) {
#ifdef ESP_PLATFORM
const uint32_t sequence = cemi_sequence_.fetch_add(1, std::memory_order_relaxed);
const auto envelope = buildCemiEnvelope(kCemiDirectionUp, sequence, data, len);
if (envelope.empty()) {
return false;
}
bool delivered = false;
if (cemiUsesLteUart(config_)) {
delivered = publishLteUartBytes(envelope.data(), envelope.size()) || delivered;
}
if (cemiUsesMqtt(config_) && client_ != nullptr) {
delivered = publishBytes(topicCemiUp(), envelope.data(), envelope.size(), 0) || delivered;
}
return delivered;
#else
(void)data;
(void)len;
return false;
#endif
}
bool DaliCloudBridge::startLteUart() {
#ifdef ESP_PLATFORM
const int port = config_.lteUartPort;
if (port < 0 || port > 2 || config_.lteBaudrate <= 0) {
ESP_LOGW(kTag, "LTE UART cEMI transport disabled by invalid port=%d baud=%d",
port, config_.lteBaudrate);
return false;
}
uart_config_t uart_config = {};
uart_config.baud_rate = config_.lteBaudrate;
uart_config.data_bits = UART_DATA_8_BITS;
uart_config.parity = UART_PARITY_DISABLE;
uart_config.stop_bits = UART_STOP_BITS_1;
uart_config.flow_ctrl = UART_HW_FLOWCTRL_DISABLE;
uart_config.source_clk = UART_SCLK_DEFAULT;
const uart_port_t uart_port = static_cast<uart_port_t>(port);
esp_err_t err = uart_param_config(uart_port, &uart_config);
if (err != ESP_OK) {
ESP_LOGE(kTag, "uart_param_config failed: %s", esp_err_to_name(err));
return false;
}
err = uart_set_pin(uart_port,
config_.lteTxPin < 0 ? UART_PIN_NO_CHANGE : config_.lteTxPin,
config_.lteRxPin < 0 ? UART_PIN_NO_CHANGE : config_.lteRxPin,
UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
if (err != ESP_OK) {
ESP_LOGE(kTag, "uart_set_pin failed: %s", esp_err_to_name(err));
return false;
}
const int rx_buffer = std::max(config_.lteRxBufferSize, 512);
const int tx_buffer = std::max(config_.lteTxBufferSize, 512);
err = uart_driver_install(uart_port, rx_buffer, tx_buffer, 0, nullptr, 0);
if (err != ESP_OK && err != ESP_ERR_INVALID_STATE) {
ESP_LOGE(kTag, "uart_driver_install failed: %s", esp_err_to_name(err));
return false;
}
lte_uart_stop_requested_.store(false);
lte_uart_started_.store(true);
if (xTaskCreate(&DaliCloudBridge::lteUartTaskEntry, "cloud_lte_cemi", 4096,
this, 5, &lte_uart_task_) != pdPASS) {
lte_uart_started_.store(false);
uart_driver_delete(uart_port);
lte_uart_task_ = nullptr;
ESP_LOGE(kTag, "failed to create LTE UART cEMI task");
return false;
}
ESP_LOGI(kTag, "LTE UART cEMI transport started on UART%d", port);
return true;
#else
return false;
#endif
}
void DaliCloudBridge::stopLteUart() {
#ifdef ESP_PLATFORM
if (!lte_uart_started_.load()) {
return;
}
lte_uart_stop_requested_.store(true);
for (int i = 0; i < 20 && lte_uart_task_ != nullptr; ++i) {
vTaskDelay(pdMS_TO_TICKS(10));
}
const int port = config_.lteUartPort;
if (port >= 0 && port <= 2) {
uart_driver_delete(static_cast<uart_port_t>(port));
}
lte_uart_started_.store(false);
#endif
}
bool DaliCloudBridge::publishLteUartBytes(const uint8_t* data, size_t len) {
#ifdef ESP_PLATFORM
if (!lte_uart_started_.load() || data == nullptr || len == 0 ||
config_.lteUartPort < 0 || config_.lteUartPort > 2) {
return false;
}
const int written = uart_write_bytes(static_cast<uart_port_t>(config_.lteUartPort),
reinterpret_cast<const char*>(data), len);
return written == static_cast<int>(len);
#else
(void)data;
(void)len;
return false;
#endif
}
#ifdef ESP_PLATFORM
void DaliCloudBridge::lteUartTaskEntry(void* arg) {
auto* self = static_cast<DaliCloudBridge*>(arg);
if (self != nullptr) {
self->lteUartLoop();
}
vTaskDelete(nullptr);
}
void DaliCloudBridge::lteUartLoop() {
std::vector<uint8_t> buffer;
buffer.reserve(kMaxCemiEnvelopeSize);
std::array<uint8_t, 128> chunk{};
const uart_port_t port = static_cast<uart_port_t>(config_.lteUartPort);
while (!lte_uart_stop_requested_.load()) {
const int read = uart_read_bytes(port, chunk.data(), chunk.size(), pdMS_TO_TICKS(100));
if (read <= 0) {
continue;
}
buffer.insert(buffer.end(), chunk.begin(), chunk.begin() + read);
consumeCemiSerialBuffer(&buffer, [this](const uint8_t* payload, size_t len) {
return handleCemiDownlink(payload, len);
});
}
lte_uart_task_ = nullptr;
}
#else
void DaliCloudBridge::lteUartLoop() {}
#endif
#ifdef ESP_PLATFORM #ifdef ESP_PLATFORM
std::string buildRegisterPayload(const GatewayCloudConfig& config) { std::string buildRegisterPayload(const GatewayCloudConfig& config) {
const std::string deviceID = jsonEscape(config.deviceID); const std::string deviceID = jsonEscape(config.deviceID);
@@ -226,12 +508,8 @@ std::string buildRegisterPayload(const GatewayCloudConfig& config) {
bool DaliCloudBridge::publishJSON(const std::string& topic, const std::string& payloadJson) { bool DaliCloudBridge::publishJSON(const std::string& topic, const std::string& payloadJson) {
#ifdef ESP_PLATFORM #ifdef ESP_PLATFORM
if (client_ == nullptr || !connected_.load()) { return publishBytes(topic, reinterpret_cast<const uint8_t*>(payloadJson.data()),
return false; payloadJson.size(), config_.qos);
}
int msgID = esp_mqtt_client_publish(client_, topic.c_str(), payloadJson.c_str(),
static_cast<int>(payloadJson.size()), config_.qos, 0);
return msgID >= 0;
#else #else
(void)topic; (void)topic;
(void)payloadJson; (void)payloadJson;
@@ -239,6 +517,25 @@ bool DaliCloudBridge::publishJSON(const std::string& topic, const std::string& p
#endif #endif
} }
bool DaliCloudBridge::publishBytes(const std::string& topic, const uint8_t* data,
size_t len, int qos) {
#ifdef ESP_PLATFORM
if (client_ == nullptr || !connected_.load() || data == nullptr) {
return false;
}
int msgID = esp_mqtt_client_publish(client_, topic.c_str(),
reinterpret_cast<const char*>(data),
static_cast<int>(len), qos, 0);
return msgID >= 0;
#else
(void)topic;
(void)data;
(void)len;
(void)qos;
return false;
#endif
}
std::string DaliCloudBridge::topicDown() const { std::string DaliCloudBridge::topicDown() const {
return config_.topicPrefix + "/" + config_.deviceID + "/down"; return config_.topicPrefix + "/" + config_.deviceID + "/down";
} }
@@ -255,6 +552,18 @@ std::string DaliCloudBridge::topicRegister() const {
return config_.topicPrefix + "/" + config_.deviceID + "/register"; return config_.topicPrefix + "/" + config_.deviceID + "/register";
} }
std::string DaliCloudBridge::topicCemiDown() const {
return config_.topicPrefix + "/" + config_.deviceID + "/cemi/down";
}
std::string DaliCloudBridge::topicCemiUp() const {
return config_.topicPrefix + "/" + config_.deviceID + "/cemi/up";
}
std::string DaliCloudBridge::topicCemiStatus() const {
return config_.topicPrefix + "/" + config_.deviceID + "/cemi/status";
}
bool DaliCloudBridge::handleDownlink(const std::string& payload) { bool DaliCloudBridge::handleDownlink(const std::string& payload) {
#ifdef ESP_PLATFORM #ifdef ESP_PLATFORM
cJSON* root = cJSON_Parse(payload.c_str()); cJSON* root = cJSON_Parse(payload.c_str());
@@ -341,6 +650,24 @@ bool DaliCloudBridge::handleDownlink(const std::string& payload) {
#endif #endif
} }
bool DaliCloudBridge::handleCemiDownlink(const uint8_t* payload, size_t len) {
#ifdef ESP_PLATFORM
if (!cemi_downlink_handler_) {
return false;
}
const auto cemi = decodeCemiEnvelope(payload, len);
if (cemi.empty()) {
ESP_LOGW(kTag, "invalid cEMI cloud payload len=%u", static_cast<unsigned>(len));
return false;
}
return cemi_downlink_handler_(cemi.data(), cemi.size());
#else
(void)payload;
(void)len;
return false;
#endif
}
#ifdef ESP_PLATFORM #ifdef ESP_PLATFORM
void DaliCloudBridge::mqttEventHandler(void* handler_args, void DaliCloudBridge::mqttEventHandler(void* handler_args,
esp_event_base_t base, esp_event_base_t base,
@@ -361,6 +688,7 @@ void DaliCloudBridge::onMqttEvent(esp_mqtt_event_handle_t event) {
connected_.store(true); connected_.store(true);
ESP_LOGI(kTag, "MQTT connected"); ESP_LOGI(kTag, "MQTT connected");
esp_mqtt_client_subscribe(client_, topicDown().c_str(), config_.qos); esp_mqtt_client_subscribe(client_, topicDown().c_str(), config_.qos);
esp_mqtt_client_subscribe(client_, topicCemiDown().c_str(), 0);
publishStatus("online"); publishStatus("online");
publishRegister(buildRegisterPayload(config_)); publishRegister(buildRegisterPayload(config_));
break; break;
@@ -374,6 +702,8 @@ void DaliCloudBridge::onMqttEvent(esp_mqtt_event_handle_t event) {
std::string data(event->data, event->data_len); std::string data(event->data, event->data_len);
if (topic == topicDown()) { if (topic == topicDown()) {
handleDownlink(data); handleDownlink(data);
} else if (topic == topicCemiDown()) {
handleCemiDownlink(reinterpret_cast<const uint8_t*>(data.data()), data.size());
} }
break; break;
} }
+45
View File
@@ -14,6 +14,14 @@ constexpr const char* kKeyDeviceID = "device_id";
constexpr const char* kKeyUsername = "username"; constexpr const char* kKeyUsername = "username";
constexpr const char* kKeyPassword = "password"; constexpr const char* kKeyPassword = "password";
constexpr const char* kKeyTopicPrefix = "topic_prefix"; constexpr const char* kKeyTopicPrefix = "topic_prefix";
constexpr const char* kKeyCemiTransport = "cemi_transport";
constexpr const char* kKeyLteUartEnabled = "lte_uart_en";
constexpr const char* kKeyLteUartPort = "lte_uart_port";
constexpr const char* kKeyLteTxPin = "lte_tx_pin";
constexpr const char* kKeyLteRxPin = "lte_rx_pin";
constexpr const char* kKeyLteBaudrate = "lte_baudrate";
constexpr const char* kKeyLteRxBuffer = "lte_rx_buf";
constexpr const char* kKeyLteTxBuffer = "lte_tx_buf";
constexpr const char* kKeyQos = "qos"; constexpr const char* kKeyQos = "qos";
esp_err_t writeString(nvs_handle_t handle, const char* key, const std::string& value) { esp_err_t writeString(nvs_handle_t handle, const char* key, const std::string& value) {
@@ -52,6 +60,15 @@ esp_err_t GatewayProvisioningStore::save(const GatewayCloudConfig& config) const
if (err == ESP_OK) err = writeString(handle, kKeyUsername, config.username); 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, kKeyPassword, config.password);
if (err == ESP_OK) err = writeString(handle, kKeyTopicPrefix, config.topicPrefix); if (err == ESP_OK) err = writeString(handle, kKeyTopicPrefix, config.topicPrefix);
if (err == ESP_OK) err = writeString(handle, kKeyCemiTransport, config.cemiTransport);
if (err == ESP_OK) err = nvs_set_i32(handle, kKeyLteUartEnabled,
config.lteUartEnabled ? 1 : 0);
if (err == ESP_OK) err = nvs_set_i32(handle, kKeyLteUartPort, config.lteUartPort);
if (err == ESP_OK) err = nvs_set_i32(handle, kKeyLteTxPin, config.lteTxPin);
if (err == ESP_OK) err = nvs_set_i32(handle, kKeyLteRxPin, config.lteRxPin);
if (err == ESP_OK) err = nvs_set_i32(handle, kKeyLteBaudrate, config.lteBaudrate);
if (err == ESP_OK) err = nvs_set_i32(handle, kKeyLteRxBuffer, config.lteRxBufferSize);
if (err == ESP_OK) err = nvs_set_i32(handle, kKeyLteTxBuffer, config.lteTxBufferSize);
if (err == ESP_OK) err = nvs_set_i32(handle, kKeyQos, config.qos); if (err == ESP_OK) err = nvs_set_i32(handle, kKeyQos, config.qos);
if (err == ESP_OK) err = nvs_commit(handle); if (err == ESP_OK) err = nvs_commit(handle);
@@ -83,6 +100,34 @@ esp_err_t GatewayProvisioningStore::load(GatewayCloudConfig* config) const {
config->topicPrefix = "devices"; config->topicPrefix = "devices";
} }
esp_err_t transportErr = readString(handle, kKeyCemiTransport, &config->cemiTransport);
if (transportErr != ESP_OK) {
config->cemiTransport = "mqtt";
}
int32_t intValue = 0;
if (nvs_get_i32(handle, kKeyLteUartEnabled, &intValue) == ESP_OK) {
config->lteUartEnabled = intValue != 0;
}
if (nvs_get_i32(handle, kKeyLteUartPort, &intValue) == ESP_OK) {
config->lteUartPort = intValue;
}
if (nvs_get_i32(handle, kKeyLteTxPin, &intValue) == ESP_OK) {
config->lteTxPin = intValue;
}
if (nvs_get_i32(handle, kKeyLteRxPin, &intValue) == ESP_OK) {
config->lteRxPin = intValue;
}
if (nvs_get_i32(handle, kKeyLteBaudrate, &intValue) == ESP_OK) {
config->lteBaudrate = intValue;
}
if (nvs_get_i32(handle, kKeyLteRxBuffer, &intValue) == ESP_OK) {
config->lteRxBufferSize = intValue;
}
if (nvs_get_i32(handle, kKeyLteTxBuffer, &intValue) == ESP_OK) {
config->lteTxBufferSize = intValue;
}
int32_t qos = 1; int32_t qos = 1;
esp_err_t qosErr = nvs_get_i32(handle, kKeyQos, &qos); esp_err_t qosErr = nvs_get_i32(handle, kKeyQos, &qos);
if (qosErr == ESP_OK) { if (qosErr == ESP_OK) {