From 01cf28e8f0e5ca1349509e7af9b70332aa225774 Mon Sep 17 00:00:00 2001 From: CommanderRedYT Date: Tue, 31 May 2022 00:58:53 +0200 Subject: [PATCH] Implemented cloud nvs --- main/CMakeLists.txt | 1 + main/cloud.cpp | 201 ++++++++++++++++++++------------------------ main/newsettings.h | 9 ++ 3 files changed, 100 insertions(+), 111 deletions(-) diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt index c93f056..6c190d3 100644 --- a/main/CMakeLists.txt +++ b/main/CMakeLists.txt @@ -241,6 +241,7 @@ set(headers texthelpers/wifistatexthelpers.h time_bobbycar.h types.h + typeutils.h udpcloud.h unifiedmodelmode.h utils.h diff --git a/main/cloud.cpp b/main/cloud.cpp index 365f132..9010faa 100644 --- a/main/cloud.cpp +++ b/main/cloud.cpp @@ -20,6 +20,7 @@ #include "bobbyerrorhandler.h" #include "globals.h" #include "newsettings.h" +#include "typeutils.h" #include "utils.h" using namespace std::chrono_literals; @@ -30,15 +31,15 @@ espchrono::millis_clock::time_point lastCreateTry; espchrono::millis_clock::time_point lastStartTry; std::string cloudBuffer; +namespace { std::optional lastCloudCollect; std::optional lastCloudSend; std::optional lastHeartbeat; bool hasAnnouncedItself{}; -namespace { constexpr const char * const TAG = "BOBBYCLOUD"; -constexpr const auto json_document_size = 256; +constexpr const auto json_document_size = 1024; StaticJsonDocument doc; template @@ -66,149 +67,89 @@ typename std::enable_if< !std::is_same_v && !std::is_same_v && !std::is_same_v && - !std::is_same_v + !std::is_same_v && + !std::is_same_v , void>::type -toArduinoJson(std::string_view key, T value, StaticJsonDocument &doc) +toArduinoJson(std::string_view key, T value, JsonObject &object) { - doc[key.data()] = nullptr; + object["name"] = key; + object["value"] = nullptr; } template typename std::enable_if< - std::is_same_v - , void>::type -toArduinoJson(std::string_view key, T value, StaticJsonDocument &doc) -{ - doc[key.data()] = value; -} - -template -typename std::enable_if< - !std::is_same_v && + std::is_same_v || std::is_integral_v , void>::type -toArduinoJson(std::string_view key, T value, StaticJsonDocument &doc) +toArduinoJson(std::string_view key, T value, JsonObject &object) { - doc[key.data()] = value; + object["name"] = key; + object["value"] = value; } template typename std::enable_if< is_duration_v , void>::type -toArduinoJson(std::string_view key, T value, StaticJsonDocument &doc) +toArduinoJson(std::string_view key, T value, JsonObject &object) { - doc[key.data()] = value.count(); + object["name"] = key; + object["value"] = value.count(); } template typename std::enable_if< std::is_same_v , void>::type -toArduinoJson(std::string_view key, T value, StaticJsonDocument &doc) +toArduinoJson(std::string_view key, T value, JsonObject &object) { - doc[key.data()] = value.data(); + object["name"] = key; + object["value"] = value; } template typename std::enable_if< - std::is_same_v + std::is_same_v || + std::is_same_v || + std::is_same_v , void>::type -toArduinoJson(std::string_view key, T value, StaticJsonDocument &doc) +toArduinoJson(std::string_view key, T value, JsonObject &object) { - doc[key.data()] = wifi_stack::toString(value); -} - -template -typename std::enable_if< - std::is_same_v - , void>::type -toArduinoJson(std::string_view key, T value, StaticJsonDocument &doc) -{ - doc[key.data()] = wifi_stack::toString(value); + object["name"] = key; + object["value"] = wifi_stack::toString(value); } template typename std::enable_if< std::is_same_v> , void>::type -toArduinoJson(std::string_view key, T value, StaticJsonDocument &doc) +toArduinoJson(std::string_view key, T value, JsonObject &object) { - doc[key.data()] = value ? wifi_stack::toString(*value) : std::string{}; + object["name"] = key; + if (value) + object["value"] = wifi_stack::toString(*value); + else + object["value"] = nullptr; } template typename std::enable_if< - std::is_same_v + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v , void>::type -toArduinoJson(std::string_view key, T value, StaticJsonDocument &doc) +toArduinoJson(std::string_view key, T value, JsonObject &object) { - doc[key.data()] = wifi_stack::toString(value); -} - -template -typename std::enable_if< - std::is_same_v - , void>::type -toArduinoJson(std::string_view key, T value, StaticJsonDocument &doc) -{ - doc[key.data()] = std::to_underlying(value); -} - -template -typename std::enable_if< - std::is_same_v - , void>::type -toArduinoJson(std::string_view key, T value, StaticJsonDocument &doc) -{ - doc[key.data()] = std::to_underlying(value); -} - -template -typename std::enable_if< - std::is_same_v - , void>::type -toArduinoJson(std::string_view key, T value, StaticJsonDocument &doc) -{ - doc[key.data()] = std::to_underlying(value); -} - -template -typename std::enable_if< - std::is_same_v - , void>::type -toArduinoJson(std::string_view key, T value, StaticJsonDocument &doc) -{ - doc[key.data()] = std::to_underlying(value); -} - -template -typename std::enable_if< - std::is_same_v - , void>::type -toArduinoJson(std::string_view key, T value, StaticJsonDocument &doc) -{ - doc[key.data()] = std::to_underlying(value); -} - -template -typename std::enable_if< - std::is_same_v - , void>::type -toArduinoJson(std::string_view key, T value, StaticJsonDocument &doc) -{ - doc[key.data()] = std::to_underlying(value); -} - -template -typename std::enable_if< - std::is_same_v - , void>::type -toArduinoJson(std::string_view key, T value, StaticJsonDocument &doc) -{ - doc[key.data()] = std::to_underlying(value); + object["name"] = key; + object["value"] = std::to_underlying(value); } +// setter template typename std::enable_if< @@ -225,7 +166,8 @@ typename std::enable_if< !std::is_same_v && !std::is_same_v && !std::is_same_v && - !std::is_same_v + !std::is_same_v && + !std::is_same_v , tl::expected>::type set_config(ConfigWrapper &config, std::string_view newValue) { @@ -313,7 +255,8 @@ typename std::enable_if< std::is_same_v || std::is_same_v || std::is_same_v || - std::is_same_v + std::is_same_v || + std::is_same_v , tl::expected>::type set_config(ConfigWrapper &config, std::string_view newValue) { @@ -325,13 +268,27 @@ set_config(ConfigWrapper &config, std::string_view newValue) void send_config(uint32_t skipCount) { - doc.clear(); - doc["type"] = "config"; - if (!cloudClient.is_connected()) return; + doc.clear(); + + { + const std::string body = fmt::format(R"({{"type":"configCount","count":{}}})", configs.getConfigCount()); + const auto timeout = std::chrono::ceil( + espchrono::milliseconds32{configs.cloudSettings.cloudTransmitTimeout.value()}).count(); + const auto result_size = cloudClient.send_text(body, timeout); + if (result_size != body.size()) { + ESP_LOGE(TAG, "send_text failed: %d", result_size); + } + } + + doc["type"] = "config"; + JsonArray configsArray = doc.createNestedArray("configs"); bool stop{false}; + bool has_overflowed{false}; + + size_t i{0}; configs.callForEveryConfig([&](auto &config) { if (skipCount > 0) @@ -344,24 +301,43 @@ void send_config(uint32_t skipCount) return; const std::string_view nvsName{config.nvsName()}; - toArduinoJson(nvsName, config.value(), doc); + + i++; + + JsonObject configObject = configsArray.createNestedObject(); + toArduinoJson(nvsName, config.value(), configObject); + configObject["type"] = typeutils::t_to_str::str; + if (doc.overflowed()) { + has_overflowed = true; // send data, clear doc and try again std::string body; - doc.remove(nvsName); + configsArray.remove(i-1); serializeJson(doc, body); - ESP_LOGI(TAG, "body_size: %d, heap free: %d, stack free: %d", body.size(), esp_get_free_heap_size(), uxTaskGetStackHighWaterMark(nullptr)); const auto timeout = std::chrono::ceil(espchrono::milliseconds32{configs.cloudSettings.cloudTransmitTimeout.value()}).count(); const auto result_size = cloudClient.send_text(body, timeout); if (result_size != body.size()) { ESP_LOGE(TAG, "send_text failed: %d", result_size); } - doc["type"] = "config"; stop = true; } }); + + if (!has_overflowed) + { + std::string body; + doc["last"] = true; + doc["type"] = "lastConfig"; + serializeJson(doc, body); + const auto timeout = std::chrono::ceil(espchrono::milliseconds32{configs.cloudSettings.cloudTransmitTimeout.value()}).count(); + const auto result_size = cloudClient.send_text(body, timeout); + if (result_size != body.size()) + { + ESP_LOGE(TAG, "send_text failed: %d", result_size); + } + } } void send_single_config(const std::string &nvsName) @@ -370,11 +346,14 @@ void send_single_config(const std::string &nvsName) return; doc.clear(); doc["type"] = "singleConfig"; + bool success{false}; configs.callForEveryConfig([&](auto &config) { if (config.nvsName() == nvsName) { - toArduinoJson(nvsName, config.value(), doc); + JsonObject configObject = doc.createNestedObject("config"); + toArduinoJson(nvsName, config.value(), configObject); + configObject["type"] = typeutils::t_to_str::str; success = true; } }); diff --git a/main/newsettings.h b/main/newsettings.h index 21cf7b2..cb4be61 100644 --- a/main/newsettings.h +++ b/main/newsettings.h @@ -852,6 +852,15 @@ public: std::ref(feature.webserver_disable_lock) ); } + + constexpr size_t getConfigCount() const + { + size_t count = 0; +#define HELPER(x) count++; + NEW_SETTINGS(HELPER) +#undef HELPER + return count; + } }; extern ConfigManager configs;