16 namespace http_request {
18 static const char *
const TAG =
"http_request.ota";
21 #ifdef USE_OTA_STATE_CALLBACK 46 if (this->
url_.empty()) {
47 ESP_LOGE(TAG,
"URL not set; cannot start update");
51 ESP_LOGI(TAG,
"Starting update...");
52 #ifdef USE_OTA_STATE_CALLBACK 56 auto ota_status = this->
do_ota_();
60 #ifdef USE_OTA_STATE_CALLBACK 68 #ifdef USE_OTA_STATE_CALLBACK 78 const std::shared_ptr<HttpContainer> &container) {
80 ESP_LOGV(TAG,
"Aborting OTA backend");
83 ESP_LOGV(TAG,
"Aborting HTTP connection");
89 uint32_t last_progress = 0;
90 uint32_t update_start_time =
millis();
92 std::unique_ptr<char[]> md5_receive_str(
new char[33]);
98 ESP_LOGD(TAG,
"MD5 expected: %s", this->
md5_expected_.c_str());
101 if (url_with_auth.empty()) {
104 ESP_LOGVV(TAG,
"url_with_auth: %s", url_with_auth.c_str());
105 ESP_LOGI(TAG,
"Connecting to: %s", this->
url_.c_str());
107 auto container = this->
parent_->get(url_with_auth);
109 if (container ==
nullptr || container->status_code !=
HTTP_STATUS_OK) {
115 ESP_LOGV(TAG,
"MD5Digest initialized");
117 ESP_LOGV(TAG,
"OTA backend begin");
119 auto error_code = backend->begin(container->content_length);
121 ESP_LOGW(TAG,
"backend->begin error: %d", error_code);
122 this->
cleanup_(std::move(backend), container);
126 while (container->get_bytes_read() < container->content_length) {
129 ESP_LOGVV(TAG,
"bytes_read_ = %u, body_length_ = %u, bufsize = %i", container->get_bytes_read(),
130 container->content_length, bufsize);
137 ESP_LOGE(TAG,
"Stream closed");
138 this->
cleanup_(std::move(backend), container);
142 md5_receive.
add(buf, bufsize);
146 error_code = backend->write(buf, bufsize);
150 ESP_LOGE(TAG,
"Error code (%02X) writing binary data to flash at offset %d and size %d", error_code,
151 container->get_bytes_read() - bufsize, container->content_length);
152 this->
cleanup_(std::move(backend), container);
158 if ((now - last_progress > 1000) or (container->get_bytes_read() == container->content_length)) {
160 float percentage = container->get_bytes_read() * 100.0f / container->content_length;
161 ESP_LOGD(TAG,
"Progress: %0.1f%%", percentage);
162 #ifdef USE_OTA_STATE_CALLBACK 168 ESP_LOGI(TAG,
"Done in %.0f seconds",
float(
millis() - update_start_time) / 1000);
172 md5_receive.
get_hex(md5_receive_str.get());
175 ESP_LOGE(TAG,
"MD5 computed: %s - Aborting due to MD5 mismatch", this->
md5_computed_.c_str());
176 this->
cleanup_(std::move(backend), container);
179 backend->set_update_md5(md5_receive_str.get());
189 error_code = backend->end();
191 ESP_LOGW(TAG,
"Error ending update! error_code: %d", error_code);
192 this->
cleanup_(std::move(backend), container);
196 ESP_LOGI(TAG,
"Update complete");
205 auto start_char = url.find(
"://");
206 if ((start_char == std::string::npos) || (start_char < 4)) {
207 ESP_LOGE(TAG,
"Incorrect URL prefix");
211 ESP_LOGD(TAG,
"Using basic HTTP authentication");
215 url.substr(0, start_char) + this->
username_ +
":" + this->
password_ +
"@" + url.substr(start_char);
216 return url_with_auth;
225 if (url_with_auth.empty()) {
229 ESP_LOGVV(TAG,
"url_with_auth: %s", url_with_auth.c_str());
230 ESP_LOGI(TAG,
"Connecting to: %s", this->
md5_url_.c_str());
231 auto container = this->
parent_->get(url_with_auth);
232 if (container ==
nullptr) {
233 ESP_LOGE(TAG,
"Failed to connect to MD5 URL");
236 size_t length = container->content_length;
241 if (length < MD5_SIZE) {
242 ESP_LOGE(TAG,
"MD5 file must be %u bytes; %u bytes reported by HTTP server. Aborting", MD5_SIZE, length);
249 while (container->get_bytes_read() < MD5_SIZE) {
250 read_len = container->read((uint8_t *) this->
md5_expected_.data(), MD5_SIZE);
256 ESP_LOGV(TAG,
"Read len: %u, MD5 expected: %u", read_len, MD5_SIZE);
257 return read_len == MD5_SIZE;
261 if ((url.length() < 8) || (url.find(
"http") != 0) || (url.find(
"://") == std::string::npos)) {
262 ESP_LOGE(TAG,
"URL is invalid and/or must be prefixed with 'http://' or 'https://'");
void init()
Initialize a new MD5 digest computation.
void cleanup_(std::unique_ptr< ota::OTABackend > backend, const std::shared_ptr< HttpContainer > &container)
std::string md5_expected_
static const uint16_t HTTP_RECV_BUFFER
std::string get_url_with_auth_(const std::string &url)
void set_md5_url(const std::string &md5_url)
void register_ota_platform(OTAComponent *ota_caller)
uint32_t IRAM_ATTR HOT millis()
void add(const uint8_t *data, size_t len)
Add bytes of data for the digest.
CallbackManager< void(ota::OTAState, float, uint8_t)> state_callback_
HttpRequestComponent * parent_
void set_url(const std::string &url)
Application App
Global storage of Application pointer - only one Application can exist.
std::unique_ptr< ota::OTABackend > make_ota_backend()
void get_hex(char *output)
Retrieve the MD5 digest as hex characters.
bool validate_url_(const std::string &url)
void IRAM_ATTR HOT yield()
Implementation of SPI Controller mode.
void calculate()
Compute the digest, based on the provided data.
std::string md5_computed_
void dump_config() override
void IRAM_ATTR HOT delay(uint32_t ms)