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