more cleanups

This commit is contained in:
J. Nick Koston
2026-04-29 12:57:18 -05:00
parent 185fa7e302
commit 6de08ea563
5 changed files with 83 additions and 86 deletions
@@ -87,9 +87,6 @@ void ESPHomeOTAComponent::setup() {
// no wakes fire and loop() falls back to the self-disable safety net.
esphome_fast_select_set_ota_listener_sock(esphome_lwip_get_sock(this->server_->get_fd()));
#endif
#ifdef USE_OTA_PARTITIONS
ota::get_running_app_position(this->running_app_offset_, this->running_app_size_);
#endif
}
void ESPHomeOTAComponent::dump_config() {
@@ -104,12 +101,16 @@ void ESPHomeOTAComponent::dump_config() {
}
#endif
#ifdef USE_OTA_PARTITIONS
// Avoid running esp_image_verify here: it reads and checksums the entire app image, which is too
// expensive for a config dump. The address comes from a cached lookup; the precise used size is
// computed lazily by update_partition_table() the first time a partition-table OTA is requested.
const esp_partition_t *running_app_part = esp_ota_get_running_partition();
ESP_LOGCONFIG(TAG,
" Partition access allowed\n"
" Running app:\n"
" Partition address: 0x%X\n"
" Used size: %zu bytes",
this->running_app_offset_, this->running_app_size_);
" Partition size: 0x%X bytes",
running_app_part->address, running_app_part->size);
#ifdef USE_ESP32
ESP_LOGCONFIG(TAG, " Partition table:");
esp_partition_iterator_t it = esp_partition_find(ESP_PARTITION_TYPE_ANY, ESP_PARTITION_SUBTYPE_ANY, nullptr);
@@ -92,9 +92,6 @@ class ESPHomeOTAComponent final : public ota::OTAComponent {
std::unique_ptr<uint8_t[]> auth_buf_;
#endif // USE_OTA_PASSWORD
#ifdef USE_OTA_PARTITIONS
// 4-byte members first, 1-byte member last to minimize padding.
uint32_t running_app_offset_{0};
size_t running_app_size_{0};
bool extended_proto_{false};
#endif
+3 -1
View File
@@ -4,6 +4,8 @@
#include "esphome/core/defines.h"
#include "esphome/core/helpers.h"
#include <cstdint>
#ifdef USE_OTA_STATE_LISTENER
#include <vector>
#endif
@@ -53,7 +55,7 @@ enum OTAState {
OTA_ERROR,
};
enum OTAType {
enum OTAType : uint8_t {
OTA_TYPE_UPDATE_APP = 0x00,
OTA_TYPE_UPDATE_PARTITION_TABLE = 0x01,
};
@@ -321,7 +321,12 @@ OTAResponseTypes IDFOTABackend::update_partition_table() {
return OTA_RESPONSE_ERROR_PARTITION_TABLE_VERIFY;
}
ESP_LOGW(TAG, "Checks passed, starting partition table update. Don't remove power until it is completed!");
// Past this point any failure (power loss, watchdog reset, write error after the table has been
// partially erased) can leave the device unable to boot. Logged at ERROR severity so the message
// is visible in default log filters.
ESP_LOGE(TAG, "Starting partition table update.\n"
" DO NOT REMOVE POWER until the device reboots successfully.\n"
" Loss of power during this operation may permanently brick the device.");
// Deinitialize NVS to prevent unwanted flash writes
nvs_flash_deinit();
+68 -76
View File
@@ -73,6 +73,71 @@ _AUTH_METHODS: dict[int, tuple[Callable[..., Any], int, str]] = {
RESPONSE_REQUEST_AUTH: (hashlib.md5, 32, "MD5"),
}
# Error response code -> human-readable message (without the "Error: " prefix; check_error()
# prepends it uniformly). Looked up by check_error() to translate a single byte from the device
# into an OTAError. Add new error codes here rather than extending the if-chain in check_error().
_ERROR_MESSAGES: dict[int, str] = {
RESPONSE_ERROR_MAGIC: "Invalid magic byte",
RESPONSE_ERROR_UPDATE_PREPARE: (
"Couldn't prepare flash memory for update. Is the binary too big? "
"Please try restarting the ESP."
),
RESPONSE_ERROR_AUTH_INVALID: "Authentication invalid. Is the password correct?",
RESPONSE_ERROR_WRITING_FLASH: (
"Writing OTA data to flash memory failed. See USB logs for more information."
),
RESPONSE_ERROR_UPDATE_END: (
"Finishing update failed. See the MQTT/USB logs for more information."
),
RESPONSE_ERROR_INVALID_BOOTSTRAPPING: (
"Please press the reset button on the ESP. A manual reset is "
"required on the first OTA-Update after flashing via USB."
),
RESPONSE_ERROR_WRONG_CURRENT_FLASH_CONFIG: (
"ESP has been flashed with wrong flash size. Please choose the "
"correct 'board' option (esp01_1m always works) and then flash over USB."
),
RESPONSE_ERROR_WRONG_NEW_FLASH_CONFIG: (
"ESP does not have the requested flash size (wrong board). Please "
"choose the correct 'board' option (esp01_1m always works) and try "
"uploading again."
),
RESPONSE_ERROR_ESP8266_NOT_ENOUGH_SPACE: (
"ESP does not have enough space to store OTA file. Please try "
"flashing a minimal firmware (remove everything except ota)"
),
RESPONSE_ERROR_ESP32_NOT_ENOUGH_SPACE: (
"The OTA partition on the ESP is too small. ESPHome needs to resize "
"this partition, please flash over USB."
),
RESPONSE_ERROR_NO_UPDATE_PARTITION: (
"The OTA partition on the ESP couldn't be found. ESPHome needs to "
"create this partition, please flash over USB."
),
RESPONSE_ERROR_MD5_MISMATCH: (
"Application MD5 code mismatch. Please try again "
"or flash over USB with a good quality cable."
),
RESPONSE_ERROR_SIGNATURE_INVALID: (
"Firmware signature verification failed. The firmware was not signed "
"with the correct key. Ensure the signing key matches the one used to build "
"the firmware currently running on the device."
),
RESPONSE_ERROR_UNSUPPORTED_OTA_TYPE: (
"The requested OTA type is not supported by the device."
),
RESPONSE_ERROR_PARTITION_TABLE_VERIFY: (
"The partition table update could not be verified. No changes were "
"made to the flash content. Check the logs for more information and retry."
),
RESPONSE_ERROR_PARTITION_TABLE_UPDATE: (
"An error occurred while updating the partition table. The device may "
"not be able to reboot to a working application. Check the logs and retry "
"the update without rebooting the device."
),
RESPONSE_ERROR_UNKNOWN: "Unknown error from ESP",
}
class OTAError(EsphomeError):
pass
@@ -148,82 +213,9 @@ def check_error(data: list[int] | bytes, expect: int | list[int] | None) -> None
"a network issue, or the connection was interrupted."
)
dat = data[0]
if dat == RESPONSE_ERROR_MAGIC:
raise OTAError("Error: Invalid magic byte")
if dat == RESPONSE_ERROR_UPDATE_PREPARE:
raise OTAError(
"Error: Couldn't prepare flash memory for update. Is the binary too big? "
"Please try restarting the ESP."
)
if dat == RESPONSE_ERROR_AUTH_INVALID:
raise OTAError("Error: Authentication invalid. Is the password correct?")
if dat == RESPONSE_ERROR_WRITING_FLASH:
raise OTAError(
"Error: Writing OTA data to flash memory failed. See USB logs for more "
"information."
)
if dat == RESPONSE_ERROR_UPDATE_END:
raise OTAError(
"Error: Finishing update failed. See the MQTT/USB logs for more "
"information."
)
if dat == RESPONSE_ERROR_INVALID_BOOTSTRAPPING:
raise OTAError(
"Error: Please press the reset button on the ESP. A manual reset is "
"required on the first OTA-Update after flashing via USB."
)
if dat == RESPONSE_ERROR_WRONG_CURRENT_FLASH_CONFIG:
raise OTAError(
"Error: ESP has been flashed with wrong flash size. Please choose the "
"correct 'board' option (esp01_1m always works) and then flash over USB."
)
if dat == RESPONSE_ERROR_WRONG_NEW_FLASH_CONFIG:
raise OTAError(
"Error: ESP does not have the requested flash size (wrong board). Please "
"choose the correct 'board' option (esp01_1m always works) and try "
"uploading again."
)
if dat == RESPONSE_ERROR_ESP8266_NOT_ENOUGH_SPACE:
raise OTAError(
"Error: ESP does not have enough space to store OTA file. Please try "
"flashing a minimal firmware (remove everything except ota)"
)
if dat == RESPONSE_ERROR_ESP32_NOT_ENOUGH_SPACE:
raise OTAError(
"Error: The OTA partition on the ESP is too small. ESPHome needs to resize "
"this partition, please flash over USB."
)
if dat == RESPONSE_ERROR_NO_UPDATE_PARTITION:
raise OTAError(
"Error: The OTA partition on the ESP couldn't be found. ESPHome needs to create "
"this partition, please flash over USB."
)
if dat == RESPONSE_ERROR_MD5_MISMATCH:
raise OTAError(
"Error: Application MD5 code mismatch. Please try again "
"or flash over USB with a good quality cable."
)
if dat == RESPONSE_ERROR_SIGNATURE_INVALID:
raise OTAError(
"Error: Firmware signature verification failed. The firmware was not signed "
"with the correct key. Ensure the signing key matches the one used to build "
"the firmware currently running on the device."
)
if dat == RESPONSE_ERROR_UNSUPPORTED_OTA_TYPE:
raise OTAError("Error: The requested OTA type is not supported by the device.")
if dat == RESPONSE_ERROR_PARTITION_TABLE_VERIFY:
raise OTAError(
"Error: The partition table update could not be verified. No changes were "
"made to the flash content. Check the logs for more information and retry."
)
if dat == RESPONSE_ERROR_PARTITION_TABLE_UPDATE:
raise OTAError(
"Error: An error occurred while updating the partition table. The device may not "
"be able to reboot to a working application. Check the logs and retry the update "
"without rebooting the device."
)
if dat == RESPONSE_ERROR_UNKNOWN:
raise OTAError("Unknown error from ESP")
error_msg = _ERROR_MESSAGES.get(dat)
if error_msg is not None:
raise OTAError(f"Error: {error_msg}")
if not isinstance(expect, (list, tuple)):
expect = [expect]
if dat not in expect: