diff --git a/esphome/components/json/__init__.py b/esphome/components/json/__init__.py index 6a0e4c50d2..399cf708f6 100644 --- a/esphome/components/json/__init__.py +++ b/esphome/components/json/__init__.py @@ -12,6 +12,6 @@ CONFIG_SCHEMA = cv.All( @coroutine_with_priority(1.0) async def to_code(config): - cg.add_library("bblanchon/ArduinoJson", "6.18.5") + cg.add_library("bblanchon/ArduinoJson", "7.4.1") cg.add_define("USE_JSON") cg.add_global(json_ns.using) diff --git a/esphome/components/json/json_util.cpp b/esphome/components/json/json_util.cpp index 6c66476dc1..f5b662d543 100644 --- a/esphome/components/json/json_util.cpp +++ b/esphome/components/json/json_util.cpp @@ -6,30 +6,39 @@ namespace json { static const char *const TAG = "json"; -static std::vector global_json_build_buffer; // NOLINT -static const auto ALLOCATOR = RAMAllocator(RAMAllocator::ALLOC_INTERNAL); +static auto ALLOCATOR = RAMAllocator( + RAMAllocator::NONE); // Attempt to allocate in PSRAM before falling back into internal + +// Build an allocator for the JSON Library using the RAMAllocator class +struct SpiRamAllocator : ArduinoJson::Allocator { + void *allocate(size_t size) { return ALLOCATOR.allocate(size); } + + void deallocate(void *pointer) { + free(pointer); // NOLINT(cppcoreguidelines-owning-memory,cppcoreguidelines-no-malloc) + } + + void *reallocate(void *ptr, size_t new_size) { return ALLOCATOR.reallocate(static_cast(ptr), new_size); } +}; + +static auto DOC_ALLOCATOR = SpiRamAllocator(); std::string build_json(const json_build_t &f) { // Here we are allocating up to 5kb of memory, // with the heap size minus 2kb to be safe if less than 5kb // as we can not have a true dynamic sized document. // The excess memory is freed below with `shrinkToFit()` - auto free_heap = ALLOCATOR.get_max_free_block_size(); - size_t request_size = std::min(free_heap, (size_t) 512); while (true) { ESP_LOGV(TAG, "Attempting to allocate %zu bytes for JSON serialization", request_size); DynamicJsonDocument json_document(request_size); if (json_document.capacity() == 0) { - ESP_LOGE(TAG, "Could not allocate memory for document! Requested %zu bytes, largest free heap block: %zu bytes", - request_size, free_heap); + ESP_LOGE(TAG, "Could not allocate memory for JSON document!"); return "{}"; } JsonObject root = json_document.to(); f(root); if (json_document.overflowed()) { if (request_size == free_heap) { - ESP_LOGE(TAG, "Could not allocate memory for document! Overflowed largest free heap block: %zu bytes", - free_heap); + ESP_LOGE(TAG, "Could not allocate memory for JSON document!"); return "{}"; } request_size = std::min(request_size * 2, free_heap); @@ -48,30 +57,21 @@ bool parse_json(const std::string &data, const json_parse_t &f) { // with the heap size minus 2kb to be safe if less than that // as we can not have a true dynamic sized document. // The excess memory is freed below with `shrinkToFit()` - auto free_heap = ALLOCATOR.get_max_free_block_size(); - size_t request_size = std::min(free_heap, (size_t) (data.size() * 1.5)); while (true) { DynamicJsonDocument json_document(request_size); if (json_document.capacity() == 0) { - ESP_LOGE(TAG, "Could not allocate memory for document! Requested %zu bytes, free heap: %zu", request_size, - free_heap); + ESP_LOGE(TAG, "Could not allocate memory for JSON document!"); return false; } DeserializationError err = deserializeJson(json_document, data); - json_document.shrinkToFit(); JsonObject root = json_document.as(); if (err == DeserializationError::Ok) { return f(root); } else if (err == DeserializationError::NoMemory) { - if (request_size * 2 >= free_heap) { - ESP_LOGE(TAG, "Can not allocate more memory for deserialization. Consider making source string smaller"); - return false; - } - ESP_LOGV(TAG, "Increasing memory allocation."); - request_size *= 2; - continue; + ESP_LOGE(TAG, "Can not allocate more memory for deserialization. Consider making source string smaller"); + return false; } else { ESP_LOGE(TAG, "Parse error: %s", err.c_str()); return false; diff --git a/platformio.ini b/platformio.ini index 54c72eb28d..b2478d356e 100644 --- a/platformio.ini +++ b/platformio.ini @@ -35,7 +35,7 @@ build_flags = lib_deps = esphome/noise-c@0.1.10 ; api improv/Improv@1.2.4 ; improv_serial / esp32_improv - bblanchon/ArduinoJson@6.18.5 ; json + bblanchon/ArduinoJson@7.4.1 ; json wjtje/qr-code-generator-library@1.7.0 ; qr_code functionpointer/arduino-MLX90393@1.0.2 ; mlx90393 pavlodn/HaierProtocol@0.9.31 ; haier