ESPHome 2025.12.0-dev
Loading...
Searching...
No Matches
http_request_arduino.cpp
Go to the documentation of this file.
2
3#ifdef USE_ARDUINO
4
7
10#include "esphome/core/log.h"
11
12namespace esphome {
13namespace http_request {
14
15static const char *const TAG = "http_request.arduino";
16
17std::shared_ptr<HttpContainer> HttpRequestArduino::perform(const std::string &url, const std::string &method,
18 const std::string &body,
19 const std::list<Header> &request_headers,
20 const std::set<std::string> &collect_headers) {
21 if (!network::is_connected()) {
22 this->status_momentary_error("failed", 1000);
23 ESP_LOGW(TAG, "HTTP Request failed; Not connected to network");
24 return nullptr;
25 }
26
27 std::shared_ptr<HttpContainerArduino> container = std::make_shared<HttpContainerArduino>();
28 container->set_parent(this);
29
30 const uint32_t start = millis();
31
32 bool secure = url.find("https:") != std::string::npos;
33 container->set_secure(secure);
34
36
37 if (this->follow_redirects_) {
38 container->client_.setFollowRedirects(HTTPC_FORCE_FOLLOW_REDIRECTS);
39 container->client_.setRedirectLimit(this->redirect_limit_);
40 } else {
41 container->client_.setFollowRedirects(HTTPC_DISABLE_FOLLOW_REDIRECTS);
42 }
43
44#if defined(USE_ESP8266)
45 std::unique_ptr<WiFiClient> stream_ptr;
46#ifdef USE_HTTP_REQUEST_ESP8266_HTTPS
47 if (secure) {
48 ESP_LOGV(TAG, "ESP8266 HTTPS connection with WiFiClientSecure");
49 stream_ptr = std::make_unique<WiFiClientSecure>();
50 WiFiClientSecure *secure_client = static_cast<WiFiClientSecure *>(stream_ptr.get());
51 secure_client->setBufferSizes(512, 512);
52 secure_client->setInsecure();
53 } else {
54 stream_ptr = std::make_unique<WiFiClient>();
55 }
56#else
57 ESP_LOGV(TAG, "ESP8266 HTTP connection with WiFiClient");
58 if (secure) {
59 ESP_LOGE(TAG, "Can't use HTTPS connection with esp8266_disable_ssl_support");
60 return nullptr;
61 }
62 stream_ptr = std::make_unique<WiFiClient>();
63#endif // USE_HTTP_REQUEST_ESP8266_HTTPS
64
65#if USE_ARDUINO_VERSION_CODE >= VERSION_CODE(3, 1, 0) // && USE_ARDUINO_VERSION_CODE < VERSION_CODE(?, ?, ?)
66 if (!secure) {
67 ESP_LOGW(TAG, "Using HTTP on Arduino version >= 3.1 is **very** slow. Consider setting framework version to 3.0.2 "
68 "in your YAML, or use HTTPS");
69 }
70#endif // USE_ARDUINO_VERSION_CODE
71 bool status = container->client_.begin(*stream_ptr, url.c_str());
72
73#elif defined(USE_RP2040)
74 if (secure) {
75 container->client_.setInsecure();
76 }
77 bool status = container->client_.begin(url.c_str());
78#elif defined(USE_ESP32)
79 bool status = container->client_.begin(url.c_str());
80#endif
81
82 App.feed_wdt();
83
84 if (!status) {
85 ESP_LOGW(TAG, "HTTP Request failed; URL: %s", url.c_str());
86 container->end();
87 this->status_momentary_error("failed", 1000);
88 return nullptr;
89 }
90
91 container->client_.setReuse(true);
92 container->client_.setTimeout(this->timeout_);
93#if defined(USE_ESP32)
94 container->client_.setConnectTimeout(this->timeout_);
95#endif
96
97 if (this->useragent_ != nullptr) {
98 container->client_.setUserAgent(this->useragent_);
99 }
100 for (const auto &header : request_headers) {
101 container->client_.addHeader(header.name.c_str(), header.value.c_str(), false, true);
102 }
103
104 // returned needed headers must be collected before the requests
105 const char *header_keys[collect_headers.size()];
106 int index = 0;
107 for (auto const &header_name : collect_headers) {
108 header_keys[index++] = header_name.c_str();
109 }
110 container->client_.collectHeaders(header_keys, index);
111
112 App.feed_wdt();
113 container->status_code = container->client_.sendRequest(method.c_str(), body.c_str());
114 App.feed_wdt();
115 if (container->status_code < 0) {
116 ESP_LOGW(TAG, "HTTP Request failed; URL: %s; Error: %s", url.c_str(),
117 HTTPClient::errorToString(container->status_code).c_str());
118 this->status_momentary_error("failed", 1000);
119 container->end();
120 return nullptr;
121 }
122
123 if (!is_success(container->status_code)) {
124 ESP_LOGE(TAG, "HTTP Request failed; URL: %s; Code: %d", url.c_str(), container->status_code);
125 this->status_momentary_error("failed", 1000);
126 // Still return the container, so it can be used to get the status code and error message
127 }
128
129 container->response_headers_ = {};
130 auto header_count = container->client_.headers();
131 for (int i = 0; i < header_count; i++) {
132 const std::string header_name = str_lower_case(container->client_.headerName(i).c_str());
133 if (collect_headers.count(header_name) > 0) {
134 std::string header_value = container->client_.header(i).c_str();
135 ESP_LOGD(TAG, "Received response header, name: %s, value: %s", header_name.c_str(), header_value.c_str());
136 container->response_headers_[header_name].push_back(header_value);
137 }
138 }
139
140 int content_length = container->client_.getSize();
141 ESP_LOGD(TAG, "Content-Length: %d", content_length);
142 container->content_length = (size_t) content_length;
143 container->duration_ms = millis() - start;
144
145 return container;
146}
147
148int HttpContainerArduino::read(uint8_t *buf, size_t max_len) {
149 const uint32_t start = millis();
150 watchdog::WatchdogManager wdm(this->parent_->get_watchdog_timeout());
151
152 WiFiClient *stream_ptr = this->client_.getStreamPtr();
153 if (stream_ptr == nullptr) {
154 ESP_LOGE(TAG, "Stream pointer vanished!");
155 return -1;
156 }
157
158 int available_data = stream_ptr->available();
159 int bufsize = std::min(max_len, std::min(this->content_length - this->bytes_read_, (size_t) available_data));
160
161 if (bufsize == 0) {
162 this->duration_ms += (millis() - start);
163 return 0;
164 }
165
166 App.feed_wdt();
167 int read_len = stream_ptr->readBytes(buf, bufsize);
168 this->bytes_read_ += read_len;
169
170 this->duration_ms += (millis() - start);
171
172 return read_len;
173}
174
176 watchdog::WatchdogManager wdm(this->parent_->get_watchdog_timeout());
177 this->client_.end();
178}
179
180} // namespace http_request
181} // namespace esphome
182
183#endif // USE_ARDUINO
uint8_t status
Definition bl0942.h:8
void feed_wdt(uint32_t time=0)
void status_momentary_error(const std::string &name, uint32_t length=5000)
int read(uint8_t *buf, size_t max_len) override
std::shared_ptr< HttpContainer > perform(const std::string &url, const std::string &method, const std::string &body, const std::list< Header > &request_headers, const std::set< std::string > &collect_headers) override
std::shared_ptr< HttpContainer > start(const std::string &url, const std::string &method, const std::string &body, const std::list< Header > &request_headers)
bool is_success(int const status)
Checks if the given HTTP status code indicates a successful request.
bool is_connected()
Return whether the node is connected to the network (through wifi, eth, ...)
Definition util.cpp:26
Providing packet encoding functions for exchanging data with a remote host.
Definition a01nyub.cpp:7
std::string str_lower_case(const std::string &str)
Convert the string to lower case.
Definition helpers.cpp:189
uint32_t IRAM_ATTR HOT millis()
Definition core.cpp:30
Application App
Global storage of Application pointer - only one Application can exist.