ESPHome 2026.3.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 {
17namespace json {
18
22template<size_t STACK_SIZE = 640> class SerializationBuffer {
23 public:
24 static constexpr size_t BUFFER_SIZE = STACK_SIZE;
25
27 explicit SerializationBuffer(size_t size) : size_(size) {
28 if (size + 1 <= STACK_SIZE) {
29 buffer_ = stack_buffer_;
30 } else {
31 heap_buffer_ = new char[size + 1];
32 buffer_ = heap_buffer_;
33 }
34 buffer_[0] = '\0';
35 }
36
37 ~SerializationBuffer() { delete[] heap_buffer_; }
38
39 // Move constructor - works with same template instantiation
40 SerializationBuffer(SerializationBuffer &&other) noexcept : heap_buffer_(other.heap_buffer_), size_(other.size_) {
41 if (other.buffer_ == other.stack_buffer_) {
42 // Stack buffer - must copy content
43 std::memcpy(stack_buffer_, other.stack_buffer_, size_ + 1);
44 buffer_ = stack_buffer_;
45 } else {
46 // Heap buffer - steal ownership
47 buffer_ = heap_buffer_;
48 other.heap_buffer_ = nullptr;
49 }
50 // Leave moved-from object in valid empty state
51 other.stack_buffer_[0] = '\0';
52 other.buffer_ = other.stack_buffer_;
53 other.size_ = 0;
54 }
55
56 // Move assignment
58 if (this != &other) {
59 delete[] heap_buffer_;
60 heap_buffer_ = other.heap_buffer_;
61 size_ = other.size_;
62 if (other.buffer_ == other.stack_buffer_) {
63 std::memcpy(stack_buffer_, other.stack_buffer_, size_ + 1);
64 buffer_ = stack_buffer_;
65 } else {
66 buffer_ = heap_buffer_;
67 other.heap_buffer_ = nullptr;
68 }
69 // Leave moved-from object in valid empty state
70 other.stack_buffer_[0] = '\0';
71 other.buffer_ = other.stack_buffer_;
72 other.size_ = 0;
73 }
74 return *this;
75 }
76
77 // Delete copy operations
80
82 const char *c_str() const { return buffer_; }
84 const char *data() const { return buffer_; }
86 size_t size() const { return size_; }
87
91 operator std::string() const { return std::string(buffer_, size_); } // NOLINT(google-explicit-constructor)
92
93 private:
94 friend class JsonBuilder;
95
97 char *data_writable_() { return buffer_; }
100 void set_size_(size_t size) {
101 size_ = size;
102 buffer_[size] = '\0';
103 }
104
107 void reallocate_heap_(size_t size) {
108 delete[] heap_buffer_;
109 heap_buffer_ = new char[size + 1];
110 buffer_ = heap_buffer_;
111 size_ = size;
112 buffer_[0] = '\0';
113 }
114
115 char stack_buffer_[STACK_SIZE];
116 char *heap_buffer_{nullptr};
117 char *buffer_;
118 size_t size_;
119};
120
121#ifdef USE_PSRAM
122// Build an allocator for the JSON Library using the RAMAllocator class
123// This is only compiled when PSRAM is enabled
124struct SpiRamAllocator : ArduinoJson::Allocator {
125 void *allocate(size_t size) override {
126 RAMAllocator<uint8_t> allocator;
127 return allocator.allocate(size);
128 }
129
130 void deallocate(void *ptr) override {
131 // ArduinoJson's Allocator interface doesn't provide the size parameter in deallocate.
132 // RAMAllocator::deallocate() requires the size, which we don't have access to here.
133 // RAMAllocator::deallocate implementation just calls free() regardless of whether
134 // the memory was allocated with heap_caps_malloc or malloc.
135 // This is safe because ESP-IDF's heap implementation internally tracks the memory region
136 // and routes free() to the appropriate heap.
137 free(ptr); // NOLINT(cppcoreguidelines-owning-memory,cppcoreguidelines-no-malloc)
138 }
139
140 void *reallocate(void *ptr, size_t new_size) override {
141 RAMAllocator<uint8_t> allocator;
142 return allocator.reallocate(static_cast<uint8_t *>(ptr), new_size);
143 }
144};
145#endif
146
148using json_parse_t = std::function<bool(JsonObject)>;
149
151using json_build_t = std::function<void(JsonObject)>;
152
156
158bool parse_json(const std::string &data, const json_parse_t &f);
160bool parse_json(const uint8_t *data, size_t len, const json_parse_t &f);
161
163JsonDocument parse_json(const uint8_t *data, size_t len);
165inline JsonDocument parse_json(const std::string &data) {
166 return parse_json(reinterpret_cast<const uint8_t *>(data.c_str()), data.size());
167}
168
171 public:
172 JsonObject root() {
173 if (!root_created_) {
174 root_ = doc_.to<JsonObject>();
175 root_created_ = true;
176 }
177 return root_;
178 }
179
183
184 private:
185#ifdef USE_PSRAM
186 SpiRamAllocator allocator_;
187 JsonDocument doc_{&allocator_};
188#else
189 JsonDocument doc_;
190#endif
191 JsonObject root_;
192 bool root_created_{false};
193};
194
195} // namespace json
196} // namespace esphome
An STL allocator that uses SPI or internal RAM.
Definition helpers.h:1794
T * reallocate(T *p, size_t n)
Definition helpers.h:1830
T * allocate(size_t n)
Definition helpers.h:1811
Builder class for creating JSON documents without lambdas.
Definition json_util.h:170
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:22
static constexpr size_t BUFFER_SIZE
Stack buffer size for this instantiation.
Definition json_util.h:24
size_t size() const
Get string length (excluding null terminator)
Definition json_util.h:86
SerializationBuffer(size_t size)
Construct with known size (typically from measureJson)
Definition json_util.h:27
SerializationBuffer & operator=(const SerializationBuffer &)=delete
const char * data() const
Get data pointer.
Definition json_util.h:84
SerializationBuffer(const SerializationBuffer &)=delete
const char * c_str() const
Get null-terminated C string.
Definition json_util.h:82
SerializationBuffer & operator=(SerializationBuffer &&other) noexcept
Definition json_util.h:57
SerializationBuffer(SerializationBuffer &&other) noexcept
Definition json_util.h:40
std::function< void(JsonObject)> json_build_t
Callback function typedef for building JsonObjects.
Definition json_util.h:151
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:27
std::function< bool(JsonObject)> json_parse_t
Callback function typedef for parsing JsonObjects.
Definition json_util.h:148
SerializationBuffer build_json(const json_build_t &f)
Build a JSON string with the provided json build function.
Definition json_util.cpp:18
Providing packet encoding functions for exchanging data with a remote host.
Definition a01nyub.cpp:7
std::string size_t len
Definition helpers.h:817
size_t size
Definition helpers.h:854
void deallocate(void *ptr) override
Definition json_util.h:130
void * allocate(size_t size) override
Definition json_util.h:125
void * reallocate(void *ptr, size_t new_size) override
Definition json_util.h:140