mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-31 07:03:55 +00:00 
			
		
		
		
	Optimize entity icon memory usage with USE_ENTITY_ICON flag (#9337)
This commit is contained in:
		
							
								
								
									
										78
									
								
								tests/integration/fixtures/entity_icon.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										78
									
								
								tests/integration/fixtures/entity_icon.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,78 @@ | ||||
| esphome: | ||||
|   name: icon-test | ||||
|  | ||||
| host: | ||||
|  | ||||
| api: | ||||
|  | ||||
| logger: | ||||
|  | ||||
| # Test entities with custom icons | ||||
| sensor: | ||||
|   - platform: template | ||||
|     name: "Sensor With Icon" | ||||
|     icon: "mdi:temperature-celsius" | ||||
|     unit_of_measurement: "°C" | ||||
|     update_interval: 1s | ||||
|     lambda: |- | ||||
|       return 25.5; | ||||
|  | ||||
|   - platform: template | ||||
|     name: "Sensor Without Icon" | ||||
|     unit_of_measurement: "%" | ||||
|     update_interval: 1s | ||||
|     lambda: |- | ||||
|       return 50.0; | ||||
|  | ||||
| binary_sensor: | ||||
|   - platform: template | ||||
|     name: "Binary Sensor With Icon" | ||||
|     icon: "mdi:motion-sensor" | ||||
|     lambda: |- | ||||
|       return true; | ||||
|  | ||||
|   - platform: template | ||||
|     name: "Binary Sensor Without Icon" | ||||
|     lambda: |- | ||||
|       return false; | ||||
|  | ||||
| text_sensor: | ||||
|   - platform: template | ||||
|     name: "Text Sensor With Icon" | ||||
|     icon: "mdi:text-box" | ||||
|     lambda: |- | ||||
|       return {"Hello Icons"}; | ||||
|  | ||||
| switch: | ||||
|   - platform: template | ||||
|     name: "Switch With Icon" | ||||
|     icon: "mdi:toggle-switch" | ||||
|     optimistic: true | ||||
|  | ||||
| button: | ||||
|   - platform: template | ||||
|     name: "Button With Icon" | ||||
|     icon: "mdi:gesture-tap-button" | ||||
|     on_press: | ||||
|       - logger.log: "Button with icon pressed" | ||||
|  | ||||
| number: | ||||
|   - platform: template | ||||
|     name: "Number With Icon" | ||||
|     icon: "mdi:numeric" | ||||
|     initial_value: 42 | ||||
|     min_value: 0 | ||||
|     max_value: 100 | ||||
|     step: 1 | ||||
|     optimistic: true | ||||
|  | ||||
| select: | ||||
|   - platform: template | ||||
|     name: "Select With Icon" | ||||
|     icon: "mdi:format-list-bulleted" | ||||
|     options: | ||||
|       - "Option A" | ||||
|       - "Option B" | ||||
|       - "Option C" | ||||
|     initial_option: "Option A" | ||||
|     optimistic: true | ||||
							
								
								
									
										97
									
								
								tests/integration/test_entity_icon.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										97
									
								
								tests/integration/test_entity_icon.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,97 @@ | ||||
| """Integration test for entity icons with USE_ENTITY_ICON feature.""" | ||||
|  | ||||
| from __future__ import annotations | ||||
|  | ||||
| import asyncio | ||||
|  | ||||
| from aioesphomeapi import EntityState | ||||
| import pytest | ||||
|  | ||||
| from .types import APIClientConnectedFactory, RunCompiledFunction | ||||
|  | ||||
|  | ||||
| @pytest.mark.asyncio | ||||
| async def test_entity_icon( | ||||
|     yaml_config: str, | ||||
|     run_compiled: RunCompiledFunction, | ||||
|     api_client_connected: APIClientConnectedFactory, | ||||
| ) -> None: | ||||
|     """Test that entities with custom icons work correctly with USE_ENTITY_ICON.""" | ||||
|     # Write, compile and run the ESPHome device, then connect to API | ||||
|     async with run_compiled(yaml_config), api_client_connected() as client: | ||||
|         # Get all entities | ||||
|         entities = await client.list_entities_services() | ||||
|  | ||||
|         # Create a map of entity names to entity info | ||||
|         entity_map = {entity.name: entity for entity in entities[0]} | ||||
|  | ||||
|         # Test entities with icons | ||||
|         icon_test_cases = [ | ||||
|             # (entity_name, expected_icon) | ||||
|             ("Sensor With Icon", "mdi:temperature-celsius"), | ||||
|             ("Binary Sensor With Icon", "mdi:motion-sensor"), | ||||
|             ("Text Sensor With Icon", "mdi:text-box"), | ||||
|             ("Switch With Icon", "mdi:toggle-switch"), | ||||
|             ("Button With Icon", "mdi:gesture-tap-button"), | ||||
|             ("Number With Icon", "mdi:numeric"), | ||||
|             ("Select With Icon", "mdi:format-list-bulleted"), | ||||
|         ] | ||||
|  | ||||
|         # Test entities without icons (should have empty string) | ||||
|         no_icon_test_cases = [ | ||||
|             "Sensor Without Icon", | ||||
|             "Binary Sensor Without Icon", | ||||
|         ] | ||||
|  | ||||
|         # Verify entities with icons | ||||
|         for entity_name, expected_icon in icon_test_cases: | ||||
|             assert entity_name in entity_map, ( | ||||
|                 f"Entity '{entity_name}' not found in API response" | ||||
|             ) | ||||
|             entity = entity_map[entity_name] | ||||
|  | ||||
|             # Check icon field | ||||
|             assert hasattr(entity, "icon"), ( | ||||
|                 f"{entity_name}: Entity should have icon attribute" | ||||
|             ) | ||||
|             assert entity.icon == expected_icon, ( | ||||
|                 f"{entity_name}: icon mismatch - " | ||||
|                 f"expected '{expected_icon}', got '{entity.icon}'" | ||||
|             ) | ||||
|  | ||||
|         # Verify entities without icons | ||||
|         for entity_name in no_icon_test_cases: | ||||
|             assert entity_name in entity_map, ( | ||||
|                 f"Entity '{entity_name}' not found in API response" | ||||
|             ) | ||||
|             entity = entity_map[entity_name] | ||||
|  | ||||
|             # Check icon field is empty | ||||
|             assert hasattr(entity, "icon"), ( | ||||
|                 f"{entity_name}: Entity should have icon attribute" | ||||
|             ) | ||||
|             assert entity.icon == "", ( | ||||
|                 f"{entity_name}: icon should be empty string for entities without icons, " | ||||
|                 f"got '{entity.icon}'" | ||||
|             ) | ||||
|  | ||||
|         # Subscribe to states to ensure everything works normally | ||||
|         states: dict[int, EntityState] = {} | ||||
|         state_received = asyncio.Event() | ||||
|  | ||||
|         def on_state(state: EntityState) -> None: | ||||
|             states[state.key] = state | ||||
|             state_received.set() | ||||
|  | ||||
|         client.subscribe_states(on_state) | ||||
|  | ||||
|         # Wait for states | ||||
|         try: | ||||
|             await asyncio.wait_for(state_received.wait(), timeout=5.0) | ||||
|         except asyncio.TimeoutError: | ||||
|             pytest.fail("No states received within 5 seconds") | ||||
|  | ||||
|         # Verify we received states | ||||
|         assert len(states) > 0, ( | ||||
|             "No states received - entities may not be working correctly" | ||||
|         ) | ||||
		Reference in New Issue
	
	Block a user