diff --git a/esphome/components/mqtt/mqtt_client.cpp b/esphome/components/mqtt/mqtt_client.cpp index 6f63935e6e..923762aea4 100644 --- a/esphome/components/mqtt/mqtt_client.cpp +++ b/esphome/components/mqtt/mqtt_client.cpp @@ -147,7 +147,7 @@ void MQTTClientComponent::dump_config() { ESP_LOGCONFIG(TAG, " Availability: '%s'", this->availability_.topic.c_str()); } } -bool MQTTClientComponent::can_proceed() { return this->is_connected(); } +bool MQTTClientComponent::can_proceed() { return network::is_disabled() || this->is_connected(); } void MQTTClientComponent::start_dnslookup_() { for (auto &subscription : this->subscriptions_) { diff --git a/esphome/components/network/util.cpp b/esphome/components/network/util.cpp index 941102d6c1..109c2947ce 100644 --- a/esphome/components/network/util.cpp +++ b/esphome/components/network/util.cpp @@ -29,6 +29,14 @@ bool is_connected() { return false; } +bool is_disabled() { +#ifdef USE_WIFI + if (wifi::global_wifi_component != nullptr) + return wifi::global_wifi_component->is_disabled(); +#endif + return false; +} + network::IPAddress get_ip_address() { #ifdef USE_ETHERNET if (ethernet::global_eth_component != nullptr) diff --git a/esphome/components/network/util.h b/esphome/components/network/util.h index f248d5cbf4..0322f19215 100644 --- a/esphome/components/network/util.h +++ b/esphome/components/network/util.h @@ -8,6 +8,8 @@ namespace network { /// Return whether the node is connected to the network (through wifi, eth, ...) bool is_connected(); +/// Return whether the network is disabled (only wifi for now) +bool is_disabled(); /// Get the active network hostname std::string get_use_address(); IPAddress get_ip_address(); diff --git a/esphome/components/wifi/wifi_component.cpp b/esphome/components/wifi/wifi_component.cpp index cd87bb48a7..c1d5138f7b 100644 --- a/esphome/components/wifi/wifi_component.cpp +++ b/esphome/components/wifi/wifi_component.cpp @@ -389,6 +389,10 @@ void WiFiComponent::print_connect_params_() { bssid_t bssid = wifi_bssid(); ESP_LOGCONFIG(TAG, " Local MAC: %s", get_mac_address_pretty().c_str()); + if (this->is_disabled()) { + ESP_LOGCONFIG(TAG, " WiFi is disabled!"); + return; + } ESP_LOGCONFIG(TAG, " SSID: " LOG_SECRET("'%s'"), wifi_ssid().c_str()); ESP_LOGCONFIG(TAG, " IP Address: %s", wifi_sta_ip().str().c_str()); ESP_LOGCONFIG(TAG, " BSSID: " LOG_SECRET("%02X:%02X:%02X:%02X:%02X:%02X"), bssid[0], bssid[1], bssid[2], bssid[3], diff --git a/esphome/dashboard/async_adapter.py b/esphome/dashboard/async_adapter.py index 44d2f42ce0..01babe23e4 100644 --- a/esphome/dashboard/async_adapter.py +++ b/esphome/dashboard/async_adapter.py @@ -28,4 +28,4 @@ class AsyncEvent: def async_clear(self) -> None: """Clear the event async.""" - self.async_event.clear() + self.async_event.clear() \ No newline at end of file diff --git a/esphome/dashboard/dashboard.py b/esphome/dashboard/dashboard.py index ac33d38002..b3515464f9 100644 --- a/esphome/dashboard/dashboard.py +++ b/esphome/dashboard/dashboard.py @@ -50,7 +50,6 @@ from esphome.zeroconf import ( DashboardImportDiscovery, DashboardStatus, ) - from .async_adapter import AsyncEvent from .util import chunked, friendly_name_slugify, password_hash @@ -407,7 +406,7 @@ DASHBOARD_COMMAND = ["esphome", "--dashboard"] class EsphomePortCommandWebSocket(EsphomeCommandWebSocket): """Base class for commands that require a port.""" - async def run_command( + async def build_device_command( self, args: list[str], json_message: dict[str, Any] ) -> list[str]: """Build the command to run.""" @@ -434,7 +433,7 @@ class EsphomePortCommandWebSocket(EsphomeCommandWebSocket): class EsphomeLogsHandler(EsphomePortCommandWebSocket): async def build_command(self, json_message: dict[str, Any]) -> list[str]: """Build the command to run.""" - return await self.run_command(["logs"], json_message) + return await self.build_device_command(["logs"], json_message) class EsphomeRenameHandler(EsphomeCommandWebSocket): @@ -463,13 +462,13 @@ class EsphomeRenameHandler(EsphomeCommandWebSocket): class EsphomeUploadHandler(EsphomePortCommandWebSocket): async def build_command(self, json_message: dict[str, Any]) -> list[str]: """Build the command to run.""" - return await self.run_command(["upload"], json_message) + return await self.build_device_command(["upload"], json_message) class EsphomeRunHandler(EsphomePortCommandWebSocket): async def build_command(self, json_message: dict[str, Any]) -> list[str]: """Build the command to run.""" - return await self.run_command(["run"], json_message) + return await self.build_device_command(["run"], json_message) class EsphomeCompileHandler(EsphomeCommandWebSocket): @@ -1582,4 +1581,4 @@ async def async_start_web_server(args): MQTT_PING_REQUEST.set() if args.socket is not None: os.remove(args.socket) - await asyncio.sleep(0) + await asyncio.sleep(0) \ No newline at end of file diff --git a/esphome/espota2.py b/esphome/espota2.py index 98d6d3a0d9..dbf48a989a 100644 --- a/esphome/espota2.py +++ b/esphome/espota2.py @@ -1,10 +1,13 @@ +from __future__ import annotations + +import gzip import hashlib +import io import logging 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 @@ -40,6 +43,10 @@ MAGIC_BYTES = [0x6C, 0x26, 0xF7, 0x5C, 0x45] FEATURE_SUPPORTS_COMPRESSION = 0x01 + +UPLOAD_BLOCK_SIZE = 8192 +UPLOAD_BUFFER_SIZE = UPLOAD_BLOCK_SIZE * 8 + _LOGGER = logging.getLogger(__name__) @@ -184,7 +191,9 @@ def send_check(sock, data, msg): raise OTAError(f"Error sending {msg}: {err}") from err -def perform_ota(sock, password, file_handle, filename): +def perform_ota( + sock: socket.socket, password: str, file_handle: io.IOBase, filename: str +) -> None: file_contents = file_handle.read() file_size = len(file_contents) _LOGGER.info("Uploading %s (%s bytes)", filename, file_size) @@ -254,14 +263,16 @@ def perform_ota(sock, password, file_handle, filename): sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 0) # Limit send buffer (usually around 100kB) in order to have progress bar # show the actual progress - sock.setsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF, 8192) + + sock.setsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF, UPLOAD_BUFFER_SIZE) # Set higher timeout during upload - sock.settimeout(20.0) + sock.settimeout(30.0) + start_time = time.perf_counter() offset = 0 progress = ProgressBar() while True: - chunk = upload_contents[offset : offset + 1024] + chunk = upload_contents[offset : offset + UPLOAD_BLOCK_SIZE] if not chunk: break offset += len(chunk) @@ -277,8 +288,9 @@ def perform_ota(sock, password, file_handle, filename): # Enable nodelay for last checks sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) + duration = time.perf_counter() - start_time - _LOGGER.info("Waiting for result...") + _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) diff --git a/script/bump-version.py b/script/bump-version.py index 1f034344f9..3e1e473c4b 100755 --- a/script/bump-version.py +++ b/script/bump-version.py @@ -45,7 +45,7 @@ def sub(path, pattern, repl, expected_count=1): content, count = re.subn(pattern, repl, content, flags=re.MULTILINE) if expected_count is not None: assert count == expected_count, f"Pattern {pattern} replacement failed!" - with open(path, "wt") as fh: + with open(path, "w") as fh: fh.write(content) diff --git a/tests/unit_tests/test_cpp_generator.py b/tests/unit_tests/test_cpp_generator.py index 331c500c04..6f4b5a40bc 100644 --- a/tests/unit_tests/test_cpp_generator.py +++ b/tests/unit_tests/test_cpp_generator.py @@ -1,4 +1,4 @@ -from typing import Iterator +from collections.abc import Iterator import math diff --git a/tests/unit_tests/test_cpp_helpers.py b/tests/unit_tests/test_cpp_helpers.py index ad234250ce..497b3966fb 100644 --- a/tests/unit_tests/test_cpp_helpers.py +++ b/tests/unit_tests/test_cpp_helpers.py @@ -1,5 +1,5 @@ import pytest -from mock import Mock +from unittest.mock import Mock from esphome import cpp_helpers as ch from esphome import const