1
0
mirror of https://github.com/esphome/esphome.git synced 2025-09-29 08:32:26 +01:00

Add OTA upload compression for ESP8266 (#2601)

This commit is contained in:
Otto Winter
2021-10-22 13:02:55 +02:00
committed by GitHub
parent c08b21b7cd
commit 0d90ef94ae
7 changed files with 42 additions and 16 deletions

View File

@@ -4,6 +4,7 @@ import random
import socket
import sys
import time
import gzip
from esphome.core import EsphomeError
from esphome.helpers import is_ip_address, resolve_ip_address
@@ -17,6 +18,7 @@ RESPONSE_UPDATE_PREPARE_OK = 66
RESPONSE_BIN_MD5_OK = 67
RESPONSE_RECEIVE_OK = 68
RESPONSE_UPDATE_END_OK = 69
RESPONSE_SUPPORTS_COMPRESSION = 70
RESPONSE_ERROR_MAGIC = 128
RESPONSE_ERROR_UPDATE_PREPARE = 129
@@ -34,6 +36,8 @@ OTA_VERSION_1_0 = 1
MAGIC_BYTES = [0x6C, 0x26, 0xF7, 0x5C, 0x45]
FEATURE_SUPPORTS_COMPRESSION = 0x01
_LOGGER = logging.getLogger(__name__)
@@ -170,11 +174,9 @@ def send_check(sock, data, msg):
def perform_ota(sock, password, file_handle, filename):
file_md5 = hashlib.md5(file_handle.read()).hexdigest()
file_size = file_handle.tell()
file_contents = file_handle.read()
file_size = len(file_contents)
_LOGGER.info("Uploading %s (%s bytes)", filename, file_size)
file_handle.seek(0)
_LOGGER.debug("MD5 of binary is %s", file_md5)
# Enable nodelay, we need it for phase 1
sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
@@ -185,8 +187,16 @@ def perform_ota(sock, password, file_handle, filename):
raise OTAError(f"Unsupported OTA version {version}")
# Features
send_check(sock, 0x00, "features")
receive_exactly(sock, 1, "features", RESPONSE_HEADER_OK)
send_check(sock, FEATURE_SUPPORTS_COMPRESSION, "features")
features = receive_exactly(
sock, 1, "features", [RESPONSE_HEADER_OK, RESPONSE_SUPPORTS_COMPRESSION]
)[0]
if features == RESPONSE_SUPPORTS_COMPRESSION:
upload_contents = gzip.compress(file_contents, compresslevel=9)
_LOGGER.info("Compressed to %s bytes", len(upload_contents))
else:
upload_contents = file_contents
(auth,) = receive_exactly(
sock, 1, "auth", [RESPONSE_REQUEST_AUTH, RESPONSE_AUTH_OK]
@@ -213,16 +223,20 @@ def perform_ota(sock, password, file_handle, filename):
send_check(sock, result, "auth result")
receive_exactly(sock, 1, "auth result", RESPONSE_AUTH_OK)
file_size_encoded = [
(file_size >> 24) & 0xFF,
(file_size >> 16) & 0xFF,
(file_size >> 8) & 0xFF,
(file_size >> 0) & 0xFF,
upload_size = len(upload_contents)
upload_size_encoded = [
(upload_size >> 24) & 0xFF,
(upload_size >> 16) & 0xFF,
(upload_size >> 8) & 0xFF,
(upload_size >> 0) & 0xFF,
]
send_check(sock, file_size_encoded, "binary size")
send_check(sock, upload_size_encoded, "binary size")
receive_exactly(sock, 1, "binary size", RESPONSE_UPDATE_PREPARE_OK)
send_check(sock, file_md5, "file checksum")
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)
# Disable nodelay for transfer
@@ -236,7 +250,7 @@ def perform_ota(sock, password, file_handle, filename):
offset = 0
progress = ProgressBar()
while True:
chunk = file_handle.read(1024)
chunk = upload_contents[offset : offset + 1024]
if not chunk:
break
offset += len(chunk)
@@ -247,7 +261,7 @@ def perform_ota(sock, password, file_handle, filename):
sys.stderr.write("\n")
raise OTAError(f"Error sending data: {err}") from err
progress.update(offset / float(file_size))
progress.update(offset / upload_size)
progress.done()
# Enable nodelay for last checks