[ota] Improve OTA error messages (#16327)

Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: J. Nick Koston <nick+github@koston.org>
This commit is contained in:
Mat931
2026-05-12 02:32:58 +00:00
committed by GitHub
co-authored by pre-commit-ci-lite[bot] Copilot Autofix powered by AI J. Nick Koston
parent 49df1bd30e
commit b5e50144e3
3 changed files with 50 additions and 40 deletions
@@ -68,6 +68,9 @@ OTAResponseTypes IDFOTABackend::begin(size_t image_size, ota::OTAType ota_type)
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;
} else if (err == ESP_ERR_OTA_PARTITION_CONFLICT) {
// This error appears with 1 factory and 1 ota partition
return OTA_RESPONSE_ERROR_NO_UPDATE_PARTITION;
}
return OTA_RESPONSE_ERROR_UNKNOWN;
}
+15 -14
View File
@@ -118,7 +118,8 @@ _ERROR_MESSAGES: dict[int, str] = {
),
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."
"this partition. Please flash over USB or update the partition table "
"over the air."
),
RESPONSE_ERROR_NO_UPDATE_PARTITION: (
"The OTA partition on the ESP couldn't be found. ESPHome needs to "
@@ -202,19 +203,19 @@ def receive_exactly(
try:
data += recv_decode(sock, 1, decode=decode) # type: ignore[operator]
except OSError as err:
raise OTAError(f"Error receiving acknowledge {msg}: {err}") from err
raise OTAError(f"receiving {msg} response: {err}") from err
try:
check_error(data, expect)
except OTAError as err:
sock.close()
raise OTAError(f"Error {msg}: {err}") from err
raise OTAError(f"receiving {msg}: {err}") from err
while len(data) < amount:
try:
data += recv_decode(sock, amount - len(data), decode=decode) # type: ignore[operator]
except OSError as err:
raise OTAError(f"Error receiving {msg}: {err}") from err
raise OTAError(f"receiving {msg}: {err}") from err
return data
@@ -231,14 +232,14 @@ def check_error(data: list[int] | bytes, expect: int | list[int] | None) -> None
# silently passed through and surface later as cryptic decode/timeout failures.
if not data:
raise OTAError(
"Error: Device closed connection without responding. "
"Device closed connection without responding. "
"This may indicate the device ran out of memory, "
"a network issue, or the connection was interrupted."
)
dat = data[0]
error_msg = _ERROR_MESSAGES.get(dat)
if error_msg is not None:
raise OTAError(f"Error: {error_msg}")
raise OTAError(error_msg)
if expect is None:
return
if not isinstance(expect, (list, tuple)):
@@ -267,7 +268,7 @@ def send_check(
sock.sendall(data)
except OSError as err:
raise OTAError(f"Error sending {msg}: {err}") from err
raise OTAError(f"sending {msg}: {err}") from err
def perform_ota(
@@ -376,7 +377,7 @@ def perform_ota(
raise OTAError("ESP requests password, but no password given!")
nonce_bytes = receive_exactly(
sock, nonce_size, f"{hash_name} authentication nonce", None, decode=False
sock, nonce_size, f"{hash_name} auth nonce", None, decode=False
)
assert isinstance(nonce_bytes, bytes)
nonce = nonce_bytes.decode()
@@ -424,13 +425,13 @@ def perform_ota(
(upload_size >> 0) & 0xFF,
]
send_check(sock, upload_size_encoded, "binary size")
receive_exactly(sock, 1, "binary size", RESPONSE_UPDATE_PREPARE_OK)
receive_exactly(sock, 1, "update prepare result", RESPONSE_UPDATE_PREPARE_OK)
upload_md5 = hashlib.md5(upload_contents).hexdigest()
_LOGGER.debug("MD5 of upload is %s", upload_md5)
send_check(sock, upload_md5, "file checksum")
receive_exactly(sock, 1, "file checksum", RESPONSE_BIN_MD5_OK)
receive_exactly(sock, 1, "file checksum result", RESPONSE_BIN_MD5_OK)
# Disable nodelay for transfer
sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 0)
@@ -451,10 +452,10 @@ def perform_ota(
try:
sock.sendall(chunk)
if version >= OTA_VERSION_2_0:
receive_exactly(sock, 1, "chunk OK", RESPONSE_CHUNK_OK)
receive_exactly(sock, 1, "chunk result", RESPONSE_CHUNK_OK)
except OSError as err:
sys.stderr.write("\n")
raise OTAError(f"Error sending data: {err}") from err
raise OTAError(f"sending data: {err}") from err
progress.update(offset / upload_size)
progress.done()
@@ -465,8 +466,8 @@ def perform_ota(
_LOGGER.info("Upload took %.2f seconds, waiting for result...", duration)
receive_exactly(sock, 1, "receive OK", RESPONSE_RECEIVE_OK)
receive_exactly(sock, 1, "Update end", RESPONSE_UPDATE_END_OK)
receive_exactly(sock, 1, "update receive result", RESPONSE_RECEIVE_OK)
receive_exactly(sock, 1, "update end result", RESPONSE_UPDATE_END_OK)
send_check(sock, RESPONSE_OK, "end acknowledgement")
_LOGGER.info("OTA successful")