ESPHome  2024.4.1
http_request.cpp
Go to the documentation of this file.
1 #ifdef USE_ARDUINO
2 
3 #include "http_request.h"
4 #include "esphome/core/defines.h"
5 #include "esphome/core/log.h"
7 
8 namespace esphome {
9 namespace http_request {
10 
11 static const char *const TAG = "http_request";
12 
14  ESP_LOGCONFIG(TAG, "HTTP Request:");
15  ESP_LOGCONFIG(TAG, " Timeout: %ums", this->timeout_);
16  ESP_LOGCONFIG(TAG, " User-Agent: %s", this->useragent_);
17  ESP_LOGCONFIG(TAG, " Follow Redirects: %d", this->follow_redirects_);
18  ESP_LOGCONFIG(TAG, " Redirect limit: %d", this->redirect_limit_);
19 }
20 
21 void HttpRequestComponent::set_url(std::string url) {
22  this->url_ = std::move(url);
23  this->secure_ = this->url_.compare(0, 6, "https:") == 0;
24 
25  if (!this->last_url_.empty() && this->url_ != this->last_url_) {
26  // Close connection if url has been changed
27  this->client_.setReuse(false);
28  this->client_.end();
29  }
30  this->client_.setReuse(true);
31 }
32 
33 void HttpRequestComponent::send(const std::vector<HttpRequestResponseTrigger *> &response_triggers) {
34  if (!network::is_connected()) {
35  this->client_.end();
36  this->status_set_warning();
37  ESP_LOGW(TAG, "HTTP Request failed; Not connected to network");
38  return;
39  }
40 
41  bool begin_status = false;
42  const String url = this->url_.c_str();
43 #if defined(USE_ESP32) || (defined(USE_ESP8266) && USE_ARDUINO_VERSION_CODE >= VERSION_CODE(2, 6, 0))
44 #if defined(USE_ESP32) || USE_ARDUINO_VERSION_CODE >= VERSION_CODE(2, 7, 0)
45  if (this->follow_redirects_) {
46  this->client_.setFollowRedirects(HTTPC_FORCE_FOLLOW_REDIRECTS);
47  } else {
48  this->client_.setFollowRedirects(HTTPC_DISABLE_FOLLOW_REDIRECTS);
49  }
50 #else
51  this->client_.setFollowRedirects(this->follow_redirects_);
52 #endif
53  this->client_.setRedirectLimit(this->redirect_limit_);
54 #endif
55 #if defined(USE_ESP32)
56  begin_status = this->client_.begin(url);
57 #elif defined(USE_ESP8266)
58  begin_status = this->client_.begin(*this->get_wifi_client_(), url);
59 #endif
60 
61  if (!begin_status) {
62  this->client_.end();
63  this->status_set_warning();
64  ESP_LOGW(TAG, "HTTP Request failed at the begin phase. Please check the configuration");
65  return;
66  }
67 
68  this->client_.setTimeout(this->timeout_);
69 #if defined(USE_ESP32)
70  this->client_.setConnectTimeout(this->timeout_);
71 #endif
72  if (this->useragent_ != nullptr) {
73  this->client_.setUserAgent(this->useragent_);
74  }
75  for (const auto &header : this->headers_) {
76  this->client_.addHeader(header.name, header.value, false, true);
77  }
78 
79  uint32_t start_time = millis();
80  int http_code = this->client_.sendRequest(this->method_, this->body_.c_str());
81  uint32_t duration = millis() - start_time;
82  for (auto *trigger : response_triggers)
83  trigger->process(http_code, duration);
84 
85  if (http_code < 0) {
86  ESP_LOGW(TAG, "HTTP Request failed; URL: %s; Error: %s; Duration: %u ms", this->url_.c_str(),
87  HTTPClient::errorToString(http_code).c_str(), duration);
88  this->status_set_warning();
89  return;
90  }
91 
92  if (http_code < 200 || http_code >= 300) {
93  ESP_LOGW(TAG, "HTTP Request failed; URL: %s; Code: %d; Duration: %u ms", this->url_.c_str(), http_code, duration);
94  this->status_set_warning();
95  return;
96  }
97 
98  this->status_clear_warning();
99  ESP_LOGD(TAG, "HTTP Request completed; URL: %s; Code: %d; Duration: %u ms", this->url_.c_str(), http_code, duration);
100 }
101 
102 #ifdef USE_ESP8266
103 std::shared_ptr<WiFiClient> HttpRequestComponent::get_wifi_client_() {
104 #ifdef USE_HTTP_REQUEST_ESP8266_HTTPS
105  if (this->secure_) {
106  if (this->wifi_client_secure_ == nullptr) {
107  this->wifi_client_secure_ = std::make_shared<BearSSL::WiFiClientSecure>();
108  this->wifi_client_secure_->setInsecure();
109  this->wifi_client_secure_->setBufferSizes(512, 512);
110  }
111  return this->wifi_client_secure_;
112  }
113 #endif
114 
115  if (this->wifi_client_ == nullptr) {
116  this->wifi_client_ = std::make_shared<WiFiClient>();
117  }
118  return this->wifi_client_;
119 }
120 #endif
121 
123  this->last_url_ = this->url_;
124  this->client_.end();
125 }
126 
128 #if defined(ESP32)
129  // The static variable is here because HTTPClient::getString() returns a String on ESP32,
130  // and we need something to keep a buffer alive.
131  static String str;
132 #else
133  // However on ESP8266, HTTPClient::getString() returns a String& to a member variable.
134  // Leaving this the default so that any new platform either doesn't copy, or encounters a compilation error.
135  auto &
136 #endif
137  str = this->client_.getString();
138  return str.c_str();
139 }
140 
141 } // namespace http_request
142 } // namespace esphome
143 
144 #endif // USE_ARDUINO
void status_set_warning(const char *message="unspecified")
Definition: component.cpp:151
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
std::shared_ptr< BearSSL::WiFiClientSecure > wifi_client_secure_
Definition: http_request.h:71
void status_clear_warning()
Definition: component.cpp:166
void send(const std::vector< HttpRequestResponseTrigger *> &response_triggers)
std::shared_ptr< WiFiClient > get_wifi_client_()
This is a workaround until we can figure out a way to get the tflite-micro idf component code availab...
Definition: a01nyub.cpp:7
std::shared_ptr< WiFiClient > wifi_client_
Definition: http_request.h:69