diff --git a/esphome/components/bk72xx_ble/__init__.py b/esphome/components/bk72xx_ble/__init__.py index b58464a1f6..81073c9b02 100644 --- a/esphome/components/bk72xx_ble/__init__.py +++ b/esphome/components/bk72xx_ble/__init__.py @@ -68,12 +68,11 @@ def _unsupported_family_message(family: str) -> str | None: return None -def _final_validate(config: ConfigType) -> ConfigType: +def _final_validate(config: ConfigType) -> None: # Warn only: a hard error here would break the validate-only CI fixtures, # which run on a BLE 4.2 board. The hard error is raised at codegen. if msg := _unsupported_family_message(libretiny.get_libretiny_family()): _LOGGER.warning("%s (this configuration cannot compile)", msg) - return config FINAL_VALIDATE_SCHEMA = _final_validate diff --git a/esphome/components/captive_portal/__init__.py b/esphome/components/captive_portal/__init__.py index d62c718097..8e5274f58f 100644 --- a/esphome/components/captive_portal/__init__.py +++ b/esphome/components/captive_portal/__init__.py @@ -61,7 +61,7 @@ CONFIG_SCHEMA = cv.All( ) -def _final_validate(config: ConfigType) -> ConfigType: +def _final_validate(config: ConfigType) -> None: full_config = fv.full_config.get() wifi_conf = full_config.get("wifi") @@ -88,8 +88,6 @@ def _final_validate(config: ConfigType) -> ConfigType: socket.consume_sockets(3, "captive_portal")(config) socket.consume_sockets(1, "captive_portal", socket.SocketType.UDP)(config) - return config - FINAL_VALIDATE_SCHEMA = _final_validate diff --git a/esphome/components/dsmr/__init__.py b/esphome/components/dsmr/__init__.py index 34f37ace35..eaf36d34fa 100644 --- a/esphome/components/dsmr/__init__.py +++ b/esphome/components/dsmr/__init__.py @@ -88,7 +88,7 @@ async def to_code(config): cg.add_library("esphome/dsmr_parser", "1.9.0") -def final_validate(config: ConfigType) -> ConfigType: +def final_validate(config: ConfigType) -> None: full_config = fv.full_config.get() for uart_conf in full_config["uart"]: @@ -102,7 +102,5 @@ def final_validate(config: ConfigType) -> ConfigType: ) break - return config - FINAL_VALIDATE_SCHEMA = final_validate diff --git a/esphome/components/emontx/__init__.py b/esphome/components/emontx/__init__.py index a2d4349698..3f83578926 100644 --- a/esphome/components/emontx/__init__.py +++ b/esphome/components/emontx/__init__.py @@ -59,7 +59,7 @@ CONFIG_SCHEMA = ( ) -def final_validate(config: ConfigType) -> ConfigType: +def final_validate(config: ConfigType) -> None: full_config = fv.full_config.get() # Count sensors registered to this hub (IDs are resolved at final_validate stage) @@ -95,7 +95,7 @@ def final_validate(config: ConfigType) -> ConfigType: parity="NONE", stop_bits=1, ) - return schema(config) + schema(config) FINAL_VALIDATE_SCHEMA = final_validate diff --git a/esphome/components/epaper_spi/display.py b/esphome/components/epaper_spi/display.py index 0b82850f1e..e9da924de5 100644 --- a/esphome/components/epaper_spi/display.py +++ b/esphome/components/epaper_spi/display.py @@ -153,7 +153,7 @@ def customise_schema(config): CONFIG_SCHEMA = customise_schema -def _final_validate(config): +def _final_validate(config) -> None: spi.final_validate_device_schema( "epaper_spi", require_miso=False, require_mosi=True )(config) @@ -170,7 +170,6 @@ def _final_validate(config): config[CONF_SHOW_TEST_CARD] = True elif CONF_UPDATE_INTERVAL not in config: config[CONF_UPDATE_INTERVAL] = update_interval("1min") - return config FINAL_VALIDATE_SCHEMA = _final_validate diff --git a/esphome/components/esp32/__init__.py b/esphome/components/esp32/__init__.py index 7263571d69..7d43c3ac07 100644 --- a/esphome/components/esp32/__init__.py +++ b/esphome/components/esp32/__init__.py @@ -1368,7 +1368,7 @@ def _validate_signed_ota_keys(config: ConfigType) -> ConfigType: return config -def final_validate(config): +def final_validate(config) -> None: # Imported locally to avoid circular import issues from esphome.components.psram import DOMAIN as PSRAM_DOMAIN @@ -1629,8 +1629,6 @@ def final_validate(config): if errs: raise cv.MultipleInvalid(errs) - return config - CONF_SDKCONFIG_OPTIONS = "sdkconfig_options" CONF_ENABLE_LWIP_DHCP_SERVER = "enable_lwip_dhcp_server" diff --git a/esphome/components/esp32_ble/__init__.py b/esphome/components/esp32_ble/__init__.py index 935d8b1b7e..f099c68e57 100644 --- a/esphome/components/esp32_ble/__init__.py +++ b/esphome/components/esp32_ble/__init__.py @@ -443,7 +443,7 @@ def validate_connection_slots(max_connections: int) -> None: ) -def final_validation(config): +def final_validation(config) -> None: validate_variant(config) if (name := config.get(CONF_NAME)) is not None: full_config = fv.full_config.get() @@ -514,8 +514,6 @@ def final_validation(config): # For newer chips (C3/S3/etc), different configs are used automatically add_idf_sdkconfig_option("CONFIG_BTDM_CTRL_BLE_MAX_CONN", max_connections) - return config - FINAL_VALIDATE_SCHEMA = final_validation diff --git a/esphome/components/esp32_ble_server/__init__.py b/esphome/components/esp32_ble_server/__init__.py index ea2a9667d7..855a3be29b 100644 --- a/esphome/components/esp32_ble_server/__init__.py +++ b/esphome/components/esp32_ble_server/__init__.py @@ -307,7 +307,7 @@ def create_device_information_service(config): return config -def final_validate_config(config): +def final_validate_config(config) -> None: # Validate max_clients does not exceed esp32_ble max_connections max_clients = config[CONF_MAX_CLIENTS] if max_clients > 1: @@ -355,7 +355,6 @@ def final_validate_config(config): raise cv.Invalid( f"Characteristic {char_config[CONF_UUID]} has both a set_value action and a templated value" ) - return config def validate_value_type(value_config): diff --git a/esphome/components/esp32_hosted/__init__.py b/esphome/components/esp32_hosted/__init__.py index d3432fb461..7dc61ce382 100644 --- a/esphome/components/esp32_hosted/__init__.py +++ b/esphome/components/esp32_hosted/__init__.py @@ -126,7 +126,7 @@ CONFIG_SCHEMA = cv.typed_schema( ) -def _final_validate(config: ConfigType) -> ConfigType: +def _final_validate(config: ConfigType) -> None: # The esp_hosted releases compatible with older ESP-IDF versions crash at # boot with a heap double free in the SDIO RX path (fixed in esp_hosted # 2.11.0, which requires ESP-IDF 5.3), so reject them at validation time. @@ -136,7 +136,6 @@ def _final_validate(config: ConfigType) -> ConfigType: "Remove the framework version from your configuration to use the " "recommended version, or pin a version at or above 5.3." ) - return config FINAL_VALIDATE_SCHEMA = _final_validate diff --git a/esphome/components/ethernet/__init__.py b/esphome/components/ethernet/__init__.py index f3c77baaae..5eda0fc12c 100644 --- a/esphome/components/ethernet/__init__.py +++ b/esphome/components/ethernet/__init__.py @@ -767,7 +767,7 @@ def _final_validate_rmii_pins(config: ConfigType) -> None: raise cv.Invalid(error_msg, path=pin_path) -def _final_validate(config: ConfigType) -> ConfigType: +def _final_validate(config: ConfigType) -> None: """Final validation for Ethernet component.""" # Allow ethernet + wifi coexistence only when both are declared in network: priority:. if "wifi" in fv.full_config.get(): @@ -787,7 +787,6 @@ def _final_validate(config: ConfigType) -> ConfigType: _final_validate_spi(config) _final_validate_rmii_pins(config) - return config FINAL_VALIDATE_SCHEMA = _final_validate diff --git a/esphome/components/factory_reset/__init__.py b/esphome/components/factory_reset/__init__.py index 818a53c0ed..d5d5d2ecb5 100644 --- a/esphome/components/factory_reset/__init__.py +++ b/esphome/components/factory_reset/__init__.py @@ -60,14 +60,13 @@ CONFIG_SCHEMA = cv.All( ) -def _final_validate(config): +def _final_validate(config) -> None: if CORE.is_esp8266 and CONF_RESETS_REQUIRED in config: fconfig = full_config.get() if not fconfig.get_config_for_path([KEY_ESP8266, CONF_RESTORE_FROM_FLASH]): raise cv.Invalid( "'resets_required' needs 'restore_from_flash' to be enabled in the 'esp8266' configuration" ) - return config FINAL_VALIDATE_SCHEMA = _final_validate diff --git a/esphome/components/file/image.py b/esphome/components/file/image.py index b54c3f2adf..d340d21490 100644 --- a/esphome/components/file/image.py +++ b/esphome/components/file/image.py @@ -225,7 +225,7 @@ def image_schema(class_: MockObjClass = Image_) -> cv.Schema: ) -def validate_image_final(config: ConfigType) -> ConfigType: +def validate_image_final(config: ConfigType) -> None: """Per-entry final validation, shared by file-backed image platforms. For LVGL 9 the default byte order for RGB565 images is little-endian, so @@ -240,7 +240,6 @@ def validate_image_final(config: ConfigType) -> ConfigType: ) else: config[CONF_BYTE_ORDER] = "LITTLE_ENDIAN" - return config async def new_image(config: ConfigType) -> MockObj: diff --git a/esphome/components/gpio/binary_sensor/__init__.py b/esphome/components/gpio/binary_sensor/__init__.py index 43358baedb..703806670c 100644 --- a/esphome/components/gpio/binary_sensor/__init__.py +++ b/esphome/components/gpio/binary_sensor/__init__.py @@ -68,10 +68,10 @@ def _pin_shared_only_with_deep_sleep(pin_num: int) -> bool: return any(path and path[0] == "deep_sleep" for path, _, _ in pin_users) -def _final_validate(config): +def _final_validate(config) -> None: use_interrupt = config[CONF_USE_INTERRUPT] if not use_interrupt: - return config + return # Expander pins (e.g. PCF8574, MCP23017) don't support direct interrupt # attachment — only internal/native GPIO pins do. @@ -82,7 +82,7 @@ def _final_validate(config): config.get(CONF_NAME, config[CONF_ID]), ) config[CONF_USE_INTERRUPT] = False - return config + return pin_num = config[CONF_PIN][CONF_NUMBER] @@ -96,7 +96,7 @@ def _final_validate(config): config.get(CONF_NAME, config[CONF_ID]), ) config[CONF_USE_INTERRUPT] = False - return config + return # When a pin is shared, interrupts can interfere with other components # (e.g., duty_cycle sensor) that need to monitor the pin's state changes. @@ -120,8 +120,6 @@ def _final_validate(config): pin_num, ) - return config - FINAL_VALIDATE_SCHEMA = _final_validate diff --git a/esphome/components/growatt_solar/sensor.py b/esphome/components/growatt_solar/sensor.py index d1f0069341..d62486f5ec 100644 --- a/esphome/components/growatt_solar/sensor.py +++ b/esphome/components/growatt_solar/sensor.py @@ -163,8 +163,8 @@ CONFIG_SCHEMA = ( ) -def _final_validate(config: ConfigType) -> ConfigType: - return modbus.final_validate_modbus_device("growatt_solar", role="client")(config) +def _final_validate(config: ConfigType) -> None: + modbus.final_validate_modbus_device("growatt_solar", role="client")(config) FINAL_VALIDATE_SCHEMA = _final_validate diff --git a/esphome/components/haier/climate.py b/esphome/components/haier/climate.py index 424ef46392..70ae36f528 100644 --- a/esphome/components/haier/climate.py +++ b/esphome/components/haier/climate.py @@ -424,7 +424,7 @@ async def power_action_to_code(config, action_id, template_arg, args): return cg.new_Pvariable(action_id, template_arg, paren) -def _final_validate(config): +def _final_validate(config) -> None: full_config = fv.full_config.get() if CONF_LOGGER in full_config: _level = "NONE" @@ -448,7 +448,6 @@ def _final_validate(config): raise cv.Invalid( f"No WiFi configured, if you want to use haier climate without WiFi add {CONF_WIFI_SIGNAL}: false to climate configuration" ) - return config FINAL_VALIDATE_SCHEMA = _final_validate diff --git a/esphome/components/haier/switch/__init__.py b/esphome/components/haier/switch/__init__.py index acff0cf265..99ffcb37af 100644 --- a/esphome/components/haier/switch/__init__.py +++ b/esphome/components/haier/switch/__init__.py @@ -60,7 +60,7 @@ CONFIG_SCHEMA = cv.Schema( ) -def _final_validate(config): +def _final_validate(config) -> None: full_config = fv.full_config.get() for switch_type in [CONF_BEEPER, CONF_QUIET_MODE]: # Check switches that are only supported for HonClimate @@ -72,7 +72,6 @@ def _final_validate(config): raise cv.Invalid( f"{switch_type} switch is only supported for hon climate" ) - return config FINAL_VALIDATE_SCHEMA = _final_validate diff --git a/esphome/components/havells_solar/sensor.py b/esphome/components/havells_solar/sensor.py index d18ae0d9af..8eafe1d9d6 100644 --- a/esphome/components/havells_solar/sensor.py +++ b/esphome/components/havells_solar/sensor.py @@ -217,8 +217,8 @@ CONFIG_SCHEMA = ( ) -def _final_validate(config: ConfigType) -> ConfigType: - return modbus.final_validate_modbus_device("havells_solar", role="client")(config) +def _final_validate(config: ConfigType) -> None: + modbus.final_validate_modbus_device("havells_solar", role="client")(config) FINAL_VALIDATE_SCHEMA = _final_validate diff --git a/esphome/components/hub75/display.py b/esphome/components/hub75/display.py index a404fbbade..24b8197073 100644 --- a/esphome/components/hub75/display.py +++ b/esphome/components/hub75/display.py @@ -315,7 +315,7 @@ def _validate_config(config: ConfigType) -> ConfigType: return config -def _final_validate(config: ConfigType) -> ConfigType: +def _final_validate(config: ConfigType) -> None: """Validate requirements when using HUB75 display.""" # Local imports to avoid circular dependencies from esphome.components.esp32 import get_esp32_variant @@ -381,8 +381,6 @@ def _final_validate(config: ConfigType) -> ConfigType: if errs: raise cv.MultipleInvalid(errs) - return config - FINAL_VALIDATE_SCHEMA = cv.Schema(_final_validate) diff --git a/esphome/components/improv_serial/__init__.py b/esphome/components/improv_serial/__init__.py index 4266f5b78b..3e2a6db1bc 100644 --- a/esphome/components/improv_serial/__init__.py +++ b/esphome/components/improv_serial/__init__.py @@ -22,7 +22,7 @@ CONFIG_SCHEMA = ( ) -def validate_logger(config): +def validate_logger(config) -> 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") @@ -33,7 +33,6 @@ def validate_logger(config): raise cv.Invalid( "improv_serial does not support the selected logger hardware_uart" ) - return config FINAL_VALIDATE_SCHEMA = validate_logger diff --git a/esphome/components/inkplate/display.py b/esphome/components/inkplate/display.py index 47c8c898e5..a0c0d5dc18 100644 --- a/esphome/components/inkplate/display.py +++ b/esphome/components/inkplate/display.py @@ -146,13 +146,12 @@ CONFIG_SCHEMA = cv.All( ) -def _validate_cpu_frequency(config): +def _validate_cpu_frequency(config) -> None: esp32_config = fv.full_config.get()[PLATFORM_ESP32] if esp32_config[CONF_CPU_FREQUENCY] != "240MHZ": raise cv.Invalid( "Inkplate requires 240MHz CPU frequency (set in esp32 component)" ) - return config FINAL_VALIDATE_SCHEMA = _validate_cpu_frequency diff --git a/esphome/components/it8951/display.py b/esphome/components/it8951/display.py index 51c5fc6118..bdc68b5257 100644 --- a/esphome/components/it8951/display.py +++ b/esphome/components/it8951/display.py @@ -336,7 +336,7 @@ def _customise_schema(config): CONFIG_SCHEMA = _customise_schema -def _final_validate(config): +def _final_validate(config) -> None: # IT8951 reads from SPI (DevInfo, VCOM, register reads) so MISO is required. spi.final_validate_device_schema("it8951", require_miso=True, require_mosi=True)( config @@ -351,7 +351,6 @@ def _final_validate(config): config[CONF_UPDATE_INTERVAL] = update_interval("never") else: config[CONF_SHOW_TEST_CARD] = True - return config FINAL_VALIDATE_SCHEMA = _final_validate diff --git a/esphome/components/kuntze/sensor.py b/esphome/components/kuntze/sensor.py index c11ede9db6..2b53e70756 100644 --- a/esphome/components/kuntze/sensor.py +++ b/esphome/components/kuntze/sensor.py @@ -89,8 +89,8 @@ CONFIG_SCHEMA = ( ) -def _final_validate(config: ConfigType) -> ConfigType: - return modbus.final_validate_modbus_device("kuntze", role="client")(config) +def _final_validate(config: ConfigType) -> None: + modbus.final_validate_modbus_device("kuntze", role="client")(config) FINAL_VALIDATE_SCHEMA = _final_validate diff --git a/esphome/components/ld6002b/button/__init__.py b/esphome/components/ld6002b/button/__init__.py index c327c331c6..508d5c2bc6 100644 --- a/esphome/components/ld6002b/button/__init__.py +++ b/esphome/components/ld6002b/button/__init__.py @@ -84,7 +84,7 @@ CONFIG_SCHEMA = cv.Schema( ) -def final_validate(config: ConfigType) -> ConfigType: +def final_validate(config: ConfigType) -> None: full_config = fv.full_config.get() hub_id = config[CONF_LD6002B_ID] @@ -108,8 +108,6 @@ def final_validate(config: ConfigType) -> ConfigType: path=[CONF_WAKE], ) - return config - FINAL_VALIDATE_SCHEMA = final_validate diff --git a/esphome/components/ld6002b/number/__init__.py b/esphome/components/ld6002b/number/__init__.py index 7e0be66c64..452e38d6e3 100644 --- a/esphome/components/ld6002b/number/__init__.py +++ b/esphome/components/ld6002b/number/__init__.py @@ -105,9 +105,9 @@ CONFIG_SCHEMA = cv.Schema( ) -def final_validate(config: ConfigType) -> ConfigType: +def final_validate(config: ConfigType) -> None: if config.get(CONF_AREA_CONFIG) is None: - return config + return full_config = fv.full_config.get() hub_id = config[CONF_LD6002B_ID] @@ -132,8 +132,6 @@ def final_validate(config: ConfigType) -> ConfigType: path=[CONF_AREA_CONFIG], ) - return config - FINAL_VALIDATE_SCHEMA = final_validate diff --git a/esphome/components/light/__init__.py b/esphome/components/light/__init__.py index 7c4d7ed431..b5b3d7c905 100644 --- a/esphome/components/light/__init__.py +++ b/esphome/components/light/__init__.py @@ -165,7 +165,7 @@ def available_effects_str(effects: list) -> str: return ", ".join(f"'{name}'" for name in available) if available else "none" -def _final_validate(config: ConfigType) -> ConfigType: +def _final_validate(config: ConfigType) -> None: """Validate all recorded effect name references against their target lights. This runs once per light platform instance. If no light platform is configured, @@ -173,7 +173,7 @@ def _final_validate(config: ConfigType) -> ConfigType: """ data = _get_data() if not data.effect_refs and not data.effect_cycle_refs: - return config + return # Drain the lists so we only validate once even though # FINAL_VALIDATE_SCHEMA runs for each light platform instance. @@ -217,8 +217,6 @@ def _final_validate(config: ConfigType) -> ConfigType: path=[cv.ROOT_CONFIG_PATH] + ref.component_path, ) - return config - FINAL_VALIDATE_SCHEMA = _final_validate diff --git a/esphome/components/mcp4461/output/__init__.py b/esphome/components/mcp4461/output/__init__.py index 1642f6149a..99d4988c90 100644 --- a/esphome/components/mcp4461/output/__init__.py +++ b/esphome/components/mcp4461/output/__init__.py @@ -34,7 +34,7 @@ CONF_NONVOLATILE_WRITE_DELAY = "nonvolatile_write_delay" VOLATILE_CHANNELS = ("A", "B", "C", "D") -def _validate_nonvolatile(config): +def _validate_nonvolatile(config) -> None: channel = str(config[CONF_CHANNEL]) # Channels E-H address the nonvolatile registers directly — the mirroring options only @@ -49,7 +49,7 @@ def _validate_nonvolatile(config): f"enabling '{CONF_NONVOLATILE}' or setting '{CONF_NONVOLATILE_WRITE_DELAY}' is only valid for the " f"volatile channels A-D; channels E-H are the nonvolatile registers themselves" ) - return config + return config.setdefault(CONF_NONVOLATILE, True) if config[CONF_NONVOLATILE]: @@ -62,7 +62,6 @@ def _validate_nonvolatile(config): raise cv.Invalid( f"'{CONF_NONVOLATILE_WRITE_DELAY}' requires '{CONF_NONVOLATILE}: true'" ) - return config CONFIG_SCHEMA = output.FLOAT_OUTPUT_SCHEMA.extend( diff --git a/esphome/components/mdns/__init__.py b/esphome/components/mdns/__init__.py index 2d4f6085e5..24bce0cc3c 100644 --- a/esphome/components/mdns/__init__.py +++ b/esphome/components/mdns/__init__.py @@ -62,7 +62,7 @@ def _consume_mdns_sockets(config: ConfigType) -> ConfigType: return config -def _require_network_interface(config: ConfigType) -> ConfigType: +def _require_network_interface(config: ConfigType) -> None: """Require a network interface for mDNS on Arduino/LEAmDNS platforms. On ESP8266 and RP2040 the C++ implementation needs at least one IP state @@ -71,7 +71,7 @@ def _require_network_interface(config: ConfigType) -> ConfigType: that never initializes. """ if config.get(CONF_DISABLED) or not (CORE.is_esp8266 or CORE.is_rp2): - return config + return full_config = fv.full_config.get() has_wifi = "wifi" in full_config has_ethernet = CORE.is_rp2 and "ethernet" in full_config @@ -81,7 +81,6 @@ def _require_network_interface(config: ConfigType) -> ConfigType: "mdns on this platform requires a network interface — " f"add a {options} component to your configuration." ) - return config CONFIG_SCHEMA = cv.All( diff --git a/esphome/components/mipi_dsi/display.py b/esphome/components/mipi_dsi/display.py index e5bb3d413d..8c125a9606 100644 --- a/esphome/components/mipi_dsi/display.py +++ b/esphome/components/mipi_dsi/display.py @@ -175,7 +175,7 @@ def _config_schema(config): return config -def _final_validate(config): +def _final_validate(config) -> None: global_config = full_config.get() from esphome.components.lvgl import DOMAIN as LVGL_DOMAIN @@ -183,7 +183,6 @@ def _final_validate(config): if not requires_buffer(config) and LVGL_DOMAIN not in global_config: # If no drawing methods are configured, and LVGL is not enabled, show a test card config[CONF_SHOW_TEST_CARD] = True - return config CONFIG_SCHEMA = _config_schema diff --git a/esphome/components/mipi_rgb/display.py b/esphome/components/mipi_rgb/display.py index ebe930d37a..897088a257 100644 --- a/esphome/components/mipi_rgb/display.py +++ b/esphome/components/mipi_rgb/display.py @@ -248,7 +248,7 @@ def _config_schema(config): CONFIG_SCHEMA = _config_schema -def _final_validate(config): +def _final_validate(config) -> None: global_config = full_config.get() from esphome.components.lvgl import DOMAIN as LVGL_DOMAIN @@ -260,7 +260,6 @@ def _final_validate(config): config = spi.final_validate_device_schema( "mipi_rgb", require_miso=False, require_mosi=True )(config) - return config FINAL_VALIDATE_SCHEMA = _final_validate diff --git a/esphome/components/mitsubishi_cn105/climate.py b/esphome/components/mitsubishi_cn105/climate.py index 64475d0e32..05a29b3665 100644 --- a/esphome/components/mitsubishi_cn105/climate.py +++ b/esphome/components/mitsubishi_cn105/climate.py @@ -143,11 +143,11 @@ def CONFIG_SCHEMA(config: ConfigType) -> ConfigType: # Legacy climate-owned hub compatibility. Remove in 2027.2.0. -def _legacy_final_validate(config: ConfigType) -> ConfigType: +def _legacy_final_validate(config: ConfigType) -> None: if CONF_MITSUBISHI_CN105_ID in config: - return config + return - return uart.final_validate_device_schema( + uart.final_validate_device_schema( DOMAIN, require_rx=True, require_tx=True, diff --git a/esphome/components/modbus_controller/__init__.py b/esphome/components/modbus_controller/__init__.py index 1ce1e38d16..f3cd28d138 100644 --- a/esphome/components/modbus_controller/__init__.py +++ b/esphome/components/modbus_controller/__init__.py @@ -135,10 +135,8 @@ def validate_modbus_register(config): return config -def _final_validate(config: ConfigType) -> ConfigType: - return modbus.final_validate_modbus_device("modbus_controller", role="client")( - config - ) +def _final_validate(config: ConfigType) -> None: + modbus.final_validate_modbus_device("modbus_controller", role="client")(config) FINAL_VALIDATE_SCHEMA = _final_validate diff --git a/esphome/components/modbus_server/__init__.py b/esphome/components/modbus_server/__init__.py index 16b956d7b5..249454b6b0 100644 --- a/esphome/components/modbus_server/__init__.py +++ b/esphome/components/modbus_server/__init__.py @@ -144,8 +144,8 @@ CONFIG_SCHEMA = cv.All( ) -def _final_validate(config: ConfigType) -> ConfigType: - return modbus.final_validate_modbus_device("modbus_server", role="server")(config) +def _final_validate(config: ConfigType) -> None: + modbus.final_validate_modbus_device("modbus_server", role="server")(config) FINAL_VALIDATE_SCHEMA = _final_validate diff --git a/esphome/components/packet_transport/binary_sensor.py b/esphome/components/packet_transport/binary_sensor.py index 09bbf91c99..3291ff2c59 100644 --- a/esphome/components/packet_transport/binary_sensor.py +++ b/esphome/components/packet_transport/binary_sensor.py @@ -44,10 +44,10 @@ CONFIG_SCHEMA = cv.typed_schema( ) -def _final_validate(config): +def _final_validate(config) -> None: if config[CONF_TYPE] != CONF_STATUS: # Only run this validation if a status sensor is being configured - return config + return full_config = fv.full_config.get() transport_path = full_config.get_path_for_id(config[CONF_TRANSPORT_ID])[:-1] transport_config = full_config.get_config_for_path(transport_path) @@ -56,7 +56,7 @@ def _final_validate(config): for p in transport_config[CONF_PROVIDERS] if p[CONF_NAME] == config[CONF_PROVIDER] ): - return config + return raise cv.Invalid( "Status sensor requires ping-pong to be enabled and the nominated provider to use encryption." ) diff --git a/esphome/components/provisioning/__init__.py b/esphome/components/provisioning/__init__.py index 36fa69357a..9462bbb3b7 100644 --- a/esphome/components/provisioning/__init__.py +++ b/esphome/components/provisioning/__init__.py @@ -67,7 +67,7 @@ CONFIG_SCHEMA = cv.Schema( ).extend(cv.COMPONENT_SCHEMA) -def _final_validate(config: ConfigType) -> ConfigType: +def _final_validate(config: ConfigType) -> None: """Validate the provisioning setup once every component has been processed. Sources register during their own config validation, so by final validation @@ -89,7 +89,6 @@ def _final_validate(config: ConfigType) -> ConfigType: "hardcoding them makes the window pointless.", ", ".join(sorted(data.hardcoded_credentials)), ) - return config FINAL_VALIDATE_SCHEMA = _final_validate diff --git a/esphome/components/pzemac/sensor.py b/esphome/components/pzemac/sensor.py index 4e228f6aa3..5bb734cb2d 100644 --- a/esphome/components/pzemac/sensor.py +++ b/esphome/components/pzemac/sensor.py @@ -98,8 +98,8 @@ async def reset_energy_to_code(config, action_id, template_arg, args): return cg.new_Pvariable(action_id, template_arg, paren) -def _final_validate(config: ConfigType) -> ConfigType: - return modbus.final_validate_modbus_device("pzemac", role="client")(config) +def _final_validate(config: ConfigType) -> None: + modbus.final_validate_modbus_device("pzemac", role="client")(config) FINAL_VALIDATE_SCHEMA = _final_validate diff --git a/esphome/components/pzemdc/sensor.py b/esphome/components/pzemdc/sensor.py index 40cfe7b08a..b2c7c3a29d 100644 --- a/esphome/components/pzemdc/sensor.py +++ b/esphome/components/pzemdc/sensor.py @@ -80,8 +80,8 @@ async def reset_energy_to_code(config, action_id, template_arg, args): return cg.new_Pvariable(action_id, template_arg, paren) -def _final_validate(config: ConfigType) -> ConfigType: - return modbus.final_validate_modbus_device("pzemdc", role="client")(config) +def _final_validate(config: ConfigType) -> None: + modbus.final_validate_modbus_device("pzemdc", role="client")(config) FINAL_VALIDATE_SCHEMA = _final_validate diff --git a/esphome/components/router/speaker/__init__.py b/esphome/components/router/speaker/__init__.py index 2b2dc56433..18311416c3 100644 --- a/esphome/components/router/speaker/__init__.py +++ b/esphome/components/router/speaker/__init__.py @@ -63,7 +63,7 @@ CONFIG_SCHEMA = cv.All( ) -def _final_validate(config: ConfigType) -> ConfigType: +def _final_validate(config: ConfigType) -> None: # Validate every configured output speaker can accept the router's format. # Switching to an output that can't reproduce the format the producer is # already sending would otherwise fail silently at runtime. @@ -76,7 +76,6 @@ def _final_validate(config: ConfigType) -> ConfigType: channels=config[CONF_NUM_CHANNELS], sample_rate=config[CONF_SAMPLE_RATE], )(proxy) - return config FINAL_VALIDATE_SCHEMA = _final_validate diff --git a/esphome/components/rp2040_ble/__init__.py b/esphome/components/rp2040_ble/__init__.py index 332ea73a61..d2a08e9fc0 100644 --- a/esphome/components/rp2040_ble/__init__.py +++ b/esphome/components/rp2040_ble/__init__.py @@ -71,10 +71,9 @@ def validate_connection_slots() -> None: ) -def _final_validate(config: ConfigType) -> ConfigType: +def _final_validate(config: ConfigType) -> None: _validate_board(config) validate_connection_slots() - return config FINAL_VALIDATE_SCHEMA = _final_validate diff --git a/esphome/components/sdm_meter/sensor.py b/esphome/components/sdm_meter/sensor.py index 46f5025080..125240e891 100644 --- a/esphome/components/sdm_meter/sensor.py +++ b/esphome/components/sdm_meter/sensor.py @@ -148,8 +148,8 @@ CONFIG_SCHEMA = ( ) -def _final_validate(config: ConfigType) -> ConfigType: - return modbus.final_validate_modbus_device("sdm_meter", role="client")(config) +def _final_validate(config: ConfigType) -> None: + modbus.final_validate_modbus_device("sdm_meter", role="client")(config) FINAL_VALIDATE_SCHEMA = _final_validate diff --git a/esphome/components/sds011/sensor.py b/esphome/components/sds011/sensor.py index 2d7b6b07e5..59ee6667a1 100644 --- a/esphome/components/sds011/sensor.py +++ b/esphome/components/sds011/sensor.py @@ -63,7 +63,7 @@ CONFIG_SCHEMA = cv.All( ) -def _final_validate(config): +def _final_validate(config) -> 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( @@ -75,7 +75,6 @@ def _final_validate(config): parity="NONE", stop_bits=1, )(config) - return config FINAL_VALIDATE_SCHEMA = _final_validate diff --git a/esphome/components/selec_meter/sensor.py b/esphome/components/selec_meter/sensor.py index ef4929c375..120b997605 100644 --- a/esphome/components/selec_meter/sensor.py +++ b/esphome/components/selec_meter/sensor.py @@ -164,8 +164,8 @@ CONFIG_SCHEMA = ( ) -def _final_validate(config: ConfigType) -> ConfigType: - return modbus.final_validate_modbus_device("selec_meter", role="client")(config) +def _final_validate(config: ConfigType) -> None: + modbus.final_validate_modbus_device("selec_meter", role="client")(config) FINAL_VALIDATE_SCHEMA = _final_validate diff --git a/esphome/components/tinyusb/__init__.py b/esphome/components/tinyusb/__init__.py index 9e1ad3afc4..4c6f4db85b 100644 --- a/esphome/components/tinyusb/__init__.py +++ b/esphome/components/tinyusb/__init__.py @@ -57,7 +57,7 @@ CONFIG_SCHEMA = cv.All( ) -def _final_validate(config): +def _final_validate(config) -> None: full_config = fv.full_config.get() if not any(name in full_config for name in _USB_CLASS_COMPONENTS): raise cv.Invalid( @@ -75,7 +75,6 @@ def _final_validate(config): "USB_SERIAL_JTAG on variants that support it " "(ESP32-S3, ESP32-S31, ESP32-P4, ESP32-H4)" ) - return config FINAL_VALIDATE_SCHEMA = _final_validate diff --git a/esphome/components/web_server/__init__.py b/esphome/components/web_server/__init__.py index c1887cc3fc..b2c0ea14ad 100644 --- a/esphome/components/web_server/__init__.py +++ b/esphome/components/web_server/__init__.py @@ -193,7 +193,7 @@ def _validate_no_sorting_component( ) -def _final_validate_sorting(config: ConfigType) -> ConfigType: +def _final_validate_sorting(config: ConfigType) -> None: if (webserver_version := config.get(CONF_VERSION)) != 3: _validate_no_sorting_component( CONF_SORTING_WEIGHT, webserver_version, fv.full_config.get() @@ -201,7 +201,6 @@ def _final_validate_sorting(config: ConfigType) -> ConfigType: _validate_no_sorting_component( CONF_SORTING_GROUP_ID, webserver_version, fv.full_config.get() ) - return config FINAL_VALIDATE_SCHEMA = _final_validate_sorting diff --git a/esphome/components/zephyr_pwm/output.py b/esphome/components/zephyr_pwm/output.py index 54c04473e3..b7ee27f63c 100644 --- a/esphome/components/zephyr_pwm/output.py +++ b/esphome/components/zephyr_pwm/output.py @@ -102,9 +102,8 @@ def _allocate_blocks() -> None: _get_data().pwm_blocks = pwm_blocks -def _final_validate(config: ConfigType) -> ConfigType: +def _final_validate(config: ConfigType) -> None: _allocate_blocks() - return config FINAL_VALIDATE_SCHEMA = _final_validate diff --git a/esphome/components/zwave_proxy/__init__.py b/esphome/components/zwave_proxy/__init__.py index d88f9f7041..14b8474045 100644 --- a/esphome/components/zwave_proxy/__init__.py +++ b/esphome/components/zwave_proxy/__init__.py @@ -11,7 +11,7 @@ zwave_proxy_ns = cg.esphome_ns.namespace("zwave_proxy") ZWaveProxy = zwave_proxy_ns.class_("ZWaveProxy", cg.Component, uart.UARTDevice) -def final_validate(config): +def final_validate(config) -> 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" @@ -20,8 +20,6 @@ def final_validate(config): f"{CONF_WIFI} {CONF_POWER_SAVE_MODE} must be set to 'none' when using Z-Wave proxy" ) - return config - CONFIG_SCHEMA = ( cv.Schema( diff --git a/tests/component_tests/esp32_hosted/test_init.py b/tests/component_tests/esp32_hosted/test_init.py index cec81e4e83..5cc3f928cc 100644 --- a/tests/component_tests/esp32_hosted/test_init.py +++ b/tests/component_tests/esp32_hosted/test_init.py @@ -19,7 +19,7 @@ def test_final_validate_accepts_supported_idf( PlatformFramework.ESP32_IDF, platform_data={KEY_IDF_VERSION: cv.Version.parse(idf)}, ) - assert _final_validate({}) == {} + _final_validate({}) @pytest.mark.parametrize("idf", ["5.0.0", "5.2.2"]) diff --git a/tests/component_tests/image/test_init.py b/tests/component_tests/image/test_init.py index 78462463b1..f52c477c85 100644 --- a/tests/component_tests/image/test_init.py +++ b/tests/component_tests/image/test_init.py @@ -371,27 +371,28 @@ def test_migrate_returns_none_for_invalid_legacy_shapes( def test_validate_image_final_defaults_to_little_endian() -> None: - out = validate_image_final({CONF_FILE: "x.png"}) - assert out[CONF_BYTE_ORDER] == "LITTLE_ENDIAN" + config = {CONF_FILE: "x.png"} + validate_image_final(config) + assert config[CONF_BYTE_ORDER] == "LITTLE_ENDIAN" def test_validate_image_final_keeps_little_endian( caplog: pytest.LogCaptureFixture, ) -> None: + config = {CONF_FILE: "x.png", CONF_BYTE_ORDER: "LITTLE_ENDIAN"} with caplog.at_level(logging.WARNING): - out = validate_image_final( - {CONF_FILE: "x.png", CONF_BYTE_ORDER: "LITTLE_ENDIAN"} - ) - assert out[CONF_BYTE_ORDER] == "LITTLE_ENDIAN" + validate_image_final(config) + assert config[CONF_BYTE_ORDER] == "LITTLE_ENDIAN" assert "big-endian" not in caplog.text def test_validate_image_final_warns_on_big_endian( caplog: pytest.LogCaptureFixture, ) -> None: + config = {CONF_FILE: "x.png", CONF_BYTE_ORDER: "BIG_ENDIAN"} with caplog.at_level(logging.WARNING): - out = validate_image_final({CONF_FILE: "x.png", CONF_BYTE_ORDER: "BIG_ENDIAN"}) - assert out[CONF_BYTE_ORDER] == "BIG_ENDIAN" + validate_image_final(config) + assert config[CONF_BYTE_ORDER] == "BIG_ENDIAN" assert "big-endian" in caplog.text diff --git a/tests/component_tests/provisioning/test_provisioning.py b/tests/component_tests/provisioning/test_provisioning.py index 07f5065241..d3a3771bbc 100644 --- a/tests/component_tests/provisioning/test_provisioning.py +++ b/tests/component_tests/provisioning/test_provisioning.py @@ -37,7 +37,7 @@ def test_provisioning_accepts_a_registered_source( set_core_config(PlatformFramework.ESP32_IDF) register_source("network") # Should not raise. - assert FINAL_VALIDATE_SCHEMA({}) == {} + FINAL_VALIDATE_SCHEMA({}) def test_provisioning_warns_on_hardcoded_credentials( @@ -49,7 +49,7 @@ def test_provisioning_warns_on_hardcoded_credentials( register_source("network") report_hardcoded_credentials("wifi") with caplog.at_level(logging.WARNING): - assert FINAL_VALIDATE_SCHEMA({}) == {} + FINAL_VALIDATE_SCHEMA({}) assert "wifi" in caplog.text assert "credentials" in caplog.text @@ -62,7 +62,7 @@ def test_provisioning_no_warning_without_hardcoded_credentials( set_core_config(PlatformFramework.ESP32_IDF) register_source("network") with caplog.at_level(logging.WARNING): - assert FINAL_VALIDATE_SCHEMA({}) == {} + FINAL_VALIDATE_SCHEMA({}) assert "credentials" not in caplog.text