ESPHome 2026.3.0-dev
Loading...
Searching...
No Matches
http_request.h
Go to the documentation of this file.
1#pragma once
2
3#include <list>
4#include <memory>
5#include <set>
6#include <utility>
7#include <vector>
8
15#include "esphome/core/log.h"
16
17namespace esphome::http_request {
18
19struct Header {
20 std::string name;
21 std::string value;
22};
23
24// Some common HTTP status codes
52
59inline bool is_redirect(int const status) {
60 switch (status) {
66 return true;
67 default:
68 return false;
69 }
70}
71
80inline bool is_success(int const status) { return status >= HTTP_STATUS_OK && status < HTTP_STATUS_MULTIPLE_CHOICES; }
81
83inline bool should_collect_header(const std::vector<std::string> &lower_case_collect_headers,
84 const std::string &lower_header_name) {
85 for (const auto &h : lower_case_collect_headers) {
86 if (h == lower_header_name)
87 return true;
88 }
89 return false;
90}
91
92/*
93 * HTTP Container Read Semantics
94 * =============================
95 *
96 * IMPORTANT: These semantics differ from standard BSD sockets!
97 *
98 * BSD socket read() returns:
99 * > 0: bytes read
100 * == 0: connection closed (EOF)
101 * < 0: error (check errno)
102 *
103 * HttpContainer::read() returns:
104 * > 0: bytes read successfully
105 * == 0: no data available yet OR all content read
106 * (caller should check bytes_read vs content_length)
107 * < 0: error or connection closed (caller should EXIT)
108 * HTTP_ERROR_CONNECTION_CLOSED (-1) = connection closed prematurely
109 * other negative values = platform-specific errors
110 *
111 * Platform behaviors:
112 * - ESP-IDF: blocking reads, 0 only returned when all content read
113 * - Arduino: non-blocking, 0 means "no data yet" or "all content read"
114 *
115 * Chunked responses that complete in a reasonable time work correctly on both
116 * platforms. The limitation below applies only to *streaming* chunked
117 * responses where data arrives slowly over a long period.
118 *
119 * Streaming chunked responses are NOT supported (all platforms):
120 * The read helpers (http_read_loop_result, http_read_fully) block the main
121 * event loop until all response data is received. For streaming responses
122 * where data trickles in slowly (e.g., TTS streaming via ffmpeg proxy),
123 * this starves the event loop on both ESP-IDF and Arduino. If data arrives
124 * just often enough to avoid the caller's timeout, the loop runs
125 * indefinitely. If data stops entirely, ESP-IDF fails with
126 * -ESP_ERR_HTTP_EAGAIN (transport timeout) while Arduino spins with
127 * delay(1) until the caller's timeout fires. Supporting streaming requires
128 * a non-blocking incremental read pattern that yields back to the event
129 * loop between chunks. Components that need streaming should use
130 * esp_http_client directly on a separate FreeRTOS task with
131 * esp_http_client_is_complete_data_received() for completion detection
132 * (see audio_reader.cpp for an example).
133 *
134 * Chunked transfer encoding - platform differences:
135 * - ESP-IDF HttpContainer:
136 * HttpContainerIDF overrides is_read_complete() to call
137 * esp_http_client_is_complete_data_received(), which is the
138 * authoritative completion check for both chunked and non-chunked
139 * transfers. When esp_http_client_read() returns 0 for a completed
140 * chunked response, read() returns 0 and is_read_complete() returns
141 * true, so callers get COMPLETE from http_read_loop_result().
142 *
143 * - Arduino HttpContainer:
144 * Chunked responses are decoded internally (see
145 * HttpContainerArduino::read_chunked_()). When the final chunk arrives,
146 * is_chunked_ is cleared and content_length is set to bytes_read_.
147 * Completion is then detected via is_read_complete(), and a subsequent
148 * read() returns 0 to indicate "all content read" (not
149 * HTTP_ERROR_CONNECTION_CLOSED).
150 *
151 * Use the helper functions below instead of checking return values directly:
152 * - http_read_loop_result(): for manual loops with per-chunk processing
153 * - http_read_fully(): for simple "read N bytes into buffer" operations
154 */
155
158static constexpr int HTTP_ERROR_CONNECTION_CLOSED = -1;
159
161enum class HttpReadStatus : uint8_t {
162 OK,
163 ERROR,
164 TIMEOUT,
165};
166
172
174enum class HttpReadLoopResult : uint8_t {
175 DATA,
176 COMPLETE,
177 RETRY,
178 ERROR,
179 TIMEOUT,
180};
181
188inline HttpReadLoopResult http_read_loop_result(int bytes_read_or_error, uint32_t &last_data_time, uint32_t timeout_ms,
189 bool is_read_complete) {
190 if (bytes_read_or_error > 0) {
191 last_data_time = millis();
193 }
194 if (bytes_read_or_error < 0) {
196 }
197 // bytes_read_or_error == 0: either "no data yet" or "all content read"
198 if (is_read_complete) {
200 }
201 if (millis() - last_data_time >= timeout_ms) {
203 }
204 delay(1); // Small delay to prevent tight spinning
206}
207
208class HttpRequestComponent;
209
210class HttpContainer : public Parented<HttpRequestComponent> {
211 public:
212 virtual ~HttpContainer() = default;
213 size_t content_length{0};
214 int status_code{-1};
215 uint32_t duration_ms{0};
216
244 virtual int read(uint8_t *buf, size_t max_len) = 0;
245 virtual void end() = 0;
246
247 void set_secure(bool secure) { this->secure_ = secure; }
248 void set_chunked(bool chunked) { this->is_chunked_ = chunked; }
249
250 size_t get_bytes_read() const { return this->bytes_read_; }
251
258 virtual bool is_read_complete() const {
259 // Per RFC 9112, these responses have no body:
260 // - 1xx (Informational), 204 No Content, 205 Reset Content, 304 Not Modified
261 if ((this->status_code >= 100 && this->status_code < 200) || this->status_code == HTTP_STATUS_NO_CONTENT ||
263 return true;
264 }
265 // For non-chunked responses, complete when bytes_read >= content_length
266 // This handles both Content-Length: 0 and Content-Length: N cases
267 return !this->is_chunked_ && this->bytes_read_ >= this->content_length;
268 }
269
270 std::string get_response_header(const std::string &header_name);
271
272 protected:
273 size_t bytes_read_{0};
274 bool secure_{false};
275 bool is_chunked_{false};
276 std::vector<Header> response_headers_{};
277};
278
287inline HttpReadResult http_read_fully(HttpContainer *container, uint8_t *buffer, size_t total_size, size_t chunk_size,
288 uint32_t timeout_ms) {
289 size_t read_index = 0;
290 uint32_t last_data_time = millis();
291
292 while (read_index < total_size) {
293 int read_bytes_or_error = container->read(buffer + read_index, std::min(chunk_size, total_size - read_index));
294
295 App.feed_wdt();
296 yield();
297
298 auto result = http_read_loop_result(read_bytes_or_error, last_data_time, timeout_ms, container->is_read_complete());
299 if (result == HttpReadLoopResult::RETRY)
300 continue;
301 if (result == HttpReadLoopResult::COMPLETE)
302 break; // Server sent less data than requested, but transfer is complete
303 if (result == HttpReadLoopResult::ERROR)
304 return {HttpReadStatus::ERROR, read_bytes_or_error};
305 if (result == HttpReadLoopResult::TIMEOUT)
306 return {HttpReadStatus::TIMEOUT, 0};
307
308 read_index += read_bytes_or_error;
309 }
310 return {HttpReadStatus::OK, 0};
311}
312
313class HttpRequestResponseTrigger : public Trigger<std::shared_ptr<HttpContainer>, std::string &> {
314 public:
315 void process(const std::shared_ptr<HttpContainer> &container, std::string &response_body) {
316 this->trigger(container, response_body);
317 }
318};
319
321 public:
322 void dump_config() override;
323 float get_setup_priority() const override { return setup_priority::AFTER_WIFI; }
324
325 void set_useragent(const char *useragent) { this->useragent_ = useragent; }
326 void set_timeout(uint32_t timeout) { this->timeout_ = timeout; }
327 uint32_t get_timeout() const { return this->timeout_; }
328 void set_watchdog_timeout(uint32_t watchdog_timeout) { this->watchdog_timeout_ = watchdog_timeout; }
329 uint32_t get_watchdog_timeout() const { return this->watchdog_timeout_; }
330 void set_follow_redirects(bool follow_redirects) { this->follow_redirects_ = follow_redirects; }
331 void set_redirect_limit(uint16_t limit) { this->redirect_limit_ = limit; }
332
333 std::shared_ptr<HttpContainer> get(const std::string &url) {
334 return this->start(url, "GET", "", std::vector<Header>{});
335 }
336 std::shared_ptr<HttpContainer> get(const std::string &url, const std::vector<Header> &request_headers) {
337 return this->start(url, "GET", "", request_headers);
338 }
339 std::shared_ptr<HttpContainer> get(const std::string &url, const std::vector<Header> &request_headers,
340 const std::vector<std::string> &lower_case_collect_headers) {
341 return this->start(url, "GET", "", request_headers, lower_case_collect_headers);
342 }
343 std::shared_ptr<HttpContainer> post(const std::string &url, const std::string &body) {
344 return this->start(url, "POST", body, std::vector<Header>{});
345 }
346 std::shared_ptr<HttpContainer> post(const std::string &url, const std::string &body,
347 const std::vector<Header> &request_headers) {
348 return this->start(url, "POST", body, request_headers);
349 }
350 std::shared_ptr<HttpContainer> post(const std::string &url, const std::string &body,
351 const std::vector<Header> &request_headers,
352 const std::vector<std::string> &lower_case_collect_headers) {
353 return this->start(url, "POST", body, request_headers, lower_case_collect_headers);
354 }
355
356 // Remove before 2027.1.0
357 ESPDEPRECATED("Pass request_headers as std::vector<Header> instead of std::list. Removed in 2027.1.0.", "2026.7.0")
358 std::shared_ptr<HttpContainer> get(const std::string &url, const std::list<Header> &request_headers) {
359 return this->get(url, std::vector<Header>(request_headers.begin(), request_headers.end()));
360 }
361 // Remove before 2027.1.0
362 ESPDEPRECATED("Pass request_headers as std::vector<Header> instead of std::list. Removed in 2027.1.0.", "2026.7.0")
363 std::shared_ptr<HttpContainer> get(const std::string &url, const std::list<Header> &request_headers,
364 const std::vector<std::string> &collect_headers) {
365 return this->get(url, std::vector<Header>(request_headers.begin(), request_headers.end()), collect_headers);
366 }
367 // Remove before 2027.1.0
368 ESPDEPRECATED("Pass request_headers as std::vector<Header> instead of std::list. Removed in 2027.1.0.", "2026.7.0")
369 std::shared_ptr<HttpContainer> post(const std::string &url, const std::string &body,
370 const std::list<Header> &request_headers) {
371 return this->post(url, body, std::vector<Header>(request_headers.begin(), request_headers.end()));
372 }
373 // Remove before 2027.1.0
374 ESPDEPRECATED("Pass request_headers as std::vector<Header> instead of std::list. Removed in 2027.1.0.", "2026.7.0")
375 std::shared_ptr<HttpContainer> post(const std::string &url, const std::string &body,
376 const std::list<Header> &request_headers,
377 const std::vector<std::string> &collect_headers) {
378 return this->post(url, body, std::vector<Header>(request_headers.begin(), request_headers.end()), collect_headers);
379 }
380
381 std::shared_ptr<HttpContainer> start(const std::string &url, const std::string &method, const std::string &body,
382 const std::vector<Header> &request_headers) {
383 // Call perform() directly to avoid ambiguity with the deprecated overloads
384 return this->perform(url, method, body, request_headers, {});
385 }
386
387 // Remove before 2027.1.0
388 ESPDEPRECATED("Pass request_headers as std::vector<Header> instead of std::list. Removed in 2027.1.0.", "2026.7.0")
389 std::shared_ptr<HttpContainer> start(const std::string &url, const std::string &method, const std::string &body,
390 const std::list<Header> &request_headers) {
391 return this->start(url, method, body, std::vector<Header>(request_headers.begin(), request_headers.end()));
392 }
393
394 // Remove before 2027.1.0
395 ESPDEPRECATED("Pass collect_headers as std::vector<std::string> instead of std::set. Removed in 2027.1.0.",
396 "2026.7.0")
397 std::shared_ptr<HttpContainer> start(const std::string &url, const std::string &method, const std::string &body,
398 const std::vector<Header> &request_headers,
399 const std::set<std::string> &collect_headers) {
400 std::vector<std::string> lower;
401 lower.reserve(collect_headers.size());
402 for (const auto &h : collect_headers) {
403 lower.push_back(str_lower_case(h));
404 }
405 return this->perform(url, method, body, request_headers, lower);
406 }
407
408 // Remove before 2027.1.0
409 ESPDEPRECATED("Pass request_headers as std::vector<Header> instead of std::list, and collect_headers as "
410 "std::vector<std::string> instead of std::set. Removed in 2027.1.0.",
411 "2026.7.0")
412 std::shared_ptr<HttpContainer> start(const std::string &url, const std::string &method, const std::string &body,
413 const std::list<Header> &request_headers,
414 const std::set<std::string> &collect_headers) {
415 std::vector<std::string> lower;
416 lower.reserve(collect_headers.size());
417 for (const auto &h : collect_headers) {
418 lower.push_back(str_lower_case(h));
419 }
420 return this->perform(url, method, body, std::vector<Header>(request_headers.begin(), request_headers.end()), lower);
421 }
422
423 // Remove before 2027.1.0
424 ESPDEPRECATED("Pass request_headers as std::vector<Header> instead of std::list. Removed in 2027.1.0.", "2026.7.0")
425 std::shared_ptr<HttpContainer> start(const std::string &url, const std::string &method, const std::string &body,
426 const std::list<Header> &request_headers,
427 const std::vector<std::string> &lower_case_collect_headers) {
428 return this->perform(url, method, body, std::vector<Header>(request_headers.begin(), request_headers.end()),
429 lower_case_collect_headers);
430 }
431
432 std::shared_ptr<HttpContainer> start(const std::string &url, const std::string &method, const std::string &body,
433 const std::vector<Header> &request_headers,
434 const std::vector<std::string> &lower_case_collect_headers) {
435 return this->perform(url, method, body, request_headers, lower_case_collect_headers);
436 }
437
438 protected:
439 virtual std::shared_ptr<HttpContainer> perform(const std::string &url, const std::string &method,
440 const std::string &body, const std::vector<Header> &request_headers,
441 const std::vector<std::string> &lower_case_collect_headers) = 0;
442 const char *useragent_{nullptr};
444 uint16_t redirect_limit_{};
445 uint32_t timeout_{4500};
446 uint32_t watchdog_timeout_{0};
447};
448
449template<typename... Ts> class HttpRequestSendAction : public Action<Ts...> {
450 public:
452 TEMPLATABLE_VALUE(std::string, url)
453 TEMPLATABLE_VALUE(const char *, method)
454 TEMPLATABLE_VALUE(std::string, body)
455#ifdef USE_HTTP_REQUEST_RESPONSE
456 TEMPLATABLE_VALUE(bool, capture_response)
457#endif
458
459 void init_request_headers(size_t count) { this->request_headers_.init(count); }
461 this->request_headers_.push_back({key, value});
462 }
463
464 void add_collect_header(const char *value) { this->lower_case_collect_headers_.push_back(value); }
465
466 void init_json(size_t count) { this->json_.init(count); }
467 void add_json(const char *key, TemplatableValue<std::string, Ts...> value) { this->json_.push_back({key, value}); }
468
469 void set_json(std::function<void(Ts..., JsonObject)> json_func) { this->json_func_ = json_func; }
470
471#ifdef USE_HTTP_REQUEST_RESPONSE
475#endif
477
478 Trigger<Ts...> *get_error_trigger() { return &this->error_trigger_; }
479
480 void set_max_response_buffer_size(size_t max_response_buffer_size) {
481 this->max_response_buffer_size_ = max_response_buffer_size;
482 }
483
484 void play(const Ts &...x) override {
485 std::string body;
486 if (this->body_.has_value()) {
487 body = this->body_.value(x...);
488 }
489 if (!this->json_.empty()) {
490 auto f = std::bind(&HttpRequestSendAction<Ts...>::encode_json_, this, x..., std::placeholders::_1);
491 body = json::build_json(f);
492 }
493 if (this->json_func_ != nullptr) {
494 auto f = std::bind(&HttpRequestSendAction<Ts...>::encode_json_func_, this, x..., std::placeholders::_1);
495 body = json::build_json(f);
496 }
497 std::vector<Header> request_headers;
498 request_headers.reserve(this->request_headers_.size());
499 for (const auto &[key, val] : this->request_headers_) {
500 request_headers.push_back({key, val.value(x...)});
501 }
502
503 auto container = this->parent_->start(this->url_.value(x...), this->method_.value(x...), body, request_headers,
504 this->lower_case_collect_headers_);
505
506 auto captured_args = std::make_tuple(x...);
507
508 if (container == nullptr) {
509 std::apply([this](Ts... captured_args_inner) { this->error_trigger_.trigger(captured_args_inner...); },
510 captured_args);
511 return;
512 }
513
514 size_t max_length = this->max_response_buffer_size_;
515#ifdef USE_HTTP_REQUEST_RESPONSE
516 if (this->capture_response_.value(x...)) {
517 std::string response_body;
518 RAMAllocator<uint8_t> allocator;
519 uint8_t *buf = allocator.allocate(max_length);
520 if (buf != nullptr) {
521 // NOTE: HttpContainer::read() has non-BSD socket semantics - see top of this file
522 // Use http_read_loop_result() helper instead of checking return values directly
523 size_t read_index = 0;
524 uint32_t last_data_time = millis();
525 const uint32_t read_timeout = this->parent_->get_timeout();
526 while (container->get_bytes_read() < max_length) {
527 int read_or_error = container->read(buf + read_index, std::min<size_t>(max_length - read_index, 512));
528 App.feed_wdt();
529 yield();
530 auto result =
531 http_read_loop_result(read_or_error, last_data_time, read_timeout, container->is_read_complete());
532 if (result == HttpReadLoopResult::RETRY)
533 continue;
534 if (result != HttpReadLoopResult::DATA)
535 break; // COMPLETE, ERROR, or TIMEOUT
536 read_index += read_or_error;
537 }
538 response_body.reserve(read_index);
539 response_body.assign((char *) buf, read_index);
540 allocator.deallocate(buf, max_length);
541 }
542 std::apply(
543 [this, &container, &response_body](Ts... captured_args_inner) {
544 this->success_trigger_with_response_.trigger(container, response_body, captured_args_inner...);
545 },
546 captured_args);
547 } else
548#endif
549 {
550 std::apply([this, &container](
551 Ts... captured_args_inner) { this->success_trigger_.trigger(container, captured_args_inner...); },
552 captured_args);
553 }
554 container->end();
555 }
556
557 protected:
558 void encode_json_(Ts... x, JsonObject root) {
559 for (const auto &item : this->json_) {
560 auto val = item.second;
561 root[item.first] = val.value(x...);
562 }
563 }
564 void encode_json_func_(Ts... x, JsonObject root) { this->json_func_(x..., root); }
566 FixedVector<std::pair<const char *, TemplatableValue<const char *, Ts...>>> request_headers_{};
567 std::vector<std::string> lower_case_collect_headers_{"content-type", "content-length"};
568 FixedVector<std::pair<const char *, TemplatableValue<std::string, Ts...>>> json_{};
569 std::function<void(Ts..., JsonObject)> json_func_{nullptr};
570#ifdef USE_HTTP_REQUEST_RESPONSE
572#endif
575
577};
578
579} // namespace esphome::http_request
uint8_t h
Definition bl0906.h:2
uint8_t status
Definition bl0942.h:8
void feed_wdt(uint32_t time=0)
Fixed-capacity vector - allocates once at runtime, never reallocates This avoids std::vector template...
Definition helpers.h:299
Helper class to easily give an object a parent of type T.
Definition helpers.h:1618
An STL allocator that uses SPI or internal RAM.
Definition helpers.h:1794
void deallocate(T *p, size_t n)
Definition helpers.h:1849
T * allocate(size_t n)
Definition helpers.h:1811
std::string get_response_header(const std::string &header_name)
virtual int read(uint8_t *buf, size_t max_len)=0
Read data from the HTTP response body.
virtual bool is_read_complete() const
Check if all expected content has been read.
std::vector< Header > response_headers_
int status_code
-1 indicates no response received yet
bool is_chunked_
True if response uses chunked transfer encoding.
ESPDEPRECATED("Pass request_headers as std::vector<Header> instead of std::list. Removed in 2027.1.0.", "2026.7.0") std
std::shared_ptr< HttpContainer > post(const std::string &url, const std::string &body)
void set_useragent(const char *useragent)
ESPDEPRECATED("Pass request_headers as std::vector<Header> instead of std::list, and collect_headers as " "std::vector<std::string> instead of std::set. Removed in 2027.1.0.", "2026.7.0") std
std::shared_ptr< HttpContainer > start(const std::string &url, const std::string &method, const std::string &body, const std::vector< Header > &request_headers)
std::shared_ptr< HttpContainer > post(const std::string &url, const std::string &body, const std::vector< Header > &request_headers, const std::vector< std::string > &lower_case_collect_headers)
void set_follow_redirects(bool follow_redirects)
std::shared_ptr< HttpContainer > get(const std::string &url, const std::vector< Header > &request_headers, const std::vector< std::string > &lower_case_collect_headers)
void set_watchdog_timeout(uint32_t watchdog_timeout)
ESPDEPRECATED("Pass collect_headers as std::vector<std::string> instead of std::set. Removed in 2027.1.0.", "2026.7.0") std
std::shared_ptr< HttpContainer > post(const std::string &url, const std::string &body, const std::vector< Header > &request_headers)
std::shared_ptr< HttpContainer > start(const std::string &url, const std::string &method, const std::string &body, const std::vector< Header > &request_headers, const std::vector< std::string > &lower_case_collect_headers)
std::shared_ptr< HttpContainer > get(const std::string &url)
virtual std::shared_ptr< HttpContainer > perform(const std::string &url, const std::string &method, const std::string &body, const std::vector< Header > &request_headers, const std::vector< std::string > &lower_case_collect_headers)=0
std::shared_ptr< HttpContainer > get(const std::string &url, const std::vector< Header > &request_headers)
void process(const std::shared_ptr< HttpContainer > &container, std::string &response_body)
void set_max_response_buffer_size(size_t max_response_buffer_size)
TEMPLATABLE_VALUE(std::string, url) TEMPLATABLE_VALUE(const char *
Trigger< std::shared_ptr< HttpContainer >, std::string &, Ts... > success_trigger_with_response_
method capture_response void init_request_headers(size_t count)
FixedVector< std::pair< const char *, TemplatableValue< const char *, Ts... > > > request_headers_
std::function< void(Ts..., JsonObject)> json_func_
Trigger< std::shared_ptr< HttpContainer >, Ts... > success_trigger_
std::vector< std::string > lower_case_collect_headers_
void encode_json_func_(Ts... x, JsonObject root)
void set_json(std::function< void(Ts..., JsonObject)> json_func)
void add_json(const char *key, TemplatableValue< std::string, Ts... > value)
Trigger< std::shared_ptr< HttpContainer >, std::string &, Ts... > * get_success_trigger_with_response()
void add_request_header(const char *key, TemplatableValue< const char *, Ts... > value)
void encode_json_(Ts... x, JsonObject root)
Trigger< std::shared_ptr< HttpContainer >, Ts... > * get_success_trigger()
HttpRequestSendAction(HttpRequestComponent *parent)
FixedVector< std::pair< const char *, TemplatableValue< std::string, Ts... > > > json_
mopeka_std_values val[4]
bool should_collect_header(const std::vector< std::string > &lower_case_collect_headers, const std::string &lower_header_name)
Check if a header name should be collected (linear scan, fine for small lists)
HttpReadLoopResult
Result of processing a non-blocking read with timeout (for manual loops)
@ TIMEOUT
Timeout waiting for data, caller should exit loop.
@ COMPLETE
All content has been read, caller should exit loop.
@ ERROR
Read error, caller should exit loop.
@ RETRY
No data yet, already delayed, caller should continue loop.
@ DATA
Data was read, process it.
bool is_success(int const status)
Checks if the given HTTP status code indicates a successful request.
HttpReadLoopResult http_read_loop_result(int bytes_read_or_error, uint32_t &last_data_time, uint32_t timeout_ms, bool is_read_complete)
Process a read result with timeout tracking and delay handling.
bool is_redirect(int const status)
Returns true if the HTTP status code is a redirect.
HttpReadResult http_read_fully(HttpContainer *container, uint8_t *buffer, size_t total_size, size_t chunk_size, uint32_t timeout_ms)
Read data from HTTP container into buffer with timeout handling Handles feed_wdt, yield,...
HttpReadStatus
Status of a read operation.
@ TIMEOUT
Timeout waiting for data.
@ OK
Read completed successfully.
SerializationBuffer build_json(const json_build_t &f)
Build a JSON string with the provided json build function.
Definition json_util.cpp:18
constexpr float AFTER_WIFI
For components that should be initialized after WiFi is connected.
Definition component.h:41
std::string str_lower_case(const std::string &str)
Convert the string to lower case.
Definition helpers.cpp:201
void HOT yield()
Definition core.cpp:24
void HOT delay(uint32_t ms)
Definition core.cpp:27
uint32_t IRAM_ATTR HOT millis()
Definition core.cpp:25
Application App
Global storage of Application pointer - only one Application can exist.
Result of an HTTP read operation.
HttpReadStatus status
Status of the read operation.
int error_code
Error code from read() on failure, 0 on success.
uint16_t x
Definition tt21100.cpp:5