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