From b110cee973ed230f9270a93f4506aaf8dbb94a9f Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Wed, 2 Sep 2026 12:18:32 +0200 Subject: [PATCH] Keep the platform level error message alongside the socket implementation check --- esphome/components/api/__init__.py | 14 ++++++++++---- .../api/test_outgoing_connection.py | 15 +++++---------- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/esphome/components/api/__init__.py b/esphome/components/api/__init__.py index 1ea06d980e..545013fdec 100644 --- a/esphome/components/api/__init__.py +++ b/esphome/components/api/__init__.py @@ -295,11 +295,17 @@ def _consume_api_sockets(config: ConfigType) -> ConfigType: def _validate_outgoing_connection(config: ConfigType) -> ConfigType: - # The socket-layer constraint (raw lwip_tcp cannot dial out, the default - # on esp8266/rp2040) is checked against the resolved implementation in - # _validate_outgoing_socket_implementation at final validate if CONF_OUTGOING_CONNECTION not in config: return config + # Platform default check here for a friendly early error; an explicit + # lwip_tcp selection on other platforms is caught against the resolved + # implementation in _validate_outgoing_socket_implementation + if CORE.is_esp8266 or CORE.is_rp2: + raise cv.Invalid( + "outgoing_connection is not supported on this platform because its " + "socket layer cannot make outgoing connections", + path=[CONF_OUTGOING_CONNECTION], + ) if CONF_ENCRYPTION not in config: raise cv.Invalid( "outgoing_connection requires 'encryption' so the peer is verified by key", @@ -472,7 +478,7 @@ def _validate_outgoing_socket_implementation(config: ConfigType) -> ConfigType: def _validate_outgoing_host_ipv6(config: ConfigType) -> ConfigType: - """An IPv6 host silently dials 255.255.255.255 on a build without IPv6.""" + """An IPv6 host can never be parsed, so never dialed, without IPv6.""" if ( (outgoing := config.get(CONF_OUTGOING_CONNECTION)) is None or (host := outgoing.get(CONF_HOST)) is None diff --git a/tests/component_tests/api/test_outgoing_connection.py b/tests/component_tests/api/test_outgoing_connection.py index 51d3efc5dc..780adf2ac6 100644 --- a/tests/component_tests/api/test_outgoing_connection.py +++ b/tests/component_tests/api/test_outgoing_connection.py @@ -67,20 +67,15 @@ def test_outgoing_connection_rejected_on_raw_lwip_platforms( set_core_config: SetCoreConfigCallable, platform_framework: PlatformFramework, ) -> None: - """esp8266 and rp2040 default to lwip_tcp and are rejected at final validate.""" - set_core_config( - platform_framework, - full_config={"socket": {"implementation": "lwip_tcp"}}, - ) - config = CONFIG_SCHEMA(_api_config({"host": "192.168.1.2"})) - with pytest.raises(cv.Invalid, match="lwip_tcp"): - _validate_outgoing_socket_implementation(config) + set_core_config(platform_framework) + with pytest.raises(cv.Invalid, match="not supported on this platform"): + CONFIG_SCHEMA(_api_config({"host": "192.168.1.2"})) -def test_outgoing_connection_rejects_lwip_tcp_socket( +def test_outgoing_connection_rejects_lwip_tcp_selected_on_esp32( set_core_config: SetCoreConfigCallable, ) -> None: - """An explicit lwip_tcp socket selection is rejected at final validate.""" + """An explicit lwip_tcp selection is caught at final validate.""" set_core_config( PlatformFramework.ESP32_IDF, platform_data=ESP32_PLATFORM_DATA,