mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-31 07:03:55 +00:00 
			
		
		
		
	Merge branch 'lwip_locking_fix' into integration
This commit is contained in:
		| @@ -11,6 +11,15 @@ namespace esphome { | |||||||
| namespace api { | namespace api { | ||||||
|  |  | ||||||
| template<typename... X> class TemplatableStringValue : public TemplatableValue<std::string, X...> { | template<typename... X> class TemplatableStringValue : public TemplatableValue<std::string, X...> { | ||||||
|  |  private: | ||||||
|  |   // Helper to convert value to string - handles the case where value is already a string | ||||||
|  |   template<typename T> static std::string value_to_string(T &&val) { return to_string(std::forward<T>(val)); } | ||||||
|  |  | ||||||
|  |   // Overloads for string types - needed because std::to_string doesn't support them | ||||||
|  |   static std::string value_to_string(const char *val) { return std::string(val); }  // For lambdas returning .c_str() | ||||||
|  |   static std::string value_to_string(const std::string &val) { return val; } | ||||||
|  |   static std::string value_to_string(std::string &&val) { return std::move(val); } | ||||||
|  |  | ||||||
|  public: |  public: | ||||||
|   TemplatableStringValue() : TemplatableValue<std::string, X...>() {} |   TemplatableStringValue() : TemplatableValue<std::string, X...>() {} | ||||||
|  |  | ||||||
| @@ -19,7 +28,7 @@ template<typename... X> class TemplatableStringValue : public TemplatableValue<s | |||||||
|  |  | ||||||
|   template<typename F, enable_if_t<is_invocable<F, X...>::value, int> = 0> |   template<typename F, enable_if_t<is_invocable<F, X...>::value, int> = 0> | ||||||
|   TemplatableStringValue(F f) |   TemplatableStringValue(F f) | ||||||
|       : TemplatableValue<std::string, X...>([f](X... x) -> std::string { return to_string(f(x...)); }) {} |       : TemplatableValue<std::string, X...>([f](X... x) -> std::string { return value_to_string(f(x...)); }) {} | ||||||
| }; | }; | ||||||
|  |  | ||||||
| template<typename... Ts> class TemplatableKeyValuePair { | template<typename... Ts> class TemplatableKeyValuePair { | ||||||
|   | |||||||
| @@ -309,19 +309,19 @@ def _format_framework_espidf_version( | |||||||
|  |  | ||||||
| # The default/recommended arduino framework version | # The default/recommended arduino framework version | ||||||
| #  - https://github.com/espressif/arduino-esp32/releases | #  - https://github.com/espressif/arduino-esp32/releases | ||||||
| RECOMMENDED_ARDUINO_FRAMEWORK_VERSION = cv.Version(3, 2, 1) | RECOMMENDED_ARDUINO_FRAMEWORK_VERSION = cv.Version(3, 1, 3) | ||||||
| # The platform-espressif32 version to use for arduino frameworks | # The platform-espressif32 version to use for arduino frameworks | ||||||
| #  - https://github.com/pioarduino/platform-espressif32/releases | #  - https://github.com/pioarduino/platform-espressif32/releases | ||||||
| ARDUINO_PLATFORM_VERSION = cv.Version(54, 3, 21) | ARDUINO_PLATFORM_VERSION = cv.Version(53, 3, 13) | ||||||
|  |  | ||||||
| # The default/recommended esp-idf framework version | # The default/recommended esp-idf framework version | ||||||
| #  - https://github.com/espressif/esp-idf/releases | #  - https://github.com/espressif/esp-idf/releases | ||||||
| #  - https://api.registry.platformio.org/v3/packages/platformio/tool/framework-espidf | #  - https://api.registry.platformio.org/v3/packages/platformio/tool/framework-espidf | ||||||
| RECOMMENDED_ESP_IDF_FRAMEWORK_VERSION = cv.Version(5, 4, 2) | RECOMMENDED_ESP_IDF_FRAMEWORK_VERSION = cv.Version(5, 3, 2) | ||||||
| # The platformio/espressif32 version to use for esp-idf frameworks | # The platformio/espressif32 version to use for esp-idf frameworks | ||||||
| #  - https://github.com/platformio/platform-espressif32/releases | #  - https://github.com/platformio/platform-espressif32/releases | ||||||
| #  - https://api.registry.platformio.org/v3/packages/platformio/platform/espressif32 | #  - https://api.registry.platformio.org/v3/packages/platformio/platform/espressif32 | ||||||
| ESP_IDF_PLATFORM_VERSION = cv.Version(54, 3, 21) | ESP_IDF_PLATFORM_VERSION = cv.Version(53, 3, 13) | ||||||
|  |  | ||||||
| # List based on https://registry.platformio.org/tools/platformio/framework-espidf/versions | # List based on https://registry.platformio.org/tools/platformio/framework-espidf/versions | ||||||
| SUPPORTED_PLATFORMIO_ESP_IDF_5X = [ | SUPPORTED_PLATFORMIO_ESP_IDF_5X = [ | ||||||
| @@ -356,8 +356,8 @@ SUPPORTED_PIOARDUINO_ESP_IDF_5X = [ | |||||||
| def _arduino_check_versions(value): | def _arduino_check_versions(value): | ||||||
|     value = value.copy() |     value = value.copy() | ||||||
|     lookups = { |     lookups = { | ||||||
|         "dev": (cv.Version(3, 2, 1), "https://github.com/espressif/arduino-esp32.git"), |         "dev": (cv.Version(3, 1, 3), "https://github.com/espressif/arduino-esp32.git"), | ||||||
|         "latest": (cv.Version(3, 2, 1), None), |         "latest": (cv.Version(3, 1, 3), None), | ||||||
|         "recommended": (RECOMMENDED_ARDUINO_FRAMEWORK_VERSION, None), |         "recommended": (RECOMMENDED_ARDUINO_FRAMEWORK_VERSION, None), | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -395,8 +395,8 @@ def _arduino_check_versions(value): | |||||||
| def _esp_idf_check_versions(value): | def _esp_idf_check_versions(value): | ||||||
|     value = value.copy() |     value = value.copy() | ||||||
|     lookups = { |     lookups = { | ||||||
|         "dev": (cv.Version(5, 4, 2), "https://github.com/espressif/esp-idf.git"), |         "dev": (cv.Version(5, 3, 2), "https://github.com/espressif/esp-idf.git"), | ||||||
|         "latest": (cv.Version(5, 2, 2), None), |         "latest": (cv.Version(5, 3, 2), None), | ||||||
|         "recommended": (RECOMMENDED_ESP_IDF_FRAMEWORK_VERSION, None), |         "recommended": (RECOMMENDED_ESP_IDF_FRAMEWORK_VERSION, None), | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -39,15 +39,14 @@ LwIPLock::LwIPLock() { | |||||||
|   // Only lock if we're not already in the TCPIP thread |   // Only lock if we're not already in the TCPIP thread | ||||||
|   if (!sys_thread_tcpip(LWIP_CORE_LOCK_QUERY_HOLDER)) { |   if (!sys_thread_tcpip(LWIP_CORE_LOCK_QUERY_HOLDER)) { | ||||||
|     LOCK_TCPIP_CORE(); |     LOCK_TCPIP_CORE(); | ||||||
|     locked_ = true; |  | ||||||
|   } |   } | ||||||
| #endif | #endif | ||||||
| } | } | ||||||
|  |  | ||||||
| LwIPLock::~LwIPLock() { | LwIPLock::~LwIPLock() { | ||||||
| #ifdef CONFIG_LWIP_TCPIP_CORE_LOCKING | #ifdef CONFIG_LWIP_TCPIP_CORE_LOCKING | ||||||
|   // Only unlock if we locked it |   // Only unlock if we hold the lock | ||||||
|   if (locked_ && sys_thread_tcpip(LWIP_CORE_LOCK_QUERY_HOLDER)) { |   if (sys_thread_tcpip(LWIP_CORE_LOCK_QUERY_HOLDER)) { | ||||||
|     UNLOCK_TCPIP_CORE(); |     UNLOCK_TCPIP_CORE(); | ||||||
|   } |   } | ||||||
| #endif | #endif | ||||||
|   | |||||||
| @@ -25,9 +25,6 @@ | |||||||
| #include "driver/gpio.h" | #include "driver/gpio.h" | ||||||
| #include "esp_rom_gpio.h" | #include "esp_rom_gpio.h" | ||||||
| #include "esp_rom_sys.h" | #include "esp_rom_sys.h" | ||||||
| #include "esp_idf_version.h" |  | ||||||
|  |  | ||||||
| #if defined(USE_ARDUINO) || ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 4, 2) |  | ||||||
|  |  | ||||||
| static const char *TAG = "jl1101"; | static const char *TAG = "jl1101"; | ||||||
| #define PHY_CHECK(a, str, goto_tag, ...) \ | #define PHY_CHECK(a, str, goto_tag, ...) \ | ||||||
| @@ -339,6 +336,4 @@ esp_eth_phy_t *esp_eth_phy_new_jl1101(const eth_phy_config_t *config) { | |||||||
| err: | err: | ||||||
|   return NULL; |   return NULL; | ||||||
| } | } | ||||||
|  |  | ||||||
| #endif /* USE_ARDUINO */ |  | ||||||
| #endif /* USE_ESP32 */ | #endif /* USE_ESP32 */ | ||||||
|   | |||||||
| @@ -11,7 +11,6 @@ | |||||||
| #include "esp_eth_mac.h" | #include "esp_eth_mac.h" | ||||||
| #include "esp_netif.h" | #include "esp_netif.h" | ||||||
| #include "esp_mac.h" | #include "esp_mac.h" | ||||||
| #include "esp_idf_version.h" |  | ||||||
|  |  | ||||||
| namespace esphome { | namespace esphome { | ||||||
| namespace ethernet { | namespace ethernet { | ||||||
| @@ -154,10 +153,7 @@ class EthernetComponent : public Component { | |||||||
|  |  | ||||||
| // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) | // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) | ||||||
| extern EthernetComponent *global_eth_component; | extern EthernetComponent *global_eth_component; | ||||||
|  |  | ||||||
| #if defined(USE_ARDUINO) || ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 4, 2) |  | ||||||
| extern "C" esp_eth_phy_t *esp_eth_phy_new_jl1101(const eth_phy_config_t *config); | extern "C" esp_eth_phy_t *esp_eth_phy_new_jl1101(const eth_phy_config_t *config); | ||||||
| #endif |  | ||||||
|  |  | ||||||
| }  // namespace ethernet | }  // namespace ethernet | ||||||
| }  // namespace esphome | }  // namespace esphome | ||||||
|   | |||||||
| @@ -3,6 +3,7 @@ import esphome.codegen as cg | |||||||
| from esphome.components import i2c, sensirion_common, sensor | from esphome.components import i2c, sensirion_common, sensor | ||||||
| import esphome.config_validation as cv | import esphome.config_validation as cv | ||||||
| from esphome.const import ( | from esphome.const import ( | ||||||
|  |     CONF_ALTITUDE_COMPENSATION, | ||||||
|     CONF_AMBIENT_PRESSURE_COMPENSATION, |     CONF_AMBIENT_PRESSURE_COMPENSATION, | ||||||
|     CONF_AUTOMATIC_SELF_CALIBRATION, |     CONF_AUTOMATIC_SELF_CALIBRATION, | ||||||
|     CONF_CO2, |     CONF_CO2, | ||||||
| @@ -35,8 +36,6 @@ ForceRecalibrationWithReference = scd30_ns.class_( | |||||||
|     "ForceRecalibrationWithReference", automation.Action |     "ForceRecalibrationWithReference", automation.Action | ||||||
| ) | ) | ||||||
|  |  | ||||||
| CONF_ALTITUDE_COMPENSATION = "altitude_compensation" |  | ||||||
|  |  | ||||||
| CONFIG_SCHEMA = ( | CONFIG_SCHEMA = ( | ||||||
|     cv.Schema( |     cv.Schema( | ||||||
|         { |         { | ||||||
|   | |||||||
| @@ -4,6 +4,7 @@ import esphome.codegen as cg | |||||||
| from esphome.components import i2c, sensirion_common, sensor | from esphome.components import i2c, sensirion_common, sensor | ||||||
| import esphome.config_validation as cv | import esphome.config_validation as cv | ||||||
| from esphome.const import ( | from esphome.const import ( | ||||||
|  |     CONF_ALTITUDE_COMPENSATION, | ||||||
|     CONF_AMBIENT_PRESSURE_COMPENSATION, |     CONF_AMBIENT_PRESSURE_COMPENSATION, | ||||||
|     CONF_AMBIENT_PRESSURE_COMPENSATION_SOURCE, |     CONF_AMBIENT_PRESSURE_COMPENSATION_SOURCE, | ||||||
|     CONF_AUTOMATIC_SELF_CALIBRATION, |     CONF_AUTOMATIC_SELF_CALIBRATION, | ||||||
| @@ -49,9 +50,6 @@ PerformForcedCalibrationAction = scd4x_ns.class_( | |||||||
| ) | ) | ||||||
| FactoryResetAction = scd4x_ns.class_("FactoryResetAction", automation.Action) | FactoryResetAction = scd4x_ns.class_("FactoryResetAction", automation.Action) | ||||||
|  |  | ||||||
|  |  | ||||||
| CONF_ALTITUDE_COMPENSATION = "altitude_compensation" |  | ||||||
|  |  | ||||||
| CONFIG_SCHEMA = ( | CONFIG_SCHEMA = ( | ||||||
|     cv.Schema( |     cv.Schema( | ||||||
|         { |         { | ||||||
|   | |||||||
| @@ -96,6 +96,7 @@ CONF_ALL = "all" | |||||||
| CONF_ALLOW_OTHER_USES = "allow_other_uses" | CONF_ALLOW_OTHER_USES = "allow_other_uses" | ||||||
| CONF_ALPHA = "alpha" | CONF_ALPHA = "alpha" | ||||||
| CONF_ALTITUDE = "altitude" | CONF_ALTITUDE = "altitude" | ||||||
|  | CONF_ALTITUDE_COMPENSATION = "altitude_compensation" | ||||||
| CONF_AMBIENT_LIGHT = "ambient_light" | CONF_AMBIENT_LIGHT = "ambient_light" | ||||||
| CONF_AMBIENT_PRESSURE_COMPENSATION = "ambient_pressure_compensation" | CONF_AMBIENT_PRESSURE_COMPENSATION = "ambient_pressure_compensation" | ||||||
| CONF_AMBIENT_PRESSURE_COMPENSATION_SOURCE = "ambient_pressure_compensation_source" | CONF_AMBIENT_PRESSURE_COMPENSATION_SOURCE = "ambient_pressure_compensation_source" | ||||||
|   | |||||||
| @@ -163,11 +163,12 @@ | |||||||
| #define USE_WIFI_11KV_SUPPORT | #define USE_WIFI_11KV_SUPPORT | ||||||
|  |  | ||||||
| #ifdef USE_ARDUINO | #ifdef USE_ARDUINO | ||||||
| #define USE_ARDUINO_VERSION_CODE VERSION_CODE(3, 2, 1) | #define USE_ARDUINO_VERSION_CODE VERSION_CODE(3, 1, 3) | ||||||
| #define USE_ETHERNET | #define USE_ETHERNET | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| #ifdef USE_ESP_IDF | #ifdef USE_ESP_IDF | ||||||
|  | #define USE_ESP_IDF_VERSION_CODE VERSION_CODE(5, 3, 2) | ||||||
| #define USE_MICRO_WAKE_WORD | #define USE_MICRO_WAKE_WORD | ||||||
| #define USE_MICRO_WAKE_WORD_VAD | #define USE_MICRO_WAKE_WORD_VAD | ||||||
| #if defined(USE_ESP32_VARIANT_ESP32C6) || defined(USE_ESP32_VARIANT_ESP32H2) | #if defined(USE_ESP32_VARIANT_ESP32C6) || defined(USE_ESP32_VARIANT_ESP32H2) | ||||||
|   | |||||||
| @@ -695,11 +695,6 @@ class LwIPLock { | |||||||
|  public: |  public: | ||||||
|   LwIPLock(); |   LwIPLock(); | ||||||
|   ~LwIPLock(); |   ~LwIPLock(); | ||||||
|  |  | ||||||
|  protected: |  | ||||||
| #if defined(USE_ESP32) |  | ||||||
|   bool locked_{false}; |  | ||||||
| #endif |  | ||||||
| }; | }; | ||||||
|  |  | ||||||
| /** Helper class to request `loop()` to be called as fast as possible. | /** Helper class to request `loop()` to be called as fast as possible. | ||||||
|   | |||||||
| @@ -125,9 +125,9 @@ extra_scripts = post:esphome/components/esp8266/post_build.py.script | |||||||
| ; This are common settings for the ESP32 (all variants) using Arduino. | ; This are common settings for the ESP32 (all variants) using Arduino. | ||||||
| [common:esp32-arduino] | [common:esp32-arduino] | ||||||
| extends = common:arduino | extends = common:arduino | ||||||
| platform = https://github.com/pioarduino/platform-espressif32/releases/download/54.03.21/platform-espressif32.zip | platform = https://github.com/pioarduino/platform-espressif32/releases/download/53.03.13/platform-espressif32.zip | ||||||
| platform_packages = | platform_packages = | ||||||
|     pioarduino/framework-arduinoespressif32@https://github.com/espressif/arduino-esp32/releases/download/3.2.1/esp32-3.2.1.zip |     pioarduino/framework-arduinoespressif32@https://github.com/espressif/arduino-esp32/releases/download/3.1.3/esp32-3.1.3.zip | ||||||
|  |  | ||||||
| framework = arduino | framework = arduino | ||||||
| lib_deps = | lib_deps = | ||||||
| @@ -161,9 +161,9 @@ extra_scripts = post:esphome/components/esp32/post_build.py.script | |||||||
| ; This are common settings for the ESP32 (all variants) using IDF. | ; This are common settings for the ESP32 (all variants) using IDF. | ||||||
| [common:esp32-idf] | [common:esp32-idf] | ||||||
| extends = common:idf | extends = common:idf | ||||||
| platform = https://github.com/pioarduino/platform-espressif32/releases/download/54.03.21/platform-espressif32.zip | platform = https://github.com/pioarduino/platform-espressif32/releases/download/53.03.13/platform-espressif32.zip | ||||||
| platform_packages = | platform_packages = | ||||||
|     pioarduino/framework-espidf@https://github.com/pioarduino/esp-idf/releases/download/v5.4.2/esp-idf-v5.4.2.zip |     pioarduino/framework-espidf@https://github.com/pioarduino/esp-idf/releases/download/v5.3.2/esp-idf-v5.3.2.zip | ||||||
|  |  | ||||||
| framework = espidf | framework = espidf | ||||||
| lib_deps = | lib_deps = | ||||||
|   | |||||||
							
								
								
									
										64
									
								
								tests/integration/fixtures/api_string_lambda.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								tests/integration/fixtures/api_string_lambda.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,64 @@ | |||||||
|  | esphome: | ||||||
|  |   name: api-string-lambda-test | ||||||
|  | host: | ||||||
|  |  | ||||||
|  | api: | ||||||
|  |   actions: | ||||||
|  |     # Service that tests string lambda functionality | ||||||
|  |     - action: test_string_lambda | ||||||
|  |       variables: | ||||||
|  |         input_string: string | ||||||
|  |       then: | ||||||
|  |         # Log the input to verify service was called | ||||||
|  |         - logger.log: | ||||||
|  |             format: "Service called with string: %s" | ||||||
|  |             args: [input_string.c_str()] | ||||||
|  |  | ||||||
|  |         # This is the key test - using a lambda that returns x.c_str() | ||||||
|  |         # where x is already a string. This would fail to compile in 2025.7.0b5 | ||||||
|  |         # with "no matching function for call to 'to_string(std::string)'" | ||||||
|  |         # This is the exact case from issue #9539 | ||||||
|  |         - homeassistant.tag_scanned: !lambda 'return input_string.c_str();' | ||||||
|  |  | ||||||
|  |         # Also test with homeassistant.event to verify our fix works with data fields | ||||||
|  |         - homeassistant.event: | ||||||
|  |             event: esphome.test_string_lambda | ||||||
|  |             data: | ||||||
|  |               value: !lambda 'return input_string.c_str();' | ||||||
|  |  | ||||||
|  |     # Service that tests int lambda functionality | ||||||
|  |     - action: test_int_lambda | ||||||
|  |       variables: | ||||||
|  |         input_number: int | ||||||
|  |       then: | ||||||
|  |         # Log the input to verify service was called | ||||||
|  |         - logger.log: | ||||||
|  |             format: "Service called with int: %d" | ||||||
|  |             args: [input_number] | ||||||
|  |  | ||||||
|  |         # Test that int lambdas still work correctly with to_string | ||||||
|  |         # The TemplatableStringValue should automatically convert int to string | ||||||
|  |         - homeassistant.event: | ||||||
|  |             event: esphome.test_int_lambda | ||||||
|  |             data: | ||||||
|  |               value: !lambda 'return input_number;' | ||||||
|  |  | ||||||
|  |     # Service that tests float lambda functionality | ||||||
|  |     - action: test_float_lambda | ||||||
|  |       variables: | ||||||
|  |         input_float: float | ||||||
|  |       then: | ||||||
|  |         # Log the input to verify service was called | ||||||
|  |         - logger.log: | ||||||
|  |             format: "Service called with float: %.2f" | ||||||
|  |             args: [input_float] | ||||||
|  |  | ||||||
|  |         # Test that float lambdas still work correctly with to_string | ||||||
|  |         # The TemplatableStringValue should automatically convert float to string | ||||||
|  |         - homeassistant.event: | ||||||
|  |             event: esphome.test_float_lambda | ||||||
|  |             data: | ||||||
|  |               value: !lambda 'return input_float;' | ||||||
|  |  | ||||||
|  | logger: | ||||||
|  |   level: DEBUG | ||||||
							
								
								
									
										85
									
								
								tests/integration/test_api_string_lambda.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										85
									
								
								tests/integration/test_api_string_lambda.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,85 @@ | |||||||
|  | """Integration test for TemplatableStringValue with string lambdas.""" | ||||||
|  |  | ||||||
|  | from __future__ import annotations | ||||||
|  |  | ||||||
|  | import asyncio | ||||||
|  | import re | ||||||
|  |  | ||||||
|  | import pytest | ||||||
|  |  | ||||||
|  | from .types import APIClientConnectedFactory, RunCompiledFunction | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @pytest.mark.asyncio | ||||||
|  | async def test_api_string_lambda( | ||||||
|  |     yaml_config: str, | ||||||
|  |     run_compiled: RunCompiledFunction, | ||||||
|  |     api_client_connected: APIClientConnectedFactory, | ||||||
|  | ) -> None: | ||||||
|  |     """Test TemplatableStringValue works with lambdas that return different types.""" | ||||||
|  |     loop = asyncio.get_running_loop() | ||||||
|  |  | ||||||
|  |     # Track log messages for all three service calls | ||||||
|  |     string_called_future = loop.create_future() | ||||||
|  |     int_called_future = loop.create_future() | ||||||
|  |     float_called_future = loop.create_future() | ||||||
|  |  | ||||||
|  |     # Patterns to match in logs - confirms the lambdas compiled and executed | ||||||
|  |     string_pattern = re.compile(r"Service called with string: STRING_FROM_LAMBDA") | ||||||
|  |     int_pattern = re.compile(r"Service called with int: 42") | ||||||
|  |     float_pattern = re.compile(r"Service called with float: 3\.14") | ||||||
|  |  | ||||||
|  |     def check_output(line: str) -> None: | ||||||
|  |         """Check log output for expected messages.""" | ||||||
|  |         if not string_called_future.done() and string_pattern.search(line): | ||||||
|  |             string_called_future.set_result(True) | ||||||
|  |         if not int_called_future.done() and int_pattern.search(line): | ||||||
|  |             int_called_future.set_result(True) | ||||||
|  |         if not float_called_future.done() and float_pattern.search(line): | ||||||
|  |             float_called_future.set_result(True) | ||||||
|  |  | ||||||
|  |     # Run with log monitoring | ||||||
|  |     async with ( | ||||||
|  |         run_compiled(yaml_config, line_callback=check_output), | ||||||
|  |         api_client_connected() as client, | ||||||
|  |     ): | ||||||
|  |         # Verify device info | ||||||
|  |         device_info = await client.device_info() | ||||||
|  |         assert device_info is not None | ||||||
|  |         assert device_info.name == "api-string-lambda-test" | ||||||
|  |  | ||||||
|  |         # List services to find our test services | ||||||
|  |         _, services = await client.list_entities_services() | ||||||
|  |  | ||||||
|  |         # Find all test services | ||||||
|  |         string_service = next( | ||||||
|  |             (s for s in services if s.name == "test_string_lambda"), None | ||||||
|  |         ) | ||||||
|  |         assert string_service is not None, "test_string_lambda service not found" | ||||||
|  |  | ||||||
|  |         int_service = next((s for s in services if s.name == "test_int_lambda"), None) | ||||||
|  |         assert int_service is not None, "test_int_lambda service not found" | ||||||
|  |  | ||||||
|  |         float_service = next( | ||||||
|  |             (s for s in services if s.name == "test_float_lambda"), None | ||||||
|  |         ) | ||||||
|  |         assert float_service is not None, "test_float_lambda service not found" | ||||||
|  |  | ||||||
|  |         # Execute all three services to test different lambda return types | ||||||
|  |         client.execute_service(string_service, {"input_string": "STRING_FROM_LAMBDA"}) | ||||||
|  |         client.execute_service(int_service, {"input_number": 42}) | ||||||
|  |         client.execute_service(float_service, {"input_float": 3.14}) | ||||||
|  |  | ||||||
|  |         # Wait for all service log messages | ||||||
|  |         # This confirms the lambdas compiled successfully and executed | ||||||
|  |         try: | ||||||
|  |             await asyncio.wait_for( | ||||||
|  |                 asyncio.gather( | ||||||
|  |                     string_called_future, int_called_future, float_called_future | ||||||
|  |                 ), | ||||||
|  |                 timeout=5.0, | ||||||
|  |             ) | ||||||
|  |         except TimeoutError: | ||||||
|  |             pytest.fail( | ||||||
|  |                 "One or more service log messages not received - lambda may have failed to compile or execute" | ||||||
|  |             ) | ||||||
		Reference in New Issue
	
	Block a user