ESPHome 2026.6.0-dev
Loading...
Searching...
No Matches
json_util.h
Go to the documentation of this file.
1#pragma once
2
3#include <cstring>
4#include <string>
5#include <vector>
6
9
10#define ARDUINOJSON_ENABLE_STD_STRING 1 // NOLINT
11
12#define ARDUINOJSON_USE_LONG_LONG 1 // NOLINT
13
14#include <ArduinoJson.h>
15
16namespace esphome::json {
17
21template<size_t STACK_SIZE = 640> class SerializationBuffer {
22 public:
23 static constexpr size_t BUFFER_SIZE = STACK_SIZE;
24
26 explicit SerializationBuffer(size_t size) : size_(size) {
27 if (size + 1 <= STACK_SIZE) {
28 buffer_ = stack_buffer_;
29 } else {
30 heap_buffer_ = new char[size + 1];
31 buffer_ = heap_buffer_;
32 }
33 buffer_[0] = '\0';
34 }
35
36 ~SerializationBuffer() { delete[] heap_buffer_; }
37
38 // Move constructor - works with same template instantiation
39 SerializationBuffer(SerializationBuffer &&other) noexcept : heap_buffer_(other.heap_buffer_), size_(other.size_) {
40 if (other.buffer_ == other.stack_buffer_) {
41 // Stack buffer - must copy content
42 std::memcpy(stack_buffer_, other.stack_buffer_, size_ + 1);
43 buffer_ = stack_buffer_;
44 } else {
45 // Heap buffer - steal ownership
46 buffer_ = heap_buffer_;
47 other.heap_buffer_ = nullptr;
48 }
49 // Leave moved-from object in valid empty state
50 other.stack_buffer_[0] = '\0';
51 other.buffer_ = other.stack_buffer_;
52 other.size_ = 0;
53 }
54
55 // Move assignment
57 if (this != &other) {
58 delete[] heap_buffer_;
59 heap_buffer_ = other.heap_buffer_;
60 size_ = other.size_;
61 if (other.buffer_ == other.stack_buffer_) {
62 std::memcpy(stack_buffer_, other.stack_buffer_, size_ + 1);
63 buffer_ = stack_buffer_;
64 } else {
65 buffer_ = heap_buffer_;
66 other.heap_buffer_ = nullptr;
67 }
68 // Leave moved-from object in valid empty state
69 other.stack_buffer_[0] = '\0';
70 other.buffer_ = other.stack_buffer_;
71 other.size_ = 0;
72 }
73 return *this;
74 }
75
76 // Delete copy operations
79
81 const char *c_str() const { return buffer_; }
83 const char *data() const { return buffer_; }
85 size_t size() const { return size_; }
86
90 operator std::string() const { return std::string(buffer_, size_); } // NOLINT(google-explicit-constructor)
91
92 private:
93 friend class JsonBuilder;
94
96 char *data_writable_() { return buffer_; }
99 void set_size_(size_t size) {
100 size_ = size;
101 buffer_[size] = '\0';
102 }
103
106 void reallocate_heap_(size_t size) {
107 delete[] heap_buffer_;
108 heap_buffer_ = new char[size + 1];
109 buffer_ = heap_buffer_;
110 size_ = size;
111 buffer_[0] = '\0';
112 }
113
114 char stack_buffer_[STACK_SIZE];
115 char *heap_buffer_{nullptr};
116 char *buffer_;
117 size_t size_;
118};
119
120#ifdef USE_PSRAM
121// Build an allocator for the JSON Library using the RAMAllocator class
122// This is only compiled when PSRAM is enabled
123struct SpiRamAllocator : ArduinoJson::Allocator {
124 void *allocate(size_t size) override {
125 RAMAllocator<uint8_t> allocator;
126 return allocator.allocate(size);
127 }
128
129 void deallocate(void *ptr) override {
130 // ArduinoJson's Allocator interface doesn't provide the size parameter in deallocate.
131 // RAMAllocator::deallocate() requires the size, which we don't have access to here.
132 // RAMAllocator::deallocate implementation just calls free() regardless of whether
133 // the memory was allocated with heap_caps_malloc or malloc.
134 // This is safe because ESP-IDF's heap implementation internally tracks the memory region
135 // and routes free() to the appropriate heap.
136 free(ptr); // NOLINT(cppcoreguidelines-owning-memory,cppcoreguidelines-no-malloc)
137 }
138
139 void *reallocate(void *ptr, size_t new_size) override {
140 RAMAllocator<uint8_t> allocator;
141 return allocator.reallocate(static_cast<uint8_t *>(ptr), new_size);
142 }
143};
144#endif
145
147using json_parse_t = std::function<bool(JsonObject)>;
148
150using json_build_t = std::function<void(JsonObject)>;
151
155
157bool parse_json(const std::string &data, const json_parse_t &f);
159bool parse_json(const uint8_t *data, size_t len, const json_parse_t &f);
160
162JsonDocument parse_json(const uint8_t *data, size_t len);
164inline JsonDocument parse_json(const std::string &data) {
165 return parse_json(reinterpret_cast<const uint8_t *>(data.c_str()), data.size());
166}
167
170 public:
171 JsonObject root() {
172 if (!root_created_) {
173 root_ = doc_.to<JsonObject>();
174 root_created_ = true;
175 }
176 return root_;
177 }
178
182
183 private:
184#ifdef USE_PSRAM
185 SpiRamAllocator allocator_;
186 JsonDocument doc_{&allocator_};
187#else
188 JsonDocument doc_;
189#endif
190 JsonObject root_;
191 bool root_created_{false};
192};
193
194} // namespace esphome::json
An STL allocator that uses SPI or internal RAM.
Definition helpers.h:2053
T * reallocate(T *p, size_t n)
Definition helpers.h:2095
T * allocate(size_t n)
Definition helpers.h:2080
Builder class for creating JSON documents without lambdas.
Definition json_util.h:169
SerializationBuffer serialize()
Serialize the JSON document to a SerializationBuffer (stack-first allocation) Uses 512-byte stack buf...
Definition json_util.cpp:69
Buffer for JSON serialization that uses stack allocation for small payloads.
Definition json_util.h:21
static constexpr size_t BUFFER_SIZE
Stack buffer size for this instantiation.
Definition json_util.h:23
size_t size() const
Get string length (excluding null terminator)
Definition json_util.h:85
SerializationBuffer(size_t size)
Construct with known size (typically from measureJson)
Definition json_util.h:26
SerializationBuffer & operator=(const SerializationBuffer &)=delete
const char * data() const
Get data pointer.
Definition json_util.h:83
SerializationBuffer(const SerializationBuffer &)=delete
const char * c_str() const
Get null-terminated C string.
Definition json_util.h:81
SerializationBuffer & operator=(SerializationBuffer &&other) noexcept
Definition json_util.h:56
SerializationBuffer(SerializationBuffer &&other) noexcept
Definition json_util.h:39
std::function< void(JsonObject)> json_build_t
Callback function typedef for building JsonObjects.
Definition json_util.h:150
bool parse_json(const std::string &data, const json_parse_t &f)
Parse a JSON string and run the provided json parse function if it's valid.
Definition json_util.cpp:26
std::function< bool(JsonObject)> json_parse_t
Callback function typedef for parsing JsonObjects.
Definition json_util.h:147
SerializationBuffer build_json(const json_build_t &f)
Build a JSON string with the provided json build function.
Definition json_util.cpp:17
const void size_t len
Definition hal.h:64
uint16_t size
Definition helpers.cpp:25
void deallocate(void *ptr) override
Definition json_util.h:129
void * allocate(size_t size) override
Definition json_util.h:124
void * reallocate(void *ptr, size_t new_size) override
Definition json_util.h:139