Compare commits
12 Commits
dev
...
jesserockz
Author | SHA1 | Date | |
---|---|---|---|
|
27d7d10d94 | ||
|
ba96647fba | ||
|
7c7b508620 | ||
|
1c44538fc9 | ||
|
6639121a5b | ||
|
b3d4b1e2ee | ||
|
bcf98471cf | ||
|
0be672179d | ||
|
8491ec9a84 | ||
|
a3119e8d83 | ||
|
f36d0c9b33 | ||
|
aba8d63fe3 |
@ -12,17 +12,24 @@ from esphome.const import (
|
||||
CONF_ESP8266_DISABLE_SSL_SUPPORT,
|
||||
)
|
||||
from esphome.core import Lambda, CORE
|
||||
from esphome.components import esp32
|
||||
|
||||
DEPENDENCIES = ["network"]
|
||||
AUTO_LOAD = ["json"]
|
||||
|
||||
http_request_ns = cg.esphome_ns.namespace("http_request")
|
||||
HttpRequestComponent = http_request_ns.class_("HttpRequestComponent", cg.Component)
|
||||
HttpRequestArduino = http_request_ns.class_("HttpRequestArduino", HttpRequestComponent)
|
||||
HttpRequestIDF = http_request_ns.class_("HttpRequestIDF", HttpRequestComponent)
|
||||
|
||||
HttpResponse = http_request_ns.class_("HttpResponse")
|
||||
|
||||
HttpRequestSendAction = http_request_ns.class_(
|
||||
"HttpRequestSendAction", automation.Action
|
||||
)
|
||||
HttpRequestResponseTrigger = http_request_ns.class_(
|
||||
"HttpRequestResponseTrigger", automation.Trigger
|
||||
"HttpRequestResponseTrigger",
|
||||
automation.Trigger.template(int, HttpResponse.operator("ref")),
|
||||
)
|
||||
|
||||
CONF_HEADERS = "headers"
|
||||
@ -33,6 +40,7 @@ CONF_VERIFY_SSL = "verify_ssl"
|
||||
CONF_ON_RESPONSE = "on_response"
|
||||
CONF_FOLLOW_REDIRECTS = "follow_redirects"
|
||||
CONF_REDIRECT_LIMIT = "redirect_limit"
|
||||
CONF_CAPTURE_RESPONSE = "capture_response"
|
||||
|
||||
|
||||
def validate_url(value):
|
||||
@ -68,10 +76,18 @@ def validate_secure_url(config):
|
||||
return config
|
||||
|
||||
|
||||
def _declare_request_class(value):
|
||||
if CORE.using_esp_idf:
|
||||
return cv.declare_id(HttpRequestIDF)(value)
|
||||
if CORE.is_esp8266 or CORE.is_esp32:
|
||||
return cv.declare_id(HttpRequestArduino)(value)
|
||||
return NotImplementedError
|
||||
|
||||
|
||||
CONFIG_SCHEMA = cv.All(
|
||||
cv.Schema(
|
||||
{
|
||||
cv.GenerateID(): cv.declare_id(HttpRequestComponent),
|
||||
cv.GenerateID(): _declare_request_class,
|
||||
cv.Optional(CONF_USERAGENT, "ESPHome"): cv.string,
|
||||
cv.Optional(CONF_FOLLOW_REDIRECTS, True): cv.boolean,
|
||||
cv.Optional(CONF_REDIRECT_LIMIT, 3): cv.int_,
|
||||
@ -86,6 +102,7 @@ CONFIG_SCHEMA = cv.All(
|
||||
cv.require_framework_version(
|
||||
esp8266_arduino=cv.Version(2, 5, 1),
|
||||
esp32_arduino=cv.Version(0, 0, 0),
|
||||
esp_idf=cv.Version(0, 0, 0),
|
||||
),
|
||||
)
|
||||
|
||||
@ -101,8 +118,14 @@ async def to_code(config):
|
||||
cg.add_define("USE_HTTP_REQUEST_ESP8266_HTTPS")
|
||||
|
||||
if CORE.is_esp32:
|
||||
cg.add_library("WiFiClientSecure", None)
|
||||
cg.add_library("HTTPClient", None)
|
||||
if CORE.using_esp_idf:
|
||||
esp32.add_idf_sdkconfig_option("CONFIG_ESP_TLS_INSECURE", True)
|
||||
esp32.add_idf_sdkconfig_option(
|
||||
"CONFIG_ESP_TLS_SKIP_SERVER_CERT_VERIFY", True
|
||||
)
|
||||
else:
|
||||
cg.add_library("WiFiClientSecure", None)
|
||||
cg.add_library("HTTPClient", None)
|
||||
if CORE.is_esp8266:
|
||||
cg.add_library("ESP8266HTTPClient", None)
|
||||
|
||||
@ -117,6 +140,7 @@ HTTP_REQUEST_ACTION_SCHEMA = cv.Schema(
|
||||
cv.Schema({cv.string: cv.templatable(cv.string)})
|
||||
),
|
||||
cv.Optional(CONF_VERIFY_SSL, default=True): cv.boolean,
|
||||
cv.Optional(CONF_CAPTURE_RESPONSE, default=False): cv.boolean,
|
||||
cv.Optional(CONF_ON_RESPONSE): automation.validate_automation(
|
||||
{cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(HttpRequestResponseTrigger)}
|
||||
),
|
||||
@ -173,6 +197,7 @@ async def http_request_action_to_code(config, action_id, template_arg, args):
|
||||
template_ = await cg.templatable(config[CONF_URL], args, cg.std_string)
|
||||
cg.add(var.set_url(template_))
|
||||
cg.add(var.set_method(config[CONF_METHOD]))
|
||||
cg.add(var.set_capture_response(config[CONF_CAPTURE_RESPONSE]))
|
||||
if CONF_BODY in config:
|
||||
template_ = await cg.templatable(config[CONF_BODY], args, cg.std_string)
|
||||
cg.add(var.set_body(template_))
|
||||
@ -195,6 +220,13 @@ async def http_request_action_to_code(config, action_id, template_arg, args):
|
||||
for conf in config.get(CONF_ON_RESPONSE, []):
|
||||
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID])
|
||||
cg.add(var.register_response_trigger(trigger))
|
||||
await automation.build_automation(trigger, [(int, "status_code")], conf)
|
||||
await automation.build_automation(
|
||||
trigger,
|
||||
[
|
||||
(int, "status_code"),
|
||||
(HttpResponse.operator("ref"), "response"),
|
||||
],
|
||||
conf,
|
||||
)
|
||||
|
||||
return var
|
||||
|
@ -1,15 +1,14 @@
|
||||
#ifdef USE_ARDUINO
|
||||
|
||||
#include "http_request.h"
|
||||
#include "esphome/core/defines.h"
|
||||
|
||||
#include "esphome/core/log.h"
|
||||
#include "esphome/components/network/util.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace http_request {
|
||||
|
||||
static const char *const TAG = "http_request";
|
||||
|
||||
HttpRequestComponent::HttpRequestComponent() { global_http_request = this; }
|
||||
|
||||
void HttpRequestComponent::dump_config() {
|
||||
ESP_LOGCONFIG(TAG, "HTTP Request:");
|
||||
ESP_LOGCONFIG(TAG, " Timeout: %ums", this->timeout_);
|
||||
@ -18,122 +17,7 @@ void HttpRequestComponent::dump_config() {
|
||||
ESP_LOGCONFIG(TAG, " Redirect limit: %d", this->redirect_limit_);
|
||||
}
|
||||
|
||||
void HttpRequestComponent::set_url(std::string url) {
|
||||
this->url_ = std::move(url);
|
||||
this->secure_ = this->url_.compare(0, 6, "https:") == 0;
|
||||
|
||||
if (!this->last_url_.empty() && this->url_ != this->last_url_) {
|
||||
// Close connection if url has been changed
|
||||
this->client_.setReuse(false);
|
||||
this->client_.end();
|
||||
}
|
||||
this->client_.setReuse(true);
|
||||
}
|
||||
|
||||
void HttpRequestComponent::send(const std::vector<HttpRequestResponseTrigger *> &response_triggers) {
|
||||
if (!network::is_connected()) {
|
||||
this->client_.end();
|
||||
this->status_set_warning();
|
||||
ESP_LOGW(TAG, "HTTP Request failed; Not connected to network");
|
||||
return;
|
||||
}
|
||||
|
||||
bool begin_status = false;
|
||||
const String url = this->url_.c_str();
|
||||
#if defined(USE_ESP32) || (defined(USE_ESP8266) && USE_ARDUINO_VERSION_CODE >= VERSION_CODE(2, 6, 0))
|
||||
#if defined(USE_ESP32) || USE_ARDUINO_VERSION_CODE >= VERSION_CODE(2, 7, 0)
|
||||
if (this->follow_redirects_) {
|
||||
this->client_.setFollowRedirects(HTTPC_FORCE_FOLLOW_REDIRECTS);
|
||||
} else {
|
||||
this->client_.setFollowRedirects(HTTPC_DISABLE_FOLLOW_REDIRECTS);
|
||||
}
|
||||
#else
|
||||
this->client_.setFollowRedirects(this->follow_redirects_);
|
||||
#endif
|
||||
this->client_.setRedirectLimit(this->redirect_limit_);
|
||||
#endif
|
||||
#if defined(USE_ESP32)
|
||||
begin_status = this->client_.begin(url);
|
||||
#elif defined(USE_ESP8266)
|
||||
begin_status = this->client_.begin(*this->get_wifi_client_(), url);
|
||||
#endif
|
||||
|
||||
if (!begin_status) {
|
||||
this->client_.end();
|
||||
this->status_set_warning();
|
||||
ESP_LOGW(TAG, "HTTP Request failed at the begin phase. Please check the configuration");
|
||||
return;
|
||||
}
|
||||
|
||||
this->client_.setTimeout(this->timeout_);
|
||||
if (this->useragent_ != nullptr) {
|
||||
this->client_.setUserAgent(this->useragent_);
|
||||
}
|
||||
for (const auto &header : this->headers_) {
|
||||
this->client_.addHeader(header.name, header.value, false, true);
|
||||
}
|
||||
|
||||
int http_code = this->client_.sendRequest(this->method_, this->body_.c_str());
|
||||
for (auto *trigger : response_triggers)
|
||||
trigger->process(http_code);
|
||||
|
||||
if (http_code < 0) {
|
||||
ESP_LOGW(TAG, "HTTP Request failed; URL: %s; Error: %s", this->url_.c_str(),
|
||||
HTTPClient::errorToString(http_code).c_str());
|
||||
this->status_set_warning();
|
||||
return;
|
||||
}
|
||||
|
||||
if (http_code < 200 || http_code >= 300) {
|
||||
ESP_LOGW(TAG, "HTTP Request failed; URL: %s; Code: %d", this->url_.c_str(), http_code);
|
||||
this->status_set_warning();
|
||||
return;
|
||||
}
|
||||
|
||||
this->status_clear_warning();
|
||||
ESP_LOGD(TAG, "HTTP Request completed; URL: %s; Code: %d", this->url_.c_str(), http_code);
|
||||
}
|
||||
|
||||
#ifdef USE_ESP8266
|
||||
std::shared_ptr<WiFiClient> HttpRequestComponent::get_wifi_client_() {
|
||||
#ifdef USE_HTTP_REQUEST_ESP8266_HTTPS
|
||||
if (this->secure_) {
|
||||
if (this->wifi_client_secure_ == nullptr) {
|
||||
this->wifi_client_secure_ = std::make_shared<BearSSL::WiFiClientSecure>();
|
||||
this->wifi_client_secure_->setInsecure();
|
||||
this->wifi_client_secure_->setBufferSizes(512, 512);
|
||||
}
|
||||
return this->wifi_client_secure_;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (this->wifi_client_ == nullptr) {
|
||||
this->wifi_client_ = std::make_shared<WiFiClient>();
|
||||
}
|
||||
return this->wifi_client_;
|
||||
}
|
||||
#endif
|
||||
|
||||
void HttpRequestComponent::close() {
|
||||
this->last_url_ = this->url_;
|
||||
this->client_.end();
|
||||
}
|
||||
|
||||
const char *HttpRequestComponent::get_string() {
|
||||
#if defined(ESP32)
|
||||
// The static variable is here because HTTPClient::getString() returns a String on ESP32,
|
||||
// and we need something to keep a buffer alive.
|
||||
static String str;
|
||||
#else
|
||||
// However on ESP8266, HTTPClient::getString() returns a String& to a member variable.
|
||||
// Leaving this the default so that any new platform either doesn't copy, or encounters a compilation error.
|
||||
auto &
|
||||
#endif
|
||||
str = this->client_.getString();
|
||||
return str.c_str();
|
||||
}
|
||||
HttpRequestComponent *global_http_request; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
|
||||
} // namespace http_request
|
||||
} // namespace esphome
|
||||
|
||||
#endif // USE_ARDUINO
|
||||
|
@ -1,25 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef USE_ARDUINO
|
||||
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include "esphome/components/json/json_util.h"
|
||||
#include "esphome/core/automation.h"
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/core/defines.h"
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <utility>
|
||||
#include <memory>
|
||||
|
||||
#ifdef USE_ESP32
|
||||
#include <HTTPClient.h>
|
||||
#endif
|
||||
#ifdef USE_ESP8266
|
||||
#include <ESP8266HTTPClient.h>
|
||||
#ifdef USE_HTTP_REQUEST_ESP8266_HTTPS
|
||||
#include <WiFiClientSecure.h>
|
||||
#endif
|
||||
#endif
|
||||
#include "esphome/core/helpers.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace http_request {
|
||||
@ -29,44 +18,48 @@ struct Header {
|
||||
const char *value;
|
||||
};
|
||||
|
||||
class HttpRequestResponseTrigger;
|
||||
struct HttpResponse {
|
||||
int status_code;
|
||||
int content_length;
|
||||
std::vector<char> data;
|
||||
};
|
||||
|
||||
class HttpRequestResponseTrigger : public Trigger<int, HttpResponse &> {
|
||||
public:
|
||||
void process(HttpResponse &response) { this->trigger(response.status_code, response); }
|
||||
};
|
||||
|
||||
class HttpRequestComponent : public Component {
|
||||
public:
|
||||
HttpRequestComponent();
|
||||
void dump_config() override;
|
||||
float get_setup_priority() const override { return setup_priority::AFTER_WIFI; }
|
||||
|
||||
void set_url(std::string url);
|
||||
void set_method(const char *method) { this->method_ = method; }
|
||||
void set_method(std::string method) { this->method_ = std::move(method); }
|
||||
void set_useragent(const char *useragent) { this->useragent_ = useragent; }
|
||||
void set_timeout(uint16_t timeout) { this->timeout_ = timeout; }
|
||||
void set_follow_redirects(bool follow_redirects) { this->follow_redirects_ = follow_redirects; }
|
||||
void set_redirect_limit(uint16_t limit) { this->redirect_limit_ = limit; }
|
||||
void set_body(const std::string &body) { this->body_ = body; }
|
||||
void set_headers(std::list<Header> headers) { this->headers_ = std::move(headers); }
|
||||
void send(const std::vector<HttpRequestResponseTrigger *> &response_triggers);
|
||||
void close();
|
||||
const char *get_string();
|
||||
void set_capture_response(bool capture_response) { this->capture_response_ = capture_response; }
|
||||
|
||||
bool get_capture_response() { return this->capture_response_; }
|
||||
|
||||
virtual void set_url(std::string url) = 0;
|
||||
virtual HttpResponse send() = 0;
|
||||
|
||||
protected:
|
||||
HTTPClient client_{};
|
||||
std::string url_;
|
||||
std::string last_url_;
|
||||
const char *method_;
|
||||
std::string method_;
|
||||
const char *useragent_{nullptr};
|
||||
bool secure_;
|
||||
bool follow_redirects_;
|
||||
bool capture_response_;
|
||||
uint16_t redirect_limit_;
|
||||
uint16_t timeout_{5000};
|
||||
std::string body_;
|
||||
std::list<Header> headers_;
|
||||
#ifdef USE_ESP8266
|
||||
std::shared_ptr<WiFiClient> wifi_client_;
|
||||
#ifdef USE_HTTP_REQUEST_ESP8266_HTTPS
|
||||
std::shared_ptr<BearSSL::WiFiClientSecure> wifi_client_secure_;
|
||||
#endif
|
||||
std::shared_ptr<WiFiClient> get_wifi_client_();
|
||||
#endif
|
||||
};
|
||||
|
||||
template<typename... Ts> class HttpRequestSendAction : public Action<Ts...> {
|
||||
@ -77,6 +70,7 @@ template<typename... Ts> class HttpRequestSendAction : public Action<Ts...> {
|
||||
TEMPLATABLE_VALUE(std::string, body)
|
||||
TEMPLATABLE_VALUE(const char *, useragent)
|
||||
TEMPLATABLE_VALUE(uint16_t, timeout)
|
||||
TEMPLATABLE_VALUE(bool, capture_response)
|
||||
|
||||
void add_header(const char *key, TemplatableValue<const char *, Ts...> value) { this->headers_.insert({key, value}); }
|
||||
|
||||
@ -89,6 +83,7 @@ template<typename... Ts> class HttpRequestSendAction : public Action<Ts...> {
|
||||
void play(Ts... x) override {
|
||||
this->parent_->set_url(this->url_.value(x...));
|
||||
this->parent_->set_method(this->method_.value(x...));
|
||||
this->parent_->set_capture_response(this->capture_response_.value(x...));
|
||||
if (this->body_.has_value()) {
|
||||
this->parent_->set_body(this->body_.value(x...));
|
||||
}
|
||||
@ -117,8 +112,10 @@ template<typename... Ts> class HttpRequestSendAction : public Action<Ts...> {
|
||||
}
|
||||
this->parent_->set_headers(headers);
|
||||
}
|
||||
this->parent_->send(this->response_triggers_);
|
||||
this->parent_->close();
|
||||
HttpResponse response = this->parent_->send();
|
||||
|
||||
for (auto *trigger : this->response_triggers_)
|
||||
trigger->process(response);
|
||||
}
|
||||
|
||||
protected:
|
||||
@ -136,12 +133,7 @@ template<typename... Ts> class HttpRequestSendAction : public Action<Ts...> {
|
||||
std::vector<HttpRequestResponseTrigger *> response_triggers_;
|
||||
};
|
||||
|
||||
class HttpRequestResponseTrigger : public Trigger<int> {
|
||||
public:
|
||||
void process(int status_code) { this->trigger(status_code); }
|
||||
};
|
||||
extern HttpRequestComponent *global_http_request; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
|
||||
} // namespace http_request
|
||||
} // namespace esphome
|
||||
|
||||
#endif // USE_ARDUINO
|
||||
|
129
esphome/components/http_request/http_request_arduino.cpp
Normal file
129
esphome/components/http_request/http_request_arduino.cpp
Normal file
@ -0,0 +1,129 @@
|
||||
#include "http_request_arduino.h"
|
||||
|
||||
#ifdef USE_ARDUINO
|
||||
|
||||
#include "esphome/components/network/util.h"
|
||||
#include "esphome/core/defines.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace http_request {
|
||||
|
||||
static const char *const TAG = "http_request.arduino";
|
||||
|
||||
void HttpRequestArduino::set_url(std::string url) {
|
||||
this->url_ = std::move(url);
|
||||
this->secure_ = this->url_.compare(0, 6, "https:") == 0;
|
||||
|
||||
if (!this->last_url_.empty() && this->url_ != this->last_url_) {
|
||||
// Close connection if url has been changed
|
||||
this->client_.setReuse(false);
|
||||
this->client_.end();
|
||||
}
|
||||
this->client_.setReuse(true);
|
||||
}
|
||||
|
||||
HttpResponse HttpRequestArduino::send() {
|
||||
if (!network::is_connected()) {
|
||||
this->client_.end();
|
||||
this->status_set_warning();
|
||||
ESP_LOGW(TAG, "HTTP Request failed; Not connected to network");
|
||||
return {-1, 0, {}};
|
||||
}
|
||||
|
||||
bool begin_status = false;
|
||||
const String url = this->url_.c_str();
|
||||
#if defined(USE_ESP32) || (defined(USE_ESP8266) && USE_ARDUINO_VERSION_CODE >= VERSION_CODE(2, 6, 0))
|
||||
#if defined(USE_ESP32) || USE_ARDUINO_VERSION_CODE >= VERSION_CODE(2, 7, 0)
|
||||
if (this->follow_redirects_) {
|
||||
this->client_.setFollowRedirects(HTTPC_FORCE_FOLLOW_REDIRECTS);
|
||||
} else {
|
||||
this->client_.setFollowRedirects(HTTPC_DISABLE_FOLLOW_REDIRECTS);
|
||||
}
|
||||
#else
|
||||
this->client_.setFollowRedirects(this->follow_redirects_);
|
||||
#endif
|
||||
this->client_.setRedirectLimit(this->redirect_limit_);
|
||||
#endif
|
||||
#if defined(USE_ESP32)
|
||||
begin_status = this->client_.begin(url);
|
||||
#elif defined(USE_ESP8266)
|
||||
begin_status = this->client_.begin(*this->get_wifi_client_(), url);
|
||||
#endif
|
||||
|
||||
if (!begin_status) {
|
||||
this->client_.end();
|
||||
this->status_set_warning();
|
||||
ESP_LOGW(TAG, "HTTP Request failed at the begin phase. Please check the configuration");
|
||||
return {-1, 0, {}};
|
||||
}
|
||||
|
||||
this->client_.setTimeout(this->timeout_);
|
||||
if (this->useragent_ != nullptr) {
|
||||
this->client_.setUserAgent(this->useragent_);
|
||||
}
|
||||
for (const auto &header : this->headers_) {
|
||||
this->client_.addHeader(header.name, header.value, false, true);
|
||||
}
|
||||
|
||||
int http_code = this->client_.sendRequest(this->method_.c_str(), this->body_.c_str());
|
||||
|
||||
HttpResponse response = {};
|
||||
|
||||
response.status_code = http_code;
|
||||
response.content_length = this->client_.getSize();
|
||||
|
||||
if (http_code < 0) {
|
||||
ESP_LOGW(TAG, "HTTP Request failed; URL: %s; Error: %s", this->url_.c_str(),
|
||||
HTTPClient::errorToString(http_code).c_str());
|
||||
this->status_set_warning();
|
||||
return {http_code, 0, {}};
|
||||
}
|
||||
if (this->capture_response_) {
|
||||
#ifdef USE_ESP32
|
||||
String str;
|
||||
#else
|
||||
auto &
|
||||
#endif
|
||||
str = this->client_.getString();
|
||||
response.data = std::vector<char>(str.c_str(), str.c_str() + str.length());
|
||||
}
|
||||
|
||||
if (http_code < 200 || http_code >= 300) {
|
||||
ESP_LOGW(TAG, "HTTP Request failed; URL: %s; Code: %d", this->url_.c_str(), http_code);
|
||||
this->status_set_warning();
|
||||
return response;
|
||||
}
|
||||
|
||||
this->status_clear_warning();
|
||||
ESP_LOGD(TAG, "HTTP Request completed; URL: %s; Code: %d", this->url_.c_str(), http_code);
|
||||
|
||||
this->last_url_ = this->url_;
|
||||
this->client_.end();
|
||||
return response;
|
||||
}
|
||||
|
||||
#ifdef USE_ESP8266
|
||||
std::shared_ptr<WiFiClient> HttpRequestArduino::get_wifi_client_() {
|
||||
#ifdef USE_HTTP_REQUEST_ESP8266_HTTPS
|
||||
if (this->secure_) {
|
||||
if (this->wifi_client_secure_ == nullptr) {
|
||||
this->wifi_client_secure_ = std::make_shared<BearSSL::WiFiClientSecure>();
|
||||
this->wifi_client_secure_->setInsecure();
|
||||
this->wifi_client_secure_->setBufferSizes(512, 512);
|
||||
}
|
||||
return this->wifi_client_secure_;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (this->wifi_client_ == nullptr) {
|
||||
this->wifi_client_ = std::make_shared<WiFiClient>();
|
||||
}
|
||||
return this->wifi_client_;
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace http_request
|
||||
} // namespace esphome
|
||||
|
||||
#endif // USE_ARDUINO
|
40
esphome/components/http_request/http_request_arduino.h
Normal file
40
esphome/components/http_request/http_request_arduino.h
Normal file
@ -0,0 +1,40 @@
|
||||
#pragma once
|
||||
|
||||
#include "http_request.h"
|
||||
|
||||
#ifdef USE_ARDUINO
|
||||
|
||||
#ifdef USE_ESP32
|
||||
#include <HTTPClient.h>
|
||||
#endif
|
||||
#ifdef USE_ESP8266
|
||||
#include <ESP8266HTTPClient.h>
|
||||
#ifdef USE_HTTP_REQUEST_ESP8266_HTTPS
|
||||
#include <WiFiClientSecure.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
namespace esphome {
|
||||
namespace http_request {
|
||||
|
||||
class HttpRequestArduino : public HttpRequestComponent {
|
||||
public:
|
||||
void set_url(std::string url) override;
|
||||
HttpResponse send() override;
|
||||
|
||||
protected:
|
||||
std::string last_url_;
|
||||
HTTPClient client_{};
|
||||
#ifdef USE_ESP8266
|
||||
std::shared_ptr<WiFiClient> wifi_client_;
|
||||
#ifdef USE_HTTP_REQUEST_ESP8266_HTTPS
|
||||
std::shared_ptr<BearSSL::WiFiClientSecure> wifi_client_secure_;
|
||||
#endif
|
||||
std::shared_ptr<WiFiClient> get_wifi_client_();
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace http_request
|
||||
} // namespace esphome
|
||||
|
||||
#endif // USE_ARDUINO
|
138
esphome/components/http_request/http_request_idf.cpp
Normal file
138
esphome/components/http_request/http_request_idf.cpp
Normal file
@ -0,0 +1,138 @@
|
||||
#include "http_request_idf.h"
|
||||
|
||||
#ifdef USE_ESP_IDF
|
||||
|
||||
#include "esphome/components/network/util.h"
|
||||
#include "esphome/core/application.h"
|
||||
#include "esphome/core/defines.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace http_request {
|
||||
|
||||
static const char *const TAG = "http_request.idf";
|
||||
|
||||
esp_err_t http_event_handler(esp_http_client_event_t *evt) {
|
||||
App.feed_wdt();
|
||||
switch (evt->event_id) {
|
||||
case HTTP_EVENT_ERROR:
|
||||
ESP_LOGE(TAG, "HTTP_EVENT_ERROR");
|
||||
break;
|
||||
case HTTP_EVENT_ON_CONNECTED:
|
||||
ESP_LOGV(TAG, "HTTP_EVENT_ON_CONNECTED");
|
||||
break;
|
||||
case HTTP_EVENT_HEADER_SENT:
|
||||
ESP_LOGV(TAG, "HTTP_EVENT_HEADER_SENT");
|
||||
break;
|
||||
case HTTP_EVENT_ON_HEADER:
|
||||
ESP_LOGV(TAG, "HTTP_EVENT_ON_HEADER, key=%s, value=%s", evt->header_key, evt->header_value);
|
||||
break;
|
||||
case HTTP_EVENT_ON_DATA:
|
||||
ESP_LOGV(TAG, "HTTP_EVENT_ON_DATA, len=%d", evt->data_len);
|
||||
/*
|
||||
* Check for chunked encoding is added as the URL for chunked encoding used in this example returns binary data.
|
||||
* However, event handler can also be used in case chunked encoding is used.
|
||||
*/
|
||||
if (!esp_http_client_is_chunked_response(evt->client)) {
|
||||
if (global_http_request->get_capture_response()) {
|
||||
auto &response = *reinterpret_cast<HttpResponse *>(evt->user_data);
|
||||
auto *const data_begin = reinterpret_cast<char *>(evt->data);
|
||||
auto *const data_end = data_begin + evt->data_len;
|
||||
response.data.insert(response.data.end(), data_begin, data_end);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case HTTP_EVENT_ON_FINISH:
|
||||
ESP_LOGV(TAG, "HTTP_EVENT_ON_FINISH");
|
||||
break;
|
||||
case HTTP_EVENT_DISCONNECTED:
|
||||
ESP_LOGV(TAG, "HTTP_EVENT_DISCONNECTED");
|
||||
break;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
void HttpRequestIDF::set_url(std::string url) { this->url_ = std::move(url); }
|
||||
|
||||
HttpResponse HttpRequestIDF::send() {
|
||||
if (!network::is_connected()) {
|
||||
this->status_set_warning();
|
||||
ESP_LOGE(TAG, "HTTP Request failed; Not connected to network");
|
||||
return {};
|
||||
}
|
||||
|
||||
esp_http_client_method_t method;
|
||||
if (this->method_ == "GET") {
|
||||
method = HTTP_METHOD_GET;
|
||||
} else if (this->method_ == "POST") {
|
||||
method = HTTP_METHOD_POST;
|
||||
} else if (this->method_ == "PUT") {
|
||||
method = HTTP_METHOD_PUT;
|
||||
} else if (this->method_ == "DELETE") {
|
||||
method = HTTP_METHOD_DELETE;
|
||||
} else if (this->method_ == "PATCH") {
|
||||
method = HTTP_METHOD_PATCH;
|
||||
} else {
|
||||
this->status_set_warning();
|
||||
ESP_LOGE(TAG, "HTTP Request failed; Unsupported method");
|
||||
return {};
|
||||
}
|
||||
|
||||
HttpResponse response = {}; // used as user_data, by http_event_handler, in esp_http_client_perform
|
||||
esp_http_client_config_t config = {};
|
||||
|
||||
config.url = this->url_.c_str();
|
||||
config.method = method;
|
||||
config.timeout_ms = this->timeout_;
|
||||
config.disable_auto_redirect = !this->follow_redirects_;
|
||||
config.max_redirection_count = this->redirect_limit_;
|
||||
config.user_data = reinterpret_cast<void *>(&response);
|
||||
config.event_handler = &http_event_handler;
|
||||
|
||||
if (this->useragent_ != nullptr) {
|
||||
config.user_agent = this->useragent_;
|
||||
}
|
||||
|
||||
esp_http_client_handle_t client = esp_http_client_init(&config);
|
||||
|
||||
for (const auto &header : this->headers_) {
|
||||
esp_http_client_set_header(client, header.name, header.value);
|
||||
}
|
||||
|
||||
if (!this->body_.empty()) {
|
||||
esp_http_client_set_post_field(client, this->body_.c_str(), this->body_.length());
|
||||
}
|
||||
|
||||
esp_err_t err = esp_http_client_perform(client);
|
||||
|
||||
if (err != ESP_OK) {
|
||||
this->status_set_warning();
|
||||
ESP_LOGE(TAG, "HTTP Request failed: %s", esp_err_to_name(err));
|
||||
esp_http_client_cleanup(client);
|
||||
return {};
|
||||
}
|
||||
|
||||
const auto status_code = esp_http_client_get_status_code(client);
|
||||
response.status_code = status_code;
|
||||
response.content_length = esp_http_client_get_content_length(client);
|
||||
|
||||
if (status_code < 200 || status_code >= 300) {
|
||||
ESP_LOGE(TAG, "HTTP Request failed; URL: %s; Code: %d", this->url_.c_str(), status_code);
|
||||
this->status_set_warning();
|
||||
return response;
|
||||
}
|
||||
|
||||
this->status_clear_warning();
|
||||
ESP_LOGD(TAG, "HTTP Request completed; URL: %s; Code: %d", this->url_.c_str(), status_code);
|
||||
|
||||
esp_http_client_cleanup(client);
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
} // namespace http_request
|
||||
} // namespace esphome
|
||||
|
||||
#endif // USE_ESP_IDF
|
31
esphome/components/http_request/http_request_idf.h
Normal file
31
esphome/components/http_request/http_request_idf.h
Normal file
@ -0,0 +1,31 @@
|
||||
#pragma once
|
||||
|
||||
#include "http_request.h"
|
||||
|
||||
#ifdef USE_ESP_IDF
|
||||
|
||||
#include "esp_event.h"
|
||||
#include "esp_http_client.h"
|
||||
#include "esp_netif.h"
|
||||
#include "esp_tls.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace http_request {
|
||||
|
||||
static const size_t RESPONSE_BUFFER_SIZE = 2048;
|
||||
|
||||
class HttpRequestIDF : public HttpRequestComponent {
|
||||
public:
|
||||
void set_url(std::string url) override;
|
||||
HttpResponse send() override;
|
||||
|
||||
protected:
|
||||
char last_response_buffer_[RESPONSE_BUFFER_SIZE];
|
||||
int last_status_code_ = 0;
|
||||
int last_content_length_ = 0;
|
||||
};
|
||||
|
||||
} // namespace http_request
|
||||
} // namespace esphome
|
||||
|
||||
#endif // USE_ESP_IDF
|
Loading…
x
Reference in New Issue
Block a user