ESPHome  2023.5.5
json_util.cpp
Go to the documentation of this file.
1 #include "json_util.h"
2 #include "esphome/core/log.h"
3 
4 #ifdef USE_ESP8266
5 #include <Esp.h>
6 #endif
7 #ifdef USE_ESP32
8 #include <esp_heap_caps.h>
9 #endif
10 #ifdef USE_RP2040
11 #include <Arduino.h>
12 #endif
13 
14 namespace esphome {
15 namespace json {
16 
17 static const char *const TAG = "json";
18 
19 static std::vector<char> global_json_build_buffer; // NOLINT
20 
21 std::string build_json(const json_build_t &f) {
22  // Here we are allocating up to 5kb of memory,
23  // with the heap size minus 2kb to be safe if less than 5kb
24  // as we can not have a true dynamic sized document.
25  // The excess memory is freed below with `shrinkToFit()`
26 #ifdef USE_ESP8266
27  const size_t free_heap = ESP.getMaxFreeBlockSize(); // NOLINT(readability-static-accessed-through-instance)
28 #elif defined(USE_ESP32)
29  const size_t free_heap = heap_caps_get_largest_free_block(MALLOC_CAP_8BIT);
30 #elif defined(USE_RP2040)
31  const size_t free_heap = rp2040.getFreeHeap();
32 #endif
33 
34  size_t request_size = std::min(free_heap, (size_t) 512);
35  while (true) {
36  ESP_LOGV(TAG, "Attempting to allocate %u bytes for JSON serialization", request_size);
37  DynamicJsonDocument json_document(request_size);
38  if (json_document.capacity() == 0) {
39  ESP_LOGE(TAG,
40  "Could not allocate memory for JSON document! Requested %u bytes, largest free heap block: %u bytes",
41  request_size, free_heap);
42  return "{}";
43  }
44  JsonObject root = json_document.to<JsonObject>();
45  f(root);
46  if (json_document.overflowed()) {
47  if (request_size == free_heap) {
48  ESP_LOGE(TAG, "Could not allocate memory for JSON document! Overflowed largest free heap block: %u bytes",
49  free_heap);
50  return "{}";
51  }
52  request_size = std::min(request_size * 2, free_heap);
53  continue;
54  }
55  json_document.shrinkToFit();
56  ESP_LOGV(TAG, "Size after shrink %u bytes", json_document.capacity());
57  std::string output;
58  serializeJson(json_document, output);
59  return output;
60  }
61 }
62 
63 void parse_json(const std::string &data, const json_parse_t &f) {
64  // Here we are allocating 1.5 times the data size,
65  // with the heap size minus 2kb to be safe if less than that
66  // as we can not have a true dynamic sized document.
67  // The excess memory is freed below with `shrinkToFit()`
68 #ifdef USE_ESP8266
69  const size_t free_heap = ESP.getMaxFreeBlockSize(); // NOLINT(readability-static-accessed-through-instance)
70 #elif defined(USE_ESP32)
71  const size_t free_heap = heap_caps_get_largest_free_block(MALLOC_CAP_8BIT);
72 #elif defined(USE_RP2040)
73  const size_t free_heap = rp2040.getFreeHeap();
74 #endif
75  bool pass = false;
76  size_t request_size = std::min(free_heap, (size_t) (data.size() * 1.5));
77  do {
78  DynamicJsonDocument json_document(request_size);
79  if (json_document.capacity() == 0) {
80  ESP_LOGE(TAG, "Could not allocate memory for JSON document! Requested %u bytes, free heap: %u", request_size,
81  free_heap);
82  return;
83  }
84  DeserializationError err = deserializeJson(json_document, data);
85  json_document.shrinkToFit();
86 
87  JsonObject root = json_document.as<JsonObject>();
88 
89  if (err == DeserializationError::Ok) {
90  pass = true;
91  f(root);
92  } else if (err == DeserializationError::NoMemory) {
93  if (request_size * 2 >= free_heap) {
94  ESP_LOGE(TAG, "Can not allocate more memory for deserialization. Consider making source string smaller");
95  return;
96  }
97  ESP_LOGV(TAG, "Increasing memory allocation.");
98  request_size *= 2;
99  continue;
100  } else {
101  ESP_LOGE(TAG, "JSON parse error: %s", err.c_str());
102  return;
103  }
104  } while (!pass);
105 }
106 
107 } // namespace json
108 } // namespace esphome
void parse_json(const std::string &data, const json_parse_t &f)
Parse a JSON string and run the provided json parse function if it&#39;s valid.
Definition: json_util.cpp:63
std::function< void(JsonObject)> json_build_t
Callback function typedef for building JsonObjects.
Definition: json_util.h:20
std::string build_json(const json_build_t &f)
Build a JSON string with the provided json build function.
Definition: json_util.cpp:21
Definition: a4988.cpp:4
std::function< void(JsonObject)> json_parse_t
Callback function typedef for parsing JsonObjects.
Definition: json_util.h:17