From 6c23ad661da7c642215d6d2ddcc08c63d09786ac Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sun, 23 Aug 2026 18:30:11 -0500 Subject: [PATCH 01/10] [bluetooth_proxy] Warn once per transaction when the TCP buffer is congested (#18605) --- .../bluetooth_connection_hub.cpp | 23 +++++++++++++++---- .../bluetooth_connection_hub.h | 9 +++++++- 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/esphome/components/bluetooth_connection/bluetooth_connection_hub.cpp b/esphome/components/bluetooth_connection/bluetooth_connection_hub.cpp index c8f97f207e..ddab4812cc 100644 --- a/esphome/components/bluetooth_connection/bluetooth_connection_hub.cpp +++ b/esphome/components/bluetooth_connection/bluetooth_connection_hub.cpp @@ -275,10 +275,15 @@ void BluetoothConnection::send_ack_(PendingAck kind, uint16_t handle, conn_err_t if (this->try_send_ack_(kind, handle, error)) return; // Report a newly owed reply and a displaced one; displacing is the case - // that loses a reply. Re-refusing the same one stays quiet. + // that loses a reply. Re-refusing the same one stays quiet, and so does a + // fresh deferral for the handle already warned about: a congested bulk + // transfer re-asks the same handle every cycle and each ack would warn. if (!this->has_pending_ack_()) { - ESP_LOGW(TAG, "[%d] [%s] GATT reply for handle 0x%04X deferred, TCP buffer full", this->connection_index_, - this->address_str_, handle); + if (!this->ack_deferred_warned_ || this->pending_ack_handle_ != handle) { + ESP_LOGW(TAG, "[%d] [%s] GATT reply for handle 0x%04X deferred, TCP buffer full", this->connection_index_, + this->address_str_, handle); + this->ack_deferred_warned_ = true; + } } else if (this->pending_ack_handle_ != handle || this->pending_ack_ != kind) { ESP_LOGW(TAG, "[%d] [%s] GATT reply for handle 0x%04X dropped for handle 0x%04X", this->connection_index_, this->address_str_, this->pending_ack_handle_, handle); @@ -365,8 +370,16 @@ void BluetoothConnection::on_notify_data(uint16_t handle, const uint8_t *data, u resp.set_data(data, len); if (!api_connection->send_message(resp)) { // Not latched, same reason as the read reply. Notify data is lossy: the - // peripheral will not resend it. - ESP_LOGW(TAG, "[%d] [%s] Failed to send notify data response", this->connection_index_, this->address_str_); + // peripheral will not resend it. Warn on the first drop only; a congested + // link drops a whole stream and one line per notify floods the log. + if (!this->notify_drop_warned_) { + ESP_LOGW(TAG, "[%d] [%s] Failed to send notify data response, handle 0x%04X", this->connection_index_, + this->address_str_, handle); + this->notify_drop_warned_ = true; + } else { + ESP_LOGV(TAG, "[%d] [%s] Failed to send notify data response, handle 0x%04X", this->connection_index_, + this->address_str_, handle); + } } } diff --git a/esphome/components/bluetooth_connection/bluetooth_connection_hub.h b/esphome/components/bluetooth_connection/bluetooth_connection_hub.h index f87d545f7d..47181e81a7 100644 --- a/esphome/components/bluetooth_connection/bluetooth_connection_hub.h +++ b/esphome/components/bluetooth_connection/bluetooth_connection_hub.h @@ -164,6 +164,8 @@ class BluetoothConnection final : public ble_device_base::GattClientListener { this->pending_ack_ = PendingAck::PENDING_ACK_NONE; this->batch_stalled_ = false; this->connected_reply_owed_ = false; + this->ack_deferred_warned_ = false; + this->notify_drop_warned_ = false; } /// Sole construction site for these replies, shared by send and retry. bool try_send_ack_(PendingAck kind, uint16_t handle, conn_err_t error); @@ -238,7 +240,7 @@ class BluetoothConnection final : public ble_device_base::GattClientListener { // Group 5: bit-packed tail. The first two bytes were already full, so the // first added bit forced a third and took the 8-aligned object 48 -> 56; - // the handle, error and retry counter ride in that padding. Four bitfield + // the handle, error and retry counter ride in that padding. Two bitfield // bits left; another byte-sized member costs 8 per slot. static_assert(static_cast(ClientState::ESTABLISHED) < (1 << 3), "state_ bitfield too narrow"); static_assert(static_cast(ConnectionType::V3_WITHOUT_CACHE) < (1 << 2), @@ -258,6 +260,11 @@ class BluetoothConnection final : public ble_device_base::GattClientListener { bool batch_stalled_ : 1 {false}; /// An owed connected=true reply; the proxy's paced drain re-offers it. bool connected_reply_owed_ : 1 {false}; + /// Set once the deferred warn fired; with an unchanged pending_ack_handle_ + /// it keeps re-deferrals of the same handle quiet (see send_ack_). + bool ack_deferred_warned_ : 1 {false}; + /// Set on the first dropped notify; later drops log at verbose only. + bool notify_drop_warned_ : 1 {false}; // Plain byte after the bitfields: takes the padding byte instead of // straddling pending_ack_'s storage unit and growing the object. static_assert(PENDING_ACK_RETRY_LIMIT <= 0xFF, "retry counter too narrow"); From 6f7b9a148227dfc2f8788e3e2a4749f578796026 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sun, 23 Aug 2026 18:31:48 -0500 Subject: [PATCH 02/10] [gpio] Fix linker error when binary sensor only uses expander pins (#18698) --- .../components/gpio/binary_sensor/__init__.py | 1 + .../gpio/binary_sensor/gpio_binary_sensor.cpp | 22 +++++-- .../gpio/binary_sensor/gpio_binary_sensor.h | 13 +++- esphome/core/defines.h | 1 + .../gpio/test_gpio_binary_sensor.py | 64 +++++++++++++++++++ .../test_gpio_binary_sensor_expander.yaml | 21 ++++++ .../gpio/test_gpio_binary_sensor_mixed.yaml | 17 +++++ 7 files changed, 133 insertions(+), 6 deletions(-) create mode 100644 tests/component_tests/gpio/test_gpio_binary_sensor_expander.yaml create mode 100644 tests/component_tests/gpio/test_gpio_binary_sensor_mixed.yaml diff --git a/esphome/components/gpio/binary_sensor/__init__.py b/esphome/components/gpio/binary_sensor/__init__.py index 7cc16eb5b2..8a40e4e732 100644 --- a/esphome/components/gpio/binary_sensor/__init__.py +++ b/esphome/components/gpio/binary_sensor/__init__.py @@ -133,6 +133,7 @@ async def to_code(config: ConfigType) -> None: cg.add(var.set_pin(pin)) if config[CONF_USE_INTERRUPT]: + cg.add_define("USE_GPIO_BINARY_SENSOR_INTERRUPT") cg.add(var.set_interrupt_type(config[CONF_INTERRUPT_TYPE])) else: cg.add(var.set_use_interrupt(False)) diff --git a/esphome/components/gpio/binary_sensor/gpio_binary_sensor.cpp b/esphome/components/gpio/binary_sensor/gpio_binary_sensor.cpp index ff07d76901..9d044dca2d 100644 --- a/esphome/components/gpio/binary_sensor/gpio_binary_sensor.cpp +++ b/esphome/components/gpio/binary_sensor/gpio_binary_sensor.cpp @@ -7,6 +7,7 @@ namespace esphome::gpio { static const char *const TAG = "gpio.binary_sensor"; #if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_DEBUG +#ifdef USE_GPIO_BINARY_SENSOR_INTERRUPT // Interrupt type strings indexed by edge-triggered InterruptType values: // indices 1-3: RISING_EDGE, FALLING_EDGE, ANY_EDGE; other values (e.g. level-triggered) map to UNKNOWN (index 0). PROGMEM_STRING_TABLE(InterruptTypeStrings, "UNKNOWN", "RISING_EDGE", "FALLING_EDGE", "ANY_EDGE"); @@ -19,7 +20,9 @@ static const LogString *gpio_mode_to_string(bool use_interrupt) { return use_interrupt ? LOG_STR("interrupt") : LOG_STR("polling"); } #endif +#endif +#ifdef USE_GPIO_BINARY_SENSOR_INTERRUPT void IRAM_ATTR GPIOBinarySensorStore::gpio_intr(GPIOBinarySensorStore *arg) { bool new_state = arg->isr_pin_.digital_read(); if (new_state != arg->state_) { @@ -43,28 +46,36 @@ void GPIOBinarySensorStore::setup(InternalGPIOPin *pin, Component *component) { // Attach interrupt - from this point on, any changes will be caught by the interrupt pin->attach_interrupt(&GPIOBinarySensorStore::gpio_intr, this, this->interrupt_type_); } +#endif // USE_GPIO_BINARY_SENSOR_INTERRUPT void GPIOBinarySensor::setup() { +#ifdef USE_GPIO_BINARY_SENSOR_INTERRUPT if (this->store_.use_interrupt_) { auto *internal_pin = static_cast(this->pin_); this->store_.setup(internal_pin, this); this->publish_initial_state(this->store_.get_state()); - } else { - this->pin_->setup(); - this->publish_initial_state(this->pin_->digital_read()); + return; } +#endif + this->pin_->setup(); + this->publish_initial_state(this->pin_->digital_read()); } void GPIOBinarySensor::dump_config() { LOG_BINARY_SENSOR("", "GPIO Binary Sensor", this); LOG_PIN(" Pin: ", this->pin_); +#ifdef USE_GPIO_BINARY_SENSOR_INTERRUPT ESP_LOGCONFIG(TAG, " Mode: %s", LOG_STR_ARG(gpio_mode_to_string(this->store_.use_interrupt_))); if (this->store_.use_interrupt_) { ESP_LOGCONFIG(TAG, " Interrupt Type: %s", LOG_STR_ARG(interrupt_type_to_string(this->store_.interrupt_type_))); } +#else + ESP_LOGCONFIG(TAG, " Mode: polling"); +#endif } void GPIOBinarySensor::loop() { +#ifdef USE_GPIO_BINARY_SENSOR_INTERRUPT if (this->store_.use_interrupt_) { if (this->store_.is_changed()) { // Clear the flag immediately to minimize the window where we might miss changes @@ -78,9 +89,10 @@ void GPIOBinarySensor::loop() { // No changes, disable the loop until the next interrupt this->disable_loop(); } - } else { - this->publish_state(this->pin_->digital_read()); + return; } +#endif + this->publish_state(this->pin_->digital_read()); } float GPIOBinarySensor::get_setup_priority() const { return setup_priority::HARDWARE; } diff --git a/esphome/components/gpio/binary_sensor/gpio_binary_sensor.h b/esphome/components/gpio/binary_sensor/gpio_binary_sensor.h index 100edb4cca..956443fab5 100644 --- a/esphome/components/gpio/binary_sensor/gpio_binary_sensor.h +++ b/esphome/components/gpio/binary_sensor/gpio_binary_sensor.h @@ -1,6 +1,7 @@ #pragma once #include "esphome/core/component.h" +#include "esphome/core/defines.h" #include "esphome/core/hal.h" #include "esphome/core/helpers.h" #include "esphome/components/binary_sensor/binary_sensor.h" @@ -10,6 +11,7 @@ namespace esphome::gpio { // Store class for ISR data and configuration (no vtables, ISR-safe) class GPIOBinarySensorStore { public: +#ifdef USE_GPIO_BINARY_SENSOR_INTERRUPT void setup(InternalGPIOPin *pin, Component *component); static void gpio_intr(GPIOBinarySensorStore *arg); @@ -29,15 +31,18 @@ class GPIOBinarySensorStore { // Separate method to clear the flag this->changed_ = false; } +#endif protected: friend class GPIOBinarySensor; +#ifdef USE_GPIO_BINARY_SENSOR_INTERRUPT ISRInternalGPIOPin isr_pin_; Component *component_{nullptr}; // Pointer to the component for enable_loop_soon_any_context() volatile bool state_{false}; volatile bool changed_{false}; - bool use_interrupt_{true}; gpio::InterruptType interrupt_type_{gpio::INTERRUPT_ANY_EDGE}; + bool use_interrupt_{true}; +#endif }; class GPIOBinarySensor final : public binary_sensor::BinarySensor, public Component { @@ -46,8 +51,14 @@ class GPIOBinarySensor final : public binary_sensor::BinarySensor, public Compon // Interrupts are only detached on reboot when memory is cleared anyway. void set_pin(GPIOPin *pin) { this->pin_ = pin; } +#ifdef USE_GPIO_BINARY_SENSOR_INTERRUPT void set_use_interrupt(bool use_interrupt) { this->store_.use_interrupt_ = use_interrupt; } void set_interrupt_type(gpio::InterruptType type) { this->store_.interrupt_type_ = type; } +#else + // Polling-only build: codegen still emits set_use_interrupt(false) calls, + // so keep the setter as an inlined no-op instead of storing the flag. + void set_use_interrupt(bool /*use_interrupt*/) {} +#endif // ========== INTERNAL METHODS ========== // (In most use cases you won't need these) /// Setup pin diff --git a/esphome/core/defines.h b/esphome/core/defines.h index 5f34437145..42da0191ed 100644 --- a/esphome/core/defines.h +++ b/esphome/core/defines.h @@ -72,6 +72,7 @@ #define USE_ESP32_IMPROV_STATE_CALLBACK #define USE_EVENT #define USE_FAN +#define USE_GPIO_BINARY_SENSOR_INTERRUPT #define USE_GPIO_SWITCH_INTERLOCK #define USE_GRAPH #define USE_GRAPHICAL_DISPLAY_MENU diff --git a/tests/component_tests/gpio/test_gpio_binary_sensor.py b/tests/component_tests/gpio/test_gpio_binary_sensor.py index f336a9105e..60494d9cba 100644 --- a/tests/component_tests/gpio/test_gpio_binary_sensor.py +++ b/tests/component_tests/gpio/test_gpio_binary_sensor.py @@ -3,10 +3,15 @@ from __future__ import annotations from collections.abc import Callable +import logging from pathlib import Path import pytest +from esphome.core import CORE + +INTERRUPT_DEFINE = "USE_GPIO_BINARY_SENSOR_INTERRUPT" + def test_gpio_binary_sensor_basic_setup( generate_main: Callable[[str | Path], str], @@ -69,3 +74,62 @@ def test_gpio_binary_sensor_explicit_polling_mode( ) assert "bs_polling->set_use_interrupt(false);" in main_cpp + + +def test_gpio_binary_sensor_interrupt_emits_define( + generate_main: Callable[[str | Path], str], +) -> None: + """ + An interrupt-mode sensor must emit the define that compiles the ISR code, + since the platform ISR pin implementation is only built when needed + """ + generate_main("tests/component_tests/gpio/test_gpio_binary_sensor.yaml") + + assert INTERRUPT_DEFINE in {d.name for d in CORE.defines} + + +def test_gpio_binary_sensor_polling_omits_define( + generate_main: Callable[[str | Path], str], +) -> None: + """ + A polling-only config must not emit the interrupt define, so the ISR code + (and its reference to ISRInternalGPIOPin) is compiled out + """ + generate_main("tests/component_tests/gpio/test_gpio_binary_sensor_polling.yaml") + + assert INTERRUPT_DEFINE not in {d.name for d in CORE.defines} + + +def test_gpio_binary_sensor_mixed_modes_emit_define( + generate_main: Callable[[str | Path], str], +) -> None: + """ + With one interrupt and one polling sensor, the define is emitted and the + polling instance still opts out via its setter + """ + main_cpp = generate_main( + "tests/component_tests/gpio/test_gpio_binary_sensor_mixed.yaml" + ) + + assert INTERRUPT_DEFINE in {d.name for d in CORE.defines} + assert "bs_polling->set_use_interrupt(false);" in main_cpp + assert "bs_interrupt->set_use_interrupt" not in main_cpp + + +def test_gpio_binary_sensor_expander_pin_omits_define( + generate_main: Callable[[str | Path], str], + caplog: pytest.LogCaptureFixture, +) -> None: + """ + An expander pin can't use interrupts: final validation falls back to + polling and the interrupt define must not be emitted. This is the config + that fails to link if the ISR code is compiled without an internal pin + """ + with caplog.at_level(logging.INFO): + main_cpp = generate_main( + "tests/component_tests/gpio/test_gpio_binary_sensor_expander.yaml" + ) + + assert "bs_expander->set_use_interrupt(false);" in main_cpp + assert INTERRUPT_DEFINE not in {d.name for d in CORE.defines} + assert "falling back to polling mode" in caplog.text diff --git a/tests/component_tests/gpio/test_gpio_binary_sensor_expander.yaml b/tests/component_tests/gpio/test_gpio_binary_sensor_expander.yaml new file mode 100644 index 0000000000..f153ccebfd --- /dev/null +++ b/tests/component_tests/gpio/test_gpio_binary_sensor_expander.yaml @@ -0,0 +1,21 @@ +esphome: + name: test + +esp32: + board: esp32dev + +i2c: + scl: 16 + sda: 17 + +ch422g: + - id: ch422g_hub + +binary_sensor: + - platform: gpio + name: "Expander Sensor" + id: bs_expander + pin: + ch422g: ch422g_hub + number: 1 + mode: INPUT diff --git a/tests/component_tests/gpio/test_gpio_binary_sensor_mixed.yaml b/tests/component_tests/gpio/test_gpio_binary_sensor_mixed.yaml new file mode 100644 index 0000000000..0e8c7ec3fd --- /dev/null +++ b/tests/component_tests/gpio/test_gpio_binary_sensor_mixed.yaml @@ -0,0 +1,17 @@ +esphome: + name: test + +esp32: + board: esp32dev + +binary_sensor: + - platform: gpio + pin: 5 + name: "Interrupt Sensor" + id: bs_interrupt + + - platform: gpio + pin: 4 + name: "Polling Sensor" + id: bs_polling + use_interrupt: false From 31afd94a30dfa134548864a6123c6c74ce1218f7 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sun, 23 Aug 2026 18:35:45 -0500 Subject: [PATCH 03/10] [noise] Declare libsodium as a direct dependency (#18692) --- esphome/components/noise/__init__.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/esphome/components/noise/__init__.py b/esphome/components/noise/__init__.py index e5fcc94332..3a8e2609ef 100644 --- a/esphome/components/noise/__init__.py +++ b/esphome/components/noise/__init__.py @@ -64,6 +64,11 @@ def encryption_schema(config: ConfigType | None) -> ConfigType: async def to_code(config: ConfigType) -> None: cg.add_define("USE_NOISE") cg.add_library("esphome/noise-c", "0.1.21") + # noise-c depends on libsodium, but declaring it here too lets the + # library manager see the full set up front instead of discovering + # libsodium only after noise-c has downloaded, so the two can download + # in parallel. The version must match noise-c's library.json. + cg.add_library("esphome/libsodium", "1.10021.4") # Enable optimized memzero/memcmp in libsodium instead of volatile byte loops cg.add_build_flag("-DHAVE_WEAK_SYMBOLS=1") cg.add_build_flag("-DHAVE_INLINE_ASM=1") From c9e91be35fe834e76f6b9735d7f21cb25ef89a3b Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sun, 23 Aug 2026 18:45:26 -0500 Subject: [PATCH 04/10] [web_server_idf] Skip multipart parser sources when OTA upload is disabled (#18534) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com> --- esphome/components/web_server_idf/__init__.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/esphome/components/web_server_idf/__init__.py b/esphome/components/web_server_idf/__init__.py index adf21ddc49..1f195425f5 100644 --- a/esphome/components/web_server_idf/__init__.py +++ b/esphome/components/web_server_idf/__init__.py @@ -2,6 +2,7 @@ from esphome.components.esp32 import ( add_idf_sdkconfig_option, include_builtin_idf_component, ) +from esphome.config_helpers import filter_source_files_from_defines import esphome.config_validation as cv CODEOWNERS = ["@dentra"] @@ -18,3 +19,10 @@ async def to_code(config): # Re-enable esp-tls (excluded by default to save compile time); # web_server_idf.cpp includes for digest auth include_builtin_idf_component("esp-tls") + + +# multipart.cpp is fully #ifdef'd on USE_WEBSERVER_OTA (set by the +# web_server OTA platform); skip it when OTA uploads are not configured. +FILTER_SOURCE_FILES = filter_source_files_from_defines( + {"multipart.cpp": "USE_WEBSERVER_OTA"} +) From 34c1a009b638f4fc0f92e2f0c0219ee34ea651ca Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sun, 23 Aug 2026 19:20:00 -0500 Subject: [PATCH 05/10] [core] Use filter_source_files_from_defines in api, socket and ethernet (#18674) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/api/__init__.py | 36 ++++++++++--------------- esphome/components/ethernet/__init__.py | 22 +++++++++------ esphome/components/socket/__init__.py | 23 +++++++--------- 3 files changed, 38 insertions(+), 43 deletions(-) diff --git a/esphome/components/api/__init__.py b/esphome/components/api/__init__.py index 53ad0fe5d7..a10bfd3418 100644 --- a/esphome/components/api/__init__.py +++ b/esphome/components/api/__init__.py @@ -14,7 +14,7 @@ from esphome.components.noise import ( # noqa: F401 encryption_schema, validate_encryption_key, ) -from esphome.config_helpers import get_logger_level +from esphome.config_helpers import filter_source_files_from_defines, get_logger_level import esphome.config_validation as cv from esphome.const import ( CONF_ACTION, @@ -835,11 +835,20 @@ async def api_connected_to_code( return var +# user_services.cpp is only needed when user defined actions exist; the +# frame helpers are fully #ifdef'd on the protocol defines set in to_code +# (both are set when encryption is configured without a key). +_define_filter = filter_source_files_from_defines( + { + "user_services.cpp": "USE_API_USER_DEFINED_ACTIONS", + "api_frame_helper_noise.cpp": "USE_API_NOISE", + "api_frame_helper_plaintext.cpp": "USE_API_PLAINTEXT", + } +) + + def FILTER_SOURCE_FILES() -> list[str]: - """Filter out api_pb2_dump.cpp when proto message dumping is not enabled, - user_services.cpp when no services are defined, and protocol-specific - implementations based on encryption configuration.""" - files_to_filter: list[str] = [] + files_to_filter = _define_filter() # api_pb2_dump.cpp is only needed when HAS_PROTO_MESSAGE_DUMP is defined # This is a particularly large file that still needs to be opened and read @@ -850,21 +859,4 @@ def FILTER_SOURCE_FILES() -> list[str]: if get_logger_level() != "VERY_VERBOSE": files_to_filter.append("api_pb2_dump.cpp") - # user_services.cpp is only needed when services are defined - config = CORE.config.get(DOMAIN, {}) - if config and not config.get(CONF_ACTIONS) and not config[CONF_CUSTOM_SERVICES]: - files_to_filter.append("user_services.cpp") - - # Filter protocol-specific implementations based on encryption configuration - encryption_config = config.get(CONF_ENCRYPTION) if config else None - - # If encryption is not configured at all, we only need plaintext - if encryption_config is None: - files_to_filter.append("api_frame_helper_noise.cpp") - # If encryption is configured with a key, we only need noise - elif encryption_config.get(CONF_KEY): - files_to_filter.append("api_frame_helper_plaintext.cpp") - # If encryption is configured but no key is provided, we need both - # (this allows a plaintext client to provide a noise key) - return files_to_filter diff --git a/esphome/components/ethernet/__init__.py b/esphome/components/ethernet/__init__.py index cd5904f501..a44a609d3c 100644 --- a/esphome/components/ethernet/__init__.py +++ b/esphome/components/ethernet/__init__.py @@ -10,7 +10,10 @@ from esphome.components.network import ( get_priority_interfaces_from_full_config, ip_address_literal, ) -from esphome.config_helpers import filter_source_files_from_platform +from esphome.config_helpers import ( + filter_source_files_from_defines, + filter_source_files_from_platform, +) import esphome.config_validation as cv from esphome.const import ( CONF_ADDRESS, @@ -821,8 +824,15 @@ _platform_filter = filter_source_files_from_platform( ) +# The custom W5500 SPI driver is fully #ifdef'd on USE_ESP32 and +# USE_ETHERNET_W5500 (the platform filter map above handles non-ESP32). +_define_filter = filter_source_files_from_defines( + {"w5500_custom_spi.cpp": "USE_ETHERNET_W5500"} +) + + def _filter_source_files() -> list[str]: - excluded = _platform_filter() + excluded = _platform_filter() + _define_filter() eth_data = CORE.data.get(KEY_ETHERNET, {}) eth_type = eth_data.get(ETHERNET_TYPE_KEY) # Only compile the custom JL1101 driver when JL1101 is configured @@ -836,12 +846,8 @@ def _filter_source_files() -> list[str]: # to avoid shadowing. Native IDF builds always need the custom driver. if cv.Version(5, 4, 2) <= idf_version() < cv.Version(6, 0, 0): excluded.append("esp_eth_phy_jl1101.c") - # The custom W5500 SPI driver is fully #ifdef'd on USE_ESP32 and - # USE_ETHERNET_W5500 (the platform filter map above handles non-ESP32); - # skip it entirely for the other ethernet types. - if eth_type != "W5500": - excluded.append("w5500_custom_spi.cpp") - return excluded + # The platform and define filters can both name the same file + return list(dict.fromkeys(excluded)) FILTER_SOURCE_FILES = _filter_source_files diff --git a/esphome/components/socket/__init__.py b/esphome/components/socket/__init__.py index cd002d9eb0..895fc8d03a 100644 --- a/esphome/components/socket/__init__.py +++ b/esphome/components/socket/__init__.py @@ -4,6 +4,7 @@ from enum import StrEnum import logging import esphome.codegen as cg +from esphome.config_helpers import filter_source_files_from_defines import esphome.config_validation as cv from esphome.core import CORE @@ -181,16 +182,12 @@ async def to_code(config): cg.add_build_flag("-DUSE_LWIP_FAST_SELECT") -def FILTER_SOURCE_FILES() -> list[str]: - """Return list of socket implementation files that aren't selected by the user.""" - impl = CORE.config["socket"][CONF_IMPLEMENTATION] - - # Build list of files to exclude based on selected implementation - excluded = [] - if impl != IMPLEMENTATION_LWIP_TCP: - excluded.append("lwip_raw_tcp_impl.cpp") - if impl != IMPLEMENTATION_BSD_SOCKETS: - excluded.append("bsd_sockets_impl.cpp") - if impl != IMPLEMENTATION_LWIP_SOCKETS: - excluded.append("lwip_sockets_impl.cpp") - return excluded +# Each implementation file is fully #ifdef'd on the define set in to_code +# for the selected implementation. +FILTER_SOURCE_FILES = filter_source_files_from_defines( + { + "lwip_raw_tcp_impl.cpp": "USE_SOCKET_IMPL_LWIP_TCP", + "bsd_sockets_impl.cpp": "USE_SOCKET_IMPL_BSD_SOCKETS", + "lwip_sockets_impl.cpp": "USE_SOCKET_IMPL_LWIP_SOCKETS", + } +) From d75f85b089745416246f6a43482945d35eb62af1 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sun, 23 Aug 2026 19:23:08 -0500 Subject: [PATCH 06/10] [network] Add tcp_send_buffer option (#18610) --- esphome/components/network/__init__.py | 25 ++++++ .../components/network/network_component.cpp | 10 +++ .../components/network/network_component.h | 1 + .../network/config/tcp_send_buffer.yaml | 14 +++ .../config/tcp_send_buffer_high_perf.yaml | 15 ++++ .../network/test_tcp_send_buffer.py | 85 +++++++++++++++++++ tests/components/network/test.esp32-idf.yaml | 1 + 7 files changed, 151 insertions(+) create mode 100644 tests/component_tests/network/config/tcp_send_buffer.yaml create mode 100644 tests/component_tests/network/config/tcp_send_buffer_high_perf.yaml create mode 100644 tests/component_tests/network/test_tcp_send_buffer.py diff --git a/esphome/components/network/__init__.py b/esphome/components/network/__init__.py index 3544fb2647..96a6f11b9a 100644 --- a/esphome/components/network/__init__.py +++ b/esphome/components/network/__init__.py @@ -26,6 +26,16 @@ _LOGGER = logging.getLogger(__name__) # Components can request high performance networking and this configures lwip and WiFi settings KEY_HIGH_PERFORMANCE_NETWORKING = "high_performance_networking" CONF_ENABLE_HIGH_PERFORMANCE = "enable_high_performance" +CONF_TCP_SEND_BUFFER = "tcp_send_buffer" + +# lwIP queues at most this many unsent/unacked bytes per TCP socket; the +# stock ESP-IDF default (5744 bytes) stalls bursty senders like a Bluetooth +# proxy streaming GATT notifications. Bounds follow the lwIP guidance for the +# default 1440 byte MSS: at least 2 x MSS, at most 65535 without window +# scaling. The cap is kept even when window scaling is on (high performance +# with PSRAM) as a deliberate conservative bound. +TCP_SEND_BUFFER_MIN = 2880 +TCP_SEND_BUFFER_MAX = 65535 # Network priority tracking infrastructure # Components can query this to determine their relative setup priority. @@ -306,6 +316,11 @@ CONFIG_SCHEMA = cv.All( cv.Optional(CONF_ENABLE_HIGH_PERFORMANCE): cv.All( cv.boolean, cv.only_on_esp32 ), + cv.Optional(CONF_TCP_SEND_BUFFER): cv.All( + cv.validate_bytes, + cv.int_range(min=TCP_SEND_BUFFER_MIN, max=TCP_SEND_BUFFER_MAX), + cv.only_on_esp32, + ), cv.Optional(CONF_PRIORITY): _validate_priority_list, } ), @@ -446,6 +461,16 @@ async def to_code(config): add_idf_sdkconfig_option("CONFIG_LWIP_TCP_RECVMBOX_SIZE", 64) add_idf_sdkconfig_option("CONFIG_LWIP_TCPIP_RECVMBOX_SIZE", 64) + # After the high performance block so an explicit size wins over the + # bundle's 65534 (last write wins in the sdkconfig store). + if (tcp_send_buffer := config.get(CONF_TCP_SEND_BUFFER)) is not None: + if CORE.is_esp32 and should_enable: + _LOGGER.info( + "TCP send buffer set to %d bytes by configuration (overriding high performance value)", + tcp_send_buffer, + ) + add_idf_sdkconfig_option("CONFIG_LWIP_TCP_SND_BUF_DEFAULT", tcp_send_buffer) + if CORE.is_nrf52: zephyr_add_prj_conf("NETWORKING", True) zephyr_add_prj_conf("NET_IPV6", True) diff --git a/esphome/components/network/network_component.cpp b/esphome/components/network/network_component.cpp index cf457bb661..7e05983733 100644 --- a/esphome/components/network/network_component.cpp +++ b/esphome/components/network/network_component.cpp @@ -6,6 +6,7 @@ #include "esp_err.h" #include "esp_netif.h" #include "esp_event.h" +#include "lwip/opt.h" #ifdef USE_NETWORK_DEFAULT_ROUTE #include "esphome/core/application.h" @@ -43,6 +44,15 @@ void NetworkComponent::setup() { } } +void NetworkComponent::dump_config() { + // The effective compile-time lwIP value, so the log reflects tcp_send_buffer + // or the high performance bundle when either changed it. + ESP_LOGCONFIG(TAG, + "Network:\n" + " TCP send buffer: %d bytes", + TCP_SND_BUF); +} + #ifdef USE_NETWORK_DEFAULT_ROUTE static esp_netif_t *connected_wifi_netif() { #ifdef USE_WIFI diff --git a/esphome/components/network/network_component.h b/esphome/components/network/network_component.h index 8d4866d4f0..870530974e 100644 --- a/esphome/components/network/network_component.h +++ b/esphome/components/network/network_component.h @@ -13,6 +13,7 @@ namespace esphome::network { class NetworkComponent final : public Component { public: void setup() override; + void dump_config() override; // AFTER_BLUETOOTH: BLE controller must initialize before esp_netif_init per IDF guidance. float get_setup_priority() const override { return setup_priority::AFTER_BLUETOOTH; } diff --git a/tests/component_tests/network/config/tcp_send_buffer.yaml b/tests/component_tests/network/config/tcp_send_buffer.yaml new file mode 100644 index 0000000000..59c3a29fd2 --- /dev/null +++ b/tests/component_tests/network/config/tcp_send_buffer.yaml @@ -0,0 +1,14 @@ +esphome: + name: test + +esp32: + board: esp32dev + framework: + type: esp-idf + +wifi: + ssid: "test_ssid" + password: "test_password" + +network: + tcp_send_buffer: 32kB diff --git a/tests/component_tests/network/config/tcp_send_buffer_high_perf.yaml b/tests/component_tests/network/config/tcp_send_buffer_high_perf.yaml new file mode 100644 index 0000000000..18dd1fe5fd --- /dev/null +++ b/tests/component_tests/network/config/tcp_send_buffer_high_perf.yaml @@ -0,0 +1,15 @@ +esphome: + name: test + +esp32: + board: esp32dev + framework: + type: esp-idf + +wifi: + ssid: "test_ssid" + password: "test_password" + +network: + enable_high_performance: true + tcp_send_buffer: 16384 diff --git a/tests/component_tests/network/test_tcp_send_buffer.py b/tests/component_tests/network/test_tcp_send_buffer.py new file mode 100644 index 0000000000..6498921243 --- /dev/null +++ b/tests/component_tests/network/test_tcp_send_buffer.py @@ -0,0 +1,85 @@ +"""Tests for the ``network: tcp_send_buffer:`` option. + +The option sets lwIP's per-socket TCP send buffer +(CONFIG_LWIP_TCP_SND_BUF_DEFAULT) on ESP-IDF. The stock default (5744 bytes) +stalls bursty senders such as a Bluetooth proxy streaming GATT notifications; +until now the only way to raise it was the all-or-nothing +``enable_high_performance`` bundle. +""" + +from collections.abc import Callable +from pathlib import Path + +import pytest +from voluptuous import Invalid + +from esphome import config_validation as cv +from esphome.components.esp32.const import ( + KEY_SDKCONFIG_OPTIONS, + KEY_VARIANT, + VARIANT_ESP32, +) +from esphome.components.network import ( + CONF_TCP_SEND_BUFFER, + CONFIG_SCHEMA, + TCP_SEND_BUFFER_MAX, + TCP_SEND_BUFFER_MIN, +) +from esphome.const import KEY_ESP32, KEY_FRAMEWORK_VERSION, PlatformFramework +from esphome.core import CORE +from tests.component_tests.types import SetCoreConfigCallable + + +def _sdkconfig_option(name: str) -> int | None: + return CORE.data[KEY_ESP32][KEY_SDKCONFIG_OPTIONS].get(name) + + +def test_tcp_send_buffer_sets_sdkconfig( + generate_main: Callable[[str | Path], str], + component_config_path: Callable[[str], Path], +) -> None: + generate_main(component_config_path("tcp_send_buffer.yaml")) + assert _sdkconfig_option("CONFIG_LWIP_TCP_SND_BUF_DEFAULT") == 32000 + + +def test_tcp_send_buffer_overrides_high_performance( + generate_main: Callable[[str | Path], str], + component_config_path: Callable[[str], Path], +) -> None: + """An explicit size wins over the high performance bundle's 65534.""" + generate_main(component_config_path("tcp_send_buffer_high_perf.yaml")) + assert _sdkconfig_option("CONFIG_LWIP_TCP_SND_BUF_DEFAULT") == 16384 + + +@pytest.mark.parametrize("value", [TCP_SEND_BUFFER_MIN, TCP_SEND_BUFFER_MAX]) +def test_boundary_values_accepted( + set_core_config: SetCoreConfigCallable, value: int +) -> None: + set_core_config( + PlatformFramework.ESP32_IDF, + core_data={KEY_FRAMEWORK_VERSION: cv.Version(5, 5, 5)}, + platform_data={KEY_VARIANT: VARIANT_ESP32}, + ) + assert CONFIG_SCHEMA({"tcp_send_buffer": value})[CONF_TCP_SEND_BUFFER] == value + + +@pytest.mark.parametrize("value", ["1kB", "128kB"]) +def test_out_of_range_rejected( + set_core_config: SetCoreConfigCallable, value: str +) -> None: + set_core_config( + PlatformFramework.ESP32_IDF, + core_data={KEY_FRAMEWORK_VERSION: cv.Version(5, 5, 5)}, + platform_data={KEY_VARIANT: VARIANT_ESP32}, + ) + with pytest.raises(Invalid): + CONFIG_SCHEMA({"tcp_send_buffer": value}) + + +def test_rejected_on_esp8266(set_core_config: SetCoreConfigCallable) -> None: + set_core_config( + PlatformFramework.ESP8266_ARDUINO, + core_data={KEY_FRAMEWORK_VERSION: cv.Version(3, 1, 2)}, + ) + with pytest.raises(Invalid, match="esp32"): + CONFIG_SCHEMA({"tcp_send_buffer": "32kB"}) diff --git a/tests/components/network/test.esp32-idf.yaml b/tests/components/network/test.esp32-idf.yaml index 7c01bafa0d..6ad365ead2 100644 --- a/tests/components/network/test.esp32-idf.yaml +++ b/tests/components/network/test.esp32-idf.yaml @@ -2,3 +2,4 @@ network: enable_high_performance: true + tcp_send_buffer: 32kB From 1ceaf699c2f4aaae4f90f5113ad4168e5c4977e7 Mon Sep 17 00:00:00 2001 From: Bonne Eggleston Date: Sun, 23 Aug 2026 17:33:53 -0700 Subject: [PATCH 07/10] [modbus_controller] Rename custom_command to custom_pdu; reject address 0; retire skip_updates (#18652) --- esphome/components/modbus/__init__.py | 33 ++++- .../components/modbus_controller/__init__.py | 121 ++++++++++++++++-- .../binary_sensor/__init__.py | 5 +- .../binary_sensor/modbus_binarysensor.h | 3 +- esphome/components/modbus_controller/const.py | 1 + .../modbus_controller/modbus_controller.cpp | 92 ++++++------- .../modbus_controller/modbus_controller.h | 21 +-- .../modbus_controller/number/__init__.py | 12 +- .../modbus_controller/number/modbus_number.h | 3 +- .../modbus_controller/output/__init__.py | 11 +- .../modbus_controller/output/modbus_output.h | 2 - .../modbus_controller/select/__init__.py | 10 +- .../modbus_controller/select/modbus_select.h | 5 +- .../modbus_controller/sensor/__init__.py | 5 +- .../modbus_controller/sensor/modbus_sensor.h | 3 +- .../modbus_controller/switch/__init__.py | 5 +- .../modbus_controller/switch/modbus_switch.h | 3 +- .../modbus_controller/text_sensor/__init__.py | 5 +- .../text_sensor/modbus_textsensor.h | 3 +- .../modbus_controller/test_custom_pdu.py | 47 +++++++ .../components/modbus_controller/common.yaml | 16 +++ ....yaml => uart_mock_modbus_custom_pdu.yaml} | 11 +- .../fixtures/uart_mock_modbus_grouping.yaml | 4 +- .../fixtures/uart_mock_modbus_offline.yaml | 6 +- .../uart_mock_modbus_shared_address.yaml | 21 +-- tests/integration/test_uart_mock_modbus.py | 28 ++-- 26 files changed, 315 insertions(+), 161 deletions(-) create mode 100644 tests/component_tests/modbus_controller/test_custom_pdu.py rename tests/integration/fixtures/{uart_mock_modbus_custom_command.yaml => uart_mock_modbus_custom_pdu.yaml} (83%) diff --git a/esphome/components/modbus/__init__.py b/esphome/components/modbus/__init__.py index 89ffc7facf..c9ba00f111 100644 --- a/esphome/components/modbus/__init__.py +++ b/esphome/components/modbus/__init__.py @@ -175,15 +175,34 @@ async def to_code(config: ConfigType) -> None: cg.add(var.set_turnaround_time(config[CONF_TURNAROUND_TIME])) +# The broadcast address (0) is delivered to every device and is never answered (Modbus 4.1), +# so it cannot identify an individual device or read anything back. +BROADCAST_ADDRESS = 0 + + +def reject_broadcast_address( + address: int, usage: str, guidance: str, path: list[str] | None = None +) -> None: + """Raise cv.Invalid if `address` is the Modbus broadcast address (0). + + `usage` names how the address is being used (e.g. "a server device address") and `guidance` + is a sentence telling the user what to do instead. Sharing the leading sentence here keeps the + call sites (server device, modbus_controller) from drifting apart. + """ + if address == BROADCAST_ADDRESS: + raise cv.Invalid( + f"Address 0 is the Modbus broadcast address and cannot be used as {usage}. {guidance}", + path, + ) + + def _validate_server_address(value: Any) -> int: address = cv.hex_uint8_t(value) - # The broadcast address (0) is delivered to every device and is never answered (Modbus 4.1), - # so it cannot identify an individual server device. - if address == 0: - raise cv.Invalid( - "Address 0 is the Modbus broadcast address and cannot be used as a " - "server device address. Assign a unique unit address instead." - ) + reject_broadcast_address( + address, + "a server device address", + "Assign a unique unit address instead.", + ) return address diff --git a/esphome/components/modbus_controller/__init__.py b/esphome/components/modbus_controller/__init__.py index f3cd28d138..188b552a3c 100644 --- a/esphome/components/modbus_controller/__init__.py +++ b/esphome/components/modbus_controller/__init__.py @@ -1,4 +1,6 @@ import binascii +from dataclasses import dataclass +from typing import Any from esphome import automation import esphome.codegen as cg @@ -10,7 +12,9 @@ from esphome.components.modbus.helpers import ( ) import esphome.config_validation as cv from esphome.const import CONF_ADDRESS, CONF_ID, CONF_LAMBDA, CONF_NAME, CONF_OFFSET +from esphome.core import CORE from esphome.cpp_helpers import logging +import esphome.final_validate as fv from esphome.types import ConfigType from .const import ( @@ -19,6 +23,7 @@ from .const import ( CONF_BYTE_OFFSET, CONF_COMMAND_THROTTLE, CONF_CUSTOM_COMMAND, + CONF_CUSTOM_PDU, CONF_FORCE_NEW_RANGE, CONF_MAX_CMD_RETRIES, CONF_MODBUS_CONTROLLER_ID, @@ -41,6 +46,8 @@ AUTO_LOAD = ["modbus"] MULTI_CONF = True +DOMAIN = "modbus_controller" + modbus_controller_ns = cg.esphome_ns.namespace("modbus_controller") ModbusController = modbus_controller_ns.class_("ModbusController", cg.PollingComponent) @@ -48,6 +55,19 @@ SensorItem = modbus_controller_ns.struct("SensorItem") _LOGGER = logging.getLogger(__name__) + +@dataclass +class ModbusControllerData: + # Set once the deprecated 'skip_updates' warning has been emitted so we warn only once total. + skip_updates_warned: bool = False + + +def _get_data() -> ModbusControllerData: + if DOMAIN not in CORE.data: + CORE.data[DOMAIN] = ModbusControllerData() + return CORE.data[DOMAIN] + + # Remove before 2027.2.0 _REMOVED_OPTIONS = { CONF_COMMAND_THROTTLE: "Command spacing is handled by the 'modbus' component - use 'turnaround_time' there instead.", @@ -67,6 +87,32 @@ def _warn_removed_options(config: ConfigType) -> ConfigType: return config +def _reject_broadcast_address(config: ConfigType) -> ConfigType: + """A modbus_controller polls one device, so its address cannot be the broadcast address (0): + a broadcast is never answered (Modbus 4.1), so no register could ever read back.""" + modbus.reject_broadcast_address( + config.get(CONF_ADDRESS), + "a modbus_controller device address", + "Assign the unit address of the device you want to poll.", + [CONF_ADDRESS], + ) + return config + + +# Remove before 2027.3.0. skip_updates (a per-sensor option) no longer does anything: every range is +# polled each update_interval. The key is still accepted so existing configs keep working, with a warning. +def validate_skip_updates_deprecated(value: Any) -> int: + data = _get_data() + if not data.skip_updates_warned: + _LOGGER.warning( + "[modbus_controller] 'skip_updates' no longer has any effect and will be removed in 2027.3.0. " + "To poll some registers less often, add a second modbus_controller with the same address and a " + "slower update_interval, and attach the slow sensors to it." + ) + data.skip_updates_warned = True + return cv.positive_int(value) + + CONFIG_SCHEMA = cv.All( cv.Schema( { @@ -92,13 +138,32 @@ CONFIG_SCHEMA = cv.All( .extend(cv.polling_component_schema("60s")) .extend(modbus.modbus_device_schema(0x01)), _warn_removed_options, + _reject_broadcast_address, ) ModbusItemBaseSchema = cv.Schema( { cv.GenerateID(CONF_MODBUS_CONTROLLER_ID): cv.use_id(ModbusController), cv.Optional(CONF_ADDRESS): cv.positive_int, - cv.Optional(CONF_CUSTOM_COMMAND): cv.ensure_list(cv.hex_uint8_t), + cv.Exclusive( + CONF_CUSTOM_PDU, + "custom_source", + f"{CONF_CUSTOM_PDU} and {CONF_CUSTOM_COMMAND} can't be used together", + ): cv.All( + cv.ensure_list(cv.hex_uint8_t), + cv.Length(min=1, max=modbus.MAX_PDU_SIZE), + ), + # Deprecated: takes a raw frame with a leading device address byte. Auto-migrated to + # custom_pdu in migrate_custom_command (final validate). Remove before 2027.3.0. The upper + # bound is MAX_PDU_SIZE + 1: the extra byte is the address the migration strips. + cv.Exclusive( + CONF_CUSTOM_COMMAND, + "custom_source", + f"{CONF_CUSTOM_PDU} and {CONF_CUSTOM_COMMAND} can't be used together", + ): cv.All( + cv.ensure_list(cv.hex_uint8_t), + cv.Length(min=2, max=modbus.MAX_PDU_SIZE + 1), + ), cv.Exclusive( CONF_OFFSET, "offset", @@ -110,7 +175,7 @@ ModbusItemBaseSchema = cv.Schema( f"{CONF_OFFSET} and {CONF_BYTE_OFFSET} can't be used together", ): cv.positive_int, cv.Optional(CONF_BITMASK, default=0xFFFFFFFF): cv.hex_uint32_t, - cv.Optional(CONF_SKIP_UPDATES, default=0): cv.positive_int, + cv.Optional(CONF_SKIP_UPDATES): validate_skip_updates_deprecated, cv.Optional(CONF_FORCE_NEW_RANGE, default=False): cv.boolean, cv.Optional(CONF_LAMBDA): cv.returning_lambda, cv.Optional(CONF_RESPONSE_SIZE, default=0): cv.positive_int, @@ -119,22 +184,56 @@ ModbusItemBaseSchema = cv.Schema( def validate_modbus_register(config): - if CONF_CUSTOM_COMMAND not in config and CONF_ADDRESS not in config: + # custom_command is the deprecated alias for custom_pdu (migrated later in final validate); treat + # either as "a custom frame is configured" so the address/register_type rules match. + has_custom = CONF_CUSTOM_PDU in config or CONF_CUSTOM_COMMAND in config + if not has_custom and CONF_ADDRESS not in config: raise cv.Invalid( - f" {CONF_ADDRESS} is a required property if '{CONF_CUSTOM_COMMAND}:' isn't used" + f" {CONF_ADDRESS} is a required property if '{CONF_CUSTOM_PDU}:' isn't used" ) - if CONF_CUSTOM_COMMAND in config and CONF_REGISTER_TYPE in config: + if has_custom and CONF_REGISTER_TYPE in config: raise cv.Invalid( - f"can't use '{CONF_REGISTER_TYPE}:' together with '{CONF_CUSTOM_COMMAND}:'", + f"can't use '{CONF_REGISTER_TYPE}:' together with '{CONF_CUSTOM_PDU}:'", ) - if CONF_CUSTOM_COMMAND not in config and CONF_REGISTER_TYPE not in config: + if not has_custom and CONF_REGISTER_TYPE not in config: raise cv.Invalid( - f" {CONF_REGISTER_TYPE} is a required property if '{CONF_CUSTOM_COMMAND}:' isn't used" + f" {CONF_REGISTER_TYPE} is a required property if '{CONF_CUSTOM_PDU}:' isn't used" ) return config +def migrate_custom_command(config: ConfigType) -> None: + """Final-validate: auto-migrate the deprecated custom_command (raw frame incl. device address) + to custom_pdu (PDU only). custom_pdu is always sent to the controller's own address, so a frame + whose address byte does not match the controller's address is a hard error (it targeted a + different unit). Mutates config in place; final validate discards the return value.""" + frame = config.get(CONF_CUSTOM_COMMAND) + if frame is None: + return + fconf = fv.full_config.get() + path = fconf.get_path_for_id(config[CONF_MODBUS_CONTROLLER_ID])[:-1] + controller = fconf.get_config_for_path(path) + # the controller's DEVICE address (from modbus_device_schema) + address = controller[CONF_ADDRESS] + if frame[0] != address: + raise cv.Invalid( + f"'custom_command' begins with device address {frame[0]:#04x}, but this sensor's " + f"modbus_controller uses address {address:#04x}. 'custom_command' is renamed to " + f"'custom_pdu', which is always sent to the controller's own address. Drop the leading " + f"address byte and use 'custom_pdu' if {address:#04x} is correct, or move this sensor to " + f"the modbus_controller for device {frame[0]:#04x}.", + [CONF_CUSTOM_COMMAND], + ) + _LOGGER.warning( + "[modbus_controller] 'custom_command' is deprecated and will be removed in 2027.3.0; " + "auto-migrated to 'custom_pdu' (dropped the leading device address byte). Rename the key " + "and drop that byte to silence this warning." + ) + config[CONF_CUSTOM_PDU] = list(frame[1:]) + del config[CONF_CUSTOM_COMMAND] + + def _final_validate(config: ConfigType) -> None: modbus.final_validate_modbus_device("modbus_controller", role="client")(config) @@ -156,7 +255,7 @@ def modbus_calc_properties(config): value_type = config[CONF_VALUE_TYPE] if reg_count == 0: reg_count = TYPE_REGISTER_MAP[value_type] - if CONF_CUSTOM_COMMAND in config: + if CONF_CUSTOM_PDU in config: if CONF_ADDRESS not in config: # generate a unique modbus address using the hash of the name # CONF_NAME set even if only CONF_ID is used. @@ -173,8 +272,8 @@ def modbus_calc_properties(config): async def add_modbus_base_properties( var, config, sensor_type, lambda_param_type=cg.float_, lambda_return_type=float ): - if CONF_CUSTOM_COMMAND in config: - cg.add(var.set_custom_data(config[CONF_CUSTOM_COMMAND])) + if CONF_CUSTOM_PDU in config: + cg.add(var.set_custom_pdu(config[CONF_CUSTOM_PDU])) if config[CONF_RESPONSE_SIZE] > 0: cg.add(var.set_register_size(config[CONF_RESPONSE_SIZE])) diff --git a/esphome/components/modbus_controller/binary_sensor/__init__.py b/esphome/components/modbus_controller/binary_sensor/__init__.py index 18d017e13f..6ff1975b1e 100644 --- a/esphome/components/modbus_controller/binary_sensor/__init__.py +++ b/esphome/components/modbus_controller/binary_sensor/__init__.py @@ -8,6 +8,7 @@ from .. import ( ModbusItemBaseSchema, SensorItem, add_modbus_base_properties, + migrate_custom_command, modbus_calc_properties, modbus_controller_ns, validate_modbus_register, @@ -17,7 +18,6 @@ from ..const import ( CONF_FORCE_NEW_RANGE, CONF_MODBUS_CONTROLLER_ID, CONF_REGISTER_TYPE, - CONF_SKIP_UPDATES, ) DEPENDENCIES = ["modbus_controller"] @@ -40,6 +40,8 @@ CONFIG_SCHEMA = cv.All( validate_modbus_register, ) +FINAL_VALIDATE_SCHEMA = migrate_custom_command + async def to_code(config): byte_offset, _ = modbus_calc_properties(config) @@ -49,7 +51,6 @@ async def to_code(config): config[CONF_ADDRESS], byte_offset, config[CONF_BITMASK], - config[CONF_SKIP_UPDATES], config[CONF_FORCE_NEW_RANGE], ) await cg.register_component(var, config) diff --git a/esphome/components/modbus_controller/binary_sensor/modbus_binarysensor.h b/esphome/components/modbus_controller/binary_sensor/modbus_binarysensor.h index 62a7fe93d3..f5ddbd82cc 100644 --- a/esphome/components/modbus_controller/binary_sensor/modbus_binarysensor.h +++ b/esphome/components/modbus_controller/binary_sensor/modbus_binarysensor.h @@ -11,13 +11,12 @@ namespace esphome::modbus_controller { class ModbusBinarySensor final : public Component, public binary_sensor::BinarySensor, public SensorItem { public: ModbusBinarySensor(modbus::EntityType register_type, uint16_t start_address, uint8_t offset, uint32_t bitmask, - uint16_t skip_updates, bool force_new_range) { + bool force_new_range) { this->register_type = register_type; this->set_address(start_address); this->set_offset_from_start_address(offset); this->bitmask = bitmask; this->sensor_value_type = SensorValueType::BIT; - this->skip_updates = skip_updates; this->force_new_range = force_new_range; if (modbus::helpers::is_entity_type_binary(register_type)) { diff --git a/esphome/components/modbus_controller/const.py b/esphome/components/modbus_controller/const.py index 0149a3cc49..8412a651b8 100644 --- a/esphome/components/modbus_controller/const.py +++ b/esphome/components/modbus_controller/const.py @@ -4,6 +4,7 @@ CONF_BYTE_OFFSET = "byte_offset" CONF_COMMAND_THROTTLE = "command_throttle" CONF_OFFLINE_SKIP_UPDATES = "offline_skip_updates" CONF_CUSTOM_COMMAND = "custom_command" +CONF_CUSTOM_PDU = "custom_pdu" CONF_FORCE_NEW_RANGE = "force_new_range" CONF_MAX_CMD_RETRIES = "max_cmd_retries" CONF_MODBUS_CONTROLLER_ID = "modbus_controller_id" diff --git a/esphome/components/modbus_controller/modbus_controller.cpp b/esphome/components/modbus_controller/modbus_controller.cpp index 515459f62a..fb7010cb4e 100644 --- a/esphome/components/modbus_controller/modbus_controller.cpp +++ b/esphome/components/modbus_controller/modbus_controller.cpp @@ -14,7 +14,6 @@ ModbusCommandItem::ModbusCommandItem(ModbusController &controller, modbus::Modbu RegisterRange &&range) : modbus::ModbusClientDevice(parent, address), sensors(std::move(range.sensors)), - skip_updates(range.skip_updates), register_type_(range.register_type), start_address_(range.start_address), register_count_(range.register_count), @@ -24,12 +23,14 @@ ModbusCommandItem::ModbusCommandItem(ModbusController &controller, modbus::Modbu ModbusCommandItem::ModbusCommandItem(ModbusController &controller, modbus::ModbusClientHub *parent, uint8_t address, SensorItem *sensor) : modbus::ModbusClientDevice(parent, address), - skip_updates(sensor->skip_updates), start_address_(sensor->start_address), register_count_(sensor->register_count), - function_code_(FunctionCode::CUSTOM), - custom_data_(&sensor->custom_data), + custom_pdu_(&sensor->custom_pdu), controller_(&controller) { + // The PDU's first byte is its real function code; carry it so dump_config, the on_command_sent + // trigger and the response callbacks report the actual code instead of CUSTOM. + if (!sensor->custom_pdu.empty()) + this->function_code_ = static_cast(sensor->custom_pdu.data()[0]); this->sensors.insert(sensor); } @@ -40,13 +41,12 @@ ModbusCommandItem::ModbusCommandItem(ModbusController &controller, modbus::Modbu ModbusCommandItem::ModbusCommandItem(const ModbusCommandItem &other) : modbus::ModbusClientDevice(other.parent_, other.address_), sensors(other.sensors), - skip_updates(other.skip_updates), on_data_func(other.on_data_func), register_type_(other.register_type_), start_address_(other.start_address_), register_count_(other.register_count_), function_code_(other.function_code_), - custom_data_(other.custom_data_), + custom_pdu_(other.custom_pdu_), controller_(other.controller_) { // SmallInlineBuffer is move-only, so deep-copy the bytes explicitly. this->payload.set(other.payload.data(), other.payload.size()); @@ -55,14 +55,13 @@ ModbusCommandItem::ModbusCommandItem(const ModbusCommandItem &other) ModbusCommandItem::ModbusCommandItem(ModbusCommandItem &&other) noexcept : modbus::ModbusClientDevice(other.parent_, other.address_), sensors(std::move(other.sensors)), - skip_updates(other.skip_updates), on_data_func(std::move(other.on_data_func)), payload(std::move(other.payload)), register_type_(other.register_type_), start_address_(other.start_address_), register_count_(other.register_count_), function_code_(other.function_code_), - custom_data_(other.custom_data_), + custom_pdu_(other.custom_pdu_), controller_(other.controller_) { other.parent_ = nullptr; } @@ -74,11 +73,14 @@ void ModbusCommandItem::on_response(std::span request_pdu, std::s auto data = modbus::helpers::server_pdu_payload(response_pdu); if (this->on_data_func) { this->on_data_func(this->register_type_, this->start_address_, data); - } else if (modbus::helpers::is_function_code_write(static_cast(this->function_code_))) { - // write acknowledgement - nothing to publish - } else { + } else if (!this->sensors.empty()) { + // A polling command always has sensors; a factory/write command never does. Test this before the + // write-code branch so a custom_pdu whose function code is a write (e.g. 0x17, whose response + // carries read data) still reaches its sensor instead of being treated as a bare write ack. for (auto *sensor : this->sensors) sensor->parse_and_publish(data); + } else if (modbus::helpers::is_function_code_write(static_cast(this->function_code_))) { + // write acknowledgement - nothing to publish } if (this->controller_ != nullptr) this->controller_->unqueue_command(this); @@ -116,13 +118,11 @@ void ModbusCommandItem::on_sent(std::span request_pdu) { // on_sent is this command's only callback, so drop the one-shot from the queue here, or it would leak. // Test the address the frame went to, not address_: a custom command's frame carries its own address // (frame[0]), which may differ from this controller's. (unqueue_command() is a no-op for a poll.) + // A custom polling command sends its PDU to this controller's own address, so only a factory custom + // command (a raw frame staged in payload) can carry a different address byte. uint8_t wire_address = this->address_; - if (this->function_code_ == FunctionCode::CUSTOM) { - std::span frame = - this->custom_data_ != nullptr ? std::span(*this->custom_data_) : this->payload; - if (!frame.empty()) - wire_address = frame[0]; - } + if (this->function_code_ == FunctionCode::CUSTOM && !this->payload.empty()) + wire_address = this->payload.data()[0]; if (wire_address == modbus::BROADCAST_ADDRESS) this->controller_->unqueue_command(this); } @@ -194,23 +194,11 @@ void ModbusController::sweep_completed_one_shots_() { [](const std::unique_ptr &item) { return item->pending_removal; }); } -void ModbusController::update_range_(ModbusCommandItem &cmd) { - if (this->update_counter_ % (cmd.skip_updates + 1) != 0) { - ESP_LOGVV(TAG, "Skipping update for range 0x%X", cmd.register_address()); - return; - } - // A refusal is already logged by the hub; note the affected range for controller-level diagnostics. - if (!cmd.send()) { - ESP_LOGD(TAG, "Poll refused by hub for range 0x%X", cmd.register_address()); - } -} - void ModbusController::update() { this->sweep_completed_one_shots_(); // reclaim one-shots deferred out of their own callbacks if (this->module_offline_) { - // Offline probing follows the offline cadence alone; per-range skip_updates resumes once the - // device is back online. Requiring both cadences to coincide would leave phase combinations - // where a probe never goes out. + // Offline probing follows the offline cadence alone; regular every-update polling resumes once + // the device is back online. if (offline_retry_due(this->update_counter_, this->module_offline_at_, this->offline_skip_updates_)) { ESP_LOGV(TAG, "Module offline - retrying"); this->cmd_non_responses_ = 0; // allow the probe through can_send() @@ -229,7 +217,9 @@ void ModbusController::update() { if (this->can_send()) { for (auto &cmd : this->polling_command_items_) { ESP_LOGVV(TAG, "Updating range 0x%X", cmd.register_address()); - this->update_range_(cmd); + // A refusal is already logged by the hub; note the affected range for controller-level diagnostics. + if (!cmd.send()) + ESP_LOGD(TAG, "Poll refused by hub for range 0x%X", cmd.register_address()); } } this->update_counter_++; @@ -264,8 +254,8 @@ void ModbusController::create_polling_commands_() { bool range_custom_size = false; SensorItem *prev = nullptr; for (SensorItem *curr : this->sensorset_) { - ESP_LOGV(TAG, "Register: 0x%X count=%d size=%zu offset=%u skip=%u addr=%p", curr->start_address, - curr->register_count, curr->get_register_size(), curr->offset, curr->skip_updates, curr); + ESP_LOGV(TAG, "Register: 0x%X count=%d size=%zu offset=%u addr=%p", curr->start_address, curr->register_count, + curr->get_register_size(), curr->offset, curr); const bool custom_size = curr->get_register_size() != static_cast(curr->register_count) * 2; @@ -296,14 +286,12 @@ void ModbusController::create_polling_commands_() { ESP_LOGV(TAG, "Extend range to include 0x%X", curr->start_address); } else if (range_shared && !range_forced && curr->start_address >= r.start_address && curr->start_address + curr->register_count <= r.start_address + r.register_count && - !range_custom_size && !custom_size && curr->skip_updates == r.skip_updates) { + !range_custom_size && !custom_size) { // The registers already fall inside a range that a shared-address join widened, so this sensor // reads its slice of that response instead of adding an overlapping second poll. The guards keep // it narrow: only a widened range, never a force-isolated one; only where every register in the // range returns two bytes, so interior positions follow from the addresses; only sensors genuinely - // inside it, which is why the lower bound is needed given the walk is not address-ordered; and - // only where the polling rates already match, since joining runs this sensor through the rate - // merge below and would otherwise change one of them. + // inside it, which is why the lower bound is needed given the walk is not address-ordered. const uint16_t addr_delta = curr->start_address - r.start_address; curr->offset = static_cast((curr->addresses_bits() ? addr_delta : addr_delta * 2) + curr->offset_from_start_address); @@ -329,7 +317,7 @@ void ModbusController::create_polling_commands_() { if (!join) { if (have_range) { - ESP_LOGV(TAG, "Add range 0x%X %d skip:%d", r.start_address, r.register_count, r.skip_updates); + ESP_LOGV(TAG, "Add range 0x%X %d", r.start_address, r.register_count); this->create_polling_command_(std::move(r)); } r = {}; @@ -341,11 +329,7 @@ void ModbusController::create_polling_commands_() { r.start_address = curr->start_address; r.register_count = curr->register_count; r.register_type = curr->register_type; - r.skip_updates = curr->skip_updates; have_range = true; - } else if (curr->skip_updates != 0) { - // use the lowest non-zero skip_updates for the whole range (0 is the default and is excluded) - r.skip_updates = (r.skip_updates != 0) ? std::min(r.skip_updates, curr->skip_updates) : curr->skip_updates; } // Every member records its range's first register. The resolved offset is relative to it, so the @@ -355,7 +339,7 @@ void ModbusController::create_polling_commands_() { prev = curr; } if (have_range) { - ESP_LOGV(TAG, "Add last range 0x%X %d skip:%d", r.start_address, r.register_count, r.skip_updates); + ESP_LOGV(TAG, "Add last range 0x%X %d", r.start_address, r.register_count); this->create_polling_command_(std::move(r)); } // Reclaim growth slack; safe here because nothing has registered with the hub yet (see the @@ -380,8 +364,8 @@ void ModbusController::dump_config() { } ESP_LOGCONFIG(TAG, "ranges"); for (auto &it : this->polling_command_items_) { - ESP_LOGCONFIG(TAG, " Range type=%u start=0x%X count=%d skip_updates=%d", static_cast(it.register_type()), - it.register_address(), it.register_count(), it.skip_updates); + ESP_LOGCONFIG(TAG, " Range type=%u start=0x%X count=%d", static_cast(it.register_type()), + it.register_address(), it.register_count()); } #endif } @@ -513,17 +497,19 @@ ModbusCommandItem ModbusCommandItem::create_custom_command( bool ModbusCommandItem::send() { bool accepted; - if (this->function_code_ != FunctionCode::CUSTOM) { + if (this->custom_pdu_ != nullptr) { + // Custom polling command: send the sensor's ready-made PDU (function code + data, no address byte) + // to this controller's own device address; the hub prepends the address and appends the CRC. + accepted = modbus::ModbusClientDevice::queue_pdu(std::span(*this->custom_pdu_)); + } else if (this->function_code_ != FunctionCode::CUSTOM) { accepted = this->queue_pdu(modbus::helpers::create_client_pdu( this->function_code_, this->start_address_, this->register_count_, this->payload.empty() ? nullptr : this->payload.data(), this->payload.size())); } else { - // Custom command: the bytes are a complete raw frame (address + PDU). Send the PDU to the frame's own - // address (which may differ from this controller's); the hub appends the CRC and routes the response - // back to this item by pointer. (send_raw() is deprecated, so queue_pdu() is called with the extracted - // address. Raw-frame semantics are kept here; the custom_pdu migration is a later step.) - std::span frame = - this->custom_data_ != nullptr ? std::span(*this->custom_data_) : this->payload; + // Factory custom command: payload holds a complete raw frame (address + PDU). Send the PDU to the + // frame's own address (which may differ from this controller's); the hub appends the CRC and routes + // the response back to this item by pointer. + std::span frame = this->payload; if (frame.empty()) { ESP_LOGW(TAG, "Empty custom command frame, not sent"); accepted = false; diff --git a/esphome/components/modbus_controller/modbus_controller.h b/esphome/components/modbus_controller/modbus_controller.h index fb0037a0e6..f36705cda4 100644 --- a/esphome/components/modbus_controller/modbus_controller.h +++ b/esphome/components/modbus_controller/modbus_controller.h @@ -157,7 +157,7 @@ class SensorItem { this->range_start_address = address; } - void set_custom_data(const std::vector &data) { custom_data = data; } + void set_custom_pdu(std::initializer_list pdu) { this->custom_pdu.set(pdu.begin(), pdu.size()); } size_t virtual get_register_size() const { if (this->addresses_bits()) { return 1; @@ -186,8 +186,7 @@ class SensorItem { uint8_t offset_from_start_address{0}; /// First register of the range this sensor is polled in; equals start_address for an unpolled item. uint16_t range_start_address{0}; - uint16_t skip_updates{0}; - std::vector custom_data{}; + SmallInlineBuffer<8> custom_pdu{}; bool force_new_range{false}; }; @@ -230,8 +229,7 @@ struct RegisterRange { uint16_t start_address; modbus::EntityType register_type; uint8_t register_count; - uint16_t skip_updates; // the config value - SensorSet sensors; // all sensors of this range + SensorSet sensors; // all sensors of this range }; /// A single modbus command. Each command is its own ModbusClientDevice: it sends its frame to the hub @@ -257,7 +255,6 @@ class ModbusCommandItem : public modbus::ModbusClientDevice { ModbusCommandItem &operator=(ModbusCommandItem &&) = delete; SensorSet sensors; // sensors served by this command (empty for factory/write commands) - uint16_t skip_updates{0}; std::function data)> on_data_func; /// Write data bytes for the command (register/coil values), or the raw frame of a one-shot custom /// command; reads leave it empty. Small-buffer optimized: fixed-size commands (single-register/coil @@ -378,7 +375,7 @@ class ModbusCommandItem : public modbus::ModbusClientDevice { uint16_t register_count_{0}; FunctionCode function_code_{FunctionCode::CUSTOM}; /// Custom polling commands reference the PDU bytes owned by their SensorItem instead of copying them. - const std::vector *custom_data_{nullptr}; + const SmallInlineBuffer<8> *custom_pdu_{nullptr}; ModbusController *controller_{nullptr}; }; @@ -462,19 +459,15 @@ class ModbusController final : public PollingComponent { void create_polling_commands_(); /// build one persistent polling command from a range and add it to polling_command_items_ void create_polling_command_(RegisterRange &&range) { - // A custom range polls the first sensor's custom_data (a ready-made raw frame); it needs the - // sensor constructor so the command references those bytes and decodes the real function code. - // The response still dispatches to every sensor in the range. + // A custom range polls the first sensor's custom_pdu (referenced, not copied); the sensor constructor + // decodes the real function code. The response still dispatches to every sensor in the range. if (range.register_type == EntityType::CUSTOM && !range.sensors.empty()) { auto &cmd = this->polling_command_items_.emplace_back(*this, this->hub_, this->address_, *range.sensors.begin()); cmd.sensors = std::move(range.sensors); - cmd.skip_updates = range.skip_updates; // the range's merged rate, not the first sensor's } else { this->polling_command_items_.emplace_back(*this, this->hub_, this->address_, std::move(range)); } } - /// send a range's polling command if it is due this update - void update_range_(ModbusCommandItem &cmd); /// The hub this controller's commands/entities send through, and the modbus address they target. modbus::ModbusClientHub *hub_{nullptr}; uint8_t address_{0}; @@ -496,7 +489,7 @@ class ModbusController final : public PollingComponent { bool module_offline_{false}; /// update_counter_ value at which the module went offline (for offline_skip_updates timing) uint16_t module_offline_at_{0}; - /// counts update() cycles; drives skip_updates and offline timing + /// counts update() cycles; drives the offline-retry cadence uint16_t update_counter_{0}; /// consecutive non-responses; drives can_send() and offline detection uint8_t cmd_non_responses_{0}; diff --git a/esphome/components/modbus_controller/number/__init__.py b/esphome/components/modbus_controller/number/__init__.py index 7563adfad9..39d04e8d91 100644 --- a/esphome/components/modbus_controller/number/__init__.py +++ b/esphome/components/modbus_controller/number/__init__.py @@ -18,16 +18,17 @@ from .. import ( ModbusItemBaseSchema, SensorItem, add_modbus_base_properties, + migrate_custom_command, modbus_calc_properties, modbus_controller_ns, ) from ..const import ( CONF_BITMASK, CONF_CUSTOM_COMMAND, + CONF_CUSTOM_PDU, CONF_FORCE_NEW_RANGE, CONF_MODBUS_CONTROLLER_ID, CONF_REGISTER_TYPE, - CONF_SKIP_UPDATES, CONF_USE_WRITE_MULTIPLE, CONF_VALUE_TYPE, CONF_WRITE_LAMBDA, @@ -53,9 +54,11 @@ def validate_min_max(config): def validate_modbus_number(config): - if CONF_CUSTOM_COMMAND not in config and CONF_ADDRESS not in config: + # custom_command is the deprecated alias for custom_pdu (migrated later in final validate). + has_custom = CONF_CUSTOM_PDU in config or CONF_CUSTOM_COMMAND in config + if not has_custom and CONF_ADDRESS not in config: raise cv.Invalid( - f" {CONF_ADDRESS} is a required property if '{CONF_CUSTOM_COMMAND}:' isn't used" + f" {CONF_ADDRESS} is a required property if '{CONF_CUSTOM_PDU}:' isn't used" ) return config @@ -83,6 +86,8 @@ CONFIG_SCHEMA = cv.All( validate_modbus_number, ) +FINAL_VALIDATE_SCHEMA = migrate_custom_command + async def to_code(config): byte_offset, reg_count = modbus_calc_properties(config) @@ -94,7 +99,6 @@ async def to_code(config): config[CONF_BITMASK], config[CONF_VALUE_TYPE], reg_count, - config[CONF_SKIP_UPDATES], config[CONF_FORCE_NEW_RANGE], ) diff --git a/esphome/components/modbus_controller/number/modbus_number.h b/esphome/components/modbus_controller/number/modbus_number.h index 1f0d0581eb..538a982f80 100644 --- a/esphome/components/modbus_controller/number/modbus_number.h +++ b/esphome/components/modbus_controller/number/modbus_number.h @@ -13,14 +13,13 @@ using value_to_data_t = std::function(float); class ModbusNumber final : public number::Number, public Component, public SensorItem { public: ModbusNumber(modbus::EntityType register_type, uint16_t start_address, uint8_t offset, uint32_t bitmask, - SensorValueType value_type, int register_count, uint16_t skip_updates, bool force_new_range) { + SensorValueType value_type, int register_count, bool force_new_range) { this->register_type = register_type; this->set_address(start_address); this->set_offset_from_start_address(offset); this->bitmask = bitmask; this->sensor_value_type = value_type; this->register_count = register_count; - this->skip_updates = skip_updates; this->force_new_range = force_new_range; }; diff --git a/esphome/components/modbus_controller/output/__init__.py b/esphome/components/modbus_controller/output/__init__.py index 27d212d58d..178c99caa1 100644 --- a/esphome/components/modbus_controller/output/__init__.py +++ b/esphome/components/modbus_controller/output/__init__.py @@ -12,6 +12,7 @@ from .. import ( ) from ..const import ( CONF_CUSTOM_COMMAND, + CONF_CUSTOM_PDU, CONF_MODBUS_CONTROLLER_ID, CONF_REGISTER_TYPE, CONF_USE_WRITE_MULTIPLE, @@ -37,8 +38,11 @@ CONFIG_SCHEMA = cv.typed_schema( { cv.GenerateID(): cv.declare_id(ModbusBinaryOutput), cv.Required(CONF_ADDRESS): cv.positive_int, + cv.Optional(CONF_CUSTOM_PDU): cv.invalid( + "custom_pdu is not supported for outputs; use a write_lambda instead" + ), cv.Optional(CONF_CUSTOM_COMMAND): cv.invalid( - "custom_command is not supported for outputs" + "custom_command is not supported for outputs; use a write_lambda instead" ), cv.Optional(CONF_WRITE_LAMBDA): cv.returning_lambda, cv.Optional(CONF_USE_WRITE_MULTIPLE, default=False): cv.boolean, @@ -48,8 +52,11 @@ CONFIG_SCHEMA = cv.typed_schema( { cv.GenerateID(): cv.declare_id(ModbusFloatOutput), cv.Required(CONF_ADDRESS): cv.positive_int, + cv.Optional(CONF_CUSTOM_PDU): cv.invalid( + "custom_pdu is not supported for outputs; use a write_lambda instead" + ), cv.Optional(CONF_CUSTOM_COMMAND): cv.invalid( - "custom_command is not supported for outputs" + "custom_command is not supported for outputs; use a write_lambda instead" ), cv.Optional(CONF_VALUE_TYPE, default="U_WORD"): cv.enum( SENSOR_VALUE_TYPE diff --git a/esphome/components/modbus_controller/output/modbus_output.h b/esphome/components/modbus_controller/output/modbus_output.h index 17eb8e3a8f..e79c442aa4 100644 --- a/esphome/components/modbus_controller/output/modbus_output.h +++ b/esphome/components/modbus_controller/output/modbus_output.h @@ -17,7 +17,6 @@ class ModbusFloatOutput final : public output::FloatOutput, public Component, pu this->bitmask = 0xFFFFFFFF; this->register_count = register_count; this->sensor_value_type = value_type; - this->skip_updates = 0; this->set_address(this->start_address + offset); this->set_offset_from_start_address(0); } @@ -48,7 +47,6 @@ class ModbusBinaryOutput final : public output::BinaryOutput, public Component, this->set_address(start_address); this->bitmask = 0xFFFFFFFF; this->sensor_value_type = SensorValueType::BIT; - this->skip_updates = 0; this->register_count = 1; this->set_address(this->start_address + offset); this->set_offset_from_start_address(0); diff --git a/esphome/components/modbus_controller/select/__init__.py b/esphome/components/modbus_controller/select/__init__.py index 5127360770..1d77f9235d 100644 --- a/esphome/components/modbus_controller/select/__init__.py +++ b/esphome/components/modbus_controller/select/__init__.py @@ -4,7 +4,12 @@ from esphome.components.modbus.helpers import SENSOR_VALUE_TYPE, TYPE_REGISTER_M import esphome.config_validation as cv from esphome.const import CONF_ADDRESS, CONF_ID, CONF_LAMBDA, CONF_OPTIMISTIC -from .. import ModbusController, SensorItem, modbus_controller_ns +from .. import ( + ModbusController, + SensorItem, + modbus_controller_ns, + validate_skip_updates_deprecated, +) from ..const import ( CONF_FORCE_NEW_RANGE, CONF_MODBUS_CONTROLLER_ID, @@ -69,7 +74,7 @@ CONFIG_SCHEMA = cv.All( INTEGER_SENSOR_VALUE_TYPE ), cv.Optional(CONF_REGISTER_COUNT): cv.positive_int, - cv.Optional(CONF_SKIP_UPDATES, default=0): cv.positive_int, + cv.Optional(CONF_SKIP_UPDATES): validate_skip_updates_deprecated, cv.Optional(CONF_FORCE_NEW_RANGE, default=False): cv.boolean, cv.Required(CONF_OPTIONSMAP): ensure_option_map(), cv.Optional(CONF_USE_WRITE_MULTIPLE, default=False): cv.boolean, @@ -95,7 +100,6 @@ async def to_code(config): value_type, config[CONF_ADDRESS], reg_count, - config[CONF_SKIP_UPDATES], config[CONF_FORCE_NEW_RANGE], list(options_map.values()), ) diff --git a/esphome/components/modbus_controller/select/modbus_select.h b/esphome/components/modbus_controller/select/modbus_select.h index e1ae578ddf..41ebd4f658 100644 --- a/esphome/components/modbus_controller/select/modbus_select.h +++ b/esphome/components/modbus_controller/select/modbus_select.h @@ -11,8 +11,8 @@ namespace esphome::modbus_controller { class ModbusSelect final : public Component, public select::Select, public SensorItem { public: - ModbusSelect(SensorValueType sensor_value_type, uint16_t start_address, uint8_t register_count, uint16_t skip_updates, - bool force_new_range, std::vector mapping) { + ModbusSelect(SensorValueType sensor_value_type, uint16_t start_address, uint8_t register_count, bool force_new_range, + std::vector mapping) { this->register_type = modbus::EntityType::HOLDING; // not configurable this->sensor_value_type = sensor_value_type; this->set_address(start_address); @@ -20,7 +20,6 @@ class ModbusSelect final : public Component, public select::Select, public Senso this->bitmask = 0xFFFFFFFF; // not configurable this->register_count = register_count; this->response_bytes = 0; // not configurable - this->skip_updates = skip_updates; this->force_new_range = force_new_range; this->mapping_ = std::move(mapping); } diff --git a/esphome/components/modbus_controller/sensor/__init__.py b/esphome/components/modbus_controller/sensor/__init__.py index 5b72586c66..c3c9bd4718 100644 --- a/esphome/components/modbus_controller/sensor/__init__.py +++ b/esphome/components/modbus_controller/sensor/__init__.py @@ -8,6 +8,7 @@ from .. import ( ModbusItemBaseSchema, SensorItem, add_modbus_base_properties, + migrate_custom_command, modbus_calc_properties, modbus_controller_ns, validate_modbus_register, @@ -18,7 +19,6 @@ from ..const import ( CONF_MODBUS_CONTROLLER_ID, CONF_REGISTER_COUNT, CONF_REGISTER_TYPE, - CONF_SKIP_UPDATES, CONF_VALUE_TYPE, ) @@ -44,6 +44,8 @@ CONFIG_SCHEMA = cv.All( validate_modbus_register, ) +FINAL_VALIDATE_SCHEMA = migrate_custom_command + async def to_code(config): byte_offset, reg_count = modbus_calc_properties(config) @@ -56,7 +58,6 @@ async def to_code(config): config[CONF_BITMASK], value_type, reg_count, - config[CONF_SKIP_UPDATES], config[CONF_FORCE_NEW_RANGE], ) await cg.register_component(var, config) diff --git a/esphome/components/modbus_controller/sensor/modbus_sensor.h b/esphome/components/modbus_controller/sensor/modbus_sensor.h index 9d66b2afa7..68dc9e6fcc 100644 --- a/esphome/components/modbus_controller/sensor/modbus_sensor.h +++ b/esphome/components/modbus_controller/sensor/modbus_sensor.h @@ -11,14 +11,13 @@ namespace esphome::modbus_controller { class ModbusSensor final : public Component, public sensor::Sensor, public SensorItem { public: ModbusSensor(modbus::EntityType register_type, uint16_t start_address, uint8_t offset, uint32_t bitmask, - SensorValueType value_type, int register_count, uint16_t skip_updates, bool force_new_range) { + SensorValueType value_type, int register_count, bool force_new_range) { this->register_type = register_type; this->set_address(start_address); this->set_offset_from_start_address(offset); this->bitmask = bitmask; this->sensor_value_type = value_type; this->register_count = register_count; - this->skip_updates = skip_updates; this->force_new_range = force_new_range; } diff --git a/esphome/components/modbus_controller/switch/__init__.py b/esphome/components/modbus_controller/switch/__init__.py index a40c15ab92..35ad12087c 100644 --- a/esphome/components/modbus_controller/switch/__init__.py +++ b/esphome/components/modbus_controller/switch/__init__.py @@ -8,6 +8,7 @@ from .. import ( ModbusItemBaseSchema, SensorItem, add_modbus_base_properties, + migrate_custom_command, modbus_calc_properties, modbus_controller_ns, validate_modbus_register, @@ -17,7 +18,6 @@ from ..const import ( CONF_FORCE_NEW_RANGE, CONF_MODBUS_CONTROLLER_ID, CONF_REGISTER_TYPE, - CONF_SKIP_UPDATES, CONF_USE_WRITE_MULTIPLE, CONF_WRITE_LAMBDA, ) @@ -45,6 +45,8 @@ CONFIG_SCHEMA = cv.All( validate_modbus_register, ) +FINAL_VALIDATE_SCHEMA = migrate_custom_command + async def to_code(config): byte_offset, _ = modbus_calc_properties(config) @@ -54,7 +56,6 @@ async def to_code(config): config[CONF_ADDRESS], byte_offset, config[CONF_BITMASK], - config[CONF_SKIP_UPDATES], config[CONF_FORCE_NEW_RANGE], ) await cg.register_component(var, config) diff --git a/esphome/components/modbus_controller/switch/modbus_switch.h b/esphome/components/modbus_controller/switch/modbus_switch.h index e5b8cf5c21..c21a1939bc 100644 --- a/esphome/components/modbus_controller/switch/modbus_switch.h +++ b/esphome/components/modbus_controller/switch/modbus_switch.h @@ -11,13 +11,12 @@ namespace esphome::modbus_controller { class ModbusSwitch final : public Component, public switch_::Switch, public SensorItem { public: ModbusSwitch(modbus::EntityType register_type, uint16_t start_address, uint8_t offset, uint32_t bitmask, - uint16_t skip_updates, bool force_new_range) { + bool force_new_range) { this->register_type = register_type; this->set_address(start_address); this->set_offset_from_start_address(offset); this->bitmask = bitmask; this->sensor_value_type = SensorValueType::BIT; - this->skip_updates = skip_updates; this->register_count = 1; if (register_type == modbus::EntityType::HOLDING || register_type == modbus::EntityType::COIL) { this->set_address(this->start_address + offset); diff --git a/esphome/components/modbus_controller/text_sensor/__init__.py b/esphome/components/modbus_controller/text_sensor/__init__.py index 93ecd31168..e8447658e2 100644 --- a/esphome/components/modbus_controller/text_sensor/__init__.py +++ b/esphome/components/modbus_controller/text_sensor/__init__.py @@ -8,6 +8,7 @@ from .. import ( ModbusItemBaseSchema, SensorItem, add_modbus_base_properties, + migrate_custom_command, modbus_calc_properties, modbus_controller_ns, validate_modbus_register, @@ -19,7 +20,6 @@ from ..const import ( CONF_REGISTER_COUNT, CONF_REGISTER_TYPE, CONF_RESPONSE_SIZE, - CONF_SKIP_UPDATES, ) DEPENDENCIES = ["modbus_controller"] @@ -55,6 +55,8 @@ CONFIG_SCHEMA = cv.All( validate_modbus_register, ) +FINAL_VALIDATE_SCHEMA = migrate_custom_command + async def to_code(config): byte_offset, reg_count = modbus_calc_properties(config) @@ -70,7 +72,6 @@ async def to_code(config): reg_count, config[CONF_RESPONSE_SIZE], config[CONF_RAW_ENCODE], - config[CONF_SKIP_UPDATES], config[CONF_FORCE_NEW_RANGE], ) diff --git a/esphome/components/modbus_controller/text_sensor/modbus_textsensor.h b/esphome/components/modbus_controller/text_sensor/modbus_textsensor.h index 5bb16eb58a..9e8dce57e7 100644 --- a/esphome/components/modbus_controller/text_sensor/modbus_textsensor.h +++ b/esphome/components/modbus_controller/text_sensor/modbus_textsensor.h @@ -13,14 +13,13 @@ enum class RawEncoding { NONE = 0, HEXBYTES = 1, COMMA = 2, ANSI = 3 }; class ModbusTextSensor final : public Component, public text_sensor::TextSensor, public SensorItem { public: ModbusTextSensor(modbus::EntityType register_type, uint16_t start_address, uint8_t offset, uint8_t register_count, - uint16_t response_bytes, RawEncoding encode, uint16_t skip_updates, bool force_new_range) { + uint16_t response_bytes, RawEncoding encode, bool force_new_range) { this->register_type = register_type; this->set_address(start_address); this->set_offset_from_start_address(offset); this->response_bytes = response_bytes; this->register_count = register_count; this->encode_ = encode; - this->skip_updates = skip_updates; this->bitmask = 0xFFFFFFFF; this->sensor_value_type = SensorValueType::RAW; this->force_new_range = force_new_range; diff --git a/tests/component_tests/modbus_controller/test_custom_pdu.py b/tests/component_tests/modbus_controller/test_custom_pdu.py new file mode 100644 index 0000000000..a5d065c965 --- /dev/null +++ b/tests/component_tests/modbus_controller/test_custom_pdu.py @@ -0,0 +1,47 @@ +"""Schema-level config validation for custom_pdu and the deprecated custom_command alias. + +custom_command took a raw frame with a leading device address byte; custom_pdu takes the PDU only. +The old key is still accepted at the schema level and auto-migrated later in final validate (which a +bare-schema test can't reach), so these tests only cover what the schema itself enforces: the two keys +are mutually exclusive, and custom_pdu takes byte-sized values. +""" + +import pytest +from voluptuous import Invalid, MultipleInvalid + +from esphome.components.modbus_controller import ModbusItemBaseSchema +from esphome.components.modbus_controller.const import ( + CONF_CUSTOM_COMMAND, + CONF_CUSTOM_PDU, +) + + +def test_custom_command_accepted_at_schema_level() -> None: + """custom_command validates at the schema level; migration/rejection happens in final validate.""" + config = ModbusItemBaseSchema( + {CONF_CUSTOM_COMMAND: [0x01, 0x03, 0x00, 0x2A, 0x00, 0x01]} + ) + assert config[CONF_CUSTOM_COMMAND] == [0x01, 0x03, 0x00, 0x2A, 0x00, 0x01] + + +def test_custom_pdu_and_custom_command_mutually_exclusive() -> None: + """Only one custom source may be given; supplying both is a schema error.""" + with pytest.raises((Invalid, MultipleInvalid)): + ModbusItemBaseSchema( + { + CONF_CUSTOM_PDU: [0x03, 0x00, 0x2A, 0x00, 0x01], + CONF_CUSTOM_COMMAND: [0x01, 0x03, 0x00, 0x2A, 0x00, 0x01], + } + ) + + +def test_custom_pdu_accepted() -> None: + """The new key takes PDU bytes (function code + data, no address byte).""" + config = ModbusItemBaseSchema({CONF_CUSTOM_PDU: [0x03, 0x00, 0x2A, 0x00, 0x01]}) + assert config[CONF_CUSTOM_PDU] == [0x03, 0x00, 0x2A, 0x00, 0x01] + + +def test_custom_pdu_rejects_non_byte_values() -> None: + """PDU entries are bytes; a word-sized value is a sign the old raw format is being used.""" + with pytest.raises((Invalid, MultipleInvalid)): + ModbusItemBaseSchema({CONF_CUSTOM_PDU: [0x0103, 0x002A]}) diff --git a/tests/components/modbus_controller/common.yaml b/tests/components/modbus_controller/common.yaml index 67b022cdf5..9c35a2f868 100644 --- a/tests/components/modbus_controller/common.yaml +++ b/tests/components/modbus_controller/common.yaml @@ -108,6 +108,22 @@ select: return value; sensor: + # custom_pdu polls a ready-made PDU (function code + data - no device address byte, no CRC); covers + # the set_custom_pdu codegen path and the custom-range polling constructor. + - platform: modbus_controller + modbus_controller_id: modbus_controller1 + id: modbus_sensor_custom_pdu + name: Test Custom PDU Sensor + custom_pdu: [0x03, 0x00, 0x2A, 0x00, 0x01] + value_type: U_WORD + # Deprecated custom_command (leading byte 0x02 == modbus_controller1's address) drives the + # migrate_custom_command final-validate auto-migration path in CI. + - platform: modbus_controller + modbus_controller_id: modbus_controller1 + id: modbus_sensor_custom_command + name: Test Custom Command Sensor + custom_command: [0x02, 0x03, 0x00, 0x2B, 0x00, 0x01] + value_type: U_WORD - platform: modbus_controller modbus_controller_id: modbus_controller1 id: modbus_sensor1 diff --git a/tests/integration/fixtures/uart_mock_modbus_custom_command.yaml b/tests/integration/fixtures/uart_mock_modbus_custom_pdu.yaml similarity index 83% rename from tests/integration/fixtures/uart_mock_modbus_custom_command.yaml rename to tests/integration/fixtures/uart_mock_modbus_custom_pdu.yaml index 738e691110..188abf90f1 100644 --- a/tests/integration/fixtures/uart_mock_modbus_custom_command.yaml +++ b/tests/integration/fixtures/uart_mock_modbus_custom_pdu.yaml @@ -1,5 +1,5 @@ esphome: - name: uart-mock-modbus-custom-command + name: uart-mock-modbus-custom-pdu host: api: @@ -69,13 +69,14 @@ sensor: address: 0x01 register_type: holding value_type: U_WORD - # Custom command: a raw frame {device address, function code, address hi, address lo, - # count hi, count lo}; the CRC is appended by the hub. Reads holding register 0x0001, - # count 1; the lambda parses the response payload (the register value, big-endian). + # Custom PDU: read holding register 0x0001, count 1. The PDU is + # {function code, address hi, address lo, count hi, count lo}; the device + # address and CRC are added by the hub. The lambda parses the response payload + # (the register value, big-endian). - platform: modbus_controller modbus_controller_id: modbus_controller_1 name: "custom_read" - custom_command: [0x01, 0x03, 0x00, 0x01, 0x00, 0x01] + custom_pdu: [0x03, 0x00, 0x01, 0x00, 0x01] lambda: |- if (data.size() < 2) return {}; return (float) ((data[0] << 8) | data[1]); diff --git a/tests/integration/fixtures/uart_mock_modbus_grouping.yaml b/tests/integration/fixtures/uart_mock_modbus_grouping.yaml index a5394f1d05..d580f5c2e2 100644 --- a/tests/integration/fixtures/uart_mock_modbus_grouping.yaml +++ b/tests/integration/fixtures/uart_mock_modbus_grouping.yaml @@ -134,7 +134,8 @@ sensor: value_type: U_WORD modbus_controller_id: modbus_controller_ok - # F - contiguous registers where the second asks for a slower rate. + # F - contiguous registers that historically carried differing skip_updates rates and were split by + # the rate merge; with per-range rates gone they group like any contiguous pair. - platform: modbus_controller name: "rate_first" address: 0x150 @@ -146,7 +147,6 @@ sensor: address: 0x151 register_type: holding value_type: U_WORD - skip_updates: 5 modbus_controller_id: modbus_controller_ok # B - a wide value and one of its halves share a start address, with a contiguous sensor after them. diff --git a/tests/integration/fixtures/uart_mock_modbus_offline.yaml b/tests/integration/fixtures/uart_mock_modbus_offline.yaml index e4d2dfa294..c34890cd02 100644 --- a/tests/integration/fixtures/uart_mock_modbus_offline.yaml +++ b/tests/integration/fixtures/uart_mock_modbus_offline.yaml @@ -51,9 +51,8 @@ modbus_controller: modbus_id: virtual_modbus_client id: ctl max_cmd_retries: 1 - # offline_skip_updates and the sensor's skip_updates deliberately share a period: offline - # probing must follow the offline cadence alone, or phase combinations like this one can - # leave the device never probing again. + # offline_skip_updates: 1 -> once offline, the controller re-probes every second update cycle; + # the test silences the device to force it offline, then answers again and checks it recovers. offline_skip_updates: 1 update_interval: never on_offline: @@ -71,7 +70,6 @@ sensor: address: 0x03 register_type: holding value_type: U_WORD - skip_updates: 1 # Mirrors the controller's online state so the test can await the transitions. - platform: template name: link_state diff --git a/tests/integration/fixtures/uart_mock_modbus_shared_address.yaml b/tests/integration/fixtures/uart_mock_modbus_shared_address.yaml index 25574d0c42..109603f3b6 100644 --- a/tests/integration/fixtures/uart_mock_modbus_shared_address.yaml +++ b/tests/integration/fixtures/uart_mock_modbus_shared_address.yaml @@ -49,14 +49,10 @@ uart_mock: inject_rx: [0x01, 0x03, 0x02, 0x01, 0x41, 0x79, 0xE4] # 0x101 = 0x0141 = 321 - expect_tx: [0x01, 0x03, 0x01, 0x03, 0x00, 0x01, 0x75, 0xF6] # Read holding 0x103 count 1 inject_rx: [0x01, 0x03, 0x02, 0x01, 0xA5, 0x79, 0xAF] # 0x103 = 0x01A5 = 421 - # A widened shared-address range at 0x200 plus a sensor at 0x201 carrying its own skip_updates. - # The sensor must keep its own range so the polling rates stay independent; if it were folded into - # the widened range it would decode 0x201 from THAT response (2, not 777) and drag the range's - # rate down to its own. + # Two sensors sharing start address 0x200 (a word and a dword) widen the range to 2 registers + # and both decode from the single response. - expect_tx: [0x01, 0x03, 0x02, 0x00, 0x00, 0x02, 0xC5, 0xB3] # Read holding 0x200 count 2 inject_rx: [0x01, 0x03, 0x04, 0x01, 0x41, 0x00, 0x02, 0x2A, 0x1A] # 0x200=0x0141, 0x201=0x0002 - - expect_tx: [0x01, 0x03, 0x02, 0x01, 0x00, 0x01, 0xD4, 0x72] # Read holding 0x201 count 1 - inject_rx: [0x01, 0x03, 0x02, 0x03, 0x09, 0x78, 0xB2] # 0x201 = 0x0309 = 777 modbus: uart_id: virtual_uart_dev @@ -128,26 +124,17 @@ sensor: modbus_controller_id: modbus_controller_ok # Shared address 0x200: the dword widens the range the word opened (or vice versa) - platform: modbus_controller - name: "rate_word" + name: "widen_word" address: 0x200 register_type: holding value_type: U_WORD modbus_controller_id: modbus_controller_ok - platform: modbus_controller - name: "rate_dword" + name: "widen_dword" address: 0x200 register_type: holding value_type: U_DWORD modbus_controller_id: modbus_controller_ok - # Inside the widened range but with its own skip_updates: must NOT be folded in, or the two sensors - # above would silently drop to this sensor's polling rate - - platform: modbus_controller - name: "own_rate" - address: 0x201 - register_type: holding - value_type: U_WORD - skip_updates: 100 - modbus_controller_id: modbus_controller_ok button: - platform: template diff --git a/tests/integration/test_uart_mock_modbus.py b/tests/integration/test_uart_mock_modbus.py index d0b375dd25..09e841b4bb 100644 --- a/tests/integration/test_uart_mock_modbus.py +++ b/tests/integration/test_uart_mock_modbus.py @@ -675,9 +675,7 @@ async def test_uart_mock_modbus_shared_address( wide sensor's span keep polling separately, and that the sensor at the span's tail address does not anchor a re-use join on a mid-range predecessor (which would make it decode that sensor's bytes). - A sensor at 0x201 carrying skip_updates sits inside a widened shared-address range at 0x200 but - keeps its own range, so polling rates stay independent; folding it in would also make it decode - 0x201 out of the shared response (2) instead of its own poll (777). + A word and a dword sharing 0x200 widen that range to two registers and both decode from the one read. """ line_callback, error_log_lines, warning_log_lines = _make_modbus_line_callback() @@ -693,9 +691,8 @@ async def test_uart_mock_modbus_shared_address( "wide_qword": 100, "inside_wide": 321, "tail_of_wide": 421, - "rate_word": 321, - "rate_dword": pytest.approx(21037058), - "own_rate": 777, + "widen_word": 321, + "widen_dword": pytest.approx(21037058), } tracker = SensorTracker(list(expected_values.keys())) futures = tracker.expect_all(expected_values) @@ -710,18 +707,18 @@ async def test_uart_mock_modbus_shared_address( @pytest.mark.asyncio -async def test_uart_mock_modbus_custom_command( +async def test_uart_mock_modbus_custom_pdu( yaml_config: str, run_compiled: RunCompiledFunction, api_client_connected: APIClientConnectedFactory, ) -> None: - """Test a custom_command sensor polling a register served by the mock server. + """Test a custom_pdu sensor reading a register served by the mock server. - The custom_command is a raw frame (device address + PDU); the hub appends the CRC and - routes the response back to the polling command, whose sensor lambda parses the payload. - Guards the custom polling wiring: the command must reference the sensor's custom_data and - decode the real function code, or nothing is ever transmitted. A plain read on the same - register anchors the bus. + The custom_pdu is a raw read-holding PDU (function code + address + count); the + controller prepends its own device address and appends the CRC, sends it, and the + sensor's lambda parses the response payload. Confirms the custom PDU path decodes + the function code and routes the response to the sensor (the gap that hid the + step-2 raw-vs-PDU bug). A plain read on the same register anchors the bus. """ line_callback, error_log_lines, warning_log_lines = _make_modbus_line_callback() @@ -754,9 +751,8 @@ async def test_uart_mock_modbus_offline( publishes. This pins the pooled non-response counter, can_send() gating, the offline retry cadence, and recovery - none of which the responding-path tests touch. - The fixture gives offline_skip_updates and the sensor's skip_updates the same period - on purpose: offline probing must follow the offline cadence alone, since requiring - both cadences to coincide leaves phase combinations where no probe ever goes out. + Offline probing follows the offline cadence alone; regular every-update polling + resumes once the device answers again. """ tracker = SensorTracker(["link_state", "reg"]) From 3c56b9e66e1070b732c0fec1e779f6d1bbe64d43 Mon Sep 17 00:00:00 2001 From: Brandon Harvey <8107750+bharvey88@users.noreply.github.com> Date: Sun, 23 Aug 2026 20:05:35 -0500 Subject: [PATCH 08/10] [wifi] Share the scan list dedupe helper with improv_serial (#18612) Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com> Co-authored-by: J. Nick Koston Co-authored-by: Bluetooth Devices Bot --- .../captive_portal/captive_portal.cpp | 4 +-- .../improv_serial/improv_serial_component.cpp | 25 +++++-------------- .../{captive_portal => wifi}/scan_list.h | 4 +-- tests/components/captive_portal/__init__.py | 10 -------- .../scan_list_test.cpp | 12 ++++----- 5 files changed, 16 insertions(+), 39 deletions(-) rename esphome/components/{captive_portal => wifi}/scan_list.h (92%) delete mode 100644 tests/components/captive_portal/__init__.py rename tests/components/{captive_portal => wifi}/scan_list_test.cpp (93%) diff --git a/esphome/components/captive_portal/captive_portal.cpp b/esphome/components/captive_portal/captive_portal.cpp index ffd121499b..e80f9e669f 100644 --- a/esphome/components/captive_portal/captive_portal.cpp +++ b/esphome/components/captive_portal/captive_portal.cpp @@ -4,9 +4,9 @@ #include "esphome/core/application.h" #include "esphome/core/helpers.h" #include "esphome/core/string_ref.h" +#include "esphome/components/wifi/scan_list.h" #include "esphome/components/wifi/wifi_component.h" #include "captive_index.h" -#include "scan_list.h" namespace esphome::captive_portal { @@ -37,7 +37,7 @@ void CaptivePortal::handle_config(AsyncWebServerRequest *request) { const auto &results = wifi::global_wifi_component->get_scan_result(); for (const auto &scan : results) { bool with_auth = false; - if (!should_show_scan_entry(results, scan, with_auth)) + if (!wifi::should_show_scan_entry(results, scan, with_auth)) continue; json_escape_into_buffer(escaped_ssid, scan.get_ssid()); diff --git a/esphome/components/improv_serial/improv_serial_component.cpp b/esphome/components/improv_serial/improv_serial_component.cpp index a191889138..de9c7899cd 100644 --- a/esphome/components/improv_serial/improv_serial_component.cpp +++ b/esphome/components/improv_serial/improv_serial_component.cpp @@ -7,6 +7,7 @@ #include "esphome/core/version.h" #include "esphome/components/logger/logger.h" +#include "esphome/components/wifi/scan_list.h" namespace esphome::improv_serial { @@ -230,31 +231,17 @@ bool ImprovSerialComponent::parse_improv_payload_(improv::ImprovCommand &command return true; } case improv::GET_WIFI_NETWORKS: { - std::vector networks; const auto &results = wifi::global_wifi_component->get_scan_result(); - for (auto &scan : results) { - if (scan.get_is_hidden()) + for (const auto &scan : results) { + bool with_auth = false; + if (!wifi::should_show_scan_entry(results, scan, with_auth)) continue; - const char *ssid_cstr = scan.get_ssid().c_str(); - // Check if we've already sent this SSID - bool duplicate = false; - for (const auto &seen : networks) { - if (strcmp(seen.c_str(), ssid_cstr) == 0) { - duplicate = true; - break; - } - } - if (duplicate) - continue; - // Only allocate std::string after confirming it's not a duplicate - std::string ssid(ssid_cstr); // Send each ssid separately to avoid overflowing the buffer char rssi_buf[5]; // int8_t: -128 to 127, max 4 chars + null *int8_to_str(rssi_buf, scan.get_rssi()) = '\0'; - std::vector data = - improv::build_rpc_response(improv::GET_WIFI_NETWORKS, {ssid, rssi_buf, YESNO(scan.get_with_auth())}, false); + std::vector data = improv::build_rpc_response( + improv::GET_WIFI_NETWORKS, {scan.get_ssid().str(), rssi_buf, YESNO(with_auth)}, false); this->send_response_(data); - networks.push_back(std::move(ssid)); } // Send empty response to signify the end of the list. std::vector data = diff --git a/esphome/components/captive_portal/scan_list.h b/esphome/components/wifi/scan_list.h similarity index 92% rename from esphome/components/captive_portal/scan_list.h rename to esphome/components/wifi/scan_list.h index d24a88a670..8a11c745da 100644 --- a/esphome/components/captive_portal/scan_list.h +++ b/esphome/components/wifi/scan_list.h @@ -1,7 +1,7 @@ #pragma once #include -namespace esphome::captive_portal { +namespace esphome::wifi { // A scan lists every BSSID, so one SSID can appear several times. Returns true for // the strongest entry per SSID (earliest on ties), never for hidden entries. scan @@ -25,4 +25,4 @@ bool should_show_scan_entry(const Results &results, const Entry &scan, bool &wit return true; } -} // namespace esphome::captive_portal +} // namespace esphome::wifi diff --git a/tests/components/captive_portal/__init__.py b/tests/components/captive_portal/__init__.py deleted file mode 100644 index 1ac0704a59..0000000000 --- a/tests/components/captive_portal/__init__.py +++ /dev/null @@ -1,10 +0,0 @@ -from tests.testing_helpers import ComponentManifestOverride - - -def override_manifest(manifest: ComponentManifestOverride) -> None: - # The scan list helper is header-only and needs none of the component's real - # dependencies. Pulling them in breaks the host build: web_server_base - # includes ESPAsyncWebServer.h and ota.web_server includes md5/md5.h, neither - # of which exists there. - manifest.dependencies = [] - manifest.auto_load = [] diff --git a/tests/components/captive_portal/scan_list_test.cpp b/tests/components/wifi/scan_list_test.cpp similarity index 93% rename from tests/components/captive_portal/scan_list_test.cpp rename to tests/components/wifi/scan_list_test.cpp index f67581dc0b..47427f063f 100644 --- a/tests/components/captive_portal/scan_list_test.cpp +++ b/tests/components/wifi/scan_list_test.cpp @@ -4,13 +4,13 @@ #include #include -#include "esphome/components/captive_portal/scan_list.h" +#include "esphome/components/wifi/scan_list.h" -namespace esphome::captive_portal::testing { +namespace esphome::wifi::testing { namespace { -// Stand-in for wifi::WiFiScanResult, which does not compile on the host. +// Stand-in for WiFiScanResult, which does not compile on the host. struct Entry { std::string ssid; int8_t rssi; @@ -24,7 +24,7 @@ struct Entry { bool get_is_hidden() const { return this->is_hidden; } }; -// One row as the portal would emit it. +// One network as a consumer would emit it. struct Row { std::string ssid; int8_t rssi; @@ -33,7 +33,7 @@ struct Row { bool operator==(const Row &rhs) const { return ssid == rhs.ssid && rssi == rhs.rssi && lock == rhs.lock; } }; -// Walk the results the way handle_config does and collect the rows that survive. +// Walk the results the way the consumers do and collect the rows that survive. std::vector rows(const std::vector &results) { std::vector out; for (size_t i = 0; i < results.size(); i++) { @@ -127,4 +127,4 @@ TEST(ScanList, EmptyListShowsNothing) { EXPECT_TRUE(rows(results).empty()); } -} // namespace esphome::captive_portal::testing +} // namespace esphome::wifi::testing From d877fb021c9776650803ee6f95bd490d5969917d Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sun, 23 Aug 2026 20:24:00 -0500 Subject: [PATCH 09/10] [time] Remove C++ POSIX TZ string parser (#18383) --- esphome/components/api/api.proto | 8 +- esphome/components/api/api_connection.cpp | 45 +- esphome/components/api/api_options.proto | 6 + esphome/components/api/api_pb2.cpp | 5 +- esphome/components/api/api_pb2.h | 4 +- esphome/components/api/api_pb2_dump.cpp | 2 +- esphome/components/time/__init__.py | 22 +- esphome/components/time/posix_tz.cpp | 198 --- esphome/components/time/posix_tz.h | 45 +- esphome/components/time/real_time_clock.cpp | 31 - esphome/components/time/real_time_clock.h | 34 +- script/api_protobuf/api_protobuf.py | 40 +- .../{posix_tz_parser.cpp => posix_tz.cpp} | 1142 ++++++----------- tests/components/time/test.host.yaml | 10 + .../api_get_time_response_timezone.yaml | 20 + .../test_api_get_time_response_timezone.py | 67 + 16 files changed, 604 insertions(+), 1075 deletions(-) rename tests/components/time/{posix_tz_parser.cpp => posix_tz.cpp} (56%) create mode 100644 tests/components/time/test.host.yaml create mode 100644 tests/integration/fixtures/api_get_time_response_timezone.yaml create mode 100644 tests/integration/test_api_get_time_response_timezone.py diff --git a/esphome/components/api/api.proto b/esphome/components/api/api.proto index f1bc9b003a..6ea124d155 100644 --- a/esphome/components/api/api.proto +++ b/esphome/components/api/api.proto @@ -1002,8 +1002,12 @@ message GetTimeResponse { option (no_delay) = true; fixed32 epoch_seconds = 1; - string timezone = 2; - ParsedTimezone parsed_timezone = 3; + // Deprecated in 2026.9.0: clients still send this string for older firmware, + // but new firmware only reads parsed_timezone. Clients older than Home + // Assistant 2026.3.0 that send only the string leave the device on its + // codegen-configured timezone (or UTC). + string timezone = 2 [deprecated = true]; + ParsedTimezone parsed_timezone = 3 [(track_presence) = true]; } // ==================== USER-DEFINES SERVICES ==================== diff --git a/esphome/components/api/api_connection.cpp b/esphome/components/api/api_connection.cpp index 91d13eed65..bb6c1695dd 100644 --- a/esphome/components/api/api_connection.cpp +++ b/esphome/components/api/api_connection.cpp @@ -1204,31 +1204,28 @@ void APIConnection::on_get_time_response(const GetTimeResponse &value) { if (homeassistant::global_homeassistant_time != nullptr) { homeassistant::global_homeassistant_time->set_epoch_time(value.epoch_seconds); #if defined(USE_HOMEASSISTANT_TIMEZONE) && defined(USE_TIME_TIMEZONE) - if (!value.timezone.empty()) { - // Check if the sender provided pre-parsed timezone data. - // If std_offset is non-zero or DST rules are present, the parsed data was populated. - // For UTC (all zeros), string parsing produces the same result, so the fallback is equivalent. + // Apply only if the sender provided pre-parsed timezone data (Home Assistant 2026.3.0 + // and newer); field presence distinguishes a genuine all-zero UTC timezone from an + // absent field. Older clients send only the deprecated timezone string, which is no + // longer decoded; for them the device keeps its codegen-configured timezone. + if (value.has_parsed_timezone) { const auto &pt = value.parsed_timezone; - if (pt.std_offset_seconds != 0 || pt.dst_start.type != enums::DST_RULE_TYPE_NONE) { - time::ParsedTimezone tz{}; - tz.std_offset_seconds = pt.std_offset_seconds; - tz.dst_offset_seconds = pt.dst_offset_seconds; - tz.dst_start.time_seconds = pt.dst_start.time_seconds; - tz.dst_start.day = static_cast(pt.dst_start.day); - tz.dst_start.type = static_cast(pt.dst_start.type); - tz.dst_start.month = static_cast(pt.dst_start.month); - tz.dst_start.week = static_cast(pt.dst_start.week); - tz.dst_start.day_of_week = static_cast(pt.dst_start.day_of_week); - tz.dst_end.time_seconds = pt.dst_end.time_seconds; - tz.dst_end.day = static_cast(pt.dst_end.day); - tz.dst_end.type = static_cast(pt.dst_end.type); - tz.dst_end.month = static_cast(pt.dst_end.month); - tz.dst_end.week = static_cast(pt.dst_end.week); - tz.dst_end.day_of_week = static_cast(pt.dst_end.day_of_week); - time::set_global_tz(tz); - } else { - homeassistant::global_homeassistant_time->set_timezone(value.timezone.c_str(), value.timezone.size()); - } + time::ParsedTimezone tz{}; + tz.std_offset_seconds = pt.std_offset_seconds; + tz.dst_offset_seconds = pt.dst_offset_seconds; + tz.dst_start.time_seconds = pt.dst_start.time_seconds; + tz.dst_start.day = static_cast(pt.dst_start.day); + tz.dst_start.type = static_cast(pt.dst_start.type); + tz.dst_start.month = static_cast(pt.dst_start.month); + tz.dst_start.week = static_cast(pt.dst_start.week); + tz.dst_start.day_of_week = static_cast(pt.dst_start.day_of_week); + tz.dst_end.time_seconds = pt.dst_end.time_seconds; + tz.dst_end.day = static_cast(pt.dst_end.day); + tz.dst_end.type = static_cast(pt.dst_end.type); + tz.dst_end.month = static_cast(pt.dst_end.month); + tz.dst_end.week = static_cast(pt.dst_end.week); + tz.dst_end.day_of_week = static_cast(pt.dst_end.day_of_week); + time::set_global_tz(tz); } #endif } diff --git a/esphome/components/api/api_options.proto b/esphome/components/api/api_options.proto index ac9c4e59cc..66295b3d53 100644 --- a/esphome/components/api/api_options.proto +++ b/esphome/components/api/api_options.proto @@ -116,4 +116,10 @@ extend google.protobuf.FieldOptions { // the per-byte loop when the upper bits are non-zero (the common case // for real MAC addresses, since OUIs occupy the top 24 bits). optional bool mac_address = 50019 [default=false]; + + // track_presence: Track whether this message-typed field was present on the wire. + // Generates a `bool has_{false};` member on the decoding side that is set + // to true when the field arrives, so an all-default submessage can be told apart + // from an absent one (e.g. a UTC ParsedTimezone, which is all zeros). + optional bool track_presence = 50020 [default=false]; } diff --git a/esphome/components/api/api_pb2.cpp b/esphome/components/api/api_pb2.cpp index 1b8c6b05bd..33611c5ee1 100644 --- a/esphome/components/api/api_pb2.cpp +++ b/esphome/components/api/api_pb2.cpp @@ -1249,12 +1249,9 @@ bool ParsedTimezone::decode_length(uint32_t field_id, ProtoLengthDelimited value } bool GetTimeResponse::decode_length(uint32_t field_id, ProtoLengthDelimited value) { switch (field_id) { - case 2: { - this->timezone = StringRef(reinterpret_cast(value.data()), value.size()); - break; - } case 3: value.decode_to_message(this->parsed_timezone); + this->has_parsed_timezone = true; break; default: return false; diff --git a/esphome/components/api/api_pb2.h b/esphome/components/api/api_pb2.h index 8335dae1f2..13db857467 100644 --- a/esphome/components/api/api_pb2.h +++ b/esphome/components/api/api_pb2.h @@ -1283,13 +1283,13 @@ class ParsedTimezone final : public ProtoDecodableMessage { class GetTimeResponse final : public ProtoDecodableMessage { public: static constexpr uint8_t MESSAGE_TYPE = 37; - static constexpr uint8_t ESTIMATED_SIZE = 31; + static constexpr uint8_t ESTIMATED_SIZE = 22; #ifdef HAS_PROTO_MESSAGE_DUMP const LogString *message_name() const override { return LOG_STR("get_time_response"); } #endif uint32_t epoch_seconds{0}; - StringRef timezone{}; ParsedTimezone parsed_timezone{}; + bool has_parsed_timezone{false}; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif diff --git a/esphome/components/api/api_pb2_dump.cpp b/esphome/components/api/api_pb2_dump.cpp index 4d5829e45d..d54215ba2e 100644 --- a/esphome/components/api/api_pb2_dump.cpp +++ b/esphome/components/api/api_pb2_dump.cpp @@ -1468,7 +1468,7 @@ const char *ParsedTimezone::dump_to(DumpBuffer &out) const { const char *GetTimeResponse::dump_to(DumpBuffer &out) const { MessageDumpHelper helper(out, ESPHOME_PSTR("GetTimeResponse")); dump_field(out, ESPHOME_PSTR("epoch_seconds"), this->epoch_seconds); - dump_field(out, ESPHOME_PSTR("timezone"), this->timezone); + dump_field(out, ESPHOME_PSTR("has_parsed_timezone"), this->has_parsed_timezone); out.append(2, ' ').append_p(ESPHOME_PSTR("parsed_timezone")).append(": "); this->parsed_timezone.dump_to(out); out.append("\n"); diff --git a/esphome/components/time/__init__.py b/esphome/components/time/__init__.py index 35fad0a450..94ff6ab051 100644 --- a/esphome/components/time/__init__.py +++ b/esphome/components/time/__init__.py @@ -36,6 +36,7 @@ from esphome.const import ( PLATFORM_RTL87XX, ) from esphome.core import CORE, CoroPriority, EsphomeError, coroutine_with_priority +from esphome.helpers import cpp_string_escape _LOGGER = logging.getLogger(__name__) @@ -411,17 +412,18 @@ async def setup_time_core_(time_var, config): cg.add_define("USE_TIME_TIMEZONE") if CORE.is_host: - # Host platform needs setenv("TZ")/tzset() for libc compatibility - cg.add(time_var.set_timezone(timezone)) - else: - # Embedded: pre-parse at codegen time, emit struct directly - from aioesphomeapi.posix_tz import parse_posix_tz as parse_posix_tz_python + # Host platform also needs setenv("TZ")/tzset() for libc compatibility + cg.add(cg.RawExpression(f'setenv("TZ", {cpp_string_escape(timezone)}, 1)')) + cg.add(cg.RawExpression("tzset()")) - try: - parsed = parse_posix_tz_python(timezone) - _emit_parsed_timezone_fields(parsed) - except ValueError as e: - raise EsphomeError(f"Invalid timezone: {timezone}") from e + # Pre-parse at codegen time, emit struct directly + from aioesphomeapi.posix_tz import parse_posix_tz as parse_posix_tz_python + + try: + parsed = parse_posix_tz_python(timezone) + except ValueError as e: + raise EsphomeError(f"Invalid timezone: {timezone}") from e + _emit_parsed_timezone_fields(parsed) for conf in config.get(CONF_ON_TIME, []): trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], time_var) diff --git a/esphome/components/time/posix_tz.cpp b/esphome/components/time/posix_tz.cpp index c25248e457..188df599f6 100644 --- a/esphome/components/time/posix_tz.cpp +++ b/esphome/components/time/posix_tz.cpp @@ -3,7 +3,6 @@ #ifdef USE_TIME_TIMEZONE #include "posix_tz.h" -#include #include namespace esphome::time { @@ -18,17 +17,6 @@ const ParsedTimezone &get_global_tz() { return global_tz_; } namespace internal { -// Remove before 2026.9.0: parse_uint, skip_tz_name, parse_offset, parse_dst_rule, -// and parse_transition_time are only used by parse_posix_tz() (bridge code). -static uint32_t parse_uint(const char *&p) { - uint32_t value = 0; - while (std::isdigit(static_cast(*p))) { - value = value * 10 + (*p - '0'); - p++; - } - return value; -} - bool is_leap_year(int year) { return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0); } // Get days in year (avoids duplicate is_leap_year calls) @@ -140,62 +128,6 @@ void __attribute__((noinline)) epoch_to_tm_utc(time_t epoch, struct tm *out_tm) out_tm->tm_isdst = 0; } -bool skip_tz_name(const char *&p) { - if (*p == '<') { - // Angle-bracket quoted name: <+07>, <-03>, - p++; // skip '<' - while (*p && *p != '>') { - p++; - } - if (*p == '>') { - p++; // skip '>' - return true; - } - return false; // Unterminated - } - - // Standard name: 3+ letters - const char *start = p; - while (*p && std::isalpha(static_cast(*p))) { - p++; - } - return (p - start) >= 3; -} - -int32_t __attribute__((noinline)) parse_offset(const char *&p) { - int sign = 1; - if (*p == '-') { - sign = -1; - p++; - } else if (*p == '+') { - p++; - } - - int hours = parse_uint(p); - int minutes = 0; - int seconds = 0; - - if (*p == ':') { - p++; - minutes = parse_uint(p); - if (*p == ':') { - p++; - seconds = parse_uint(p); - } - } - - return sign * (hours * 3600 + minutes * 60 + seconds); -} - -// Helper to parse the optional /time suffix (reuses parse_offset logic) -static void parse_transition_time(const char *&p, DSTRule &rule) { - rule.time_seconds = 2 * 3600; // Default 02:00 - if (*p == '/') { - p++; - rule.time_seconds = parse_offset(p); - } -} - void __attribute__((noinline)) julian_to_month_day(int julian_day, int &out_month, int &out_day) { // J format: day 1-365, Feb 29 is NOT counted even in leap years // So day 60 is always March 1 @@ -236,59 +168,6 @@ void __attribute__((noinline)) day_of_year_to_month_day(int day_of_year, int yea out_day = 31; } -bool parse_dst_rule(const char *&p, DSTRule &rule) { - rule = {}; // Zero initialize - - if (*p == 'M' || *p == 'm') { - // M format: Mm.w.d (month.week.day) - rule.type = DSTRuleType::MONTH_WEEK_DAY; - p++; - - rule.month = parse_uint(p); - if (rule.month < 1 || rule.month > 12) - return false; - - if (*p++ != '.') - return false; - - rule.week = parse_uint(p); - if (rule.week < 1 || rule.week > 5) - return false; - - if (*p++ != '.') - return false; - - rule.day_of_week = parse_uint(p); - if (rule.day_of_week > 6) - return false; - - } else if (*p == 'J' || *p == 'j') { - // J format: Jn (Julian day 1-365, not counting Feb 29) - rule.type = DSTRuleType::JULIAN_NO_LEAP; - p++; - - rule.day = parse_uint(p); - if (rule.day < 1 || rule.day > 365) - return false; - - } else if (std::isdigit(static_cast(*p))) { - // Plain number format: n (day 0-365, counting Feb 29) - rule.type = DSTRuleType::DAY_OF_YEAR; - - rule.day = parse_uint(p); - if (rule.day > 365) - return false; - - } else { - return false; - } - - // Parse optional /time suffix - parse_transition_time(p, rule); - - return true; -} - // Calculate days from Jan 1 of given year to given month/day static int __attribute__((noinline)) days_from_year_start(int year, int month, int day) { int days = day - 1; @@ -373,83 +252,6 @@ bool __attribute__((noinline)) is_in_dst(time_t utc_epoch, const ParsedTimezone } } -// Remove before 2026.9.0: This parser is bridge code for backward compatibility with -// older Home Assistant clients that send the timezone as a POSIX TZ string instead of -// the pre-parsed ParsedTimezone protobuf struct. Once all clients send the struct -// directly, this function and the parsing helpers above (skip_tz_name, parse_offset, -// parse_dst_rule, parse_transition_time) can be removed. -// See https://github.com/esphome/backlog/issues/91 -bool parse_posix_tz(const char *tz_string, ParsedTimezone &result) { - if (!tz_string || !*tz_string) { - return false; - } - - const char *p = tz_string; - - // Initialize result (dst_start/dst_end default to type=NONE, so has_dst() returns false) - result.std_offset_seconds = 0; - result.dst_offset_seconds = 0; - result.dst_start = {}; - result.dst_end = {}; - - // Skip standard timezone name - if (!internal::skip_tz_name(p)) { - return false; - } - - // Parse standard offset (required) - if (!*p || (!std::isdigit(static_cast(*p)) && *p != '+' && *p != '-')) { - return false; - } - result.std_offset_seconds = internal::parse_offset(p); - - // Check for DST name - if (!*p) { - return true; // No DST - } - - // If next char is comma, there's no DST name but there are rules (invalid) - if (*p == ',') { - return false; - } - - // Check if there's something that looks like a DST name start - // (letter or angle bracket). If not, treat as trailing garbage and return success. - if (!std::isalpha(static_cast(*p)) && *p != '<') { - return true; // No DST, trailing characters ignored - } - - if (!internal::skip_tz_name(p)) { - return false; // Invalid DST name (started but malformed) - } - - // Optional DST offset (default is std - 1 hour) - if (*p && *p != ',' && (std::isdigit(static_cast(*p)) || *p == '+' || *p == '-')) { - result.dst_offset_seconds = internal::parse_offset(p); - } else { - result.dst_offset_seconds = result.std_offset_seconds - 3600; - } - - // Parse DST rules (required when DST name is present) - if (*p != ',') { - // DST name without rules - treat as no DST since we can't determine transitions - return true; - } - - p++; - if (!internal::parse_dst_rule(p, result.dst_start)) { - return false; - } - - // Second rule is required per POSIX - if (*p != ',') { - return false; - } - p++; - // has_dst() now returns true since dst_start.type was set by parse_dst_rule - return internal::parse_dst_rule(p, result.dst_end); -} - // Format a POSIX offset (positive = west) as "+HHMM" / "-HHMM" for display. // Convention: negate POSIX sign so east-of-UTC is positive (ISO 8601 / RFC 2822). void format_designation(int32_t posix_offset, char *buf, size_t buf_size) { diff --git a/esphome/components/time/posix_tz.h b/esphome/components/time/posix_tz.h index be1ddfd689..249f597166 100644 --- a/esphome/components/time/posix_tz.h +++ b/esphome/components/time/posix_tz.h @@ -39,28 +39,6 @@ struct ParsedTimezone { /// Format a POSIX offset as "+HHMM"/"-HHMM" into buf (must be >= 6 bytes). void format_designation(int32_t posix_offset, char *buf, size_t buf_size); -/// Parse a POSIX TZ string into a ParsedTimezone struct. -/// -/// @deprecated Remove before 2026.9.0 (bridge code for backward compatibility). -/// This parser only exists so that older Home Assistant clients that send the timezone -/// as a string (instead of the pre-parsed ParsedTimezone protobuf struct) can still -/// set the timezone on the device. Once all clients are updated to send the struct -/// directly, this function and all internal parsing helpers will be removed. -/// See https://github.com/esphome/backlog/issues/91 -/// -/// Supports formats like: -/// - "EST5" (simple offset, no DST) -/// - "EST5EDT,M3.2.0,M11.1.0" (with DST, M-format rules) -/// - "CST6CDT,M3.2.0/2,M11.1.0/2" (with transition times) -/// - "<+07>-7" (angle-bracket notation for special names) -/// - "IST-5:30" (half-hour offsets) -/// - "EST5EDT,J60,J300" (J-format: Julian day without leap day) -/// - "EST5EDT,60,300" (plain day number: day of year with leap day) -/// @param tz_string The POSIX TZ string to parse -/// @param result Output: the parsed timezone data -/// @return true if parsing succeeded, false on error -bool parse_posix_tz(const char *tz_string, ParsedTimezone &result); - /// Convert a UTC epoch to local time using the parsed timezone. /// This replaces libc's localtime() to avoid scanf dependency. /// @param utc_epoch Unix timestamp in UTC @@ -70,8 +48,7 @@ bool parse_posix_tz(const char *tz_string, ParsedTimezone &result); bool epoch_to_local_tm(time_t utc_epoch, const ParsedTimezone &tz, struct tm *out_tm); /// Set the global timezone used by epoch_to_local_tm() when called without a timezone. -/// This is called by RealTimeClock::apply_timezone_() to enable ESPTime::from_epoch_local() -/// to work without libc's localtime(). +/// This enables ESPTime::from_epoch_local() to work without libc's localtime(). void set_global_tz(const ParsedTimezone &tz); /// Get the global timezone. @@ -84,29 +61,9 @@ const ParsedTimezone &get_global_tz(); bool is_in_dst(time_t utc_epoch, const ParsedTimezone &tz); // Internal helper functions exposed for testing. -// Remove before 2026.9.0: skip_tz_name, parse_offset, parse_dst_rule are only -// used by parse_posix_tz() which is bridge code for backward compatibility. -// The remaining helpers (epoch_to_tm_utc, day_of_week, days_in_month, etc.) -// are used by the conversion functions and will stay. namespace internal { -/// Skip a timezone name (letters or <...> quoted format) -/// @param p Pointer to current position, updated on return -/// @return true if a valid name was found -bool skip_tz_name(const char *&p); - -/// Parse an offset in format [-]hh[:mm[:ss]] -/// @param p Pointer to current position, updated on return -/// @return Offset in seconds -int32_t parse_offset(const char *&p); - -/// Parse a DST rule in format Mm.w.d[/time], Jn[/time], or n[/time] -/// @param p Pointer to current position, updated on return -/// @param rule Output: the parsed rule -/// @return true if parsing succeeded -bool parse_dst_rule(const char *&p, DSTRule &rule); - /// Convert Julian day (J format, 1-365 not counting Feb 29) to month/day /// @param julian_day Day number 1-365 /// @param[out] month Output: month 1-12 diff --git a/esphome/components/time/real_time_clock.cpp b/esphome/components/time/real_time_clock.cpp index 6a52348ae9..4f32560525 100644 --- a/esphome/components/time/real_time_clock.cpp +++ b/esphome/components/time/real_time_clock.cpp @@ -107,35 +107,4 @@ void RealTimeClock::synchronize_epoch_(uint32_t epoch) { this->time_sync_callback_.call(); } -#ifdef USE_TIME_TIMEZONE -void RealTimeClock::apply_timezone_(const char *tz) { - ParsedTimezone parsed{}; - - // Handle null or empty input - use UTC - if (tz == nullptr || *tz == '\0') { - // Skip if already UTC - if (!get_global_tz().has_dst() && get_global_tz().std_offset_seconds == 0) { - return; - } - set_global_tz(parsed); - return; - } - -#ifdef USE_HOST - // On host platform, also set TZ environment variable for libc compatibility - setenv("TZ", tz, 1); - tzset(); -#endif - - // Parse the POSIX TZ string using our custom parser - if (!parse_posix_tz(tz, parsed)) { - ESP_LOGW(TAG, "Failed to parse timezone: %s", tz); - return; - } - - // Set global timezone for all time conversions - set_global_tz(parsed); -} -#endif - } // namespace esphome::time diff --git a/esphome/components/time/real_time_clock.h b/esphome/components/time/real_time_clock.h index 7a9175f39c..c449309c9f 100644 --- a/esphome/components/time/real_time_clock.h +++ b/esphome/components/time/real_time_clock.h @@ -15,37 +15,13 @@ namespace esphome::time { /// The RealTimeClock class exposes common timekeeping functions via the device's local real-time clock. /// /// \note -/// The C library (newlib) available on ESPs only supports TZ strings that specify an offset and DST info; -/// you cannot specify zone names or paths to zoneinfo files. -/// \see https://www.gnu.org/software/libc/manual/html_node/TZ-Variable.html +/// The timezone is pre-parsed into a ParsedTimezone struct: at codegen time from the YAML +/// configuration, or at runtime by API clients that send the parsed struct (Home Assistant +/// 2026.3.0 and newer). See set_global_tz() in posix_tz.h. class RealTimeClock : public PollingComponent { public: explicit RealTimeClock(); -#ifdef USE_TIME_TIMEZONE - /// Set the time zone from a POSIX TZ string. - void set_timezone(const char *tz) { this->apply_timezone_(tz); } - - /// Set the time zone from a character buffer with known length. - /// The buffer does not need to be null-terminated. - void set_timezone(const char *tz, size_t len) { - if (tz == nullptr) { - this->apply_timezone_(nullptr); - return; - } - // Stack buffer - TZ strings from tzdata are typically short (< 50 chars) - char buf[128]; - if (len >= sizeof(buf)) - len = sizeof(buf) - 1; - memcpy(buf, tz, len); - buf[len] = '\0'; - this->apply_timezone_(buf); - } - - /// Set the time zone from a std::string. - void set_timezone(const std::string &tz) { this->apply_timezone_(tz.c_str()); } -#endif - /// Get the time in the currently defined timezone. ESPTime now(); @@ -65,10 +41,6 @@ class RealTimeClock : public PollingComponent { /// Report a unix epoch as current time. void synchronize_epoch_(uint32_t epoch); -#ifdef USE_TIME_TIMEZONE - void apply_timezone_(const char *tz); -#endif - LazyCallbackManager time_sync_callback_; }; diff --git a/script/api_protobuf/api_protobuf.py b/script/api_protobuf/api_protobuf.py index f4eff4a254..dc3dd4b868 100755 --- a/script/api_protobuf/api_protobuf.py +++ b/script/api_protobuf/api_protobuf.py @@ -498,6 +498,15 @@ def create_field_type_info( needs_encode: bool = True, ) -> TypeInfo: """Create the appropriate TypeInfo instance for a field, handling repeated fields and custom options.""" + if get_field_opt(field, pb.track_presence, False) and ( + field.label == FieldDescriptorProto.LABEL_REPEATED + or field.type != 11 + or not needs_decode + ): + raise ValueError( + f"track_presence on field '{field.name}' has no effect; it requires " + "a non-repeated message field in a message that is decoded" + ) if field.label == FieldDescriptorProto.LABEL_REPEATED: # Check if this is a packed_buffer field (zero-copy packed repeated) if get_field_opt(field, pb.packed_buffer, False): @@ -541,6 +550,8 @@ def create_field_type_info( return PointerToStringBufferType(field, None) validate_field_type(field.type, field.name) + if field.type == 11: + return MessageType(field, needs_decode, needs_encode) return TYPE_INFO[field.type](field) @@ -937,9 +948,33 @@ class MessageType(TypeInfo): # runtime polymorphism through virtual function calls. return None + @property + def public_content(self) -> list[str]: + content = [self.class_member] + if self._track_presence: + content.append(f"bool has_{self.name}{{false}};") + return content + + @property + def _track_presence(self) -> bool: + # Presence is only observable on the decode side + return self._needs_decode and get_field_opt( + self._field, pb.track_presence, False + ) + @property def decode_length_content(self) -> str: # Custom decode that doesn't use templates + if self._track_presence: + # decode_to_message() cannot report failure, so setting the flag + # afterwards only documents intent; a status-returning decode could + # gate it for real without touching callers. + return ( + f"case {self.number}:\n" + f" value.decode_to_message(this->{self.field_name});\n" + f" this->has_{self.name} = true;\n" + f" break;" + ) return f"case {self.number}: value.decode_to_message(this->{self.field_name}); break;" def dump(self, name: str) -> str: @@ -947,7 +982,10 @@ class MessageType(TypeInfo): @property def dump_content(self) -> str: - o = f'out.append(2, \' \').append_p(ESPHOME_PSTR("{self.name}")).append(": ");\n' + o = "" + if self._track_presence: + o += f'dump_field(out, ESPHOME_PSTR("has_{self.name}"), this->has_{self.name});\n' + o += f'out.append(2, \' \').append_p(ESPHOME_PSTR("{self.name}")).append(": ");\n' o += f"this->{self.field_name}.dump_to(out);\n" o += 'out.append("\\n");' return o diff --git a/tests/components/time/posix_tz_parser.cpp b/tests/components/time/posix_tz.cpp similarity index 56% rename from tests/components/time/posix_tz_parser.cpp rename to tests/components/time/posix_tz.cpp index 440eea608d..760328a518 100644 --- a/tests/components/time/posix_tz_parser.cpp +++ b/tests/components/time/posix_tz.cpp @@ -1,14 +1,7 @@ -// Tests for the POSIX TZ parser, time conversion functions, and ESPTime::strptime. +// Tests for time conversion functions, DST detection, and ESPTime::strptime. // -// Most tests here cover the C++ POSIX TZ string parser (parse_posix_tz), which is -// bridge code for backward compatibility — it will be removed before ESPHome 2026.9.0. -// After https://github.com/esphome/esphome/pull/14233 merges, the parser is solely -// used to handle timezone strings from Home Assistant clients older than 2026.3.0 -// that haven't been updated to send the pre-parsed ParsedTimezone protobuf struct. -// See https://github.com/esphome/backlog/issues/91 -// -// The epoch_to_local_tm, is_in_dst, and ESPTime::strptime tests cover conversion -// functions that will remain permanently. +// These tests cover the permanent timezone functions: epoch_to_local_tm, is_in_dst, +// calculate_dst_transition, and the internal helper functions they depend on. // Enable USE_TIME_TIMEZONE for tests #define USE_TIME_TIMEZONE @@ -16,6 +9,8 @@ #include #include #include +#include +#include #include "esphome/components/time/posix_tz.h" #include "esphome/core/time.h" @@ -35,435 +30,83 @@ static time_t make_utc(int year, int month, int day, int hour = 0, int min = 0, return days * 86400 + hour * 3600 + min * 60 + sec; } -// ============================================================================ -// Basic TZ string parsing tests -// ============================================================================ - -TEST(PosixTzParser, ParseSimpleOffsetEST5) { - ParsedTimezone tz; - ASSERT_TRUE(parse_posix_tz("EST5", tz)); - EXPECT_EQ(tz.std_offset_seconds, 5 * 3600); // +5 hours (west of UTC) - EXPECT_FALSE(tz.has_dst()); +// Helper to build a US Eastern timezone (EST5EDT,M3.2.0/2,M11.1.0/2) +static ParsedTimezone make_us_eastern() { + ParsedTimezone tz{}; + tz.std_offset_seconds = 5 * 3600; + tz.dst_offset_seconds = 4 * 3600; + tz.dst_start.type = DSTRuleType::MONTH_WEEK_DAY; + tz.dst_start.month = 3; + tz.dst_start.week = 2; + tz.dst_start.day_of_week = 0; + tz.dst_start.time_seconds = 2 * 3600; + tz.dst_end.type = DSTRuleType::MONTH_WEEK_DAY; + tz.dst_end.month = 11; + tz.dst_end.week = 1; + tz.dst_end.day_of_week = 0; + tz.dst_end.time_seconds = 2 * 3600; + return tz; } -TEST(PosixTzParser, ParseNegativeOffsetCET) { - ParsedTimezone tz; - ASSERT_TRUE(parse_posix_tz("CET-1", tz)); - EXPECT_EQ(tz.std_offset_seconds, -1 * 3600); // -1 hour (east of UTC) - EXPECT_FALSE(tz.has_dst()); +// Helper to build a US Central timezone (CST6CDT,M3.2.0,M11.1.0) +static ParsedTimezone make_us_central() { + ParsedTimezone tz{}; + tz.std_offset_seconds = 6 * 3600; + tz.dst_offset_seconds = 5 * 3600; + tz.dst_start.type = DSTRuleType::MONTH_WEEK_DAY; + tz.dst_start.month = 3; + tz.dst_start.week = 2; + tz.dst_start.day_of_week = 0; + tz.dst_start.time_seconds = 2 * 3600; + tz.dst_end.type = DSTRuleType::MONTH_WEEK_DAY; + tz.dst_end.month = 11; + tz.dst_end.week = 1; + tz.dst_end.day_of_week = 0; + tz.dst_end.time_seconds = 2 * 3600; + return tz; } -TEST(PosixTzParser, ParseExplicitPositiveOffset) { - ParsedTimezone tz; - ASSERT_TRUE(parse_posix_tz("TEST+5", tz)); - EXPECT_EQ(tz.std_offset_seconds, 5 * 3600); - EXPECT_FALSE(tz.has_dst()); +// Helper to build New Zealand timezone (NZST-12NZDT,M9.5.0,M4.1.0/3) +static ParsedTimezone make_new_zealand() { + ParsedTimezone tz{}; + tz.std_offset_seconds = -12 * 3600; + tz.dst_offset_seconds = -13 * 3600; + tz.dst_start.type = DSTRuleType::MONTH_WEEK_DAY; + tz.dst_start.month = 9; + tz.dst_start.week = 5; + tz.dst_start.day_of_week = 0; + tz.dst_start.time_seconds = 2 * 3600; + tz.dst_end.type = DSTRuleType::MONTH_WEEK_DAY; + tz.dst_end.month = 4; + tz.dst_end.week = 1; + tz.dst_end.day_of_week = 0; + tz.dst_end.time_seconds = 3 * 3600; + return tz; } -TEST(PosixTzParser, ParseZeroOffset) { - ParsedTimezone tz; - ASSERT_TRUE(parse_posix_tz("UTC0", tz)); - EXPECT_EQ(tz.std_offset_seconds, 0); - EXPECT_FALSE(tz.has_dst()); -} - -TEST(PosixTzParser, ParseUSEasternWithDST) { - ParsedTimezone tz; - ASSERT_TRUE(parse_posix_tz("EST5EDT,M3.2.0,M11.1.0", tz)); - EXPECT_EQ(tz.std_offset_seconds, 5 * 3600); - EXPECT_EQ(tz.dst_offset_seconds, 4 * 3600); // Default: STD - 1hr - EXPECT_TRUE(tz.has_dst()); - EXPECT_EQ(tz.dst_start.month, 3); - EXPECT_EQ(tz.dst_start.week, 2); - EXPECT_EQ(tz.dst_start.day_of_week, 0); // Sunday - EXPECT_EQ(tz.dst_start.time_seconds, 2 * 3600); // Default 2:00 AM - EXPECT_EQ(tz.dst_end.month, 11); - EXPECT_EQ(tz.dst_end.week, 1); - EXPECT_EQ(tz.dst_end.day_of_week, 0); -} - -TEST(PosixTzParser, ParseUSCentralWithTime) { - ParsedTimezone tz; - ASSERT_TRUE(parse_posix_tz("CST6CDT,M3.2.0/2,M11.1.0/2", tz)); - EXPECT_EQ(tz.std_offset_seconds, 6 * 3600); - EXPECT_EQ(tz.dst_offset_seconds, 5 * 3600); - EXPECT_EQ(tz.dst_start.time_seconds, 2 * 3600); // 2:00 AM - EXPECT_EQ(tz.dst_end.time_seconds, 2 * 3600); -} - -TEST(PosixTzParser, ParseEuropeBerlin) { - ParsedTimezone tz; - ASSERT_TRUE(parse_posix_tz("CET-1CEST,M3.5.0,M10.5.0/3", tz)); - EXPECT_EQ(tz.std_offset_seconds, -1 * 3600); - EXPECT_EQ(tz.dst_offset_seconds, -2 * 3600); // Default: STD - 1hr - EXPECT_TRUE(tz.has_dst()); - EXPECT_EQ(tz.dst_start.month, 3); - EXPECT_EQ(tz.dst_start.week, 5); // Last week - EXPECT_EQ(tz.dst_end.month, 10); - EXPECT_EQ(tz.dst_end.week, 5); // Last week - EXPECT_EQ(tz.dst_end.time_seconds, 3 * 3600); // 3:00 AM -} - -TEST(PosixTzParser, ParseNewZealand) { - ParsedTimezone tz; - // Southern hemisphere - DST starts in Sept, ends in April - ASSERT_TRUE(parse_posix_tz("NZST-12NZDT,M9.5.0,M4.1.0/3", tz)); - EXPECT_EQ(tz.std_offset_seconds, -12 * 3600); - EXPECT_EQ(tz.dst_offset_seconds, -13 * 3600); // Default: STD - 1hr - EXPECT_TRUE(tz.has_dst()); - EXPECT_EQ(tz.dst_start.month, 9); // September - EXPECT_EQ(tz.dst_end.month, 4); // April -} - -TEST(PosixTzParser, ParseExplicitDstOffset) { - ParsedTimezone tz; - // Some places have non-standard DST offsets - ASSERT_TRUE(parse_posix_tz("TEST5DST4,M3.2.0,M11.1.0", tz)); - EXPECT_EQ(tz.std_offset_seconds, 5 * 3600); - EXPECT_EQ(tz.dst_offset_seconds, 4 * 3600); - EXPECT_TRUE(tz.has_dst()); -} - -// ============================================================================ -// Angle-bracket notation tests (espressif/newlib-esp32#8) -// ============================================================================ - -TEST(PosixTzParser, ParseAngleBracketPositive) { - // Format: <+07>-7 means UTC+7 (name is "+07", offset is -7 hours east) - ParsedTimezone tz; - ASSERT_TRUE(parse_posix_tz("<+07>-7", tz)); - EXPECT_EQ(tz.std_offset_seconds, -7 * 3600); // -7 = 7 hours east of UTC - EXPECT_FALSE(tz.has_dst()); -} - -TEST(PosixTzParser, ParseAngleBracketNegative) { - // <-03>3 means UTC-3 (name is "-03", offset is 3 hours west) - ParsedTimezone tz; - ASSERT_TRUE(parse_posix_tz("<-03>3", tz)); - EXPECT_EQ(tz.std_offset_seconds, 3 * 3600); - EXPECT_FALSE(tz.has_dst()); -} - -TEST(PosixTzParser, ParseAngleBracketWithDST) { - // <+10>-10<+11>,M10.1.0,M4.1.0/3 (Australia/Sydney style) - ParsedTimezone tz; - ASSERT_TRUE(parse_posix_tz("<+10>-10<+11>,M10.1.0,M4.1.0/3", tz)); - EXPECT_EQ(tz.std_offset_seconds, -10 * 3600); - EXPECT_EQ(tz.dst_offset_seconds, -11 * 3600); - EXPECT_TRUE(tz.has_dst()); - EXPECT_EQ(tz.dst_start.month, 10); - EXPECT_EQ(tz.dst_end.month, 4); -} - -TEST(PosixTzParser, ParseAngleBracketNamed) { - // -10 (Australian Eastern Standard Time) - ParsedTimezone tz; - ASSERT_TRUE(parse_posix_tz("-10", tz)); - EXPECT_EQ(tz.std_offset_seconds, -10 * 3600); - EXPECT_FALSE(tz.has_dst()); -} - -TEST(PosixTzParser, ParseAngleBracketWithMinutes) { - // <+0545>-5:45 (Nepal) - ParsedTimezone tz; - ASSERT_TRUE(parse_posix_tz("<+0545>-5:45", tz)); - EXPECT_EQ(tz.std_offset_seconds, -(5 * 3600 + 45 * 60)); - EXPECT_FALSE(tz.has_dst()); -} - -// ============================================================================ -// Half-hour and unusual offset tests -// ============================================================================ - -TEST(PosixTzParser, ParseOffsetWithMinutesIndia) { - ParsedTimezone tz; - // India: UTC+5:30 - ASSERT_TRUE(parse_posix_tz("IST-5:30", tz)); - EXPECT_EQ(tz.std_offset_seconds, -(5 * 3600 + 30 * 60)); - EXPECT_FALSE(tz.has_dst()); -} - -TEST(PosixTzParser, ParseOffsetWithMinutesNepal) { - ParsedTimezone tz; - // Nepal: UTC+5:45 - ASSERT_TRUE(parse_posix_tz("NPT-5:45", tz)); - EXPECT_EQ(tz.std_offset_seconds, -(5 * 3600 + 45 * 60)); - EXPECT_FALSE(tz.has_dst()); -} - -TEST(PosixTzParser, ParseOffsetWithSeconds) { - ParsedTimezone tz; - // Unusual but valid: offset with seconds - ASSERT_TRUE(parse_posix_tz("TEST-1:30:30", tz)); - EXPECT_EQ(tz.std_offset_seconds, -(1 * 3600 + 30 * 60 + 30)); -} - -TEST(PosixTzParser, ParseChathamIslands) { - // Chatham Islands: UTC+12:45 with DST - ParsedTimezone tz; - ASSERT_TRUE(parse_posix_tz("<+1245>-12:45<+1345>,M9.5.0/2:45,M4.1.0/3:45", tz)); - EXPECT_EQ(tz.std_offset_seconds, -(12 * 3600 + 45 * 60)); - EXPECT_EQ(tz.dst_offset_seconds, -(13 * 3600 + 45 * 60)); - EXPECT_TRUE(tz.has_dst()); -} - -// ============================================================================ -// Invalid input tests -// ============================================================================ - -TEST(PosixTzParser, ParseEmptyStringFails) { - ParsedTimezone tz; - EXPECT_FALSE(parse_posix_tz("", tz)); -} - -TEST(PosixTzParser, ParseNullFails) { - ParsedTimezone tz; - EXPECT_FALSE(parse_posix_tz(nullptr, tz)); -} - -TEST(PosixTzParser, ParseShortNameFails) { - ParsedTimezone tz; - // TZ name must be at least 3 characters - EXPECT_FALSE(parse_posix_tz("AB5", tz)); -} - -TEST(PosixTzParser, ParseMissingOffsetFails) { - ParsedTimezone tz; - EXPECT_FALSE(parse_posix_tz("EST", tz)); -} - -TEST(PosixTzParser, ParseUnterminatedBracketFails) { - ParsedTimezone tz; - EXPECT_FALSE(parse_posix_tz("<+07-7", tz)); // Missing closing > -} - -// ============================================================================ -// J-format and plain day number tests -// ============================================================================ - -TEST(PosixTzParser, ParseJFormatBasic) { - ParsedTimezone tz; - // J format: Julian day 1-365, not counting Feb 29 - ASSERT_TRUE(parse_posix_tz("EST5EDT,J60,J305", tz)); - EXPECT_TRUE(tz.has_dst()); - EXPECT_EQ(tz.dst_start.type, DSTRuleType::JULIAN_NO_LEAP); - EXPECT_EQ(tz.dst_start.day, 60); // March 1 - EXPECT_EQ(tz.dst_end.type, DSTRuleType::JULIAN_NO_LEAP); - EXPECT_EQ(tz.dst_end.day, 305); // November 1 -} - -TEST(PosixTzParser, ParseJFormatWithTime) { - ParsedTimezone tz; - ASSERT_TRUE(parse_posix_tz("EST5EDT,J60/2,J305/2", tz)); - EXPECT_EQ(tz.dst_start.day, 60); - EXPECT_EQ(tz.dst_start.time_seconds, 2 * 3600); - EXPECT_EQ(tz.dst_end.day, 305); - EXPECT_EQ(tz.dst_end.time_seconds, 2 * 3600); -} - -TEST(PosixTzParser, ParsePlainDayNumber) { - ParsedTimezone tz; - // Plain format: day 0-365, counting Feb 29 in leap years - ASSERT_TRUE(parse_posix_tz("EST5EDT,59,304", tz)); - EXPECT_TRUE(tz.has_dst()); - EXPECT_EQ(tz.dst_start.type, DSTRuleType::DAY_OF_YEAR); - EXPECT_EQ(tz.dst_start.day, 59); - EXPECT_EQ(tz.dst_end.type, DSTRuleType::DAY_OF_YEAR); - EXPECT_EQ(tz.dst_end.day, 304); -} - -TEST(PosixTzParser, JFormatInvalidDayZero) { - ParsedTimezone tz; - // J format day must be 1-365, not 0 - EXPECT_FALSE(parse_posix_tz("EST5EDT,J0,J305", tz)); -} - -TEST(PosixTzParser, JFormatInvalidDay366) { - ParsedTimezone tz; - // J format day must be 1-365 - EXPECT_FALSE(parse_posix_tz("EST5EDT,J366,J305", tz)); -} - -TEST(PosixTzParser, ParsePlainDayNumberWithTime) { - ParsedTimezone tz; - ASSERT_TRUE(parse_posix_tz("EST5EDT,59/3,304/1:30", tz)); - EXPECT_EQ(tz.dst_start.day, 59); - EXPECT_EQ(tz.dst_start.time_seconds, 3 * 3600); - EXPECT_EQ(tz.dst_end.day, 304); - EXPECT_EQ(tz.dst_end.time_seconds, 1 * 3600 + 30 * 60); -} - -TEST(PosixTzParser, PlainDayInvalidDay366) { - ParsedTimezone tz; - // Plain format day must be 0-365 - EXPECT_FALSE(parse_posix_tz("EST5EDT,366,304", tz)); -} - -// ============================================================================ -// Transition time edge cases (POSIX V3 allows -167 to +167 hours) -// ============================================================================ - -TEST(PosixTzParser, NegativeTransitionTime) { - ParsedTimezone tz; - // Negative transition time: /-1 means 11 PM (23:00) the previous day - ASSERT_TRUE(parse_posix_tz("EST5EDT,M3.2.0/-1,M11.1.0/2", tz)); - EXPECT_EQ(tz.dst_start.time_seconds, -1 * 3600); // -1 hour = 11 PM previous day - EXPECT_EQ(tz.dst_end.time_seconds, 2 * 3600); -} - -TEST(PosixTzParser, NegativeTransitionTimeWithMinutes) { - ParsedTimezone tz; - // /-1:30 means 10:30 PM the previous day - ASSERT_TRUE(parse_posix_tz("EST5EDT,M3.2.0/-1:30,M11.1.0", tz)); - EXPECT_EQ(tz.dst_start.time_seconds, -(1 * 3600 + 30 * 60)); -} - -TEST(PosixTzParser, LargeTransitionTime) { - ParsedTimezone tz; - // POSIX V3 allows transition times from -167 to +167 hours - // /25 means 1:00 AM the next day - ASSERT_TRUE(parse_posix_tz("EST5EDT,M3.2.0/25,M11.1.0", tz)); - EXPECT_EQ(tz.dst_start.time_seconds, 25 * 3600); -} - -TEST(PosixTzParser, MaxTransitionTime167Hours) { - ParsedTimezone tz; - // Maximum allowed transition time per POSIX V3 - ASSERT_TRUE(parse_posix_tz("EST5EDT,M3.2.0/167,M11.1.0", tz)); - EXPECT_EQ(tz.dst_start.time_seconds, 167 * 3600); -} - -TEST(PosixTzParser, TransitionTimeWithHoursMinutesSeconds) { - ParsedTimezone tz; - ASSERT_TRUE(parse_posix_tz("EST5EDT,M3.2.0/2:30:45,M11.1.0", tz)); - EXPECT_EQ(tz.dst_start.time_seconds, 2 * 3600 + 30 * 60 + 45); -} - -// ============================================================================ -// Invalid M format tests -// ============================================================================ - -TEST(PosixTzParser, MFormatInvalidMonth13) { - ParsedTimezone tz; - // Month must be 1-12 - EXPECT_FALSE(parse_posix_tz("EST5EDT,M13.1.0,M11.1.0", tz)); -} - -TEST(PosixTzParser, MFormatInvalidMonth0) { - ParsedTimezone tz; - // Month must be 1-12 - EXPECT_FALSE(parse_posix_tz("EST5EDT,M0.1.0,M11.1.0", tz)); -} - -TEST(PosixTzParser, MFormatInvalidWeek6) { - ParsedTimezone tz; - // Week must be 1-5 - EXPECT_FALSE(parse_posix_tz("EST5EDT,M3.6.0,M11.1.0", tz)); -} - -TEST(PosixTzParser, MFormatInvalidWeek0) { - ParsedTimezone tz; - // Week must be 1-5 - EXPECT_FALSE(parse_posix_tz("EST5EDT,M3.0.0,M11.1.0", tz)); -} - -TEST(PosixTzParser, MFormatInvalidDayOfWeek7) { - ParsedTimezone tz; - // Day of week must be 0-6 - EXPECT_FALSE(parse_posix_tz("EST5EDT,M3.2.7,M11.1.0", tz)); -} - -TEST(PosixTzParser, MissingEndRule) { - ParsedTimezone tz; - // POSIX requires both start and end rules if any rules are specified - EXPECT_FALSE(parse_posix_tz("EST5EDT,M3.2.0", tz)); -} - -TEST(PosixTzParser, MissingEndRuleJFormat) { - ParsedTimezone tz; - // POSIX requires both start and end rules if any rules are specified - EXPECT_FALSE(parse_posix_tz("EST5EDT,J60", tz)); -} - -TEST(PosixTzParser, MissingEndRulePlainDay) { - ParsedTimezone tz; - // POSIX requires both start and end rules if any rules are specified - EXPECT_FALSE(parse_posix_tz("EST5EDT,60", tz)); -} - -TEST(PosixTzParser, LowercaseMFormat) { - ParsedTimezone tz; - // Lowercase 'm' should be accepted - ASSERT_TRUE(parse_posix_tz("EST5EDT,m3.2.0,m11.1.0", tz)); - EXPECT_TRUE(tz.has_dst()); - EXPECT_EQ(tz.dst_start.month, 3); - EXPECT_EQ(tz.dst_end.month, 11); -} - -TEST(PosixTzParser, LowercaseJFormat) { - ParsedTimezone tz; - // Lowercase 'j' should be accepted - ASSERT_TRUE(parse_posix_tz("EST5EDT,j60,j305", tz)); - EXPECT_EQ(tz.dst_start.type, DSTRuleType::JULIAN_NO_LEAP); - EXPECT_EQ(tz.dst_start.day, 60); -} - -TEST(PosixTzParser, DstNameWithoutRules) { - ParsedTimezone tz; - // DST name present but no rules - treat as no DST since we can't determine transitions - ASSERT_TRUE(parse_posix_tz("EST5EDT", tz)); - EXPECT_FALSE(tz.has_dst()); - EXPECT_EQ(tz.std_offset_seconds, 5 * 3600); -} - -TEST(PosixTzParser, TrailingCharactersIgnored) { - ParsedTimezone tz; - // Trailing characters after valid TZ should be ignored (parser stops at end of valid input) - // This matches libc behavior - ASSERT_TRUE(parse_posix_tz("EST5 extra garbage here", tz)); - EXPECT_EQ(tz.std_offset_seconds, 5 * 3600); - EXPECT_FALSE(tz.has_dst()); -} - -TEST(PosixTzParser, PlainDay365LeapYear) { - // Day 365 in leap year is Dec 31 - int month, day; - internal::day_of_year_to_month_day(365, 2024, month, day); - EXPECT_EQ(month, 12); - EXPECT_EQ(day, 31); -} - -TEST(PosixTzParser, PlainDay364NonLeapYear) { - // Day 364 (0-indexed) is Dec 31 in non-leap year (last valid day) - int month, day; - internal::day_of_year_to_month_day(364, 2025, month, day); - EXPECT_EQ(month, 12); - EXPECT_EQ(day, 31); -} - -// ============================================================================ -// Large offset tests -// ============================================================================ - -TEST(PosixTzParser, MaxOffset14Hours) { - ParsedTimezone tz; - // Line Islands (Kiribati) is UTC+14, the maximum offset - ASSERT_TRUE(parse_posix_tz("<+14>-14", tz)); - EXPECT_EQ(tz.std_offset_seconds, -14 * 3600); -} - -TEST(PosixTzParser, MaxNegativeOffset12Hours) { - ParsedTimezone tz; - // Baker Island is UTC-12 - ASSERT_TRUE(parse_posix_tz("<-12>12", tz)); - EXPECT_EQ(tz.std_offset_seconds, 12 * 3600); +// Helper to build Australia/Sydney timezone (AEST-10AEDT,M10.1.0,M4.1.0/3) +static ParsedTimezone make_australia_sydney() { + ParsedTimezone tz{}; + tz.std_offset_seconds = -10 * 3600; + tz.dst_offset_seconds = -11 * 3600; + tz.dst_start.type = DSTRuleType::MONTH_WEEK_DAY; + tz.dst_start.month = 10; + tz.dst_start.week = 1; + tz.dst_start.day_of_week = 0; + tz.dst_start.time_seconds = 2 * 3600; + tz.dst_end.type = DSTRuleType::MONTH_WEEK_DAY; + tz.dst_end.month = 4; + tz.dst_end.week = 1; + tz.dst_end.day_of_week = 0; + tz.dst_end.time_seconds = 3 * 3600; + return tz; } // ============================================================================ // Helper function tests // ============================================================================ -TEST(PosixTzParser, JulianDay60IsMarch1) { +TEST(PosixTz, JulianDay60IsMarch1) { // J60 is always March 1 (J format ignores leap years by design) int month, day; internal::julian_to_month_day(60, month, day); @@ -471,7 +114,7 @@ TEST(PosixTzParser, JulianDay60IsMarch1) { EXPECT_EQ(day, 1); } -TEST(PosixTzParser, DayOfYear59DiffersByLeap) { +TEST(PosixTz, DayOfYear59DiffersByLeap) { int month, day; // Day 59 in leap year is Feb 29 internal::day_of_year_to_month_day(59, 2024, month, day); @@ -483,7 +126,7 @@ TEST(PosixTzParser, DayOfYear59DiffersByLeap) { EXPECT_EQ(day, 1); } -TEST(PosixTzParser, DayOfWeekKnownDates) { +TEST(PosixTz, DayOfWeekKnownDates) { // January 1, 1970 was Thursday (4) EXPECT_EQ(internal::day_of_week(1970, 1, 1), 4); // January 1, 2000 was Saturday (6) @@ -492,56 +135,56 @@ TEST(PosixTzParser, DayOfWeekKnownDates) { EXPECT_EQ(internal::day_of_week(2026, 3, 8), 0); } -TEST(PosixTzParser, LeapYearDetection) { +TEST(PosixTz, LeapYearDetection) { EXPECT_FALSE(internal::is_leap_year(1900)); // Divisible by 100 but not 400 EXPECT_TRUE(internal::is_leap_year(2000)); // Divisible by 400 EXPECT_TRUE(internal::is_leap_year(2024)); // Divisible by 4 EXPECT_FALSE(internal::is_leap_year(2025)); // Not divisible by 4 } -TEST(PosixTzParser, JulianDay1IsJan1) { +TEST(PosixTz, JulianDay1IsJan1) { int month, day; internal::julian_to_month_day(1, month, day); EXPECT_EQ(month, 1); EXPECT_EQ(day, 1); } -TEST(PosixTzParser, JulianDay31IsJan31) { +TEST(PosixTz, JulianDay31IsJan31) { int month, day; internal::julian_to_month_day(31, month, day); EXPECT_EQ(month, 1); EXPECT_EQ(day, 31); } -TEST(PosixTzParser, JulianDay32IsFeb1) { +TEST(PosixTz, JulianDay32IsFeb1) { int month, day; internal::julian_to_month_day(32, month, day); EXPECT_EQ(month, 2); EXPECT_EQ(day, 1); } -TEST(PosixTzParser, JulianDay59IsFeb28) { +TEST(PosixTz, JulianDay59IsFeb28) { int month, day; internal::julian_to_month_day(59, month, day); EXPECT_EQ(month, 2); EXPECT_EQ(day, 28); } -TEST(PosixTzParser, JulianDay365IsDec31) { +TEST(PosixTz, JulianDay365IsDec31) { int month, day; internal::julian_to_month_day(365, month, day); EXPECT_EQ(month, 12); EXPECT_EQ(day, 31); } -TEST(PosixTzParser, DayOfYear0IsJan1) { +TEST(PosixTz, DayOfYear0IsJan1) { int month, day; internal::day_of_year_to_month_day(0, 2025, month, day); EXPECT_EQ(month, 1); EXPECT_EQ(day, 1); } -TEST(PosixTzParser, DaysInMonthRegular) { +TEST(PosixTz, DaysInMonthRegular) { // Test all 12 months to ensure switch coverage EXPECT_EQ(internal::days_in_month(2025, 1), 31); // Jan - default case EXPECT_EQ(internal::days_in_month(2025, 2), 28); // Feb - case 2 @@ -557,19 +200,32 @@ TEST(PosixTzParser, DaysInMonthRegular) { EXPECT_EQ(internal::days_in_month(2025, 12), 31); // Dec - default case } -TEST(PosixTzParser, DaysInMonthLeapYear) { +TEST(PosixTz, DaysInMonthLeapYear) { EXPECT_EQ(internal::days_in_month(2024, 2), 29); EXPECT_EQ(internal::days_in_month(2025, 2), 28); } +TEST(PosixTz, PlainDay365LeapYear) { + int month, day; + internal::day_of_year_to_month_day(365, 2024, month, day); + EXPECT_EQ(month, 12); + EXPECT_EQ(day, 31); +} + +TEST(PosixTz, PlainDay364NonLeapYear) { + int month, day; + internal::day_of_year_to_month_day(364, 2025, month, day); + EXPECT_EQ(month, 12); + EXPECT_EQ(day, 31); +} + // ============================================================================ // DST transition calculation tests // ============================================================================ -TEST(PosixTzParser, DstStartUSEastern2026) { +TEST(PosixTz, DstStartUSEastern2026) { // March 8, 2026 is 2nd Sunday of March - ParsedTimezone tz; - parse_posix_tz("EST5EDT,M3.2.0/2,M11.1.0/2", tz); + auto tz = make_us_eastern(); time_t dst_start = internal::calculate_dst_transition(2026, tz.dst_start, tz.std_offset_seconds); struct tm tm; @@ -582,10 +238,9 @@ TEST(PosixTzParser, DstStartUSEastern2026) { EXPECT_EQ(tm.tm_hour, 7); // 7:00 UTC = 2:00 EST } -TEST(PosixTzParser, DstEndUSEastern2026) { +TEST(PosixTz, DstEndUSEastern2026) { // November 1, 2026 is 1st Sunday of November - ParsedTimezone tz; - parse_posix_tz("EST5EDT,M3.2.0/2,M11.1.0/2", tz); + auto tz = make_us_eastern(); time_t dst_end = internal::calculate_dst_transition(2026, tz.dst_end, tz.dst_offset_seconds); struct tm tm; @@ -598,7 +253,7 @@ TEST(PosixTzParser, DstEndUSEastern2026) { EXPECT_EQ(tm.tm_hour, 6); // 6:00 UTC = 2:00 EDT } -TEST(PosixTzParser, LastSundayOfMarch2026) { +TEST(PosixTz, LastSundayOfMarch2026) { // Europe: M3.5.0 = last Sunday of March = March 29, 2026 DSTRule rule{}; rule.type = DSTRuleType::MONTH_WEEK_DAY; @@ -613,7 +268,7 @@ TEST(PosixTzParser, LastSundayOfMarch2026) { EXPECT_EQ(tm.tm_wday, 0); // Sunday } -TEST(PosixTzParser, LastSundayOfOctober2026) { +TEST(PosixTz, LastSundayOfOctober2026) { // Europe: M10.5.0 = last Sunday of October = October 25, 2026 DSTRule rule{}; rule.type = DSTRuleType::MONTH_WEEK_DAY; @@ -628,7 +283,7 @@ TEST(PosixTzParser, LastSundayOfOctober2026) { EXPECT_EQ(tm.tm_wday, 0); // Sunday } -TEST(PosixTzParser, FirstSundayOfApril2026) { +TEST(PosixTz, FirstSundayOfApril2026) { // April 5, 2026 is 1st Sunday DSTRule rule{}; rule.type = DSTRuleType::MONTH_WEEK_DAY; @@ -647,46 +302,39 @@ TEST(PosixTzParser, FirstSundayOfApril2026) { // DST detection tests // ============================================================================ -TEST(PosixTzParser, IsInDstUSEasternSummer) { - ParsedTimezone tz; - parse_posix_tz("EST5EDT,M3.2.0/2,M11.1.0/2", tz); - +TEST(PosixTz, IsInDstUSEasternSummer) { + auto tz = make_us_eastern(); // July 4, 2026 12:00 UTC - definitely in DST time_t summer = make_utc(2026, 7, 4, 12); EXPECT_TRUE(is_in_dst(summer, tz)); } -TEST(PosixTzParser, IsInDstUSEasternWinter) { - ParsedTimezone tz; - parse_posix_tz("EST5EDT,M3.2.0/2,M11.1.0/2", tz); - +TEST(PosixTz, IsInDstUSEasternWinter) { + auto tz = make_us_eastern(); // January 15, 2026 12:00 UTC - definitely not in DST time_t winter = make_utc(2026, 1, 15, 12); EXPECT_FALSE(is_in_dst(winter, tz)); } -TEST(PosixTzParser, IsInDstNoDstTimezone) { - ParsedTimezone tz; - parse_posix_tz("IST-5:30", tz); +TEST(PosixTz, IsInDstNoDstTimezone) { + // India: IST-5:30 (no DST) + ParsedTimezone tz{}; + tz.std_offset_seconds = -(5 * 3600 + 30 * 60); + // No DST rules - // July 15, 2026 12:00 UTC time_t epoch = make_utc(2026, 7, 15, 12); EXPECT_FALSE(is_in_dst(epoch, tz)); } -TEST(PosixTzParser, SouthernHemisphereDstSummer) { - ParsedTimezone tz; - parse_posix_tz("NZST-12NZDT,M9.5.0,M4.1.0/3", tz); - +TEST(PosixTz, SouthernHemisphereDstSummer) { + auto tz = make_new_zealand(); // December 15, 2025 12:00 UTC - summer in NZ, should be in DST time_t nz_summer = make_utc(2025, 12, 15, 12); EXPECT_TRUE(is_in_dst(nz_summer, tz)); } -TEST(PosixTzParser, SouthernHemisphereDstWinter) { - ParsedTimezone tz; - parse_posix_tz("NZST-12NZDT,M9.5.0,M4.1.0/3", tz); - +TEST(PosixTz, SouthernHemisphereDstWinter) { + auto tz = make_new_zealand(); // July 15, 2026 12:00 UTC - winter in NZ, should NOT be in DST time_t nz_winter = make_utc(2026, 7, 15, 12); EXPECT_FALSE(is_in_dst(nz_winter, tz)); @@ -696,9 +344,8 @@ TEST(PosixTzParser, SouthernHemisphereDstWinter) { // epoch_to_local_tm tests // ============================================================================ -TEST(PosixTzParser, EpochToLocalBasic) { - ParsedTimezone tz; - parse_posix_tz("UTC0", tz); +TEST(PosixTz, EpochToLocalBasic) { + ParsedTimezone tz{}; // UTC time_t epoch = 0; // Jan 1, 1970 00:00:00 UTC struct tm local; @@ -709,9 +356,8 @@ TEST(PosixTzParser, EpochToLocalBasic) { EXPECT_EQ(local.tm_hour, 0); } -TEST(PosixTzParser, EpochToLocalNegativeEpoch) { - ParsedTimezone tz; - parse_posix_tz("UTC0", tz); +TEST(PosixTz, EpochToLocalNegativeEpoch) { + ParsedTimezone tz{}; // UTC // Dec 31, 1969 23:59:59 UTC (1 second before epoch) time_t epoch = -1; @@ -725,15 +371,15 @@ TEST(PosixTzParser, EpochToLocalNegativeEpoch) { EXPECT_EQ(local.tm_sec, 59); } -TEST(PosixTzParser, EpochToLocalNullTmFails) { - ParsedTimezone tz; - parse_posix_tz("UTC0", tz); +TEST(PosixTz, EpochToLocalNullTmFails) { + ParsedTimezone tz{}; EXPECT_FALSE(epoch_to_local_tm(0, tz, nullptr)); } -TEST(PosixTzParser, EpochToLocalWithOffset) { - ParsedTimezone tz; - parse_posix_tz("EST5", tz); // UTC-5 +TEST(PosixTz, EpochToLocalWithOffset) { + // EST5 (UTC-5, no DST) + ParsedTimezone tz{}; + tz.std_offset_seconds = 5 * 3600; // Jan 1, 2026 05:00:00 UTC should be Jan 1, 2026 00:00:00 EST time_t utc_epoch = make_utc(2026, 1, 1, 5); @@ -745,9 +391,8 @@ TEST(PosixTzParser, EpochToLocalWithOffset) { EXPECT_EQ(local.tm_isdst, 0); } -TEST(PosixTzParser, EpochToLocalDstTransition) { - ParsedTimezone tz; - parse_posix_tz("EST5EDT,M3.2.0/2,M11.1.0/2", tz); +TEST(PosixTz, EpochToLocalDstTransition) { + auto tz = make_us_eastern(); // July 4, 2026 16:00 UTC = 12:00 EDT (noon) time_t utc_epoch = make_utc(2026, 7, 4, 16); @@ -758,210 +403,12 @@ TEST(PosixTzParser, EpochToLocalDstTransition) { EXPECT_EQ(local.tm_isdst, 1); } -// ============================================================================ -// Leap year edge cases for closed-form year arithmetic -// ============================================================================ - -TEST(PosixTzParser, EpochToLocalLeapYear2000) { - // 2000 is a leap year (divisible by 400) - ParsedTimezone tz; - ASSERT_TRUE(parse_posix_tz("UTC0", tz)); - - // Feb 29, 2000 12:00:00 UTC - time_t epoch = make_utc(2000, 2, 29, 12); - struct tm local; - ASSERT_TRUE(epoch_to_local_tm(epoch, tz, &local)); - EXPECT_EQ(local.tm_year, 100); // 2000 - EXPECT_EQ(local.tm_mon, 1); // February - EXPECT_EQ(local.tm_mday, 29); - EXPECT_EQ(local.tm_hour, 12); -} - -TEST(PosixTzParser, EpochToLocalNonLeapYear2100) { - // 2100 is NOT a leap year (divisible by 100 but not 400) - ParsedTimezone tz; - ASSERT_TRUE(parse_posix_tz("UTC0", tz)); - - // Mar 1, 2100 00:00:00 UTC — the day after what would be Feb 29 - time_t epoch = make_utc(2100, 3, 1); - struct tm local; - ASSERT_TRUE(epoch_to_local_tm(epoch, tz, &local)); - EXPECT_EQ(local.tm_year, 200); // 2100 - EXPECT_EQ(local.tm_mon, 2); // March - EXPECT_EQ(local.tm_mday, 1); - - // Feb 28, 2100 23:59:59 UTC — last second of February (no Feb 29) - epoch = make_utc(2100, 2, 28, 23, 59, 59); - ASSERT_TRUE(epoch_to_local_tm(epoch, tz, &local)); - EXPECT_EQ(local.tm_year, 200); - EXPECT_EQ(local.tm_mon, 1); // February - EXPECT_EQ(local.tm_mday, 28); -} - -TEST(PosixTzParser, EpochToLocalLeapYear2400) { - // 2400 is a leap year (divisible by 400) - ParsedTimezone tz; - ASSERT_TRUE(parse_posix_tz("UTC0", tz)); - - time_t epoch = make_utc(2400, 2, 29, 6); - struct tm local; - ASSERT_TRUE(epoch_to_local_tm(epoch, tz, &local)); - EXPECT_EQ(local.tm_year, 500); // 2400 - EXPECT_EQ(local.tm_mon, 1); // February - EXPECT_EQ(local.tm_mday, 29); - EXPECT_EQ(local.tm_hour, 6); -} - -TEST(PosixTzParser, EpochToLocalNewYearBoundaries) { - // Test year boundary — last second of 2099 and first second of 2100 - ParsedTimezone tz; - ASSERT_TRUE(parse_posix_tz("UTC0", tz)); - struct tm local; - - // Dec 31, 2099 23:59:59 UTC - time_t epoch = make_utc(2099, 12, 31, 23, 59, 59); - ASSERT_TRUE(epoch_to_local_tm(epoch, tz, &local)); - EXPECT_EQ(local.tm_year, 199); // 2099 - EXPECT_EQ(local.tm_mon, 11); // December - EXPECT_EQ(local.tm_mday, 31); - - // Jan 1, 2100 00:00:00 UTC - epoch = make_utc(2100, 1, 1); - ASSERT_TRUE(epoch_to_local_tm(epoch, tz, &local)); - EXPECT_EQ(local.tm_year, 200); // 2100 - EXPECT_EQ(local.tm_mon, 0); // January - EXPECT_EQ(local.tm_mday, 1); -} - -TEST(PosixTzParser, EpochToLocalDstAcrossCenturyBoundary) { - // DST transition in year 2100 (non-leap) with US Eastern rules - ParsedTimezone tz; - ASSERT_TRUE(parse_posix_tz("EST5EDT,M3.2.0/2,M11.1.0/2", tz)); - - // July 4, 2100 16:00 UTC = 12:00 EDT - time_t epoch = make_utc(2100, 7, 4, 16); - struct tm local; - ASSERT_TRUE(epoch_to_local_tm(epoch, tz, &local)); - EXPECT_EQ(local.tm_hour, 12); - EXPECT_EQ(local.tm_isdst, 1); - - // Jan 15, 2100 10:00 UTC = 05:00 EST - epoch = make_utc(2100, 1, 15, 10); - ASSERT_TRUE(epoch_to_local_tm(epoch, tz, &local)); - EXPECT_EQ(local.tm_hour, 5); - EXPECT_EQ(local.tm_isdst, 0); -} - -TEST(PosixTzParser, EpochToLocalFarFutureYear5000) { - // Year 5000 — days/365 estimate overshoots by ~2 years due to leap days, - // requiring multiple correction steps in days_to_year. - ParsedTimezone tz; - ASSERT_TRUE(parse_posix_tz("UTC0", tz)); - - time_t epoch = make_utc(5000, 6, 15, 12); - struct tm local; - ASSERT_TRUE(epoch_to_local_tm(epoch, tz, &local)); - EXPECT_EQ(local.tm_year, 3100); // 5000 - EXPECT_EQ(local.tm_mon, 5); // June - EXPECT_EQ(local.tm_mday, 15); - EXPECT_EQ(local.tm_hour, 12); -} - -// ============================================================================ -// Verification against libc -// ============================================================================ - -class LibcVerificationTest : public ::testing::TestWithParam> { - protected: - // NOLINTNEXTLINE(readability-identifier-naming) - Google Test requires this name - void SetUp() override { - // Save current TZ - const char *current_tz = getenv("TZ"); - saved_tz_ = current_tz ? current_tz : ""; - had_tz_ = current_tz != nullptr; - } - - // NOLINTNEXTLINE(readability-identifier-naming) - Google Test requires this name - void TearDown() override { - // Restore TZ - if (had_tz_) { - setenv("TZ", saved_tz_.c_str(), 1); - } else { - unsetenv("TZ"); - } - tzset(); - } - - private: - std::string saved_tz_; - bool had_tz_{false}; -}; - -TEST_P(LibcVerificationTest, MatchesLibc) { - auto [tz_str, epoch] = GetParam(); - - ParsedTimezone tz; - ASSERT_TRUE(parse_posix_tz(tz_str, tz)); - - // Our implementation - struct tm our_tm {}; - ASSERT_TRUE(epoch_to_local_tm(epoch, tz, &our_tm)); - - // libc implementation - setenv("TZ", tz_str, 1); - tzset(); - struct tm *libc_tm = localtime(&epoch); - ASSERT_NE(libc_tm, nullptr); - - EXPECT_EQ(our_tm.tm_year, libc_tm->tm_year); - EXPECT_EQ(our_tm.tm_mon, libc_tm->tm_mon); - EXPECT_EQ(our_tm.tm_mday, libc_tm->tm_mday); - EXPECT_EQ(our_tm.tm_hour, libc_tm->tm_hour); - EXPECT_EQ(our_tm.tm_min, libc_tm->tm_min); - EXPECT_EQ(our_tm.tm_sec, libc_tm->tm_sec); - EXPECT_EQ(our_tm.tm_isdst, libc_tm->tm_isdst); -} - -INSTANTIATE_TEST_SUITE_P(USEastern, LibcVerificationTest, - ::testing::Values(std::make_tuple("EST5EDT,M3.2.0/2,M11.1.0/2", 1704067200), - std::make_tuple("EST5EDT,M3.2.0/2,M11.1.0/2", 1720000000), - std::make_tuple("EST5EDT,M3.2.0/2,M11.1.0/2", 1735689600))); - -INSTANTIATE_TEST_SUITE_P(AngleBracket, LibcVerificationTest, - ::testing::Values(std::make_tuple("<+07>-7", 1704067200), - std::make_tuple("<+07>-7", 1720000000))); - -INSTANTIATE_TEST_SUITE_P(India, LibcVerificationTest, - ::testing::Values(std::make_tuple("IST-5:30", 1704067200), - std::make_tuple("IST-5:30", 1720000000))); - -INSTANTIATE_TEST_SUITE_P(NewZealand, LibcVerificationTest, - ::testing::Values(std::make_tuple("NZST-12NZDT,M9.5.0,M4.1.0/3", 1704067200), - std::make_tuple("NZST-12NZDT,M9.5.0,M4.1.0/3", 1720000000))); - -INSTANTIATE_TEST_SUITE_P(USCentral, LibcVerificationTest, - ::testing::Values(std::make_tuple("CST6CDT,M3.2.0/2,M11.1.0/2", 1704067200), - std::make_tuple("CST6CDT,M3.2.0/2,M11.1.0/2", 1720000000), - std::make_tuple("CST6CDT,M3.2.0/2,M11.1.0/2", 1735689600))); - -INSTANTIATE_TEST_SUITE_P(EuropeBerlin, LibcVerificationTest, - ::testing::Values(std::make_tuple("CET-1CEST,M3.5.0,M10.5.0/3", 1704067200), - std::make_tuple("CET-1CEST,M3.5.0,M10.5.0/3", 1720000000), - std::make_tuple("CET-1CEST,M3.5.0,M10.5.0/3", 1735689600))); - -INSTANTIATE_TEST_SUITE_P(AustraliaSydney, LibcVerificationTest, - ::testing::Values(std::make_tuple("AEST-10AEDT,M10.1.0,M4.1.0/3", 1704067200), - std::make_tuple("AEST-10AEDT,M10.1.0,M4.1.0/3", 1720000000), - std::make_tuple("AEST-10AEDT,M10.1.0,M4.1.0/3", 1735689600))); - // ============================================================================ // DST boundary edge cases // ============================================================================ -TEST(PosixTzParser, DstBoundaryJustBeforeSpringForward) { - // Test 1 second before DST starts - ParsedTimezone tz; - parse_posix_tz("EST5EDT,M3.2.0/2,M11.1.0/2", tz); +TEST(PosixTz, DstBoundaryJustBeforeSpringForward) { + auto tz = make_us_eastern(); // March 8, 2026 06:59:59 UTC = 01:59:59 EST (1 second before spring forward) time_t before_epoch = make_utc(2026, 3, 8, 6, 59, 59); @@ -972,10 +419,8 @@ TEST(PosixTzParser, DstBoundaryJustBeforeSpringForward) { EXPECT_TRUE(is_in_dst(after_epoch, tz)); } -TEST(PosixTzParser, DstBoundaryJustBeforeFallBack) { - // Test 1 second before DST ends - ParsedTimezone tz; - parse_posix_tz("EST5EDT,M3.2.0/2,M11.1.0/2", tz); +TEST(PosixTz, DstBoundaryJustBeforeFallBack) { + auto tz = make_us_eastern(); // November 1, 2026 05:59:59 UTC = 01:59:59 EDT (1 second before fall back) time_t before_epoch = make_utc(2026, 11, 1, 5, 59, 59); @@ -1102,7 +547,6 @@ TEST(ESPTimeStrptime, PartialTimeFails) { TEST(ESPTimeStrptime, ExtraCharactersFails) { ESPTime t{}; - // Full datetime with extra characters should fail EXPECT_FALSE(ESPTime::strptime("2026-03-15 14:30:45x", 20, t)); } @@ -1123,6 +567,12 @@ TEST(ESPTimeStrptime, LeadingZeroTime) { // recalc_timestamp_local() tests - verify behavior matches libc mktime() // ============================================================================ +} // namespace esphome::testing + +namespace esphome::time::testing { + +using esphome::ESPTime; + // Helper to call libc mktime with same fields static time_t libc_mktime(int year, int month, int day, int hour, int min, int sec) { struct tm tm {}; @@ -1154,8 +604,7 @@ TEST(RecalcTimestampLocal, NormalTimeMatchesLibc) { const char *tz_str = "CST6CDT,M3.2.0,M11.1.0"; setenv("TZ", tz_str, 1); tzset(); - time::ParsedTimezone tz{}; - ASSERT_TRUE(parse_posix_tz(tz_str, tz)); + auto tz = make_us_central(); set_global_tz(tz); // Test a normal time in winter (no DST) @@ -1177,8 +626,7 @@ TEST(RecalcTimestampLocal, SpringForwardSkippedHour) { const char *tz_str = "CST6CDT,M3.2.0,M11.1.0"; setenv("TZ", tz_str, 1); tzset(); - time::ParsedTimezone tz{}; - ASSERT_TRUE(parse_posix_tz(tz_str, tz)); + auto tz = make_us_central(); set_global_tz(tz); // Test time before the transition (1:30 AM CST exists) @@ -1204,8 +652,7 @@ TEST(RecalcTimestampLocal, FallBackRepeatedHour) { const char *tz_str = "CST6CDT,M3.2.0,M11.1.0"; setenv("TZ", tz_str, 1); tzset(); - time::ParsedTimezone tz{}; - ASSERT_TRUE(parse_posix_tz(tz_str, tz)); + auto tz = make_us_central(); set_global_tz(tz); // Test time before the transition (midnight CDT) @@ -1227,13 +674,12 @@ TEST(RecalcTimestampLocal, FallBackRepeatedHour) { } TEST(RecalcTimestampLocal, SouthernHemisphereDST) { - // Set timezone to Australia/Sydney (AEST-10AEDT,M10.1.0,M4.1.0) + // Set timezone to Australia/Sydney (AEST-10AEDT,M10.1.0,M4.1.0/3) // DST starts first Sunday of October, ends first Sunday of April - const char *tz_str = "AEST-10AEDT,M10.1.0,M4.1.0"; + const char *tz_str = "AEST-10AEDT,M10.1.0,M4.1.0/3"; setenv("TZ", tz_str, 1); tzset(); - time::ParsedTimezone tz{}; - ASSERT_TRUE(parse_posix_tz(tz_str, tz)); + auto tz = make_australia_sydney(); set_global_tz(tz); // Test winter time (July - no DST in southern hemisphere) @@ -1253,8 +699,7 @@ TEST(RecalcTimestampLocal, ExactTransitionBoundary) { const char *tz_str = "CST6CDT,M3.2.0,M11.1.0"; setenv("TZ", tz_str, 1); tzset(); - time::ParsedTimezone tz{}; - ASSERT_TRUE(parse_posix_tz(tz_str, tz)); + auto tz = make_us_central(); set_global_tz(tz); // 1:59:59 AM CST - last second before transition (still standard time) @@ -1279,8 +724,19 @@ TEST(RecalcTimestampLocal, NonDefaultTransitionTime) { const char *tz_str = "CST6CDT,M3.2.0/3,M11.1.0/3"; setenv("TZ", tz_str, 1); tzset(); - time::ParsedTimezone tz{}; - ASSERT_TRUE(parse_posix_tz(tz_str, tz)); + ParsedTimezone tz{}; + tz.std_offset_seconds = 6 * 3600; + tz.dst_offset_seconds = 5 * 3600; + tz.dst_start.type = DSTRuleType::MONTH_WEEK_DAY; + tz.dst_start.month = 3; + tz.dst_start.week = 2; + tz.dst_start.day_of_week = 0; + tz.dst_start.time_seconds = 3 * 3600; + tz.dst_end.type = DSTRuleType::MONTH_WEEK_DAY; + tz.dst_end.month = 11; + tz.dst_end.week = 1; + tz.dst_end.day_of_week = 0; + tz.dst_end.time_seconds = 3 * 3600; set_global_tz(tz); // 2:30 AM should still be standard time (transition at 3:00 AM) @@ -1298,11 +754,21 @@ TEST(RecalcTimestampLocal, MinimalFieldsWithoutDayOfWeekOrYear) { // Regression test for issue #15115: DateTimeEntity::state_as_esptime() constructs // an ESPTime with only year/month/day/hour/minute/second set (no day_of_week or // day_of_year). recalc_timestamp_local() must work without those fields. - const char *tz_str = "CET-1CEST,M3.5.0,M10.5.0"; - setenv("TZ", tz_str, 1); + setenv("TZ", "CET-1CEST,M3.5.0,M10.5.0", 1); tzset(); time::ParsedTimezone tz{}; - ASSERT_TRUE(parse_posix_tz(tz_str, tz)); + tz.std_offset_seconds = -1 * 3600; // CET-1 = UTC+1 + tz.dst_offset_seconds = -2 * 3600; // CEST = UTC+2 + tz.dst_start.type = DSTRuleType::MONTH_WEEK_DAY; + tz.dst_start.month = 3; + tz.dst_start.week = 5; + tz.dst_start.day_of_week = 0; + tz.dst_start.time_seconds = 2 * 3600; + tz.dst_end.type = DSTRuleType::MONTH_WEEK_DAY; + tz.dst_end.month = 10; + tz.dst_end.week = 5; + tz.dst_end.day_of_week = 0; + tz.dst_end.time_seconds = 2 * 3600; set_global_tz(tz); // Construct ESPTime with only date/time fields (like state_as_esptime does) @@ -1326,11 +792,11 @@ TEST(RecalcTimestampLocal, MinimalFieldsWithoutDayOfWeekOrYear) { TEST(RecalcTimestampLocal, MinimalFieldsNoDST) { // Same test but with a timezone that has no DST - const char *tz_str = "IST-5:30"; - setenv("TZ", tz_str, 1); + setenv("TZ", "IST-5:30", 1); tzset(); time::ParsedTimezone tz{}; - ASSERT_TRUE(parse_posix_tz(tz_str, tz)); + tz.std_offset_seconds = -(5 * 3600 + 30 * 60); // IST-5:30 = UTC+5:30 + // No DST set_global_tz(tz); ESPTime t{}; @@ -1351,11 +817,10 @@ TEST(RecalcTimestampLocal, MinimalFieldsNoDST) { TEST(RecalcTimestampLocal, YearBoundaryDST) { // Test southern hemisphere DST across year boundary // Australia/Sydney: DST active from October to April (spans Jan 1) - const char *tz_str = "AEST-10AEDT,M10.1.0,M4.1.0"; + const char *tz_str = "AEST-10AEDT,M10.1.0,M4.1.0/3"; setenv("TZ", tz_str, 1); tzset(); - time::ParsedTimezone tz{}; - ASSERT_TRUE(parse_posix_tz(tz_str, tz)); + auto tz = make_australia_sydney(); set_global_tz(tz); // Dec 31, 2025 at 23:30 - DST should be active @@ -1380,8 +845,7 @@ TEST(RecalcTimestampLocal, YearBoundaryDST) { // ============================================================================ TEST(TimezoneOffset, NoTimezone) { - // When no timezone is set, offset should be 0 - time::ParsedTimezone tz{}; + ParsedTimezone tz{}; set_global_tz(tz); int32_t offset = ESPTime::timezone_offset(); @@ -1389,34 +853,28 @@ TEST(TimezoneOffset, NoTimezone) { } TEST(TimezoneOffset, FixedOffsetPositive) { - // India: UTC+5:30 (no DST) - const char *tz_str = "IST-5:30"; - time::ParsedTimezone tz{}; - ASSERT_TRUE(parse_posix_tz(tz_str, tz)); + // India: IST-5:30 (no DST) + ParsedTimezone tz{}; + tz.std_offset_seconds = -(5 * 3600 + 30 * 60); set_global_tz(tz); int32_t offset = ESPTime::timezone_offset(); - // Offset should be +5:30 = 19800 seconds (to add to UTC to get local) EXPECT_EQ(offset, 5 * 3600 + 30 * 60); } TEST(TimezoneOffset, FixedOffsetNegative) { - // US Eastern Standard Time: UTC-5 (testing without DST rules) - const char *tz_str = "EST5"; - time::ParsedTimezone tz{}; - ASSERT_TRUE(parse_posix_tz(tz_str, tz)); + // EST5 (no DST) + ParsedTimezone tz{}; + tz.std_offset_seconds = 5 * 3600; set_global_tz(tz); int32_t offset = ESPTime::timezone_offset(); - // Offset should be -5 hours = -18000 seconds EXPECT_EQ(offset, -5 * 3600); } TEST(TimezoneOffset, WithDstReturnsCorrectOffsetBasedOnCurrentTime) { // US Eastern with DST - const char *tz_str = "EST5EDT,M3.2.0,M11.1.0"; - time::ParsedTimezone tz{}; - ASSERT_TRUE(parse_posix_tz(tz_str, tz)); + auto tz = make_us_eastern(); set_global_tz(tz); // Get current time and check offset matches expected based on DST status @@ -1424,7 +882,7 @@ TEST(TimezoneOffset, WithDstReturnsCorrectOffsetBasedOnCurrentTime) { int32_t offset = ESPTime::timezone_offset(); // Verify offset matches what is_in_dst says - if (time::is_in_dst(now, tz)) { + if (is_in_dst(now, tz)) { // During DST, offset should be -4 hours (EDT) EXPECT_EQ(offset, -4 * 3600); } else { @@ -1433,4 +891,234 @@ TEST(TimezoneOffset, WithDstReturnsCorrectOffsetBasedOnCurrentTime) { } } -} // namespace esphome::testing +// ============================================================================ +// Leap year edge cases for closed-form year arithmetic +// ============================================================================ + +TEST(PosixTz, EpochToLocalLeapYear2000) { + // 2000 is a leap year (divisible by 400) + ParsedTimezone tz{}; // UTC + + // Feb 29, 2000 12:00:00 UTC + time_t epoch = make_utc(2000, 2, 29, 12); + struct tm local; + ASSERT_TRUE(epoch_to_local_tm(epoch, tz, &local)); + EXPECT_EQ(local.tm_year, 100); // 2000 + EXPECT_EQ(local.tm_mon, 1); // February + EXPECT_EQ(local.tm_mday, 29); + EXPECT_EQ(local.tm_hour, 12); +} + +TEST(PosixTz, EpochToLocalNonLeapYear2100) { + // 2100 is NOT a leap year (divisible by 100 but not 400) + ParsedTimezone tz{}; // UTC + + // Mar 1, 2100 00:00:00 UTC — the day after what would be Feb 29 + time_t epoch = make_utc(2100, 3, 1); + struct tm local; + ASSERT_TRUE(epoch_to_local_tm(epoch, tz, &local)); + EXPECT_EQ(local.tm_year, 200); // 2100 + EXPECT_EQ(local.tm_mon, 2); // March + EXPECT_EQ(local.tm_mday, 1); + + // Feb 28, 2100 23:59:59 UTC — last second of February (no Feb 29) + epoch = make_utc(2100, 2, 28, 23, 59, 59); + ASSERT_TRUE(epoch_to_local_tm(epoch, tz, &local)); + EXPECT_EQ(local.tm_year, 200); + EXPECT_EQ(local.tm_mon, 1); // February + EXPECT_EQ(local.tm_mday, 28); +} + +TEST(PosixTz, EpochToLocalLeapYear2400) { + // 2400 is a leap year (divisible by 400) + ParsedTimezone tz{}; // UTC + + time_t epoch = make_utc(2400, 2, 29, 6); + struct tm local; + ASSERT_TRUE(epoch_to_local_tm(epoch, tz, &local)); + EXPECT_EQ(local.tm_year, 500); // 2400 + EXPECT_EQ(local.tm_mon, 1); // February + EXPECT_EQ(local.tm_mday, 29); + EXPECT_EQ(local.tm_hour, 6); +} + +TEST(PosixTz, EpochToLocalNewYearBoundaries) { + // Test year boundary — last second of 2099 and first second of 2100 + ParsedTimezone tz{}; // UTC + struct tm local; + + // Dec 31, 2099 23:59:59 UTC + time_t epoch = make_utc(2099, 12, 31, 23, 59, 59); + ASSERT_TRUE(epoch_to_local_tm(epoch, tz, &local)); + EXPECT_EQ(local.tm_year, 199); // 2099 + EXPECT_EQ(local.tm_mon, 11); // December + EXPECT_EQ(local.tm_mday, 31); + + // Jan 1, 2100 00:00:00 UTC + epoch = make_utc(2100, 1, 1); + ASSERT_TRUE(epoch_to_local_tm(epoch, tz, &local)); + EXPECT_EQ(local.tm_year, 200); // 2100 + EXPECT_EQ(local.tm_mon, 0); // January + EXPECT_EQ(local.tm_mday, 1); +} + +TEST(PosixTz, EpochToLocalDstAcrossCenturyBoundary) { + // DST transition in year 2100 (non-leap) with US Eastern rules + ParsedTimezone tz = make_us_eastern(); + + // July 4, 2100 16:00 UTC = 12:00 EDT + time_t epoch = make_utc(2100, 7, 4, 16); + struct tm local; + ASSERT_TRUE(epoch_to_local_tm(epoch, tz, &local)); + EXPECT_EQ(local.tm_hour, 12); + EXPECT_EQ(local.tm_isdst, 1); + + // Jan 15, 2100 10:00 UTC = 05:00 EST + epoch = make_utc(2100, 1, 15, 10); + ASSERT_TRUE(epoch_to_local_tm(epoch, tz, &local)); + EXPECT_EQ(local.tm_hour, 5); + EXPECT_EQ(local.tm_isdst, 0); +} + +TEST(PosixTz, EpochToLocalFarFutureYear5000) { + // Year 5000 — days/365 estimate overshoots by ~2 years due to leap days, + // requiring multiple correction steps in days_to_year. + ParsedTimezone tz{}; // UTC + + time_t epoch = make_utc(5000, 6, 15, 12); + struct tm local; + ASSERT_TRUE(epoch_to_local_tm(epoch, tz, &local)); + EXPECT_EQ(local.tm_year, 3100); // 5000 + EXPECT_EQ(local.tm_mon, 5); // June + EXPECT_EQ(local.tm_mday, 15); + EXPECT_EQ(local.tm_hour, 12); +} + +// ============================================================================ +// Verification against libc +// ============================================================================ + +// Helper to build the <+07>-7 timezone (UTC+7, no DST) +static ParsedTimezone make_plus_seven() { + ParsedTimezone tz{}; + tz.std_offset_seconds = -7 * 3600; + return tz; +} + +// Helper to build the India timezone (IST-5:30, no DST) +static ParsedTimezone make_india() { + ParsedTimezone tz{}; + tz.std_offset_seconds = -(5 * 3600 + 30 * 60); + return tz; +} + +// Helper to build the Europe/Berlin timezone (CET-1CEST,M3.5.0,M10.5.0/3) +static ParsedTimezone make_europe_berlin() { + ParsedTimezone tz{}; + tz.std_offset_seconds = -1 * 3600; + tz.dst_offset_seconds = -2 * 3600; + tz.dst_start.type = DSTRuleType::MONTH_WEEK_DAY; + tz.dst_start.month = 3; + tz.dst_start.week = 5; + tz.dst_start.day_of_week = 0; + tz.dst_start.time_seconds = 2 * 3600; + tz.dst_end.type = DSTRuleType::MONTH_WEEK_DAY; + tz.dst_end.month = 10; + tz.dst_end.week = 5; + tz.dst_end.day_of_week = 0; + tz.dst_end.time_seconds = 3 * 3600; + return tz; +} + +// Compares our converter against libc for the same zone: the struct drives +// epoch_to_local_tm() and the equivalent POSIX TZ string drives libc localtime(). +using LibcVerificationParam = std::tuple; + +class LibcVerificationTest : public ::testing::TestWithParam { + protected: + // NOLINTNEXTLINE(readability-identifier-naming) - Google Test requires this name + void SetUp() override { + // Save current TZ + const char *current_tz = getenv("TZ"); + saved_tz_ = current_tz ? current_tz : ""; + had_tz_ = current_tz != nullptr; + } + + // NOLINTNEXTLINE(readability-identifier-naming) - Google Test requires this name + void TearDown() override { + // Restore TZ + if (had_tz_) { + setenv("TZ", saved_tz_.c_str(), 1); + } else { + unsetenv("TZ"); + } + tzset(); + } + + private: + std::string saved_tz_; + bool had_tz_{false}; +}; + +TEST_P(LibcVerificationTest, MatchesLibc) { + auto [make_tz, tz_str, epoch] = GetParam(); + + ParsedTimezone tz = make_tz(); + + // Our implementation + struct tm our_tm {}; + ASSERT_TRUE(epoch_to_local_tm(epoch, tz, &our_tm)); + + // libc implementation + setenv("TZ", tz_str, 1); + tzset(); + struct tm *libc_tm = localtime(&epoch); + ASSERT_NE(libc_tm, nullptr); + + EXPECT_EQ(our_tm.tm_year, libc_tm->tm_year); + EXPECT_EQ(our_tm.tm_mon, libc_tm->tm_mon); + EXPECT_EQ(our_tm.tm_mday, libc_tm->tm_mday); + EXPECT_EQ(our_tm.tm_hour, libc_tm->tm_hour); + EXPECT_EQ(our_tm.tm_min, libc_tm->tm_min); + EXPECT_EQ(our_tm.tm_sec, libc_tm->tm_sec); + EXPECT_EQ(our_tm.tm_isdst, libc_tm->tm_isdst); +} + +INSTANTIATE_TEST_SUITE_P(USEastern, LibcVerificationTest, + ::testing::Values(std::make_tuple(&make_us_eastern, "EST5EDT,M3.2.0/2,M11.1.0/2", 1704067200), + std::make_tuple(&make_us_eastern, "EST5EDT,M3.2.0/2,M11.1.0/2", 1720000000), + std::make_tuple(&make_us_eastern, "EST5EDT,M3.2.0/2,M11.1.0/2", + 1735689600))); + +INSTANTIATE_TEST_SUITE_P(AngleBracket, LibcVerificationTest, + ::testing::Values(std::make_tuple(&make_plus_seven, "<+07>-7", 1704067200), + std::make_tuple(&make_plus_seven, "<+07>-7", 1720000000))); + +INSTANTIATE_TEST_SUITE_P(India, LibcVerificationTest, + ::testing::Values(std::make_tuple(&make_india, "IST-5:30", 1704067200), + std::make_tuple(&make_india, "IST-5:30", 1720000000))); + +INSTANTIATE_TEST_SUITE_P( + NewZealand, LibcVerificationTest, + ::testing::Values(std::make_tuple(&make_new_zealand, "NZST-12NZDT,M9.5.0,M4.1.0/3", 1704067200), + std::make_tuple(&make_new_zealand, "NZST-12NZDT,M9.5.0,M4.1.0/3", 1720000000))); + +INSTANTIATE_TEST_SUITE_P(USCentral, LibcVerificationTest, + ::testing::Values(std::make_tuple(&make_us_central, "CST6CDT,M3.2.0/2,M11.1.0/2", 1704067200), + std::make_tuple(&make_us_central, "CST6CDT,M3.2.0/2,M11.1.0/2", 1720000000), + std::make_tuple(&make_us_central, "CST6CDT,M3.2.0/2,M11.1.0/2", + 1735689600))); + +INSTANTIATE_TEST_SUITE_P( + EuropeBerlin, LibcVerificationTest, + ::testing::Values(std::make_tuple(&make_europe_berlin, "CET-1CEST,M3.5.0,M10.5.0/3", 1704067200), + std::make_tuple(&make_europe_berlin, "CET-1CEST,M3.5.0,M10.5.0/3", 1720000000), + std::make_tuple(&make_europe_berlin, "CET-1CEST,M3.5.0,M10.5.0/3", 1735689600))); + +INSTANTIATE_TEST_SUITE_P( + AustraliaSydney, LibcVerificationTest, + ::testing::Values(std::make_tuple(&make_australia_sydney, "AEST-10AEDT,M10.1.0,M4.1.0/3", 1704067200), + std::make_tuple(&make_australia_sydney, "AEST-10AEDT,M10.1.0,M4.1.0/3", 1720000000), + std::make_tuple(&make_australia_sydney, "AEST-10AEDT,M10.1.0,M4.1.0/3", 1735689600))); + +} // namespace esphome::time::testing diff --git a/tests/components/time/test.host.yaml b/tests/components/time/test.host.yaml new file mode 100644 index 0000000000..f6bec9fd1d --- /dev/null +++ b/tests/components/time/test.host.yaml @@ -0,0 +1,10 @@ +network: + +api: + +time: + - platform: homeassistant + # Angle-bracket name pins the explicit-timezone host codegen path + # (setenv/tzset plus pre-parsed struct emission) with characters that + # would break unescaped string interpolation. + timezone: "<+07>-7" diff --git a/tests/integration/fixtures/api_get_time_response_timezone.yaml b/tests/integration/fixtures/api_get_time_response_timezone.yaml new file mode 100644 index 0000000000..bece0c5684 --- /dev/null +++ b/tests/integration/fixtures/api_get_time_response_timezone.yaml @@ -0,0 +1,20 @@ +esphome: + name: get-time-tz-test +host: +api: +logger: + +time: + - platform: homeassistant + id: ha_time + +sensor: + # Exposes the standard offset of the effective timezone so the test can + # observe which GetTimeResponse messages changed it + - platform: template + name: "TZ Offset" + id: tz_offset + accuracy_decimals: 0 + update_interval: 100ms + lambda: |- + return time::get_global_tz().std_offset_seconds; diff --git a/tests/integration/test_api_get_time_response_timezone.py b/tests/integration/test_api_get_time_response_timezone.py new file mode 100644 index 0000000000..c90380607f --- /dev/null +++ b/tests/integration/test_api_get_time_response_timezone.py @@ -0,0 +1,67 @@ +"""Integration test for GetTimeResponse parsed_timezone presence handling.""" + +from __future__ import annotations + +from aioesphomeapi import connection as api_connection +from aioesphomeapi.api_pb2 import GetTimeResponse +import pytest + +from .state_utils import SensorTracker, build_key_to_entity_mapping +from .types import APIClientConnectedFactory, RunCompiledFunction + +# 2024-01-01 00:00:00 UTC +EPOCH = 1704067200 +# POSIX offsets are positive west of UTC, so UTC+7 is -25200 and UTC-5 is 18000 +UTC_PLUS_7 = -25200 +UTC_MINUS_5 = 18000 + + +@pytest.mark.asyncio +async def test_api_get_time_response_timezone( + yaml_config: str, + run_compiled: RunCompiledFunction, + api_client_connected: APIClientConnectedFactory, + monkeypatch: pytest.MonkeyPatch, +) -> None: + """A present parsed_timezone is applied even when all zero; an absent one is ignored.""" + # The client answers the device's own GetTimeRequest with the host timezone; + # strip the parsed field from that reply so only the messages sent below + # can change the device timezone. + monkeypatch.setattr(api_connection, "_build_parsed_tz_proto", lambda tz: None) + + async with run_compiled(yaml_config), api_client_connected() as client: + entities, _ = await client.list_entities_services() + tracker = SensorTracker(["tz_offset"]) + tracker.key_to_sensor = build_key_to_entity_mapping(entities, ["tz_offset"]) + client.subscribe_states(tracker.on_state) + + await tracker.await_change(tracker.expect_any("tz_offset"), "tz_offset") + initial = tracker.sensor_states["tz_offset"][-1] + # Pick a zone that differs from the codegen default so the change is visible + target = UTC_PLUS_7 if initial != UTC_PLUS_7 else UTC_MINUS_5 + + # Present, non-zero: applied + future = tracker.expect("tz_offset", target) + resp = GetTimeResponse(epoch_seconds=EPOCH) + resp.parsed_timezone.std_offset_seconds = target + resp.parsed_timezone.dst_offset_seconds = target + client._connection.send_messages((resp,)) + await tracker.await_change(future, "tz_offset") + + # Absent (legacy client with only the deprecated string): ignored, and in + # particular not mistaken for an all-zero UTC zone + future = tracker.expect("tz_offset", 0) + resp = GetTimeResponse(epoch_seconds=EPOCH, timezone="UTC0") + client._connection.send_messages((resp,)) + await tracker.await_must_not_change(future, "tz_offset", timeout=1.0) + assert tracker.sensor_states["tz_offset"][-1] == target + # Retire the expectation so it cannot swallow the first matching state + # meant for the next phase + future.cancel() + + # Present but all zero (genuine UTC): applied + future = tracker.expect("tz_offset", 0) + resp = GetTimeResponse(epoch_seconds=EPOCH) + resp.parsed_timezone.SetInParent() + client._connection.send_messages((resp,)) + await tracker.await_change(future, "tz_offset") From de1361ac0e2777a13ec7275ca014da890da2f626 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Mon, 24 Aug 2026 13:50:27 +1200 Subject: [PATCH 10/10] [core] Add type annotations to component Python (#18697) Co-authored-by: J. Nick Koston --- esphome/components/a01nyub/sensor.py | 3 ++- esphome/components/a02yyuw/sensor.py | 3 ++- esphome/components/a4988/stepper.py | 3 ++- esphome/components/absolute_humidity/sensor.py | 3 ++- esphome/components/ac_dimmer/output.py | 3 ++- esphome/components/adalight/__init__.py | 5 ++++- esphome/components/adc128s102/__init__.py | 3 ++- esphome/components/adc128s102/sensor/__init__.py | 3 ++- esphome/components/addressable_light/display.py | 3 ++- esphome/components/ade7880/sensor.py | 7 ++++--- esphome/components/ade7953_base/__init__.py | 4 +++- esphome/components/ade7953_i2c/sensor.py | 3 ++- esphome/components/ade7953_spi/sensor.py | 3 ++- esphome/components/ads1115/__init__.py | 3 ++- esphome/components/ads1115/sensor/__init__.py | 3 ++- esphome/components/ads1118/__init__.py | 3 ++- esphome/components/ads1118/sensor/__init__.py | 3 ++- esphome/components/aht10/sensor.py | 3 ++- esphome/components/airthings_ble/__init__.py | 3 ++- esphome/components/airthings_wave_base/__init__.py | 4 +++- esphome/components/airthings_wave_mini/sensor.py | 3 ++- esphome/components/airthings_wave_plus/sensor.py | 2 +- esphome/components/alpha3/sensor.py | 3 ++- esphome/components/am2315c/sensor.py | 3 ++- esphome/components/am2320/sensor.py | 3 ++- esphome/components/am43/cover/__init__.py | 3 ++- esphome/components/am43/sensor/__init__.py | 3 ++- esphome/components/analog_threshold/binary_sensor.py | 3 ++- esphome/components/anova/climate.py | 3 ++- esphome/components/apds9306/sensor.py | 8 ++++++-- esphome/components/aqi/sensor.py | 5 +++-- esphome/components/as3935_i2c/__init__.py | 3 ++- esphome/components/as3935_spi/__init__.py | 3 ++- esphome/components/as7341/sensor.py | 3 ++- esphome/components/async_tcp/__init__.py | 3 ++- esphome/components/atc_mithermometer/sensor.py | 3 ++- esphome/components/atm90e26/sensor.py | 3 ++- esphome/components/axs15231/touchscreen/__init__.py | 3 ++- esphome/components/b_parasite/sensor.py | 3 ++- esphome/components/ballu/climate.py | 3 ++- esphome/components/bang_bang/climate.py | 3 ++- esphome/components/beken_spi_led_strip/light.py | 2 +- esphome/components/bh1750/sensor.py | 3 ++- esphome/components/bh1900nux/sensor.py | 3 ++- esphome/components/binary/fan/__init__.py | 3 ++- esphome/components/binary/light/__init__.py | 3 ++- esphome/components/binary_sensor_map/sensor.py | 3 ++- esphome/components/bk72xx/__init__.py | 8 +++++--- esphome/components/bl0939/sensor.py | 3 ++- esphome/components/bl0942/sensor.py | 3 ++- esphome/components/ble_device_base/automation.py | 7 ++++--- esphome/components/ble_presence/binary_sensor.py | 5 +++-- esphome/components/ble_rssi/sensor.py | 5 +++-- esphome/components/ble_scanner/text_sensor.py | 3 ++- esphome/components/bluetooth_proxy/__init__.py | 2 +- esphome/components/bme280_base/__init__.py | 4 +++- esphome/components/bme280_i2c/sensor.py | 3 ++- esphome/components/bme280_spi/sensor.py | 3 ++- esphome/components/bme680/sensor.py | 3 ++- esphome/components/bme68x_bsec2_i2c/__init__.py | 3 ++- esphome/components/bmi160/sensor.py | 3 ++- esphome/components/bmi270/motion.py | 3 ++- esphome/components/bmi270/sensor.py | 3 ++- esphome/components/bmp085/sensor.py | 3 ++- esphome/components/bmp280_base/__init__.py | 4 +++- esphome/components/bmp280_i2c/sensor.py | 3 ++- esphome/components/bmp280_spi/sensor.py | 3 ++- esphome/components/bmp3xx_base/__init__.py | 4 +++- esphome/components/bmp3xx_i2c/sensor.py | 3 ++- esphome/components/bmp3xx_spi/sensor.py | 3 ++- esphome/components/bmp581_base/__init__.py | 6 ++++-- esphome/components/bmp581_i2c/sensor.py | 3 ++- esphome/components/bmp581_spi/sensor.py | 5 +++-- esphome/components/bp1658cj/__init__.py | 3 ++- esphome/components/bp1658cj/output.py | 3 ++- esphome/components/bp5758d/__init__.py | 3 ++- esphome/components/bp5758d/output.py | 3 ++- esphome/components/cap1188/__init__.py | 3 ++- esphome/components/cap1188/binary_sensor.py | 3 ++- esphome/components/captive_portal/__init__.py | 2 +- esphome/components/ccs811/sensor.py | 3 ++- esphome/components/cd74hc4067/__init__.py | 3 ++- esphome/components/cd74hc4067/sensor.py | 3 ++- esphome/components/ch422g/__init__.py | 8 +++++--- esphome/components/ch423/__init__.py | 8 +++++--- esphome/components/chsc6x/touchscreen.py | 3 ++- esphome/components/climate_ir/__init__.py | 7 ++++--- esphome/components/climate_ir_lg/climate.py | 3 ++- esphome/components/color_temperature/light.py | 3 ++- esphome/components/combination/sensor.py | 5 +++-- esphome/components/coolix/climate.py | 3 ++- esphome/components/cse7761/sensor.py | 3 ++- esphome/components/cse7766/sensor.py | 3 ++- esphome/components/cst226/binary_sensor/__init__.py | 3 ++- esphome/components/cst226/touchscreen/__init__.py | 3 ++- esphome/components/cst328/binary_sensor/__init__.py | 3 ++- esphome/components/cst328/touchscreen/__init__.py | 3 ++- esphome/components/cst816/touchscreen/__init__.py | 3 ++- esphome/components/cst9220/touchscreen/__init__.py | 3 ++- esphome/components/ct_clamp/sensor.py | 3 ++- esphome/components/current_based/cover.py | 3 ++- esphome/components/cwww/light.py | 3 ++- esphome/components/dac7678/__init__.py | 4 +++- esphome/components/dac7678/output.py | 4 +++- esphome/components/daikin/climate.py | 3 ++- esphome/components/daikin_arc/climate.py | 3 ++- esphome/components/daikin_brc/climate.py | 3 ++- esphome/components/dallas_temp/sensor.py | 3 ++- esphome/components/delonghi/climate.py | 3 ++- esphome/components/demo/__init__.py | 3 ++- esphome/components/dew_point/sensor.py | 3 ++- esphome/components/dht/sensor.py | 3 ++- esphome/components/dht12/sensor.py | 3 ++- esphome/components/dps310/sensor.py | 3 ++- esphome/components/ds2484/one_wire.py | 3 ++- esphome/components/dsmr/__init__.py | 2 +- esphome/components/dsmr/sensor.py | 3 ++- esphome/components/dsmr/text_sensor.py | 3 ++- esphome/components/duty_cycle/sensor.py | 3 ++- esphome/components/e131/__init__.py | 7 +++++-- esphome/components/ee895/sensor.py | 3 ++- esphome/components/ektf2232/touchscreen/__init__.py | 3 ++- esphome/components/emmeti/climate.py | 3 ++- esphome/components/endstop/cover.py | 3 ++- esphome/components/ens160_base/__init__.py | 4 +++- esphome/components/ens160_i2c/sensor.py | 3 ++- esphome/components/ens160_spi/sensor.py | 3 ++- esphome/components/ens210/sensor.py | 3 ++- esphome/components/es7210/audio_adc.py | 3 ++- esphome/components/es7243e/audio_adc.py | 3 ++- esphome/components/es8156/audio_dac.py | 5 +++-- esphome/components/es8311/audio_dac.py | 3 ++- esphome/components/es8388/audio_dac.py | 3 ++- esphome/components/es8388/select/__init__.py | 3 ++- esphome/components/esp32_ble_beacon/__init__.py | 5 +++-- esphome/components/esp32_camera/__init__.py | 8 +++++--- esphome/components/esp32_camera_web_server/__init__.py | 2 +- esphome/components/esp32_can/canbus.py | 8 +++++--- esphome/components/esp32_dac/output.py | 5 +++-- esphome/components/esp32_improv/__init__.py | 3 ++- esphome/components/esphome/ota/__init__.py | 2 +- esphome/components/ethernet_info/text_sensor.py | 3 ++- esphome/components/exposure_notifications/__init__.py | 2 +- esphome/components/ezo/sensor.py | 3 ++- esphome/components/fastled_base/__init__.py | 4 +++- esphome/components/fastled_clockless/light.py | 5 +++-- esphome/components/fastled_spi/light.py | 3 ++- esphome/components/feedback/cover.py | 5 +++-- esphome/components/fs3000/sensor.py | 3 ++- esphome/components/ft5x06/touchscreen/__init__.py | 3 ++- esphome/components/ft63x6/touchscreen.py | 3 ++- esphome/components/fujitsu_general/climate.py | 3 ++- esphome/components/gcja5/sensor.py | 3 ++- esphome/components/gl_r01_i2c/sensor.py | 3 ++- esphome/components/gp2y1010au0f/sensor.py | 3 ++- esphome/components/gp8403/__init__.py | 3 ++- esphome/components/gp8403/output/__init__.py | 3 ++- esphome/components/gps/__init__.py | 3 ++- esphome/components/gps/time/__init__.py | 3 ++- esphome/components/graphical_display_menu/__init__.py | 3 ++- esphome/components/gree/climate.py | 3 ++- esphome/components/gree/switch/__init__.py | 5 +++-- esphome/components/grove_gas_mc_v2/sensor.py | 3 ++- esphome/components/growatt_solar/sensor.py | 2 +- esphome/components/gsl3670/touchscreen.py | 6 +++--- esphome/components/gt911/binary_sensor/__init__.py | 3 ++- esphome/components/gt911/touchscreen/__init__.py | 3 ++- esphome/components/havells_solar/sensor.py | 2 +- esphome/components/hdc1080/sensor.py | 3 ++- esphome/components/hdc2010/sensor.py | 3 ++- esphome/components/hdc2080/sensor.py | 3 ++- esphome/components/he60r/cover.py | 3 ++- esphome/components/heatpumpir/climate.py | 2 +- esphome/components/hitachi_ac344/climate.py | 3 ++- esphome/components/hitachi_ac424/climate.py | 3 ++- esphome/components/hlw8012/sensor.py | 3 ++- esphome/components/hlw8032/sensor.py | 3 ++- esphome/components/hm3301/sensor.py | 5 +++-- esphome/components/honeywell_hih_i2c/sensor.py | 3 ++- esphome/components/honeywellabp/sensor.py | 3 ++- esphome/components/honeywellabp2_i2c/sensor.py | 3 ++- esphome/components/hrxl_maxsonar_wr/sensor.py | 3 ++- esphome/components/hte501/sensor.py | 3 ++- esphome/components/htu31d/sensor.py | 3 ++- esphome/components/hub75/boards/__init__.py | 2 +- esphome/components/hub75/display.py | 4 ++-- esphome/components/hx711/sensor.py | 3 ++- esphome/components/hydreon_rgxx/binary_sensor.py | 3 ++- esphome/components/hydreon_rgxx/sensor.py | 5 +++-- esphome/components/hyt271/sensor.py | 3 ++- esphome/components/i2c_device/__init__.py | 3 ++- esphome/components/iaqcore/sensor.py | 3 ++- esphome/components/improv_base/__init__.py | 7 ++++--- esphome/components/improv_serial/__init__.py | 5 +++-- esphome/components/ina219/sensor.py | 3 ++- esphome/components/ina226/sensor.py | 7 +++++-- esphome/components/ina260/sensor.py | 3 ++- esphome/components/ina2xx_i2c/sensor.py | 3 ++- esphome/components/ina2xx_spi/sensor.py | 3 ++- esphome/components/ina3221/sensor.py | 3 ++- esphome/components/infrared/__init__.py | 8 ++++---- esphome/components/inkbird_ibsth1_mini/sensor.py | 3 ++- esphome/components/inkplate/display.py | 7 ++++--- esphome/components/internal_temperature/sensor.py | 3 ++- esphome/components/interval/__init__.py | 3 ++- esphome/components/jsn_sr04t/sensor.py | 3 ++- esphome/components/json/__init__.py | 3 ++- esphome/components/kamstrup_kmp/sensor.py | 3 ++- esphome/components/kmeteriso/sensor.py | 3 ++- esphome/components/kuntze/sensor.py | 2 +- esphome/components/lc709203f/sensor.py | 3 ++- esphome/components/lcd_gpio/display.py | 5 +++-- esphome/components/lcd_menu/__init__.py | 5 +++-- esphome/components/lcd_pcf8574/display.py | 3 ++- esphome/components/lilygo_t5_47/touchscreen/__init__.py | 3 ++- esphome/components/lm75b/sensor.py | 3 ++- esphome/components/ln882x/__init__.py | 8 +++++--- esphome/components/lps22/sensor.py | 3 ++- esphome/components/lsm6ds/motion.py | 3 ++- esphome/components/lsm6ds/sensor.py | 3 ++- esphome/components/ltr390/sensor.py | 3 ++- esphome/components/max31855/sensor.py | 3 ++- esphome/components/max31856/sensor.py | 3 ++- esphome/components/max31865/sensor.py | 3 ++- esphome/components/max44009/sensor.py | 3 ++- esphome/components/max6675/sensor.py | 3 ++- esphome/components/max7219/display.py | 3 ++- esphome/components/max9611/sensor.py | 3 ++- esphome/components/mcp23008/__init__.py | 3 ++- esphome/components/mcp23016/__init__.py | 8 +++++--- esphome/components/mcp23017/__init__.py | 3 ++- esphome/components/mcp23s08/__init__.py | 3 ++- esphome/components/mcp23s17/__init__.py | 3 ++- esphome/components/mcp2515/canbus.py | 3 ++- esphome/components/mcp3008/__init__.py | 3 ++- esphome/components/mcp3008/sensor/__init__.py | 3 ++- esphome/components/mcp3204/__init__.py | 3 ++- esphome/components/mcp3204/sensor/__init__.py | 3 ++- esphome/components/mcp3221/sensor.py | 3 ++- esphome/components/mcp4725/output.py | 3 ++- esphome/components/mcp4728/__init__.py | 3 ++- esphome/components/mcp4728/output/__init__.py | 3 ++- esphome/components/mcp47a1/output.py | 3 ++- esphome/components/mcp9600/sensor.py | 3 ++- esphome/components/mcp9808/sensor.py | 3 ++- esphome/components/md5/__init__.py | 3 ++- esphome/components/mdns/__init__.py | 8 ++++---- esphome/components/media_source/__init__.py | 7 ++++--- esphome/components/mics_4514/sensor.py | 3 ++- esphome/components/midea_ir/climate.py | 3 ++- esphome/components/mitsubishi/climate.py | 3 ++- esphome/components/mlx90393/sensor.py | 7 ++++--- esphome/components/mlx90614/sensor.py | 3 ++- esphome/components/mmc5603/sensor.py | 6 ++++-- esphome/components/mmc5983/sensor.py | 3 ++- esphome/components/modbus_server/__init__.py | 2 +- esphome/components/monochromatic/light.py | 3 ++- esphome/components/mopeka_ble/__init__.py | 3 ++- esphome/components/mopeka_pro_check/sensor.py | 7 +++++-- esphome/components/mopeka_std_check/sensor.py | 7 +++++-- esphome/components/mpl3115a2/sensor.py | 3 ++- esphome/components/mpu6050/sensor.py | 3 ++- esphome/components/mpu6886/sensor.py | 3 ++- esphome/components/mqtt_subscribe/sensor/__init__.py | 3 ++- esphome/components/mqtt_subscribe/text_sensor/__init__.py | 3 ++- esphome/components/ms5611/sensor.py | 3 ++- esphome/components/ms8607/sensor.py | 3 ++- esphome/components/my9231/__init__.py | 3 ++- esphome/components/my9231/output.py | 3 ++- esphome/components/network/__init__.py | 2 +- esphome/components/nfc/binary_sensor/__init__.py | 7 +++++-- esphome/components/noblex/climate.py | 3 ++- esphome/components/npi19/sensor.py | 3 ++- esphome/components/one_wire/__init__.py | 6 ++++-- esphome/components/opt3001/sensor.py | 3 ++- esphome/components/packages/__init__.py | 6 +++--- esphome/components/partition/light.py | 7 ++++--- esphome/components/pca6416a/__init__.py | 8 +++++--- esphome/components/pca9685/__init__.py | 5 +++-- esphome/components/pca9685/output.py | 3 ++- esphome/components/pcd8544/display.py | 3 ++- esphome/components/pcf8574/__init__.py | 8 +++++--- esphome/components/pi4ioe5v6408/__init__.py | 8 +++++--- esphome/components/pm1006/sensor.py | 5 +++-- esphome/components/pm2005/sensor.py | 3 ++- esphome/components/pmsa003i/sensor.py | 3 ++- esphome/components/pn532_i2c/__init__.py | 3 ++- esphome/components/pn532_spi/__init__.py | 3 ++- esphome/components/pn7150_i2c/__init__.py | 3 ++- esphome/components/pn7160_i2c/__init__.py | 3 ++- esphome/components/pn7160_spi/__init__.py | 3 ++- esphome/components/power_supply/__init__.py | 3 ++- esphome/components/preferences/__init__.py | 3 ++- esphome/components/prometheus/__init__.py | 3 ++- esphome/components/psram/__init__.py | 6 +++--- esphome/components/pulse_width/sensor.py | 3 ++- esphome/components/pvvx_mithermometer/display/__init__.py | 3 ++- esphome/components/pvvx_mithermometer/sensor.py | 3 ++- esphome/components/pzem004t/sensor.py | 3 ++- esphome/components/qmi8658/motion.py | 3 ++- esphome/components/qmi8658/sensor.py | 3 ++- esphome/components/qmp6988/sensor.py | 3 ++- esphome/components/qr_code/__init__.py | 3 ++- esphome/components/qwiic_pir/binary_sensor.py | 5 +++-- esphome/components/radio_frequency/__init__.py | 8 ++++---- esphome/components/radon_eye_ble/__init__.py | 3 ++- esphome/components/radon_eye_rd200/sensor.py | 3 ++- esphome/components/rc522_i2c/__init__.py | 3 ++- esphome/components/rc522_spi/__init__.py | 3 ++- esphome/components/rc522_spi/binary_sensor.py | 3 ++- esphome/components/rdm6300/__init__.py | 3 ++- esphome/components/rdm6300/binary_sensor.py | 3 ++- esphome/components/resistance/sensor.py | 3 ++- esphome/components/restart/button/__init__.py | 3 ++- esphome/components/restart/switch/__init__.py | 3 ++- esphome/components/rgb/light.py | 3 ++- esphome/components/rgbct/light.py | 3 ++- esphome/components/rgbw/light.py | 3 ++- esphome/components/rgbww/light.py | 3 ++- esphome/components/rp2_pio/__init__.py | 3 ++- esphome/components/rtl87xx/__init__.py | 8 +++++--- esphome/components/runtime_image/__init__.py | 8 ++++---- esphome/components/runtime_stats/__init__.py | 3 ++- esphome/components/ruuvi_ble/__init__.py | 3 ++- esphome/components/ruuvitag/sensor.py | 3 ++- esphome/components/sdm_meter/sensor.py | 2 +- esphome/components/sdp3x/sensor.py | 3 ++- esphome/components/sds011/sensor.py | 7 ++++--- esphome/components/selec_meter/sensor.py | 2 +- esphome/components/sen0321/sensor.py | 3 ++- esphome/components/sen21231/sensor.py | 3 ++- esphome/components/sen6x/sensor.py | 3 ++- esphome/components/serial_proxy/__init__.py | 5 +++-- esphome/components/sfa30/sensor.py | 3 ++- esphome/components/sgp30/sensor.py | 3 ++- esphome/components/sgp4x/sensor.py | 7 ++++--- esphome/components/sht3xd/sensor.py | 3 ++- esphome/components/sht4x/sensor.py | 3 ++- esphome/components/shtcx/sensor.py | 3 ++- esphome/components/shutdown/button/__init__.py | 3 ++- esphome/components/shutdown/switch/__init__.py | 3 ++- esphome/components/sigma_delta_output/output.py | 3 ++- esphome/components/slow_pwm/output.py | 3 ++- esphome/components/sm10bit_base/__init__.py | 4 +++- esphome/components/sm16716/__init__.py | 3 ++- esphome/components/sm16716/output.py | 3 ++- esphome/components/sm2135/__init__.py | 3 ++- esphome/components/sm2135/output.py | 3 ++- esphome/components/sm2235/__init__.py | 3 ++- esphome/components/sm2235/output.py | 3 ++- esphome/components/sm2335/__init__.py | 3 ++- esphome/components/sm2335/output.py | 3 ++- esphome/components/sm300d2/sensor.py | 3 ++- esphome/components/smt100/sensor.py | 3 ++- esphome/components/sntp/time.py | 2 +- esphome/components/socket/__init__.py | 3 ++- esphome/components/sonoff_d1/light.py | 3 ++- esphome/components/spa06_i2c/sensor.py | 3 ++- esphome/components/spa06_spi/sensor.py | 5 +++-- esphome/components/speed/fan/__init__.py | 3 ++- esphome/components/spi_device/__init__.py | 3 ++- esphome/components/spi_led_strip/light.py | 3 ++- esphome/components/ssd1306_base/__init__.py | 6 ++++-- esphome/components/ssd1306_i2c/display.py | 3 ++- esphome/components/ssd1306_spi/display.py | 3 ++- esphome/components/ssd1322_base/__init__.py | 4 +++- esphome/components/ssd1322_spi/display.py | 3 ++- esphome/components/ssd1325_base/__init__.py | 4 +++- esphome/components/ssd1325_spi/display.py | 3 ++- esphome/components/ssd1327_base/__init__.py | 4 +++- esphome/components/ssd1327_i2c/display.py | 3 ++- esphome/components/ssd1327_spi/display.py | 3 ++- esphome/components/ssd1331_base/__init__.py | 4 +++- esphome/components/ssd1331_spi/display.py | 3 ++- esphome/components/ssd1351_base/__init__.py | 4 +++- esphome/components/ssd1351_spi/display.py | 3 ++- esphome/components/st7123/touchscreen/__init__.py | 3 ++- esphome/components/st7567_base/__init__.py | 4 +++- esphome/components/st7567_i2c/display.py | 3 ++- esphome/components/st7567_spi/display.py | 3 ++- esphome/components/st7735/display.py | 6 ++++-- esphome/components/st7920/display.py | 3 ++- esphome/components/statsd/__init__.py | 3 ++- esphome/components/status/binary_sensor.py | 3 ++- esphome/components/status_led/__init__.py | 3 ++- esphome/components/status_led/light/__init__.py | 3 ++- esphome/components/sts3x/sensor.py | 3 ++- esphome/components/stts22h/sensor.py | 3 ++- esphome/components/sx126x/packet_transport/__init__.py | 3 ++- esphome/components/syslog/__init__.py | 3 ++- esphome/components/t6615/sensor.py | 3 ++- esphome/components/tc74/sensor.py | 3 ++- esphome/components/tca9548a/__init__.py | 3 ++- esphome/components/tca9555/__init__.py | 8 +++++--- esphome/components/tcl112/climate.py | 3 ++- esphome/components/tcs34725/sensor.py | 3 ++- esphome/components/tee501/sensor.py | 3 ++- esphome/components/tem3200/sensor.py | 3 ++- esphome/components/thermopro_ble/sensor.py | 3 ++- esphome/components/time_based/cover/__init__.py | 3 ++- esphome/components/tinyusb/__init__.py | 5 +++-- esphome/components/tlc59208f/__init__.py | 3 ++- esphome/components/tlc59208f/output.py | 3 ++- esphome/components/tlc5947/__init__.py | 3 ++- esphome/components/tlc5947/output/__init__.py | 3 ++- esphome/components/tlc5971/__init__.py | 3 ++- esphome/components/tlc5971/output/__init__.py | 3 ++- esphome/components/tm1621/display.py | 3 ++- esphome/components/tm1637/binary_sensor.py | 3 ++- esphome/components/tm1637/display.py | 3 ++- esphome/components/tmp102/sensor.py | 3 ++- esphome/components/tmp1075/sensor.py | 3 ++- esphome/components/tmp117/sensor.py | 5 +++-- esphome/components/tof10120/sensor.py | 3 ++- esphome/components/tormatic/cover.py | 3 ++- esphome/components/toshiba/climate.py | 3 ++- esphome/components/total_daily_energy/sensor.py | 7 ++++--- esphome/components/tsl2561/sensor.py | 8 ++++++-- esphome/components/tsl2591/sensor.py | 8 ++++++-- esphome/components/tt21100/binary_sensor/__init__.py | 3 ++- esphome/components/tt21100/touchscreen/__init__.py | 3 ++- esphome/components/ttp229_bsf/__init__.py | 3 ++- esphome/components/ttp229_bsf/binary_sensor.py | 3 ++- esphome/components/ttp229_lsf/__init__.py | 3 ++- esphome/components/ttp229_lsf/binary_sensor.py | 3 ++- esphome/components/tx20/sensor.py | 3 ++- esphome/components/uln2003/stepper.py | 3 ++- esphome/components/ultrasonic/sensor.py | 3 ++- esphome/components/uptime/sensor/__init__.py | 3 ++- esphome/components/uptime/text_sensor/__init__.py | 3 ++- esphome/components/usb_host/__init__.py | 7 +++++-- esphome/components/veml3235/sensor.py | 5 +++-- esphome/components/veml7700/sensor.py | 8 ++++++-- esphome/components/version/text_sensor.py | 3 ++- esphome/components/wake_on_lan/button.py | 5 +++-- esphome/components/waveshare_epaper/display.py | 7 ++++--- esphome/components/web_server_base/__init__.py | 7 ++++--- esphome/components/web_server_idf/__init__.py | 3 ++- esphome/components/whirlpool/climate.py | 3 ++- esphome/components/whynter/climate.py | 3 ++- esphome/components/wiegand/__init__.py | 3 ++- esphome/components/wifi_info/text_sensor.py | 5 +++-- esphome/components/wifi_signal/sensor.py | 3 ++- esphome/components/wk2132_i2c/__init__.py | 3 ++- esphome/components/wk2132_spi/__init__.py | 3 ++- esphome/components/wk2168_i2c/__init__.py | 6 ++++-- esphome/components/wk2168_spi/__init__.py | 6 ++++-- esphome/components/wk2204_i2c/__init__.py | 3 ++- esphome/components/wk2204_spi/__init__.py | 3 ++- esphome/components/wk2212_i2c/__init__.py | 6 ++++-- esphome/components/wk2212_spi/__init__.py | 6 ++++-- esphome/components/wl_134/text_sensor.py | 3 ++- esphome/components/wled/__init__.py | 5 +++-- esphome/components/wts01/sensor.py | 3 ++- esphome/components/x9c/output.py | 3 ++- esphome/components/xdb401/sensor.py | 3 ++- esphome/components/xgzp68xx/sensor.py | 3 ++- esphome/components/xiaomi_ble/__init__.py | 3 ++- esphome/components/xiaomi_cgd1/sensor.py | 3 ++- esphome/components/xiaomi_cgdk2/sensor.py | 3 ++- esphome/components/xiaomi_cgg1/sensor.py | 3 ++- esphome/components/xiaomi_cgpr1/binary_sensor.py | 3 ++- esphome/components/xiaomi_gcls002/sensor.py | 3 ++- esphome/components/xiaomi_hhccjcy01/sensor.py | 3 ++- esphome/components/xiaomi_hhccjcy10/sensor.py | 3 ++- esphome/components/xiaomi_hhccpot002/sensor.py | 3 ++- esphome/components/xiaomi_jqjcy01ym/sensor.py | 3 ++- esphome/components/xiaomi_lywsd02/sensor.py | 3 ++- esphome/components/xiaomi_lywsd02mmc/sensor.py | 3 ++- esphome/components/xiaomi_lywsd03mmc/sensor.py | 3 ++- esphome/components/xiaomi_lywsdcgq/sensor.py | 3 ++- esphome/components/xiaomi_mhoc303/sensor.py | 3 ++- esphome/components/xiaomi_mhoc401/sensor.py | 3 ++- esphome/components/xiaomi_miscale/sensor.py | 3 ++- esphome/components/xiaomi_mjyd02yla/binary_sensor.py | 3 ++- esphome/components/xiaomi_mue4094rt/binary_sensor.py | 3 ++- esphome/components/xiaomi_wx08zm/binary_sensor.py | 3 ++- esphome/components/xiaomi_xmwsdj04mmc/sensor.py | 3 ++- esphome/components/xpt2046/touchscreen/__init__.py | 3 ++- esphome/components/yashima/climate.py | 3 ++- esphome/components/zephyr/__init__.py | 6 +++--- esphome/components/zephyr_mcumgr/ota/__init__.py | 2 +- esphome/components/zephyr_pwm/output.py | 7 ++++--- esphome/components/zhlt01/climate.py | 3 ++- esphome/components/zio_ultrasonic/sensor.py | 3 ++- esphome/components/zwave_proxy/__init__.py | 5 +++-- esphome/components/zyaura/sensor.py | 3 ++- 487 files changed, 1129 insertions(+), 607 deletions(-) diff --git a/esphome/components/a01nyub/sensor.py b/esphome/components/a01nyub/sensor.py index e5f4f7ef30..f84091d688 100644 --- a/esphome/components/a01nyub/sensor.py +++ b/esphome/components/a01nyub/sensor.py @@ -6,6 +6,7 @@ from esphome.const import ( STATE_CLASS_MEASUREMENT, UNIT_METER, ) +from esphome.types import ConfigType CODEOWNERS = ["@MrSuicideParrot"] DEPENDENCIES = ["uart"] @@ -35,7 +36,7 @@ FINAL_VALIDATE_SCHEMA = uart.final_validate_device_schema( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await sensor.new_sensor(config) await cg.register_component(var, config) await uart.register_uart_device(var, config) diff --git a/esphome/components/a02yyuw/sensor.py b/esphome/components/a02yyuw/sensor.py index f0bc59ae6c..7372f8f760 100644 --- a/esphome/components/a02yyuw/sensor.py +++ b/esphome/components/a02yyuw/sensor.py @@ -6,6 +6,7 @@ from esphome.const import ( STATE_CLASS_MEASUREMENT, UNIT_MILLIMETER, ) +from esphome.types import ConfigType CODEOWNERS = ["@TH-Braemer"] DEPENDENCIES = ["uart"] @@ -35,7 +36,7 @@ FINAL_VALIDATE_SCHEMA = uart.final_validate_device_schema( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await sensor.new_sensor(config) await cg.register_component(var, config) await uart.register_uart_device(var, config) diff --git a/esphome/components/a4988/stepper.py b/esphome/components/a4988/stepper.py index 97f5a6fe0f..7a19bd550d 100644 --- a/esphome/components/a4988/stepper.py +++ b/esphome/components/a4988/stepper.py @@ -3,6 +3,7 @@ import esphome.codegen as cg from esphome.components import stepper import esphome.config_validation as cv from esphome.const import CONF_DIR_PIN, CONF_ID, CONF_SLEEP_PIN, CONF_STEP_PIN +from esphome.types import ConfigType a4988_ns = cg.esphome_ns.namespace("a4988") A4988 = a4988_ns.class_("A4988", stepper.Stepper, cg.Component) @@ -17,7 +18,7 @@ CONFIG_SCHEMA = stepper.STEPPER_SCHEMA.extend( ).extend(cv.COMPONENT_SCHEMA) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await stepper.register_stepper(var, config) diff --git a/esphome/components/absolute_humidity/sensor.py b/esphome/components/absolute_humidity/sensor.py index caaa546e25..84a69dfa23 100644 --- a/esphome/components/absolute_humidity/sensor.py +++ b/esphome/components/absolute_humidity/sensor.py @@ -9,6 +9,7 @@ from esphome.const import ( STATE_CLASS_MEASUREMENT, UNIT_GRAMS_PER_CUBIC_METER, ) +from esphome.types import ConfigType absolute_humidity_ns = cg.esphome_ns.namespace("absolute_humidity") AbsoluteHumidityComponent = absolute_humidity_ns.class_( @@ -43,7 +44,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await sensor.new_sensor(config) await cg.register_component(var, config) diff --git a/esphome/components/ac_dimmer/output.py b/esphome/components/ac_dimmer/output.py index 48bef2c317..498565b0ea 100644 --- a/esphome/components/ac_dimmer/output.py +++ b/esphome/components/ac_dimmer/output.py @@ -4,6 +4,7 @@ from esphome.components import output import esphome.config_validation as cv from esphome.const import CONF_ID, CONF_METHOD, CONF_MIN_POWER from esphome.core import CORE +from esphome.types import ConfigType CODEOWNERS = ["@glmnet"] @@ -48,7 +49,7 @@ CONFIG_SCHEMA = cv.All( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: if CORE.is_esp32: from esphome.components.esp32 import include_builtin_idf_component diff --git a/esphome/components/adalight/__init__.py b/esphome/components/adalight/__init__.py index 5e122676cd..afdfefaba6 100644 --- a/esphome/components/adalight/__init__.py +++ b/esphome/components/adalight/__init__.py @@ -4,6 +4,9 @@ from esphome.components.light.effects import register_addressable_effect from esphome.components.light.types import AddressableLightEffect import esphome.config_validation as cv from esphome.const import CONF_NAME, CONF_UART_ID +from esphome.core import ID +from esphome.cpp_generator import MockObj +from esphome.types import ConfigType DEPENDENCIES = ["uart"] @@ -21,7 +24,7 @@ CONFIG_SCHEMA = cv.Schema({}) "Adalight", {cv.GenerateID(CONF_UART_ID): cv.use_id(uart.UARTComponent)}, ) -async def adalight_light_effect_to_code(config, effect_id): +async def adalight_light_effect_to_code(config: ConfigType, effect_id: ID) -> MockObj: effect = cg.new_Pvariable(effect_id, config[CONF_NAME]) await uart.register_uart_device(effect, config) return effect diff --git a/esphome/components/adc128s102/__init__.py b/esphome/components/adc128s102/__init__.py index a5281aacc7..684147752d 100644 --- a/esphome/components/adc128s102/__init__.py +++ b/esphome/components/adc128s102/__init__.py @@ -2,6 +2,7 @@ import esphome.codegen as cg from esphome.components import spi import esphome.config_validation as cv from esphome.const import CONF_ID +from esphome.types import ConfigType DEPENDENCIES = ["spi"] MULTI_CONF = True @@ -17,7 +18,7 @@ CONFIG_SCHEMA = cv.Schema( ).extend(spi.spi_device_schema(cs_pin_required=True)) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await spi.register_spi_device(var, config) diff --git a/esphome/components/adc128s102/sensor/__init__.py b/esphome/components/adc128s102/sensor/__init__.py index a65ae9d537..04589a7ce2 100644 --- a/esphome/components/adc128s102/sensor/__init__.py +++ b/esphome/components/adc128s102/sensor/__init__.py @@ -2,6 +2,7 @@ import esphome.codegen as cg from esphome.components import sensor, voltage_sampler import esphome.config_validation as cv from esphome.const import CONF_CHANNEL, CONF_ID +from esphome.types import ConfigType from .. import ADC128S102, adc128s102_ns @@ -28,7 +29,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable( config[CONF_ID], config[CONF_CHANNEL], diff --git a/esphome/components/addressable_light/display.py b/esphome/components/addressable_light/display.py index 929d45121c..1db01b40f9 100644 --- a/esphome/components/addressable_light/display.py +++ b/esphome/components/addressable_light/display.py @@ -11,6 +11,7 @@ from esphome.const import ( CONF_UPDATE_INTERVAL, CONF_WIDTH, ) +from esphome.types import ConfigType CODEOWNERS = ["@justfalter"] @@ -38,7 +39,7 @@ CONFIG_SCHEMA = cv.All( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) wrapped_light = await cg.get_variable(config[CONF_ADDRESSABLE_LIGHT_ID]) cg.add(var.set_width(config[CONF_WIDTH])) diff --git a/esphome/components/ade7880/sensor.py b/esphome/components/ade7880/sensor.py index beb74d7310..93c279e235 100644 --- a/esphome/components/ade7880/sensor.py +++ b/esphome/components/ade7880/sensor.py @@ -36,6 +36,7 @@ from esphome.const import ( UNIT_WATT, UNIT_WATT_HOURS, ) +from esphome.cpp_generator import MockObj from esphome.types import ConfigType DEPENDENCIES = ["i2c"] @@ -243,7 +244,7 @@ CONFIG_SCHEMA = cv.All( ) -async def neutral_channel(config): +async def neutral_channel(config: ConfigType) -> MockObj: var = cg.new_Pvariable(config[CONF_ID]) current = config[CONF_CURRENT] @@ -257,7 +258,7 @@ async def neutral_channel(config): return var -async def power_channel(config): +async def power_channel(config: ConfigType) -> MockObj: var = cg.new_Pvariable(config[CONF_ID]) for sensor_type in POWER_SENSOR_TYPES: @@ -280,7 +281,7 @@ async def power_channel(config): return var -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/ade7953_base/__init__.py b/esphome/components/ade7953_base/__init__.py index 4fc35352f9..71250ac94e 100644 --- a/esphome/components/ade7953_base/__init__.py +++ b/esphome/components/ade7953_base/__init__.py @@ -23,6 +23,8 @@ from esphome.const import ( UNIT_VOLT_AMPS_REACTIVE, UNIT_WATT, ) +from esphome.cpp_generator import MockObj +from esphome.types import ConfigType CODEOWNERS = ["@angelnu"] @@ -163,7 +165,7 @@ ADE7953_CONFIG_SCHEMA = cv.Schema( ).extend(cv.polling_component_schema("60s")) -async def register_ade7953(var, config): +async def register_ade7953(var: MockObj, config: ConfigType) -> None: await cg.register_component(var, config) if irq_pin_config := config.get(CONF_IRQ_PIN): diff --git a/esphome/components/ade7953_i2c/sensor.py b/esphome/components/ade7953_i2c/sensor.py index 4b55acdafa..8447042d30 100644 --- a/esphome/components/ade7953_i2c/sensor.py +++ b/esphome/components/ade7953_i2c/sensor.py @@ -2,6 +2,7 @@ import esphome.codegen as cg from esphome.components import ade7953_base, i2c import esphome.config_validation as cv from esphome.const import CONF_ID +from esphome.types import ConfigType DEPENDENCIES = ["i2c"] AUTO_LOAD = ["ade7953_base"] @@ -20,7 +21,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await i2c.register_i2c_device(var, config) await ade7953_base.register_ade7953(var, config) diff --git a/esphome/components/ade7953_spi/sensor.py b/esphome/components/ade7953_spi/sensor.py index dce021daad..6fdf2147f3 100644 --- a/esphome/components/ade7953_spi/sensor.py +++ b/esphome/components/ade7953_spi/sensor.py @@ -2,6 +2,7 @@ import esphome.codegen as cg from esphome.components import ade7953_base, spi import esphome.config_validation as cv from esphome.const import CONF_ID +from esphome.types import ConfigType DEPENDENCIES = ["spi"] AUTO_LOAD = ["ade7953_base"] @@ -20,7 +21,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await spi.register_spi_device(var, config) await ade7953_base.register_ade7953(var, config) diff --git a/esphome/components/ads1115/__init__.py b/esphome/components/ads1115/__init__.py index 6d52fc83fd..b42ee918c5 100644 --- a/esphome/components/ads1115/__init__.py +++ b/esphome/components/ads1115/__init__.py @@ -2,6 +2,7 @@ import esphome.codegen as cg from esphome.components import i2c import esphome.config_validation as cv from esphome.const import CONF_ID +from esphome.types import ConfigType DEPENDENCIES = ["i2c"] MULTI_CONF = True @@ -24,7 +25,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/ads1115/sensor/__init__.py b/esphome/components/ads1115/sensor/__init__.py index afb70d07c8..742f82d302 100644 --- a/esphome/components/ads1115/sensor/__init__.py +++ b/esphome/components/ads1115/sensor/__init__.py @@ -11,6 +11,7 @@ from esphome.const import ( STATE_CLASS_MEASUREMENT, UNIT_VOLT, ) +from esphome.types import ConfigType from .. import CONF_ADS1115_ID, ADS1115Component, ads1115_ns @@ -86,7 +87,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await sensor.register_sensor(var, config) await cg.register_component(var, config) diff --git a/esphome/components/ads1118/__init__.py b/esphome/components/ads1118/__init__.py index 45d47a329e..956b9a0c1f 100644 --- a/esphome/components/ads1118/__init__.py +++ b/esphome/components/ads1118/__init__.py @@ -2,6 +2,7 @@ import esphome.codegen as cg from esphome.components import spi import esphome.config_validation as cv from esphome.const import CONF_ID +from esphome.types import ConfigType CODEOWNERS = ["@solomondg1"] DEPENDENCIES = ["spi"] @@ -23,7 +24,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await spi.register_spi_device(var, config) diff --git a/esphome/components/ads1118/sensor/__init__.py b/esphome/components/ads1118/sensor/__init__.py index 33bfe97789..6bc3baa2e4 100644 --- a/esphome/components/ads1118/sensor/__init__.py +++ b/esphome/components/ads1118/sensor/__init__.py @@ -11,6 +11,7 @@ from esphome.const import ( UNIT_CELSIUS, UNIT_VOLT, ) +from esphome.types import ConfigType from .. import ADS1118, CONF_ADS1118_ID, ads1118_ns @@ -86,7 +87,7 @@ CONFIG_SCHEMA = cv.typed_schema( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await sensor.new_sensor(config) await cg.register_component(var, config) await cg.register_parented(var, config[CONF_ADS1118_ID]) diff --git a/esphome/components/aht10/sensor.py b/esphome/components/aht10/sensor.py index a5b1cf0ffb..ae669d0000 100644 --- a/esphome/components/aht10/sensor.py +++ b/esphome/components/aht10/sensor.py @@ -12,6 +12,7 @@ from esphome.const import ( UNIT_CELSIUS, UNIT_PERCENT, ) +from esphome.types import ConfigType DEPENDENCIES = ["i2c"] @@ -50,7 +51,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/airthings_ble/__init__.py b/esphome/components/airthings_ble/__init__.py index d0cb7631d2..44534b80e9 100644 --- a/esphome/components/airthings_ble/__init__.py +++ b/esphome/components/airthings_ble/__init__.py @@ -2,6 +2,7 @@ import esphome.codegen as cg from esphome.components import ble_device_base import esphome.config_validation as cv from esphome.const import CONF_ID +from esphome.types import ConfigType AUTO_LOAD = ["ble_device_base"] CODEOWNERS = ["@jeromelaban"] @@ -21,6 +22,6 @@ CONFIG_SCHEMA = cv.All( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await ble_device_base.register_ble_device(var, config) diff --git a/esphome/components/airthings_wave_base/__init__.py b/esphome/components/airthings_wave_base/__init__.py index dee26b524a..58fde11a3d 100644 --- a/esphome/components/airthings_wave_base/__init__.py +++ b/esphome/components/airthings_wave_base/__init__.py @@ -20,6 +20,8 @@ from esphome.const import ( UNIT_PERCENT, UNIT_VOLT, ) +from esphome.cpp_generator import MockObj +from esphome.types import ConfigType CODEOWNERS = ["@ncareau", "@jeromelaban"] @@ -78,7 +80,7 @@ BASE_SCHEMA = ( ) -async def wave_base_to_code(var, config): +async def wave_base_to_code(var: MockObj, config: ConfigType) -> None: await cg.register_component(var, config) await ble_client.register_ble_node(var, config) diff --git a/esphome/components/airthings_wave_mini/sensor.py b/esphome/components/airthings_wave_mini/sensor.py index f231be6670..9136b333e2 100644 --- a/esphome/components/airthings_wave_mini/sensor.py +++ b/esphome/components/airthings_wave_mini/sensor.py @@ -2,6 +2,7 @@ import esphome.codegen as cg from esphome.components import airthings_wave_base import esphome.config_validation as cv from esphome.const import CONF_ID +from esphome.types import ConfigType DEPENDENCIES = airthings_wave_base.DEPENDENCIES @@ -20,6 +21,6 @@ CONFIG_SCHEMA = airthings_wave_base.BASE_SCHEMA.extend( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await airthings_wave_base.wave_base_to_code(var, config) diff --git a/esphome/components/airthings_wave_plus/sensor.py b/esphome/components/airthings_wave_plus/sensor.py index a12c70f04c..8ea79e644f 100644 --- a/esphome/components/airthings_wave_plus/sensor.py +++ b/esphome/components/airthings_wave_plus/sensor.py @@ -83,7 +83,7 @@ CONFIG_SCHEMA = cv.All( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await airthings_wave_base.wave_base_to_code(var, config) diff --git a/esphome/components/alpha3/sensor.py b/esphome/components/alpha3/sensor.py index 279ab214cf..2c1a04ef27 100644 --- a/esphome/components/alpha3/sensor.py +++ b/esphome/components/alpha3/sensor.py @@ -20,6 +20,7 @@ from esphome.const import ( UNIT_VOLT, UNIT_WATT, ) +from esphome.types import ConfigType alpha3_ns = cg.esphome_ns.namespace("alpha3") Alpha3 = alpha3_ns.class_("Alpha3", ble_client.BLEClientNode, cg.PollingComponent) @@ -68,7 +69,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await ble_client.register_ble_node(var, config) diff --git a/esphome/components/am2315c/sensor.py b/esphome/components/am2315c/sensor.py index ec12ab717e..febb11409c 100644 --- a/esphome/components/am2315c/sensor.py +++ b/esphome/components/am2315c/sensor.py @@ -11,6 +11,7 @@ from esphome.const import ( UNIT_CELSIUS, UNIT_PERCENT, ) +from esphome.types import ConfigType DEPENDENCIES = ["i2c"] @@ -40,7 +41,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/am2320/sensor.py b/esphome/components/am2320/sensor.py index ed4a5fd922..ffac0e6407 100644 --- a/esphome/components/am2320/sensor.py +++ b/esphome/components/am2320/sensor.py @@ -11,6 +11,7 @@ from esphome.const import ( UNIT_CELSIUS, UNIT_PERCENT, ) +from esphome.types import ConfigType DEPENDENCIES = ["i2c"] @@ -42,7 +43,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/am43/cover/__init__.py b/esphome/components/am43/cover/__init__.py index e4ecf1444f..d1783b77df 100644 --- a/esphome/components/am43/cover/__init__.py +++ b/esphome/components/am43/cover/__init__.py @@ -2,6 +2,7 @@ import esphome.codegen as cg from esphome.components import ble_client, cover import esphome.config_validation as cv from esphome.const import CONF_PIN +from esphome.types import ConfigType CODEOWNERS = ["@buxtronix"] DEPENDENCIES = ["ble_client"] @@ -27,7 +28,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await cover.new_cover(config) cg.add(var.set_pin(config[CONF_PIN])) cg.add(var.set_invert_position(config[CONF_INVERT_POSITION])) diff --git a/esphome/components/am43/sensor/__init__.py b/esphome/components/am43/sensor/__init__.py index 2697d364ad..80341972a9 100644 --- a/esphome/components/am43/sensor/__init__.py +++ b/esphome/components/am43/sensor/__init__.py @@ -11,6 +11,7 @@ from esphome.const import ( STATE_CLASS_MEASUREMENT, UNIT_PERCENT, ) +from esphome.types import ConfigType AUTO_LOAD = ["am43"] CODEOWNERS = ["@buxtronix"] @@ -42,7 +43,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await ble_client.register_ble_node(var, config) diff --git a/esphome/components/analog_threshold/binary_sensor.py b/esphome/components/analog_threshold/binary_sensor.py index 8c13727755..b2de1d6184 100644 --- a/esphome/components/analog_threshold/binary_sensor.py +++ b/esphome/components/analog_threshold/binary_sensor.py @@ -2,6 +2,7 @@ import esphome.codegen as cg from esphome.components import binary_sensor, sensor import esphome.config_validation as cv from esphome.const import CONF_SENSOR_ID, CONF_THRESHOLD +from esphome.types import ConfigType analog_threshold_ns = cg.esphome_ns.namespace("analog_threshold") @@ -32,7 +33,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await binary_sensor.new_binary_sensor(config) await cg.register_component(var, config) diff --git a/esphome/components/anova/climate.py b/esphome/components/anova/climate.py index e1fd38fddc..5590b18a83 100644 --- a/esphome/components/anova/climate.py +++ b/esphome/components/anova/climate.py @@ -2,6 +2,7 @@ import esphome.codegen as cg from esphome.components import ble_client, climate import esphome.config_validation as cv from esphome.const import CONF_UNIT_OF_MEASUREMENT +from esphome.types import ConfigType UNITS = { "f": "f", @@ -28,7 +29,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await climate.new_climate(config) await cg.register_component(var, config) await ble_client.register_ble_node(var, config) diff --git a/esphome/components/apds9306/sensor.py b/esphome/components/apds9306/sensor.py index c3cba96fbf..4f165eec0b 100644 --- a/esphome/components/apds9306/sensor.py +++ b/esphome/components/apds9306/sensor.py @@ -1,6 +1,8 @@ # Based on this datasheet: # https://www.mouser.ca/datasheet/2/678/AVGO_S_A0002854364_1-2574547.pdf +from typing import Any + import esphome.codegen as cg from esphome.components import i2c, sensor import esphome.config_validation as cv @@ -11,6 +13,8 @@ from esphome.const import ( STATE_CLASS_MEASUREMENT, UNIT_LUX, ) +from esphome.cpp_generator import MockObj +from esphome.types import ConfigType DEPENDENCIES = ["i2c"] @@ -55,7 +59,7 @@ AMBIENT_LIGHT_GAINS = { } -def _validate_measurement_rate(value): +def _validate_measurement_rate(value: Any) -> MockObj: value = cv.positive_time_period_milliseconds(value) return cv.enum(MEASUREMENT_RATES, int=True)(value.total_milliseconds) @@ -85,7 +89,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await sensor.new_sensor(config) await cg.register_component(var, config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/aqi/sensor.py b/esphome/components/aqi/sensor.py index 9c361560df..a98d977227 100644 --- a/esphome/components/aqi/sensor.py +++ b/esphome/components/aqi/sensor.py @@ -7,6 +7,7 @@ from esphome.const import ( DEVICE_CLASS_AQI, STATE_CLASS_MEASUREMENT, ) +from esphome.types import ConfigType from . import AQI_CALCULATION_TYPE, CONF_CALCULATION_TYPE, CONF_EXTENDED_RANGE, aqi_ns @@ -16,7 +17,7 @@ DEPENDENCIES = ["sensor"] AQISensor = aqi_ns.class_("AQISensor", sensor.Sensor, cg.Component) -def _validate_extended_range(config): +def _validate_extended_range(config: ConfigType) -> ConfigType: if CONF_EXTENDED_RANGE in config and config[CONF_CALCULATION_TYPE] == "CAQI": raise cv.Invalid( f"'{CONF_EXTENDED_RANGE}' is not supported with 'calculation_type: CAQI'. " @@ -48,7 +49,7 @@ CONFIG_SCHEMA = cv.All( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await sensor.new_sensor(config) await cg.register_component(var, config) diff --git a/esphome/components/as3935_i2c/__init__.py b/esphome/components/as3935_i2c/__init__.py index 09b588cb0c..83924de760 100644 --- a/esphome/components/as3935_i2c/__init__.py +++ b/esphome/components/as3935_i2c/__init__.py @@ -2,6 +2,7 @@ import esphome.codegen as cg from esphome.components import as3935, i2c import esphome.config_validation as cv from esphome.const import CONF_ID +from esphome.types import ConfigType AUTO_LOAD = ["as3935"] DEPENDENCIES = ["i2c"] @@ -20,7 +21,7 @@ CONFIG_SCHEMA = cv.All( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await as3935.setup_as3935(var, config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/as3935_spi/__init__.py b/esphome/components/as3935_spi/__init__.py index f4cf07a906..332a51c7a9 100644 --- a/esphome/components/as3935_spi/__init__.py +++ b/esphome/components/as3935_spi/__init__.py @@ -2,6 +2,7 @@ import esphome.codegen as cg from esphome.components import as3935, spi import esphome.config_validation as cv from esphome.const import CONF_ID +from esphome.types import ConfigType AUTO_LOAD = ["as3935"] DEPENDENCIES = ["spi"] @@ -20,7 +21,7 @@ CONFIG_SCHEMA = cv.All( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await as3935.setup_as3935(var, config) await spi.register_spi_device(var, config) diff --git a/esphome/components/as7341/sensor.py b/esphome/components/as7341/sensor.py index 8b6cf61028..f70c5e999f 100644 --- a/esphome/components/as7341/sensor.py +++ b/esphome/components/as7341/sensor.py @@ -9,6 +9,7 @@ from esphome.const import ( ICON_BRIGHTNESS_5, STATE_CLASS_MEASUREMENT, ) +from esphome.types import ConfigType CODEOWNERS = ["@mrgnr"] DEPENDENCIES = ["i2c"] @@ -96,7 +97,7 @@ SENSORS = { } -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/async_tcp/__init__.py b/esphome/components/async_tcp/__init__.py index 22d544ba37..31007022d5 100644 --- a/esphome/components/async_tcp/__init__.py +++ b/esphome/components/async_tcp/__init__.py @@ -2,6 +2,7 @@ import esphome.codegen as cg import esphome.config_validation as cv from esphome.core import CORE, CoroPriority, coroutine_with_priority +from esphome.types import ConfigType CODEOWNERS = ["@esphome/core"] DEPENDENCIES = ["network"] @@ -25,7 +26,7 @@ CONFIG_SCHEMA = cv.Schema({}) @coroutine_with_priority(CoroPriority.NETWORK_TRANSPORT) -async def to_code(config): +async def to_code(config: ConfigType) -> None: if CORE.is_esp32: # https://github.com/ESP32Async/AsyncTCP from esphome.components.esp32 import add_idf_component diff --git a/esphome/components/atc_mithermometer/sensor.py b/esphome/components/atc_mithermometer/sensor.py index 5c2d75753c..184b2e8733 100644 --- a/esphome/components/atc_mithermometer/sensor.py +++ b/esphome/components/atc_mithermometer/sensor.py @@ -21,6 +21,7 @@ from esphome.const import ( UNIT_PERCENT, UNIT_VOLT, ) +from esphome.types import ConfigType CODEOWNERS = ["@ahpohl"] @@ -77,7 +78,7 @@ CONFIG_SCHEMA = cv.All( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await ble_device_base.register_ble_device(var, config) diff --git a/esphome/components/atm90e26/sensor.py b/esphome/components/atm90e26/sensor.py index 5941cb35b4..87db214233 100644 --- a/esphome/components/atm90e26/sensor.py +++ b/esphome/components/atm90e26/sensor.py @@ -30,6 +30,7 @@ from esphome.const import ( UNIT_WATT, UNIT_WATT_HOURS, ) +from esphome.types import ConfigType CONF_METER_CONSTANT = "meter_constant" CONF_PL_CONST = "pl_const" @@ -123,7 +124,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await spi.register_spi_device(var, config) diff --git a/esphome/components/axs15231/touchscreen/__init__.py b/esphome/components/axs15231/touchscreen/__init__.py index 8c18d8ca75..2616cb281b 100644 --- a/esphome/components/axs15231/touchscreen/__init__.py +++ b/esphome/components/axs15231/touchscreen/__init__.py @@ -3,6 +3,7 @@ import esphome.codegen as cg from esphome.components import i2c, touchscreen import esphome.config_validation as cv from esphome.const import CONF_ID, CONF_INTERRUPT_PIN, CONF_RESET_PIN +from esphome.types import ConfigType from .. import axs15231_ns @@ -25,7 +26,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await touchscreen.register_touchscreen(var, config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/b_parasite/sensor.py b/esphome/components/b_parasite/sensor.py index 673c5981b7..cb8f569c0d 100644 --- a/esphome/components/b_parasite/sensor.py +++ b/esphome/components/b_parasite/sensor.py @@ -20,6 +20,7 @@ from esphome.const import ( UNIT_PERCENT, UNIT_VOLT, ) +from esphome.types import ConfigType CODEOWNERS = ["@rbaron"] @@ -74,7 +75,7 @@ CONFIG_SCHEMA = cv.All( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await ble_device_base.register_ble_device(var, config) diff --git a/esphome/components/ballu/climate.py b/esphome/components/ballu/climate.py index 1127084632..c4d64cd692 100644 --- a/esphome/components/ballu/climate.py +++ b/esphome/components/ballu/climate.py @@ -1,5 +1,6 @@ import esphome.codegen as cg from esphome.components import climate_ir +from esphome.types import ConfigType AUTO_LOAD = ["climate_ir"] CODEOWNERS = ["@bazuchan"] @@ -10,5 +11,5 @@ BalluClimate = ballu_ns.class_("BalluClimate", climate_ir.ClimateIR) CONFIG_SCHEMA = climate_ir.climate_ir_with_receiver_schema(BalluClimate) -async def to_code(config): +async def to_code(config: ConfigType) -> None: await climate_ir.new_climate_ir(config) diff --git a/esphome/components/bang_bang/climate.py b/esphome/components/bang_bang/climate.py index bfdb12278f..65c5eaed18 100644 --- a/esphome/components/bang_bang/climate.py +++ b/esphome/components/bang_bang/climate.py @@ -12,6 +12,7 @@ from esphome.const import ( CONF_IDLE_ACTION, CONF_SENSOR, ) +from esphome.types import ConfigType bang_bang_ns = cg.esphome_ns.namespace("bang_bang") BangBangClimate = bang_bang_ns.class_("BangBangClimate", climate.Climate, cg.Component) @@ -41,7 +42,7 @@ CONFIG_SCHEMA = cv.All( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await climate.new_climate(config) await cg.register_component(var, config) diff --git a/esphome/components/beken_spi_led_strip/light.py b/esphome/components/beken_spi_led_strip/light.py index 2be5842818..5576f286f1 100644 --- a/esphome/components/beken_spi_led_strip/light.py +++ b/esphome/components/beken_spi_led_strip/light.py @@ -56,7 +56,7 @@ SUPPORTED_PINS = { } -def _validate_pin(value): +def _validate_pin(value: int) -> int: family = libretiny.get_libretiny_family() if family not in SUPPORTED_PINS: raise cv.Invalid(f"Chip family {family} is not supported.") diff --git a/esphome/components/bh1750/sensor.py b/esphome/components/bh1750/sensor.py index 36af5aeef9..07272b3b4f 100644 --- a/esphome/components/bh1750/sensor.py +++ b/esphome/components/bh1750/sensor.py @@ -2,6 +2,7 @@ import esphome.codegen as cg from esphome.components import i2c, sensor import esphome.config_validation as cv from esphome.const import DEVICE_CLASS_ILLUMINANCE, STATE_CLASS_MEASUREMENT, UNIT_LUX +from esphome.types import ConfigType DEPENDENCIES = ["i2c"] CODEOWNERS = ["@OttoWinter"] @@ -25,7 +26,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await sensor.new_sensor(config) await cg.register_component(var, config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/bh1900nux/sensor.py b/esphome/components/bh1900nux/sensor.py index a70db3555a..4ddffb7940 100644 --- a/esphome/components/bh1900nux/sensor.py +++ b/esphome/components/bh1900nux/sensor.py @@ -6,6 +6,7 @@ from esphome.const import ( STATE_CLASS_MEASUREMENT, UNIT_CELSIUS, ) +from esphome.types import ConfigType DEPENDENCIES = ["i2c"] CODEOWNERS = ["@B48D81EFCC"] @@ -28,7 +29,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await sensor.new_sensor(config) await cg.register_component(var, config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/binary/fan/__init__.py b/esphome/components/binary/fan/__init__.py index dadcf52372..03a03ec7ca 100644 --- a/esphome/components/binary/fan/__init__.py +++ b/esphome/components/binary/fan/__init__.py @@ -2,6 +2,7 @@ import esphome.codegen as cg from esphome.components import fan, output import esphome.config_validation as cv from esphome.const import CONF_DIRECTION_OUTPUT, CONF_OSCILLATION_OUTPUT, CONF_OUTPUT +from esphome.types import ConfigType from .. import binary_ns @@ -20,7 +21,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await fan.new_fan(config) await cg.register_component(var, config) diff --git a/esphome/components/binary/light/__init__.py b/esphome/components/binary/light/__init__.py index ebb22f4409..b6eddac341 100644 --- a/esphome/components/binary/light/__init__.py +++ b/esphome/components/binary/light/__init__.py @@ -2,6 +2,7 @@ import esphome.codegen as cg from esphome.components import light, output import esphome.config_validation as cv from esphome.const import CONF_OUTPUT, CONF_OUTPUT_ID +from esphome.types import ConfigType from .. import binary_ns @@ -15,7 +16,7 @@ CONFIG_SCHEMA = light.BINARY_LIGHT_SCHEMA.extend( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_OUTPUT_ID]) await light.register_light(var, config) diff --git a/esphome/components/binary_sensor_map/sensor.py b/esphome/components/binary_sensor_map/sensor.py index 965e332e28..f3133c0621 100644 --- a/esphome/components/binary_sensor_map/sensor.py +++ b/esphome/components/binary_sensor_map/sensor.py @@ -10,6 +10,7 @@ from esphome.const import ( CONF_VALUE, ICON_CHECK_CIRCLE_OUTLINE, ) +from esphome.types import ConfigType DEPENDENCIES = ["binary_sensor"] @@ -82,7 +83,7 @@ CONFIG_SCHEMA = cv.typed_schema( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await sensor.new_sensor(config) await cg.register_component(var, config) diff --git a/esphome/components/bk72xx/__init__.py b/esphome/components/bk72xx/__init__.py index ee9bf1e0d4..e64237c95a 100644 --- a/esphome/components/bk72xx/__init__.py +++ b/esphome/components/bk72xx/__init__.py @@ -28,6 +28,8 @@ from esphome.components.libretiny.const import ( LibreTinyComponent, ) from esphome.core import CORE +from esphome.cpp_generator import MockObj +from esphome.types import ConfigType from .boards import BK72XX_BOARD_PINS, BK72XX_BOARDS @@ -45,7 +47,7 @@ COMPONENT_DATA = LibreTinyComponent( ) -def _set_core_data(config): +def _set_core_data(config: ConfigType) -> ConfigType: CORE.data[KEY_LIBRETINY] = {} CORE.data[KEY_LIBRETINY][KEY_COMPONENT_DATA] = COMPONENT_DATA return config @@ -62,12 +64,12 @@ PIN_SCHEMA = libretiny.gpio.BASE_PIN_SCHEMA CONFIG_SCHEMA.prepend_extra(_set_core_data) -async def to_code(config): +async def to_code(config: ConfigType) -> MockObj: return await libretiny.component_to_code(config) @pins.PIN_SCHEMA_REGISTRY.register("bk72xx", PIN_SCHEMA) -async def pin_to_code(config): +async def pin_to_code(config: ConfigType) -> MockObj: return await libretiny.gpio.component_pin_to_code(config) diff --git a/esphome/components/bl0939/sensor.py b/esphome/components/bl0939/sensor.py index bd4bdd93e5..ec17ef2c7e 100644 --- a/esphome/components/bl0939/sensor.py +++ b/esphome/components/bl0939/sensor.py @@ -15,6 +15,7 @@ from esphome.const import ( UNIT_VOLT, UNIT_WATT, ) +from esphome.types import ConfigType DEPENDENCIES = ["uart"] @@ -88,7 +89,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await uart.register_uart_device(var, config) diff --git a/esphome/components/bl0942/sensor.py b/esphome/components/bl0942/sensor.py index f9fe7f5a5e..5531fe411b 100644 --- a/esphome/components/bl0942/sensor.py +++ b/esphome/components/bl0942/sensor.py @@ -24,6 +24,7 @@ from esphome.const import ( UNIT_VOLT, UNIT_WATT, ) +from esphome.types import ConfigType CONF_CURRENT_REFERENCE = "current_reference" CONF_ENERGY_REFERENCE = "energy_reference" @@ -95,7 +96,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await uart.register_uart_device(var, config) diff --git a/esphome/components/ble_device_base/automation.py b/esphome/components/ble_device_base/automation.py index eb63061a8d..6acc4edb92 100644 --- a/esphome/components/ble_device_base/automation.py +++ b/esphome/components/ble_device_base/automation.py @@ -1,5 +1,6 @@ """Shared codegen for the neutral BLE advertisement triggers (automation.h).""" +from collections.abc import Callable from typing import Any from esphome import automation @@ -52,7 +53,7 @@ _UUID_WIDTHS = { def uuid_trigger_schema( trigger_class: MockObjClass, extra: dict[Any, Any] | None = None -): +) -> Callable[[Any], Any]: """Schema for a UUID-filtered trigger — pairs with uuid_trigger_to_code(). `extra` carries the required UUID key (a cv marker, so a dict rather than @@ -68,7 +69,7 @@ def uuid_trigger_schema( ) -def advertise_trigger_schema(trigger_class: MockObjClass): +def advertise_trigger_schema(trigger_class: MockObjClass) -> Callable[[Any], Any]: """on_ble_advertise schema: multi-mac list filter, unlike the single-mac uuid_trigger_schema() — pairs with advertise_trigger_to_code().""" return automation.validate_automation( @@ -79,7 +80,7 @@ def advertise_trigger_schema(trigger_class: MockObjClass): ) -def scan_end_trigger_schema(trigger_class: MockObjClass): +def scan_end_trigger_schema(trigger_class: MockObjClass) -> Callable[[Any], Any]: """on_scan_end schema: id only — pairs with scan_end_trigger_to_code().""" return automation.validate_automation( {cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(trigger_class)} diff --git a/esphome/components/ble_presence/binary_sensor.py b/esphome/components/ble_presence/binary_sensor.py index a7713d9a4b..a43d3561f8 100644 --- a/esphome/components/ble_presence/binary_sensor.py +++ b/esphome/components/ble_presence/binary_sensor.py @@ -10,6 +10,7 @@ from esphome.const import ( CONF_SERVICE_UUID, CONF_TIMEOUT, ) +from esphome.types import ConfigType CONF_IRK = "irk" @@ -24,7 +25,7 @@ BLEPresenceDevice = ble_presence_ns.class_( ) -def _validate(config): +def _validate(config: ConfigType) -> ConfigType: if CONF_IBEACON_MAJOR in config and CONF_IBEACON_UUID not in config: raise cv.Invalid("iBeacon major identifier requires iBeacon UUID") if CONF_IBEACON_MINOR in config and CONF_IBEACON_UUID not in config: @@ -58,7 +59,7 @@ CONFIG_SCHEMA = cv.All( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await binary_sensor.new_binary_sensor(config) await cg.register_component(var, config) await ble_device_base.register_ble_device(var, config) diff --git a/esphome/components/ble_rssi/sensor.py b/esphome/components/ble_rssi/sensor.py index 43e5813ea2..6813505d58 100644 --- a/esphome/components/ble_rssi/sensor.py +++ b/esphome/components/ble_rssi/sensor.py @@ -11,6 +11,7 @@ from esphome.const import ( STATE_CLASS_MEASUREMENT, UNIT_DECIBEL_MILLIWATT, ) +from esphome.types import ConfigType CONF_IRK = "irk" @@ -22,7 +23,7 @@ BLERSSISensor = ble_rssi_ns.class_( ) -def _validate(config): +def _validate(config: ConfigType) -> ConfigType: if CONF_IBEACON_MAJOR in config and CONF_IBEACON_UUID not in config: raise cv.Invalid("iBeacon major identifier requires iBeacon UUID") if CONF_IBEACON_MINOR in config and CONF_IBEACON_UUID not in config: @@ -58,7 +59,7 @@ CONFIG_SCHEMA = cv.All( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await sensor.new_sensor(config) await cg.register_component(var, config) await ble_device_base.register_ble_device(var, config) diff --git a/esphome/components/ble_scanner/text_sensor.py b/esphome/components/ble_scanner/text_sensor.py index 0c08e1f734..0c60b53783 100644 --- a/esphome/components/ble_scanner/text_sensor.py +++ b/esphome/components/ble_scanner/text_sensor.py @@ -1,6 +1,7 @@ import esphome.codegen as cg from esphome.components import ble_device_base, text_sensor import esphome.config_validation as cv +from esphome.types import ConfigType AUTO_LOAD = ["ble_device_base"] @@ -20,7 +21,7 @@ CONFIG_SCHEMA = cv.All( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await text_sensor.new_text_sensor(config) await cg.register_component(var, config) await ble_device_base.register_ble_device(var, config) diff --git a/esphome/components/bluetooth_proxy/__init__.py b/esphome/components/bluetooth_proxy/__init__.py index 95f71fc8ea..1b761849a5 100644 --- a/esphome/components/bluetooth_proxy/__init__.py +++ b/esphome/components/bluetooth_proxy/__init__.py @@ -92,7 +92,7 @@ def _esp32_config_schema() -> cv.All: CONNECTION_SCHEMA = bluetooth_connection.hub_connection_schema(PLATFORM_ESP32) - def validate_connections(config): + def validate_connections(config: ConfigType) -> ConfigType: if CONF_CONNECTIONS in config: if not config[CONF_ACTIVE]: raise cv.Invalid( diff --git a/esphome/components/bme280_base/__init__.py b/esphome/components/bme280_base/__init__.py index c37191bc07..287946801e 100644 --- a/esphome/components/bme280_base/__init__.py +++ b/esphome/components/bme280_base/__init__.py @@ -16,6 +16,8 @@ from esphome.const import ( UNIT_HECTOPASCAL, UNIT_PERCENT, ) +from esphome.cpp_generator import MockObj +from esphome.types import ConfigType CODEOWNERS = ["@esphome/core"] @@ -84,7 +86,7 @@ CONFIG_SCHEMA_BASE = cv.Schema( ).extend(cv.polling_component_schema("60s")) -async def to_code_base(config): +async def to_code_base(config: ConfigType) -> MockObj: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) diff --git a/esphome/components/bme280_i2c/sensor.py b/esphome/components/bme280_i2c/sensor.py index 1c37033613..536e8ec794 100644 --- a/esphome/components/bme280_i2c/sensor.py +++ b/esphome/components/bme280_i2c/sensor.py @@ -1,6 +1,7 @@ import esphome.codegen as cg from esphome.components import i2c import esphome.config_validation as cv +from esphome.types import ConfigType from ..bme280_base import CONFIG_SCHEMA_BASE, to_code_base @@ -17,6 +18,6 @@ CONFIG_SCHEMA = CONFIG_SCHEMA_BASE.extend( ).extend({cv.GenerateID(): cv.declare_id(BME280I2CComponent)}) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await to_code_base(config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/bme280_spi/sensor.py b/esphome/components/bme280_spi/sensor.py index 7f4fb5cf44..1d53fe25fa 100644 --- a/esphome/components/bme280_spi/sensor.py +++ b/esphome/components/bme280_spi/sensor.py @@ -1,6 +1,7 @@ import esphome.codegen as cg from esphome.components import spi import esphome.config_validation as cv +from esphome.types import ConfigType from ..bme280_base import CONFIG_SCHEMA_BASE, to_code_base @@ -19,6 +20,6 @@ CONFIG_SCHEMA = CONFIG_SCHEMA_BASE.extend(spi.spi_device_schema()).extend( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await to_code_base(config) await spi.register_spi_device(var, config) diff --git a/esphome/components/bme680/sensor.py b/esphome/components/bme680/sensor.py index f41aefcec3..dce5c88cfa 100644 --- a/esphome/components/bme680/sensor.py +++ b/esphome/components/bme680/sensor.py @@ -22,6 +22,7 @@ from esphome.const import ( UNIT_OHM, UNIT_PERCENT, ) +from esphome.types import ConfigType DEPENDENCIES = ["i2c"] @@ -125,7 +126,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/bme68x_bsec2_i2c/__init__.py b/esphome/components/bme68x_bsec2_i2c/__init__.py index dacd4e32ad..1da3bdbd6c 100644 --- a/esphome/components/bme68x_bsec2_i2c/__init__.py +++ b/esphome/components/bme68x_bsec2_i2c/__init__.py @@ -6,6 +6,7 @@ from esphome.components.bme68x_bsec2 import ( to_code_base, ) import esphome.config_validation as cv +from esphome.types import ConfigType CODEOWNERS = ["@neffs", "@kbx81"] @@ -29,6 +30,6 @@ CONFIG_SCHEMA = CONFIG_SCHEMA_BASE.extend( ).extend(i2c.i2c_device_schema(0x76)) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await to_code_base(config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/bmi160/sensor.py b/esphome/components/bmi160/sensor.py index cc4037c1ee..4309f0a79f 100644 --- a/esphome/components/bmi160/sensor.py +++ b/esphome/components/bmi160/sensor.py @@ -22,6 +22,7 @@ from esphome.const import ( UNIT_DEGREE_PER_SECOND, UNIT_METER_PER_SECOND_SQUARED, ) +from esphome.types import ConfigType DEPENDENCIES = ["i2c"] @@ -82,7 +83,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/bmi270/motion.py b/esphome/components/bmi270/motion.py index c1616665f9..ad36e592d1 100644 --- a/esphome/components/bmi270/motion.py +++ b/esphome/components/bmi270/motion.py @@ -8,6 +8,7 @@ from esphome.components.const import ( ) from esphome.components.motion import motion_schema, new_motion_component import esphome.config_validation as cv +from esphome.types import ConfigType from . import BMI270Component, bmi270_ns @@ -79,7 +80,7 @@ CONFIG_SCHEMA = ( # Code generation -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await new_motion_component(config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/bmi270/sensor.py b/esphome/components/bmi270/sensor.py index 69235ed8dc..0e1b0604a3 100644 --- a/esphome/components/bmi270/sensor.py +++ b/esphome/components/bmi270/sensor.py @@ -11,6 +11,7 @@ from esphome.const import ( UNIT_CELSIUS, ) from esphome.cpp_generator import MockObj +from esphome.types import ConfigType from . import CONF_BMI270_ID, BMI270Component @@ -30,7 +31,7 @@ CONFIG_SCHEMA = sensor.sensor_schema( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await sensor.new_sensor(config) parent = await cg.get_variable(config[CONF_BMI270_ID]) data = MockObj("data") diff --git a/esphome/components/bmp085/sensor.py b/esphome/components/bmp085/sensor.py index 6e51984e1f..e4e559844e 100644 --- a/esphome/components/bmp085/sensor.py +++ b/esphome/components/bmp085/sensor.py @@ -11,6 +11,7 @@ from esphome.const import ( UNIT_CELSIUS, UNIT_HECTOPASCAL, ) +from esphome.types import ConfigType DEPENDENCIES = ["i2c"] @@ -42,7 +43,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/bmp280_base/__init__.py b/esphome/components/bmp280_base/__init__.py index d612920dd4..c0f0ae90bf 100644 --- a/esphome/components/bmp280_base/__init__.py +++ b/esphome/components/bmp280_base/__init__.py @@ -13,6 +13,8 @@ from esphome.const import ( UNIT_CELSIUS, UNIT_HECTOPASCAL, ) +from esphome.cpp_generator import MockObj +from esphome.types import ConfigType CODEOWNERS = ["@ademuri"] @@ -69,7 +71,7 @@ CONFIG_SCHEMA_BASE = cv.Schema( ).extend(cv.polling_component_schema("60s")) -async def to_code_base(config): +async def to_code_base(config: ConfigType) -> MockObj: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) diff --git a/esphome/components/bmp280_i2c/sensor.py b/esphome/components/bmp280_i2c/sensor.py index 3ff556d51a..8e3c14f50a 100644 --- a/esphome/components/bmp280_i2c/sensor.py +++ b/esphome/components/bmp280_i2c/sensor.py @@ -1,6 +1,7 @@ import esphome.codegen as cg from esphome.components import i2c import esphome.config_validation as cv +from esphome.types import ConfigType from ..bmp280_base import CONFIG_SCHEMA_BASE, to_code_base @@ -18,6 +19,6 @@ CONFIG_SCHEMA = CONFIG_SCHEMA_BASE.extend( ).extend({cv.GenerateID(): cv.declare_id(BMP280I2CComponent)}) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await to_code_base(config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/bmp280_spi/sensor.py b/esphome/components/bmp280_spi/sensor.py index b3678ec01d..d97a6ea579 100644 --- a/esphome/components/bmp280_spi/sensor.py +++ b/esphome/components/bmp280_spi/sensor.py @@ -1,6 +1,7 @@ import esphome.codegen as cg from esphome.components import spi import esphome.config_validation as cv +from esphome.types import ConfigType from ..bmp280_base import CONFIG_SCHEMA_BASE, to_code_base @@ -18,6 +19,6 @@ CONFIG_SCHEMA = CONFIG_SCHEMA_BASE.extend( ).extend({cv.GenerateID(): cv.declare_id(BMP280SPIComponent)}) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await to_code_base(config) await spi.register_spi_device(var, config) diff --git a/esphome/components/bmp3xx_base/__init__.py b/esphome/components/bmp3xx_base/__init__.py index c31db31761..75e168378e 100644 --- a/esphome/components/bmp3xx_base/__init__.py +++ b/esphome/components/bmp3xx_base/__init__.py @@ -13,6 +13,8 @@ from esphome.const import ( UNIT_CELSIUS, UNIT_HECTOPASCAL, ) +from esphome.cpp_generator import MockObj +from esphome.types import ConfigType CODEOWNERS = ["@martgras", "@latonita"] @@ -73,7 +75,7 @@ CONFIG_SCHEMA_BASE = cv.Schema( ).extend(cv.polling_component_schema("60s")) -async def to_code_base(config): +async def to_code_base(config: ConfigType) -> MockObj: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) diff --git a/esphome/components/bmp3xx_i2c/sensor.py b/esphome/components/bmp3xx_i2c/sensor.py index 6fed9fc9ee..46e50ea39f 100644 --- a/esphome/components/bmp3xx_i2c/sensor.py +++ b/esphome/components/bmp3xx_i2c/sensor.py @@ -1,5 +1,6 @@ import esphome.codegen as cg from esphome.components import i2c +from esphome.types import ConfigType from ..bmp3xx_base import CONFIG_SCHEMA_BASE, cv, to_code_base @@ -18,6 +19,6 @@ CONFIG_SCHEMA = CONFIG_SCHEMA_BASE.extend( ).extend({cv.GenerateID(): cv.declare_id(BMP3XXI2CComponent)}) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await to_code_base(config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/bmp3xx_spi/sensor.py b/esphome/components/bmp3xx_spi/sensor.py index 22aab71977..fb3580bbad 100644 --- a/esphome/components/bmp3xx_spi/sensor.py +++ b/esphome/components/bmp3xx_spi/sensor.py @@ -1,5 +1,6 @@ import esphome.codegen as cg from esphome.components import spi +from esphome.types import ConfigType from ..bmp3xx_base import CONFIG_SCHEMA_BASE, cv, to_code_base @@ -18,6 +19,6 @@ CONFIG_SCHEMA = CONFIG_SCHEMA_BASE.extend(spi.spi_device_schema()).extend( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await to_code_base(config) await spi.register_spi_device(var, config) diff --git a/esphome/components/bmp581_base/__init__.py b/esphome/components/bmp581_base/__init__.py index 6a7cf45089..1c2c5c37d4 100644 --- a/esphome/components/bmp581_base/__init__.py +++ b/esphome/components/bmp581_base/__init__.py @@ -15,6 +15,8 @@ from esphome.const import ( UNIT_CELSIUS, UNIT_PASCAL, ) +from esphome.cpp_generator import MockObj +from esphome.types import ConfigType CODEOWNERS = ["@kahrendt", "@danielkent-net"] @@ -47,7 +49,7 @@ IIR_FILTER_OPTIONS = { BMP581Component = bmp581_ns.class_("BMP581Component", cg.PollingComponent) -def compute_measurement_conversion_time(config): +def compute_measurement_conversion_time(config: ConfigType) -> int: # - adds up sensor conversion time based on temperature and pressure oversampling rates given in datasheet # - returns a rounded up time in ms @@ -132,7 +134,7 @@ CONFIG_SCHEMA_BASE = cv.Schema( ).extend(cv.polling_component_schema("60s")) -async def to_code_base(config): +async def to_code_base(config: ConfigType) -> MockObj: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) if temperature_config := config.get(CONF_TEMPERATURE): diff --git a/esphome/components/bmp581_i2c/sensor.py b/esphome/components/bmp581_i2c/sensor.py index 42645022a6..b4cd00325d 100644 --- a/esphome/components/bmp581_i2c/sensor.py +++ b/esphome/components/bmp581_i2c/sensor.py @@ -1,6 +1,7 @@ import esphome.codegen as cg from esphome.components import i2c import esphome.config_validation as cv +from esphome.types import ConfigType from ..bmp581_base import CONFIG_SCHEMA_BASE, to_code_base @@ -18,6 +19,6 @@ CONFIG_SCHEMA = CONFIG_SCHEMA_BASE.extend( ).extend({cv.GenerateID(): cv.declare_id(BMP581I2CComponent)}) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await to_code_base(config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/bmp581_spi/sensor.py b/esphome/components/bmp581_spi/sensor.py index db0d0cd529..435c5cd6f9 100644 --- a/esphome/components/bmp581_spi/sensor.py +++ b/esphome/components/bmp581_spi/sensor.py @@ -4,6 +4,7 @@ import esphome.codegen as cg from esphome.components import spi from esphome.components.spi import CONF_SPI_MODE import esphome.config_validation as cv +from esphome.types import ConfigType from ..bmp581_base import CONFIG_SCHEMA_BASE, to_code_base @@ -28,7 +29,7 @@ BMP581SPIComponent = bmp581_ns.class_( ) -def check_spi_mode(config): +def check_spi_mode(config: ConfigType) -> ConfigType: spi_mode = config.get(CONF_SPI_MODE) if spi_mode not in VALID_SPI_MODES: raise cv.Invalid("BMP581 only supports SPI mode 0 or mode 3") @@ -43,6 +44,6 @@ CONFIG_SCHEMA = cv.All( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await to_code_base(config) await spi.register_spi_device(var, config) diff --git a/esphome/components/bp1658cj/__init__.py b/esphome/components/bp1658cj/__init__.py index dc80c67b44..b45272d2ea 100644 --- a/esphome/components/bp1658cj/__init__.py +++ b/esphome/components/bp1658cj/__init__.py @@ -2,6 +2,7 @@ from esphome import pins import esphome.codegen as cg import esphome.config_validation as cv from esphome.const import CONF_CLOCK_PIN, CONF_DATA_PIN, CONF_ID +from esphome.types import ConfigType CODEOWNERS = ["@Cossid"] MULTI_CONF = True @@ -28,7 +29,7 @@ CONFIG_SCHEMA = cv.Schema( ).extend(cv.COMPONENT_SCHEMA) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) diff --git a/esphome/components/bp1658cj/output.py b/esphome/components/bp1658cj/output.py index 78cf717aba..93e3c75daf 100644 --- a/esphome/components/bp1658cj/output.py +++ b/esphome/components/bp1658cj/output.py @@ -2,6 +2,7 @@ import esphome.codegen as cg from esphome.components import output import esphome.config_validation as cv from esphome.const import CONF_CHANNEL, CONF_ID +from esphome.types import ConfigType from . import BP1658CJ @@ -19,7 +20,7 @@ CONFIG_SCHEMA = output.FLOAT_OUTPUT_SCHEMA.extend( ).extend(cv.COMPONENT_SCHEMA) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await output.register_output(var, config) diff --git a/esphome/components/bp5758d/__init__.py b/esphome/components/bp5758d/__init__.py index af78b38ef5..fa4e8a231b 100644 --- a/esphome/components/bp5758d/__init__.py +++ b/esphome/components/bp5758d/__init__.py @@ -2,6 +2,7 @@ from esphome import pins import esphome.codegen as cg import esphome.config_validation as cv from esphome.const import CONF_CLOCK_PIN, CONF_DATA_PIN, CONF_ID +from esphome.types import ConfigType CODEOWNERS = ["@Cossid"] MULTI_CONF = True @@ -19,7 +20,7 @@ CONFIG_SCHEMA = cv.Schema( ).extend(cv.COMPONENT_SCHEMA) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) diff --git a/esphome/components/bp5758d/output.py b/esphome/components/bp5758d/output.py index 9adf13de55..bbca7c18cc 100644 --- a/esphome/components/bp5758d/output.py +++ b/esphome/components/bp5758d/output.py @@ -2,6 +2,7 @@ import esphome.codegen as cg from esphome.components import output import esphome.config_validation as cv from esphome.const import CONF_CHANNEL, CONF_CURRENT, CONF_ID +from esphome.types import ConfigType from . import BP5758D @@ -20,7 +21,7 @@ CONFIG_SCHEMA = output.FLOAT_OUTPUT_SCHEMA.extend( ).extend(cv.COMPONENT_SCHEMA) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await output.register_output(var, config) diff --git a/esphome/components/cap1188/__init__.py b/esphome/components/cap1188/__init__.py index cde9dd46ae..eff0a05163 100644 --- a/esphome/components/cap1188/__init__.py +++ b/esphome/components/cap1188/__init__.py @@ -3,6 +3,7 @@ import esphome.codegen as cg from esphome.components import i2c import esphome.config_validation as cv from esphome.const import CONF_ID, CONF_RESET_PIN +from esphome.types import ConfigType CONF_TOUCH_THRESHOLD = "touch_threshold" CONF_ALLOW_MULTIPLE_TOUCHES = "allow_multiple_touches" @@ -32,7 +33,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) cg.add(var.set_touch_threshold(config[CONF_TOUCH_THRESHOLD])) cg.add(var.set_allow_multiple_touches(config[CONF_ALLOW_MULTIPLE_TOUCHES])) diff --git a/esphome/components/cap1188/binary_sensor.py b/esphome/components/cap1188/binary_sensor.py index b7af53638a..21fd98ed41 100644 --- a/esphome/components/cap1188/binary_sensor.py +++ b/esphome/components/cap1188/binary_sensor.py @@ -2,6 +2,7 @@ import esphome.codegen as cg from esphome.components import binary_sensor import esphome.config_validation as cv from esphome.const import CONF_CHANNEL +from esphome.types import ConfigType from . import CONF_CAP1188_ID, CAP1188Component, cap1188_ns @@ -16,7 +17,7 @@ CONFIG_SCHEMA = binary_sensor.binary_sensor_schema(CAP1188Channel).extend( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await binary_sensor.new_binary_sensor(config) hub = await cg.get_variable(config[CONF_CAP1188_ID]) cg.add(var.set_channel(config[CONF_CHANNEL])) diff --git a/esphome/components/captive_portal/__init__.py b/esphome/components/captive_portal/__init__.py index 8e5274f58f..e490d89062 100644 --- a/esphome/components/captive_portal/__init__.py +++ b/esphome/components/captive_portal/__init__.py @@ -93,7 +93,7 @@ FINAL_VALIDATE_SCHEMA = _final_validate @coroutine_with_priority(CoroPriority.CAPTIVE_PORTAL) -async def to_code(config): +async def to_code(config: ConfigType) -> None: paren = await cg.get_variable(config[CONF_WEB_SERVER_BASE_ID]) var = cg.new_Pvariable(config[CONF_ID], paren) diff --git a/esphome/components/ccs811/sensor.py b/esphome/components/ccs811/sensor.py index d9023a415f..d134d2cf21 100644 --- a/esphome/components/ccs811/sensor.py +++ b/esphome/components/ccs811/sensor.py @@ -18,6 +18,7 @@ from esphome.const import ( UNIT_PARTS_PER_BILLION, UNIT_PARTS_PER_MILLION, ) +from esphome.types import ConfigType AUTO_LOAD = ["text_sensor"] CODEOWNERS = ["@habbie"] @@ -59,7 +60,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/cd74hc4067/__init__.py b/esphome/components/cd74hc4067/__init__.py index af6866df78..5f7778e186 100644 --- a/esphome/components/cd74hc4067/__init__.py +++ b/esphome/components/cd74hc4067/__init__.py @@ -2,6 +2,7 @@ from esphome import pins import esphome.codegen as cg import esphome.config_validation as cv from esphome.const import CONF_DELAY, CONF_ID +from esphome.types import ConfigType AUTO_LOAD = ["sensor", "voltage_sampler"] CODEOWNERS = ["@asoehlke"] @@ -33,7 +34,7 @@ CONFIG_SCHEMA = cv.Schema( ).extend(cv.COMPONENT_SCHEMA) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) diff --git a/esphome/components/cd74hc4067/sensor.py b/esphome/components/cd74hc4067/sensor.py index dceaf6f371..670b050271 100644 --- a/esphome/components/cd74hc4067/sensor.py +++ b/esphome/components/cd74hc4067/sensor.py @@ -10,6 +10,7 @@ from esphome.const import ( STATE_CLASS_MEASUREMENT, UNIT_VOLT, ) +from esphome.types import ConfigType from . import CD74HC4067Component, cd74hc4067_ns @@ -44,7 +45,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: parent = await cg.get_variable(config[CONF_CD74HC4067_ID]) var = cg.new_Pvariable(config[CONF_ID], parent) diff --git a/esphome/components/ch422g/__init__.py b/esphome/components/ch422g/__init__.py index 6a7bace0a2..7f0c5bb95e 100644 --- a/esphome/components/ch422g/__init__.py +++ b/esphome/components/ch422g/__init__.py @@ -13,6 +13,8 @@ from esphome.const import ( CONF_OPEN_DRAIN, CONF_OUTPUT, ) +from esphome.cpp_generator import MockObj +from esphome.types import ConfigType CODEOWNERS = ["@jesterret", "@clydebarrow"] DEPENDENCIES = ["i2c"] @@ -35,7 +37,7 @@ CONFIG_SCHEMA = cv.Schema( ).extend(cv.COMPONENT_SCHEMA) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) # Can't use register_i2c_device because there is no CONF_ADDRESS @@ -44,7 +46,7 @@ async def to_code(config): # This is used as a final validation step so that modes have been fully transformed. -def pin_mode_check(pin_config, _): +def pin_mode_check(pin_config: ConfigType, _: ConfigType) -> None: if pin_config[CONF_MODE][CONF_INPUT] and pin_config[CONF_NUMBER] >= 8: raise cv.Invalid("CH422G only supports input on pins 0-7") if pin_config[CONF_MODE][CONF_OPEN_DRAIN] and pin_config[CONF_NUMBER] < 8: @@ -63,7 +65,7 @@ CH422G_PIN_SCHEMA = pins.gpio_base_schema( @pins.PIN_SCHEMA_REGISTRY.register(CONF_CH422G, CH422G_PIN_SCHEMA, pin_mode_check) -async def ch422g_pin_to_code(config): +async def ch422g_pin_to_code(config: ConfigType) -> MockObj: var = cg.new_Pvariable(config[CONF_ID]) parent = await cg.get_variable(config[CONF_CH422G]) diff --git a/esphome/components/ch423/__init__.py b/esphome/components/ch423/__init__.py index e3990ee631..9fbf3ea515 100644 --- a/esphome/components/ch423/__init__.py +++ b/esphome/components/ch423/__init__.py @@ -14,6 +14,8 @@ from esphome.const import ( CONF_OUTPUT, ) from esphome.core import CORE +from esphome.cpp_generator import MockObj +from esphome.types import ConfigType CODEOWNERS = ["@dwmw2"] DEPENDENCIES = ["i2c"] @@ -36,7 +38,7 @@ CONFIG_SCHEMA = cv.Schema( ).extend(cv.COMPONENT_SCHEMA) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) # Can't use register_i2c_device because there is no CONF_ADDRESS @@ -45,7 +47,7 @@ async def to_code(config): # This is used as a final validation step so that modes have been fully transformed. -def pin_mode_check(pin_config, _): +def pin_mode_check(pin_config: ConfigType, _: ConfigType) -> None: if pin_config[CONF_MODE][CONF_INPUT] and pin_config[CONF_NUMBER] >= 8: raise cv.Invalid("CH423 only supports input on pins 0-7") if pin_config[CONF_MODE][CONF_OPEN_DRAIN] and pin_config[CONF_NUMBER] < 8: @@ -90,7 +92,7 @@ CH423_PIN_SCHEMA = pins.gpio_base_schema( @pins.PIN_SCHEMA_REGISTRY.register(CONF_CH423, CH423_PIN_SCHEMA, pin_mode_check) -async def ch423_pin_to_code(config): +async def ch423_pin_to_code(config: ConfigType) -> MockObj: var = cg.new_Pvariable(config[CONF_ID]) parent = await cg.get_variable(config[CONF_CH423]) diff --git a/esphome/components/chsc6x/touchscreen.py b/esphome/components/chsc6x/touchscreen.py index 759e38609e..de974d2a79 100644 --- a/esphome/components/chsc6x/touchscreen.py +++ b/esphome/components/chsc6x/touchscreen.py @@ -3,6 +3,7 @@ import esphome.codegen as cg from esphome.components import i2c, touchscreen import esphome.config_validation as cv from esphome.const import CONF_ID, CONF_INTERRUPT_PIN +from esphome.types import ConfigType chsc6x_ns = cg.esphome_ns.namespace("chsc6x") @@ -24,7 +25,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await touchscreen.register_touchscreen(var, config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/climate_ir/__init__.py b/esphome/components/climate_ir/__init__.py index 5315be3db6..0667bd91a2 100644 --- a/esphome/components/climate_ir/__init__.py +++ b/esphome/components/climate_ir/__init__.py @@ -9,7 +9,8 @@ from esphome.const import ( CONF_SUPPORTS_COOL, CONF_SUPPORTS_HEAT, ) -from esphome.cpp_generator import MockObjClass +from esphome.cpp_generator import MockObj, MockObjClass +from esphome.types import ConfigType, SafeExpType _LOGGER = logging.getLogger(__name__) @@ -57,7 +58,7 @@ def climate_ir_with_receiver_schema( ) -async def register_climate_ir(var, config): +async def register_climate_ir(var: MockObj, config: ConfigType) -> None: await cg.register_component(var, config) await remote_base.register_transmittable(var, config) cg.add(var.set_supports_cool(config[CONF_SUPPORTS_COOL])) @@ -72,7 +73,7 @@ async def register_climate_ir(var, config): cg.add(var.set_humidity_sensor(sens)) -async def new_climate_ir(config, *args): +async def new_climate_ir(config: ConfigType, *args: SafeExpType) -> MockObj: var = await climate.new_climate(config, *args) await register_climate_ir(var, config) return var diff --git a/esphome/components/climate_ir_lg/climate.py b/esphome/components/climate_ir_lg/climate.py index 9c832642ce..48fd373b78 100644 --- a/esphome/components/climate_ir_lg/climate.py +++ b/esphome/components/climate_ir_lg/climate.py @@ -1,6 +1,7 @@ import esphome.codegen as cg from esphome.components import climate_ir import esphome.config_validation as cv +from esphome.types import ConfigType AUTO_LOAD = ["climate_ir"] @@ -34,7 +35,7 @@ CONFIG_SCHEMA = climate_ir.climate_ir_with_receiver_schema(LgIrClimate).extend( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await climate_ir.new_climate_ir(config) cg.add(var.set_header_high(config[CONF_HEADER_HIGH])) diff --git a/esphome/components/color_temperature/light.py b/esphome/components/color_temperature/light.py index 045ab265cd..7686ede155 100644 --- a/esphome/components/color_temperature/light.py +++ b/esphome/components/color_temperature/light.py @@ -8,6 +8,7 @@ from esphome.const import ( CONF_OUTPUT_ID, CONF_WARM_WHITE_COLOR_TEMPERATURE, ) +from esphome.types import ConfigType CODEOWNERS = ["@jesserockz"] @@ -28,7 +29,7 @@ CONFIG_SCHEMA = cv.All( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_OUTPUT_ID]) await light.register_light(var, config) diff --git a/esphome/components/combination/sensor.py b/esphome/components/combination/sensor.py index 327cedee1e..ccc5a03964 100644 --- a/esphome/components/combination/sensor.py +++ b/esphome/components/combination/sensor.py @@ -16,6 +16,7 @@ from esphome.const import ( CONF_UNIT_OF_MEASUREMENT, ) from esphome.core.entity_helpers import inherit_property_from +from esphome.types import ConfigType _LOGGER = logging.getLogger(__name__) @@ -74,7 +75,7 @@ KALMAN_SOURCE_SCHEMA = cv.Schema( ) -def _migrate_coeffecient(config): +def _migrate_coeffecient(config: ConfigType) -> ConfigType: """Migrate deprecated 'coeffecient' spelling to 'coefficient'.""" if CONF_COEFFECIENT in config: if CONF_COEFFICIENT in config: @@ -172,7 +173,7 @@ FINAL_VALIDATE_SCHEMA = cv.All( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await sensor.register_sensor(var, config) diff --git a/esphome/components/coolix/climate.py b/esphome/components/coolix/climate.py index 1ebcff3c1b..3eb8dbe2f4 100644 --- a/esphome/components/coolix/climate.py +++ b/esphome/components/coolix/climate.py @@ -1,5 +1,6 @@ import esphome.codegen as cg from esphome.components import climate_ir +from esphome.types import ConfigType AUTO_LOAD = ["climate_ir"] CODEOWNERS = ["@glmnet"] @@ -10,5 +11,5 @@ CoolixClimate = coolix_ns.class_("CoolixClimate", climate_ir.ClimateIR) CONFIG_SCHEMA = climate_ir.climate_ir_with_receiver_schema(CoolixClimate) -async def to_code(config): +async def to_code(config: ConfigType) -> None: await climate_ir.new_climate_ir(config) diff --git a/esphome/components/cse7761/sensor.py b/esphome/components/cse7761/sensor.py index 7e8caf1ae1..b53ed26ca3 100644 --- a/esphome/components/cse7761/sensor.py +++ b/esphome/components/cse7761/sensor.py @@ -12,6 +12,7 @@ from esphome.const import ( UNIT_VOLT, UNIT_WATT, ) +from esphome.types import ConfigType CODEOWNERS = ["@berfenger"] DEPENDENCIES = ["uart"] @@ -71,7 +72,7 @@ FINAL_VALIDATE_SCHEMA = uart.final_validate_device_schema( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await uart.register_uart_device(var, config) diff --git a/esphome/components/cse7766/sensor.py b/esphome/components/cse7766/sensor.py index 94ed66d7cc..a1a68e18e8 100644 --- a/esphome/components/cse7766/sensor.py +++ b/esphome/components/cse7766/sensor.py @@ -26,6 +26,7 @@ from esphome.const import ( UNIT_WATT, UNIT_WATT_HOURS, ) +from esphome.types import ConfigType DEPENDENCIES = ["uart"] @@ -87,7 +88,7 @@ FINAL_VALIDATE_SCHEMA = uart.final_validate_device_schema( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await uart.register_uart_device(var, config) diff --git a/esphome/components/cst226/binary_sensor/__init__.py b/esphome/components/cst226/binary_sensor/__init__.py index 324d794772..7fd81f6c18 100644 --- a/esphome/components/cst226/binary_sensor/__init__.py +++ b/esphome/components/cst226/binary_sensor/__init__.py @@ -1,6 +1,7 @@ import esphome.codegen as cg from esphome.components import binary_sensor import esphome.config_validation as cv +from esphome.types import ConfigType from .. import cst226_ns from ..touchscreen import CST226ButtonListener, CST226Touchscreen @@ -26,7 +27,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await binary_sensor.new_binary_sensor(config) await cg.register_component(var, config) await cg.register_parented(var, config[CONF_CST226_ID]) diff --git a/esphome/components/cst226/touchscreen/__init__.py b/esphome/components/cst226/touchscreen/__init__.py index 62c2e3b20a..459cba61cd 100644 --- a/esphome/components/cst226/touchscreen/__init__.py +++ b/esphome/components/cst226/touchscreen/__init__.py @@ -3,6 +3,7 @@ import esphome.codegen as cg from esphome.components import i2c, touchscreen import esphome.config_validation as cv from esphome.const import CONF_ID, CONF_INTERRUPT_PIN, CONF_RESET_PIN +from esphome.types import ConfigType from .. import cst226_ns @@ -26,7 +27,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await touchscreen.register_touchscreen(var, config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/cst328/binary_sensor/__init__.py b/esphome/components/cst328/binary_sensor/__init__.py index 6d881cc6c1..33e68a112b 100644 --- a/esphome/components/cst328/binary_sensor/__init__.py +++ b/esphome/components/cst328/binary_sensor/__init__.py @@ -1,6 +1,7 @@ import esphome.codegen as cg from esphome.components import binary_sensor import esphome.config_validation as cv +from esphome.types import ConfigType from .. import cst328_ns from ..touchscreen import CST328ButtonListener, CST328Touchscreen @@ -22,7 +23,7 @@ CONFIG_SCHEMA = binary_sensor.binary_sensor_schema(CST328Button).extend( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await binary_sensor.new_binary_sensor(config) await cg.register_component(var, config) await cg.register_parented(var, config[CONF_CST328_ID]) diff --git a/esphome/components/cst328/touchscreen/__init__.py b/esphome/components/cst328/touchscreen/__init__.py index 18c00bb6c5..9bc7744b7c 100644 --- a/esphome/components/cst328/touchscreen/__init__.py +++ b/esphome/components/cst328/touchscreen/__init__.py @@ -3,6 +3,7 @@ import esphome.codegen as cg from esphome.components import i2c, touchscreen import esphome.config_validation as cv from esphome.const import CONF_ID, CONF_INTERRUPT_PIN, CONF_RESET_PIN +from esphome.types import ConfigType from .. import cst328_ns @@ -27,7 +28,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await touchscreen.register_touchscreen(var, config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/cst816/touchscreen/__init__.py b/esphome/components/cst816/touchscreen/__init__.py index 288ca17593..029a544a91 100644 --- a/esphome/components/cst816/touchscreen/__init__.py +++ b/esphome/components/cst816/touchscreen/__init__.py @@ -3,6 +3,7 @@ import esphome.codegen as cg from esphome.components import i2c, touchscreen import esphome.config_validation as cv from esphome.const import CONF_ID, CONF_INTERRUPT_PIN, CONF_RESET_PIN +from esphome.types import ConfigType from .. import cst816_ns @@ -25,7 +26,7 @@ CONFIG_SCHEMA = touchscreen.TOUCHSCREEN_SCHEMA.extend( ).extend(i2c.i2c_device_schema(0x15)) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await touchscreen.register_touchscreen(var, config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/cst9220/touchscreen/__init__.py b/esphome/components/cst9220/touchscreen/__init__.py index 6d8fc5e2f6..393685e67b 100644 --- a/esphome/components/cst9220/touchscreen/__init__.py +++ b/esphome/components/cst9220/touchscreen/__init__.py @@ -3,6 +3,7 @@ import esphome.codegen as cg from esphome.components import i2c, touchscreen import esphome.config_validation as cv from esphome.const import CONF_ID, CONF_INTERRUPT_PIN, CONF_RESET_PIN +from esphome.types import ConfigType from .. import cst9220_ns @@ -25,7 +26,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await touchscreen.register_touchscreen(var, config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/ct_clamp/sensor.py b/esphome/components/ct_clamp/sensor.py index 6ad7990e80..8ef211cb24 100644 --- a/esphome/components/ct_clamp/sensor.py +++ b/esphome/components/ct_clamp/sensor.py @@ -7,6 +7,7 @@ from esphome.const import ( STATE_CLASS_MEASUREMENT, UNIT_AMPERE, ) +from esphome.types import ConfigType AUTO_LOAD = ["voltage_sampler"] CODEOWNERS = ["@jesserockz"] @@ -36,7 +37,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await sensor.new_sensor(config) await cg.register_component(var, config) diff --git a/esphome/components/current_based/cover.py b/esphome/components/current_based/cover.py index 99952adb12..a552956082 100644 --- a/esphome/components/current_based/cover.py +++ b/esphome/components/current_based/cover.py @@ -10,6 +10,7 @@ from esphome.const import ( CONF_OPEN_DURATION, CONF_STOP_ACTION, ) +from esphome.types import ConfigType CONF_OPEN_SENSOR = "open_sensor" CONF_OPEN_MOVING_CURRENT_THRESHOLD = "open_moving_current_threshold" @@ -67,7 +68,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await cover.new_cover(config) await cg.register_component(var, config) diff --git a/esphome/components/cwww/light.py b/esphome/components/cwww/light.py index 50d84a582d..90fe6d0bad 100644 --- a/esphome/components/cwww/light.py +++ b/esphome/components/cwww/light.py @@ -9,6 +9,7 @@ from esphome.const import ( CONF_WARM_WHITE, CONF_WARM_WHITE_COLOR_TEMPERATURE, ) +from esphome.types import ConfigType cwww_ns = cg.esphome_ns.namespace("cwww") CWWWLightOutput = cwww_ns.class_("CWWWLightOutput", light.LightOutput) @@ -31,7 +32,7 @@ CONFIG_SCHEMA = cv.All( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_OUTPUT_ID]) await light.register_light(var, config) diff --git a/esphome/components/dac7678/__init__.py b/esphome/components/dac7678/__init__.py index 842c84832e..668cc87cec 100644 --- a/esphome/components/dac7678/__init__.py +++ b/esphome/components/dac7678/__init__.py @@ -2,6 +2,8 @@ import esphome.codegen as cg from esphome.components import i2c import esphome.config_validation as cv from esphome.const import CONF_ID +from esphome.cpp_generator import MockObj +from esphome.types import ConfigType AUTO_LOAD = ["output"] CODEOWNERS = ["@NickB1"] @@ -24,7 +26,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> MockObj: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) cg.add(var.set_internal_reference(config[CONF_INTERNAL_REFERENCE])) diff --git a/esphome/components/dac7678/output.py b/esphome/components/dac7678/output.py index cb7739242c..8bc9e119c2 100644 --- a/esphome/components/dac7678/output.py +++ b/esphome/components/dac7678/output.py @@ -2,6 +2,8 @@ import esphome.codegen as cg from esphome.components import output import esphome.config_validation as cv from esphome.const import CONF_CHANNEL, CONF_ID +from esphome.cpp_generator import MockObj +from esphome.types import ConfigType from . import DAC7678Output, dac7678_ns @@ -19,7 +21,7 @@ CONFIG_SCHEMA = output.FLOAT_OUTPUT_SCHEMA.extend( ) -async def to_code(config): +async def to_code(config: ConfigType) -> MockObj: paren = await cg.get_variable(config[CONF_DAC7678_ID]) var = cg.new_Pvariable(config[CONF_ID]) cg.add(var.set_channel(config[CONF_CHANNEL])) diff --git a/esphome/components/daikin/climate.py b/esphome/components/daikin/climate.py index 7f0226143b..c9f9cb189f 100644 --- a/esphome/components/daikin/climate.py +++ b/esphome/components/daikin/climate.py @@ -1,5 +1,6 @@ import esphome.codegen as cg from esphome.components import climate_ir +from esphome.types import ConfigType AUTO_LOAD = ["climate_ir"] @@ -9,5 +10,5 @@ DaikinClimate = daikin_ns.class_("DaikinClimate", climate_ir.ClimateIR) CONFIG_SCHEMA = climate_ir.climate_ir_with_receiver_schema(DaikinClimate) -async def to_code(config): +async def to_code(config: ConfigType) -> None: await climate_ir.new_climate_ir(config) diff --git a/esphome/components/daikin_arc/climate.py b/esphome/components/daikin_arc/climate.py index dbaf12d959..210ec6987e 100644 --- a/esphome/components/daikin_arc/climate.py +++ b/esphome/components/daikin_arc/climate.py @@ -1,5 +1,6 @@ import esphome.codegen as cg from esphome.components import climate_ir +from esphome.types import ConfigType AUTO_LOAD = ["climate_ir"] @@ -9,5 +10,5 @@ DaikinArcClimate = daikin_arc_ns.class_("DaikinArcClimate", climate_ir.ClimateIR CONFIG_SCHEMA = climate_ir.climate_ir_with_receiver_schema(DaikinArcClimate) -async def to_code(config): +async def to_code(config: ConfigType) -> None: await climate_ir.new_climate_ir(config) diff --git a/esphome/components/daikin_brc/climate.py b/esphome/components/daikin_brc/climate.py index 5b7a4631a9..c5c1d3739e 100644 --- a/esphome/components/daikin_brc/climate.py +++ b/esphome/components/daikin_brc/climate.py @@ -2,6 +2,7 @@ import esphome.codegen as cg from esphome.components import climate_ir import esphome.config_validation as cv from esphome.const import CONF_USE_FAHRENHEIT +from esphome.types import ConfigType AUTO_LOAD = ["climate_ir"] @@ -16,6 +17,6 @@ CONFIG_SCHEMA = climate_ir.climate_ir_with_receiver_schema(DaikinBrcClimate).ext ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await climate_ir.new_climate_ir(config) cg.add(var.set_fahrenheit(config[CONF_USE_FAHRENHEIT])) diff --git a/esphome/components/dallas_temp/sensor.py b/esphome/components/dallas_temp/sensor.py index 3d35881722..c441504947 100644 --- a/esphome/components/dallas_temp/sensor.py +++ b/esphome/components/dallas_temp/sensor.py @@ -7,6 +7,7 @@ from esphome.const import ( STATE_CLASS_MEASUREMENT, UNIT_CELSIUS, ) +from esphome.types import ConfigType dallas_temp_ns = cg.esphome_ns.namespace("dallas_temp") @@ -35,7 +36,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await sensor.new_sensor(config) await cg.register_component(var, config) await one_wire.register_one_wire_device(var, config) diff --git a/esphome/components/delonghi/climate.py b/esphome/components/delonghi/climate.py index 63576f032d..919bf7b806 100644 --- a/esphome/components/delonghi/climate.py +++ b/esphome/components/delonghi/climate.py @@ -1,5 +1,6 @@ import esphome.codegen as cg from esphome.components import climate_ir +from esphome.types import ConfigType AUTO_LOAD = ["climate_ir"] @@ -9,5 +10,5 @@ DelonghiClimate = delonghi_ns.class_("DelonghiClimate", climate_ir.ClimateIR) CONFIG_SCHEMA = climate_ir.climate_ir_with_receiver_schema(DelonghiClimate) -async def to_code(config): +async def to_code(config: ConfigType) -> None: await climate_ir.new_climate_ir(config) diff --git a/esphome/components/demo/__init__.py b/esphome/components/demo/__init__.py index 2af0c18c18..75feaa65af 100644 --- a/esphome/components/demo/__init__.py +++ b/esphome/components/demo/__init__.py @@ -55,6 +55,7 @@ from esphome.const import ( UNIT_PERCENT, UNIT_WATT_HOURS, ) +from esphome.types import ConfigType AUTO_LOAD = [ "alarm_control_panel", @@ -550,7 +551,7 @@ CONFIG_SCHEMA = cv.Schema( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: for conf in config[CONF_ALARM_CONTROL_PANELS]: var = await alarm_control_panel.new_alarm_control_panel(conf) cg.add(var.set_type(conf[CONF_TYPE])) diff --git a/esphome/components/dew_point/sensor.py b/esphome/components/dew_point/sensor.py index 4fee095602..555fdef289 100644 --- a/esphome/components/dew_point/sensor.py +++ b/esphome/components/dew_point/sensor.py @@ -8,6 +8,7 @@ from esphome.const import ( STATE_CLASS_MEASUREMENT, UNIT_CELSIUS, ) +from esphome.types import ConfigType DEPENDENCIES = ["sensor"] @@ -35,7 +36,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await sensor.new_sensor(config) await cg.register_component(var, config) diff --git a/esphome/components/dht/sensor.py b/esphome/components/dht/sensor.py index d907495ba2..7376adb287 100644 --- a/esphome/components/dht/sensor.py +++ b/esphome/components/dht/sensor.py @@ -15,6 +15,7 @@ from esphome.const import ( UNIT_PERCENT, ) from esphome.cpp_helpers import gpio_pin_expression +from esphome.types import ConfigType dht_ns = cg.esphome_ns.namespace("dht") DHTModel = dht_ns.enum("DHTModel") @@ -53,7 +54,7 @@ CONFIG_SCHEMA = cv.Schema( ).extend(cv.polling_component_schema("60s")) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) diff --git a/esphome/components/dht12/sensor.py b/esphome/components/dht12/sensor.py index eb93cbae2c..2bc6e94515 100644 --- a/esphome/components/dht12/sensor.py +++ b/esphome/components/dht12/sensor.py @@ -11,6 +11,7 @@ from esphome.const import ( UNIT_CELSIUS, UNIT_PERCENT, ) +from esphome.types import ConfigType DEPENDENCIES = ["i2c"] @@ -40,7 +41,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/dps310/sensor.py b/esphome/components/dps310/sensor.py index 605812beaa..8b8fd8373b 100644 --- a/esphome/components/dps310/sensor.py +++ b/esphome/components/dps310/sensor.py @@ -13,6 +13,7 @@ from esphome.const import ( UNIT_CELSIUS, UNIT_HECTOPASCAL, ) +from esphome.types import ConfigType CODEOWNERS = ["@kbx81"] @@ -48,7 +49,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/ds2484/one_wire.py b/esphome/components/ds2484/one_wire.py index 384b2d01e6..f6277cd68e 100644 --- a/esphome/components/ds2484/one_wire.py +++ b/esphome/components/ds2484/one_wire.py @@ -3,6 +3,7 @@ from esphome.components import i2c from esphome.components.one_wire import OneWireBus import esphome.config_validation as cv from esphome.const import CONF_ID +from esphome.types import ConfigType ds2484_ns = cg.esphome_ns.namespace("ds2484") @@ -29,7 +30,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await i2c.register_i2c_device(var, config) await cg.register_component(var, config) diff --git a/esphome/components/dsmr/__init__.py b/esphome/components/dsmr/__init__.py index eaf36d34fa..96a1e75668 100644 --- a/esphome/components/dsmr/__init__.py +++ b/esphome/components/dsmr/__init__.py @@ -60,7 +60,7 @@ CONFIG_SCHEMA = cv.All( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: uart_component = await cg.get_variable(config[CONF_UART_ID]) if CONF_REQUEST_PIN in config: request_pin = await cg.gpio_pin_expression(config[CONF_REQUEST_PIN]) diff --git a/esphome/components/dsmr/sensor.py b/esphome/components/dsmr/sensor.py index 7d93ee62e1..6aecc62d6b 100644 --- a/esphome/components/dsmr/sensor.py +++ b/esphome/components/dsmr/sensor.py @@ -27,6 +27,7 @@ from esphome.const import ( UNIT_SECOND, UNIT_VOLT, ) +from esphome.types import ConfigType from . import CONF_DSMR_ID, Dsmr @@ -812,7 +813,7 @@ CONFIG_SCHEMA = cv.Schema( ).extend(cv.COMPONENT_SCHEMA) -async def to_code(config): +async def to_code(config: ConfigType) -> None: hub = await cg.get_variable(config[CONF_DSMR_ID]) sensors = [] diff --git a/esphome/components/dsmr/text_sensor.py b/esphome/components/dsmr/text_sensor.py index 54b5711923..4945ba965c 100644 --- a/esphome/components/dsmr/text_sensor.py +++ b/esphome/components/dsmr/text_sensor.py @@ -2,6 +2,7 @@ import esphome.codegen as cg from esphome.components import text_sensor import esphome.config_validation as cv from esphome.const import CONF_INTERNAL +from esphome.types import ConfigType from . import CONF_DSMR_ID, Dsmr @@ -39,7 +40,7 @@ CONFIG_SCHEMA = cv.Schema( ).extend(cv.COMPONENT_SCHEMA) -async def to_code(config): +async def to_code(config: ConfigType) -> None: hub = await cg.get_variable(config[CONF_DSMR_ID]) text_sensors = [] diff --git a/esphome/components/duty_cycle/sensor.py b/esphome/components/duty_cycle/sensor.py index 37c889cd85..b7aa1777c8 100644 --- a/esphome/components/duty_cycle/sensor.py +++ b/esphome/components/duty_cycle/sensor.py @@ -3,6 +3,7 @@ import esphome.codegen as cg from esphome.components import sensor import esphome.config_validation as cv from esphome.const import CONF_PIN, ICON_PERCENT, STATE_CLASS_MEASUREMENT, UNIT_PERCENT +from esphome.types import ConfigType duty_cycle_ns = cg.esphome_ns.namespace("duty_cycle") DutyCycleSensor = duty_cycle_ns.class_( @@ -22,7 +23,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await sensor.new_sensor(config) await cg.register_component(var, config) diff --git a/esphome/components/e131/__init__.py b/esphome/components/e131/__init__.py index a1a8e0aec5..3b1eb99e60 100644 --- a/esphome/components/e131/__init__.py +++ b/esphome/components/e131/__init__.py @@ -3,6 +3,9 @@ from esphome.components.light.effects import register_addressable_effect from esphome.components.light.types import AddressableLightEffect import esphome.config_validation as cv from esphome.const import CONF_CHANNELS, CONF_ID, CONF_METHOD, CONF_NAME +from esphome.core import ID +from esphome.cpp_generator import MockObj +from esphome.types import ConfigType AUTO_LOAD = ["socket"] DEPENDENCIES = ["network"] @@ -32,7 +35,7 @@ CONFIG_SCHEMA = cv.Schema( ).extend(cv.COMPONENT_SCHEMA) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) cg.add(var.set_method(METHODS[config[CONF_METHOD]])) @@ -48,7 +51,7 @@ async def to_code(config): cv.Optional(CONF_CHANNELS, default="RGB"): cv.one_of(*CHANNELS, upper=True), }, ) -async def e131_light_effect_to_code(config, effect_id): +async def e131_light_effect_to_code(config: ConfigType, effect_id: ID) -> MockObj: parent = await cg.get_variable(config[CONF_E131_ID]) effect = cg.new_Pvariable(effect_id, config[CONF_NAME]) diff --git a/esphome/components/ee895/sensor.py b/esphome/components/ee895/sensor.py index 8c9c7e7238..fdad47fb05 100644 --- a/esphome/components/ee895/sensor.py +++ b/esphome/components/ee895/sensor.py @@ -14,6 +14,7 @@ from esphome.const import ( UNIT_HECTOPASCAL, UNIT_PARTS_PER_MILLION, ) +from esphome.types import ConfigType CODEOWNERS = ["@Stock-M"] @@ -51,7 +52,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/ektf2232/touchscreen/__init__.py b/esphome/components/ektf2232/touchscreen/__init__.py index 64bb17a7db..7636b6993a 100644 --- a/esphome/components/ektf2232/touchscreen/__init__.py +++ b/esphome/components/ektf2232/touchscreen/__init__.py @@ -3,6 +3,7 @@ import esphome.codegen as cg from esphome.components import i2c, touchscreen import esphome.config_validation as cv from esphome.const import CONF_ID, CONF_INTERRUPT_PIN, CONF_RESET_PIN +from esphome.types import ConfigType CODEOWNERS = ["@jesserockz"] DEPENDENCIES = ["i2c"] @@ -29,7 +30,7 @@ CONFIG_SCHEMA = touchscreen.TOUCHSCREEN_SCHEMA.extend( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await touchscreen.register_touchscreen(var, config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/emmeti/climate.py b/esphome/components/emmeti/climate.py index 56e8e2b804..ea44606300 100644 --- a/esphome/components/emmeti/climate.py +++ b/esphome/components/emmeti/climate.py @@ -1,5 +1,6 @@ import esphome.codegen as cg from esphome.components import climate_ir +from esphome.types import ConfigType CODEOWNERS = ["@E440QF"] AUTO_LOAD = ["climate_ir"] @@ -10,5 +11,5 @@ EmmetiClimate = emmeti_ns.class_("EmmetiClimate", climate_ir.ClimateIR) CONFIG_SCHEMA = climate_ir.climate_ir_with_receiver_schema(EmmetiClimate) -async def to_code(config): +async def to_code(config: ConfigType) -> None: await climate_ir.new_climate_ir(config) diff --git a/esphome/components/endstop/cover.py b/esphome/components/endstop/cover.py index c16680b6af..0e27189500 100644 --- a/esphome/components/endstop/cover.py +++ b/esphome/components/endstop/cover.py @@ -12,6 +12,7 @@ from esphome.const import ( CONF_OPEN_ENDSTOP, CONF_STOP_ACTION, ) +from esphome.types import ConfigType endstop_ns = cg.esphome_ns.namespace("endstop") EndstopCover = endstop_ns.class_("EndstopCover", cover.Cover, cg.Component) @@ -34,7 +35,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await cover.new_cover(config) await cg.register_component(var, config) diff --git a/esphome/components/ens160_base/__init__.py b/esphome/components/ens160_base/__init__.py index 46c53c3b10..1bdfb0c0a6 100644 --- a/esphome/components/ens160_base/__init__.py +++ b/esphome/components/ens160_base/__init__.py @@ -18,6 +18,8 @@ from esphome.const import ( UNIT_PARTS_PER_BILLION, UNIT_PARTS_PER_MILLION, ) +from esphome.cpp_generator import MockObj +from esphome.types import ConfigType CODEOWNERS = ["@vincentscode", "@latonita"] @@ -57,7 +59,7 @@ CONFIG_SCHEMA_BASE = cv.Schema( ).extend(cv.polling_component_schema("60s")) -async def to_code_base(config): +async def to_code_base(config: ConfigType) -> MockObj: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) diff --git a/esphome/components/ens160_i2c/sensor.py b/esphome/components/ens160_i2c/sensor.py index cad4e81afc..398b9b4804 100644 --- a/esphome/components/ens160_i2c/sensor.py +++ b/esphome/components/ens160_i2c/sensor.py @@ -1,5 +1,6 @@ import esphome.codegen as cg from esphome.components import i2c +from esphome.types import ConfigType from ..ens160_base import CONFIG_SCHEMA_BASE, cv, to_code_base @@ -18,6 +19,6 @@ CONFIG_SCHEMA = CONFIG_SCHEMA_BASE.extend( ).extend({cv.GenerateID(): cv.declare_id(ENS160I2CComponent)}) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await to_code_base(config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/ens160_spi/sensor.py b/esphome/components/ens160_spi/sensor.py index 1bda05c7bb..cc6a90a33e 100644 --- a/esphome/components/ens160_spi/sensor.py +++ b/esphome/components/ens160_spi/sensor.py @@ -1,5 +1,6 @@ import esphome.codegen as cg from esphome.components import spi +from esphome.types import ConfigType from ..ens160_base import CONFIG_SCHEMA_BASE, cv, to_code_base @@ -18,6 +19,6 @@ CONFIG_SCHEMA = CONFIG_SCHEMA_BASE.extend(spi.spi_device_schema()).extend( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await to_code_base(config) await spi.register_spi_device(var, config) diff --git a/esphome/components/ens210/sensor.py b/esphome/components/ens210/sensor.py index 289a559673..bfd758f92f 100644 --- a/esphome/components/ens210/sensor.py +++ b/esphome/components/ens210/sensor.py @@ -11,6 +11,7 @@ from esphome.const import ( UNIT_CELSIUS, UNIT_PERCENT, ) +from esphome.types import ConfigType CODEOWNERS = ["@itn3rd77"] DEPENDENCIES = ["i2c"] @@ -44,7 +45,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/es7210/audio_adc.py b/esphome/components/es7210/audio_adc.py index f0bd8bc25a..2defdb0c35 100644 --- a/esphome/components/es7210/audio_adc.py +++ b/esphome/components/es7210/audio_adc.py @@ -3,6 +3,7 @@ from esphome.components import i2c from esphome.components.audio_adc import AudioAdc import esphome.config_validation as cv from esphome.const import CONF_BITS_PER_SAMPLE, CONF_ID, CONF_MIC_GAIN, CONF_SAMPLE_RATE +from esphome.types import ConfigType CODEOWNERS = ["@kahrendt"] DEPENDENCIES = ["i2c"] @@ -41,7 +42,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/es7243e/audio_adc.py b/esphome/components/es7243e/audio_adc.py index c305d60172..4916133982 100644 --- a/esphome/components/es7243e/audio_adc.py +++ b/esphome/components/es7243e/audio_adc.py @@ -3,6 +3,7 @@ from esphome.components import i2c from esphome.components.audio_adc import AudioAdc import esphome.config_validation as cv from esphome.const import CONF_ID, CONF_MIC_GAIN +from esphome.types import ConfigType CODEOWNERS = ["@kbx81"] DEPENDENCIES = ["i2c"] @@ -26,7 +27,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/es8156/audio_dac.py b/esphome/components/es8156/audio_dac.py index c5fb6096da..305aa92125 100644 --- a/esphome/components/es8156/audio_dac.py +++ b/esphome/components/es8156/audio_dac.py @@ -4,6 +4,7 @@ from esphome.components.audio_dac import AudioDac import esphome.config_validation as cv from esphome.const import CONF_AUDIO_DAC, CONF_BITS_PER_SAMPLE, CONF_ID import esphome.final_validate as fv +from esphome.types import ConfigType CODEOWNERS = ["@kbx81"] DEPENDENCIES = ["i2c"] @@ -22,7 +23,7 @@ CONFIG_SCHEMA = ( ) -def _final_validate(config): +def _final_validate(config: ConfigType) -> None: full_config = fv.full_config.get() # Check all speaker configurations for ones that reference this es8156 @@ -45,7 +46,7 @@ def _final_validate(config): FINAL_VALIDATE_SCHEMA = _final_validate -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/es8311/audio_dac.py b/esphome/components/es8311/audio_dac.py index 5941a81935..f9cfb822cc 100644 --- a/esphome/components/es8311/audio_dac.py +++ b/esphome/components/es8311/audio_dac.py @@ -3,6 +3,7 @@ from esphome.components import i2c from esphome.components.audio_dac import AudioDac import esphome.config_validation as cv from esphome.const import CONF_BITS_PER_SAMPLE, CONF_ID, CONF_MIC_GAIN, CONF_SAMPLE_RATE +from esphome.types import ConfigType CODEOWNERS = ["@kroimon", "@kahrendt"] DEPENDENCIES = ["i2c"] @@ -55,7 +56,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/es8388/audio_dac.py b/esphome/components/es8388/audio_dac.py index 77e07b2e01..2616cbfa53 100644 --- a/esphome/components/es8388/audio_dac.py +++ b/esphome/components/es8388/audio_dac.py @@ -3,6 +3,7 @@ from esphome.components import i2c from esphome.components.audio_dac import AudioDac import esphome.config_validation as cv from esphome.const import CONF_ID +from esphome.types import ConfigType CODEOWNERS = ["@P4uLT"] CONF_ES8388_ID = "es8388_id" @@ -20,7 +21,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/es8388/select/__init__.py b/esphome/components/es8388/select/__init__.py index 068d9f9fb8..b81bcd13cf 100644 --- a/esphome/components/es8388/select/__init__.py +++ b/esphome/components/es8388/select/__init__.py @@ -2,6 +2,7 @@ import esphome.codegen as cg from esphome.components import select import esphome.config_validation as cv from esphome.const import ENTITY_CATEGORY_CONFIG, ICON_CHIP # noqa: F401 +from esphome.types import ConfigType from ..audio_dac import CONF_ES8388_ID, ES8388, es8388_ns @@ -28,7 +29,7 @@ CONFIG_SCHEMA = cv.All( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: parent = await cg.get_variable(config[CONF_ES8388_ID]) if dac_output_config := config.get(CONF_DAC_OUTPUT): s = await select.new_select( diff --git a/esphome/components/esp32_ble_beacon/__init__.py b/esphome/components/esp32_ble_beacon/__init__.py index d762255040..e9c44284e4 100644 --- a/esphome/components/esp32_ble_beacon/__init__.py +++ b/esphome/components/esp32_ble_beacon/__init__.py @@ -5,6 +5,7 @@ from esphome.components.esp32_ble import CONF_BLE_ID import esphome.config_validation as cv from esphome.const import CONF_ID, CONF_TX_POWER, CONF_TYPE, CONF_UUID from esphome.core import TimePeriod +from esphome.types import ConfigType AUTO_LOAD = ["esp32_ble"] DEPENDENCIES = ["esp32"] @@ -18,7 +19,7 @@ CONF_MAX_INTERVAL = "max_interval" CONF_MEASURED_POWER = "measured_power" -def validate_config(config): +def validate_config(config: ConfigType) -> ConfigType: if config[CONF_MIN_INTERVAL] > config.get(CONF_MAX_INTERVAL): raise cv.Invalid("min_interval must be <= max_interval") return config @@ -61,7 +62,7 @@ CONFIG_SCHEMA = cv.All( FINAL_VALIDATE_SCHEMA = esp32_ble.validate_variant -async def to_code(config): +async def to_code(config: ConfigType) -> None: cg.add_define("USE_ESP32_BLE_UUID") uuid = config[CONF_UUID].hex diff --git a/esphome/components/esp32_camera/__init__.py b/esphome/components/esp32_camera/__init__.py index c3b35a8279..3c41d22903 100644 --- a/esphome/components/esp32_camera/__init__.py +++ b/esphome/components/esp32_camera/__init__.py @@ -1,4 +1,5 @@ import logging +from typing import Any from esphome import automation, pins import esphome.codegen as cg @@ -24,6 +25,7 @@ from esphome.const import ( ) from esphome.core import CORE from esphome.core.entity_helpers import setup_entity +from esphome.cpp_generator import MockObj import esphome.final_validate as fv from esphome.types import ConfigType @@ -179,7 +181,7 @@ CONF_ON_IMAGE = "on_image" camera_range_param = cv.int_range(min=-2, max=2) -def validate_fb_location_(value): +def validate_fb_location_(value: Any) -> MockObj: validator = cv.enum(ENUM_FB_LOCATION, upper=True) if value.lower() == psram_domain: validator = cv.All(validator, cv.requires_component(psram_domain)) @@ -310,7 +312,7 @@ CONFIG_SCHEMA = cv.All( ) -def _final_validate(config): +def _final_validate(config: ConfigType) -> None: # Check psram requirement for non-JPEG formats if ( config.get(CONF_PIXEL_FORMAT, "JPEG") != "JPEG" @@ -368,7 +370,7 @@ SETTERS = { } -async def to_code(config): +async def to_code(config: ConfigType) -> None: cg.add_define("USE_CAMERA") var = cg.new_Pvariable(config[CONF_ID]) await setup_entity(var, config, "camera") diff --git a/esphome/components/esp32_camera_web_server/__init__.py b/esphome/components/esp32_camera_web_server/__init__.py index da260ad7a1..55ace66681 100644 --- a/esphome/components/esp32_camera_web_server/__init__.py +++ b/esphome/components/esp32_camera_web_server/__init__.py @@ -39,7 +39,7 @@ CONFIG_SCHEMA = cv.All( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: server = cg.new_Pvariable(config[CONF_ID]) cg.add(server.set_port(config[CONF_PORT])) cg.add(server.set_mode(config[CONF_MODE])) diff --git a/esphome/components/esp32_can/canbus.py b/esphome/components/esp32_can/canbus.py index 7245ba7513..2272459fb8 100644 --- a/esphome/components/esp32_can/canbus.py +++ b/esphome/components/esp32_can/canbus.py @@ -1,4 +1,5 @@ import math +from typing import Any from esphome import pins import esphome.codegen as cg @@ -26,6 +27,7 @@ from esphome.const import ( CONF_TX_PIN, CONF_TX_QUEUE_LEN, ) +from esphome.types import ConfigType CODEOWNERS = ["@Sympatron"] DEPENDENCIES = ["esp32"] @@ -88,7 +90,7 @@ CAN_SPEEDS = { } -def validate_bit_rate(value): +def validate_bit_rate(value: Any) -> str: variant = get_esp32_variant() if variant not in CAN_SPEEDS: raise cv.Invalid(f"{variant} is not supported by component {esp32_can_ns}") @@ -112,7 +114,7 @@ CONFIG_SCHEMA = canbus.CANBUS_SCHEMA.extend( ) -def get_default_tx_enqueue_timeout(bit_rate): +def get_default_tx_enqueue_timeout(bit_rate: str) -> int: bit_rate_numeric = canbus.get_rate(bit_rate) bits_per_packet = 140 # ~max CAN message length ms_per_packet = bits_per_packet / bit_rate_numeric * 1000 @@ -121,7 +123,7 @@ def get_default_tx_enqueue_timeout(bit_rate): ) # ~10 packet lengths, min 1ms, max 1000ms -async def to_code(config): +async def to_code(config: ConfigType) -> None: # Legacy driver component provides driver/twai.h header include_builtin_idf_component("driver") # Also enable esp_driver_twai for future migration to new API diff --git a/esphome/components/esp32_dac/output.py b/esphome/components/esp32_dac/output.py index 7c63d7bd11..c87a9e2a1d 100644 --- a/esphome/components/esp32_dac/output.py +++ b/esphome/components/esp32_dac/output.py @@ -9,6 +9,7 @@ from esphome.components.esp32 import ( ) import esphome.config_validation as cv from esphome.const import CONF_ID, CONF_NUMBER, CONF_PIN +from esphome.types import ConfigType DEPENDENCIES = ["esp32"] @@ -18,7 +19,7 @@ DAC_PINS = { } -def valid_dac_pin(value): +def valid_dac_pin(value: ConfigType) -> ConfigType: variant = get_esp32_variant() try: valid_pins = DAC_PINS[variant] @@ -42,7 +43,7 @@ CONFIG_SCHEMA = output.FLOAT_OUTPUT_SCHEMA.extend( ).extend(cv.COMPONENT_SCHEMA) -async def to_code(config): +async def to_code(config: ConfigType) -> None: include_builtin_idf_component("esp_driver_dac") var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) diff --git a/esphome/components/esp32_improv/__init__.py b/esphome/components/esp32_improv/__init__.py index ad2f057163..32eb166014 100644 --- a/esphome/components/esp32_improv/__init__.py +++ b/esphome/components/esp32_improv/__init__.py @@ -4,6 +4,7 @@ from esphome.components import binary_sensor, esp32_ble, improv_base, output from esphome.components.esp32_ble import BTLoggers import esphome.config_validation as cv from esphome.const import CONF_ID, CONF_ON_START, CONF_ON_STATE, CONF_TRIGGER_ID +from esphome.types import ConfigType AUTO_LOAD = ["esp32_ble_server", "improv_base"] CODEOWNERS = ["@jesserockz"] @@ -106,7 +107,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: # Register the loggers this component needs esp32_ble.register_bt_logger(BTLoggers.GATT, BTLoggers.SMP) diff --git a/esphome/components/esphome/ota/__init__.py b/esphome/components/esphome/ota/__init__.py index d5f4efbc02..3ef4c7ba13 100644 --- a/esphome/components/esphome/ota/__init__.py +++ b/esphome/components/esphome/ota/__init__.py @@ -37,7 +37,7 @@ esphome = cg.esphome_ns.namespace("esphome") ESPHomeOTAComponent = esphome.class_("ESPHomeOTAComponent", OTAComponent) -def ota_esphome_final_validate(config): +def ota_esphome_final_validate(config: ConfigType) -> None: full_conf = fv.full_config.get() full_ota_conf = full_conf[CONF_OTA] new_ota_conf = [] diff --git a/esphome/components/ethernet_info/text_sensor.py b/esphome/components/ethernet_info/text_sensor.py index 8c20cf332c..66483cdb85 100644 --- a/esphome/components/ethernet_info/text_sensor.py +++ b/esphome/components/ethernet_info/text_sensor.py @@ -7,6 +7,7 @@ from esphome.const import ( CONF_MAC_ADDRESS, ENTITY_CATEGORY_DIAGNOSTIC, ) +from esphome.types import ConfigType DEPENDENCIES = ["ethernet"] @@ -46,7 +47,7 @@ CONFIG_SCHEMA = cv.Schema( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: # Request Ethernet IP state listener slots - one per sensor type if CONF_IP_ADDRESS in config: ethernet.request_ethernet_ip_state_listener() diff --git a/esphome/components/exposure_notifications/__init__.py b/esphome/components/exposure_notifications/__init__.py index 6cb5b750dd..4f7e698e23 100644 --- a/esphome/components/exposure_notifications/__init__.py +++ b/esphome/components/exposure_notifications/__init__.py @@ -58,7 +58,7 @@ CONFIG_SCHEMA = cv.Schema( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: for conf in config.get(CONF_ON_EXPOSURE_NOTIFICATION, []): trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID]) await automation.build_automation(trigger, [(ExposureNotification, "x")], conf) diff --git a/esphome/components/ezo/sensor.py b/esphome/components/ezo/sensor.py index b931885149..d1ee57a09b 100644 --- a/esphome/components/ezo/sensor.py +++ b/esphome/components/ezo/sensor.py @@ -3,6 +3,7 @@ import esphome.codegen as cg from esphome.components import i2c, sensor import esphome.config_validation as cv from esphome.const import CONF_ID +from esphome.types import ConfigType CODEOWNERS = ["@ssieb"] @@ -58,7 +59,7 @@ _CALLBACK_AUTOMATIONS = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await sensor.register_sensor(var, config) diff --git a/esphome/components/fastled_base/__init__.py b/esphome/components/fastled_base/__init__.py index a26a235da7..e2fc8578cd 100644 --- a/esphome/components/fastled_base/__init__.py +++ b/esphome/components/fastled_base/__init__.py @@ -8,6 +8,8 @@ from esphome.const import ( CONF_RGB_ORDER, ) from esphome.core import CORE +from esphome.cpp_generator import MockObj +from esphome.types import ConfigType CODEOWNERS = ["@OttoWinter"] fastled_base_ns = cg.esphome_ns.namespace("fastled_base") @@ -34,7 +36,7 @@ BASE_SCHEMA = light.ADDRESSABLE_LIGHT_SCHEMA.extend( ).extend(cv.COMPONENT_SCHEMA) -async def new_fastled_light(config): +async def new_fastled_light(config: ConfigType) -> MockObj: var = cg.new_Pvariable(config[CONF_OUTPUT_ID]) await cg.register_component(var, config) diff --git a/esphome/components/fastled_clockless/light.py b/esphome/components/fastled_clockless/light.py index aa2172bf88..56c1ee93fa 100644 --- a/esphome/components/fastled_clockless/light.py +++ b/esphome/components/fastled_clockless/light.py @@ -9,6 +9,7 @@ from esphome.const import ( CONF_RGB_ORDER, Framework, ) +from esphome.types import ConfigType AUTO_LOAD = ["fastled_base"] @@ -41,7 +42,7 @@ CHIPSETS = [ ] -def _validate(value): +def _validate(value: ConfigType) -> ConfigType: if value[CONF_CHIPSET] == "NEOPIXEL" and CONF_RGB_ORDER in value: raise cv.Invalid("NEOPIXEL doesn't support RGB order") return value @@ -73,7 +74,7 @@ CONFIG_SCHEMA = cv.All( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await fastled_base.new_fastled_light(config) rgb_order = None diff --git a/esphome/components/fastled_spi/light.py b/esphome/components/fastled_spi/light.py index e863d33846..1c6b6e7148 100644 --- a/esphome/components/fastled_spi/light.py +++ b/esphome/components/fastled_spi/light.py @@ -11,6 +11,7 @@ from esphome.const import ( CONF_RGB_ORDER, Framework, ) +from esphome.types import ConfigType AUTO_LOAD = ["fastled_base"] @@ -52,7 +53,7 @@ CONFIG_SCHEMA = cv.All( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await fastled_base.new_fastled_light(config) rgb_order = cg.RawExpression(config.get(CONF_RGB_ORDER, "RGB")) diff --git a/esphome/components/feedback/cover.py b/esphome/components/feedback/cover.py index 856818280f..032d01c8e5 100644 --- a/esphome/components/feedback/cover.py +++ b/esphome/components/feedback/cover.py @@ -14,6 +14,7 @@ from esphome.const import ( CONF_STOP_ACTION, CONF_UPDATE_INTERVAL, ) +from esphome.types import ConfigType CONF_OPEN_SENSOR = "open_sensor" CONF_CLOSE_SENSOR = "close_sensor" @@ -29,7 +30,7 @@ endstop_ns = cg.esphome_ns.namespace("feedback") FeedbackCover = endstop_ns.class_("FeedbackCover", cover.Cover, cg.Component) -def validate_infer_endstop(config): +def validate_infer_endstop(config: ConfigType) -> ConfigType: if config[CONF_INFER_ENDSTOP_FROM_MOVEMENT] is True: if config[CONF_HAS_BUILT_IN_ENDSTOP] is False: raise cv.Invalid( @@ -95,7 +96,7 @@ CONFIG_SCHEMA = cv.All( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await cover.new_cover(config) await cg.register_component(var, config) diff --git a/esphome/components/fs3000/sensor.py b/esphome/components/fs3000/sensor.py index a168a36c31..8c389a2593 100644 --- a/esphome/components/fs3000/sensor.py +++ b/esphome/components/fs3000/sensor.py @@ -4,6 +4,7 @@ import esphome.codegen as cg from esphome.components import i2c, sensor import esphome.config_validation as cv from esphome.const import CONF_MODEL, DEVICE_CLASS_WIND_SPEED, STATE_CLASS_MEASUREMENT +from esphome.types import ConfigType DEPENDENCIES = ["i2c"] CODEOWNERS = ["@kahrendt"] @@ -38,7 +39,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await sensor.new_sensor(config) await cg.register_component(var, config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/ft5x06/touchscreen/__init__.py b/esphome/components/ft5x06/touchscreen/__init__.py index e94791da4e..3ebff693c0 100644 --- a/esphome/components/ft5x06/touchscreen/__init__.py +++ b/esphome/components/ft5x06/touchscreen/__init__.py @@ -3,6 +3,7 @@ import esphome.codegen as cg from esphome.components import i2c, touchscreen import esphome.config_validation as cv from esphome.const import CONF_ID, CONF_INTERRUPT_PIN +from esphome.types import ConfigType from .. import ft5x06_ns @@ -22,7 +23,7 @@ CONFIG_SCHEMA = touchscreen.TOUCHSCREEN_SCHEMA.extend( ).extend(i2c.i2c_device_schema(0x48)) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await i2c.register_i2c_device(var, config) await touchscreen.register_touchscreen(var, config) diff --git a/esphome/components/ft63x6/touchscreen.py b/esphome/components/ft63x6/touchscreen.py index 7615b3046f..0d8537bde9 100644 --- a/esphome/components/ft63x6/touchscreen.py +++ b/esphome/components/ft63x6/touchscreen.py @@ -3,6 +3,7 @@ import esphome.codegen as cg from esphome.components import i2c, touchscreen import esphome.config_validation as cv from esphome.const import CONF_ID, CONF_INTERRUPT_PIN, CONF_RESET_PIN, CONF_THRESHOLD +from esphome.types import ConfigType CODEOWNERS = ["@gpambrozio"] DEPENDENCIES = ["i2c"] @@ -31,7 +32,7 @@ CONFIG_SCHEMA = touchscreen.TOUCHSCREEN_SCHEMA.extend( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await touchscreen.register_touchscreen(var, config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/fujitsu_general/climate.py b/esphome/components/fujitsu_general/climate.py index a104eafbcc..c2c41730e3 100644 --- a/esphome/components/fujitsu_general/climate.py +++ b/esphome/components/fujitsu_general/climate.py @@ -1,5 +1,6 @@ import esphome.codegen as cg from esphome.components import climate_ir +from esphome.types import ConfigType AUTO_LOAD = ["climate_ir"] @@ -11,5 +12,5 @@ FujitsuGeneralClimate = fujitsu_general_ns.class_( CONFIG_SCHEMA = climate_ir.climate_ir_with_receiver_schema(FujitsuGeneralClimate) -async def to_code(config): +async def to_code(config: ConfigType) -> None: await climate_ir.new_climate_ir(config) diff --git a/esphome/components/gcja5/sensor.py b/esphome/components/gcja5/sensor.py index e4de7721c6..49907443ff 100644 --- a/esphome/components/gcja5/sensor.py +++ b/esphome/components/gcja5/sensor.py @@ -18,6 +18,7 @@ from esphome.const import ( STATE_CLASS_MEASUREMENT, UNIT_MICROGRAMS_PER_CUBIC_METER, ) +from esphome.types import ConfigType CODEOWNERS = ["@gcormier"] DEPENDENCIES = ["uart"] @@ -111,7 +112,7 @@ TYPES = { } -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await uart.register_uart_device(var, config) diff --git a/esphome/components/gl_r01_i2c/sensor.py b/esphome/components/gl_r01_i2c/sensor.py index 6a8d47213c..73f7339e66 100644 --- a/esphome/components/gl_r01_i2c/sensor.py +++ b/esphome/components/gl_r01_i2c/sensor.py @@ -7,6 +7,7 @@ from esphome.const import ( STATE_CLASS_MEASUREMENT, UNIT_MILLIMETER, ) +from esphome.types import ConfigType CODEOWNERS = ["@pkejval"] DEPENDENCIES = ["i2c"] @@ -29,7 +30,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await sensor.register_sensor(var, config) diff --git a/esphome/components/gp2y1010au0f/sensor.py b/esphome/components/gp2y1010au0f/sensor.py index 4ff8a38226..3121aa1de5 100644 --- a/esphome/components/gp2y1010au0f/sensor.py +++ b/esphome/components/gp2y1010au0f/sensor.py @@ -9,6 +9,7 @@ from esphome.const import ( STATE_CLASS_MEASUREMENT, UNIT_MICROGRAMS_PER_CUBIC_METER, ) +from esphome.types import ConfigType DEPENDENCIES = ["output"] AUTO_LOAD = ["voltage_sampler"] @@ -43,7 +44,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await sensor.new_sensor(config) await cg.register_component(var, config) diff --git a/esphome/components/gp8403/__init__.py b/esphome/components/gp8403/__init__.py index 83859a4030..17c88b6875 100644 --- a/esphome/components/gp8403/__init__.py +++ b/esphome/components/gp8403/__init__.py @@ -2,6 +2,7 @@ import esphome.codegen as cg from esphome.components import i2c import esphome.config_validation as cv from esphome.const import CONF_ID, CONF_MODEL, CONF_VOLTAGE +from esphome.types import ConfigType CODEOWNERS = ["@jesserockz", "@sebydocky"] DEPENDENCIES = ["i2c"] @@ -38,7 +39,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/gp8403/output/__init__.py b/esphome/components/gp8403/output/__init__.py index 5245c405db..432f387b1b 100644 --- a/esphome/components/gp8403/output/__init__.py +++ b/esphome/components/gp8403/output/__init__.py @@ -2,6 +2,7 @@ import esphome.codegen as cg from esphome.components import i2c, output import esphome.config_validation as cv from esphome.const import CONF_CHANNEL, CONF_ID +from esphome.types import ConfigType from .. import CONF_GP8403_ID, GP8403Component, gp8403_ns @@ -20,7 +21,7 @@ CONFIG_SCHEMA = output.FLOAT_OUTPUT_SCHEMA.extend( ).extend(cv.COMPONENT_SCHEMA) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await output.register_output(var, config) diff --git a/esphome/components/gps/__init__.py b/esphome/components/gps/__init__.py index ab48417a4e..94a36a0afa 100644 --- a/esphome/components/gps/__init__.py +++ b/esphome/components/gps/__init__.py @@ -16,6 +16,7 @@ from esphome.const import ( UNIT_KILOMETER_PER_HOUR, UNIT_METER, ) +from esphome.types import ConfigType CONF_GPS_ID = "gps_id" CONF_HDOP = "hdop" @@ -93,7 +94,7 @@ CONFIG_SCHEMA = cv.All( FINAL_VALIDATE_SCHEMA = uart.final_validate_device_schema("gps", require_rx=True) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await uart.register_uart_device(var, config) diff --git a/esphome/components/gps/time/__init__.py b/esphome/components/gps/time/__init__.py index bdeeb86e00..faa06e6ae3 100644 --- a/esphome/components/gps/time/__init__.py +++ b/esphome/components/gps/time/__init__.py @@ -2,6 +2,7 @@ import esphome.codegen as cg from esphome.components import time as time_ import esphome.config_validation as cv from esphome.const import CONF_ID +from esphome.types import ConfigType from .. import CONF_GPS_ID, GPS, GPSListener, gps_ns @@ -19,7 +20,7 @@ CONFIG_SCHEMA = time_.TIME_SCHEMA.extend( ).extend(cv.polling_component_schema("5min")) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await time_.register_time(var, config) await cg.register_component(var, config) diff --git a/esphome/components/graphical_display_menu/__init__.py b/esphome/components/graphical_display_menu/__init__.py index 56b720e75c..668a0d74d1 100644 --- a/esphome/components/graphical_display_menu/__init__.py +++ b/esphome/components/graphical_display_menu/__init__.py @@ -15,6 +15,7 @@ from esphome.const import ( CONF_ID, CONF_TRIGGER_ID, ) +from esphome.types import ConfigType CONF_MENU_ITEM_VALUE = "menu_item_value" CONF_ON_REDRAW = "on_redraw" @@ -59,7 +60,7 @@ CONFIG_SCHEMA = DISPLAY_MENU_BASE_SCHEMA.extend( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) diff --git a/esphome/components/gree/climate.py b/esphome/components/gree/climate.py index 0892155fd2..356845a7a6 100644 --- a/esphome/components/gree/climate.py +++ b/esphome/components/gree/climate.py @@ -2,6 +2,7 @@ import esphome.codegen as cg from esphome.components import climate_ir import esphome.config_validation as cv from esphome.const import CONF_MODEL +from esphome.types import ConfigType from . import gree_ns @@ -28,6 +29,6 @@ CONFIG_SCHEMA = climate_ir.climate_ir_with_receiver_schema(GreeClimate).extend( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await climate_ir.new_climate_ir(config) cg.add(var.set_model(config[CONF_MODEL])) diff --git a/esphome/components/gree/switch/__init__.py b/esphome/components/gree/switch/__init__.py index 111fea65d2..9bec3751d6 100644 --- a/esphome/components/gree/switch/__init__.py +++ b/esphome/components/gree/switch/__init__.py @@ -3,6 +3,7 @@ from esphome.components import switch import esphome.config_validation as cv from esphome.const import CONF_LIGHT, DEVICE_CLASS_SWITCH, ENTITY_CATEGORY_CONFIG import esphome.final_validate as fv +from esphome.types import ConfigType from .. import gree_ns from ..climate import CONF_MODEL, GreeClimate @@ -48,7 +49,7 @@ CONFIG_SCHEMA = cv.Schema( ) -def _validate_model(config): +def _validate_model(config: ConfigType) -> None: full_config = fv.full_config.get() climate_path = full_config.get_path_for_id(config[CONF_GREE_ID])[:-1] climate_conf = full_config.get_config_for_path(climate_path) @@ -63,7 +64,7 @@ def _validate_model(config): FINAL_VALIDATE_SCHEMA = _validate_model -async def to_code(config): +async def to_code(config: ConfigType) -> None: parent = await cg.get_variable(config[CONF_GREE_ID]) for conf_key, name, bit_mask, _ in SWITCH_CONFIGS: diff --git a/esphome/components/grove_gas_mc_v2/sensor.py b/esphome/components/grove_gas_mc_v2/sensor.py index 0c35047850..da687c4cd3 100644 --- a/esphome/components/grove_gas_mc_v2/sensor.py +++ b/esphome/components/grove_gas_mc_v2/sensor.py @@ -18,6 +18,7 @@ from esphome.const import ( UNIT_MICROGRAMS_PER_CUBIC_METER, UNIT_PARTS_PER_MILLION, ) +from esphome.types import ConfigType CODEOWNERS = ["@YorkshireIoT"] DEPENDENCIES = ["i2c"] @@ -66,7 +67,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/growatt_solar/sensor.py b/esphome/components/growatt_solar/sensor.py index d62486f5ec..2e2b218730 100644 --- a/esphome/components/growatt_solar/sensor.py +++ b/esphome/components/growatt_solar/sensor.py @@ -170,7 +170,7 @@ def _final_validate(config: ConfigType) -> None: FINAL_VALIDATE_SCHEMA = _final_validate -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await modbus.register_modbus_client_device(var, config) diff --git a/esphome/components/gsl3670/touchscreen.py b/esphome/components/gsl3670/touchscreen.py index ccccf06d69..703887864b 100644 --- a/esphome/components/gsl3670/touchscreen.py +++ b/esphome/components/gsl3670/touchscreen.py @@ -174,7 +174,7 @@ def _extract_firmware_ref(entry: ConfigType) -> RemoteFile | None: PREFETCH_FILES = external_files.single_stage_prefetch(_extract_firmware_ref) -def _config_schema(config): +def _config_schema(config: ConfigType) -> ConfigType: model_option = { cv.Optional(CONF_MODEL, default="CUSTOM"): cv.one_of(*MODELS, upper=True) } @@ -206,7 +206,7 @@ def _config_schema(config): CONFIG_SCHEMA = _config_schema -def _read_firmware(config) -> bytes: +def _read_firmware(config: ConfigType) -> bytes: path = firmware_path(config[CONF_FIRMWARE]) data = path.read_bytes() LOGGER.info( @@ -221,7 +221,7 @@ def _read_firmware(config) -> bytes: # --------------------------------------------------------------------------- # Code generation # --------------------------------------------------------------------------- -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await touchscreen.register_touchscreen(var, config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/gt911/binary_sensor/__init__.py b/esphome/components/gt911/binary_sensor/__init__.py index 941b7bb847..95c072977e 100644 --- a/esphome/components/gt911/binary_sensor/__init__.py +++ b/esphome/components/gt911/binary_sensor/__init__.py @@ -2,6 +2,7 @@ import esphome.codegen as cg from esphome.components import binary_sensor import esphome.config_validation as cv from esphome.const import CONF_INDEX +from esphome.types import ConfigType from .. import gt911_ns from ..touchscreen import GT911ButtonListener, GT911Touchscreen @@ -24,7 +25,7 @@ CONFIG_SCHEMA = binary_sensor.binary_sensor_schema(GT911Button).extend( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await binary_sensor.new_binary_sensor(config) await cg.register_component(var, config) await cg.register_parented(var, config[CONF_GT911_ID]) diff --git a/esphome/components/gt911/touchscreen/__init__.py b/esphome/components/gt911/touchscreen/__init__.py index b850eeea8b..fa929d4ba0 100644 --- a/esphome/components/gt911/touchscreen/__init__.py +++ b/esphome/components/gt911/touchscreen/__init__.py @@ -3,6 +3,7 @@ import esphome.codegen as cg from esphome.components import i2c, touchscreen import esphome.config_validation as cv from esphome.const import CONF_ID, CONF_INTERRUPT_PIN, CONF_RESET_PIN +from esphome.types import ConfigType from .. import gt911_ns @@ -22,7 +23,7 @@ CONFIG_SCHEMA = touchscreen.TOUCHSCREEN_SCHEMA.extend( ).extend(i2c.i2c_device_schema(0x5D)) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await touchscreen.register_touchscreen(var, config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/havells_solar/sensor.py b/esphome/components/havells_solar/sensor.py index 8eafe1d9d6..dcea1afd04 100644 --- a/esphome/components/havells_solar/sensor.py +++ b/esphome/components/havells_solar/sensor.py @@ -224,7 +224,7 @@ def _final_validate(config: ConfigType) -> None: FINAL_VALIDATE_SCHEMA = _final_validate -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await modbus.register_modbus_client_device(var, config) diff --git a/esphome/components/hdc1080/sensor.py b/esphome/components/hdc1080/sensor.py index e47a88545b..b2b6dc533a 100644 --- a/esphome/components/hdc1080/sensor.py +++ b/esphome/components/hdc1080/sensor.py @@ -11,6 +11,7 @@ from esphome.const import ( UNIT_CELSIUS, UNIT_PERCENT, ) +from esphome.types import ConfigType DEPENDENCIES = ["i2c"] @@ -42,7 +43,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/hdc2010/sensor.py b/esphome/components/hdc2010/sensor.py index 15e19f2cc8..ad0311fb4f 100644 --- a/esphome/components/hdc2010/sensor.py +++ b/esphome/components/hdc2010/sensor.py @@ -11,6 +11,7 @@ from esphome.const import ( UNIT_CELSIUS, UNIT_PERCENT, ) +from esphome.types import ConfigType DEPENDENCIES = ["i2c"] @@ -42,7 +43,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/hdc2080/sensor.py b/esphome/components/hdc2080/sensor.py index 777fc51cba..b5388b4c2b 100644 --- a/esphome/components/hdc2080/sensor.py +++ b/esphome/components/hdc2080/sensor.py @@ -11,6 +11,7 @@ from esphome.const import ( UNIT_CELSIUS, UNIT_PERCENT, ) +from esphome.types import ConfigType DEPENDENCIES = ["i2c"] @@ -43,7 +44,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/he60r/cover.py b/esphome/components/he60r/cover.py index a3a1b19f5a..4cb635b047 100644 --- a/esphome/components/he60r/cover.py +++ b/esphome/components/he60r/cover.py @@ -2,6 +2,7 @@ import esphome.codegen as cg from esphome.components import cover, uart import esphome.config_validation as cv from esphome.const import CONF_CLOSE_DURATION, CONF_OPEN_DURATION +from esphome.types import ConfigType he60r_ns = cg.esphome_ns.namespace("he60r") HE60rCover = he60r_ns.class_("HE60rCover", cover.Cover, cg.Component) @@ -33,7 +34,7 @@ FINAL_VALIDATE_SCHEMA = uart.final_validate_device_schema( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await cover.new_cover(config) await cg.register_component(var, config) await uart.register_uart_device(var, config) diff --git a/esphome/components/heatpumpir/climate.py b/esphome/components/heatpumpir/climate.py index 21f7ea6393..2583839ca8 100644 --- a/esphome/components/heatpumpir/climate.py +++ b/esphome/components/heatpumpir/climate.py @@ -125,7 +125,7 @@ CONFIG_SCHEMA = cv.All( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await climate_ir.new_climate_ir(config) cg.add(var.set_protocol(config[CONF_PROTOCOL])) cg.add(var.set_horizontal_default(config[CONF_HORIZONTAL_DEFAULT])) diff --git a/esphome/components/hitachi_ac344/climate.py b/esphome/components/hitachi_ac344/climate.py index ebdf4e8db4..15da73b79c 100644 --- a/esphome/components/hitachi_ac344/climate.py +++ b/esphome/components/hitachi_ac344/climate.py @@ -1,5 +1,6 @@ import esphome.codegen as cg from esphome.components import climate_ir +from esphome.types import ConfigType AUTO_LOAD = ["climate_ir"] @@ -9,5 +10,5 @@ HitachiClimate = hitachi_ac344_ns.class_("HitachiClimate", climate_ir.ClimateIR) CONFIG_SCHEMA = climate_ir.climate_ir_with_receiver_schema(HitachiClimate) -async def to_code(config): +async def to_code(config: ConfigType) -> None: await climate_ir.new_climate_ir(config) diff --git a/esphome/components/hitachi_ac424/climate.py b/esphome/components/hitachi_ac424/climate.py index fde4e77545..d2a66223b1 100644 --- a/esphome/components/hitachi_ac424/climate.py +++ b/esphome/components/hitachi_ac424/climate.py @@ -1,5 +1,6 @@ import esphome.codegen as cg from esphome.components import climate_ir +from esphome.types import ConfigType AUTO_LOAD = ["climate_ir"] @@ -9,5 +10,5 @@ HitachiClimate = hitachi_ac424_ns.class_("HitachiClimate", climate_ir.ClimateIR) CONFIG_SCHEMA = climate_ir.climate_ir_with_receiver_schema(HitachiClimate) -async def to_code(config): +async def to_code(config: ConfigType) -> None: await climate_ir.new_climate_ir(config) diff --git a/esphome/components/hlw8012/sensor.py b/esphome/components/hlw8012/sensor.py index 1d793ac6b1..384477be3d 100644 --- a/esphome/components/hlw8012/sensor.py +++ b/esphome/components/hlw8012/sensor.py @@ -27,6 +27,7 @@ from esphome.const import ( UNIT_WATT_HOURS, ) from esphome.core import CORE +from esphome.types import ConfigType AUTO_LOAD = ["pulse_counter"] @@ -92,7 +93,7 @@ CONFIG_SCHEMA = cv.Schema( ).extend(cv.polling_component_schema("60s")) -async def to_code(config): +async def to_code(config: ConfigType) -> None: if CORE.is_esp32: include_builtin_idf_component("esp_driver_pcnt") diff --git a/esphome/components/hlw8032/sensor.py b/esphome/components/hlw8032/sensor.py index 846c9a398b..7b069d85d0 100644 --- a/esphome/components/hlw8032/sensor.py +++ b/esphome/components/hlw8032/sensor.py @@ -21,6 +21,7 @@ from esphome.const import ( UNIT_VOLT_AMPS, UNIT_WATT, ) +from esphome.types import ConfigType DEPENDENCIES = ["uart"] @@ -73,7 +74,7 @@ FINAL_VALIDATE_SCHEMA = uart.final_validate_device_schema( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await uart.register_uart_device(var, config) diff --git a/esphome/components/hm3301/sensor.py b/esphome/components/hm3301/sensor.py index 9546ae1c3c..2fa82b2710 100644 --- a/esphome/components/hm3301/sensor.py +++ b/esphome/components/hm3301/sensor.py @@ -17,6 +17,7 @@ from esphome.const import ( STATE_CLASS_MEASUREMENT, UNIT_MICROGRAMS_PER_CUBIC_METER, ) +from esphome.types import ConfigType _LOGGER = logging.getLogger(__name__) @@ -32,7 +33,7 @@ HM3301Component = hm3301_ns.class_( UNIT_INDEX = "index" -def _validate(config): +def _validate(config: ConfigType) -> ConfigType: if CONF_AQI in config and CONF_PM_2_5 not in config: raise cv.Invalid("AQI sensor requires PM 2.5") if CONF_AQI in config and CONF_PM_10_0 not in config: @@ -86,7 +87,7 @@ CONFIG_SCHEMA = cv.All( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/honeywell_hih_i2c/sensor.py b/esphome/components/honeywell_hih_i2c/sensor.py index 93ae2b6056..5250e1c1c7 100644 --- a/esphome/components/honeywell_hih_i2c/sensor.py +++ b/esphome/components/honeywell_hih_i2c/sensor.py @@ -11,6 +11,7 @@ from esphome.const import ( UNIT_CELSIUS, UNIT_PERCENT, ) +from esphome.types import ConfigType DEPENDENCIES = ["i2c"] @@ -42,7 +43,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/honeywellabp/sensor.py b/esphome/components/honeywellabp/sensor.py index 25d03d31a6..4b116f0f16 100644 --- a/esphome/components/honeywellabp/sensor.py +++ b/esphome/components/honeywellabp/sensor.py @@ -10,6 +10,7 @@ from esphome.const import ( STATE_CLASS_MEASUREMENT, UNIT_CELSIUS, ) +from esphome.types import ConfigType DEPENDENCIES = ["spi"] CODEOWNERS = ["@RubyBailey"] @@ -50,7 +51,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await spi.register_spi_device(var, config) diff --git a/esphome/components/honeywellabp2_i2c/sensor.py b/esphome/components/honeywellabp2_i2c/sensor.py index 2708e5d423..299acd4b52 100644 --- a/esphome/components/honeywellabp2_i2c/sensor.py +++ b/esphome/components/honeywellabp2_i2c/sensor.py @@ -10,6 +10,7 @@ from esphome.const import ( STATE_CLASS_MEASUREMENT, UNIT_CELSIUS, ) +from esphome.types import ConfigType DEPENDENCIES = ["i2c"] @@ -57,7 +58,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/hrxl_maxsonar_wr/sensor.py b/esphome/components/hrxl_maxsonar_wr/sensor.py index d335d76dfa..e4daacd869 100644 --- a/esphome/components/hrxl_maxsonar_wr/sensor.py +++ b/esphome/components/hrxl_maxsonar_wr/sensor.py @@ -5,6 +5,7 @@ from esphome.const import ( STATE_CLASS_MEASUREMENT, UNIT_METER, ) +from esphome.types import ConfigType CODEOWNERS = ["@netmikey"] DEPENDENCIES = ["uart"] @@ -23,7 +24,7 @@ CONFIG_SCHEMA = sensor.sensor_schema( ).extend(uart.UART_DEVICE_SCHEMA) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await sensor.new_sensor(config) await cg.register_component(var, config) await uart.register_uart_device(var, config) diff --git a/esphome/components/hte501/sensor.py b/esphome/components/hte501/sensor.py index 17ae3a3d1b..bf9fe4000e 100644 --- a/esphome/components/hte501/sensor.py +++ b/esphome/components/hte501/sensor.py @@ -11,6 +11,7 @@ from esphome.const import ( UNIT_CELSIUS, UNIT_PERCENT, ) +from esphome.types import ConfigType CODEOWNERS = ["@Stock-M"] @@ -44,7 +45,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/htu31d/sensor.py b/esphome/components/htu31d/sensor.py index 638a8d77c5..8960759d9b 100644 --- a/esphome/components/htu31d/sensor.py +++ b/esphome/components/htu31d/sensor.py @@ -11,6 +11,7 @@ from esphome.const import ( UNIT_CELSIUS, UNIT_PERCENT, ) +from esphome.types import ConfigType DEPENDENCIES = ["i2c"] @@ -42,7 +43,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/hub75/boards/__init__.py b/esphome/components/hub75/boards/__init__.py index 52f8864c60..818ee732a3 100644 --- a/esphome/components/hub75/boards/__init__.py +++ b/esphome/components/hub75/boards/__init__.py @@ -49,7 +49,7 @@ class BoardConfig: # Derived field for pin lookup pins: dict[str, int | None] = field(default_factory=dict, init=False, repr=False) - def __post_init__(self): + def __post_init__(self) -> None: """Initialize derived fields and register board.""" self.name = self.name.lower() self.pins = { diff --git a/esphome/components/hub75/display.py b/esphome/components/hub75/display.py index 24b8197073..3522acf049 100644 --- a/esphome/components/hub75/display.py +++ b/esphome/components/hub75/display.py @@ -131,7 +131,7 @@ SCAN_WIRINGS = { } -def _validate_scan_wiring(value): +def _validate_scan_wiring(value: Any) -> str: """Validate scan_wiring against the allowed names.""" value = cv.string(value).upper().replace(" ", "_") @@ -477,7 +477,7 @@ def _build_pins_struct( ) -> cg.StructInitializer: """Build Hub75Pins struct from pin expressions.""" - def pin_cast(pin): + def pin_cast(pin: Any) -> cg.RawExpression: return cg.RawExpression(f"static_cast({pin.get_pin()})") return cg.StructInitializer( diff --git a/esphome/components/hx711/sensor.py b/esphome/components/hx711/sensor.py index a5d11e9241..2739589c66 100644 --- a/esphome/components/hx711/sensor.py +++ b/esphome/components/hx711/sensor.py @@ -3,6 +3,7 @@ import esphome.codegen as cg from esphome.components import sensor import esphome.config_validation as cv from esphome.const import CONF_CLK_PIN, CONF_GAIN, ICON_SCALE, STATE_CLASS_MEASUREMENT +from esphome.types import ConfigType hx711_ns = cg.esphome_ns.namespace("hx711") HX711Sensor = hx711_ns.class_("HX711Sensor", sensor.Sensor, cg.PollingComponent) @@ -34,7 +35,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await sensor.new_sensor(config) await cg.register_component(var, config) diff --git a/esphome/components/hydreon_rgxx/binary_sensor.py b/esphome/components/hydreon_rgxx/binary_sensor.py index f899ce71ce..193db9b20d 100644 --- a/esphome/components/hydreon_rgxx/binary_sensor.py +++ b/esphome/components/hydreon_rgxx/binary_sensor.py @@ -2,6 +2,7 @@ import esphome.codegen as cg from esphome.components import binary_sensor import esphome.config_validation as cv from esphome.const import CONF_ID, DEVICE_CLASS_COLD, DEVICE_CLASS_PROBLEM +from esphome.types import ConfigType from . import HydreonRGxxComponent, hydreon_rgxx_ns @@ -32,7 +33,7 @@ CONFIG_SCHEMA = cv.Schema( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: main_sensor = await cg.get_variable(config[CONF_HYDREON_RGXX_ID]) bin_component = cg.new_Pvariable(config[CONF_ID], main_sensor) await cg.register_component(bin_component, config) diff --git a/esphome/components/hydreon_rgxx/sensor.py b/esphome/components/hydreon_rgxx/sensor.py index fdb606182f..58e72571ff 100644 --- a/esphome/components/hydreon_rgxx/sensor.py +++ b/esphome/components/hydreon_rgxx/sensor.py @@ -16,6 +16,7 @@ from esphome.const import ( UNIT_CELSIUS, UNIT_MILLIMETER, ) +from esphome.types import ConfigType from . import HydreonRGxxComponent, RG15Resolution, RGModel @@ -65,7 +66,7 @@ PROTOCOL_NAMES = { } -def _validate(config): +def _validate(config: ConfigType) -> ConfigType: for conf, models in SUPPORTED_OPTIONS.items(): if conf in config and config[CONF_MODEL] not in models: raise cv.Invalid( @@ -130,7 +131,7 @@ CONFIG_SCHEMA = cv.All( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await uart.register_uart_device(var, config) diff --git a/esphome/components/hyt271/sensor.py b/esphome/components/hyt271/sensor.py index bf37646d4f..3f006a65fe 100644 --- a/esphome/components/hyt271/sensor.py +++ b/esphome/components/hyt271/sensor.py @@ -11,6 +11,7 @@ from esphome.const import ( UNIT_CELSIUS, UNIT_PERCENT, ) +from esphome.types import ConfigType DEPENDENCIES = ["i2c"] @@ -42,7 +43,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/i2c_device/__init__.py b/esphome/components/i2c_device/__init__.py index 531c363bd1..f890fefdb9 100644 --- a/esphome/components/i2c_device/__init__.py +++ b/esphome/components/i2c_device/__init__.py @@ -2,6 +2,7 @@ import esphome.codegen as cg from esphome.components import i2c import esphome.config_validation as cv from esphome.const import CONF_ID +from esphome.types import ConfigType DEPENDENCIES = ["i2c"] CODEOWNERS = ["@gabest11"] @@ -20,7 +21,7 @@ CONFIG_SCHEMA = cv.Schema( ).extend(i2c.i2c_device_schema(None)) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/iaqcore/sensor.py b/esphome/components/iaqcore/sensor.py index d3306fd0f8..1b905e4c63 100644 --- a/esphome/components/iaqcore/sensor.py +++ b/esphome/components/iaqcore/sensor.py @@ -11,6 +11,7 @@ from esphome.const import ( UNIT_PARTS_PER_BILLION, UNIT_PARTS_PER_MILLION, ) +from esphome.types import ConfigType DEPENDENCIES = ["i2c"] CODEOWNERS = ["@yozik04"] @@ -42,7 +43,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) diff --git a/esphome/components/improv_base/__init__.py b/esphome/components/improv_base/__init__.py index 5929f2b60a..f132dbacb0 100644 --- a/esphome/components/improv_base/__init__.py +++ b/esphome/components/improv_base/__init__.py @@ -1,4 +1,5 @@ import re +from typing import Any import esphome.codegen as cg import esphome.config_validation as cv @@ -13,7 +14,7 @@ CONF_NEXT_URL = "next_url" VALID_SUBSTITUTIONS = ["esphome_version", "ip_address", "device_name"] -def validate_next_url(value): +def validate_next_url(value: Any) -> str: value = cv.url(value) test = r"{{(?!" + r"\b|".join(VALID_SUBSTITUTIONS) + r"\b)(\w+)}}" result = re.search(test, value) @@ -31,13 +32,13 @@ IMPROV_SCHEMA = cv.Schema( ) -def _process_next_url(url: str): +def _process_next_url(url: str) -> str: if "{{esphome_version}}" in url: url = url.replace("{{esphome_version}}", __version__) return url -async def setup_improv_core(var: MockObj, config: ConfigType, component: str): +async def setup_improv_core(var: MockObj, config: ConfigType, component: str) -> None: if next_url := config.get(CONF_NEXT_URL): cg.add(var.set_next_url(_process_next_url(next_url))) cg.add_define(f"USE_{component.upper()}_NEXT_URL") diff --git a/esphome/components/improv_serial/__init__.py b/esphome/components/improv_serial/__init__.py index 3e2a6db1bc..40ef14c6bc 100644 --- a/esphome/components/improv_serial/__init__.py +++ b/esphome/components/improv_serial/__init__.py @@ -6,6 +6,7 @@ import esphome.config_validation as cv from esphome.const import CONF_BAUD_RATE, CONF_HARDWARE_UART, CONF_ID, CONF_LOGGER from esphome.core import CORE import esphome.final_validate as fv +from esphome.types import ConfigType AUTO_LOAD = ["improv_base"] CODEOWNERS = ["@esphome/core"] @@ -22,7 +23,7 @@ CONFIG_SCHEMA = ( ) -def validate_logger(config) -> None: +def validate_logger(config: ConfigType) -> None: logger_conf = fv.full_config.get()[CONF_LOGGER] if logger_conf[CONF_BAUD_RATE] == 0: raise cv.Invalid("improv_serial requires the logger baud_rate to be not 0") @@ -38,7 +39,7 @@ def validate_logger(config) -> None: FINAL_VALIDATE_SCHEMA = validate_logger -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await improv_base.setup_improv_core(var, config, "improv_serial") diff --git a/esphome/components/ina219/sensor.py b/esphome/components/ina219/sensor.py index 621fd62e82..97482f81a0 100644 --- a/esphome/components/ina219/sensor.py +++ b/esphome/components/ina219/sensor.py @@ -18,6 +18,7 @@ from esphome.const import ( UNIT_VOLT, UNIT_WATT, ) +from esphome.types import ConfigType DEPENDENCIES = ["i2c"] @@ -70,7 +71,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/ina226/sensor.py b/esphome/components/ina226/sensor.py index 2a7b3fc212..4fd98fbcd4 100644 --- a/esphome/components/ina226/sensor.py +++ b/esphome/components/ina226/sensor.py @@ -1,3 +1,5 @@ +from typing import Any + import esphome.codegen as cg from esphome.components import i2c, sensor import esphome.config_validation as cv @@ -18,6 +20,7 @@ from esphome.const import ( UNIT_VOLT, UNIT_WATT, ) +from esphome.types import ConfigType DEPENDENCIES = ["i2c"] @@ -54,7 +57,7 @@ ADC_AVG_SAMPLES = { } -def validate_adc_time(value): +def validate_adc_time(value: Any) -> int: value = cv.positive_time_period_microseconds(value).total_microseconds return cv.enum(ADC_TIMES, int=True)(value) @@ -112,7 +115,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/ina260/sensor.py b/esphome/components/ina260/sensor.py index b98b4ce6cb..b7b94a248b 100644 --- a/esphome/components/ina260/sensor.py +++ b/esphome/components/ina260/sensor.py @@ -14,6 +14,7 @@ from esphome.const import ( UNIT_VOLT, UNIT_WATT, ) +from esphome.types import ConfigType DEPENDENCIES = ["i2c"] CODEOWNERS = ["@mreditor97"] @@ -52,7 +53,7 @@ CONFIG_SCHEMA = cv.All( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) diff --git a/esphome/components/ina2xx_i2c/sensor.py b/esphome/components/ina2xx_i2c/sensor.py index 1a470aa628..4bcbca8762 100644 --- a/esphome/components/ina2xx_i2c/sensor.py +++ b/esphome/components/ina2xx_i2c/sensor.py @@ -2,6 +2,7 @@ import esphome.codegen as cg from esphome.components import i2c, ina2xx_base import esphome.config_validation as cv from esphome.const import CONF_ID, CONF_MODEL +from esphome.types import ConfigType AUTO_LOAD = ["ina2xx_base"] CODEOWNERS = ["@latonita"] @@ -28,7 +29,7 @@ CONFIG_SCHEMA = cv.All( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await ina2xx_base.setup_ina2xx(var, config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/ina2xx_spi/sensor.py b/esphome/components/ina2xx_spi/sensor.py index 3ebe2cac73..dc72dce7a9 100644 --- a/esphome/components/ina2xx_spi/sensor.py +++ b/esphome/components/ina2xx_spi/sensor.py @@ -2,6 +2,7 @@ import esphome.codegen as cg from esphome.components import ina2xx_base, spi import esphome.config_validation as cv from esphome.const import CONF_ID, CONF_MODEL +from esphome.types import ConfigType AUTO_LOAD = ["ina2xx_base"] CODEOWNERS = ["@latonita"] @@ -27,7 +28,7 @@ CONFIG_SCHEMA = cv.All( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await ina2xx_base.setup_ina2xx(var, config) await spi.register_spi_device(var, config) diff --git a/esphome/components/ina3221/sensor.py b/esphome/components/ina3221/sensor.py index acf7d7cdf0..db8dad2f54 100644 --- a/esphome/components/ina3221/sensor.py +++ b/esphome/components/ina3221/sensor.py @@ -16,6 +16,7 @@ from esphome.const import ( UNIT_VOLT, UNIT_WATT, ) +from esphome.types import ConfigType DEPENDENCIES = ["i2c"] @@ -74,7 +75,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/infrared/__init__.py b/esphome/components/infrared/__init__.py index f8e77209b2..d04c82ea96 100644 --- a/esphome/components/infrared/__init__.py +++ b/esphome/components/infrared/__init__.py @@ -14,7 +14,7 @@ from esphome.const import CONF_ID from esphome.core import CORE, coroutine_with_priority from esphome.core.entity_helpers import queue_entity_register, setup_entity from esphome.coroutine import CoroPriority -from esphome.types import ConfigType +from esphome.types import ConfigType, SafeExpType CODEOWNERS = ["@kbx81"] AUTO_LOAD = ["remote_base"] @@ -46,11 +46,11 @@ def infrared_schema(class_: type[cg.MockObjClass]) -> cv.Schema: @setup_entity("infrared") -async def setup_infrared_core_(var: cg.Pvariable, config: ConfigType) -> None: +async def setup_infrared_core_(var: cg.MockObj, config: ConfigType) -> None: """Set up core infrared configuration.""" -async def register_infrared(var: cg.Pvariable, config: ConfigType) -> None: +async def register_infrared(var: cg.MockObj, config: ConfigType) -> None: """Register an infrared device with the core.""" cg.add_define("USE_IR_RF") await cg.register_component(var, config) @@ -59,7 +59,7 @@ async def register_infrared(var: cg.Pvariable, config: ConfigType) -> None: CORE.register_platform_component("infrared", var) -async def new_infrared(config: ConfigType, *args) -> cg.Pvariable: +async def new_infrared(config: ConfigType, *args: SafeExpType) -> cg.MockObj: """Create a new Infrared instance. :param config: Configuration dictionary. diff --git a/esphome/components/inkbird_ibsth1_mini/sensor.py b/esphome/components/inkbird_ibsth1_mini/sensor.py index 2dcdb9a118..84a207020e 100644 --- a/esphome/components/inkbird_ibsth1_mini/sensor.py +++ b/esphome/components/inkbird_ibsth1_mini/sensor.py @@ -16,6 +16,7 @@ from esphome.const import ( UNIT_CELSIUS, UNIT_PERCENT, ) +from esphome.types import ConfigType CODEOWNERS = ["@fkirill"] AUTO_LOAD = ["ble_device_base"] @@ -63,7 +64,7 @@ CONFIG_SCHEMA = cv.All( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await ble_device_base.register_ble_device(var, config) diff --git a/esphome/components/inkplate/display.py b/esphome/components/inkplate/display.py index a0c0d5dc18..350a0c1652 100644 --- a/esphome/components/inkplate/display.py +++ b/esphome/components/inkplate/display.py @@ -19,6 +19,7 @@ from esphome.const import ( PLATFORM_ESP32, ) import esphome.final_validate as fv +from esphome.types import ConfigType from .const import INKPLATE_10_CUSTOM_WAVEFORMS, WAVEFORMS @@ -68,7 +69,7 @@ MODELS = { CONF_CUSTOM_WAVEFORM = "custom_waveform" -def _validate_custom_waveform(config): +def _validate_custom_waveform(config: ConfigType) -> ConfigType: if CONF_CUSTOM_WAVEFORM in config and config[CONF_MODEL] != "inkplate_10": raise cv.Invalid("Custom waveforms are only supported on the Inkplate 10") return config @@ -146,7 +147,7 @@ CONFIG_SCHEMA = cv.All( ) -def _validate_cpu_frequency(config) -> None: +def _validate_cpu_frequency(config: ConfigType) -> None: esp32_config = fv.full_config.get()[PLATFORM_ESP32] if esp32_config[CONF_CPU_FREQUENCY] != "240MHZ": raise cv.Invalid( @@ -157,7 +158,7 @@ def _validate_cpu_frequency(config) -> None: FINAL_VALIDATE_SCHEMA = _validate_cpu_frequency -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await display.register_display(var, config) diff --git a/esphome/components/internal_temperature/sensor.py b/esphome/components/internal_temperature/sensor.py index 805138071e..d3101f4a7c 100644 --- a/esphome/components/internal_temperature/sensor.py +++ b/esphome/components/internal_temperature/sensor.py @@ -16,6 +16,7 @@ from esphome.const import ( PlatformFramework, ) from esphome.core import CORE +from esphome.types import ConfigType internal_temperature_ns = cg.esphome_ns.namespace("internal_temperature") InternalTemperatureSensor = internal_temperature_ns.class_( @@ -43,7 +44,7 @@ CONFIG_SCHEMA = cv.All( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await sensor.new_sensor(config) await cg.register_component(var, config) diff --git a/esphome/components/interval/__init__.py b/esphome/components/interval/__init__.py index ac9219ff6a..11c3e15b0d 100644 --- a/esphome/components/interval/__init__.py +++ b/esphome/components/interval/__init__.py @@ -2,6 +2,7 @@ from esphome import automation import esphome.codegen as cg import esphome.config_validation as cv from esphome.const import CONF_ID, CONF_INTERVAL, CONF_STARTUP_DELAY +from esphome.types import ConfigType CODEOWNERS = ["@esphome/core"] interval_ns = cg.esphome_ns.namespace("interval") @@ -22,7 +23,7 @@ CONFIG_SCHEMA = automation.validate_automation( ) -async def to_code(config): +async def to_code(config: list[ConfigType]) -> None: for conf in config: var = cg.new_Pvariable(conf[CONF_ID]) await cg.register_component(var, conf) diff --git a/esphome/components/jsn_sr04t/sensor.py b/esphome/components/jsn_sr04t/sensor.py index 214724aa3f..0c4187b823 100644 --- a/esphome/components/jsn_sr04t/sensor.py +++ b/esphome/components/jsn_sr04t/sensor.py @@ -7,6 +7,7 @@ from esphome.const import ( STATE_CLASS_MEASUREMENT, UNIT_METER, ) +from esphome.types import ConfigType CODEOWNERS = ["@Mafus1"] DEPENDENCIES = ["uart"] @@ -49,7 +50,7 @@ FINAL_VALIDATE_SCHEMA = uart.final_validate_device_schema( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await sensor.new_sensor(config) await cg.register_component(var, config) await uart.register_uart_device(var, config) diff --git a/esphome/components/json/__init__.py b/esphome/components/json/__init__.py index 3cb89a6cd9..af7eb7e733 100644 --- a/esphome/components/json/__init__.py +++ b/esphome/components/json/__init__.py @@ -1,6 +1,7 @@ import esphome.codegen as cg import esphome.config_validation as cv from esphome.core import CORE, CoroPriority, coroutine_with_priority +from esphome.types import ConfigType CODEOWNERS = ["@esphome/core"] json_ns = cg.esphome_ns.namespace("json") @@ -11,7 +12,7 @@ CONFIG_SCHEMA = cv.All( @coroutine_with_priority(CoroPriority.BUS) -async def to_code(config): +async def to_code(config: ConfigType) -> None: if CORE.is_esp32: from esphome.components.esp32 import add_idf_component diff --git a/esphome/components/kamstrup_kmp/sensor.py b/esphome/components/kamstrup_kmp/sensor.py index 75ec432ad9..6465012897 100644 --- a/esphome/components/kamstrup_kmp/sensor.py +++ b/esphome/components/kamstrup_kmp/sensor.py @@ -23,6 +23,7 @@ from esphome.const import ( UNIT_KILOWATT, UNIT_LITRE_PER_HOUR, ) +from esphome.types import ConfigType CODEOWNERS = ["@cfeenstra1024"] DEPENDENCIES = ["uart"] @@ -105,7 +106,7 @@ FINAL_VALIDATE_SCHEMA = uart.final_validate_device_schema( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await uart.register_uart_device(var, config) diff --git a/esphome/components/kmeteriso/sensor.py b/esphome/components/kmeteriso/sensor.py index 4f6cb7d091..3e007d1310 100644 --- a/esphome/components/kmeteriso/sensor.py +++ b/esphome/components/kmeteriso/sensor.py @@ -10,6 +10,7 @@ from esphome.const import ( STATE_CLASS_MEASUREMENT, UNIT_CELSIUS, ) +from esphome.types import ConfigType DEPENDENCIES = ["i2c"] @@ -42,7 +43,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/kuntze/sensor.py b/esphome/components/kuntze/sensor.py index 2b53e70756..51d23991e2 100644 --- a/esphome/components/kuntze/sensor.py +++ b/esphome/components/kuntze/sensor.py @@ -96,7 +96,7 @@ def _final_validate(config: ConfigType) -> None: FINAL_VALIDATE_SCHEMA = _final_validate -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await modbus.register_modbus_client_device(var, config) diff --git a/esphome/components/lc709203f/sensor.py b/esphome/components/lc709203f/sensor.py index d4e6213425..3319c9be4b 100644 --- a/esphome/components/lc709203f/sensor.py +++ b/esphome/components/lc709203f/sensor.py @@ -18,6 +18,7 @@ from esphome.const import ( UNIT_PERCENT, UNIT_VOLT, ) +from esphome.types import ConfigType DEPENDENCIES = ["i2c"] @@ -71,7 +72,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/lcd_gpio/display.py b/esphome/components/lcd_gpio/display.py index 0a77daf336..10e21c87d1 100644 --- a/esphome/components/lcd_gpio/display.py +++ b/esphome/components/lcd_gpio/display.py @@ -10,6 +10,7 @@ from esphome.const import ( CONF_RS_PIN, CONF_RW_PIN, ) +from esphome.types import ConfigType AUTO_LOAD = ["lcd_base"] @@ -17,7 +18,7 @@ lcd_gpio_ns = cg.esphome_ns.namespace("lcd_gpio") GPIOLCDDisplay = lcd_gpio_ns.class_("GPIOLCDDisplay", lcd_base.LCDDisplay) -def validate_pin_length(value): +def validate_pin_length(value: list[ConfigType]) -> list[ConfigType]: if len(value) != 4 and len(value) != 8: raise cv.Invalid( f"LCD Displays can either operate in 4-pin or 8-pin mode,not {len(value)}-pin mode" @@ -38,7 +39,7 @@ CONFIG_SCHEMA = lcd_base.LCD_SCHEMA.extend( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await lcd_base.setup_lcd_display(var, config) pins_ = [await cg.gpio_pin_expression(conf) for conf in config[CONF_DATA_PINS]] diff --git a/esphome/components/lcd_menu/__init__.py b/esphome/components/lcd_menu/__init__.py index 3f3162e31e..88b8ac21d4 100644 --- a/esphome/components/lcd_menu/__init__.py +++ b/esphome/components/lcd_menu/__init__.py @@ -8,6 +8,7 @@ from esphome.components.display_menu_base import ( import esphome.config_validation as cv from esphome.const import CONF_DIMENSIONS, CONF_DISPLAY_ID, CONF_ID from esphome.core.entity_helpers import inherit_property_from +from esphome.types import ConfigType CODEOWNERS = ["@numo68"] @@ -29,7 +30,7 @@ LCDCharacterMenuComponent = lcd_menu_ns.class_( MULTI_CONF = True -def validate_lcd_dimensions(config): +def validate_lcd_dimensions(config: ConfigType) -> ConfigType: if config[CONF_DIMENSIONS][0] < MINIMUM_COLUMNS: raise cv.Invalid( f"LCD display must have at least {MINIMUM_COLUMNS} columns to be usable with the menu" @@ -56,7 +57,7 @@ FINAL_VALIDATE_SCHEMA = cv.All( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) disp = await cg.get_variable(config[CONF_DISPLAY_ID]) diff --git a/esphome/components/lcd_pcf8574/display.py b/esphome/components/lcd_pcf8574/display.py index 410c7f81b7..85a79e99ce 100644 --- a/esphome/components/lcd_pcf8574/display.py +++ b/esphome/components/lcd_pcf8574/display.py @@ -2,6 +2,7 @@ import esphome.codegen as cg from esphome.components import i2c, lcd_base import esphome.config_validation as cv from esphome.const import CONF_ID, CONF_LAMBDA +from esphome.types import ConfigType DEPENDENCIES = ["i2c"] AUTO_LOAD = ["lcd_base"] @@ -18,7 +19,7 @@ CONFIG_SCHEMA = lcd_base.LCD_SCHEMA.extend( ).extend(i2c.i2c_device_schema(0x3F)) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await lcd_base.setup_lcd_display(var, config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/lilygo_t5_47/touchscreen/__init__.py b/esphome/components/lilygo_t5_47/touchscreen/__init__.py index 93687846e2..1e70f379a1 100644 --- a/esphome/components/lilygo_t5_47/touchscreen/__init__.py +++ b/esphome/components/lilygo_t5_47/touchscreen/__init__.py @@ -3,6 +3,7 @@ import esphome.codegen as cg from esphome.components import i2c, touchscreen import esphome.config_validation as cv from esphome.const import CONF_ID, CONF_INTERRUPT_PIN +from esphome.types import ConfigType from .. import lilygo_t5_47_ns @@ -29,7 +30,7 @@ CONFIG_SCHEMA = touchscreen.touchscreen_schema("250ms").extend( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await touchscreen.register_touchscreen(var, config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/lm75b/sensor.py b/esphome/components/lm75b/sensor.py index 335446b62f..c59515b5b0 100644 --- a/esphome/components/lm75b/sensor.py +++ b/esphome/components/lm75b/sensor.py @@ -6,6 +6,7 @@ from esphome.const import ( STATE_CLASS_MEASUREMENT, UNIT_CELSIUS, ) +from esphome.types import ConfigType CODEOWNERS = ["@beormund"] DEPENDENCIES = ["i2c"] @@ -28,7 +29,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await sensor.new_sensor(config) await cg.register_component(var, config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/ln882x/__init__.py b/esphome/components/ln882x/__init__.py index 6da5a4969c..b4e179c4a9 100644 --- a/esphome/components/ln882x/__init__.py +++ b/esphome/components/ln882x/__init__.py @@ -28,6 +28,8 @@ from esphome.components.libretiny.const import ( LibreTinyComponent, ) from esphome.core import CORE +from esphome.cpp_generator import MockObj +from esphome.types import ConfigType from .boards import LN882X_BOARD_PINS, LN882X_BOARDS @@ -45,7 +47,7 @@ COMPONENT_DATA = LibreTinyComponent( ) -def _set_core_data(config): +def _set_core_data(config: ConfigType) -> ConfigType: CORE.data[KEY_LIBRETINY] = {} CORE.data[KEY_LIBRETINY][KEY_COMPONENT_DATA] = COMPONENT_DATA return config @@ -62,12 +64,12 @@ PIN_SCHEMA = libretiny.gpio.BASE_PIN_SCHEMA CONFIG_SCHEMA.prepend_extra(_set_core_data) -async def to_code(config): +async def to_code(config: ConfigType) -> MockObj: return await libretiny.component_to_code(config) @pins.PIN_SCHEMA_REGISTRY.register("ln882x", PIN_SCHEMA) -async def pin_to_code(config): +async def pin_to_code(config: ConfigType) -> MockObj: return await libretiny.gpio.component_pin_to_code(config) diff --git a/esphome/components/lps22/sensor.py b/esphome/components/lps22/sensor.py index 08e97ee7b7..2eec2c586c 100644 --- a/esphome/components/lps22/sensor.py +++ b/esphome/components/lps22/sensor.py @@ -12,6 +12,7 @@ from esphome.const import ( UNIT_CELSIUS, UNIT_HECTOPASCAL, ) +from esphome.types import ConfigType CODEOWNERS = ["@nagisa"] DEPENDENCIES = ["i2c"] @@ -44,7 +45,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/lsm6ds/motion.py b/esphome/components/lsm6ds/motion.py index 8c2c5198ea..064cd312a9 100644 --- a/esphome/components/lsm6ds/motion.py +++ b/esphome/components/lsm6ds/motion.py @@ -8,6 +8,7 @@ from esphome.components.const import ( ) from esphome.components.motion import motion_schema, new_motion_component import esphome.config_validation as cv +from esphome.types import ConfigType from . import LSM6DSComponent, lsm6ds_ns @@ -93,7 +94,7 @@ CONFIG_SCHEMA = ( # ── Code generation ────────────────────────────────────────────────────────── -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await new_motion_component(config) # Let the motion platform handle sensor wiring, axis mapping, and polling diff --git a/esphome/components/lsm6ds/sensor.py b/esphome/components/lsm6ds/sensor.py index 980e84a2e9..c0c37f8527 100644 --- a/esphome/components/lsm6ds/sensor.py +++ b/esphome/components/lsm6ds/sensor.py @@ -11,6 +11,7 @@ from esphome.const import ( UNIT_CELSIUS, ) from esphome.cpp_generator import MockObj +from esphome.types import ConfigType from . import CONF_LSM6DS_ID, LSM6DSComponent @@ -28,7 +29,7 @@ CONFIG_SCHEMA = sensor.sensor_schema( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await sensor.new_sensor(config) parent = await cg.get_variable(config[CONF_LSM6DS_ID]) data = MockObj("data") diff --git a/esphome/components/ltr390/sensor.py b/esphome/components/ltr390/sensor.py index 37fceaf984..c3ac90ad11 100644 --- a/esphome/components/ltr390/sensor.py +++ b/esphome/components/ltr390/sensor.py @@ -13,6 +13,7 @@ from esphome.const import ( STATE_CLASS_MEASUREMENT, UNIT_LUX, ) +from esphome.types import ConfigType CODEOWNERS = ["@sjtrny", "@latonita"] DEPENDENCIES = ["i2c"] @@ -117,7 +118,7 @@ TYPES = { } -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/max31855/sensor.py b/esphome/components/max31855/sensor.py index 35ae28d04c..a52f45a18f 100644 --- a/esphome/components/max31855/sensor.py +++ b/esphome/components/max31855/sensor.py @@ -7,6 +7,7 @@ from esphome.const import ( STATE_CLASS_MEASUREMENT, UNIT_CELSIUS, ) +from esphome.types import ConfigType max31855_ns = cg.esphome_ns.namespace("max31855") MAX31855Sensor = max31855_ns.class_( @@ -36,7 +37,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await sensor.new_sensor(config) await cg.register_component(var, config) await spi.register_spi_device(var, config) diff --git a/esphome/components/max31856/sensor.py b/esphome/components/max31856/sensor.py index 679e02b11d..43a2e18db8 100644 --- a/esphome/components/max31856/sensor.py +++ b/esphome/components/max31856/sensor.py @@ -8,6 +8,7 @@ from esphome.const import ( STATE_CLASS_MEASUREMENT, UNIT_CELSIUS, ) +from esphome.types import ConfigType max31856_ns = cg.esphome_ns.namespace("max31856") MAX31856Sensor = max31856_ns.class_( @@ -58,7 +59,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await sensor.new_sensor(config) await cg.register_component(var, config) await spi.register_spi_device(var, config) diff --git a/esphome/components/max31865/sensor.py b/esphome/components/max31865/sensor.py index d4498b062f..167a0997e4 100644 --- a/esphome/components/max31865/sensor.py +++ b/esphome/components/max31865/sensor.py @@ -10,6 +10,7 @@ from esphome.const import ( STATE_CLASS_MEASUREMENT, UNIT_CELSIUS, ) +from esphome.types import ConfigType CODEOWNERS = ["@DAVe3283"] DEPENDENCIES = ["spi"] @@ -52,7 +53,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await sensor.new_sensor(config) await cg.register_component(var, config) await spi.register_spi_device(var, config) diff --git a/esphome/components/max44009/sensor.py b/esphome/components/max44009/sensor.py index 5aea7f0be2..88673c5d00 100644 --- a/esphome/components/max44009/sensor.py +++ b/esphome/components/max44009/sensor.py @@ -8,6 +8,7 @@ from esphome.const import ( STATE_CLASS_MEASUREMENT, UNIT_LUX, ) +from esphome.types import ConfigType CODEOWNERS = ["@berfenger"] DEPENDENCIES = ["i2c"] @@ -44,7 +45,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/max6675/sensor.py b/esphome/components/max6675/sensor.py index e42abb68d1..94d857cab9 100644 --- a/esphome/components/max6675/sensor.py +++ b/esphome/components/max6675/sensor.py @@ -6,6 +6,7 @@ from esphome.const import ( STATE_CLASS_MEASUREMENT, UNIT_CELSIUS, ) +from esphome.types import ConfigType max6675_ns = cg.esphome_ns.namespace("max6675") MAX6675Sensor = max6675_ns.class_( @@ -25,7 +26,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await sensor.new_sensor(config) await cg.register_component(var, config) await spi.register_spi_device(var, config) diff --git a/esphome/components/max7219/display.py b/esphome/components/max7219/display.py index abb20702bd..b21f66b553 100644 --- a/esphome/components/max7219/display.py +++ b/esphome/components/max7219/display.py @@ -2,6 +2,7 @@ import esphome.codegen as cg from esphome.components import display, spi import esphome.config_validation as cv from esphome.const import CONF_ID, CONF_INTENSITY, CONF_LAMBDA, CONF_NUM_CHIPS +from esphome.types import ConfigType DEPENDENCIES = ["spi"] @@ -27,7 +28,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID], config[CONF_NUM_CHIPS]) await spi.register_spi_device(var, config, write_only=True) await display.register_display(var, config) diff --git a/esphome/components/max9611/sensor.py b/esphome/components/max9611/sensor.py index b3a73d8c10..9332274a95 100644 --- a/esphome/components/max9611/sensor.py +++ b/esphome/components/max9611/sensor.py @@ -19,6 +19,7 @@ from esphome.const import ( UNIT_VOLT, UNIT_WATT, ) +from esphome.types import ConfigType DEPENDENCIES = ["i2c"] max9611_ns = cg.esphome_ns.namespace("max9611") @@ -70,7 +71,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/mcp23008/__init__.py b/esphome/components/mcp23008/__init__.py index 8ff938114a..3d1480a6f7 100644 --- a/esphome/components/mcp23008/__init__.py +++ b/esphome/components/mcp23008/__init__.py @@ -2,6 +2,7 @@ import esphome.codegen as cg from esphome.components import i2c, mcp23x08_base, mcp23xxx_base import esphome.config_validation as cv from esphome.const import CONF_ID +from esphome.types import ConfigType AUTO_LOAD = ["mcp23x08_base"] CODEOWNERS = ["@jesserockz"] @@ -23,6 +24,6 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await mcp23xxx_base.register_mcp23xxx(config, mcp23x08_base.NUM_PINS) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/mcp23016/__init__.py b/esphome/components/mcp23016/__init__.py index 37c5205fe8..5f4b7276d8 100644 --- a/esphome/components/mcp23016/__init__.py +++ b/esphome/components/mcp23016/__init__.py @@ -11,6 +11,8 @@ from esphome.const import ( CONF_NUMBER, CONF_OUTPUT, ) +from esphome.cpp_generator import MockObj +from esphome.types import ConfigType AUTO_LOAD = ["gpio_expander"] DEPENDENCIES = ["i2c"] @@ -33,7 +35,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await i2c.register_i2c_device(var, config) @@ -41,7 +43,7 @@ async def to_code(config): cg.add(var.set_interrupt_pin(await cg.gpio_pin_expression(interrupt_pin))) -def validate_mode(value): +def validate_mode(value: ConfigType) -> ConfigType: if not (value[CONF_INPUT] or value[CONF_OUTPUT]): raise cv.Invalid("Mode must be either input or output") if value[CONF_INPUT] and value[CONF_OUTPUT]: @@ -64,7 +66,7 @@ MCP23016_PIN_SCHEMA = pins.gpio_base_schema( @pins.PIN_SCHEMA_REGISTRY.register(CONF_MCP23016, MCP23016_PIN_SCHEMA) -async def mcp23016_pin_to_code(config): +async def mcp23016_pin_to_code(config: ConfigType) -> MockObj: var = cg.new_Pvariable(config[CONF_ID]) parent = await cg.get_variable(config[CONF_MCP23016]) diff --git a/esphome/components/mcp23017/__init__.py b/esphome/components/mcp23017/__init__.py index e5cc1856eb..474d75f6ff 100644 --- a/esphome/components/mcp23017/__init__.py +++ b/esphome/components/mcp23017/__init__.py @@ -2,6 +2,7 @@ import esphome.codegen as cg from esphome.components import i2c, mcp23x17_base, mcp23xxx_base import esphome.config_validation as cv from esphome.const import CONF_ID +from esphome.types import ConfigType AUTO_LOAD = ["mcp23x17_base"] CODEOWNERS = ["@jesserockz"] @@ -23,6 +24,6 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await mcp23xxx_base.register_mcp23xxx(config, mcp23x17_base.NUM_PINS) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/mcp23s08/__init__.py b/esphome/components/mcp23s08/__init__.py index 312da79b75..ffc51b8146 100644 --- a/esphome/components/mcp23s08/__init__.py +++ b/esphome/components/mcp23s08/__init__.py @@ -2,6 +2,7 @@ import esphome.codegen as cg from esphome.components import mcp23x08_base, mcp23xxx_base, spi import esphome.config_validation as cv from esphome.const import CONF_ID +from esphome.types import ConfigType AUTO_LOAD = ["mcp23x08_base"] CODEOWNERS = ["@SenexCrenshaw", "@jesserockz"] @@ -26,7 +27,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await mcp23xxx_base.register_mcp23xxx(config, mcp23x08_base.NUM_PINS) cg.add(var.set_device_address(config[CONF_DEVICEADDRESS])) await spi.register_spi_device(var, config) diff --git a/esphome/components/mcp23s17/__init__.py b/esphome/components/mcp23s17/__init__.py index 599bfa0851..d693a64ce8 100644 --- a/esphome/components/mcp23s17/__init__.py +++ b/esphome/components/mcp23s17/__init__.py @@ -2,6 +2,7 @@ import esphome.codegen as cg from esphome.components import mcp23x17_base, mcp23xxx_base, spi import esphome.config_validation as cv from esphome.const import CONF_ID +from esphome.types import ConfigType AUTO_LOAD = ["mcp23x17_base"] CODEOWNERS = ["@SenexCrenshaw", "@jesserockz"] @@ -26,7 +27,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await mcp23xxx_base.register_mcp23xxx(config, mcp23x17_base.NUM_PINS) cg.add(var.set_device_address(config[CONF_DEVICEADDRESS])) await spi.register_spi_device(var, config) diff --git a/esphome/components/mcp2515/canbus.py b/esphome/components/mcp2515/canbus.py index d34a77248c..8bb8918f96 100644 --- a/esphome/components/mcp2515/canbus.py +++ b/esphome/components/mcp2515/canbus.py @@ -3,6 +3,7 @@ from esphome.components import canbus, spi from esphome.components.canbus import CanbusComponent import esphome.config_validation as cv from esphome.const import CONF_ID, CONF_MODE +from esphome.types import ConfigType CODEOWNERS = ["@mvturnho", "@danielschramm"] DEPENDENCIES = ["spi"] @@ -36,7 +37,7 @@ CONFIG_SCHEMA = canbus.CANBUS_SCHEMA.extend( ).extend(spi.spi_device_schema(True)) -async def to_code(config): +async def to_code(config: ConfigType) -> None: rhs = mcp2515.new() var = cg.Pvariable(config[CONF_ID], rhs) await canbus.register_canbus(var, config) diff --git a/esphome/components/mcp3008/__init__.py b/esphome/components/mcp3008/__init__.py index 41ccdd403a..6d1bd5a970 100644 --- a/esphome/components/mcp3008/__init__.py +++ b/esphome/components/mcp3008/__init__.py @@ -2,6 +2,7 @@ import esphome.codegen as cg from esphome.components import spi import esphome.config_validation as cv from esphome.const import CONF_ID +from esphome.types import ConfigType DEPENDENCIES = ["spi"] AUTO_LOAD = ["sensor"] @@ -19,7 +20,7 @@ CONFIG_SCHEMA = cv.Schema( ).extend(spi.spi_device_schema(cs_pin_required=True)) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await spi.register_spi_device(var, config) diff --git a/esphome/components/mcp3008/sensor/__init__.py b/esphome/components/mcp3008/sensor/__init__.py index 2576ef50e5..de31f81345 100644 --- a/esphome/components/mcp3008/sensor/__init__.py +++ b/esphome/components/mcp3008/sensor/__init__.py @@ -9,6 +9,7 @@ from esphome.const import ( STATE_CLASS_MEASUREMENT, UNIT_VOLT, ) +from esphome.types import ConfigType from .. import MCP3008, mcp3008_ns @@ -43,7 +44,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_parented(var, config[CONF_MCP3008_ID]) await cg.register_component(var, config) diff --git a/esphome/components/mcp3204/__init__.py b/esphome/components/mcp3204/__init__.py index 612297f934..5757bdbfa9 100644 --- a/esphome/components/mcp3204/__init__.py +++ b/esphome/components/mcp3204/__init__.py @@ -2,6 +2,7 @@ import esphome.codegen as cg from esphome.components import spi import esphome.config_validation as cv from esphome.const import CONF_ID, CONF_REFERENCE_VOLTAGE +from esphome.types import ConfigType DEPENDENCIES = ["spi"] MULTI_CONF = True @@ -19,7 +20,7 @@ CONFIG_SCHEMA = cv.Schema( ).extend(spi.spi_device_schema(cs_pin_required=True)) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) cg.add(var.set_reference_voltage(config[CONF_REFERENCE_VOLTAGE])) await cg.register_component(var, config) diff --git a/esphome/components/mcp3204/sensor/__init__.py b/esphome/components/mcp3204/sensor/__init__.py index 5f9aa9fdb6..728a1c0611 100644 --- a/esphome/components/mcp3204/sensor/__init__.py +++ b/esphome/components/mcp3204/sensor/__init__.py @@ -2,6 +2,7 @@ import esphome.codegen as cg from esphome.components import sensor, voltage_sampler import esphome.config_validation as cv from esphome.const import CONF_ID, CONF_NUMBER +from esphome.types import ConfigType from .. import MCP3204, mcp3204_ns @@ -28,7 +29,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable( config[CONF_ID], config[CONF_NUMBER], diff --git a/esphome/components/mcp3221/sensor.py b/esphome/components/mcp3221/sensor.py index 993876c2c8..30e972d808 100644 --- a/esphome/components/mcp3221/sensor.py +++ b/esphome/components/mcp3221/sensor.py @@ -8,6 +8,7 @@ from esphome.const import ( STATE_CLASS_MEASUREMENT, UNIT_VOLT, ) +from esphome.types import ConfigType AUTO_LOAD = ["voltage_sampler"] DEPENDENCIES = ["i2c"] @@ -42,7 +43,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await sensor.new_sensor(config) cg.add(var.set_reference_voltage(config[CONF_REFERENCE_VOLTAGE])) await cg.register_component(var, config) diff --git a/esphome/components/mcp4725/output.py b/esphome/components/mcp4725/output.py index 5ec6a9d686..0c1224a1a7 100644 --- a/esphome/components/mcp4725/output.py +++ b/esphome/components/mcp4725/output.py @@ -2,6 +2,7 @@ import esphome.codegen as cg from esphome.components import i2c, output import esphome.config_validation as cv from esphome.const import CONF_ID +from esphome.types import ConfigType DEPENDENCIES = ["i2c"] @@ -19,7 +20,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/mcp4728/__init__.py b/esphome/components/mcp4728/__init__.py index da3244be84..f48bdde681 100644 --- a/esphome/components/mcp4728/__init__.py +++ b/esphome/components/mcp4728/__init__.py @@ -2,6 +2,7 @@ import esphome.codegen as cg from esphome.components import i2c import esphome.config_validation as cv from esphome.const import CONF_ID +from esphome.types import ConfigType CODEOWNERS = ["@berfenger"] DEPENDENCIES = ["i2c"] @@ -24,7 +25,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID], config[CONF_STORE_IN_EEPROM]) await cg.register_component(var, config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/mcp4728/output/__init__.py b/esphome/components/mcp4728/output/__init__.py index 6f4a41510f..e8cb4c47d6 100644 --- a/esphome/components/mcp4728/output/__init__.py +++ b/esphome/components/mcp4728/output/__init__.py @@ -2,6 +2,7 @@ import esphome.codegen as cg from esphome.components import output import esphome.config_validation as cv from esphome.const import CONF_CHANNEL, CONF_GAIN, CONF_ID +from esphome.types import ConfigType from .. import CONF_MCP4728_ID, MCP4728Component, mcp4728_ns @@ -50,7 +51,7 @@ CONFIG_SCHEMA = output.FLOAT_OUTPUT_SCHEMA.extend( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: paren = await cg.get_variable(config[CONF_MCP4728_ID]) var = cg.new_Pvariable( config[CONF_ID], diff --git a/esphome/components/mcp47a1/output.py b/esphome/components/mcp47a1/output.py index ebd597cfeb..91bb3b47db 100644 --- a/esphome/components/mcp47a1/output.py +++ b/esphome/components/mcp47a1/output.py @@ -2,6 +2,7 @@ import esphome.codegen as cg from esphome.components import i2c, output import esphome.config_validation as cv from esphome.const import CONF_ID +from esphome.types import ConfigType CODEOWNERS = ["@jesserockz"] DEPENDENCIES = ["i2c"] @@ -20,7 +21,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/mcp9600/sensor.py b/esphome/components/mcp9600/sensor.py index 65ae5f2eec..5542ffaa6c 100644 --- a/esphome/components/mcp9600/sensor.py +++ b/esphome/components/mcp9600/sensor.py @@ -8,6 +8,7 @@ from esphome.const import ( STATE_CLASS_MEASUREMENT, UNIT_CELSIUS, ) +from esphome.types import ConfigType CONF_HOT_JUNCTION = "hot_junction" CONF_COLD_JUNCTION = "cold_junction" @@ -62,7 +63,7 @@ FINAL_VALIDATE_SCHEMA = i2c.final_validate_device_schema( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) diff --git a/esphome/components/mcp9808/sensor.py b/esphome/components/mcp9808/sensor.py index ba6718ca56..1daaa9c131 100644 --- a/esphome/components/mcp9808/sensor.py +++ b/esphome/components/mcp9808/sensor.py @@ -6,6 +6,7 @@ from esphome.const import ( STATE_CLASS_MEASUREMENT, UNIT_CELSIUS, ) +from esphome.types import ConfigType CODEOWNERS = ["@k7hpn"] DEPENDENCIES = ["i2c"] @@ -28,7 +29,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await sensor.new_sensor(config) await cg.register_component(var, config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/md5/__init__.py b/esphome/components/md5/__init__.py index 1710b00e66..6a928d1682 100644 --- a/esphome/components/md5/__init__.py +++ b/esphome/components/md5/__init__.py @@ -1,11 +1,12 @@ import esphome.codegen as cg from esphome.core import CORE from esphome.helpers import IS_MACOS +from esphome.types import ConfigType CODEOWNERS = ["@esphome/core"] -async def to_code(config): +async def to_code(config: ConfigType) -> None: cg.add_define("USE_MD5") # Add OpenSSL library for host platform diff --git a/esphome/components/mdns/__init__.py b/esphome/components/mdns/__init__.py index 24bce0cc3c..c9334ea97a 100644 --- a/esphome/components/mdns/__init__.py +++ b/esphome/components/mdns/__init__.py @@ -31,7 +31,7 @@ MDNSTXTRecord = mdns_ns.struct("MDNSTXTRecord") MDNSService = mdns_ns.struct("MDNSService") -def _remove_id_if_disabled(value): +def _remove_id_if_disabled(value: ConfigType) -> ConfigType: value = value.copy() if value[CONF_DISABLED]: value.pop(CONF_ID) @@ -117,7 +117,7 @@ def mdns_txt_record(key: str, value: str) -> cg.RawExpression: async def _mdns_txt_record_templated( - mdns_comp: cg.Pvariable, key: str, value: Lambda | str + mdns_comp: cg.MockObj, key: str, value: Lambda | str ) -> cg.RawExpression: """Create a mDNS TXT record with support for templated values. @@ -172,7 +172,7 @@ def mdns_service( ) -def enable_mdns_storage(): +def enable_mdns_storage() -> None: """Enable persistent storage of mDNS services in the MDNSComponent. Called by external components (like OpenThread) that need access to @@ -184,7 +184,7 @@ def enable_mdns_storage(): @coroutine_with_priority(CoroPriority.NETWORK_SERVICES) -async def to_code(config): +async def to_code(config: ConfigType) -> None: if config[CONF_DISABLED] is True: return diff --git a/esphome/components/media_source/__init__.py b/esphome/components/media_source/__init__.py index 43256db4af..c9dab7e4d2 100644 --- a/esphome/components/media_source/__init__.py +++ b/esphome/components/media_source/__init__.py @@ -3,7 +3,8 @@ import esphome.config_validation as cv from esphome.const import CONF_ID from esphome.core import CORE from esphome.coroutine import CoroPriority, coroutine_with_priority -from esphome.cpp_generator import MockObjClass +from esphome.cpp_generator import MockObj, MockObjClass +from esphome.types import ConfigType CODEOWNERS = ["@kahrendt"] @@ -16,7 +17,7 @@ media_source_ns = cg.esphome_ns.namespace("media_source") MediaSource = media_source_ns.class_("MediaSource") -async def register_media_source(var, config): +async def register_media_source(var: MockObj, config: ConfigType) -> MockObj: if not CORE.has_id(config[CONF_ID]): var = cg.Pvariable(config[CONF_ID], var) CORE.register_platform_component("media_source", var) @@ -35,6 +36,6 @@ def media_source_schema( @coroutine_with_priority(CoroPriority.CORE) -async def to_code(config): +async def to_code(config: ConfigType) -> None: cg.add_global(media_source_ns.using) cg.add_define("USE_MEDIA_SOURCE") diff --git a/esphome/components/mics_4514/sensor.py b/esphome/components/mics_4514/sensor.py index 09329ebfcf..3ba560c781 100644 --- a/esphome/components/mics_4514/sensor.py +++ b/esphome/components/mics_4514/sensor.py @@ -14,6 +14,7 @@ from esphome.const import ( STATE_CLASS_MEASUREMENT, UNIT_PARTS_PER_MILLION, ) +from esphome.types import ConfigType CODEOWNERS = ["@jesserockz"] DEPENDENCIES = ["i2c"] @@ -56,7 +57,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/midea_ir/climate.py b/esphome/components/midea_ir/climate.py index cbf5fae6fe..84bfeab0d4 100644 --- a/esphome/components/midea_ir/climate.py +++ b/esphome/components/midea_ir/climate.py @@ -2,6 +2,7 @@ import esphome.codegen as cg from esphome.components import climate_ir import esphome.config_validation as cv from esphome.const import CONF_USE_FAHRENHEIT +from esphome.types import ConfigType AUTO_LOAD = ["climate_ir", "coolix"] CODEOWNERS = ["@dudanov"] @@ -17,6 +18,6 @@ CONFIG_SCHEMA = climate_ir.climate_ir_with_receiver_schema(MideaIR).extend( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await climate_ir.new_climate_ir(config) cg.add(var.set_fahrenheit(config[CONF_USE_FAHRENHEIT])) diff --git a/esphome/components/mitsubishi/climate.py b/esphome/components/mitsubishi/climate.py index 8291d70346..2d38351898 100644 --- a/esphome/components/mitsubishi/climate.py +++ b/esphome/components/mitsubishi/climate.py @@ -1,6 +1,7 @@ import esphome.codegen as cg from esphome.components import climate_ir import esphome.config_validation as cv +from esphome.types import ConfigType CODEOWNERS = ["@RubyBailey"] AUTO_LOAD = ["climate_ir"] @@ -58,7 +59,7 @@ CONFIG_SCHEMA = climate_ir.climate_ir_with_receiver_schema(MitsubishiClimate).ex ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await climate_ir.new_climate_ir(config) cg.add(var.set_fan_mode(config[CONF_SET_FAN_MODE])) diff --git a/esphome/components/mlx90393/sensor.py b/esphome/components/mlx90393/sensor.py index a6330b1cc0..59bdffc114 100644 --- a/esphome/components/mlx90393/sensor.py +++ b/esphome/components/mlx90393/sensor.py @@ -17,6 +17,7 @@ from esphome.const import ( UNIT_CELSIUS, UNIT_MICROTESLA, ) +from esphome.types import ConfigType CODEOWNERS = ["@functionpointer"] DEPENDENCIES = ["i2c"] @@ -52,7 +53,7 @@ CONF_DRDY_PIN = "drdy_pin" CONF_HALLCONF = "hallconf" -def _validate(config): +def _validate(config: ConfigType) -> ConfigType: if config[CONF_TEMPERATURE_COMPENSATION]: for axis in [CONF_X_AXIS, CONF_Y_AXIS, CONF_Z_AXIS]: if axis not in config: @@ -74,7 +75,7 @@ def _validate(config): return config -def mlx90393_axis_schema(): +def mlx90393_axis_schema() -> cv.Schema: return sensor.sensor_schema( unit_of_measurement=UNIT_MICROTESLA, accuracy_decimals=0, @@ -127,7 +128,7 @@ CONFIG_SCHEMA = cv.All( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/mlx90614/sensor.py b/esphome/components/mlx90614/sensor.py index 6a34c4bdc0..0cf9b95dde 100644 --- a/esphome/components/mlx90614/sensor.py +++ b/esphome/components/mlx90614/sensor.py @@ -7,6 +7,7 @@ from esphome.const import ( STATE_CLASS_MEASUREMENT, UNIT_CELSIUS, ) +from esphome.types import ConfigType CODEOWNERS = ["@jesserockz"] DEPENDENCIES = ["i2c"] @@ -47,7 +48,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/mmc5603/sensor.py b/esphome/components/mmc5603/sensor.py index 6d2bafdd0e..a9f240508c 100644 --- a/esphome/components/mmc5603/sensor.py +++ b/esphome/components/mmc5603/sensor.py @@ -15,6 +15,8 @@ from esphome.const import ( UNIT_DEGREES, UNIT_MICROTESLA, ) +from esphome.cpp_generator import MockObj +from esphome.types import ConfigType CONF_AUTO_SET_RESET = "auto_set_reset" @@ -65,7 +67,7 @@ CONFIG_SCHEMA = ( ) -def auto_data_rate(config): +def auto_data_rate(config: ConfigType) -> MockObj: interval_msec = config[CONF_UPDATE_INTERVAL].total_milliseconds interval_hz = 1000.0 / interval_msec for datarate in sorted(MMC5603Datarates.keys()): @@ -74,7 +76,7 @@ def auto_data_rate(config): return MMC5603Datarates[75] -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/mmc5983/sensor.py b/esphome/components/mmc5983/sensor.py index aaff2946f2..797181690f 100644 --- a/esphome/components/mmc5983/sensor.py +++ b/esphome/components/mmc5983/sensor.py @@ -10,6 +10,7 @@ from esphome.const import ( STATE_CLASS_MEASUREMENT, UNIT_MICROTESLA, ) +from esphome.types import ConfigType DEPENDENCIES = ["i2c"] @@ -39,7 +40,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/modbus_server/__init__.py b/esphome/components/modbus_server/__init__.py index 249454b6b0..0de40a4cc1 100644 --- a/esphome/components/modbus_server/__init__.py +++ b/esphome/components/modbus_server/__init__.py @@ -151,7 +151,7 @@ def _final_validate(config: ConfigType) -> None: FINAL_VALIDATE_SCHEMA = _final_validate -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) if server_courtesy_response := config.get(CONF_COURTESY_RESPONSE): cg.add( diff --git a/esphome/components/monochromatic/light.py b/esphome/components/monochromatic/light.py index 4ce0202d25..04336bcde1 100644 --- a/esphome/components/monochromatic/light.py +++ b/esphome/components/monochromatic/light.py @@ -2,6 +2,7 @@ import esphome.codegen as cg from esphome.components import light, output import esphome.config_validation as cv from esphome.const import CONF_OUTPUT, CONF_OUTPUT_ID +from esphome.types import ConfigType monochromatic_ns = cg.esphome_ns.namespace("monochromatic") MonochromaticLightOutput = monochromatic_ns.class_( @@ -16,7 +17,7 @@ CONFIG_SCHEMA = light.BRIGHTNESS_ONLY_LIGHT_SCHEMA.extend( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_OUTPUT_ID]) await light.register_light(var, config) diff --git a/esphome/components/mopeka_ble/__init__.py b/esphome/components/mopeka_ble/__init__.py index ab261142b8..ec7deb3067 100644 --- a/esphome/components/mopeka_ble/__init__.py +++ b/esphome/components/mopeka_ble/__init__.py @@ -2,6 +2,7 @@ import esphome.codegen as cg from esphome.components import ble_device_base import esphome.config_validation as cv from esphome.const import CONF_ID +from esphome.types import ConfigType CODEOWNERS = ["@spbrogan", "@Fabian-Schmidt"] AUTO_LOAD = ["ble_device_base"] @@ -24,7 +25,7 @@ CONFIG_SCHEMA = cv.All( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) if CONF_SHOW_SENSORS_WITHOUT_SYNC in config: cg.add( diff --git a/esphome/components/mopeka_pro_check/sensor.py b/esphome/components/mopeka_pro_check/sensor.py index 0d10970550..5f7c9445f2 100644 --- a/esphome/components/mopeka_pro_check/sensor.py +++ b/esphome/components/mopeka_pro_check/sensor.py @@ -1,3 +1,5 @@ +from typing import Any + import esphome.codegen as cg from esphome.components import ble_device_base, sensor import esphome.config_validation as cv @@ -21,6 +23,7 @@ from esphome.const import ( UNIT_MILLIMETER, UNIT_PERCENT, ) +from esphome.types import ConfigType CONF_TANK_TYPE = "tank_type" CONF_CUSTOM_DISTANCE_FULL = "custom_distance_full" @@ -34,7 +37,7 @@ ICON_PROPANE_TANK = "mdi:propane-tank" TANK_TYPE_CUSTOM = "CUSTOM" -def small_distance(value): +def small_distance(value: Any) -> float: """small_distance is stored in mm""" meters = cv.distance(value) return meters * 1000 @@ -128,7 +131,7 @@ CONFIG_SCHEMA = cv.All( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await ble_device_base.register_ble_device(var, config) diff --git a/esphome/components/mopeka_std_check/sensor.py b/esphome/components/mopeka_std_check/sensor.py index 5cc4ea3039..d5c5d4135d 100644 --- a/esphome/components/mopeka_std_check/sensor.py +++ b/esphome/components/mopeka_std_check/sensor.py @@ -1,3 +1,5 @@ +from typing import Any + import esphome.codegen as cg from esphome.components import ble_device_base, sensor import esphome.config_validation as cv @@ -17,6 +19,7 @@ from esphome.const import ( UNIT_MILLIMETER, UNIT_PERCENT, ) +from esphome.types import ConfigType CONF_TANK_TYPE = "tank_type" CONF_CUSTOM_DISTANCE_FULL = "custom_distance_full" @@ -28,7 +31,7 @@ ICON_PROPANE_TANK = "mdi:propane-tank" TANK_TYPE_CUSTOM = "CUSTOM" -def small_distance(value): +def small_distance(value: Any) -> float: """small_distance is stored in mm""" meters = cv.distance(value) return meters * 1000 @@ -99,7 +102,7 @@ CONFIG_SCHEMA = cv.All( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await ble_device_base.register_ble_device(var, config) diff --git a/esphome/components/mpl3115a2/sensor.py b/esphome/components/mpl3115a2/sensor.py index b2cd1fb535..4fbc353644 100644 --- a/esphome/components/mpl3115a2/sensor.py +++ b/esphome/components/mpl3115a2/sensor.py @@ -13,6 +13,7 @@ from esphome.const import ( UNIT_HECTOPASCAL, UNIT_METER, ) +from esphome.types import ConfigType CODEOWNERS = ["@kbickar"] DEPENDENCIES = ["i2c"] @@ -58,7 +59,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/mpu6050/sensor.py b/esphome/components/mpu6050/sensor.py index 377958fbe7..a8370ced7f 100644 --- a/esphome/components/mpu6050/sensor.py +++ b/esphome/components/mpu6050/sensor.py @@ -12,6 +12,7 @@ from esphome.const import ( UNIT_DEGREE_PER_SECOND, UNIT_METER_PER_SECOND_SQUARED, ) +from esphome.types import ConfigType DEPENDENCIES = ["i2c"] @@ -64,7 +65,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/mpu6886/sensor.py b/esphome/components/mpu6886/sensor.py index 580fad7c23..5bdb836128 100644 --- a/esphome/components/mpu6886/sensor.py +++ b/esphome/components/mpu6886/sensor.py @@ -12,6 +12,7 @@ from esphome.const import ( UNIT_DEGREE_PER_SECOND, UNIT_METER_PER_SECOND_SQUARED, ) +from esphome.types import ConfigType CODEOWNERS = ["@fabaff"] DEPENDENCIES = ["i2c"] @@ -65,7 +66,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/mqtt_subscribe/sensor/__init__.py b/esphome/components/mqtt_subscribe/sensor/__init__.py index 56efb3f67e..e451d2db8a 100644 --- a/esphome/components/mqtt_subscribe/sensor/__init__.py +++ b/esphome/components/mqtt_subscribe/sensor/__init__.py @@ -2,6 +2,7 @@ import esphome.codegen as cg from esphome.components import mqtt, sensor import esphome.config_validation as cv from esphome.const import CONF_QOS, CONF_TOPIC +from esphome.types import ConfigType from .. import mqtt_subscribe_ns @@ -28,7 +29,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await sensor.new_sensor(config) await cg.register_component(var, config) diff --git a/esphome/components/mqtt_subscribe/text_sensor/__init__.py b/esphome/components/mqtt_subscribe/text_sensor/__init__.py index 9c5d3a81eb..d432ef8a93 100644 --- a/esphome/components/mqtt_subscribe/text_sensor/__init__.py +++ b/esphome/components/mqtt_subscribe/text_sensor/__init__.py @@ -2,6 +2,7 @@ import esphome.codegen as cg from esphome.components import mqtt, text_sensor import esphome.config_validation as cv from esphome.const import CONF_QOS, CONF_TOPIC +from esphome.types import ConfigType from .. import mqtt_subscribe_ns @@ -26,7 +27,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await text_sensor.new_text_sensor(config) await cg.register_component(var, config) diff --git a/esphome/components/ms5611/sensor.py b/esphome/components/ms5611/sensor.py index dfb6083bef..e42e0824dd 100644 --- a/esphome/components/ms5611/sensor.py +++ b/esphome/components/ms5611/sensor.py @@ -12,6 +12,7 @@ from esphome.const import ( UNIT_CELSIUS, UNIT_HECTOPASCAL, ) +from esphome.types import ConfigType DEPENDENCIES = ["i2c"] @@ -44,7 +45,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/ms8607/sensor.py b/esphome/components/ms8607/sensor.py index 038f17190a..e5d90432d8 100644 --- a/esphome/components/ms8607/sensor.py +++ b/esphome/components/ms8607/sensor.py @@ -14,6 +14,7 @@ from esphome.const import ( UNIT_HECTOPASCAL, UNIT_PERCENT, ) +from esphome.types import ConfigType DEPENDENCIES = ["i2c"] @@ -62,7 +63,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/my9231/__init__.py b/esphome/components/my9231/__init__.py index e5a879a0f0..e43454d6ed 100644 --- a/esphome/components/my9231/__init__.py +++ b/esphome/components/my9231/__init__.py @@ -9,6 +9,7 @@ from esphome.const import ( CONF_NUM_CHANNELS, CONF_NUM_CHIPS, ) +from esphome.types import ConfigType AUTO_LOAD = ["output"] my9231_ns = cg.esphome_ns.namespace("my9231") @@ -27,7 +28,7 @@ CONFIG_SCHEMA = cv.Schema( ).extend(cv.COMPONENT_SCHEMA) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) diff --git a/esphome/components/my9231/output.py b/esphome/components/my9231/output.py index b4fad82c5f..c2ec15d411 100644 --- a/esphome/components/my9231/output.py +++ b/esphome/components/my9231/output.py @@ -2,6 +2,7 @@ import esphome.codegen as cg from esphome.components import output import esphome.config_validation as cv from esphome.const import CONF_CHANNEL, CONF_ID +from esphome.types import ConfigType from . import MY9231OutputComponent @@ -19,7 +20,7 @@ CONFIG_SCHEMA = output.FLOAT_OUTPUT_SCHEMA.extend( ).extend(cv.COMPONENT_SCHEMA) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await output.register_output(var, config) diff --git a/esphome/components/network/__init__.py b/esphome/components/network/__init__.py index 96a6f11b9a..9a47679ba3 100644 --- a/esphome/components/network/__init__.py +++ b/esphome/components/network/__init__.py @@ -364,7 +364,7 @@ FINAL_VALIDATE_SCHEMA = _final_validate @coroutine_with_priority(CoroPriority.NETWORK) -async def to_code(config): +async def to_code(config: ConfigType) -> None: cg.add_define("USE_NETWORK") # ESP32 with Arduino uses ESP-IDF network APIs directly, no Arduino Network library needed diff --git a/esphome/components/nfc/binary_sensor/__init__.py b/esphome/components/nfc/binary_sensor/__init__.py index 47cf014550..e9747d7a14 100644 --- a/esphome/components/nfc/binary_sensor/__init__.py +++ b/esphome/components/nfc/binary_sensor/__init__.py @@ -1,8 +1,11 @@ +from typing import Any + import esphome.codegen as cg from esphome.components import binary_sensor import esphome.config_validation as cv from esphome.const import CONF_UID from esphome.core import HexInt +from esphome.types import ConfigType from .. import Nfcc, NfcTagListener, nfc_ns @@ -21,7 +24,7 @@ NfcTagBinarySensor = nfc_ns.class_( ) -def validate_uid(value): +def validate_uid(value: Any) -> str: value = cv.string_strict(value) for x in value.split("-"): if len(x) != 2: @@ -56,7 +59,7 @@ CONFIG_SCHEMA = cv.All( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await binary_sensor.new_binary_sensor(config) await cg.register_component(var, config) await cg.register_parented(var, config[CONF_NFCC_ID]) diff --git a/esphome/components/noblex/climate.py b/esphome/components/noblex/climate.py index 19c4b6a08e..89fff517fb 100644 --- a/esphome/components/noblex/climate.py +++ b/esphome/components/noblex/climate.py @@ -1,5 +1,6 @@ import esphome.codegen as cg from esphome.components import climate_ir +from esphome.types import ConfigType AUTO_LOAD = ["climate_ir"] @@ -9,5 +10,5 @@ NoblexClimate = noblex_ns.class_("NoblexClimate", climate_ir.ClimateIR) CONFIG_SCHEMA = climate_ir.climate_ir_with_receiver_schema(NoblexClimate) -async def to_code(config): +async def to_code(config: ConfigType) -> None: await climate_ir.new_climate_ir(config) diff --git a/esphome/components/npi19/sensor.py b/esphome/components/npi19/sensor.py index d13e72f5f8..4c7db10ce9 100644 --- a/esphome/components/npi19/sensor.py +++ b/esphome/components/npi19/sensor.py @@ -8,6 +8,7 @@ from esphome.const import ( STATE_CLASS_MEASUREMENT, UNIT_CELSIUS, ) +from esphome.types import ConfigType CODEOWNERS = ["@bakerkj"] DEPENDENCIES = ["i2c"] @@ -38,7 +39,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/one_wire/__init__.py b/esphome/components/one_wire/__init__.py index 9173b7014b..8d35aaa34e 100644 --- a/esphome/components/one_wire/__init__.py +++ b/esphome/components/one_wire/__init__.py @@ -1,6 +1,8 @@ import esphome.codegen as cg import esphome.config_validation as cv from esphome.const import CONF_ADDRESS, CONF_INDEX +from esphome.cpp_generator import MockObj +from esphome.types import ConfigType CODEOWNERS = ["@ssieb"] @@ -13,7 +15,7 @@ OneWireBus = one_wire_ns.class_("OneWireBus") OneWireDevice = one_wire_ns.class_("OneWireDevice") -def one_wire_device_schema(): +def one_wire_device_schema() -> cv.Schema: """Create a schema for a 1-wire device. :return: The 1-wire device schema, `extend` this in your config schema. @@ -27,7 +29,7 @@ def one_wire_device_schema(): ) -async def register_one_wire_device(var, config): +async def register_one_wire_device(var: MockObj, config: ConfigType) -> None: """Register an 1-wire device with the given config. Sets the 1-wire bus to use and the 1-wire address. diff --git a/esphome/components/opt3001/sensor.py b/esphome/components/opt3001/sensor.py index 8490b0bd49..01ea125630 100644 --- a/esphome/components/opt3001/sensor.py +++ b/esphome/components/opt3001/sensor.py @@ -2,6 +2,7 @@ import esphome.codegen as cg from esphome.components import i2c, sensor import esphome.config_validation as cv from esphome.const import DEVICE_CLASS_ILLUMINANCE, STATE_CLASS_MEASUREMENT, UNIT_LUX +from esphome.types import ConfigType DEPENDENCIES = ["i2c"] CODEOWNERS = ["@ccutrer"] @@ -25,7 +26,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await sensor.new_sensor(config) await cg.register_component(var, config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/packages/__init__.py b/esphome/components/packages/__init__.py index 4d1814ac7a..171c6753ae 100644 --- a/esphome/components/packages/__init__.py +++ b/esphome/components/packages/__init__.py @@ -88,7 +88,7 @@ def valid_package_contents(package_config: dict) -> dict: return package_config -def expand_file_to_files(config: dict): +def expand_file_to_files(config: dict) -> dict: if CONF_FILE in config: new_config = config new_config[CONF_FILES] = [config[CONF_FILE]] @@ -97,7 +97,7 @@ def expand_file_to_files(config: dict): return config -def validate_yaml_filename(value): +def validate_yaml_filename(value: Any) -> str: value = cv.string(value) if not value.endswith((".yaml", ".yml")): @@ -106,7 +106,7 @@ def validate_yaml_filename(value): return value -def validate_source_shorthand(value): +def validate_source_shorthand(value: Any) -> dict: if not isinstance(value, str): raise cv.Invalid("Git URL shorthand only for strings") diff --git a/esphome/components/partition/light.py b/esphome/components/partition/light.py index 58de1183ff..b2341f95b7 100644 --- a/esphome/components/partition/light.py +++ b/esphome/components/partition/light.py @@ -14,6 +14,7 @@ from esphome.const import ( CONF_TO, ) import esphome.final_validate as fv +from esphome.types import ConfigType partitions_ns = cg.esphome_ns.namespace("partition") AddressableSegment = partitions_ns.class_("AddressableSegment") @@ -25,7 +26,7 @@ PartitionLightOutput = partitions_ns.class_( ) -def validate_from_to(value): +def validate_from_to(value: ConfigType) -> ConfigType: if CONF_ID in value and value[CONF_FROM] > value[CONF_TO]: raise cv.Invalid( f"From ({value[CONF_FROM]}) must not be larger than to ({value[CONF_TO]})" @@ -33,7 +34,7 @@ def validate_from_to(value): return value -def validate_segment(config): +def validate_segment(config: ConfigType) -> None: fconf = fv.full_config.get() if CONF_ID in config: # only validate addressable segments @@ -94,7 +95,7 @@ FINAL_VALIDATE_SCHEMA = cv.Schema( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: segments = [] for conf in config[CONF_SEGMENTS]: if CONF_SINGLE_LIGHT_ID in conf: diff --git a/esphome/components/pca6416a/__init__.py b/esphome/components/pca6416a/__init__.py index 1df22a8ff5..47b9118d9a 100644 --- a/esphome/components/pca6416a/__init__.py +++ b/esphome/components/pca6416a/__init__.py @@ -12,6 +12,8 @@ from esphome.const import ( CONF_OUTPUT, CONF_PULLUP, ) +from esphome.cpp_generator import MockObj +from esphome.types import ConfigType CODEOWNERS = ["@Mat931"] DEPENDENCIES = ["i2c"] @@ -37,7 +39,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await i2c.register_i2c_device(var, config) @@ -45,7 +47,7 @@ async def to_code(config): cg.add(var.set_interrupt_pin(await cg.gpio_pin_expression(interrupt_pin))) -def validate_mode(value): +def validate_mode(value: ConfigType) -> ConfigType: if not (value[CONF_INPUT] or value[CONF_OUTPUT]): raise cv.Invalid("Mode must be either input or output") if value[CONF_INPUT] and value[CONF_OUTPUT]: @@ -74,7 +76,7 @@ PCA6416A_PIN_SCHEMA = cv.All( @pins.PIN_SCHEMA_REGISTRY.register(CONF_PCA6416A, PCA6416A_PIN_SCHEMA) -async def pca6416a_pin_to_code(config): +async def pca6416a_pin_to_code(config: ConfigType) -> MockObj: var = cg.new_Pvariable(config[CONF_ID]) parent = await cg.get_variable(config[CONF_PCA6416A]) diff --git a/esphome/components/pca9685/__init__.py b/esphome/components/pca9685/__init__.py index 0e238ff7da..817cfd1c30 100644 --- a/esphome/components/pca9685/__init__.py +++ b/esphome/components/pca9685/__init__.py @@ -7,6 +7,7 @@ from esphome.const import ( CONF_ID, CONF_PHASE_BALANCER, ) +from esphome.types import ConfigType DEPENDENCIES = ["i2c"] MULTI_CONF = True @@ -21,7 +22,7 @@ PHASE_BALANCERS = { } -def validate_frequency(config): +def validate_frequency(config: ConfigType) -> ConfigType: if config[CONF_EXTERNAL_CLOCK_INPUT]: if CONF_FREQUENCY in config: raise cv.Invalid( @@ -52,7 +53,7 @@ CONFIG_SCHEMA = cv.All( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) if CONF_FREQUENCY in config: cg.add(var.set_frequency(config[CONF_FREQUENCY])) diff --git a/esphome/components/pca9685/output.py b/esphome/components/pca9685/output.py index 302c2f78c0..3bb8882ed3 100644 --- a/esphome/components/pca9685/output.py +++ b/esphome/components/pca9685/output.py @@ -2,6 +2,7 @@ import esphome.codegen as cg from esphome.components import output import esphome.config_validation as cv from esphome.const import CONF_CHANNEL, CONF_ID +from esphome.types import ConfigType from . import PCA9685Output, pca9685_ns @@ -19,7 +20,7 @@ CONFIG_SCHEMA = output.FLOAT_OUTPUT_SCHEMA.extend( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: paren = await cg.get_variable(config[CONF_PCA9685_ID]) var = cg.new_Pvariable(config[CONF_ID]) cg.add(var.set_channel(config[CONF_CHANNEL])) diff --git a/esphome/components/pcd8544/display.py b/esphome/components/pcd8544/display.py index 2f6dcc56ed..42cef67488 100644 --- a/esphome/components/pcd8544/display.py +++ b/esphome/components/pcd8544/display.py @@ -11,6 +11,7 @@ from esphome.const import ( CONF_PAGES, CONF_RESET_PIN, ) +from esphome.types import ConfigType DEPENDENCIES = ["spi"] @@ -40,7 +41,7 @@ FINAL_VALIDATE_SCHEMA = spi.final_validate_device_schema( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await display.register_display(var, config) diff --git a/esphome/components/pcf8574/__init__.py b/esphome/components/pcf8574/__init__.py index 559fe1d76d..9f8c7fabd2 100644 --- a/esphome/components/pcf8574/__init__.py +++ b/esphome/components/pcf8574/__init__.py @@ -11,6 +11,8 @@ from esphome.const import ( CONF_NUMBER, CONF_OUTPUT, ) +from esphome.cpp_generator import MockObj +from esphome.types import ConfigType AUTO_LOAD = ["gpio_expander"] DEPENDENCIES = ["i2c"] @@ -36,7 +38,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await i2c.register_i2c_device(var, config) @@ -45,7 +47,7 @@ async def to_code(config): cg.add(var.set_interrupt_pin(await cg.gpio_pin_expression(interrupt_pin))) -def validate_mode(value): +def validate_mode(value: ConfigType) -> ConfigType: if not (value[CONF_INPUT] or value[CONF_OUTPUT]): raise cv.Invalid("Mode must be either input or output") if value[CONF_INPUT] and value[CONF_OUTPUT]: @@ -67,7 +69,7 @@ PCF8574_PIN_SCHEMA = pins.gpio_base_schema( @pins.PIN_SCHEMA_REGISTRY.register(CONF_PCF8574, PCF8574_PIN_SCHEMA) -async def pcf8574_pin_to_code(config): +async def pcf8574_pin_to_code(config: ConfigType) -> MockObj: var = cg.new_Pvariable(config[CONF_ID]) parent = await cg.get_variable(config[CONF_PCF8574]) diff --git a/esphome/components/pi4ioe5v6408/__init__.py b/esphome/components/pi4ioe5v6408/__init__.py index ee270138e1..11a5dd62bb 100644 --- a/esphome/components/pi4ioe5v6408/__init__.py +++ b/esphome/components/pi4ioe5v6408/__init__.py @@ -14,6 +14,8 @@ from esphome.const import ( CONF_PULLUP, CONF_RESET, ) +from esphome.cpp_generator import MockObj +from esphome.types import ConfigType AUTO_LOAD = ["gpio_expander"] CODEOWNERS = ["@jesserockz"] @@ -42,7 +44,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await i2c.register_i2c_device(var, config) @@ -52,7 +54,7 @@ async def to_code(config): cg.add(var.set_interrupt_pin(await cg.gpio_pin_expression(interrupt_pin))) -def validate_mode(value): +def validate_mode(value: ConfigType) -> ConfigType: if not (value[CONF_INPUT] or value[CONF_OUTPUT]): raise cv.Invalid("Mode must be either input or output") if value[CONF_INPUT] and value[CONF_OUTPUT]: @@ -78,7 +80,7 @@ PI4IOE5V6408_PIN_SCHEMA = pins.gpio_base_schema( @pins.PIN_SCHEMA_REGISTRY.register(CONF_PI4IOE5V6408, PI4IOE5V6408_PIN_SCHEMA) -async def pi4ioe5v6408_pin_schema(config): +async def pi4ioe5v6408_pin_schema(config: ConfigType) -> MockObj: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_parented(var, config[CONF_PI4IOE5V6408]) diff --git a/esphome/components/pm1006/sensor.py b/esphome/components/pm1006/sensor.py index 8ff21ab069..8274726ac4 100644 --- a/esphome/components/pm1006/sensor.py +++ b/esphome/components/pm1006/sensor.py @@ -11,6 +11,7 @@ from esphome.const import ( STATE_CLASS_MEASUREMENT, UNIT_MICROGRAMS_PER_CUBIC_METER, ) +from esphome.types import ConfigType CODEOWNERS = ["@habbie"] DEPENDENCIES = ["uart"] @@ -40,7 +41,7 @@ CONFIG_SCHEMA = cv.All( ) -def validate_interval_uart(config): +def validate_interval_uart(config: ConfigType) -> None: interval = config.get(CONF_UPDATE_INTERVAL) uart.final_validate_device_schema( "pm1006", @@ -53,7 +54,7 @@ def validate_interval_uart(config): FINAL_VALIDATE_SCHEMA = validate_interval_uart -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await uart.register_uart_device(var, config) diff --git a/esphome/components/pm2005/sensor.py b/esphome/components/pm2005/sensor.py index 3a650560a0..f16c100e5e 100644 --- a/esphome/components/pm2005/sensor.py +++ b/esphome/components/pm2005/sensor.py @@ -16,6 +16,7 @@ from esphome.const import ( STATE_CLASS_MEASUREMENT, UNIT_MICROGRAMS_PER_CUBIC_METER, ) +from esphome.types import ConfigType DEPENDENCIES = ["i2c"] CODEOWNERS = ["@andrewjswan"] @@ -65,7 +66,7 @@ CONFIG_SCHEMA = cv.All( ) -async def to_code(config) -> None: +async def to_code(config: ConfigType) -> None: """Code generation entry point.""" var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) diff --git a/esphome/components/pmsa003i/sensor.py b/esphome/components/pmsa003i/sensor.py index 2a5b9eeac0..14f27f89cc 100644 --- a/esphome/components/pmsa003i/sensor.py +++ b/esphome/components/pmsa003i/sensor.py @@ -18,6 +18,7 @@ from esphome.const import ( STATE_CLASS_MEASUREMENT, UNIT_MICROGRAMS_PER_CUBIC_METER, ) +from esphome.types import ConfigType CODEOWNERS = ["@sjtrny"] DEPENDENCIES = ["i2c"] @@ -114,7 +115,7 @@ TYPES = { } -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/pn532_i2c/__init__.py b/esphome/components/pn532_i2c/__init__.py index 7304f1b8ad..16b877b1f1 100644 --- a/esphome/components/pn532_i2c/__init__.py +++ b/esphome/components/pn532_i2c/__init__.py @@ -2,6 +2,7 @@ import esphome.codegen as cg from esphome.components import i2c, pn532 import esphome.config_validation as cv from esphome.const import CONF_ID +from esphome.types import ConfigType AUTO_LOAD = ["pn532"] CODEOWNERS = ["@OttoWinter", "@jesserockz"] @@ -20,7 +21,7 @@ CONFIG_SCHEMA = cv.All( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await pn532.setup_pn532(var, config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/pn532_spi/__init__.py b/esphome/components/pn532_spi/__init__.py index 67ebc88872..734f794180 100644 --- a/esphome/components/pn532_spi/__init__.py +++ b/esphome/components/pn532_spi/__init__.py @@ -2,6 +2,7 @@ import esphome.codegen as cg from esphome.components import pn532, spi import esphome.config_validation as cv from esphome.const import CONF_ID +from esphome.types import ConfigType AUTO_LOAD = ["pn532"] CODEOWNERS = ["@OttoWinter", "@jesserockz"] @@ -20,7 +21,7 @@ CONFIG_SCHEMA = cv.All( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await pn532.setup_pn532(var, config) await spi.register_spi_device(var, config) diff --git a/esphome/components/pn7150_i2c/__init__.py b/esphome/components/pn7150_i2c/__init__.py index 00a19ba03c..d15c0b431e 100644 --- a/esphome/components/pn7150_i2c/__init__.py +++ b/esphome/components/pn7150_i2c/__init__.py @@ -2,6 +2,7 @@ import esphome.codegen as cg from esphome.components import i2c, pn7150 import esphome.config_validation as cv from esphome.const import CONF_ID +from esphome.types import ConfigType AUTO_LOAD = ["pn7150"] CODEOWNERS = ["@kbx81", "@jesserockz"] @@ -19,7 +20,7 @@ CONFIG_SCHEMA = cv.All( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await pn7150.setup_pn7150(var, config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/pn7160_i2c/__init__.py b/esphome/components/pn7160_i2c/__init__.py index f8f8ebef98..d711c3e48f 100644 --- a/esphome/components/pn7160_i2c/__init__.py +++ b/esphome/components/pn7160_i2c/__init__.py @@ -2,6 +2,7 @@ import esphome.codegen as cg from esphome.components import i2c, pn7160 import esphome.config_validation as cv from esphome.const import CONF_ID +from esphome.types import ConfigType AUTO_LOAD = ["pn7160"] CODEOWNERS = ["@kbx81", "@jesserockz"] @@ -19,7 +20,7 @@ CONFIG_SCHEMA = cv.All( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await pn7160.setup_pn7160(var, config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/pn7160_spi/__init__.py b/esphome/components/pn7160_spi/__init__.py index 5498d0ac1b..7705dfa6f6 100644 --- a/esphome/components/pn7160_spi/__init__.py +++ b/esphome/components/pn7160_spi/__init__.py @@ -2,6 +2,7 @@ import esphome.codegen as cg from esphome.components import pn7160, spi import esphome.config_validation as cv from esphome.const import CONF_ID +from esphome.types import ConfigType AUTO_LOAD = ["pn7160"] CODEOWNERS = ["@kbx81", "@jesserockz"] @@ -20,7 +21,7 @@ CONFIG_SCHEMA = cv.All( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await pn7160.setup_pn7160(var, config) await spi.register_spi_device(var, config) diff --git a/esphome/components/power_supply/__init__.py b/esphome/components/power_supply/__init__.py index 851c136493..b68118b352 100644 --- a/esphome/components/power_supply/__init__.py +++ b/esphome/components/power_supply/__init__.py @@ -8,6 +8,7 @@ from esphome.const import ( CONF_KEEP_ON_TIME, CONF_PIN, ) +from esphome.types import ConfigType CODEOWNERS = ["@esphome/core"] power_supply_ns = cg.esphome_ns.namespace("power_supply") @@ -29,7 +30,7 @@ CONFIG_SCHEMA = cv.Schema( ).extend(cv.COMPONENT_SCHEMA) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) diff --git a/esphome/components/preferences/__init__.py b/esphome/components/preferences/__init__.py index f3f2f632c9..c92903ec2e 100644 --- a/esphome/components/preferences/__init__.py +++ b/esphome/components/preferences/__init__.py @@ -4,6 +4,7 @@ import esphome.config_validation as cv from esphome.const import CONF_ID from esphome.core import coroutine_with_priority from esphome.coroutine import CoroPriority +from esphome.types import ConfigType CODEOWNERS = ["@esphome/core"] @@ -27,7 +28,7 @@ CONFIG_SCHEMA = cv.Schema( @coroutine_with_priority(CoroPriority.PREFERENCES) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) write_interval = config[CONF_FLASH_WRITE_INTERVAL] if write_interval.total_milliseconds == 0: diff --git a/esphome/components/prometheus/__init__.py b/esphome/components/prometheus/__init__.py index cc1541ce80..3624fb2442 100644 --- a/esphome/components/prometheus/__init__.py +++ b/esphome/components/prometheus/__init__.py @@ -4,6 +4,7 @@ from esphome.components.web_server_base import CONF_WEB_SERVER_BASE_ID import esphome.config_validation as cv from esphome.const import CONF_ID, CONF_INCLUDE_INTERNAL, CONF_NAME, CONF_RELABEL from esphome.cpp_types import EntityBase +from esphome.types import ConfigType AUTO_LOAD = ["web_server_base"] @@ -36,7 +37,7 @@ CONFIG_SCHEMA = cv.Schema( ).extend(cv.COMPONENT_SCHEMA) -async def to_code(config): +async def to_code(config: ConfigType) -> None: paren = await cg.get_variable(config[CONF_WEB_SERVER_BASE_ID]) cg.add_define("USE_PROMETHEUS") diff --git a/esphome/components/psram/__init__.py b/esphome/components/psram/__init__.py index 84683e9a25..65c55efea5 100644 --- a/esphome/components/psram/__init__.py +++ b/esphome/components/psram/__init__.py @@ -129,7 +129,7 @@ def validate_task_stack_in_psram(value: Any) -> bool: return value -def validate_psram_mode(config): +def validate_psram_mode(config: ConfigType) -> ConfigType: esp32_config = fv.full_config.get()[PLATFORM_ESP32] if config[CONF_SPEED] == "120MHZ": if esp32_config[CONF_CPU_FREQUENCY] != "240MHZ": @@ -203,7 +203,7 @@ CONFIG_SCHEMA = cv.All( ) -def _store_psram_guaranteed(config): +def _store_psram_guaranteed(config: ConfigType) -> ConfigType: """Store PSRAM guaranteed status in CORE.data for other components. PSRAM is "guaranteed" when it will fail if not found, ensuring safe use @@ -220,7 +220,7 @@ def _store_psram_guaranteed(config): FINAL_VALIDATE_SCHEMA = cv.All(validate_psram_mode, _store_psram_guaranteed) -async def to_code(config): +async def to_code(config: ConfigType) -> None: if config[CONF_DISABLED]: return if CORE.using_arduino: diff --git a/esphome/components/pulse_width/sensor.py b/esphome/components/pulse_width/sensor.py index 120dc33b7b..dd7554c4eb 100644 --- a/esphome/components/pulse_width/sensor.py +++ b/esphome/components/pulse_width/sensor.py @@ -3,6 +3,7 @@ import esphome.codegen as cg from esphome.components import sensor import esphome.config_validation as cv from esphome.const import CONF_PIN, ICON_TIMER, STATE_CLASS_MEASUREMENT, UNIT_SECOND +from esphome.types import ConfigType pulse_width_ns = cg.esphome_ns.namespace("pulse_width") @@ -27,7 +28,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await sensor.new_sensor(config) await cg.register_component(var, config) diff --git a/esphome/components/pvvx_mithermometer/display/__init__.py b/esphome/components/pvvx_mithermometer/display/__init__.py index 0cf27b9f1c..436f83630c 100644 --- a/esphome/components/pvvx_mithermometer/display/__init__.py +++ b/esphome/components/pvvx_mithermometer/display/__init__.py @@ -9,6 +9,7 @@ from esphome.const import ( CONF_TIME_ID, CONF_VALIDITY_PERIOD, ) +from esphome.types import ConfigType DEPENDENCIES = ["ble_client"] @@ -36,7 +37,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await display.register_display(var, config) await ble_client.register_ble_node(var, config) diff --git a/esphome/components/pvvx_mithermometer/sensor.py b/esphome/components/pvvx_mithermometer/sensor.py index ee5b19ea77..ad13bdcca7 100644 --- a/esphome/components/pvvx_mithermometer/sensor.py +++ b/esphome/components/pvvx_mithermometer/sensor.py @@ -21,6 +21,7 @@ from esphome.const import ( UNIT_PERCENT, UNIT_VOLT, ) +from esphome.types import ConfigType CODEOWNERS = ["@pasiz"] @@ -77,7 +78,7 @@ CONFIG_SCHEMA = cv.All( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await ble_device_base.register_ble_device(var, config) diff --git a/esphome/components/pzem004t/sensor.py b/esphome/components/pzem004t/sensor.py index 7e55fd9e7e..bf5e31b48a 100644 --- a/esphome/components/pzem004t/sensor.py +++ b/esphome/components/pzem004t/sensor.py @@ -18,6 +18,7 @@ from esphome.const import ( UNIT_WATT, UNIT_WATT_HOURS, ) +from esphome.types import ConfigType DEPENDENCIES = ["uart"] @@ -63,7 +64,7 @@ FINAL_VALIDATE_SCHEMA = uart.final_validate_device_schema( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await uart.register_uart_device(var, config) diff --git a/esphome/components/qmi8658/motion.py b/esphome/components/qmi8658/motion.py index 26169189c2..2fd12dc921 100644 --- a/esphome/components/qmi8658/motion.py +++ b/esphome/components/qmi8658/motion.py @@ -8,6 +8,7 @@ from esphome.components.const import ( ) from esphome.components.motion import motion_schema, new_motion_component import esphome.config_validation as cv +from esphome.types import ConfigType from . import QMI8658Component, qmi8658_ns @@ -82,7 +83,7 @@ CONFIG_SCHEMA = ( # Code generation -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await new_motion_component(config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/qmi8658/sensor.py b/esphome/components/qmi8658/sensor.py index 80b0512361..96f97805c7 100644 --- a/esphome/components/qmi8658/sensor.py +++ b/esphome/components/qmi8658/sensor.py @@ -11,6 +11,7 @@ from esphome.const import ( UNIT_CELSIUS, ) from esphome.cpp_generator import MockObj +from esphome.types import ConfigType from . import CONF_QMI8658_ID, QMI8658Component @@ -28,7 +29,7 @@ CONFIG_SCHEMA = sensor.sensor_schema( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await sensor.new_sensor(config) parent = await cg.get_variable(config[CONF_QMI8658_ID]) data = MockObj("data") diff --git a/esphome/components/qmp6988/sensor.py b/esphome/components/qmp6988/sensor.py index 05eb7efa27..abc39176c1 100644 --- a/esphome/components/qmp6988/sensor.py +++ b/esphome/components/qmp6988/sensor.py @@ -13,6 +13,7 @@ from esphome.const import ( UNIT_CELSIUS, UNIT_HECTOPASCAL, ) +from esphome.types import ConfigType DEPENDENCIES = ["i2c"] @@ -81,7 +82,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/qr_code/__init__.py b/esphome/components/qr_code/__init__.py index 6ff92b8a7f..8b773dcdf5 100644 --- a/esphome/components/qr_code/__init__.py +++ b/esphome/components/qr_code/__init__.py @@ -1,6 +1,7 @@ import esphome.codegen as cg import esphome.config_validation as cv from esphome.const import CONF_ID, CONF_VALUE +from esphome.types import ConfigType CONF_SCALE = "scale" CONF_ECC = "ecc" @@ -32,7 +33,7 @@ CONFIG_SCHEMA = cv.ensure_list( ) -async def to_code(config): +async def to_code(config: list[ConfigType]) -> None: cg.add_library("wjtje/qr-code-generator-library", "^1.7.0") for entry in config: diff --git a/esphome/components/qwiic_pir/binary_sensor.py b/esphome/components/qwiic_pir/binary_sensor.py index cd3eda5ac8..71aabda349 100644 --- a/esphome/components/qwiic_pir/binary_sensor.py +++ b/esphome/components/qwiic_pir/binary_sensor.py @@ -3,6 +3,7 @@ import esphome.codegen as cg from esphome.components import binary_sensor, i2c import esphome.config_validation as cv from esphome.const import CONF_DEBOUNCE, DEVICE_CLASS_MOTION +from esphome.types import ConfigType DEPENDENCIES = ["i2c"] CODEOWNERS = ["@kahrendt"] @@ -23,7 +24,7 @@ QwiicPIRComponent = qwiic_pir_ns.class_( ) -def validate_no_debounce_unless_native(config): +def validate_no_debounce_unless_native(config: ConfigType) -> ConfigType: if CONF_DEBOUNCE in config and config[CONF_DEBOUNCE_MODE] != "NATIVE": raise cv.Invalid("debounce can only be set if debounce_mode is NATIVE") return config @@ -51,7 +52,7 @@ CONFIG_SCHEMA = cv.All( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await binary_sensor.new_binary_sensor(config) await cg.register_component(var, config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/radio_frequency/__init__.py b/esphome/components/radio_frequency/__init__.py index 9fdafe428a..f303a14297 100644 --- a/esphome/components/radio_frequency/__init__.py +++ b/esphome/components/radio_frequency/__init__.py @@ -15,7 +15,7 @@ from esphome.const import CONF_ID, CONF_ON_CONTROL from esphome.core import CORE, coroutine_with_priority from esphome.core.entity_helpers import queue_entity_register, setup_entity from esphome.coroutine import CoroPriority -from esphome.types import ConfigType +from esphome.types import ConfigType, SafeExpType CODEOWNERS = ["@kbx81"] AUTO_LOAD = ["remote_base"] @@ -49,11 +49,11 @@ def radio_frequency_schema(class_: type[cg.MockObjClass]) -> cv.Schema: @setup_entity("radio_frequency") -async def setup_radio_frequency_core_(var: cg.Pvariable, config: ConfigType) -> None: +async def setup_radio_frequency_core_(var: cg.MockObj, config: ConfigType) -> None: """Set up core radio frequency configuration.""" -async def register_radio_frequency(var: cg.Pvariable, config: ConfigType) -> None: +async def register_radio_frequency(var: cg.MockObj, config: ConfigType) -> None: """Register a radio frequency device with the core.""" cg.add_define("USE_RADIO_FREQUENCY") await cg.register_component(var, config) @@ -67,7 +67,7 @@ async def register_radio_frequency(var: cg.Pvariable, config: ConfigType) -> Non ) -async def new_radio_frequency(config: ConfigType, *args) -> cg.Pvariable: +async def new_radio_frequency(config: ConfigType, *args: SafeExpType) -> cg.MockObj: """Create a new RadioFrequency instance. :param config: Configuration dictionary. diff --git a/esphome/components/radon_eye_ble/__init__.py b/esphome/components/radon_eye_ble/__init__.py index 2ba9d59d4c..0ca9f64326 100644 --- a/esphome/components/radon_eye_ble/__init__.py +++ b/esphome/components/radon_eye_ble/__init__.py @@ -2,6 +2,7 @@ import esphome.codegen as cg from esphome.components import ble_device_base import esphome.config_validation as cv from esphome.const import CONF_ID +from esphome.types import ConfigType AUTO_LOAD = ["ble_device_base"] CODEOWNERS = ["@jeffeb3"] @@ -21,6 +22,6 @@ CONFIG_SCHEMA = cv.All( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await ble_device_base.register_ble_device(var, config) diff --git a/esphome/components/radon_eye_rd200/sensor.py b/esphome/components/radon_eye_rd200/sensor.py index da04328218..f38a035226 100644 --- a/esphome/components/radon_eye_rd200/sensor.py +++ b/esphome/components/radon_eye_rd200/sensor.py @@ -9,6 +9,7 @@ from esphome.const import ( STATE_CLASS_MEASUREMENT, UNIT_BECQUEREL_PER_CUBIC_METER, ) +from esphome.types import ConfigType DEPENDENCIES = ["ble_client"] @@ -40,7 +41,7 @@ CONFIG_SCHEMA = cv.All( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) diff --git a/esphome/components/rc522_i2c/__init__.py b/esphome/components/rc522_i2c/__init__.py index c67615e2d8..c3fd368bbd 100644 --- a/esphome/components/rc522_i2c/__init__.py +++ b/esphome/components/rc522_i2c/__init__.py @@ -2,6 +2,7 @@ import esphome.codegen as cg from esphome.components import i2c, rc522 import esphome.config_validation as cv from esphome.const import CONF_ID +from esphome.types import ConfigType CODEOWNERS = ["@glmnet"] DEPENDENCIES = ["i2c"] @@ -20,7 +21,7 @@ CONFIG_SCHEMA = cv.All( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await rc522.setup_rc522(var, config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/rc522_spi/__init__.py b/esphome/components/rc522_spi/__init__.py index 9ce94d7f31..f2820bbaee 100644 --- a/esphome/components/rc522_spi/__init__.py +++ b/esphome/components/rc522_spi/__init__.py @@ -2,6 +2,7 @@ import esphome.codegen as cg from esphome.components import rc522, spi import esphome.config_validation as cv from esphome.const import CONF_ID +from esphome.types import ConfigType CODEOWNERS = ["@glmnet"] DEPENDENCIES = ["spi"] @@ -24,7 +25,7 @@ FINAL_VALIDATE_SCHEMA = spi.final_validate_device_schema( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await rc522.setup_rc522(var, config) await spi.register_spi_device(var, config) diff --git a/esphome/components/rc522_spi/binary_sensor.py b/esphome/components/rc522_spi/binary_sensor.py index 8139f6d2ac..6245d5a487 100644 --- a/esphome/components/rc522_spi/binary_sensor.py +++ b/esphome/components/rc522_spi/binary_sensor.py @@ -1,9 +1,10 @@ import esphome.components.rc522.binary_sensor as rc522_binary_sensor +from esphome.types import ConfigType DEPENDENCIES = ["rc522"] CONFIG_SCHEMA = rc522_binary_sensor.CONFIG_SCHEMA -async def to_code(config): +async def to_code(config: ConfigType) -> None: await rc522_binary_sensor.to_code(config) diff --git a/esphome/components/rdm6300/__init__.py b/esphome/components/rdm6300/__init__.py index a65213d576..d3803bd3f7 100644 --- a/esphome/components/rdm6300/__init__.py +++ b/esphome/components/rdm6300/__init__.py @@ -3,6 +3,7 @@ import esphome.codegen as cg from esphome.components import uart import esphome.config_validation as cv from esphome.const import CONF_ID, CONF_ON_TAG, CONF_TRIGGER_ID +from esphome.types import ConfigType DEPENDENCIES = ["uart"] AUTO_LOAD = ["binary_sensor"] @@ -34,7 +35,7 @@ FINAL_VALIDATE_SCHEMA = uart.final_validate_device_schema( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await uart.register_uart_device(var, config) diff --git a/esphome/components/rdm6300/binary_sensor.py b/esphome/components/rdm6300/binary_sensor.py index 7eb20b1302..e62b1a3623 100644 --- a/esphome/components/rdm6300/binary_sensor.py +++ b/esphome/components/rdm6300/binary_sensor.py @@ -2,6 +2,7 @@ import esphome.codegen as cg from esphome.components import binary_sensor, rdm6300 import esphome.config_validation as cv from esphome.const import CONF_UID +from esphome.types import ConfigType from . import rdm6300_ns @@ -20,7 +21,7 @@ CONFIG_SCHEMA = binary_sensor.binary_sensor_schema(RDM6300BinarySensor).extend( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await binary_sensor.new_binary_sensor(config) hub = await cg.get_variable(config[CONF_RDM6300_ID]) diff --git a/esphome/components/resistance/sensor.py b/esphome/components/resistance/sensor.py index 1cb3c6020c..1333375717 100644 --- a/esphome/components/resistance/sensor.py +++ b/esphome/components/resistance/sensor.py @@ -8,6 +8,7 @@ from esphome.const import ( STATE_CLASS_MEASUREMENT, UNIT_OHM, ) +from esphome.types import ConfigType resistance_ns = cg.esphome_ns.namespace("resistance") ResistanceSensor = resistance_ns.class_("ResistanceSensor", cg.Component, sensor.Sensor) @@ -41,7 +42,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await sensor.new_sensor(config) await cg.register_component(var, config) diff --git a/esphome/components/restart/button/__init__.py b/esphome/components/restart/button/__init__.py index 76757f7504..2648d1e85d 100644 --- a/esphome/components/restart/button/__init__.py +++ b/esphome/components/restart/button/__init__.py @@ -7,6 +7,7 @@ from esphome.const import ( ENTITY_CATEGORY_CONFIG, ICON_RESTART, ) +from esphome.types import ConfigType restart_ns = cg.esphome_ns.namespace("restart") RestartButton = restart_ns.class_("RestartButton", button.Button, cg.Component) @@ -19,7 +20,7 @@ CONFIG_SCHEMA = button.button_schema( ).extend(cv.COMPONENT_SCHEMA) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await button.register_button(var, config) diff --git a/esphome/components/restart/switch/__init__.py b/esphome/components/restart/switch/__init__.py index e9283c9e41..9332716a9a 100644 --- a/esphome/components/restart/switch/__init__.py +++ b/esphome/components/restart/switch/__init__.py @@ -2,6 +2,7 @@ import esphome.codegen as cg from esphome.components import switch import esphome.config_validation as cv from esphome.const import ENTITY_CATEGORY_CONFIG, ICON_RESTART +from esphome.types import ConfigType restart_ns = cg.esphome_ns.namespace("restart") RestartSwitch = restart_ns.class_("RestartSwitch", switch.Switch, cg.Component) @@ -14,6 +15,6 @@ CONFIG_SCHEMA = switch.switch_schema( ).extend(cv.COMPONENT_SCHEMA) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await switch.new_switch(config) await cg.register_component(var, config) diff --git a/esphome/components/rgb/light.py b/esphome/components/rgb/light.py index b6daaaaa3c..cd55329256 100644 --- a/esphome/components/rgb/light.py +++ b/esphome/components/rgb/light.py @@ -2,6 +2,7 @@ import esphome.codegen as cg from esphome.components import light, output import esphome.config_validation as cv from esphome.const import CONF_BLUE, CONF_GREEN, CONF_OUTPUT_ID, CONF_RED +from esphome.types import ConfigType rgb_ns = cg.esphome_ns.namespace("rgb") RGBLightOutput = rgb_ns.class_("RGBLightOutput", light.LightOutput) @@ -16,7 +17,7 @@ CONFIG_SCHEMA = light.RGB_LIGHT_SCHEMA.extend( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_OUTPUT_ID]) await light.register_light(var, config) diff --git a/esphome/components/rgbct/light.py b/esphome/components/rgbct/light.py index dcd14310e3..00626ec6ba 100644 --- a/esphome/components/rgbct/light.py +++ b/esphome/components/rgbct/light.py @@ -11,6 +11,7 @@ from esphome.const import ( CONF_RED, CONF_WARM_WHITE_COLOR_TEMPERATURE, ) +from esphome.types import ConfigType CODEOWNERS = ["@jesserockz"] @@ -37,7 +38,7 @@ CONFIG_SCHEMA = cv.All( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_OUTPUT_ID]) await light.register_light(var, config) diff --git a/esphome/components/rgbw/light.py b/esphome/components/rgbw/light.py index 84425c23c2..7aedf4affc 100644 --- a/esphome/components/rgbw/light.py +++ b/esphome/components/rgbw/light.py @@ -9,6 +9,7 @@ from esphome.const import ( CONF_RED, CONF_WHITE, ) +from esphome.types import ConfigType rgbw_ns = cg.esphome_ns.namespace("rgbw") RGBWLightOutput = rgbw_ns.class_("RGBWLightOutput", light.LightOutput) @@ -25,7 +26,7 @@ CONFIG_SCHEMA = light.RGB_LIGHT_SCHEMA.extend( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_OUTPUT_ID]) await light.register_light(var, config) diff --git a/esphome/components/rgbww/light.py b/esphome/components/rgbww/light.py index 882ab0cdbc..3626a57b8c 100644 --- a/esphome/components/rgbww/light.py +++ b/esphome/components/rgbww/light.py @@ -13,6 +13,7 @@ from esphome.const import ( CONF_WARM_WHITE, CONF_WARM_WHITE_COLOR_TEMPERATURE, ) +from esphome.types import ConfigType rgbww_ns = cg.esphome_ns.namespace("rgbww") RGBWWLightOutput = rgbww_ns.class_("RGBWWLightOutput", light.LightOutput) @@ -40,7 +41,7 @@ CONFIG_SCHEMA = cv.All( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_OUTPUT_ID]) await light.register_light(var, config) diff --git a/esphome/components/rp2_pio/__init__.py b/esphome/components/rp2_pio/__init__.py index 9046d2ae6b..915ab73b87 100644 --- a/esphome/components/rp2_pio/__init__.py +++ b/esphome/components/rp2_pio/__init__.py @@ -2,6 +2,7 @@ import platform import esphome.codegen as cg import esphome.config_validation as cv +from esphome.types import ConfigType DEPENDENCIES = ["rp2"] @@ -25,7 +26,7 @@ PIOASM_DOWNLOADS = { } -async def to_code(config): +async def to_code(config: ConfigType) -> None: # cg.add_platformio_option( # "platform_packages", # [ diff --git a/esphome/components/rtl87xx/__init__.py b/esphome/components/rtl87xx/__init__.py index a8eabae9a0..88928b2bce 100644 --- a/esphome/components/rtl87xx/__init__.py +++ b/esphome/components/rtl87xx/__init__.py @@ -28,6 +28,8 @@ from esphome.components.libretiny.const import ( LibreTinyComponent, ) from esphome.core import CORE +from esphome.cpp_generator import MockObj +from esphome.types import ConfigType from .boards import RTL87XX_BOARD_PINS, RTL87XX_BOARDS @@ -45,7 +47,7 @@ COMPONENT_DATA = LibreTinyComponent( ) -def _set_core_data(config): +def _set_core_data(config: ConfigType) -> ConfigType: CORE.data[KEY_LIBRETINY] = {} CORE.data[KEY_LIBRETINY][KEY_COMPONENT_DATA] = COMPONENT_DATA return config @@ -62,12 +64,12 @@ PIN_SCHEMA = libretiny.gpio.BASE_PIN_SCHEMA CONFIG_SCHEMA.prepend_extra(_set_core_data) -async def to_code(config): +async def to_code(config: ConfigType) -> MockObj: return await libretiny.component_to_code(config) @pins.PIN_SCHEMA_REGISTRY.register("rtl87xx", PIN_SCHEMA) -async def pin_to_code(config): +async def pin_to_code(config: ConfigType) -> MockObj: return await libretiny.gpio.component_pin_to_code(config) diff --git a/esphome/components/runtime_image/__init__.py b/esphome/components/runtime_image/__init__.py index 0d4345db5b..9277c214ff 100644 --- a/esphome/components/runtime_image/__init__.py +++ b/esphome/components/runtime_image/__init__.py @@ -61,7 +61,7 @@ class Format: class AUTOFormat(Format): """AUTO format - detect from MIME type.""" - def __init__(self): + def __init__(self) -> None: super().__init__("AUTO", None) def actions(self) -> None: @@ -73,7 +73,7 @@ class AUTOFormat(Format): class BMPFormat(Format): """BMP format decoder configuration.""" - def __init__(self): + def __init__(self) -> None: super().__init__("BMP", BmpDecoder) def actions(self) -> None: @@ -83,7 +83,7 @@ class BMPFormat(Format): class JPEGFormat(Format): """JPEG format decoder configuration.""" - def __init__(self): + def __init__(self) -> None: super().__init__("JPEG", JpegDecoder) def actions(self) -> None: @@ -106,7 +106,7 @@ class JPEGFormat(Format): class PNGFormat(Format): """PNG format decoder configuration.""" - def __init__(self): + def __init__(self) -> None: super().__init__("PNG", PngDecoder) def actions(self) -> None: diff --git a/esphome/components/runtime_stats/__init__.py b/esphome/components/runtime_stats/__init__.py index a36e8bfd28..62f5f46cb4 100644 --- a/esphome/components/runtime_stats/__init__.py +++ b/esphome/components/runtime_stats/__init__.py @@ -5,6 +5,7 @@ Runtime statistics component for ESPHome. import esphome.codegen as cg import esphome.config_validation as cv from esphome.const import CONF_ID +from esphome.types import ConfigType CODEOWNERS = ["@bdraco"] @@ -23,7 +24,7 @@ CONFIG_SCHEMA = cv.Schema( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: """Generate code for the runtime statistics component.""" # Define USE_RUNTIME_STATS when this component is used cg.add_define("USE_RUNTIME_STATS") diff --git a/esphome/components/ruuvi_ble/__init__.py b/esphome/components/ruuvi_ble/__init__.py index 8ab95dcb72..ac4bafbb1a 100644 --- a/esphome/components/ruuvi_ble/__init__.py +++ b/esphome/components/ruuvi_ble/__init__.py @@ -2,6 +2,7 @@ import esphome.codegen as cg from esphome.components import ble_device_base import esphome.config_validation as cv from esphome.const import CONF_ID +from esphome.types import ConfigType AUTO_LOAD = ["ble_device_base"] @@ -20,6 +21,6 @@ CONFIG_SCHEMA = cv.All( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await ble_device_base.register_ble_device(var, config) diff --git a/esphome/components/ruuvitag/sensor.py b/esphome/components/ruuvitag/sensor.py index e58d38ca84..1ea9c457f3 100644 --- a/esphome/components/ruuvitag/sensor.py +++ b/esphome/components/ruuvitag/sensor.py @@ -34,6 +34,7 @@ from esphome.const import ( UNIT_PERCENT, UNIT_VOLT, ) +from esphome.types import ConfigType AUTO_LOAD = ["ble_device_base", "ruuvi_ble"] @@ -121,7 +122,7 @@ CONFIG_SCHEMA = cv.All( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await ble_device_base.register_ble_device(var, config) diff --git a/esphome/components/sdm_meter/sensor.py b/esphome/components/sdm_meter/sensor.py index 125240e891..8d7e981d93 100644 --- a/esphome/components/sdm_meter/sensor.py +++ b/esphome/components/sdm_meter/sensor.py @@ -155,7 +155,7 @@ def _final_validate(config: ConfigType) -> None: FINAL_VALIDATE_SCHEMA = _final_validate -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await modbus.register_modbus_client_device(var, config) diff --git a/esphome/components/sdp3x/sensor.py b/esphome/components/sdp3x/sensor.py index be2eec7baf..8a76ba4b13 100644 --- a/esphome/components/sdp3x/sensor.py +++ b/esphome/components/sdp3x/sensor.py @@ -7,6 +7,7 @@ from esphome.const import ( STATE_CLASS_MEASUREMENT, UNIT_HECTOPASCAL, ) +from esphome.types import ConfigType DEPENDENCIES = ["i2c"] AUTO_LOAD = ["sensirion_common"] @@ -48,7 +49,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await sensor.new_sensor(config) await cg.register_component(var, config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/sds011/sensor.py b/esphome/components/sds011/sensor.py index 59ee6667a1..e05d3b02e6 100644 --- a/esphome/components/sds011/sensor.py +++ b/esphome/components/sds011/sensor.py @@ -13,6 +13,7 @@ from esphome.const import ( STATE_CLASS_MEASUREMENT, UNIT_MICROGRAMS_PER_CUBIC_METER, ) +from esphome.types import ConfigType DEPENDENCIES = ["uart"] @@ -20,7 +21,7 @@ sds011_ns = cg.esphome_ns.namespace("sds011") SDS011Component = sds011_ns.class_("SDS011Component", uart.UARTDevice, cg.Component) -def validate_sds011_rx_mode(value): +def validate_sds011_rx_mode(value: ConfigType) -> ConfigType: if CONF_UPDATE_INTERVAL in value and not value.get(CONF_RX_ONLY): update_interval = value[CONF_UPDATE_INTERVAL] if update_interval.total_minutes > 30: @@ -63,7 +64,7 @@ CONFIG_SCHEMA = cv.All( ) -def _final_validate(config) -> None: +def _final_validate(config: ConfigType) -> None: # In the default mode setup() writes config commands, so tx is required; # rx_only mode never writes, so tx is optional. uart.final_validate_device_schema( @@ -80,7 +81,7 @@ def _final_validate(config) -> None: FINAL_VALIDATE_SCHEMA = _final_validate -async def to_code(config): +async def to_code(config: ConfigType) -> None: # Pop update_interval before register_component so it doesn't generate # a set_update_interval call — sds011 handles this via set_update_interval_min update_interval = config.pop(CONF_UPDATE_INTERVAL, None) diff --git a/esphome/components/selec_meter/sensor.py b/esphome/components/selec_meter/sensor.py index 120b997605..0d4e0fafc5 100644 --- a/esphome/components/selec_meter/sensor.py +++ b/esphome/components/selec_meter/sensor.py @@ -171,7 +171,7 @@ def _final_validate(config: ConfigType) -> None: FINAL_VALIDATE_SCHEMA = _final_validate -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await modbus.register_modbus_client_device(var, config) diff --git a/esphome/components/sen0321/sensor.py b/esphome/components/sen0321/sensor.py index 3910e6e4c9..58c09883b0 100644 --- a/esphome/components/sen0321/sensor.py +++ b/esphome/components/sen0321/sensor.py @@ -6,6 +6,7 @@ from esphome.const import ( STATE_CLASS_MEASUREMENT, UNIT_PARTS_PER_BILLION, ) +from esphome.types import ConfigType CODEOWNERS = ["@notjj"] DEPENDENCIES = ["i2c"] @@ -28,7 +29,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await sensor.new_sensor(config) await cg.register_component(var, config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/sen21231/sensor.py b/esphome/components/sen21231/sensor.py index 781a1213ac..fb695b14dc 100644 --- a/esphome/components/sen21231/sensor.py +++ b/esphome/components/sen21231/sensor.py @@ -2,6 +2,7 @@ import esphome.codegen as cg from esphome.components import i2c, sensor import esphome.config_validation as cv from esphome.const import ICON_MOTION_SENSOR +from esphome.types import ConfigType CODEOWNERS = ["@shreyaskarnik"] DEPENDENCIES = ["i2c"] @@ -18,7 +19,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await sensor.new_sensor(config) await cg.register_component(var, config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/sen6x/sensor.py b/esphome/components/sen6x/sensor.py index 832a2188ee..b0ffdc53a4 100644 --- a/esphome/components/sen6x/sensor.py +++ b/esphome/components/sen6x/sensor.py @@ -32,6 +32,7 @@ from esphome.const import ( UNIT_PARTS_PER_MILLION, UNIT_PERCENT, ) +from esphome.types import ConfigType CODEOWNERS = ["@martgras", "@mebner86", "@tuct"] DEPENDENCIES = ["i2c"] @@ -136,7 +137,7 @@ SENSOR_MAP = { } -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/serial_proxy/__init__.py b/esphome/components/serial_proxy/__init__.py index f9b8c375d2..4186fcf8b1 100644 --- a/esphome/components/serial_proxy/__init__.py +++ b/esphome/components/serial_proxy/__init__.py @@ -21,6 +21,7 @@ import esphome.config_validation as cv from esphome.const import CONF_ID, CONF_NAME from esphome.core import CORE, coroutine_with_priority from esphome.coroutine import CoroPriority +from esphome.types import ConfigType CODEOWNERS = ["@kbx81"] DEPENDENCIES = ["api", "uart"] @@ -72,14 +73,14 @@ CONFIG_SCHEMA = ( @coroutine_with_priority(CoroPriority.FINAL) -async def _add_serial_proxy_count_define(): +async def _add_serial_proxy_count_define() -> None: """Emit the SERIAL_PROXY_COUNT define once with the final instance count.""" count = _get_data().count if count > 0: cg.add_define("SERIAL_PROXY_COUNT", count) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await uart.register_uart_device(var, config) diff --git a/esphome/components/sfa30/sensor.py b/esphome/components/sfa30/sensor.py index 8e8a57e341..b8039af9e3 100644 --- a/esphome/components/sfa30/sensor.py +++ b/esphome/components/sfa30/sensor.py @@ -17,6 +17,7 @@ from esphome.const import ( UNIT_PARTS_PER_BILLION, UNIT_PERCENT, ) +from esphome.types import ConfigType CODEOWNERS = ["@ghsensdev"] DEPENDENCIES = ["i2c"] @@ -66,7 +67,7 @@ SENSOR_MAP = { } -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/sgp30/sensor.py b/esphome/components/sgp30/sensor.py index 848e4e9f9f..beb549ce70 100644 --- a/esphome/components/sgp30/sensor.py +++ b/esphome/components/sgp30/sensor.py @@ -18,6 +18,7 @@ from esphome.const import ( UNIT_PARTS_PER_BILLION, UNIT_PARTS_PER_MILLION, ) +from esphome.types import ConfigType DEPENDENCIES = ["i2c"] AUTO_LOAD = ["sensirion_common"] @@ -81,7 +82,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/sgp4x/sensor.py b/esphome/components/sgp4x/sensor.py index 87ef050bc1..1a88d190e4 100644 --- a/esphome/components/sgp4x/sensor.py +++ b/esphome/components/sgp4x/sensor.py @@ -19,6 +19,7 @@ from esphome.const import ( ICON_RADIATOR, STATE_CLASS_MEASUREMENT, ) +from esphome.types import ConfigType DEPENDENCIES = ["i2c"] AUTO_LOAD = ["sensirion_common"] @@ -35,7 +36,7 @@ SGP4xComponent = sgp4x_ns.class_( CONF_HUMIDITY_SOURCE = "humidity_source" -def validate_sensors(config): +def validate_sensors(config: ConfigType) -> ConfigType: if CONF_VOC_INDEX not in config and CONF_NOX_INDEX not in config: raise cv.Invalid( f"At least one sensor is required. Define {CONF_VOC_INDEX} and/or {CONF_NOX_INDEX}" @@ -43,7 +44,7 @@ def validate_sensors(config): return config -def _gas_sensor_schema(index_offset_default: int): +def _gas_sensor_schema(index_offset_default: int) -> cv.Schema: return cv.Schema( { cv.Optional(CONF_ALGORITHM_TUNING): cv.Schema( @@ -96,7 +97,7 @@ CONFIG_SCHEMA = cv.All( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/sht3xd/sensor.py b/esphome/components/sht3xd/sensor.py index 7ad34972d4..eadca15050 100644 --- a/esphome/components/sht3xd/sensor.py +++ b/esphome/components/sht3xd/sensor.py @@ -11,6 +11,7 @@ from esphome.const import ( UNIT_CELSIUS, UNIT_PERCENT, ) +from esphome.types import ConfigType CONF_HEATER_ENABLED = "heater_enabled" @@ -48,7 +49,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/sht4x/sensor.py b/esphome/components/sht4x/sensor.py index 871956f783..7fb52e37d4 100644 --- a/esphome/components/sht4x/sensor.py +++ b/esphome/components/sht4x/sensor.py @@ -13,6 +13,7 @@ from esphome.const import ( UNIT_CELSIUS, UNIT_PERCENT, ) +from esphome.types import ConfigType CODEOWNERS = ["@sjtrny"] DEPENDENCIES = ["i2c"] @@ -87,7 +88,7 @@ TYPES = { } -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/shtcx/sensor.py b/esphome/components/shtcx/sensor.py index fdb1344fb7..bda48c07ce 100644 --- a/esphome/components/shtcx/sensor.py +++ b/esphome/components/shtcx/sensor.py @@ -11,6 +11,7 @@ from esphome.const import ( UNIT_CELSIUS, UNIT_PERCENT, ) +from esphome.types import ConfigType DEPENDENCIES = ["i2c"] AUTO_LOAD = ["sensirion_common"] @@ -45,7 +46,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/shutdown/button/__init__.py b/esphome/components/shutdown/button/__init__.py index 3423b40089..44fd819d25 100644 --- a/esphome/components/shutdown/button/__init__.py +++ b/esphome/components/shutdown/button/__init__.py @@ -2,6 +2,7 @@ import esphome.codegen as cg from esphome.components import button import esphome.config_validation as cv from esphome.const import CONF_ID, ENTITY_CATEGORY_CONFIG, ICON_POWER +from esphome.types import ConfigType shutdown_ns = cg.esphome_ns.namespace("shutdown") ShutdownButton = shutdown_ns.class_("ShutdownButton", button.Button, cg.Component) @@ -11,7 +12,7 @@ CONFIG_SCHEMA = button.button_schema( ).extend(cv.COMPONENT_SCHEMA) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await button.register_button(var, config) diff --git a/esphome/components/shutdown/switch/__init__.py b/esphome/components/shutdown/switch/__init__.py index 12cc477647..78026140cb 100644 --- a/esphome/components/shutdown/switch/__init__.py +++ b/esphome/components/shutdown/switch/__init__.py @@ -2,6 +2,7 @@ import esphome.codegen as cg from esphome.components import switch import esphome.config_validation as cv from esphome.const import ENTITY_CATEGORY_CONFIG, ICON_POWER +from esphome.types import ConfigType shutdown_ns = cg.esphome_ns.namespace("shutdown") ShutdownSwitch = shutdown_ns.class_("ShutdownSwitch", switch.Switch, cg.Component) @@ -14,6 +15,6 @@ CONFIG_SCHEMA = switch.switch_schema( ).extend(cv.COMPONENT_SCHEMA) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await switch.new_switch(config) await cg.register_component(var, config) diff --git a/esphome/components/sigma_delta_output/output.py b/esphome/components/sigma_delta_output/output.py index ca5b7a53e0..aca5f26457 100644 --- a/esphome/components/sigma_delta_output/output.py +++ b/esphome/components/sigma_delta_output/output.py @@ -3,6 +3,7 @@ import esphome.codegen as cg from esphome.components import output import esphome.config_validation as cv from esphome.const import CONF_ID, CONF_PIN, CONF_TURN_OFF_ACTION, CONF_TURN_ON_ACTION +from esphome.types import ConfigType DEPENDENCIES = [] @@ -37,7 +38,7 @@ CONFIG_SCHEMA = cv.All( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await output.register_output(var, config) diff --git a/esphome/components/slow_pwm/output.py b/esphome/components/slow_pwm/output.py index 73807ba377..f3f82d7ce5 100644 --- a/esphome/components/slow_pwm/output.py +++ b/esphome/components/slow_pwm/output.py @@ -9,6 +9,7 @@ from esphome.const import ( CONF_TURN_OFF_ACTION, CONF_TURN_ON_ACTION, ) +from esphome.types import ConfigType slow_pwm_ns = cg.esphome_ns.namespace("slow_pwm") SlowPWMOutput = slow_pwm_ns.class_("SlowPWMOutput", output.FloatOutput, cg.Component) @@ -42,7 +43,7 @@ CONFIG_SCHEMA = output.FLOAT_OUTPUT_SCHEMA.extend( ).extend(cv.COMPONENT_SCHEMA) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await output.register_output(var, config) diff --git a/esphome/components/sm10bit_base/__init__.py b/esphome/components/sm10bit_base/__init__.py index 81e7c04c0e..2b555a59df 100644 --- a/esphome/components/sm10bit_base/__init__.py +++ b/esphome/components/sm10bit_base/__init__.py @@ -2,6 +2,8 @@ from esphome import pins import esphome.codegen as cg import esphome.config_validation as cv from esphome.const import CONF_CLOCK_PIN, CONF_DATA_PIN, CONF_ID +from esphome.cpp_generator import MockObj +from esphome.types import ConfigType CODEOWNERS = ["@Cossid"] MULTI_CONF = True @@ -26,7 +28,7 @@ SM10BIT_BASE_CONFIG_SCHEMA = cv.Schema( ).extend(cv.COMPONENT_SCHEMA) -async def register_sm10bit_base(config): +async def register_sm10bit_base(config: ConfigType) -> MockObj: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) diff --git a/esphome/components/sm16716/__init__.py b/esphome/components/sm16716/__init__.py index e97bc440f4..3fb9ac3f06 100644 --- a/esphome/components/sm16716/__init__.py +++ b/esphome/components/sm16716/__init__.py @@ -8,6 +8,7 @@ from esphome.const import ( CONF_NUM_CHANNELS, CONF_NUM_CHIPS, ) +from esphome.types import ConfigType AUTO_LOAD = ["output"] sm16716_ns = cg.esphome_ns.namespace("sm16716") @@ -25,7 +26,7 @@ CONFIG_SCHEMA = cv.Schema( ).extend(cv.COMPONENT_SCHEMA) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) diff --git a/esphome/components/sm16716/output.py b/esphome/components/sm16716/output.py index 2cfc38f5cc..08cec24fd6 100644 --- a/esphome/components/sm16716/output.py +++ b/esphome/components/sm16716/output.py @@ -2,6 +2,7 @@ import esphome.codegen as cg from esphome.components import output import esphome.config_validation as cv from esphome.const import CONF_CHANNEL, CONF_ID +from esphome.types import ConfigType from . import SM16716 @@ -19,7 +20,7 @@ CONFIG_SCHEMA = output.FLOAT_OUTPUT_SCHEMA.extend( ).extend(cv.COMPONENT_SCHEMA) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await output.register_output(var, config) diff --git a/esphome/components/sm2135/__init__.py b/esphome/components/sm2135/__init__.py index 28c92a42a7..537db5bbe4 100644 --- a/esphome/components/sm2135/__init__.py +++ b/esphome/components/sm2135/__init__.py @@ -2,6 +2,7 @@ from esphome import pins import esphome.codegen as cg import esphome.config_validation as cv from esphome.const import CONF_CLOCK_PIN, CONF_DATA_PIN, CONF_ID +from esphome.types import ConfigType AUTO_LOAD = ["output"] CODEOWNERS = ["@BoukeHaarsma23", "@matika77", "@dd32"] @@ -53,7 +54,7 @@ CONFIG_SCHEMA = cv.Schema( ).extend(cv.COMPONENT_SCHEMA) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) diff --git a/esphome/components/sm2135/output.py b/esphome/components/sm2135/output.py index a4ac7fc7da..80b4cb1a4f 100644 --- a/esphome/components/sm2135/output.py +++ b/esphome/components/sm2135/output.py @@ -2,6 +2,7 @@ import esphome.codegen as cg from esphome.components import output import esphome.config_validation as cv from esphome.const import CONF_CHANNEL, CONF_ID +from esphome.types import ConfigType from . import SM2135 @@ -20,7 +21,7 @@ CONFIG_SCHEMA = output.FLOAT_OUTPUT_SCHEMA.extend( ).extend(cv.COMPONENT_SCHEMA) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await output.register_output(var, config) diff --git a/esphome/components/sm2235/__init__.py b/esphome/components/sm2235/__init__.py index 1b18a1d342..95037fd275 100644 --- a/esphome/components/sm2235/__init__.py +++ b/esphome/components/sm2235/__init__.py @@ -1,6 +1,7 @@ import esphome.codegen as cg from esphome.components import sm10bit_base import esphome.config_validation as cv +from esphome.types import ConfigType AUTO_LOAD = ["sm10bit_base", "output"] CODEOWNERS = ["@Cossid"] @@ -17,6 +18,6 @@ CONFIG_SCHEMA = cv.Schema( ).extend(sm10bit_base.SM10BIT_BASE_CONFIG_SCHEMA) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await sm10bit_base.register_sm10bit_base(config) cg.add(var.set_model(0xC0)) diff --git a/esphome/components/sm2235/output.py b/esphome/components/sm2235/output.py index b17af2b1e0..29940a651e 100644 --- a/esphome/components/sm2235/output.py +++ b/esphome/components/sm2235/output.py @@ -2,6 +2,7 @@ import esphome.codegen as cg from esphome.components import output import esphome.config_validation as cv from esphome.const import CONF_CHANNEL, CONF_ID +from esphome.types import ConfigType from . import SM2235 @@ -20,7 +21,7 @@ CONFIG_SCHEMA = output.FLOAT_OUTPUT_SCHEMA.extend( ).extend(cv.COMPONENT_SCHEMA) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await output.register_output(var, config) diff --git a/esphome/components/sm2335/__init__.py b/esphome/components/sm2335/__init__.py index 02a6d1f697..145c5a0117 100644 --- a/esphome/components/sm2335/__init__.py +++ b/esphome/components/sm2335/__init__.py @@ -1,6 +1,7 @@ import esphome.codegen as cg from esphome.components import sm10bit_base import esphome.config_validation as cv +from esphome.types import ConfigType AUTO_LOAD = ["sm10bit_base", "output"] CODEOWNERS = ["@Cossid"] @@ -17,6 +18,6 @@ CONFIG_SCHEMA = cv.Schema( ).extend(sm10bit_base.SM10BIT_BASE_CONFIG_SCHEMA) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await sm10bit_base.register_sm10bit_base(config) cg.add(var.set_model(0xC0)) diff --git a/esphome/components/sm2335/output.py b/esphome/components/sm2335/output.py index 7fd00917bd..30f653b087 100644 --- a/esphome/components/sm2335/output.py +++ b/esphome/components/sm2335/output.py @@ -2,6 +2,7 @@ import esphome.codegen as cg from esphome.components import output import esphome.config_validation as cv from esphome.const import CONF_CHANNEL, CONF_ID +from esphome.types import ConfigType from . import SM2335 @@ -20,7 +21,7 @@ CONFIG_SCHEMA = output.FLOAT_OUTPUT_SCHEMA.extend( ).extend(cv.COMPONENT_SCHEMA) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await output.register_output(var, config) diff --git a/esphome/components/sm300d2/sensor.py b/esphome/components/sm300d2/sensor.py index 29e0cfe9b1..e0f2b7b280 100644 --- a/esphome/components/sm300d2/sensor.py +++ b/esphome/components/sm300d2/sensor.py @@ -26,6 +26,7 @@ from esphome.const import ( UNIT_PARTS_PER_MILLION, UNIT_PERCENT, ) +from esphome.types import ConfigType DEPENDENCIES = ["uart"] @@ -93,7 +94,7 @@ FINAL_VALIDATE_SCHEMA = uart.final_validate_device_schema( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await uart.register_uart_device(var, config) diff --git a/esphome/components/smt100/sensor.py b/esphome/components/smt100/sensor.py index f877ce2af0..632a1e7547 100644 --- a/esphome/components/smt100/sensor.py +++ b/esphome/components/smt100/sensor.py @@ -18,6 +18,7 @@ from esphome.const import ( UNIT_PERCENT, UNIT_VOLT, ) +from esphome.types import ConfigType DEPENDENCIES = ["uart"] @@ -71,7 +72,7 @@ FINAL_VALIDATE_SCHEMA = uart.final_validate_device_schema( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await uart.register_uart_device(var, config) diff --git a/esphome/components/sntp/time.py b/esphome/components/sntp/time.py index 7d592f8ef8..9d849f9fe9 100644 --- a/esphome/components/sntp/time.py +++ b/esphome/components/sntp/time.py @@ -109,7 +109,7 @@ CONFIG_SCHEMA = cv.All( FINAL_VALIDATE_SCHEMA = _sntp_final_validate -async def to_code(config): +async def to_code(config: ConfigType) -> None: servers = config[CONF_SERVERS] # Define server count at compile time diff --git a/esphome/components/socket/__init__.py b/esphome/components/socket/__init__.py index 895fc8d03a..edebed5d40 100644 --- a/esphome/components/socket/__init__.py +++ b/esphome/components/socket/__init__.py @@ -7,6 +7,7 @@ import esphome.codegen as cg from esphome.config_helpers import filter_source_files_from_defines import esphome.config_validation as cv from esphome.core import CORE +from esphome.types import ConfigType _LOGGER = logging.getLogger(__name__) @@ -162,7 +163,7 @@ CONFIG_SCHEMA = cv.Schema( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: impl = config[CONF_IMPLEMENTATION] if impl == IMPLEMENTATION_LWIP_TCP: cg.add_define("USE_SOCKET_IMPL_LWIP_TCP") diff --git a/esphome/components/sonoff_d1/light.py b/esphome/components/sonoff_d1/light.py index 06cde45cd6..ae2c65595a 100644 --- a/esphome/components/sonoff_d1/light.py +++ b/esphome/components/sonoff_d1/light.py @@ -2,6 +2,7 @@ import esphome.codegen as cg from esphome.components import light, uart import esphome.config_validation as cv from esphome.const import CONF_MAX_VALUE, CONF_MIN_VALUE, CONF_OUTPUT_ID +from esphome.types import ConfigType CONF_USE_RM433_REMOTE = "use_rm433_remote" @@ -29,7 +30,7 @@ FINAL_VALIDATE_SCHEMA = uart.final_validate_device_schema( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_OUTPUT_ID]) await cg.register_component(var, config) await uart.register_uart_device(var, config) diff --git a/esphome/components/spa06_i2c/sensor.py b/esphome/components/spa06_i2c/sensor.py index b48a5bca50..bffb4a4b4f 100644 --- a/esphome/components/spa06_i2c/sensor.py +++ b/esphome/components/spa06_i2c/sensor.py @@ -1,6 +1,7 @@ import esphome.codegen as cg from esphome.components import i2c import esphome.config_validation as cv +from esphome.types import ConfigType from ..spa06_base import CONFIG_SCHEMA_BASE, to_code_base @@ -18,6 +19,6 @@ CONFIG_SCHEMA = CONFIG_SCHEMA_BASE.extend( ).extend({cv.GenerateID(): cv.declare_id(SPA06I2CComponent)}) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await to_code_base(config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/spa06_spi/sensor.py b/esphome/components/spa06_spi/sensor.py index b82186ec21..19cb99a831 100644 --- a/esphome/components/spa06_spi/sensor.py +++ b/esphome/components/spa06_spi/sensor.py @@ -4,6 +4,7 @@ import esphome.codegen as cg from esphome.components import spi from esphome.components.spi import CONF_SPI_MODE import esphome.config_validation as cv +from esphome.types import ConfigType from ..spa06_base import CONFIG_SCHEMA_BASE, to_code_base @@ -21,7 +22,7 @@ _LOGGER = logging.getLogger(__name__) VALID_SPI_MODES = {3: "MODE3", "3": "MODE3", "MODE3": "MODE3"} -def check_spi_mode(config): +def check_spi_mode(config: ConfigType) -> ConfigType: spi_mode = config.get(CONF_SPI_MODE) if spi_mode not in VALID_SPI_MODES: raise cv.Invalid("SPA06 only supports SPI mode 3") @@ -36,6 +37,6 @@ CONFIG_SCHEMA = cv.All( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await to_code_base(config) await spi.register_spi_device(var, config) diff --git a/esphome/components/speed/fan/__init__.py b/esphome/components/speed/fan/__init__.py index 3c495f3160..9a9290e78e 100644 --- a/esphome/components/speed/fan/__init__.py +++ b/esphome/components/speed/fan/__init__.py @@ -10,6 +10,7 @@ from esphome.const import ( CONF_SPEED, CONF_SPEED_COUNT, ) +from esphome.types import ConfigType from .. import speed_ns @@ -33,7 +34,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await fan.new_fan(config, config[CONF_SPEED_COUNT]) await cg.register_component(var, config) diff --git a/esphome/components/spi_device/__init__.py b/esphome/components/spi_device/__init__.py index 2f23d8a011..bd2bfe6452 100644 --- a/esphome/components/spi_device/__init__.py +++ b/esphome/components/spi_device/__init__.py @@ -2,6 +2,7 @@ import esphome.codegen as cg from esphome.components import spi import esphome.config_validation as cv from esphome.const import CONF_ID, CONF_MODE +from esphome.types import ConfigType DEPENDENCIES = ["spi"] CODEOWNERS = ["@clydebarrow"] @@ -29,7 +30,7 @@ CONFIG_SCHEMA = cv.Schema( ).extend(spi.spi_device_schema(False, "1MHz")) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) cg.add(var.set_bit_order(config[CONF_BIT_ORDER])) diff --git a/esphome/components/spi_led_strip/light.py b/esphome/components/spi_led_strip/light.py index ca320265a9..9139cc1ae3 100644 --- a/esphome/components/spi_led_strip/light.py +++ b/esphome/components/spi_led_strip/light.py @@ -2,6 +2,7 @@ import esphome.codegen as cg from esphome.components import light, spi import esphome.config_validation as cv from esphome.const import CONF_NUM_LEDS, CONF_OUTPUT_ID +from esphome.types import ConfigType spi_led_strip_ns = cg.esphome_ns.namespace("spi_led_strip") SpiLedStrip = spi_led_strip_ns.class_( @@ -16,7 +17,7 @@ CONFIG_SCHEMA = light.ADDRESSABLE_LIGHT_SCHEMA.extend( ).extend(spi.spi_device_schema(False, "1MHz")) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_OUTPUT_ID], config[CONF_NUM_LEDS]) await light.register_light(var, config) await spi.register_spi_device(var, config) diff --git a/esphome/components/ssd1306_base/__init__.py b/esphome/components/ssd1306_base/__init__.py index 9d397e396b..26eda3b4ea 100644 --- a/esphome/components/ssd1306_base/__init__.py +++ b/esphome/components/ssd1306_base/__init__.py @@ -15,6 +15,8 @@ from esphome.const import ( CONF_OFFSET_Y, CONF_RESET_PIN, ) +from esphome.cpp_generator import MockObj +from esphome.types import ConfigType ssd1306_base_ns = cg.esphome_ns.namespace("ssd1306_base") SSD1306 = ssd1306_base_ns.class_("SSD1306", cg.PollingComponent, display.DisplayBuffer) @@ -40,7 +42,7 @@ MODELS = { SSD1306_MODEL = cv.enum(MODELS, upper=True, space="_") -def _validate(value): +def _validate(value: ConfigType) -> ConfigType: model = value[CONF_MODEL] if ( model not in ("SSD1305_128X32", "SSD1305_128X64") @@ -73,7 +75,7 @@ SSD1306_SCHEMA = display.FULL_DISPLAY_SCHEMA.extend( ).extend(cv.polling_component_schema("1s")) -async def setup_ssd1306(var, config): +async def setup_ssd1306(var: MockObj, config: ConfigType) -> None: await display.register_display(var, config) cg.add(var.set_model(config[CONF_MODEL])) diff --git a/esphome/components/ssd1306_i2c/display.py b/esphome/components/ssd1306_i2c/display.py index 2ac0093ef1..ec271039ae 100644 --- a/esphome/components/ssd1306_i2c/display.py +++ b/esphome/components/ssd1306_i2c/display.py @@ -3,6 +3,7 @@ from esphome.components import i2c, ssd1306_base from esphome.components.ssd1306_base import _validate import esphome.config_validation as cv from esphome.const import CONF_ID, CONF_LAMBDA, CONF_PAGES +from esphome.types import ConfigType AUTO_LOAD = ["ssd1306_base"] DEPENDENCIES = ["i2c"] @@ -23,7 +24,7 @@ CONFIG_SCHEMA = cv.All( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await ssd1306_base.setup_ssd1306(var, config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/ssd1306_spi/display.py b/esphome/components/ssd1306_spi/display.py index 26953b4f39..9a415ccfdb 100644 --- a/esphome/components/ssd1306_spi/display.py +++ b/esphome/components/ssd1306_spi/display.py @@ -4,6 +4,7 @@ from esphome.components import spi, ssd1306_base from esphome.components.ssd1306_base import _validate import esphome.config_validation as cv from esphome.const import CONF_DC_PIN, CONF_ID, CONF_LAMBDA, CONF_PAGES +from esphome.types import ConfigType AUTO_LOAD = ["ssd1306_base"] DEPENDENCIES = ["spi"] @@ -29,7 +30,7 @@ FINAL_VALIDATE_SCHEMA = spi.final_validate_device_schema( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await ssd1306_base.setup_ssd1306(var, config) await spi.register_spi_device(var, config, write_only=True) diff --git a/esphome/components/ssd1322_base/__init__.py b/esphome/components/ssd1322_base/__init__.py index 3569bbe957..daa0345857 100644 --- a/esphome/components/ssd1322_base/__init__.py +++ b/esphome/components/ssd1322_base/__init__.py @@ -9,6 +9,8 @@ from esphome.const import ( CONF_MODEL, CONF_RESET_PIN, ) +from esphome.cpp_generator import MockObj +from esphome.types import ConfigType CODEOWNERS = ["@kbx81"] @@ -32,7 +34,7 @@ SSD1322_SCHEMA = display.FULL_DISPLAY_SCHEMA.extend( ).extend(cv.polling_component_schema("1s")) -async def setup_ssd1322(var, config): +async def setup_ssd1322(var: MockObj, config: ConfigType) -> None: await display.register_display(var, config) cg.add(var.set_model(config[CONF_MODEL])) diff --git a/esphome/components/ssd1322_spi/display.py b/esphome/components/ssd1322_spi/display.py index 3d01caf874..63e0816ae7 100644 --- a/esphome/components/ssd1322_spi/display.py +++ b/esphome/components/ssd1322_spi/display.py @@ -3,6 +3,7 @@ import esphome.codegen as cg from esphome.components import spi, ssd1322_base import esphome.config_validation as cv from esphome.const import CONF_DC_PIN, CONF_ID, CONF_LAMBDA, CONF_PAGES +from esphome.types import ConfigType CODEOWNERS = ["@kbx81"] @@ -29,7 +30,7 @@ FINAL_VALIDATE_SCHEMA = spi.final_validate_device_schema( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await ssd1322_base.setup_ssd1322(var, config) await spi.register_spi_device(var, config, write_only=True) diff --git a/esphome/components/ssd1325_base/__init__.py b/esphome/components/ssd1325_base/__init__.py index 12cbd883a0..e48a821825 100644 --- a/esphome/components/ssd1325_base/__init__.py +++ b/esphome/components/ssd1325_base/__init__.py @@ -9,6 +9,8 @@ from esphome.const import ( CONF_MODEL, CONF_RESET_PIN, ) +from esphome.cpp_generator import MockObj +from esphome.types import ConfigType CODEOWNERS = ["@kbx81"] @@ -36,7 +38,7 @@ SSD1325_SCHEMA = display.FULL_DISPLAY_SCHEMA.extend( ).extend(cv.polling_component_schema("1s")) -async def setup_ssd1325(var, config): +async def setup_ssd1325(var: MockObj, config: ConfigType) -> None: await display.register_display(var, config) cg.add(var.set_model(config[CONF_MODEL])) diff --git a/esphome/components/ssd1325_spi/display.py b/esphome/components/ssd1325_spi/display.py index dbb9a14ac2..cca9a3cf8e 100644 --- a/esphome/components/ssd1325_spi/display.py +++ b/esphome/components/ssd1325_spi/display.py @@ -3,6 +3,7 @@ import esphome.codegen as cg from esphome.components import spi, ssd1325_base import esphome.config_validation as cv from esphome.const import CONF_DC_PIN, CONF_ID, CONF_LAMBDA, CONF_PAGES +from esphome.types import ConfigType CODEOWNERS = ["@kbx81"] @@ -29,7 +30,7 @@ FINAL_VALIDATE_SCHEMA = spi.final_validate_device_schema( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await ssd1325_base.setup_ssd1325(var, config) await spi.register_spi_device(var, config, write_only=True) diff --git a/esphome/components/ssd1327_base/__init__.py b/esphome/components/ssd1327_base/__init__.py index d0ec2410e6..462f197696 100644 --- a/esphome/components/ssd1327_base/__init__.py +++ b/esphome/components/ssd1327_base/__init__.py @@ -3,6 +3,8 @@ import esphome.codegen as cg from esphome.components import display import esphome.config_validation as cv from esphome.const import CONF_BRIGHTNESS, CONF_LAMBDA, CONF_MODEL, CONF_RESET_PIN +from esphome.cpp_generator import MockObj +from esphome.types import ConfigType CODEOWNERS = ["@kbx81"] @@ -25,7 +27,7 @@ SSD1327_SCHEMA = display.FULL_DISPLAY_SCHEMA.extend( ).extend(cv.polling_component_schema("1s")) -async def setup_ssd1327(var, config): +async def setup_ssd1327(var: MockObj, config: ConfigType) -> None: await display.register_display(var, config) cg.add(var.set_model(config[CONF_MODEL])) diff --git a/esphome/components/ssd1327_i2c/display.py b/esphome/components/ssd1327_i2c/display.py index 95de1c2979..e079a8698f 100644 --- a/esphome/components/ssd1327_i2c/display.py +++ b/esphome/components/ssd1327_i2c/display.py @@ -2,6 +2,7 @@ import esphome.codegen as cg from esphome.components import i2c, ssd1327_base import esphome.config_validation as cv from esphome.const import CONF_ID, CONF_LAMBDA, CONF_PAGES +from esphome.types import ConfigType CODEOWNERS = ["@kbx81"] @@ -23,7 +24,7 @@ CONFIG_SCHEMA = cv.All( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await ssd1327_base.setup_ssd1327(var, config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/ssd1327_spi/display.py b/esphome/components/ssd1327_spi/display.py index f052764a91..8a5ea40efa 100644 --- a/esphome/components/ssd1327_spi/display.py +++ b/esphome/components/ssd1327_spi/display.py @@ -3,6 +3,7 @@ import esphome.codegen as cg from esphome.components import spi, ssd1327_base import esphome.config_validation as cv from esphome.const import CONF_DC_PIN, CONF_ID, CONF_LAMBDA, CONF_PAGES +from esphome.types import ConfigType CODEOWNERS = ["@kbx81"] @@ -29,7 +30,7 @@ FINAL_VALIDATE_SCHEMA = spi.final_validate_device_schema( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await ssd1327_base.setup_ssd1327(var, config) await spi.register_spi_device(var, config, write_only=True) diff --git a/esphome/components/ssd1331_base/__init__.py b/esphome/components/ssd1331_base/__init__.py index 144a95a29f..d1c0b585f8 100644 --- a/esphome/components/ssd1331_base/__init__.py +++ b/esphome/components/ssd1331_base/__init__.py @@ -3,6 +3,8 @@ import esphome.codegen as cg from esphome.components import display import esphome.config_validation as cv from esphome.const import CONF_BRIGHTNESS, CONF_LAMBDA, CONF_RESET_PIN +from esphome.cpp_generator import MockObj +from esphome.types import ConfigType CODEOWNERS = ["@kbx81"] @@ -17,7 +19,7 @@ SSD1331_SCHEMA = display.FULL_DISPLAY_SCHEMA.extend( ).extend(cv.polling_component_schema("1s")) -async def setup_ssd1331(var, config): +async def setup_ssd1331(var: MockObj, config: ConfigType) -> None: await display.register_display(var, config) if CONF_RESET_PIN in config: diff --git a/esphome/components/ssd1331_spi/display.py b/esphome/components/ssd1331_spi/display.py index c16780302f..eeebb48ac6 100644 --- a/esphome/components/ssd1331_spi/display.py +++ b/esphome/components/ssd1331_spi/display.py @@ -3,6 +3,7 @@ import esphome.codegen as cg from esphome.components import spi, ssd1331_base import esphome.config_validation as cv from esphome.const import CONF_DC_PIN, CONF_ID, CONF_LAMBDA, CONF_PAGES +from esphome.types import ConfigType CODEOWNERS = ["@kbx81"] @@ -29,7 +30,7 @@ FINAL_VALIDATE_SCHEMA = spi.final_validate_device_schema( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await ssd1331_base.setup_ssd1331(var, config) await spi.register_spi_device(var, config, write_only=True) diff --git a/esphome/components/ssd1351_base/__init__.py b/esphome/components/ssd1351_base/__init__.py index fc03083ad0..a516b4d951 100644 --- a/esphome/components/ssd1351_base/__init__.py +++ b/esphome/components/ssd1351_base/__init__.py @@ -3,6 +3,8 @@ import esphome.codegen as cg from esphome.components import display import esphome.config_validation as cv from esphome.const import CONF_BRIGHTNESS, CONF_LAMBDA, CONF_MODEL, CONF_RESET_PIN +from esphome.cpp_generator import MockObj +from esphome.types import ConfigType CODEOWNERS = ["@kbx81"] @@ -26,7 +28,7 @@ SSD1351_SCHEMA = display.FULL_DISPLAY_SCHEMA.extend( ).extend(cv.polling_component_schema("1s")) -async def setup_ssd1351(var, config): +async def setup_ssd1351(var: MockObj, config: ConfigType) -> None: await display.register_display(var, config) cg.add(var.set_model(config[CONF_MODEL])) diff --git a/esphome/components/ssd1351_spi/display.py b/esphome/components/ssd1351_spi/display.py index 2a6e984029..10991b8338 100644 --- a/esphome/components/ssd1351_spi/display.py +++ b/esphome/components/ssd1351_spi/display.py @@ -3,6 +3,7 @@ import esphome.codegen as cg from esphome.components import spi, ssd1351_base import esphome.config_validation as cv from esphome.const import CONF_DC_PIN, CONF_ID, CONF_LAMBDA, CONF_PAGES +from esphome.types import ConfigType CODEOWNERS = ["@kbx81"] @@ -29,7 +30,7 @@ FINAL_VALIDATE_SCHEMA = spi.final_validate_device_schema( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await ssd1351_base.setup_ssd1351(var, config) await spi.register_spi_device(var, config, write_only=True) diff --git a/esphome/components/st7123/touchscreen/__init__.py b/esphome/components/st7123/touchscreen/__init__.py index 5ebd08066f..55ea43ca6a 100644 --- a/esphome/components/st7123/touchscreen/__init__.py +++ b/esphome/components/st7123/touchscreen/__init__.py @@ -3,6 +3,7 @@ import esphome.codegen as cg from esphome.components import i2c, touchscreen import esphome.config_validation as cv from esphome.const import CONF_ID, CONF_INTERRUPT_PIN, CONF_RESET_PIN +from esphome.types import ConfigType from .. import st7123_ns @@ -21,7 +22,7 @@ CONFIG_SCHEMA = touchscreen.TOUCHSCREEN_SCHEMA.extend( ).extend(i2c.i2c_device_schema(0x55)) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await touchscreen.register_touchscreen(var, config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/st7567_base/__init__.py b/esphome/components/st7567_base/__init__.py index 6f93172a1a..51225c5023 100644 --- a/esphome/components/st7567_base/__init__.py +++ b/esphome/components/st7567_base/__init__.py @@ -10,6 +10,8 @@ from esphome.const import ( CONF_RESET_PIN, CONF_TRANSFORM, ) +from esphome.cpp_generator import MockObj +from esphome.types import ConfigType CODEOWNERS = ["@latonita"] @@ -34,7 +36,7 @@ ST7567_SCHEMA = display.FULL_DISPLAY_SCHEMA.extend( ).extend(cv.polling_component_schema("1s")) -async def setup_st7567(var, config): +async def setup_st7567(var: MockObj, config: ConfigType) -> None: await display.register_display(var, config) if CONF_RESET_PIN in config: diff --git a/esphome/components/st7567_i2c/display.py b/esphome/components/st7567_i2c/display.py index bd62b3b382..1a7da33a8e 100644 --- a/esphome/components/st7567_i2c/display.py +++ b/esphome/components/st7567_i2c/display.py @@ -2,6 +2,7 @@ import esphome.codegen as cg from esphome.components import i2c, st7567_base import esphome.config_validation as cv from esphome.const import CONF_ID, CONF_LAMBDA, CONF_PAGES +from esphome.types import ConfigType CODEOWNERS = ["@latonita"] @@ -23,7 +24,7 @@ CONFIG_SCHEMA = cv.All( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await st7567_base.setup_st7567(var, config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/st7567_spi/display.py b/esphome/components/st7567_spi/display.py index 02cd2c105c..ad04b9f212 100644 --- a/esphome/components/st7567_spi/display.py +++ b/esphome/components/st7567_spi/display.py @@ -3,6 +3,7 @@ import esphome.codegen as cg from esphome.components import spi, st7567_base import esphome.config_validation as cv from esphome.const import CONF_DC_PIN, CONF_ID, CONF_LAMBDA, CONF_PAGES +from esphome.types import ConfigType CODEOWNERS = ["@latonita"] @@ -29,7 +30,7 @@ FINAL_VALIDATE_SCHEMA = spi.final_validate_device_schema( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await st7567_base.setup_st7567(var, config) await spi.register_spi_device(var, config, write_only=True) diff --git a/esphome/components/st7735/display.py b/esphome/components/st7735/display.py index 766370c21f..5cbcee12ab 100644 --- a/esphome/components/st7735/display.py +++ b/esphome/components/st7735/display.py @@ -13,6 +13,8 @@ from esphome.const import ( CONF_PAGES, CONF_RESET_PIN, ) +from esphome.cpp_generator import MockObj +from esphome.types import ConfigType from . import st7735_ns @@ -76,7 +78,7 @@ FINAL_VALIDATE_SCHEMA = spi.final_validate_device_schema( ) -async def setup_st7735(var, config): +async def setup_st7735(var: MockObj, config: ConfigType) -> None: await display.register_display(var, config) if CONF_RESET_PIN in config: @@ -89,7 +91,7 @@ async def setup_st7735(var, config): cg.add(var.set_writer(lambda_)) -async def to_code(config): +async def to_code(config: ConfigType) -> None: LOGGER.warning( "The 'st7735' component is deprecated, it is recommended to use 'mipi_spi' instead." ) diff --git a/esphome/components/st7920/display.py b/esphome/components/st7920/display.py index ef33fac6c6..853e38a279 100644 --- a/esphome/components/st7920/display.py +++ b/esphome/components/st7920/display.py @@ -2,6 +2,7 @@ import esphome.codegen as cg from esphome.components import display, spi import esphome.config_validation as cv from esphome.const import CONF_HEIGHT, CONF_ID, CONF_LAMBDA, CONF_WIDTH +from esphome.types import ConfigType AUTO_LOAD = ["display"] CODEOWNERS = ["@marsjan155"] @@ -26,7 +27,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await spi.register_spi_device(var, config, write_only=True) diff --git a/esphome/components/statsd/__init__.py b/esphome/components/statsd/__init__.py index 39188c6b81..b5a0586e31 100644 --- a/esphome/components/statsd/__init__.py +++ b/esphome/components/statsd/__init__.py @@ -8,6 +8,7 @@ from esphome.const import ( CONF_PORT, CONF_SENSORS, ) +from esphome.types import ConfigType AUTO_LOAD = ["socket"] CODEOWNERS = ["@Links2004"] @@ -45,7 +46,7 @@ CONFIG_SCHEMA = cv.Schema( ).extend(cv.polling_component_schema("10s")) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) cg.add( diff --git a/esphome/components/status/binary_sensor.py b/esphome/components/status/binary_sensor.py index f0c7c87e17..452ae9398f 100644 --- a/esphome/components/status/binary_sensor.py +++ b/esphome/components/status/binary_sensor.py @@ -2,6 +2,7 @@ import esphome.codegen as cg from esphome.components import binary_sensor import esphome.config_validation as cv from esphome.const import DEVICE_CLASS_CONNECTIVITY, ENTITY_CATEGORY_DIAGNOSTIC +from esphome.types import ConfigType DEPENDENCIES = ["network"] @@ -17,6 +18,6 @@ CONFIG_SCHEMA = binary_sensor.binary_sensor_schema( ).extend(cv.polling_component_schema("1s")) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await binary_sensor.new_binary_sensor(config) await cg.register_component(var, config) diff --git a/esphome/components/status_led/__init__.py b/esphome/components/status_led/__init__.py index b0fce37126..700296c0df 100644 --- a/esphome/components/status_led/__init__.py +++ b/esphome/components/status_led/__init__.py @@ -3,6 +3,7 @@ import esphome.codegen as cg import esphome.config_validation as cv from esphome.const import CONF_ID, CONF_PIN from esphome.core import CoroPriority, coroutine_with_priority +from esphome.types import ConfigType status_led_ns = cg.esphome_ns.namespace("status_led") StatusLED = status_led_ns.class_("StatusLED", cg.Component) @@ -16,7 +17,7 @@ CONFIG_SCHEMA = cv.Schema( @coroutine_with_priority(CoroPriority.STATUS) -async def to_code(config): +async def to_code(config: ConfigType) -> None: pin = await cg.gpio_pin_expression(config[CONF_PIN]) rhs = StatusLED.new(pin) var = cg.Pvariable(config[CONF_ID], rhs) diff --git a/esphome/components/status_led/light/__init__.py b/esphome/components/status_led/light/__init__.py index f8d03a3b4f..f63cf14178 100644 --- a/esphome/components/status_led/light/__init__.py +++ b/esphome/components/status_led/light/__init__.py @@ -3,6 +3,7 @@ import esphome.codegen as cg from esphome.components import light, output import esphome.config_validation as cv from esphome.const import CONF_OUTPUT, CONF_OUTPUT_ID, CONF_PIN +from esphome.types import ConfigType from .. import status_led_ns @@ -24,7 +25,7 @@ CONFIG_SCHEMA = cv.All( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_OUTPUT_ID]) if CONF_PIN in config: pin = await cg.gpio_pin_expression(config[CONF_PIN]) diff --git a/esphome/components/sts3x/sensor.py b/esphome/components/sts3x/sensor.py index 7b04bd58bb..d4fd431d13 100644 --- a/esphome/components/sts3x/sensor.py +++ b/esphome/components/sts3x/sensor.py @@ -6,6 +6,7 @@ from esphome.const import ( STATE_CLASS_MEASUREMENT, UNIT_CELSIUS, ) +from esphome.types import ConfigType DEPENDENCIES = ["i2c"] AUTO_LOAD = ["sensirion_common"] @@ -29,7 +30,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await sensor.new_sensor(config) await cg.register_component(var, config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/stts22h/sensor.py b/esphome/components/stts22h/sensor.py index 094c233361..7b86f90860 100644 --- a/esphome/components/stts22h/sensor.py +++ b/esphome/components/stts22h/sensor.py @@ -6,6 +6,7 @@ from esphome.const import ( STATE_CLASS_MEASUREMENT, UNIT_CELSIUS, ) +from esphome.types import ConfigType DEPENDENCIES = ["i2c"] @@ -27,7 +28,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await sensor.new_sensor(config) await cg.register_component(var, config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/sx126x/packet_transport/__init__.py b/esphome/components/sx126x/packet_transport/__init__.py index 4d79b23ac1..fc3bbf6df2 100644 --- a/esphome/components/sx126x/packet_transport/__init__.py +++ b/esphome/components/sx126x/packet_transport/__init__.py @@ -6,6 +6,7 @@ from esphome.components.packet_transport import ( ) import esphome.config_validation as cv from esphome.cpp_types import PollingComponent +from esphome.types import ConfigType from .. import CONF_SX126X_ID, SX126x, SX126xListener, sx126x_ns @@ -20,7 +21,7 @@ CONFIG_SCHEMA = transport_schema(SX126xTransport).extend( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var, _ = await new_packet_transport(config) sx126x = await cg.get_variable(config[CONF_SX126X_ID]) cg.add(var.set_parent(sx126x)) diff --git a/esphome/components/syslog/__init__.py b/esphome/components/syslog/__init__.py index 08626404f7..bf7fe9a307 100644 --- a/esphome/components/syslog/__init__.py +++ b/esphome/components/syslog/__init__.py @@ -6,6 +6,7 @@ from esphome.components.udp import CONF_UDP_ID import esphome.config_validation as cv from esphome.const import CONF_ID, CONF_LEVEL, CONF_PORT, CONF_TIME_ID from esphome.cpp_types import Component, Parented +from esphome.types import ConfigType CODEOWNERS = ["@clydebarrow"] @@ -28,7 +29,7 @@ CONFIG_SCHEMA = udp.UDP_SCHEMA.extend( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: parent = await cg.get_variable(config[CONF_UDP_ID]) time = await cg.get_variable(config[CONF_TIME_ID]) cg.add(parent.set_broadcast_port(config[CONF_PORT])) diff --git a/esphome/components/t6615/sensor.py b/esphome/components/t6615/sensor.py index 9315e4a669..6f3ef372bc 100644 --- a/esphome/components/t6615/sensor.py +++ b/esphome/components/t6615/sensor.py @@ -8,6 +8,7 @@ from esphome.const import ( STATE_CLASS_MEASUREMENT, UNIT_PARTS_PER_MILLION, ) +from esphome.types import ConfigType CODEOWNERS = ["@tylermenezes"] DEPENDENCIES = ["uart"] @@ -36,7 +37,7 @@ FINAL_VALIDATE_SCHEMA = uart.final_validate_device_schema( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await uart.register_uart_device(var, config) diff --git a/esphome/components/tc74/sensor.py b/esphome/components/tc74/sensor.py index 18a94016fb..3d26dc2377 100644 --- a/esphome/components/tc74/sensor.py +++ b/esphome/components/tc74/sensor.py @@ -6,6 +6,7 @@ from esphome.const import ( STATE_CLASS_MEASUREMENT, UNIT_CELSIUS, ) +from esphome.types import ConfigType CODEOWNERS = ["@sethgirvan"] DEPENDENCIES = ["i2c"] @@ -28,7 +29,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await sensor.new_sensor(config) await cg.register_component(var, config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/tca9548a/__init__.py b/esphome/components/tca9548a/__init__.py index 72973a54ad..381b84cad6 100644 --- a/esphome/components/tca9548a/__init__.py +++ b/esphome/components/tca9548a/__init__.py @@ -2,6 +2,7 @@ import esphome.codegen as cg from esphome.components import i2c import esphome.config_validation as cv from esphome.const import CONF_CHANNEL, CONF_CHANNELS, CONF_ID +from esphome.types import ConfigType CODEOWNERS = ["@andreashergert1984"] @@ -31,7 +32,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/tca9555/__init__.py b/esphome/components/tca9555/__init__.py index 1c643fe1c9..3033cc65e0 100644 --- a/esphome/components/tca9555/__init__.py +++ b/esphome/components/tca9555/__init__.py @@ -11,6 +11,8 @@ from esphome.const import ( CONF_NUMBER, CONF_OUTPUT, ) +from esphome.cpp_generator import MockObj +from esphome.types import ConfigType CODEOWNERS = ["@mobrembski"] @@ -36,7 +38,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await i2c.register_i2c_device(var, config) @@ -44,7 +46,7 @@ async def to_code(config): cg.add(var.set_interrupt_pin(await cg.gpio_pin_expression(interrupt_pin))) -def validate_mode(value): +def validate_mode(value: ConfigType) -> ConfigType: if not (value[CONF_INPUT] or value[CONF_OUTPUT]): raise cv.Invalid("Mode must be either input or output") if value[CONF_INPUT] and value[CONF_OUTPUT]: @@ -66,7 +68,7 @@ TCA9555_PIN_SCHEMA = pins.gpio_base_schema( @pins.PIN_SCHEMA_REGISTRY.register(CONF_TCA9555, TCA9555_PIN_SCHEMA) -async def tca9555_pin_to_code(config): +async def tca9555_pin_to_code(config: ConfigType) -> MockObj: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_parented(var, config[CONF_TCA9555]) diff --git a/esphome/components/tcl112/climate.py b/esphome/components/tcl112/climate.py index 58ed7ee529..c175b1ea80 100644 --- a/esphome/components/tcl112/climate.py +++ b/esphome/components/tcl112/climate.py @@ -1,5 +1,6 @@ import esphome.codegen as cg from esphome.components import climate_ir +from esphome.types import ConfigType AUTO_LOAD = ["climate_ir"] CODEOWNERS = ["@glmnet"] @@ -10,5 +11,5 @@ Tcl112Climate = tcl112_ns.class_("Tcl112Climate", climate_ir.ClimateIR) CONFIG_SCHEMA = climate_ir.climate_ir_with_receiver_schema(Tcl112Climate) -async def to_code(config): +async def to_code(config: ConfigType) -> None: await climate_ir.new_climate_ir(config) diff --git a/esphome/components/tcs34725/sensor.py b/esphome/components/tcs34725/sensor.py index 34b6c579b6..da6edfd62a 100644 --- a/esphome/components/tcs34725/sensor.py +++ b/esphome/components/tcs34725/sensor.py @@ -16,6 +16,7 @@ from esphome.const import ( UNIT_LUX, UNIT_PERCENT, ) +from esphome.types import ConfigType DEPENDENCIES = ["i2c"] @@ -103,7 +104,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/tee501/sensor.py b/esphome/components/tee501/sensor.py index db8e8d9268..2d8853394c 100644 --- a/esphome/components/tee501/sensor.py +++ b/esphome/components/tee501/sensor.py @@ -6,6 +6,7 @@ from esphome.const import ( STATE_CLASS_MEASUREMENT, UNIT_CELSIUS, ) +from esphome.types import ConfigType CODEOWNERS = ["@Stock-M"] @@ -30,7 +31,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await sensor.new_sensor(config) await cg.register_component(var, config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/tem3200/sensor.py b/esphome/components/tem3200/sensor.py index 508dc1bcd4..289641f951 100644 --- a/esphome/components/tem3200/sensor.py +++ b/esphome/components/tem3200/sensor.py @@ -8,6 +8,7 @@ from esphome.const import ( STATE_CLASS_MEASUREMENT, UNIT_CELSIUS, ) +from esphome.types import ConfigType CODEOWNERS = ["@bakerkj"] DEPENDENCIES = ["i2c"] @@ -40,7 +41,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/thermopro_ble/sensor.py b/esphome/components/thermopro_ble/sensor.py index d0d6cdacb7..c660e5fcef 100644 --- a/esphome/components/thermopro_ble/sensor.py +++ b/esphome/components/thermopro_ble/sensor.py @@ -19,6 +19,7 @@ from esphome.const import ( UNIT_DECIBEL_MILLIWATT, UNIT_PERCENT, ) +from esphome.types import ConfigType CODEOWNERS = ["@sittner"] @@ -74,7 +75,7 @@ CONFIG_SCHEMA = cv.All( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await ble_device_base.register_ble_device(var, config) diff --git a/esphome/components/time_based/cover/__init__.py b/esphome/components/time_based/cover/__init__.py index 022b48d249..895743f400 100644 --- a/esphome/components/time_based/cover/__init__.py +++ b/esphome/components/time_based/cover/__init__.py @@ -10,6 +10,7 @@ from esphome.const import ( CONF_OPEN_DURATION, CONF_STOP_ACTION, ) +from esphome.types import ConfigType from .. import time_based_ns @@ -36,7 +37,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await cover.new_cover(config) await cg.register_component(var, config) diff --git a/esphome/components/tinyusb/__init__.py b/esphome/components/tinyusb/__init__.py index 4c6f4db85b..53c4ab0073 100644 --- a/esphome/components/tinyusb/__init__.py +++ b/esphome/components/tinyusb/__init__.py @@ -12,6 +12,7 @@ from esphome.components.esp32 import ( ) import esphome.config_validation as cv from esphome.const import CONF_HARDWARE_UART, CONF_ID +from esphome.types import ConfigType CODEOWNERS = ["@kbx81"] CONFLICTS_WITH = ["usb_host"] @@ -57,7 +58,7 @@ CONFIG_SCHEMA = cv.All( ) -def _final_validate(config) -> None: +def _final_validate(config: ConfigType) -> None: full_config = fv.full_config.get() if not any(name in full_config for name in _USB_CLASS_COMPONENTS): raise cv.Invalid( @@ -80,7 +81,7 @@ def _final_validate(config) -> None: FINAL_VALIDATE_SCHEMA = _final_validate -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) diff --git a/esphome/components/tlc59208f/__init__.py b/esphome/components/tlc59208f/__init__.py index b685423787..1af9f66b95 100644 --- a/esphome/components/tlc59208f/__init__.py +++ b/esphome/components/tlc59208f/__init__.py @@ -2,6 +2,7 @@ import esphome.codegen as cg from esphome.components import i2c import esphome.config_validation as cv from esphome.const import CONF_ID +from esphome.types import ConfigType DEPENDENCIES = ["i2c"] MULTI_CONF = True @@ -20,7 +21,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/tlc59208f/output.py b/esphome/components/tlc59208f/output.py index a2f4f16554..81d864ccce 100644 --- a/esphome/components/tlc59208f/output.py +++ b/esphome/components/tlc59208f/output.py @@ -2,6 +2,7 @@ import esphome.codegen as cg from esphome.components import output import esphome.config_validation as cv from esphome.const import CONF_CHANNEL, CONF_ID +from esphome.types import ConfigType from . import TLC59208FOutput, tlc59208f_ns @@ -19,7 +20,7 @@ CONFIG_SCHEMA = output.FLOAT_OUTPUT_SCHEMA.extend( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: paren = await cg.get_variable(config[CONF_TLC59208F_ID]) var = cg.new_Pvariable(config[CONF_ID]) cg.add(var.set_channel(config[CONF_CHANNEL])) diff --git a/esphome/components/tlc5947/__init__.py b/esphome/components/tlc5947/__init__.py index 20e53893aa..05e2ef037d 100644 --- a/esphome/components/tlc5947/__init__.py +++ b/esphome/components/tlc5947/__init__.py @@ -11,6 +11,7 @@ from esphome.const import ( CONF_NUM_CHIPS, CONF_OE_PIN, ) +from esphome.types import ConfigType CONF_LAT_PIN = "lat_pin" @@ -32,7 +33,7 @@ CONFIG_SCHEMA = cv.Schema( ).extend(cv.COMPONENT_SCHEMA) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) diff --git a/esphome/components/tlc5947/output/__init__.py b/esphome/components/tlc5947/output/__init__.py index 6bea1546d3..cb285dc6ab 100644 --- a/esphome/components/tlc5947/output/__init__.py +++ b/esphome/components/tlc5947/output/__init__.py @@ -2,6 +2,7 @@ import esphome.codegen as cg from esphome.components import output import esphome.config_validation as cv from esphome.const import CONF_CHANNEL, CONF_ID +from esphome.types import ConfigType from .. import TLC5947, tlc5947_ns @@ -21,7 +22,7 @@ CONFIG_SCHEMA = output.FLOAT_OUTPUT_SCHEMA.extend( ).extend(cv.COMPONENT_SCHEMA) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await output.register_output(var, config) await cg.register_parented(var, config[CONF_TLC5947_ID]) diff --git a/esphome/components/tlc5971/__init__.py b/esphome/components/tlc5971/__init__.py index b09924c3d3..5b9027e61a 100644 --- a/esphome/components/tlc5971/__init__.py +++ b/esphome/components/tlc5971/__init__.py @@ -5,6 +5,7 @@ from esphome import pins import esphome.codegen as cg import esphome.config_validation as cv from esphome.const import CONF_CLOCK_PIN, CONF_DATA_PIN, CONF_ID, CONF_NUM_CHIPS +from esphome.types import ConfigType CODEOWNERS = ["@IJIJI"] @@ -22,7 +23,7 @@ CONFIG_SCHEMA = cv.Schema( ).extend(cv.COMPONENT_SCHEMA) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) diff --git a/esphome/components/tlc5971/output/__init__.py b/esphome/components/tlc5971/output/__init__.py index 854fbbd810..8fc19aad3b 100644 --- a/esphome/components/tlc5971/output/__init__.py +++ b/esphome/components/tlc5971/output/__init__.py @@ -2,6 +2,7 @@ import esphome.codegen as cg from esphome.components import output import esphome.config_validation as cv from esphome.const import CONF_CHANNEL, CONF_ID +from esphome.types import ConfigType from .. import TLC5971, tlc5971_ns @@ -21,7 +22,7 @@ CONFIG_SCHEMA = output.FLOAT_OUTPUT_SCHEMA.extend( ).extend(cv.COMPONENT_SCHEMA) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await output.register_output(var, config) await cg.register_parented(var, config[CONF_TLC5971_ID]) diff --git a/esphome/components/tm1621/display.py b/esphome/components/tm1621/display.py index f521af2842..e8a40507d8 100644 --- a/esphome/components/tm1621/display.py +++ b/esphome/components/tm1621/display.py @@ -10,6 +10,7 @@ from esphome.const import ( CONF_READ_PIN, CONF_WRITE_PIN, ) +from esphome.types import ConfigType tm1621_ns = cg.esphome_ns.namespace("tm1621") TM1621Display = tm1621_ns.class_("TM1621Display", cg.PollingComponent) @@ -26,7 +27,7 @@ CONFIG_SCHEMA = display.BASIC_DISPLAY_SCHEMA.extend( ).extend(cv.polling_component_schema("1s")) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await display.register_display(var, config) diff --git a/esphome/components/tm1637/binary_sensor.py b/esphome/components/tm1637/binary_sensor.py index 817231627a..3dff02bbe8 100644 --- a/esphome/components/tm1637/binary_sensor.py +++ b/esphome/components/tm1637/binary_sensor.py @@ -2,6 +2,7 @@ import esphome.codegen as cg from esphome.components import binary_sensor import esphome.config_validation as cv from esphome.const import CONF_ID, CONF_KEY +from esphome.types import ConfigType CONF_TM1637_ID = "tm1637_id" @@ -17,7 +18,7 @@ CONFIG_SCHEMA = binary_sensor.binary_sensor_schema(TM1637Key).extend( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await binary_sensor.register_binary_sensor(var, config) cg.add(var.set_keycode(config[CONF_KEY])) diff --git a/esphome/components/tm1637/display.py b/esphome/components/tm1637/display.py index 141ee5a39f..ec4d32561b 100644 --- a/esphome/components/tm1637/display.py +++ b/esphome/components/tm1637/display.py @@ -11,6 +11,7 @@ from esphome.const import ( CONF_LAMBDA, CONF_LENGTH, ) +from esphome.types import ConfigType CODEOWNERS = ["@glmnet"] @@ -32,7 +33,7 @@ CONFIG_SCHEMA = display.BASIC_DISPLAY_SCHEMA.extend( ).extend(cv.polling_component_schema("1s")) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await display.register_display(var, config) diff --git a/esphome/components/tmp102/sensor.py b/esphome/components/tmp102/sensor.py index 862d526ccf..eba0d3c026 100644 --- a/esphome/components/tmp102/sensor.py +++ b/esphome/components/tmp102/sensor.py @@ -16,6 +16,7 @@ from esphome.const import ( STATE_CLASS_MEASUREMENT, UNIT_CELSIUS, ) +from esphome.types import ConfigType CODEOWNERS = ["@timsavage"] DEPENDENCIES = ["i2c"] @@ -38,7 +39,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await sensor.new_sensor(config) await cg.register_component(var, config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/tmp1075/sensor.py b/esphome/components/tmp1075/sensor.py index bedeef8e3c..3cbda4a57a 100644 --- a/esphome/components/tmp1075/sensor.py +++ b/esphome/components/tmp1075/sensor.py @@ -7,6 +7,7 @@ from esphome.const import ( STATE_CLASS_MEASUREMENT, UNIT_CELSIUS, ) +from esphome.types import ConfigType DEPENDENCIES = ["i2c"] @@ -71,7 +72,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await sensor.new_sensor(config) await cg.register_component(var, config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/tmp117/sensor.py b/esphome/components/tmp117/sensor.py index e906fe0aee..8a3073bef6 100644 --- a/esphome/components/tmp117/sensor.py +++ b/esphome/components/tmp117/sensor.py @@ -7,6 +7,7 @@ from esphome.const import ( STATE_CLASS_MEASUREMENT, UNIT_CELSIUS, ) +from esphome.types import ConfigType DEPENDENCIES = ["i2c"] CODEOWNERS = ["@Azimath"] @@ -29,7 +30,7 @@ CONFIG_SCHEMA = cv.All( ) -def determine_config_register(polling_period): +def determine_config_register(polling_period: int) -> int: if polling_period >= 16000: # 64 averaged conversions, max conversion time # 0000 00 111 11 00000 @@ -71,7 +72,7 @@ def determine_config_register(polling_period): return 0x0000 -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await sensor.new_sensor(config) await cg.register_component(var, config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/tof10120/sensor.py b/esphome/components/tof10120/sensor.py index d3aeaa814f..2475cf6bd5 100644 --- a/esphome/components/tof10120/sensor.py +++ b/esphome/components/tof10120/sensor.py @@ -6,6 +6,7 @@ from esphome.const import ( STATE_CLASS_MEASUREMENT, UNIT_METER, ) +from esphome.types import ConfigType CODEOWNERS = ["@wstrzalka"] DEPENDENCIES = ["i2c"] @@ -28,7 +29,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await sensor.new_sensor(config) await cg.register_component(var, config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/tormatic/cover.py b/esphome/components/tormatic/cover.py index 447920326b..f4d4c2a6d4 100644 --- a/esphome/components/tormatic/cover.py +++ b/esphome/components/tormatic/cover.py @@ -2,6 +2,7 @@ import esphome.codegen as cg from esphome.components import cover, uart import esphome.config_validation as cv from esphome.const import CONF_CLOSE_DURATION, CONF_OPEN_DURATION +from esphome.types import ConfigType tormatic_ns = cg.esphome_ns.namespace("tormatic") Tormatic = tormatic_ns.class_("Tormatic", cover.Cover, cg.PollingComponent) @@ -33,7 +34,7 @@ FINAL_VALIDATE_SCHEMA = uart.final_validate_device_schema( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await cover.new_cover(config) await cg.register_component(var, config) await uart.register_uart_device(var, config) diff --git a/esphome/components/toshiba/climate.py b/esphome/components/toshiba/climate.py index bdb17923fa..3b1e7352f9 100644 --- a/esphome/components/toshiba/climate.py +++ b/esphome/components/toshiba/climate.py @@ -2,6 +2,7 @@ import esphome.codegen as cg from esphome.components import climate_ir import esphome.config_validation as cv from esphome.const import CONF_MODEL +from esphome.types import ConfigType AUTO_LOAD = ["climate_ir"] CODEOWNERS = ["@kbx81"] @@ -24,6 +25,6 @@ CONFIG_SCHEMA = climate_ir.climate_ir_with_receiver_schema(ToshibaClimate).exten ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await climate_ir.new_climate_ir(config) cg.add(var.set_model(config[CONF_MODEL])) diff --git a/esphome/components/total_daily_energy/sensor.py b/esphome/components/total_daily_energy/sensor.py index f026dc9530..343fe917de 100644 --- a/esphome/components/total_daily_energy/sensor.py +++ b/esphome/components/total_daily_energy/sensor.py @@ -13,6 +13,7 @@ from esphome.const import ( STATE_CLASS_TOTAL_INCREASING, ) from esphome.core.entity_helpers import inherit_property_from +from esphome.types import ConfigType DEPENDENCIES = ["time"] @@ -29,11 +30,11 @@ TotalDailyEnergy = total_daily_energy_ns.class_( ) -def inherit_unit_of_measurement(uom, config): +def inherit_unit_of_measurement(uom: str, config: ConfigType) -> str: return uom + "h" -def inherit_accuracy_decimals(decimals, config): +def inherit_accuracy_decimals(decimals: int, config: ConfigType) -> int: return decimals + 2 @@ -80,7 +81,7 @@ FINAL_VALIDATE_SCHEMA = cv.All( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await sensor.new_sensor(config) await cg.register_component(var, config) diff --git a/esphome/components/tsl2561/sensor.py b/esphome/components/tsl2561/sensor.py index cd4b88e740..79ee2587d3 100644 --- a/esphome/components/tsl2561/sensor.py +++ b/esphome/components/tsl2561/sensor.py @@ -1,3 +1,5 @@ +from typing import Any + import esphome.codegen as cg from esphome.components import i2c, sensor import esphome.config_validation as cv @@ -8,6 +10,8 @@ from esphome.const import ( STATE_CLASS_MEASUREMENT, UNIT_LUX, ) +from esphome.core import EnumValue +from esphome.types import ConfigType DEPENDENCIES = ["i2c"] @@ -28,7 +32,7 @@ GAINS = { CONF_IS_CS_PACKAGE = "is_cs_package" -def validate_integration_time(value): +def validate_integration_time(value: Any) -> EnumValue: value = cv.positive_time_period_milliseconds(value).total_milliseconds return cv.enum(INTEGRATION_TIMES, int=True)(value) @@ -59,7 +63,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await sensor.new_sensor(config) await cg.register_component(var, config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/tsl2591/sensor.py b/esphome/components/tsl2591/sensor.py index 0df3fa6687..fa202b0cea 100644 --- a/esphome/components/tsl2591/sensor.py +++ b/esphome/components/tsl2591/sensor.py @@ -19,6 +19,8 @@ # Here is the project that started me down the TSL2591 device trail in the first # place: https://hackaday.io/project/176690-the-water-watcher +from typing import Any + import esphome.codegen as cg from esphome.components import i2c, sensor import esphome.config_validation as cv @@ -40,6 +42,8 @@ from esphome.const import ( STATE_CLASS_MEASUREMENT, UNIT_LUX, ) +from esphome.core import EnumValue +from esphome.types import ConfigType DEPENDENCIES = ["i2c"] @@ -71,7 +75,7 @@ GAINS = { } -def validate_integration_time(value): +def validate_integration_time(value: Any) -> EnumValue: value = cv.positive_time_period_milliseconds(value).total_milliseconds return cv.enum(INTEGRATION_TIMES, int=True)(value) @@ -131,7 +135,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/tt21100/binary_sensor/__init__.py b/esphome/components/tt21100/binary_sensor/__init__.py index 081bd17c20..cc3226089d 100644 --- a/esphome/components/tt21100/binary_sensor/__init__.py +++ b/esphome/components/tt21100/binary_sensor/__init__.py @@ -2,6 +2,7 @@ import esphome.codegen as cg from esphome.components import binary_sensor import esphome.config_validation as cv from esphome.const import CONF_INDEX +from esphome.types import ConfigType from .. import tt21100_ns from ..touchscreen import TT21100ButtonListener, TT21100Touchscreen @@ -28,7 +29,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await binary_sensor.new_binary_sensor(config) await cg.register_component(var, config) await cg.register_parented(var, config[CONF_TT21100_ID]) diff --git a/esphome/components/tt21100/touchscreen/__init__.py b/esphome/components/tt21100/touchscreen/__init__.py index 9466dcdaa5..22489df379 100644 --- a/esphome/components/tt21100/touchscreen/__init__.py +++ b/esphome/components/tt21100/touchscreen/__init__.py @@ -3,6 +3,7 @@ import esphome.codegen as cg from esphome.components import i2c, touchscreen import esphome.config_validation as cv from esphome.const import CONF_ID, CONF_INTERRUPT_PIN, CONF_RESET_PIN +from esphome.types import ConfigType from .. import tt21100_ns @@ -26,7 +27,7 @@ CONFIG_SCHEMA = touchscreen.TOUCHSCREEN_SCHEMA.extend( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await touchscreen.register_touchscreen(var, config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/ttp229_bsf/__init__.py b/esphome/components/ttp229_bsf/__init__.py index fa1938723d..9e2a4ad114 100644 --- a/esphome/components/ttp229_bsf/__init__.py +++ b/esphome/components/ttp229_bsf/__init__.py @@ -2,6 +2,7 @@ from esphome import pins import esphome.codegen as cg import esphome.config_validation as cv from esphome.const import CONF_ID, CONF_SCL_PIN, CONF_SDO_PIN +from esphome.types import ConfigType AUTO_LOAD = ["binary_sensor"] @@ -20,7 +21,7 @@ CONFIG_SCHEMA = cv.Schema( ).extend(cv.COMPONENT_SCHEMA) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) diff --git a/esphome/components/ttp229_bsf/binary_sensor.py b/esphome/components/ttp229_bsf/binary_sensor.py index 178ad4f037..99280c82da 100644 --- a/esphome/components/ttp229_bsf/binary_sensor.py +++ b/esphome/components/ttp229_bsf/binary_sensor.py @@ -2,6 +2,7 @@ import esphome.codegen as cg from esphome.components import binary_sensor import esphome.config_validation as cv from esphome.const import CONF_CHANNEL +from esphome.types import ConfigType from . import CONF_TTP229_ID, TTP229BSFComponent, ttp229_bsf_ns @@ -16,7 +17,7 @@ CONFIG_SCHEMA = binary_sensor.binary_sensor_schema(TTP229BSFChannel).extend( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await binary_sensor.new_binary_sensor(config) cg.add(var.set_channel(config[CONF_CHANNEL])) diff --git a/esphome/components/ttp229_lsf/__init__.py b/esphome/components/ttp229_lsf/__init__.py index 412233a6bd..d32f72fcce 100644 --- a/esphome/components/ttp229_lsf/__init__.py +++ b/esphome/components/ttp229_lsf/__init__.py @@ -2,6 +2,7 @@ import esphome.codegen as cg from esphome.components import i2c import esphome.config_validation as cv from esphome.const import CONF_ID +from esphome.types import ConfigType DEPENDENCIES = ["i2c"] AUTO_LOAD = ["binary_sensor"] @@ -25,7 +26,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/ttp229_lsf/binary_sensor.py b/esphome/components/ttp229_lsf/binary_sensor.py index 07f00df4b4..7d11dfcbff 100644 --- a/esphome/components/ttp229_lsf/binary_sensor.py +++ b/esphome/components/ttp229_lsf/binary_sensor.py @@ -2,6 +2,7 @@ import esphome.codegen as cg from esphome.components import binary_sensor import esphome.config_validation as cv from esphome.const import CONF_CHANNEL +from esphome.types import ConfigType from . import CONF_TTP229_ID, TTP229LSFComponent, ttp229_lsf_ns @@ -16,7 +17,7 @@ CONFIG_SCHEMA = binary_sensor.binary_sensor_schema(TTP229Channel).extend( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await binary_sensor.new_binary_sensor(config) cg.add(var.set_channel(config[CONF_CHANNEL])) diff --git a/esphome/components/tx20/sensor.py b/esphome/components/tx20/sensor.py index 1bb5ab0706..3a24b8dc0b 100644 --- a/esphome/components/tx20/sensor.py +++ b/esphome/components/tx20/sensor.py @@ -14,6 +14,7 @@ from esphome.const import ( UNIT_DEGREES, UNIT_KILOMETER_PER_HOUR, ) +from esphome.types import ConfigType tx20_ns = cg.esphome_ns.namespace("tx20") Tx20Component = tx20_ns.class_("Tx20Component", cg.Component) @@ -39,7 +40,7 @@ CONFIG_SCHEMA = cv.Schema( ).extend(cv.COMPONENT_SCHEMA) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) diff --git a/esphome/components/uln2003/stepper.py b/esphome/components/uln2003/stepper.py index b57d7ffb92..03fd254d17 100644 --- a/esphome/components/uln2003/stepper.py +++ b/esphome/components/uln2003/stepper.py @@ -11,6 +11,7 @@ from esphome.const import ( CONF_SLEEP_WHEN_DONE, CONF_STEP_MODE, ) +from esphome.types import ConfigType uln2003_ns = cg.esphome_ns.namespace("uln2003") ULN2003StepMode = uln2003_ns.enum("ULN2003StepMode") @@ -38,7 +39,7 @@ CONFIG_SCHEMA = stepper.STEPPER_SCHEMA.extend( ).extend(cv.COMPONENT_SCHEMA) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await stepper.register_stepper(var, config) diff --git a/esphome/components/ultrasonic/sensor.py b/esphome/components/ultrasonic/sensor.py index fad4e6b11d..25973447f6 100644 --- a/esphome/components/ultrasonic/sensor.py +++ b/esphome/components/ultrasonic/sensor.py @@ -12,6 +12,7 @@ from esphome.const import ( STATE_CLASS_MEASUREMENT, UNIT_METER, ) +from esphome.types import ConfigType _LOGGER = logging.getLogger(__name__) @@ -44,7 +45,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await sensor.new_sensor(config) await cg.register_component(var, config) diff --git a/esphome/components/uptime/sensor/__init__.py b/esphome/components/uptime/sensor/__init__.py index dd76bb5a87..4b611ffff3 100644 --- a/esphome/components/uptime/sensor/__init__.py +++ b/esphome/components/uptime/sensor/__init__.py @@ -11,6 +11,7 @@ from esphome.const import ( STATE_CLASS_TOTAL_INCREASING, UNIT_SECOND, ) +from esphome.types import ConfigType uptime_ns = cg.esphome_ns.namespace("uptime") UptimeSecondsSensor = uptime_ns.class_( @@ -54,7 +55,7 @@ CONFIG_SCHEMA = cv.typed_schema( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await sensor.new_sensor(config) await cg.register_component(var, config) if time_id_config := config.get(CONF_TIME_ID): diff --git a/esphome/components/uptime/text_sensor/__init__.py b/esphome/components/uptime/text_sensor/__init__.py index 6b91b526c0..ed6a99c405 100644 --- a/esphome/components/uptime/text_sensor/__init__.py +++ b/esphome/components/uptime/text_sensor/__init__.py @@ -10,6 +10,7 @@ from esphome.const import ( ENTITY_CATEGORY_DIAGNOSTIC, ICON_TIMER, ) +from esphome.types import ConfigType uptime_ns = cg.esphome_ns.namespace("uptime") UptimeTextSensor = uptime_ns.class_( @@ -44,7 +45,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: format = config[CONF_FORMAT] var = cg.new_Pvariable( config[CONF_ID], diff --git a/esphome/components/usb_host/__init__.py b/esphome/components/usb_host/__init__.py index 70425c27ca..4abcc3a449 100644 --- a/esphome/components/usb_host/__init__.py +++ b/esphome/components/usb_host/__init__.py @@ -13,6 +13,7 @@ from esphome.components.esp32 import ( import esphome.config_validation as cv from esphome.const import CONF_DEVICES, CONF_ID from esphome.core import CORE +from esphome.cpp_generator import MockObj from esphome.cpp_types import Component from esphome.types import ConfigType @@ -30,7 +31,9 @@ CONF_MAX_TRANSFER_REQUESTS = "max_transfer_requests" CONF_MAX_PACKET_SIZE = "max_packet_size" -def usb_device_schema(cls=USBClient, vid: int = None, pid: int = None) -> cv.Schema: +def usb_device_schema( + cls=USBClient, vid: int | None = None, pid: int | None = None +) -> cv.Schema: schema = cv.COMPONENT_SCHEMA.extend( { cv.GenerateID(): cv.declare_id(cls), @@ -85,7 +88,7 @@ CONFIG_SCHEMA = cv.All( ) -async def register_usb_client(config): +async def register_usb_client(config: ConfigType) -> MockObj: var = cg.new_Pvariable(config[CONF_ID], config[CONF_VID], config[CONF_PID]) await cg.register_component(var, config) return var diff --git a/esphome/components/veml3235/sensor.py b/esphome/components/veml3235/sensor.py index 08d3685d1f..afff598869 100644 --- a/esphome/components/veml3235/sensor.py +++ b/esphome/components/veml3235/sensor.py @@ -8,6 +8,7 @@ from esphome.const import ( STATE_CLASS_MEASUREMENT, UNIT_LUX, ) +from esphome.types import ConfigType CODEOWNERS = ["@kbx81"] DEPENDENCIES = ["i2c"] @@ -43,7 +44,7 @@ GAINS = { } -def _validate_auto_gain_thresholds(config): +def _validate_auto_gain_thresholds(config: ConfigType) -> ConfigType: if config[CONF_AUTO_GAIN_THRESHOLD_LOW] >= config[CONF_AUTO_GAIN_THRESHOLD_HIGH]: raise cv.Invalid( f"'{CONF_AUTO_GAIN_THRESHOLD_LOW}' must be less than '{CONF_AUTO_GAIN_THRESHOLD_HIGH}'" @@ -80,7 +81,7 @@ CONFIG_SCHEMA = cv.All( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await sensor.new_sensor(config) await cg.register_component(var, config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/veml7700/sensor.py b/esphome/components/veml7700/sensor.py index d0d3584dc2..4afca4b868 100644 --- a/esphome/components/veml7700/sensor.py +++ b/esphome/components/veml7700/sensor.py @@ -1,3 +1,5 @@ +from typing import Any + import esphome.codegen as cg from esphome.components import i2c, sensor import esphome.config_validation as cv @@ -23,6 +25,8 @@ from esphome.const import ( UNIT_LUX, UNIT_MILLISECOND, ) +from esphome.core import EnumValue +from esphome.types import ConfigType CODEOWNERS = ["@latonita"] DEPENDENCIES = ["i2c"] @@ -59,7 +63,7 @@ INTEGRATION_TIMES = { } -def validate_integration_time(value): +def validate_integration_time(value: Any) -> EnumValue: value = cv.positive_time_period_milliseconds(value).total_milliseconds return cv.enum(INTEGRATION_TIMES, int=True)(value) @@ -151,7 +155,7 @@ CONFIG_SCHEMA = cv.All( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/version/text_sensor.py b/esphome/components/version/text_sensor.py index a55e18a5a7..cad239dc41 100644 --- a/esphome/components/version/text_sensor.py +++ b/esphome/components/version/text_sensor.py @@ -7,6 +7,7 @@ from esphome.const import ( ENTITY_CATEGORY_DIAGNOSTIC, ICON_NEW_BOX, ) +from esphome.types import ConfigType version_ns = cg.esphome_ns.namespace("version") VersionTextSensor = version_ns.class_( @@ -31,7 +32,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await text_sensor.new_text_sensor(config) await cg.register_component(var, config) cg.add(var.set_hide_hash(config[CONF_HIDE_HASH])) diff --git a/esphome/components/wake_on_lan/button.py b/esphome/components/wake_on_lan/button.py index e1a4e4f4b0..5e756d0057 100644 --- a/esphome/components/wake_on_lan/button.py +++ b/esphome/components/wake_on_lan/button.py @@ -3,11 +3,12 @@ from esphome.components import button import esphome.config_validation as cv from esphome.const import CONF_ID from esphome.core import CORE +from esphome.types import ConfigType DEPENDENCIES = ["network"] -def AUTO_LOAD(): +def AUTO_LOAD() -> list[str]: if CORE.is_esp8266 or CORE.is_rp2: return [] return ["socket"] @@ -30,7 +31,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) cg.add(var.set_macaddr(*config[CONF_TARGET_MAC_ADDRESS].parts)) await cg.register_component(var, config) diff --git a/esphome/components/waveshare_epaper/display.py b/esphome/components/waveshare_epaper/display.py index 7ecc3b4a87..be87c62377 100644 --- a/esphome/components/waveshare_epaper/display.py +++ b/esphome/components/waveshare_epaper/display.py @@ -13,6 +13,7 @@ from esphome.const import ( CONF_RESET_DURATION, CONF_RESET_PIN, ) +from esphome.types import ConfigType DEPENDENCIES = ["spi"] @@ -177,7 +178,7 @@ MODELS = { RESET_PIN_REQUIRED_MODELS = ("2.13inv2", "2.13in-ttgo-b74") -def validate_full_update_every_only_types_ac(value): +def validate_full_update_every_only_types_ac(value: ConfigType) -> ConfigType: if CONF_FULL_UPDATE_EVERY not in value: return value if MODELS[value[CONF_MODEL]][0] == "b": @@ -192,7 +193,7 @@ def validate_full_update_every_only_types_ac(value): return value -def validate_reset_pin_required(config): +def validate_reset_pin_required(config: ConfigType) -> ConfigType: if config[CONF_MODEL] in RESET_PIN_REQUIRED_MODELS and CONF_RESET_PIN not in config: raise cv.Invalid( f"'{CONF_RESET_PIN}' is required for model {config[CONF_MODEL]}" @@ -227,7 +228,7 @@ FINAL_VALIDATE_SCHEMA = spi.final_validate_device_schema( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: model_type, model = MODELS[config[CONF_MODEL]] if model_type == "a": rhs = WaveshareEPaperTypeA.new(model) diff --git a/esphome/components/web_server_base/__init__.py b/esphome/components/web_server_base/__init__.py index fc575d1c06..546e10ff5e 100644 --- a/esphome/components/web_server_base/__init__.py +++ b/esphome/components/web_server_base/__init__.py @@ -6,12 +6,13 @@ from esphome.const import CONF_ID from esphome.core import CORE, coroutine_with_priority from esphome.coroutine import CoroPriority from esphome.helpers import copy_file_if_changed +from esphome.types import ConfigType CODEOWNERS = ["@esphome/core"] DEPENDENCIES = ["network"] -def AUTO_LOAD(): +def AUTO_LOAD() -> list[str]: if CORE.is_esp32: return ["web_server_idf"] if CORE.using_arduino: @@ -25,7 +26,7 @@ WebServerBase = web_server_base_ns.class_("WebServerBase") CONF_WEB_SERVER_BASE_ID = "web_server_base_id" -def _consume_web_server_base_sockets(config): +def _consume_web_server_base_sockets(config: ConfigType) -> ConfigType: """Register the shared listening socket for the HTTP server. web_server_base is the shared HTTP server used by web_server and captive_portal. @@ -48,7 +49,7 @@ CONFIG_SCHEMA = cv.All( @coroutine_with_priority(CoroPriority.WEB_SERVER_BASE) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) cg.add(cg.RawExpression(f"{web_server_base_ns}::global_web_server_base = {var}")) diff --git a/esphome/components/web_server_idf/__init__.py b/esphome/components/web_server_idf/__init__.py index 1f195425f5..c16b0a2833 100644 --- a/esphome/components/web_server_idf/__init__.py +++ b/esphome/components/web_server_idf/__init__.py @@ -4,6 +4,7 @@ from esphome.components.esp32 import ( ) from esphome.config_helpers import filter_source_files_from_defines import esphome.config_validation as cv +from esphome.types import ConfigType CODEOWNERS = ["@dentra"] @@ -13,7 +14,7 @@ CONFIG_SCHEMA = cv.All( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: # Increase the maximum supported size of headers section in HTTP request packet to be processed by the server add_idf_sdkconfig_option("CONFIG_HTTPD_MAX_REQ_HDR_LEN", 1024) # Re-enable esp-tls (excluded by default to save compile time); diff --git a/esphome/components/whirlpool/climate.py b/esphome/components/whirlpool/climate.py index f969a505fb..3435a6c0bf 100644 --- a/esphome/components/whirlpool/climate.py +++ b/esphome/components/whirlpool/climate.py @@ -2,6 +2,7 @@ import esphome.codegen as cg from esphome.components import climate_ir import esphome.config_validation as cv from esphome.const import CONF_MODEL +from esphome.types import ConfigType AUTO_LOAD = ["climate_ir"] CODEOWNERS = ["@glmnet"] @@ -22,6 +23,6 @@ CONFIG_SCHEMA = climate_ir.climate_ir_with_receiver_schema(WhirlpoolClimate).ext ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await climate_ir.new_climate_ir(config) cg.add(var.set_model(config[CONF_MODEL])) diff --git a/esphome/components/whynter/climate.py b/esphome/components/whynter/climate.py index bf33890d9c..36f0942281 100644 --- a/esphome/components/whynter/climate.py +++ b/esphome/components/whynter/climate.py @@ -2,6 +2,7 @@ import esphome.codegen as cg from esphome.components import climate_ir import esphome.config_validation as cv from esphome.const import CONF_USE_FAHRENHEIT +from esphome.types import ConfigType AUTO_LOAD = ["climate_ir"] @@ -16,6 +17,6 @@ CONFIG_SCHEMA = climate_ir.climate_ir_with_receiver_schema(Whynter).extend( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await climate_ir.new_climate_ir(config) cg.add(var.set_fahrenheit(config[CONF_USE_FAHRENHEIT])) diff --git a/esphome/components/wiegand/__init__.py b/esphome/components/wiegand/__init__.py index 36ec7bd43f..dd6e84ac25 100644 --- a/esphome/components/wiegand/__init__.py +++ b/esphome/components/wiegand/__init__.py @@ -3,6 +3,7 @@ import esphome.codegen as cg from esphome.components import key_provider import esphome.config_validation as cv from esphome.const import CONF_ID, CONF_ON_KEY, CONF_ON_TAG, CONF_TRIGGER_ID +from esphome.types import ConfigType CODEOWNERS = ["@ssieb"] @@ -51,7 +52,7 @@ CONFIG_SCHEMA = cv.Schema( ).extend(cv.COMPONENT_SCHEMA) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) pin = await cg.gpio_pin_expression(config[CONF_D0]) diff --git a/esphome/components/wifi_info/text_sensor.py b/esphome/components/wifi_info/text_sensor.py index 5f72d0aa74..d14dcde46e 100644 --- a/esphome/components/wifi_info/text_sensor.py +++ b/esphome/components/wifi_info/text_sensor.py @@ -11,6 +11,7 @@ from esphome.const import ( CONF_SSID, ENTITY_CATEGORY_DIAGNOSTIC, ) +from esphome.types import ConfigType DEPENDENCIES = ["wifi"] @@ -70,14 +71,14 @@ CONFIG_SCHEMA = cv.Schema( ) -async def setup_conf(config, key): +async def setup_conf(config: ConfigType, key: str) -> None: if key in config: conf = config[key] var = await text_sensor.new_text_sensor(conf) await cg.register_component(var, conf) -async def to_code(config): +async def to_code(config: ConfigType) -> None: # Request specific WiFi listeners based on which sensors are configured # Each sensor needs its own listener slot - call request for EACH sensor diff --git a/esphome/components/wifi_signal/sensor.py b/esphome/components/wifi_signal/sensor.py index 075cfd96c6..41205f71ce 100644 --- a/esphome/components/wifi_signal/sensor.py +++ b/esphome/components/wifi_signal/sensor.py @@ -7,6 +7,7 @@ from esphome.const import ( STATE_CLASS_MEASUREMENT, UNIT_DECIBEL_MILLIWATT, ) +from esphome.types import ConfigType DEPENDENCIES = ["wifi"] wifi_signal_ns = cg.esphome_ns.namespace("wifi_signal") @@ -24,7 +25,7 @@ CONFIG_SCHEMA = sensor.sensor_schema( ).extend(cv.polling_component_schema("60s")) -async def to_code(config): +async def to_code(config: ConfigType) -> None: wifi.request_wifi_connect_state_listener() var = await sensor.new_sensor(config) await cg.register_component(var, config) diff --git a/esphome/components/wk2132_i2c/__init__.py b/esphome/components/wk2132_i2c/__init__.py index 903fe8fe4f..ecb7a5da09 100644 --- a/esphome/components/wk2132_i2c/__init__.py +++ b/esphome/components/wk2132_i2c/__init__.py @@ -2,6 +2,7 @@ import esphome.codegen as cg from esphome.components import i2c, weikai import esphome.config_validation as cv from esphome.const import CONF_ID +from esphome.types import ConfigType CODEOWNERS = ["@DrCoolZic"] DEPENDENCIES = ["i2c"] @@ -23,7 +24,7 @@ CONFIG_SCHEMA = cv.All( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) cg.add(var.set_name(str(config[CONF_ID]))) await weikai.register_weikai(var, config) diff --git a/esphome/components/wk2132_spi/__init__.py b/esphome/components/wk2132_spi/__init__.py index debc84f6d8..94b692f170 100644 --- a/esphome/components/wk2132_spi/__init__.py +++ b/esphome/components/wk2132_spi/__init__.py @@ -2,6 +2,7 @@ import esphome.codegen as cg from esphome.components import spi, weikai import esphome.config_validation as cv from esphome.const import CONF_ID +from esphome.types import ConfigType CODEOWNERS = ["@DrCoolZic"] DEPENDENCIES = ["spi"] @@ -23,7 +24,7 @@ CONFIG_SCHEMA = cv.All( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) cg.add(var.set_name(str(config[CONF_ID]))) await weikai.register_weikai(var, config) diff --git a/esphome/components/wk2168_i2c/__init__.py b/esphome/components/wk2168_i2c/__init__.py index 32fd4882db..d4aacaf97d 100644 --- a/esphome/components/wk2168_i2c/__init__.py +++ b/esphome/components/wk2168_i2c/__init__.py @@ -3,6 +3,8 @@ import esphome.codegen as cg from esphome.components import i2c, weikai import esphome.config_validation as cv from esphome.const import CONF_ID, CONF_INVERTED, CONF_MODE, CONF_NUMBER +from esphome.cpp_generator import MockObj +from esphome.types import ConfigType CODEOWNERS = ["@DrCoolZic"] DEPENDENCIES = ["i2c"] @@ -29,7 +31,7 @@ CONFIG_SCHEMA = cv.All( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) cg.add(var.set_name(str(config[CONF_ID]))) await weikai.register_weikai(var, config) @@ -48,7 +50,7 @@ WK2168_PIN_SCHEMA = cv.All( @pins.PIN_SCHEMA_REGISTRY.register(CONF_WK2168_I2C, WK2168_PIN_SCHEMA) -async def sc16is75x_pin_to_code(config): +async def sc16is75x_pin_to_code(config: ConfigType) -> MockObj: var = cg.new_Pvariable(config[CONF_ID]) parent = await cg.get_variable(config[CONF_WK2168_I2C]) cg.add(var.set_parent(parent)) diff --git a/esphome/components/wk2168_spi/__init__.py b/esphome/components/wk2168_spi/__init__.py index 123ce0bb8b..b4efaf65ac 100644 --- a/esphome/components/wk2168_spi/__init__.py +++ b/esphome/components/wk2168_spi/__init__.py @@ -3,6 +3,8 @@ import esphome.codegen as cg from esphome.components import spi, weikai import esphome.config_validation as cv from esphome.const import CONF_ID, CONF_INVERTED, CONF_MODE, CONF_NUMBER +from esphome.cpp_generator import MockObj +from esphome.types import ConfigType CODEOWNERS = ["@DrCoolZic"] DEPENDENCIES = ["spi"] @@ -27,7 +29,7 @@ CONFIG_SCHEMA = cv.All( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) cg.add(var.set_name(str(config[CONF_ID]))) await weikai.register_weikai(var, config) @@ -46,7 +48,7 @@ WK2168_PIN_SCHEMA = cv.All( @pins.PIN_SCHEMA_REGISTRY.register(CONF_WK2168_SPI, WK2168_PIN_SCHEMA) -async def sc16is75x_pin_to_code(config): +async def sc16is75x_pin_to_code(config: ConfigType) -> MockObj: var = cg.new_Pvariable(config[CONF_ID]) parent = await cg.get_variable(config[CONF_WK2168_SPI]) cg.add(var.set_parent(parent)) diff --git a/esphome/components/wk2204_i2c/__init__.py b/esphome/components/wk2204_i2c/__init__.py index a52aa30cc9..1502cc6cdb 100644 --- a/esphome/components/wk2204_i2c/__init__.py +++ b/esphome/components/wk2204_i2c/__init__.py @@ -2,6 +2,7 @@ import esphome.codegen as cg from esphome.components import i2c, weikai import esphome.config_validation as cv from esphome.const import CONF_ID +from esphome.types import ConfigType CODEOWNERS = ["@DrCoolZic"] DEPENDENCIES = ["i2c"] @@ -23,7 +24,7 @@ CONFIG_SCHEMA = cv.All( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) cg.add(var.set_name(str(config[CONF_ID]))) await weikai.register_weikai(var, config) diff --git a/esphome/components/wk2204_spi/__init__.py b/esphome/components/wk2204_spi/__init__.py index 616ba75c59..930f534bb0 100644 --- a/esphome/components/wk2204_spi/__init__.py +++ b/esphome/components/wk2204_spi/__init__.py @@ -2,6 +2,7 @@ import esphome.codegen as cg from esphome.components import spi, weikai import esphome.config_validation as cv from esphome.const import CONF_ID +from esphome.types import ConfigType CODEOWNERS = ["@DrCoolZic"] DEPENDENCIES = ["spi"] @@ -23,7 +24,7 @@ CONFIG_SCHEMA = cv.All( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) cg.add(var.set_name(str(config[CONF_ID]))) await weikai.register_weikai(var, config) diff --git a/esphome/components/wk2212_i2c/__init__.py b/esphome/components/wk2212_i2c/__init__.py index 0ef32cbc96..00018dd735 100644 --- a/esphome/components/wk2212_i2c/__init__.py +++ b/esphome/components/wk2212_i2c/__init__.py @@ -3,6 +3,8 @@ import esphome.codegen as cg from esphome.components import i2c, weikai import esphome.config_validation as cv from esphome.const import CONF_ID, CONF_INVERTED, CONF_MODE, CONF_NUMBER +from esphome.cpp_generator import MockObj +from esphome.types import ConfigType CODEOWNERS = ["@DrCoolZic"] DEPENDENCIES = ["i2c"] @@ -29,7 +31,7 @@ CONFIG_SCHEMA = cv.All( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) cg.add(var.set_name(str(config[CONF_ID]))) await weikai.register_weikai(var, config) @@ -48,7 +50,7 @@ WK2212_PIN_SCHEMA = cv.All( @pins.PIN_SCHEMA_REGISTRY.register(CONF_WK2212_I2C, WK2212_PIN_SCHEMA) -async def sc16is75x_pin_to_code(config): +async def sc16is75x_pin_to_code(config: ConfigType) -> MockObj: var = cg.new_Pvariable(config[CONF_ID]) parent = await cg.get_variable(config[CONF_WK2212_I2C]) cg.add(var.set_parent(parent)) diff --git a/esphome/components/wk2212_spi/__init__.py b/esphome/components/wk2212_spi/__init__.py index 8c9bea5416..c1a050e8ca 100644 --- a/esphome/components/wk2212_spi/__init__.py +++ b/esphome/components/wk2212_spi/__init__.py @@ -3,6 +3,8 @@ import esphome.codegen as cg from esphome.components import spi, weikai import esphome.config_validation as cv from esphome.const import CONF_ID, CONF_INVERTED, CONF_MODE, CONF_NUMBER +from esphome.cpp_generator import MockObj +from esphome.types import ConfigType CODEOWNERS = ["@DrCoolZic"] DEPENDENCIES = ["spi"] @@ -27,7 +29,7 @@ CONFIG_SCHEMA = cv.All( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) cg.add(var.set_name(str(config[CONF_ID]))) await weikai.register_weikai(var, config) @@ -46,7 +48,7 @@ WK2212_PIN_SCHEMA = cv.All( @pins.PIN_SCHEMA_REGISTRY.register(CONF_WK2212_SPI, WK2212_PIN_SCHEMA) -async def sc16is75x_pin_to_code(config): +async def sc16is75x_pin_to_code(config: ConfigType) -> MockObj: var = cg.new_Pvariable(config[CONF_ID]) parent = await cg.get_variable(config[CONF_WK2212_SPI]) cg.add(var.set_parent(parent)) diff --git a/esphome/components/wl_134/text_sensor.py b/esphome/components/wl_134/text_sensor.py index 1a10396bc6..af5e705786 100644 --- a/esphome/components/wl_134/text_sensor.py +++ b/esphome/components/wl_134/text_sensor.py @@ -2,6 +2,7 @@ import esphome.codegen as cg from esphome.components import text_sensor, uart import esphome.config_validation as cv from esphome.const import CONF_RESET, ICON_FINGERPRINT +from esphome.types import ConfigType CODEOWNERS = ["@hobbypunk90"] DEPENDENCIES = ["uart"] @@ -21,7 +22,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await text_sensor.new_text_sensor(config) await cg.register_component(var, config) cg.add(var.set_do_reset(config[CONF_RESET])) diff --git a/esphome/components/wled/__init__.py b/esphome/components/wled/__init__.py index 49eb15dad6..a7135975f0 100644 --- a/esphome/components/wled/__init__.py +++ b/esphome/components/wled/__init__.py @@ -3,7 +3,8 @@ from esphome.components.light.effects import register_addressable_effect from esphome.components.light.types import AddressableLightEffect import esphome.config_validation as cv from esphome.const import CONF_NAME, CONF_PORT -from esphome.core import CORE +from esphome.core import CORE, ID +from esphome.types import ConfigType wled_ns = cg.esphome_ns.namespace("wled") WLEDLightEffect = wled_ns.class_("WLEDLightEffect", AddressableLightEffect) @@ -23,7 +24,7 @@ CONF_BLANK_ON_START = "blank_on_start" cv.Optional(CONF_BLANK_ON_START, default=True): cv.boolean, }, ) -async def wled_light_effect_to_code(config, effect_id): +async def wled_light_effect_to_code(config: ConfigType, effect_id: ID) -> cg.MockObj: effect = cg.new_Pvariable(effect_id, config[CONF_NAME]) cg.add(effect.set_port(config[CONF_PORT])) cg.add(effect.set_sync_group_mask(config[CONF_SYNC_GROUP_MASK])) diff --git a/esphome/components/wts01/sensor.py b/esphome/components/wts01/sensor.py index bf4f0262ad..84032512f6 100644 --- a/esphome/components/wts01/sensor.py +++ b/esphome/components/wts01/sensor.py @@ -6,6 +6,7 @@ from esphome.const import ( STATE_CLASS_MEASUREMENT, UNIT_CELSIUS, ) +from esphome.types import ConfigType CONF_WTS01_ID = "wts01_id" CODEOWNERS = ["@alepee"] @@ -35,7 +36,7 @@ FINAL_VALIDATE_SCHEMA = uart.final_validate_device_schema( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await sensor.new_sensor(config) await cg.register_component(var, config) await uart.register_uart_device(var, config) diff --git a/esphome/components/x9c/output.py b/esphome/components/x9c/output.py index 0cc850b856..ff3f26e2ab 100644 --- a/esphome/components/x9c/output.py +++ b/esphome/components/x9c/output.py @@ -10,6 +10,7 @@ from esphome.const import ( CONF_STEP_DELAY, CONF_UD_PIN, ) +from esphome.types import ConfigType CODEOWNERS = ["@EtienneMD"] @@ -39,7 +40,7 @@ CONFIG_SCHEMA = cv.All( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await output.register_output(var, config) diff --git a/esphome/components/xdb401/sensor.py b/esphome/components/xdb401/sensor.py index 7545343f02..c629e46650 100644 --- a/esphome/components/xdb401/sensor.py +++ b/esphome/components/xdb401/sensor.py @@ -11,6 +11,7 @@ from esphome.const import ( UNIT_CELSIUS, UNIT_PASCAL, ) +from esphome.types import ConfigType DEPENDENCIES = ["i2c"] @@ -48,7 +49,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/xgzp68xx/sensor.py b/esphome/components/xgzp68xx/sensor.py index 6b83012eb4..83c20dfbd8 100644 --- a/esphome/components/xgzp68xx/sensor.py +++ b/esphome/components/xgzp68xx/sensor.py @@ -12,6 +12,7 @@ from esphome.const import ( UNIT_CELSIUS, UNIT_PASCAL, ) +from esphome.types import ConfigType DEPENDENCIES = ["i2c"] CODEOWNERS = ["@gcormier"] @@ -64,7 +65,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/xiaomi_ble/__init__.py b/esphome/components/xiaomi_ble/__init__.py index 7f5045f1ce..16da83934e 100644 --- a/esphome/components/xiaomi_ble/__init__.py +++ b/esphome/components/xiaomi_ble/__init__.py @@ -2,6 +2,7 @@ import esphome.codegen as cg from esphome.components import ble_device_base import esphome.config_validation as cv from esphome.const import CONF_ID +from esphome.types import ConfigType AUTO_LOAD = ["ble_device_base"] @@ -20,6 +21,6 @@ CONFIG_SCHEMA = cv.All( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await ble_device_base.register_ble_device(var, config) diff --git a/esphome/components/xiaomi_cgd1/sensor.py b/esphome/components/xiaomi_cgd1/sensor.py index 7206f023d7..09337df5ca 100644 --- a/esphome/components/xiaomi_cgd1/sensor.py +++ b/esphome/components/xiaomi_cgd1/sensor.py @@ -16,6 +16,7 @@ from esphome.const import ( UNIT_CELSIUS, UNIT_PERCENT, ) +from esphome.types import ConfigType AUTO_LOAD = ["ble_device_base", "xiaomi_ble"] @@ -57,7 +58,7 @@ CONFIG_SCHEMA = cv.All( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await ble_device_base.register_ble_device(var, config) diff --git a/esphome/components/xiaomi_cgdk2/sensor.py b/esphome/components/xiaomi_cgdk2/sensor.py index 0e7535cd76..83de32f411 100644 --- a/esphome/components/xiaomi_cgdk2/sensor.py +++ b/esphome/components/xiaomi_cgdk2/sensor.py @@ -16,6 +16,7 @@ from esphome.const import ( UNIT_CELSIUS, UNIT_PERCENT, ) +from esphome.types import ConfigType AUTO_LOAD = ["ble_device_base", "xiaomi_ble"] @@ -57,7 +58,7 @@ CONFIG_SCHEMA = cv.All( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await ble_device_base.register_ble_device(var, config) diff --git a/esphome/components/xiaomi_cgg1/sensor.py b/esphome/components/xiaomi_cgg1/sensor.py index 6273d8549b..3f0df9eafe 100644 --- a/esphome/components/xiaomi_cgg1/sensor.py +++ b/esphome/components/xiaomi_cgg1/sensor.py @@ -16,6 +16,7 @@ from esphome.const import ( UNIT_CELSIUS, UNIT_PERCENT, ) +from esphome.types import ConfigType AUTO_LOAD = ["ble_device_base", "xiaomi_ble"] @@ -57,7 +58,7 @@ CONFIG_SCHEMA = cv.All( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await ble_device_base.register_ble_device(var, config) diff --git a/esphome/components/xiaomi_cgpr1/binary_sensor.py b/esphome/components/xiaomi_cgpr1/binary_sensor.py index 3fdcd983b0..219432c1fc 100644 --- a/esphome/components/xiaomi_cgpr1/binary_sensor.py +++ b/esphome/components/xiaomi_cgpr1/binary_sensor.py @@ -17,6 +17,7 @@ from esphome.const import ( UNIT_MINUTE, UNIT_PERCENT, ) +from esphome.types import ConfigType AUTO_LOAD = ["ble_device_base", "xiaomi_ble", "sensor"] @@ -62,7 +63,7 @@ CONFIG_SCHEMA = cv.All( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await binary_sensor.new_binary_sensor(config) await cg.register_component(var, config) await ble_device_base.register_ble_device(var, config) diff --git a/esphome/components/xiaomi_gcls002/sensor.py b/esphome/components/xiaomi_gcls002/sensor.py index f430cbdd10..63ba5da597 100644 --- a/esphome/components/xiaomi_gcls002/sensor.py +++ b/esphome/components/xiaomi_gcls002/sensor.py @@ -18,6 +18,7 @@ from esphome.const import ( UNIT_MICROSIEMENS_PER_CENTIMETER, UNIT_PERCENT, ) +from esphome.types import ConfigType AUTO_LOAD = ["ble_device_base", "xiaomi_ble"] @@ -63,7 +64,7 @@ CONFIG_SCHEMA = cv.All( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await ble_device_base.register_ble_device(var, config) diff --git a/esphome/components/xiaomi_hhccjcy01/sensor.py b/esphome/components/xiaomi_hhccjcy01/sensor.py index 2c2e88b75f..13e8e509c3 100644 --- a/esphome/components/xiaomi_hhccjcy01/sensor.py +++ b/esphome/components/xiaomi_hhccjcy01/sensor.py @@ -21,6 +21,7 @@ from esphome.const import ( UNIT_MICROSIEMENS_PER_CENTIMETER, UNIT_PERCENT, ) +from esphome.types import ConfigType AUTO_LOAD = ["ble_device_base", "xiaomi_ble"] @@ -73,7 +74,7 @@ CONFIG_SCHEMA = cv.All( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await ble_device_base.register_ble_device(var, config) diff --git a/esphome/components/xiaomi_hhccjcy10/sensor.py b/esphome/components/xiaomi_hhccjcy10/sensor.py index 56eeda484e..d1ce8dfcf7 100644 --- a/esphome/components/xiaomi_hhccjcy10/sensor.py +++ b/esphome/components/xiaomi_hhccjcy10/sensor.py @@ -21,6 +21,7 @@ from esphome.const import ( UNIT_MICROSIEMENS_PER_CENTIMETER, UNIT_PERCENT, ) +from esphome.types import ConfigType AUTO_LOAD = ["ble_device_base"] @@ -73,7 +74,7 @@ CONFIG_SCHEMA = cv.All( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await ble_device_base.register_ble_device(var, config) diff --git a/esphome/components/xiaomi_hhccpot002/sensor.py b/esphome/components/xiaomi_hhccpot002/sensor.py index 50b10777bb..061753c44c 100644 --- a/esphome/components/xiaomi_hhccpot002/sensor.py +++ b/esphome/components/xiaomi_hhccpot002/sensor.py @@ -12,6 +12,7 @@ from esphome.const import ( UNIT_MICROSIEMENS_PER_CENTIMETER, UNIT_PERCENT, ) +from esphome.types import ConfigType AUTO_LOAD = ["ble_device_base", "xiaomi_ble"] @@ -45,7 +46,7 @@ CONFIG_SCHEMA = cv.All( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await ble_device_base.register_ble_device(var, config) diff --git a/esphome/components/xiaomi_jqjcy01ym/sensor.py b/esphome/components/xiaomi_jqjcy01ym/sensor.py index 7467f08785..b791c40dca 100644 --- a/esphome/components/xiaomi_jqjcy01ym/sensor.py +++ b/esphome/components/xiaomi_jqjcy01ym/sensor.py @@ -18,6 +18,7 @@ from esphome.const import ( UNIT_MILLIGRAMS_PER_CUBIC_METER, UNIT_PERCENT, ) +from esphome.types import ConfigType AUTO_LOAD = ["ble_device_base", "xiaomi_ble"] @@ -64,7 +65,7 @@ CONFIG_SCHEMA = cv.All( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await ble_device_base.register_ble_device(var, config) diff --git a/esphome/components/xiaomi_lywsd02/sensor.py b/esphome/components/xiaomi_lywsd02/sensor.py index c455961e7e..f79b81dce2 100644 --- a/esphome/components/xiaomi_lywsd02/sensor.py +++ b/esphome/components/xiaomi_lywsd02/sensor.py @@ -15,6 +15,7 @@ from esphome.const import ( UNIT_CELSIUS, UNIT_PERCENT, ) +from esphome.types import ConfigType AUTO_LOAD = ["ble_device_base", "xiaomi_ble"] @@ -55,7 +56,7 @@ CONFIG_SCHEMA = cv.All( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await ble_device_base.register_ble_device(var, config) diff --git a/esphome/components/xiaomi_lywsd02mmc/sensor.py b/esphome/components/xiaomi_lywsd02mmc/sensor.py index 000460b333..05e0204def 100644 --- a/esphome/components/xiaomi_lywsd02mmc/sensor.py +++ b/esphome/components/xiaomi_lywsd02mmc/sensor.py @@ -16,6 +16,7 @@ from esphome.const import ( UNIT_CELSIUS, UNIT_PERCENT, ) +from esphome.types import ConfigType AUTO_LOAD = ["ble_device_base", "xiaomi_ble"] CODEOWNERS = ["@juanluss31"] @@ -58,7 +59,7 @@ CONFIG_SCHEMA = cv.All( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await ble_device_base.register_ble_device(var, config) diff --git a/esphome/components/xiaomi_lywsd03mmc/sensor.py b/esphome/components/xiaomi_lywsd03mmc/sensor.py index 6362f26524..f4e24a97d0 100644 --- a/esphome/components/xiaomi_lywsd03mmc/sensor.py +++ b/esphome/components/xiaomi_lywsd03mmc/sensor.py @@ -16,6 +16,7 @@ from esphome.const import ( UNIT_CELSIUS, UNIT_PERCENT, ) +from esphome.types import ConfigType CODEOWNERS = ["@ahpohl"] @@ -59,7 +60,7 @@ CONFIG_SCHEMA = cv.All( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await ble_device_base.register_ble_device(var, config) diff --git a/esphome/components/xiaomi_lywsdcgq/sensor.py b/esphome/components/xiaomi_lywsdcgq/sensor.py index 0fbe4fcda9..8f0b93a22e 100644 --- a/esphome/components/xiaomi_lywsdcgq/sensor.py +++ b/esphome/components/xiaomi_lywsdcgq/sensor.py @@ -15,6 +15,7 @@ from esphome.const import ( UNIT_CELSIUS, UNIT_PERCENT, ) +from esphome.types import ConfigType AUTO_LOAD = ["ble_device_base", "xiaomi_ble"] @@ -55,7 +56,7 @@ CONFIG_SCHEMA = cv.All( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await ble_device_base.register_ble_device(var, config) diff --git a/esphome/components/xiaomi_mhoc303/sensor.py b/esphome/components/xiaomi_mhoc303/sensor.py index de1b3ea4b8..9ce544fc59 100644 --- a/esphome/components/xiaomi_mhoc303/sensor.py +++ b/esphome/components/xiaomi_mhoc303/sensor.py @@ -15,6 +15,7 @@ from esphome.const import ( UNIT_CELSIUS, UNIT_PERCENT, ) +from esphome.types import ConfigType AUTO_LOAD = ["ble_device_base", "xiaomi_ble"] @@ -55,7 +56,7 @@ CONFIG_SCHEMA = cv.All( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await ble_device_base.register_ble_device(var, config) diff --git a/esphome/components/xiaomi_mhoc401/sensor.py b/esphome/components/xiaomi_mhoc401/sensor.py index 4604af218e..52cae36fcd 100644 --- a/esphome/components/xiaomi_mhoc401/sensor.py +++ b/esphome/components/xiaomi_mhoc401/sensor.py @@ -16,6 +16,7 @@ from esphome.const import ( UNIT_CELSIUS, UNIT_PERCENT, ) +from esphome.types import ConfigType CODEOWNERS = ["@vevsvevs"] AUTO_LOAD = ["ble_device_base", "xiaomi_ble"] @@ -58,7 +59,7 @@ CONFIG_SCHEMA = cv.All( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await ble_device_base.register_ble_device(var, config) diff --git a/esphome/components/xiaomi_miscale/sensor.py b/esphome/components/xiaomi_miscale/sensor.py index 8a2ac6bbb3..fa4296d7a9 100644 --- a/esphome/components/xiaomi_miscale/sensor.py +++ b/esphome/components/xiaomi_miscale/sensor.py @@ -14,6 +14,7 @@ from esphome.const import ( UNIT_KILOGRAM, UNIT_OHM, ) +from esphome.types import ConfigType AUTO_LOAD = ["ble_device_base"] @@ -49,7 +50,7 @@ CONFIG_SCHEMA = cv.All( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await ble_device_base.register_ble_device(var, config) diff --git a/esphome/components/xiaomi_mjyd02yla/binary_sensor.py b/esphome/components/xiaomi_mjyd02yla/binary_sensor.py index 4cfc82d2c6..5d562a2ca9 100644 --- a/esphome/components/xiaomi_mjyd02yla/binary_sensor.py +++ b/esphome/components/xiaomi_mjyd02yla/binary_sensor.py @@ -19,6 +19,7 @@ from esphome.const import ( UNIT_MINUTE, UNIT_PERCENT, ) +from esphome.types import ConfigType AUTO_LOAD = ["ble_device_base", "xiaomi_ble", "sensor"] @@ -68,7 +69,7 @@ CONFIG_SCHEMA = cv.All( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await binary_sensor.new_binary_sensor(config) await cg.register_component(var, config) await ble_device_base.register_ble_device(var, config) diff --git a/esphome/components/xiaomi_mue4094rt/binary_sensor.py b/esphome/components/xiaomi_mue4094rt/binary_sensor.py index 6df8dcb8ea..34678eeac7 100644 --- a/esphome/components/xiaomi_mue4094rt/binary_sensor.py +++ b/esphome/components/xiaomi_mue4094rt/binary_sensor.py @@ -3,6 +3,7 @@ import esphome.codegen as cg from esphome.components import binary_sensor, ble_device_base import esphome.config_validation as cv from esphome.const import CONF_MAC_ADDRESS, CONF_TIMEOUT, DEVICE_CLASS_MOTION +from esphome.types import ConfigType AUTO_LOAD = ["ble_device_base", "xiaomi_ble"] @@ -33,7 +34,7 @@ CONFIG_SCHEMA = cv.All( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await binary_sensor.new_binary_sensor(config) await cg.register_component(var, config) await ble_device_base.register_ble_device(var, config) diff --git a/esphome/components/xiaomi_wx08zm/binary_sensor.py b/esphome/components/xiaomi_wx08zm/binary_sensor.py index 6aaf94f48f..4a6267f8b9 100644 --- a/esphome/components/xiaomi_wx08zm/binary_sensor.py +++ b/esphome/components/xiaomi_wx08zm/binary_sensor.py @@ -11,6 +11,7 @@ from esphome.const import ( STATE_CLASS_MEASUREMENT, UNIT_PERCENT, ) +from esphome.types import ConfigType AUTO_LOAD = ["ble_device_base", "xiaomi_ble", "sensor"] @@ -48,7 +49,7 @@ CONFIG_SCHEMA = cv.All( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await binary_sensor.new_binary_sensor(config) await cg.register_component(var, config) await ble_device_base.register_ble_device(var, config) diff --git a/esphome/components/xiaomi_xmwsdj04mmc/sensor.py b/esphome/components/xiaomi_xmwsdj04mmc/sensor.py index 758fa53d9e..8282523129 100644 --- a/esphome/components/xiaomi_xmwsdj04mmc/sensor.py +++ b/esphome/components/xiaomi_xmwsdj04mmc/sensor.py @@ -16,6 +16,7 @@ from esphome.const import ( UNIT_CELSIUS, UNIT_PERCENT, ) +from esphome.types import ConfigType AUTO_LOAD = ["ble_device_base", "xiaomi_ble"] CODEOWNERS = ["@medusalix"] @@ -58,7 +59,7 @@ CONFIG_SCHEMA = cv.All( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await ble_device_base.register_ble_device(var, config) diff --git a/esphome/components/xpt2046/touchscreen/__init__.py b/esphome/components/xpt2046/touchscreen/__init__.py index d91ae44789..e38bc23da3 100644 --- a/esphome/components/xpt2046/touchscreen/__init__.py +++ b/esphome/components/xpt2046/touchscreen/__init__.py @@ -3,6 +3,7 @@ import esphome.codegen as cg from esphome.components import spi, touchscreen import esphome.config_validation as cv from esphome.const import CONF_ID, CONF_INTERRUPT_PIN, CONF_THRESHOLD +from esphome.types import ConfigType CODEOWNERS = ["@numo68", "@nielsnl68"] DEPENDENCIES = ["spi"] @@ -31,7 +32,7 @@ CONFIG_SCHEMA = cv.All( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await spi.register_spi_device(var, config) await touchscreen.register_touchscreen(var, config) diff --git a/esphome/components/yashima/climate.py b/esphome/components/yashima/climate.py index d7386eb6a3..cfc4744d82 100644 --- a/esphome/components/yashima/climate.py +++ b/esphome/components/yashima/climate.py @@ -3,6 +3,7 @@ from esphome.components import climate, remote_transmitter, sensor from esphome.components.remote_base import CONF_TRANSMITTER_ID import esphome.config_validation as cv from esphome.const import CONF_SENSOR, CONF_SUPPORTS_COOL, CONF_SUPPORTS_HEAT +from esphome.types import ConfigType AUTO_LOAD = ["sensor"] @@ -25,7 +26,7 @@ CONFIG_SCHEMA = cv.All( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await climate.new_climate(config) await cg.register_component(var, config) diff --git a/esphome/components/zephyr/__init__.py b/esphome/components/zephyr/__init__.py index 338d1986ea..29ba0b9ed2 100644 --- a/esphome/components/zephyr/__init__.py +++ b/esphome/components/zephyr/__init__.py @@ -50,14 +50,14 @@ PrjConfValueType = bool | str | int | HexValue class Section: - def __init__(self, name, address, size, region): + def __init__(self, name: str, address: int, size: int, region: str) -> None: self.name = name self.address = address self.size = size self.region = region self.end_address = self.address + self.size - def __str__(self): + def __str__(self) -> str: return ( f"{self.name}:\n" f" address: 0x{self.address:X}\n" @@ -181,7 +181,7 @@ async def _cdc_acm_to_code(config: ConfigType) -> None: await cg.register_component(var, {}) -def zephyr_setup_preferences(): +def zephyr_setup_preferences() -> None: cg.add(zephyr_ns.setup_preferences()) zephyr_add_prj_conf("SETTINGS", True) zephyr_add_prj_conf("NVS", True) diff --git a/esphome/components/zephyr_mcumgr/ota/__init__.py b/esphome/components/zephyr_mcumgr/ota/__init__.py index 1503c94274..ad89c1ac79 100644 --- a/esphome/components/zephyr_mcumgr/ota/__init__.py +++ b/esphome/components/zephyr_mcumgr/ota/__init__.py @@ -177,7 +177,7 @@ async def to_code(config: ConfigType) -> None: slot1_start = slot0_start + slot_size def _mcuboot_partition_overlay() -> str: - def part(name, start, size): + def part(name: str, start: int, size: int) -> str: return f""" {name}: partition@{start:x} {{ reg = <0x{start:x} 0x{size:x}>; diff --git a/esphome/components/zephyr_pwm/output.py b/esphome/components/zephyr_pwm/output.py index b7ee27f63c..2cb62b85b5 100644 --- a/esphome/components/zephyr_pwm/output.py +++ b/esphome/components/zephyr_pwm/output.py @@ -1,4 +1,5 @@ from dataclasses import dataclass, field +from typing import Any from esphome import pins import esphome.codegen as cg @@ -29,7 +30,7 @@ ZephyrPWMChannel = zephyr_pwm_ns.class_( validate_frequency = cv.All(cv.frequency, cv.float_range(min=3.815, max=1e7)) -def _pin_schema(value): +def _pin_schema(value: Any) -> ConfigType: value = pins.internal_gpio_output_pin_schema(value) if value.get(CONF_ALLOW_OTHER_USES, False): raise cv.Invalid("allow_other_uses is not supported for zephyr_pwm pins") @@ -109,7 +110,7 @@ def _final_validate(config: ConfigType) -> None: FINAL_VALIDATE_SCHEMA = _final_validate -def _overlay_pwm(): +def _overlay_pwm() -> str: pwm_blocks: list[PWMBlock] = _get_data().pwm_blocks assert CORE.is_nrf52 @@ -153,7 +154,7 @@ def _overlay_pwm(): return "\n".join(overlay_parts) -async def to_code(config): +async def to_code(config: ConfigType) -> None: zephyr_add_prj_conf("PWM", True) pin = config[CONF_PIN] pwm_blocks: list[PWMBlock] = _get_data().pwm_blocks diff --git a/esphome/components/zhlt01/climate.py b/esphome/components/zhlt01/climate.py index 8d0c50308b..9e9933229f 100644 --- a/esphome/components/zhlt01/climate.py +++ b/esphome/components/zhlt01/climate.py @@ -1,5 +1,6 @@ import esphome.codegen as cg from esphome.components import climate_ir +from esphome.types import ConfigType AUTO_LOAD = ["climate_ir"] CODEOWNERS = ["@cfeenstra1024"] @@ -10,5 +11,5 @@ ZHLT01Climate = zhlt01_ns.class_("ZHLT01Climate", climate_ir.ClimateIR) CONFIG_SCHEMA = climate_ir.climate_ir_with_receiver_schema(ZHLT01Climate) -async def to_code(config): +async def to_code(config: ConfigType) -> None: await climate_ir.new_climate_ir(config) diff --git a/esphome/components/zio_ultrasonic/sensor.py b/esphome/components/zio_ultrasonic/sensor.py index 533bc5cc57..c4134cc40e 100644 --- a/esphome/components/zio_ultrasonic/sensor.py +++ b/esphome/components/zio_ultrasonic/sensor.py @@ -2,6 +2,7 @@ import esphome.codegen as cg from esphome.components import i2c, sensor import esphome.config_validation as cv from esphome.const import DEVICE_CLASS_DISTANCE, STATE_CLASS_MEASUREMENT +from esphome.types import ConfigType DEPENDENCIES = ["i2c"] CODEOWNERS = ["@kahrendt"] @@ -25,7 +26,7 @@ CONFIG_SCHEMA = ( ) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = await sensor.new_sensor(config) await cg.register_component(var, config) await i2c.register_i2c_device(var, config) diff --git a/esphome/components/zwave_proxy/__init__.py b/esphome/components/zwave_proxy/__init__.py index 14b8474045..660e3f49a0 100644 --- a/esphome/components/zwave_proxy/__init__.py +++ b/esphome/components/zwave_proxy/__init__.py @@ -3,6 +3,7 @@ from esphome.components import uart import esphome.config_validation as cv from esphome.const import CONF_ID, CONF_POWER_SAVE_MODE, CONF_WIFI import esphome.final_validate as fv +from esphome.types import ConfigType CODEOWNERS = ["@kbx81"] DEPENDENCIES = ["api", "uart"] @@ -11,7 +12,7 @@ zwave_proxy_ns = cg.esphome_ns.namespace("zwave_proxy") ZWaveProxy = zwave_proxy_ns.class_("ZWaveProxy", cg.Component, uart.UARTDevice) -def final_validate(config) -> None: +def final_validate(config: ConfigType) -> None: full_config = fv.full_config.get() if (wifi_conf := full_config.get(CONF_WIFI)) and ( wifi_conf.get(CONF_POWER_SAVE_MODE).lower() != "none" @@ -34,7 +35,7 @@ CONFIG_SCHEMA = ( FINAL_VALIDATE_SCHEMA = final_validate -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await uart.register_uart_device(var, config) diff --git a/esphome/components/zyaura/sensor.py b/esphome/components/zyaura/sensor.py index 58de519283..0508f456e4 100644 --- a/esphome/components/zyaura/sensor.py +++ b/esphome/components/zyaura/sensor.py @@ -19,6 +19,7 @@ from esphome.const import ( UNIT_PERCENT, ) from esphome.cpp_helpers import gpio_pin_expression +from esphome.types import ConfigType zyaura_ns = cg.esphome_ns.namespace("zyaura") ZyAuraSensor = zyaura_ns.class_("ZyAuraSensor", cg.PollingComponent) @@ -51,7 +52,7 @@ CONFIG_SCHEMA = cv.Schema( ).extend(cv.polling_component_schema("60s")) -async def to_code(config): +async def to_code(config: ConfigType) -> None: var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config)