ESPHome 2025.10.3
Loading...
Searching...
No Matches
web_server_idf.h
Go to the documentation of this file.
1#pragma once
2#ifdef USE_ESP32
5#include <esp_http_server.h>
6
7#include <atomic>
8#include <functional>
9#include <list>
10#include <map>
11#include <set>
12#include <string>
13#include <utility>
14#include <vector>
15
16namespace esphome {
17#ifdef USE_WEBSERVER
18namespace web_server {
19class WebServer;
20class ListEntitiesIterator;
21}; // namespace web_server
22#endif
23namespace web_server_idf {
24
26 public:
27 AsyncWebParameter(std::string name, std::string value) : name_(std::move(name)), value_(std::move(value)) {}
28 const std::string &name() const { return this->name_; }
29 const std::string &value() const { return this->value_; }
30
31 protected:
32 std::string name_;
33 std::string value_;
34};
35
37
39 public:
42
43 // NOLINTNEXTLINE(readability-identifier-naming)
44 void addHeader(const char *name, const char *value);
45
46 virtual const char *get_content_data() const = 0;
47 virtual size_t get_content_size() const = 0;
48
49 protected:
51};
52
54 public:
56
57 const char *get_content_data() const override { return nullptr; };
58 size_t get_content_size() const override { return 0; };
59};
60
62 public:
64 : AsyncWebServerResponse(req), content_(std::move(content)) {}
65
66 const char *get_content_data() const override { return this->content_.c_str(); };
67 size_t get_content_size() const override { return this->content_.size(); };
68
69 protected:
70 std::string content_;
71};
72
74 public:
76
77 const char *get_content_data() const override { return this->content_.c_str(); };
78 size_t get_content_size() const override { return this->content_.size(); };
79
80 void print(const char *str) { this->content_.append(str); }
81 void print(const std::string &str) { this->content_.append(str); }
82 void print(float value);
83 void printf(const char *fmt, ...) __attribute__((format(printf, 2, 3)));
84
85 protected:
86 std::string content_;
87};
88
90 public:
91 AsyncWebServerResponseProgmem(const AsyncWebServerRequest *req, const uint8_t *data, const size_t size)
92 : AsyncWebServerResponse(req), data_(data), size_(size) {}
93
94 const char *get_content_data() const override { return reinterpret_cast<const char *>(this->data_); };
95 size_t get_content_size() const override { return this->size_; };
96
97 protected:
98 const uint8_t *data_;
99 size_t size_;
100};
101
103 friend class AsyncWebServer;
104
105 public:
107
108 http_method method() const { return static_cast<http_method>(this->req_->method); }
109 std::string url() const;
110 std::string host() const;
111 // NOLINTNEXTLINE(readability-identifier-naming)
112 size_t contentLength() const { return this->req_->content_len; }
113
114#ifdef USE_WEBSERVER_AUTH
115 bool authenticate(const char *username, const char *password) const;
116 // NOLINTNEXTLINE(readability-identifier-naming)
117 void requestAuthentication(const char *realm = nullptr) const;
118#endif
119
120 void redirect(const std::string &url);
121
122 void send(AsyncWebServerResponse *response);
123 void send(int code, const char *content_type = nullptr, const char *content = nullptr);
124 // NOLINTNEXTLINE(readability-identifier-naming)
125 AsyncWebServerResponse *beginResponse(int code, const char *content_type) {
126 auto *res = new AsyncWebServerResponseEmpty(this); // NOLINT(cppcoreguidelines-owning-memory)
127 this->init_response_(res, code, content_type);
128 return res;
129 }
130 // NOLINTNEXTLINE(readability-identifier-naming)
131 AsyncWebServerResponse *beginResponse(int code, const char *content_type, const std::string &content) {
132 auto *res = new AsyncWebServerResponseContent(this, content); // NOLINT(cppcoreguidelines-owning-memory)
133 this->init_response_(res, code, content_type);
134 return res;
135 }
136 // NOLINTNEXTLINE(readability-identifier-naming)
137 AsyncWebServerResponse *beginResponse(int code, const char *content_type, const uint8_t *data,
138 const size_t data_size) {
139 auto *res = new AsyncWebServerResponseProgmem(this, data, data_size); // NOLINT(cppcoreguidelines-owning-memory)
140 this->init_response_(res, code, content_type);
141 return res;
142 }
143 // NOLINTNEXTLINE(readability-identifier-naming)
144 AsyncResponseStream *beginResponseStream(const char *content_type) {
145 auto *res = new AsyncResponseStream(this); // NOLINT(cppcoreguidelines-owning-memory)
146 this->init_response_(res, 200, content_type);
147 return res;
148 }
149
150 // NOLINTNEXTLINE(readability-identifier-naming)
151 bool hasParam(const std::string &name) { return this->getParam(name) != nullptr; }
152 // NOLINTNEXTLINE(readability-identifier-naming)
153 AsyncWebParameter *getParam(const std::string &name);
154
155 // NOLINTNEXTLINE(readability-identifier-naming)
156 bool hasArg(const char *name) { return this->hasParam(name); }
157 std::string arg(const std::string &name) {
158 auto *param = this->getParam(name);
159 if (param) {
160 return param->value();
161 }
162 return {};
163 }
164
165 operator httpd_req_t *() const { return this->req_; }
166 optional<std::string> get_header(const char *name) const;
167 // NOLINTNEXTLINE(readability-identifier-naming)
168 bool hasHeader(const char *name) const;
169
170 protected:
171 httpd_req_t *req_;
173 // Use vector instead of map/unordered_map: most requests have 0-3 params, so linear search
174 // is faster than tree/hash overhead. AsyncWebParameter stores both name and value to avoid
175 // duplicate storage. Only successful lookups are cached to prevent cache pollution when
176 // handlers check for optional parameters that don't exist.
177 std::vector<AsyncWebParameter *> params_;
178 std::string post_query_;
179 AsyncWebServerRequest(httpd_req_t *req) : req_(req) {}
180 AsyncWebServerRequest(httpd_req_t *req, std::string post_query) : req_(req), post_query_(std::move(post_query)) {}
181 void init_response_(AsyncWebServerResponse *rsp, int code, const char *content_type);
182};
183
184class AsyncWebHandler;
185
187 public:
188 AsyncWebServer(uint16_t port) : port_(port){};
189 ~AsyncWebServer() { this->end(); }
190
191 // NOLINTNEXTLINE(readability-identifier-naming)
192 void onNotFound(std::function<void(AsyncWebServerRequest *request)> fn) { on_not_found_ = std::move(fn); }
193
194 void begin();
195 void end();
196
197 // NOLINTNEXTLINE(readability-identifier-naming)
199 this->handlers_.push_back(handler);
200 return *handler;
201 }
202
203 protected:
204 uint16_t port_{};
205 httpd_handle_t server_{};
206 static esp_err_t request_handler(httpd_req_t *r);
207 static esp_err_t request_post_handler(httpd_req_t *r);
208 esp_err_t request_handler_(AsyncWebServerRequest *request) const;
209#ifdef USE_WEBSERVER_OTA
210 esp_err_t handle_multipart_upload_(httpd_req_t *r, const char *content_type);
211#endif
212 std::vector<AsyncWebHandler *> handlers_;
213 std::function<void(AsyncWebServerRequest *request)> on_not_found_{};
214};
215
217 public:
218 virtual ~AsyncWebHandler() {}
219 // NOLINTNEXTLINE(readability-identifier-naming)
220 virtual bool canHandle(AsyncWebServerRequest *request) const { return false; }
221 // NOLINTNEXTLINE(readability-identifier-naming)
222 virtual void handleRequest(AsyncWebServerRequest *request) {}
223 // NOLINTNEXTLINE(readability-identifier-naming)
224 virtual void handleUpload(AsyncWebServerRequest *request, const std::string &filename, size_t index, uint8_t *data,
225 size_t len, bool final) {}
226 // NOLINTNEXTLINE(readability-identifier-naming)
227 virtual void handleBody(AsyncWebServerRequest *request, uint8_t *data, size_t len, size_t index, size_t total) {}
228 // NOLINTNEXTLINE(readability-identifier-naming)
229 virtual bool isRequestHandlerTrivial() const { return true; }
230};
231
232#ifdef USE_WEBSERVER
233class AsyncEventSource;
235
237
238/*
239 This class holds a pointer to the source component that wants to publish a state event, and a pointer to a function
240 that will lazily generate that event. The two pointers allow dedup in the deferred queue if multiple publishes for
241 the same component are backed up, and take up only 8 bytes of memory. The entry in the deferred queue (a
242 std::vector) is the DeferredEvent instance itself (not a pointer to one elsewhere in heap) so still only 8 bytes per
243 entry (and no heap fragmentation). Even 100 backed up events (you'd have to have at least 100 sensors publishing
244 because of dedup) would take up only 0.8 kB.
245*/
248
249 protected:
250 void *source_;
252
253 public:
254 DeferredEvent(void *source, message_generator_t *message_generator)
255 : source_(source), message_generator_(message_generator) {}
256 bool operator==(const DeferredEvent &test) const {
257 return (source_ == test.source_ && message_generator_ == test.message_generator_);
258 }
259} __attribute__((packed));
260
262 friend class AsyncEventSource;
263
264 public:
265 bool try_send_nodefer(const char *message, const char *event = nullptr, uint32_t id = 0, uint32_t reconnect = 0);
266 void deferrable_send_state(void *source, const char *event_type, message_generator_t *message_generator);
267 void loop();
268
269 protected:
272
273 void deq_push_back_with_dedup_(void *source, message_generator_t *message_generator);
274 void process_deferred_queue_();
275 void process_buffer_();
276
277 static void destroy(void *p);
279 httpd_handle_t hd_{};
280 std::atomic<int> fd_{};
281 std::vector<DeferredEvent> deferred_queue_;
283 std::unique_ptr<esphome::web_server::ListEntitiesIterator> entities_iterator_;
284 std::string event_buffer_{""};
286 uint16_t consecutive_send_failures_{0};
287 static constexpr uint16_t MAX_CONSECUTIVE_SEND_FAILURES = 2500; // ~20 seconds at 125Hz loop rate
289
291
294 using connect_handler_t = std::function<void(AsyncEventSourceClient *)>;
295
296 public:
297 AsyncEventSource(std::string url, esphome::web_server::WebServer *ws) : url_(std::move(url)), web_server_(ws) {}
298 ~AsyncEventSource() override;
299
300 // NOLINTNEXTLINE(readability-identifier-naming)
301 bool canHandle(AsyncWebServerRequest *request) const override {
302 return request->method() == HTTP_GET && request->url() == this->url_;
303 }
304 // NOLINTNEXTLINE(readability-identifier-naming)
305 void handleRequest(AsyncWebServerRequest *request) override;
306 // NOLINTNEXTLINE(readability-identifier-naming)
307 void onConnect(connect_handler_t cb) { this->on_connect_ = std::move(cb); }
308
309 void try_send_nodefer(const char *message, const char *event = nullptr, uint32_t id = 0, uint32_t reconnect = 0);
310 void deferrable_send_state(void *source, const char *event_type, message_generator_t *message_generator);
311 void loop();
312 bool empty() { return this->count() == 0; }
313
314 size_t count() const { return this->sessions_.size(); }
315
316 protected:
317 std::string url_;
318 std::set<AsyncEventSourceResponse *> sessions_;
319 connect_handler_t on_connect_{};
321};
322#endif // USE_WEBSERVER
323
326#ifdef USE_WEBSERVER
328#endif
329
330 public:
331 // NOLINTNEXTLINE(readability-identifier-naming)
332 void addHeader(const char *name, const char *value) { this->headers_.emplace_back(name, value); }
333
334 // NOLINTNEXTLINE(readability-identifier-naming)
335 static DefaultHeaders &Instance();
336
337 protected:
338 std::vector<std::pair<std::string, std::string>> headers_;
339};
340
341} // namespace web_server_idf
342} // namespace esphome
343
344using namespace esphome::web_server_idf; // NOLINT(google-global-names-in-headers)
345
346#endif // !defined(USE_ESP32)
This class allows users to create a web server with their ESP nodes.
Definition web_server.h:166
AsyncEventSource(std::string url, esphome::web_server::WebServer *ws)
std::set< AsyncEventSourceResponse * > sessions_
esphome::web_server::WebServer * web_server_
bool canHandle(AsyncWebServerRequest *request) const override
esphome::web_server::WebServer * web_server_
std::unique_ptr< esphome::web_server::ListEntitiesIterator > entities_iterator_
AsyncResponseStream(const AsyncWebServerRequest *req)
void printf(const char *fmt,...) __attribute__((format(printf
const char * get_content_data() const override
virtual bool canHandle(AsyncWebServerRequest *request) const
virtual void handleRequest(AsyncWebServerRequest *request)
virtual void handleUpload(AsyncWebServerRequest *request, const std::string &filename, size_t index, uint8_t *data, size_t len, bool final)
virtual void handleBody(AsyncWebServerRequest *request, uint8_t *data, size_t len, size_t index, size_t total)
AsyncWebParameter(std::string name, std::string value)
std::vector< AsyncWebHandler * > handlers_
AsyncWebHandler & addHandler(AsyncWebHandler *handler)
void onNotFound(std::function< void(AsyncWebServerRequest *request)> fn)
AsyncWebServerResponse * beginResponse(int code, const char *content_type, const uint8_t *data, const size_t data_size)
AsyncWebServerResponse * beginResponse(int code, const char *content_type, const std::string &content)
std::string arg(const std::string &name)
AsyncWebServerResponse * beginResponse(int code, const char *content_type)
AsyncResponseStream * beginResponseStream(const char *content_type)
AsyncWebServerRequest(httpd_req_t *req, std::string post_query)
std::vector< AsyncWebParameter * > params_
AsyncWebServerResponseContent(const AsyncWebServerRequest *req, std::string content)
AsyncWebServerResponseEmpty(const AsyncWebServerRequest *req)
virtual const char * get_content_data() const =0
AsyncWebServerResponse(const AsyncWebServerRequest *req)
void addHeader(const char *name, const char *value)
AsyncWebServerResponseProgmem(const AsyncWebServerRequest *req, const uint8_t *data, const size_t size)
std::vector< std::pair< std::string, std::string > > headers_
void addHeader(const char *name, const char *value)
const char * message
Definition component.cpp:38
void loop()
std::string(esphome::web_server::WebServer *, void *) message_generator_t
class esphome::web_server_idf::AsyncEventSourceResponse __attribute__
Providing packet encoding functions for exchanging data with a remote host.
Definition a01nyub.cpp:7
bool operator==(const DeferredEvent &test) const
DeferredEvent(void *source, message_generator_t *message_generator)
uint8_t end[39]
Definition sun_gtil2.cpp:17
uint32_t len
std::string print()
message_generator_t * message_generator_
Definition web_server.h:4
void * source_
Definition web_server.h:3
friend class AsyncEventSourceResponse