diff --git a/esphome/components/ota/ota_backend.h b/esphome/components/ota/ota_backend.h new file mode 100644 index 0000000000..c253e009c6 --- /dev/null +++ b/esphome/components/ota/ota_backend.h @@ -0,0 +1,18 @@ +#pragma once +#include "ota_component.h" + +namespace esphome { +namespace ota { + +class OTABackend { + public: + virtual ~OTABackend() = default; + virtual OTAResponseTypes begin(size_t image_size) = 0; + virtual void set_update_md5(const char *md5) = 0; + virtual OTAResponseTypes write(uint8_t *data, size_t len) = 0; + virtual OTAResponseTypes end() = 0; + virtual void abort() = 0; +}; + +} // namespace ota +} // namespace esphome diff --git a/esphome/components/ota/ota_backend_arduino_esp32.cpp b/esphome/components/ota/ota_backend_arduino_esp32.cpp new file mode 100644 index 0000000000..4759737dbd --- /dev/null +++ b/esphome/components/ota/ota_backend_arduino_esp32.cpp @@ -0,0 +1,46 @@ +#include "esphome/core/defines.h" +#ifdef USE_ESP32_FRAMEWORK_ARDUINO + +#include "ota_backend_arduino_esp32.h" +#include "ota_component.h" +#include "ota_backend.h" + +#include + +namespace esphome { +namespace ota { + +OTAResponseTypes ArduinoESP32OTABackend::begin(size_t image_size) { + bool ret = Update.begin(image_size, U_FLASH); + if (ret) { + return OTA_RESPONSE_OK; + } + + uint8_t error = Update.getError(); + if (error == UPDATE_ERROR_SIZE) + return OTA_RESPONSE_ERROR_ESP32_NOT_ENOUGH_SPACE; + return OTA_RESPONSE_ERROR_UNKNOWN; +} + +void ArduinoESP32OTABackend::set_update_md5(const char *md5) { Update.setMD5(md5); } + +OTAResponseTypes ArduinoESP32OTABackend::write(uint8_t *data, size_t len) { + size_t written = Update.write(data, len); + if (written != len) { + return OTA_RESPONSE_ERROR_WRITING_FLASH; + } + return OTA_RESPONSE_OK; +} + +OTAResponseTypes ArduinoESP32OTABackend::end() { + if (!Update.end()) + return OTA_RESPONSE_ERROR_UPDATE_END; + return OTA_RESPONSE_OK; +} + +void ArduinoESP32OTABackend::abort() { Update.abort(); } + +} // namespace ota +} // namespace esphome + +#endif // USE_ESP32_FRAMEWORK_ARDUINO diff --git a/esphome/components/ota/ota_backend_arduino_esp32.h b/esphome/components/ota/ota_backend_arduino_esp32.h new file mode 100644 index 0000000000..8343bdf94f --- /dev/null +++ b/esphome/components/ota/ota_backend_arduino_esp32.h @@ -0,0 +1,22 @@ +#pragma once +#include "esphome/core/defines.h" +#ifdef USE_ESP32_FRAMEWORK_ARDUINO + +#include "ota_component.h" +#include "ota_backend.h" + +namespace esphome { +namespace ota { + +class ArduinoESP32OTABackend : public OTABackend { + OTAResponseTypes begin(size_t image_size) override; + void set_update_md5(const char *md5) override; + OTAResponseTypes write(uint8_t *data, size_t len) override; + OTAResponseTypes end() override; + void abort() override; +}; + +} // namespace ota +} // namespace esphome + +#endif // USE_ESP32_FRAMEWORK_ARDUINO diff --git a/esphome/components/ota/ota_backend_arduino_esp8266.cpp b/esphome/components/ota/ota_backend_arduino_esp8266.cpp new file mode 100644 index 0000000000..8e8a4f36ba --- /dev/null +++ b/esphome/components/ota/ota_backend_arduino_esp8266.cpp @@ -0,0 +1,58 @@ +#include "esphome/core/defines.h" +#ifdef USE_ARDUINO +#ifdef USE_ESP8266 + +#include "ota_backend_arduino_esp8266.h" +#include "ota_component.h" +#include "ota_backend.h" +#include "esphome/components/esp8266/preferences.h" + +#include + +namespace esphome { +namespace ota { + +OTAResponseTypes ArduinoESP8266OTABackend::begin(size_t image_size) { + bool ret = Update.begin(image_size, U_FLASH); + if (ret) { + esp8266::preferences_prevent_write(true); + } + + uint8_t error = Update.getError(); + if (error == UPDATE_ERROR_BOOTSTRAP) + return OTA_RESPONSE_ERROR_INVALID_BOOTSTRAPPING; + if (error == UPDATE_ERROR_NEW_FLASH_CONFIG) + return OTA_RESPONSE_ERROR_WRONG_NEW_FLASH_CONFIG; + if (error == UPDATE_ERROR_FLASH_CONFIG) + return OTA_RESPONSE_ERROR_WRONG_CURRENT_FLASH_CONFIG; + if (error == UPDATE_ERROR_SPACE) + return OTA_RESPONSE_ERROR_ESP8266_NOT_ENOUGH_SPACE; + return OTA_RESPONSE_ERROR_UNKNOWN; +} + +void ArduinoESP8266OTABackend::set_update_md5(const char *md5) { Update.setMD5(md5); } + +OTAResponseTypes ArduinoESP8266OTABackend::write(uint8_t *data, size_t len) { + size_t written = Update.write(data, len); + if (written != len) { + return OTA_RESPONSE_ERROR_WRITING_FLASH; + } + return OTA_RESPONSE_OK; +} + +OTAResponseTypes ArduinoESP8266OTABackend::end() { + if (!Update.end()) + return OTA_RESPONSE_ERROR_UPDATE_END; + return OTA_RESPONSE_OK; +} + +void ArduinoESP8266OTABackend::abort() { + Update.end(); + esp8266::preferences_prevent_write(false); +} + +} // namespace ota +} // namespace esphome + +#endif +#endif diff --git a/esphome/components/ota/ota_backend_arduino_esp8266.h b/esphome/components/ota/ota_backend_arduino_esp8266.h new file mode 100644 index 0000000000..d1195af911 --- /dev/null +++ b/esphome/components/ota/ota_backend_arduino_esp8266.h @@ -0,0 +1,25 @@ +#pragma once +#include "esphome/core/defines.h" +#ifdef USE_ARDUINO +#ifdef USE_ESP8266 + +#include "ota_component.h" +#include "ota_backend.h" + +namespace esphome { +namespace ota { + +class ArduinoESP8266OTABackend : public OTABackend { + public: + OTAResponseTypes begin(size_t image_size) override; + void set_update_md5(const char *md5) override; + OTAResponseTypes write(uint8_t *data, size_t len) override; + OTAResponseTypes end() override; + void abort() override; +}; + +} // namespace ota +} // namespace esphome + +#endif +#endif diff --git a/esphome/components/ota/ota_backend_esp_idf.cpp b/esphome/components/ota/ota_backend_esp_idf.cpp new file mode 100644 index 0000000000..4eb17d82f1 --- /dev/null +++ b/esphome/components/ota/ota_backend_esp_idf.cpp @@ -0,0 +1,72 @@ +#include "esphome/core/defines.h" +#ifdef USE_ESP_IDF + +#include "ota_backend_esp_idf.h" +#include "ota_component.h" +#include + +namespace esphome { +namespace ota { + +OTAResponseTypes IDFOTABackend::begin(size_t image_size) { + this->partition_ = esp_ota_get_next_update_partition(nullptr); + if (this->partition_ == nullptr) { + return OTA_RESPONSE_ERROR_NO_UPDATE_PARTITION; + } + esp_err_t err = esp_ota_begin(this->partition_, image_size, &this->update_handle_); + if (err != ESP_OK) { + esp_ota_abort(this->update_handle_); + this->update_handle_ = 0; + if (err == ESP_ERR_INVALID_SIZE) { + return OTA_RESPONSE_ERROR_ESP32_NOT_ENOUGH_SPACE; + } else if (err == ESP_ERR_FLASH_OP_TIMEOUT || err == ESP_ERR_FLASH_OP_FAIL) { + return OTA_RESPONSE_ERROR_WRITING_FLASH; + } + return OTA_RESPONSE_ERROR_UNKNOWN; + } + return OTA_RESPONSE_OK; +} + +void IDFOTABackend::set_update_md5(const char *md5) { + // pass +} + +OTAResponseTypes IDFOTABackend::write(uint8_t *data, size_t len) { + esp_err_t err = esp_ota_write(this->update_handle_, data, len); + if (err != ESP_OK) { + if (err == ESP_ERR_OTA_VALIDATE_FAILED) { + return OTA_RESPONSE_ERROR_MAGIC; + } else if (err == ESP_ERR_FLASH_OP_TIMEOUT || err == ESP_ERR_FLASH_OP_FAIL) { + return OTA_RESPONSE_ERROR_WRITING_FLASH; + } + return OTA_RESPONSE_ERROR_UNKNOWN; + } + return OTA_RESPONSE_OK; +} + +OTAResponseTypes IDFOTABackend::end() { + esp_err_t err = esp_ota_end(this->update_handle_); + this->update_handle_ = 0; + if (err == ESP_OK) { + err = esp_ota_set_boot_partition(this->partition_); + if (err == ESP_OK) { + return OTA_RESPONSE_OK; + } + } + if (err == ESP_ERR_OTA_VALIDATE_FAILED) { + return OTA_RESPONSE_ERROR_UPDATE_END; + } + if (err == ESP_ERR_FLASH_OP_TIMEOUT || err == ESP_ERR_FLASH_OP_FAIL) { + return OTA_RESPONSE_ERROR_WRITING_FLASH; + } + return OTA_RESPONSE_ERROR_UNKNOWN; +} + +void IDFOTABackend::abort() { + esp_ota_abort(this->update_handle_); + this->update_handle_ = 0; +} + +} // namespace ota +} // namespace esphome +#endif diff --git a/esphome/components/ota/ota_backend_esp_idf.h b/esphome/components/ota/ota_backend_esp_idf.h new file mode 100644 index 0000000000..d6e2e2742a --- /dev/null +++ b/esphome/components/ota/ota_backend_esp_idf.h @@ -0,0 +1,27 @@ +#pragma once +#include "esphome/core/defines.h" +#ifdef USE_ESP_IDF + +#include "ota_component.h" +#include "ota_backend.h" +#include + +namespace esphome { +namespace ota { + +class IDFOTABackend : public OTABackend { + public: + OTAResponseTypes begin(size_t image_size) override; + void set_update_md5(const char *md5) override; + OTAResponseTypes write(uint8_t *data, size_t len) override; + OTAResponseTypes end() override; + void abort() override; + + private: + esp_ota_handle_t update_handle_{0}; + const esp_partition_t *partition_; +}; + +} // namespace ota +} // namespace esphome +#endif diff --git a/esphome/components/ota/ota_component.cpp b/esphome/components/ota/ota_component.cpp index 0c13efa135..e1188a4d31 100644 --- a/esphome/components/ota/ota_component.cpp +++ b/esphome/components/ota/ota_component.cpp @@ -1,4 +1,8 @@ #include "ota_component.h" +#include "ota_backend.h" +#include "ota_backend_arduino_esp32.h" +#include "ota_backend_arduino_esp8266.h" +#include "ota_backend_esp_idf.h" #include "esphome/core/log.h" #include "esphome/core/application.h" @@ -9,23 +13,8 @@ #include #include -#ifdef USE_ARDUINO #ifdef USE_OTA_PASSWORD #include -#endif // USE_OTA_PASSWORD - -#ifdef USE_ESP32 -#include -#endif // USE_ESP32 -#endif // USE_ARDUINO - -#ifdef USE_ESP8266 -#include -#include "esphome/components/esp8266/preferences.h" -#endif // USE_ESP8266 - -#ifdef USE_ESP_IDF -#include #endif namespace esphome { @@ -35,125 +24,19 @@ static const char *const TAG = "ota"; static const uint8_t OTA_VERSION_1_0 = 1; -class OTABackend { - public: - virtual ~OTABackend() = default; - virtual OTAResponseTypes begin(size_t image_size) = 0; - virtual void set_update_md5(const char *md5) = 0; - virtual OTAResponseTypes write(uint8_t *data, size_t len) = 0; - virtual OTAResponseTypes end() = 0; - virtual void abort() = 0; -}; - +std::unique_ptr make_ota_backend() { #ifdef USE_ARDUINO -class ArduinoOTABackend : public OTABackend { - public: - OTAResponseTypes begin(size_t image_size) override { - bool ret = Update.begin(image_size, U_FLASH); - if (ret) { #ifdef USE_ESP8266 - esp8266::preferences_prevent_write(true); -#endif - return OTA_RESPONSE_OK; - } - - uint8_t error = Update.getError(); -#ifdef USE_ESP8266 - if (error == UPDATE_ERROR_BOOTSTRAP) - return OTA_RESPONSE_ERROR_INVALID_BOOTSTRAPPING; - if (error == UPDATE_ERROR_NEW_FLASH_CONFIG) - return OTA_RESPONSE_ERROR_WRONG_NEW_FLASH_CONFIG; - if (error == UPDATE_ERROR_FLASH_CONFIG) - return OTA_RESPONSE_ERROR_WRONG_CURRENT_FLASH_CONFIG; - if (error == UPDATE_ERROR_SPACE) - return OTA_RESPONSE_ERROR_ESP8266_NOT_ENOUGH_SPACE; -#endif + return make_unique(); +#endif // USE_ESP8266 #ifdef USE_ESP32 - if (error == UPDATE_ERROR_SIZE) - return OTA_RESPONSE_ERROR_ESP32_NOT_ENOUGH_SPACE; -#endif - return OTA_RESPONSE_ERROR_UNKNOWN; - } - void set_update_md5(const char *md5) override { Update.setMD5(md5); } - OTAResponseTypes write(uint8_t *data, size_t len) override { - size_t written = Update.write(data, len); - if (written != len) { - return OTA_RESPONSE_ERROR_WRITING_FLASH; - } - return OTA_RESPONSE_OK; - } - OTAResponseTypes end() override { - if (!Update.end()) - return OTA_RESPONSE_ERROR_UPDATE_END; - return OTA_RESPONSE_OK; - } - void abort() override { -#ifdef USE_ESP32 - Update.abort(); -#endif - -#ifdef USE_ESP8266 - Update.end(); - esp8266::preferences_prevent_write(false); -#endif - } -}; -std::unique_ptr make_ota_backend() { return make_unique(); } + return make_unique(); +#endif // USE_ESP32 #endif // USE_ARDUINO - #ifdef USE_ESP_IDF -class IDFOTABackend : public OTABackend { - public: - esp_ota_handle_t update_handle = 0; - - OTAResponseTypes begin(size_t image_size) override { - const esp_partition_t *update_partition = esp_ota_get_next_update_partition(nullptr); - if (update_partition == nullptr) { - return OTA_RESPONSE_ERROR_NO_UPDATE_PARTITION; - } - esp_err_t err = esp_ota_begin(update_partition, image_size, &update_handle); - if (err != ESP_OK) { - esp_ota_abort(update_handle); - update_handle = 0; - if (err == ESP_ERR_INVALID_SIZE) { - return OTA_RESPONSE_ERROR_ESP32_NOT_ENOUGH_SPACE; - } else if (err == ESP_ERR_FLASH_OP_TIMEOUT || err == ESP_ERR_FLASH_OP_FAIL) { - return OTA_RESPONSE_ERROR_WRITING_FLASH; - } - return OTA_RESPONSE_ERROR_UNKNOWN; - } - return OTA_RESPONSE_OK; - } - void set_update_md5(const char *md5) override { - // pass - } - OTAResponseTypes write(uint8_t *data, size_t len) override { - esp_err_t err = esp_ota_write(update_handle, data, len); - if (err != ESP_OK) { - if (err == ESP_ERR_OTA_VALIDATE_FAILED) { - return OTA_RESPONSE_ERROR_MAGIC; - } else if (err == ESP_ERR_FLASH_OP_TIMEOUT || err == ESP_ERR_FLASH_OP_FAIL) { - return OTA_RESPONSE_ERROR_WRITING_FLASH; - } - return OTA_RESPONSE_ERROR_UNKNOWN; - } - return OTA_RESPONSE_OK; - } - OTAResponseTypes end() override { - esp_err_t err = esp_ota_end(update_handle); - update_handle = 0; - if (err != ESP_OK) { - if (err == ESP_ERR_OTA_VALIDATE_FAILED) { - return OTA_RESPONSE_ERROR_UPDATE_END; - } - return OTA_RESPONSE_ERROR_UNKNOWN; - } - return OTA_RESPONSE_OK; - } - void abort() override { esp_ota_abort(update_handle); } -}; -std::unique_ptr make_ota_backend() { return make_unique(); } + return make_unique(); #endif // USE_ESP_IDF +} void OTAComponent::setup() { server_ = socket::socket(AF_INET, SOCK_STREAM, 0);