mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-30 22:53:59 +00:00 
			
		
		
		
	Merge branch 'dev' into jesserockz-2025-457
This commit is contained in:
		
							
								
								
									
										194
									
								
								tests/component_tests/psram/test_psram.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										194
									
								
								tests/component_tests/psram/test_psram.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,194 @@ | ||||
| """Tests for PSRAM component.""" | ||||
|  | ||||
| from typing import Any | ||||
|  | ||||
| import pytest | ||||
|  | ||||
| from esphome.components.esp32.const import ( | ||||
|     KEY_VARIANT, | ||||
|     VARIANT_ESP32, | ||||
|     VARIANT_ESP32C2, | ||||
|     VARIANT_ESP32C3, | ||||
|     VARIANT_ESP32C5, | ||||
|     VARIANT_ESP32C6, | ||||
|     VARIANT_ESP32H2, | ||||
|     VARIANT_ESP32P4, | ||||
|     VARIANT_ESP32S2, | ||||
|     VARIANT_ESP32S3, | ||||
| ) | ||||
| import esphome.config_validation as cv | ||||
| from esphome.const import CONF_ESPHOME, PlatformFramework | ||||
| from tests.component_tests.types import SetCoreConfigCallable | ||||
|  | ||||
| UNSUPPORTED_PSRAM_VARIANTS = [ | ||||
|     VARIANT_ESP32C2, | ||||
|     VARIANT_ESP32C3, | ||||
|     VARIANT_ESP32C5, | ||||
|     VARIANT_ESP32C6, | ||||
|     VARIANT_ESP32H2, | ||||
| ] | ||||
|  | ||||
| SUPPORTED_PSRAM_VARIANTS = [ | ||||
|     VARIANT_ESP32, | ||||
|     VARIANT_ESP32S2, | ||||
|     VARIANT_ESP32S3, | ||||
|     VARIANT_ESP32P4, | ||||
| ] | ||||
|  | ||||
|  | ||||
| @pytest.mark.parametrize( | ||||
|     ("config", "error_match"), | ||||
|     [ | ||||
|         pytest.param( | ||||
|             {}, | ||||
|             r"PSRAM is not supported on this chip", | ||||
|             id="psram_not_supported", | ||||
|         ), | ||||
|     ], | ||||
| ) | ||||
| @pytest.mark.parametrize("variant", UNSUPPORTED_PSRAM_VARIANTS) | ||||
| def test_psram_configuration_errors_unsupported_variants( | ||||
|     config: Any, | ||||
|     error_match: str, | ||||
|     variant: str, | ||||
|     set_core_config: SetCoreConfigCallable, | ||||
| ) -> None: | ||||
|     set_core_config( | ||||
|         PlatformFramework.ESP32_IDF, | ||||
|         platform_data={KEY_VARIANT: variant}, | ||||
|         full_config={CONF_ESPHOME: {}}, | ||||
|     ) | ||||
|     """Test detection of invalid PSRAM configuration on unsupported variants.""" | ||||
|     from esphome.components.psram import CONFIG_SCHEMA | ||||
|  | ||||
|     with pytest.raises(cv.Invalid, match=error_match): | ||||
|         CONFIG_SCHEMA(config) | ||||
|  | ||||
|  | ||||
| @pytest.mark.parametrize("variant", SUPPORTED_PSRAM_VARIANTS) | ||||
| def test_psram_configuration_valid_supported_variants( | ||||
|     variant: str, | ||||
|     set_core_config: SetCoreConfigCallable, | ||||
| ) -> None: | ||||
|     set_core_config( | ||||
|         PlatformFramework.ESP32_IDF, | ||||
|         platform_data={KEY_VARIANT: variant}, | ||||
|         full_config={ | ||||
|             CONF_ESPHOME: {}, | ||||
|             "esp32": { | ||||
|                 "variant": variant, | ||||
|                 "cpu_frequency": "160MHz", | ||||
|                 "framework": {"type": "esp-idf"}, | ||||
|             }, | ||||
|         }, | ||||
|     ) | ||||
|     """Test that PSRAM configuration is valid on supported variants.""" | ||||
|     from esphome.components.psram import CONFIG_SCHEMA, FINAL_VALIDATE_SCHEMA | ||||
|  | ||||
|     # This should not raise an exception | ||||
|     config = CONFIG_SCHEMA({}) | ||||
|     FINAL_VALIDATE_SCHEMA(config) | ||||
|  | ||||
|  | ||||
| def _setup_psram_final_validation_test( | ||||
|     esp32_config: dict, | ||||
|     set_core_config: SetCoreConfigCallable, | ||||
|     set_component_config: Any, | ||||
| ) -> str: | ||||
|     """Helper function to set up ESP32 configuration for PSRAM final validation tests.""" | ||||
|     # Use ESP32S3 for schema validation to allow all options, then override for final validation | ||||
|     schema_variant = "ESP32S3" | ||||
|     final_variant = esp32_config.get("variant", "ESP32S3") | ||||
|     full_esp32_config = { | ||||
|         "variant": final_variant, | ||||
|         "cpu_frequency": esp32_config.get("cpu_frequency", "240MHz"), | ||||
|         "framework": {"type": "esp-idf"}, | ||||
|     } | ||||
|  | ||||
|     set_core_config( | ||||
|         PlatformFramework.ESP32_IDF, | ||||
|         platform_data={KEY_VARIANT: schema_variant}, | ||||
|         full_config={ | ||||
|             CONF_ESPHOME: {}, | ||||
|             "esp32": full_esp32_config, | ||||
|         }, | ||||
|     ) | ||||
|     set_component_config("esp32", full_esp32_config) | ||||
|  | ||||
|     return final_variant | ||||
|  | ||||
|  | ||||
| @pytest.mark.parametrize( | ||||
|     ("config", "esp32_config", "expect_error", "error_match"), | ||||
|     [ | ||||
|         pytest.param( | ||||
|             {"speed": "120MHz"}, | ||||
|             {"cpu_frequency": "160MHz"}, | ||||
|             True, | ||||
|             r"PSRAM 120MHz requires 240MHz CPU frequency", | ||||
|             id="120mhz_requires_240mhz_cpu", | ||||
|         ), | ||||
|         pytest.param( | ||||
|             {"mode": "octal"}, | ||||
|             {"variant": "ESP32"}, | ||||
|             True, | ||||
|             r"Octal PSRAM is only supported on ESP32-S3", | ||||
|             id="octal_mode_only_esp32s3", | ||||
|         ), | ||||
|         pytest.param( | ||||
|             {"mode": "quad", "enable_ecc": True}, | ||||
|             {}, | ||||
|             True, | ||||
|             r"ECC is only available in octal mode", | ||||
|             id="ecc_only_in_octal_mode", | ||||
|         ), | ||||
|         pytest.param( | ||||
|             {"speed": "120MHZ"}, | ||||
|             {"cpu_frequency": "240MHZ"}, | ||||
|             False, | ||||
|             None, | ||||
|             id="120mhz_with_240mhz_cpu", | ||||
|         ), | ||||
|         pytest.param( | ||||
|             {"mode": "octal"}, | ||||
|             {"variant": "ESP32S3"}, | ||||
|             False, | ||||
|             None, | ||||
|             id="octal_mode_on_esp32s3", | ||||
|         ), | ||||
|         pytest.param( | ||||
|             {"mode": "octal", "enable_ecc": True}, | ||||
|             {"variant": "ESP32S3"}, | ||||
|             False, | ||||
|             None, | ||||
|             id="ecc_in_octal_mode", | ||||
|         ), | ||||
|     ], | ||||
| ) | ||||
| def test_psram_final_validation( | ||||
|     config: Any, | ||||
|     esp32_config: dict, | ||||
|     expect_error: bool, | ||||
|     error_match: str | None, | ||||
|     set_core_config: SetCoreConfigCallable, | ||||
|     set_component_config: Any, | ||||
| ) -> None: | ||||
|     """Test PSRAM final validation for both error and valid cases.""" | ||||
|     from esphome.components.psram import CONFIG_SCHEMA, FINAL_VALIDATE_SCHEMA | ||||
|     from esphome.core import CORE | ||||
|  | ||||
|     final_variant = _setup_psram_final_validation_test( | ||||
|         esp32_config, set_core_config, set_component_config | ||||
|     ) | ||||
|  | ||||
|     validated_config = CONFIG_SCHEMA(config) | ||||
|  | ||||
|     # Update CORE variant for final validation | ||||
|     CORE.data["esp32"][KEY_VARIANT] = final_variant | ||||
|  | ||||
|     if expect_error: | ||||
|         with pytest.raises(cv.Invalid, match=error_match): | ||||
|             FINAL_VALIDATE_SCHEMA(validated_config) | ||||
|     else: | ||||
|         # This should not raise an exception | ||||
|         FINAL_VALIDATE_SCHEMA(validated_config) | ||||
							
								
								
									
										89
									
								
								tests/components/esp32_can/test.esp32-c6-idf.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										89
									
								
								tests/components/esp32_can/test.esp32-c6-idf.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,89 @@ | ||||
| esphome: | ||||
|   on_boot: | ||||
|     then: | ||||
|       - canbus.send: | ||||
|           # Extended ID explicit | ||||
|           canbus_id: esp32_internal_can | ||||
|           use_extended_id: true | ||||
|           can_id: 0x100 | ||||
|           data: [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08] | ||||
|       - canbus.send: | ||||
|           # Standard ID by default | ||||
|           canbus_id: esp32_internal_can | ||||
|           can_id: 0x100 | ||||
|           data: [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08] | ||||
|       - canbus.send: | ||||
|           # Extended ID explicit | ||||
|           canbus_id: esp32_internal_can_2 | ||||
|           use_extended_id: true | ||||
|           can_id: 0x100 | ||||
|           data: [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08] | ||||
|       - canbus.send: | ||||
|           # Standard ID by default | ||||
|           canbus_id: esp32_internal_can_2 | ||||
|           can_id: 0x100 | ||||
|           data: [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08] | ||||
|  | ||||
| canbus: | ||||
|   - platform: esp32_can | ||||
|     id: esp32_internal_can | ||||
|     rx_pin: GPIO8 | ||||
|     tx_pin: GPIO7 | ||||
|     can_id: 4 | ||||
|     bit_rate: 50kbps | ||||
|     on_frame: | ||||
|       - can_id: 500 | ||||
|         then: | ||||
|           - lambda: |- | ||||
|               std::string b(x.begin(), x.end()); | ||||
|               ESP_LOGD("canbus1", "canid 500 %s", b.c_str() ); | ||||
|       - can_id: 0b00000000000000000000001000000 | ||||
|         can_id_mask: 0b11111000000000011111111000000 | ||||
|         use_extended_id: true | ||||
|         then: | ||||
|           - lambda: |- | ||||
|               auto pdo_id = can_id >> 14; | ||||
|               switch (pdo_id) | ||||
|               { | ||||
|                 case 117: | ||||
|                   ESP_LOGD("canbus1", "exhaust_fan_duty"); | ||||
|                   break; | ||||
|                 case 118: | ||||
|                   ESP_LOGD("canbus1", "supply_fan_duty"); | ||||
|                   break; | ||||
|                 case 119: | ||||
|                   ESP_LOGD("canbus1", "supply_fan_flow"); | ||||
|                   break; | ||||
|                 // to be continued... | ||||
|               } | ||||
|   - platform: esp32_can | ||||
|     id: esp32_internal_can_2 | ||||
|     rx_pin: GPIO10 | ||||
|     tx_pin: GPIO9 | ||||
|     can_id: 4 | ||||
|     bit_rate: 50kbps | ||||
|     on_frame: | ||||
|       - can_id: 500 | ||||
|         then: | ||||
|           - lambda: |- | ||||
|               std::string b(x.begin(), x.end()); | ||||
|               ESP_LOGD("canbus2", "canid 500 %s", b.c_str() ); | ||||
|       - can_id: 0b00000000000000000000001000000 | ||||
|         can_id_mask: 0b11111000000000011111111000000 | ||||
|         use_extended_id: true | ||||
|         then: | ||||
|           - lambda: |- | ||||
|               auto pdo_id = can_id >> 14; | ||||
|               switch (pdo_id) | ||||
|               { | ||||
|                 case 117: | ||||
|                   ESP_LOGD("canbus2", "exhaust_fan_duty"); | ||||
|                   break; | ||||
|                 case 118: | ||||
|                   ESP_LOGD("canbus2", "supply_fan_duty"); | ||||
|                   break; | ||||
|                 case 119: | ||||
|                   ESP_LOGD("canbus2", "supply_fan_flow"); | ||||
|                   break; | ||||
|                 // to be continued... | ||||
|               } | ||||
							
								
								
									
										9
									
								
								tests/components/lm75b/common.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								tests/components/lm75b/common.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,9 @@ | ||||
| i2c: | ||||
|   - id: i2c_lm75b | ||||
|     scl: ${scl_pin} | ||||
|     sda: ${sda_pin} | ||||
|  | ||||
| sensor: | ||||
|   - platform: lm75b | ||||
|     name: LM75B Temperature | ||||
|     update_interval: 30s | ||||
							
								
								
									
										5
									
								
								tests/components/lm75b/test.esp32-ard.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								tests/components/lm75b/test.esp32-ard.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | ||||
| substitutions: | ||||
|   scl_pin: GPIO15 | ||||
|   sda_pin: GPIO13 | ||||
|  | ||||
| <<: !include common.yaml | ||||
							
								
								
									
										5
									
								
								tests/components/lm75b/test.esp32-c3-ard.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								tests/components/lm75b/test.esp32-c3-ard.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | ||||
| substitutions: | ||||
|   scl_pin: GPIO5 | ||||
|   sda_pin: GPIO4 | ||||
|  | ||||
| <<: !include common.yaml | ||||
							
								
								
									
										5
									
								
								tests/components/lm75b/test.esp32-c3-idf.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								tests/components/lm75b/test.esp32-c3-idf.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | ||||
| substitutions: | ||||
|   scl_pin: GPIO5 | ||||
|   sda_pin: GPIO4 | ||||
|  | ||||
| <<: !include common.yaml | ||||
							
								
								
									
										5
									
								
								tests/components/lm75b/test.esp32-idf.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								tests/components/lm75b/test.esp32-idf.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | ||||
| substitutions: | ||||
|   scl_pin: GPIO15 | ||||
|   sda_pin: GPIO13 | ||||
|  | ||||
| <<: !include common.yaml | ||||
							
								
								
									
										5
									
								
								tests/components/lm75b/test.esp8266-ard.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								tests/components/lm75b/test.esp8266-ard.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | ||||
| substitutions: | ||||
|   scl_pin: GPIO5 | ||||
|   sda_pin: GPIO4 | ||||
|  | ||||
| <<: !include common.yaml | ||||
							
								
								
									
										5
									
								
								tests/components/lm75b/test.rp2040-ard.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								tests/components/lm75b/test.rp2040-ard.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | ||||
| substitutions: | ||||
|   scl_pin: GPIO5 | ||||
|   sda_pin: GPIO4 | ||||
|  | ||||
| <<: !include common.yaml | ||||
| @@ -6,11 +6,16 @@ esphome: | ||||
|           format: "Warning: Logger level is %d" | ||||
|           args: [id(logger_id).get_log_level()] | ||||
|       - logger.set_level: WARN | ||||
|       - logger.set_level: | ||||
|           level: ERROR | ||||
|           tag: mqtt.client | ||||
|  | ||||
| logger: | ||||
|   id: logger_id | ||||
|   level: DEBUG | ||||
|   initial_level: INFO | ||||
|   logs: | ||||
|     mqtt.component: WARN | ||||
|  | ||||
| select: | ||||
|   - platform: logger | ||||
|   | ||||
| @@ -17,5 +17,7 @@ sensor: | ||||
|     temperature: | ||||
|       name: QMC5883L Temperature | ||||
|     range: 800uT | ||||
|     data_rate: 200Hz | ||||
|     oversampling: 256x | ||||
|     update_interval: 15s | ||||
|     drdy_pin: ${drdy_pin} | ||||
|   | ||||
| @@ -1,5 +1,6 @@ | ||||
| substitutions: | ||||
|   scl_pin: GPIO16 | ||||
|   sda_pin: GPIO17 | ||||
|   drdy_pin: GPIO18 | ||||
|  | ||||
| <<: !include common.yaml | ||||
|   | ||||
| @@ -1,5 +1,6 @@ | ||||
| substitutions: | ||||
|   scl_pin: GPIO5 | ||||
|   sda_pin: GPIO4 | ||||
|   drdy_pin: GPIO6 | ||||
|  | ||||
| <<: !include common.yaml | ||||
|   | ||||
| @@ -1,5 +1,6 @@ | ||||
| substitutions: | ||||
|   scl_pin: GPIO5 | ||||
|   sda_pin: GPIO4 | ||||
|   drdy_pin: GPIO6 | ||||
|  | ||||
| <<: !include common.yaml | ||||
|   | ||||
| @@ -1,5 +1,6 @@ | ||||
| substitutions: | ||||
|   scl_pin: GPIO16 | ||||
|   sda_pin: GPIO17 | ||||
|   drdy_pin: GPIO18 | ||||
|  | ||||
| <<: !include common.yaml | ||||
|   | ||||
| @@ -1,5 +1,6 @@ | ||||
| substitutions: | ||||
|   scl_pin: GPIO5 | ||||
|   sda_pin: GPIO4 | ||||
|   drdy_pin: GPIO2 | ||||
|  | ||||
| <<: !include common.yaml | ||||
|   | ||||
| @@ -1,5 +1,6 @@ | ||||
| substitutions: | ||||
|   scl_pin: GPIO5 | ||||
|   sda_pin: GPIO4 | ||||
|   drdy_pin: GPIO2 | ||||
|  | ||||
| <<: !include common.yaml | ||||
|   | ||||
| @@ -1,6 +1,8 @@ | ||||
| substitutions: | ||||
|   pin: GPIO2 | ||||
|   clock_resolution: "2000000" | ||||
|   carrier_duty_percent: "25" | ||||
|   carrier_frequency: "30000" | ||||
|   filter_symbols: "2" | ||||
|   receive_symbols: "4" | ||||
|   rmt_symbols: "64" | ||||
|   | ||||
| @@ -5,6 +5,9 @@ substitutions: | ||||
|   var21: '79' | ||||
|   value: 33 | ||||
|   values: 44 | ||||
|   position: | ||||
|     x: 79 | ||||
|     y: 82 | ||||
|  | ||||
| esphome: | ||||
|   name: test | ||||
| @@ -26,3 +29,7 @@ test_list: | ||||
|   - Literal $values ${are not substituted} | ||||
|   - ["list $value", "${is not}", "${substituted}"] | ||||
|   - {"$dictionary": "$value", "${is not}": "${substituted}"} | ||||
|   - |- | ||||
|     {{{ "x", "79"}, { "y", "82"}}} | ||||
|   - '{{{"AA"}}}' | ||||
|   - '"HELLO"' | ||||
|   | ||||
| @@ -8,6 +8,9 @@ substitutions: | ||||
|   var21: "79" | ||||
|   value: 33 | ||||
|   values: 44 | ||||
|   position: | ||||
|     x: 79 | ||||
|     y: 82 | ||||
|  | ||||
| test_list: | ||||
|   - "$var1" | ||||
| @@ -27,3 +30,7 @@ test_list: | ||||
|   - !literal Literal $values ${are not substituted} | ||||
|   - !literal ["list $value", "${is not}", "${substituted}"] | ||||
|   - !literal {"$dictionary": "$value", "${is not}": "${substituted}"} | ||||
|   - |- # Test parsing things that look like a python set of sets when rendered: | ||||
|     {{{ "x", "${ position.x }"}, { "y", "${ position.y }"}}} | ||||
|   - ${ '{{{"AA"}}}' } | ||||
|   - ${ '"HELLO"' } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user