mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-31 15:12:06 +00:00 
			
		
		
		
	Merge branch 'integration' into memory_api
This commit is contained in:
		| @@ -77,6 +77,7 @@ BRIGHTNESS = 0x51 | |||||||
| WRDISBV = 0x51 | WRDISBV = 0x51 | ||||||
| RDDISBV = 0x52 | RDDISBV = 0x52 | ||||||
| WRCTRLD = 0x53 | WRCTRLD = 0x53 | ||||||
|  | WCE = 0x58 | ||||||
| SWIRE1 = 0x5A | SWIRE1 = 0x5A | ||||||
| SWIRE2 = 0x5B | SWIRE2 = 0x5B | ||||||
| IFMODE = 0xB0 | IFMODE = 0xB0 | ||||||
| @@ -91,6 +92,7 @@ PWCTR2 = 0xC1 | |||||||
| PWCTR3 = 0xC2 | PWCTR3 = 0xC2 | ||||||
| PWCTR4 = 0xC3 | PWCTR4 = 0xC3 | ||||||
| PWCTR5 = 0xC4 | PWCTR5 = 0xC4 | ||||||
|  | SPIMODESEL = 0xC4 | ||||||
| VMCTR1 = 0xC5 | VMCTR1 = 0xC5 | ||||||
| IFCTR = 0xC6 | IFCTR = 0xC6 | ||||||
| VMCTR2 = 0xC7 | VMCTR2 = 0xC7 | ||||||
|   | |||||||
| @@ -5,10 +5,13 @@ from esphome.components.mipi import ( | |||||||
|     PAGESEL, |     PAGESEL, | ||||||
|     PIXFMT, |     PIXFMT, | ||||||
|     SLPOUT, |     SLPOUT, | ||||||
|  |     SPIMODESEL, | ||||||
|     SWIRE1, |     SWIRE1, | ||||||
|     SWIRE2, |     SWIRE2, | ||||||
|     TEON, |     TEON, | ||||||
|  |     WCE, | ||||||
|     WRAM, |     WRAM, | ||||||
|  |     WRCTRLD, | ||||||
|     DriverChip, |     DriverChip, | ||||||
|     delay, |     delay, | ||||||
| ) | ) | ||||||
| @@ -87,4 +90,19 @@ T4_S3_AMOLED = RM690B0.extend( | |||||||
|     bus_mode=TYPE_QUAD, |     bus_mode=TYPE_QUAD, | ||||||
| ) | ) | ||||||
|  |  | ||||||
|  | CO5300 = DriverChip( | ||||||
|  |     "CO5300", | ||||||
|  |     brightness=0xD0, | ||||||
|  |     color_order=MODE_RGB, | ||||||
|  |     bus_mode=TYPE_QUAD, | ||||||
|  |     initsequence=( | ||||||
|  |         (SLPOUT,),  # Requires early SLPOUT | ||||||
|  |         (PAGESEL, 0x00), | ||||||
|  |         (SPIMODESEL, 0x80), | ||||||
|  |         (WRCTRLD, 0x20), | ||||||
|  |         (WCE, 0x00), | ||||||
|  |     ), | ||||||
|  | ) | ||||||
|  |  | ||||||
|  |  | ||||||
| models = {} | models = {} | ||||||
|   | |||||||
| @@ -1,6 +1,7 @@ | |||||||
| from esphome.components.mipi import DriverChip | from esphome.components.mipi import DriverChip | ||||||
| import esphome.config_validation as cv | import esphome.config_validation as cv | ||||||
|  |  | ||||||
|  | from .amoled import CO5300 | ||||||
| from .ili import ILI9488_A | from .ili import ILI9488_A | ||||||
|  |  | ||||||
| DriverChip( | DriverChip( | ||||||
| @@ -140,3 +141,14 @@ ILI9488_A.extend( | |||||||
|     data_rate="20MHz", |     data_rate="20MHz", | ||||||
|     invert_colors=True, |     invert_colors=True, | ||||||
| ) | ) | ||||||
|  |  | ||||||
|  | CO5300.extend( | ||||||
|  |     "WAVESHARE-ESP32-S3-TOUCH-AMOLED-1.75", | ||||||
|  |     width=466, | ||||||
|  |     height=466, | ||||||
|  |     pixel_mode="16bit", | ||||||
|  |     offset_height=0, | ||||||
|  |     offset_width=6, | ||||||
|  |     cs_pin=12, | ||||||
|  |     reset_pin=39, | ||||||
|  | ) | ||||||
|   | |||||||
| @@ -373,3 +373,20 @@ button: | |||||||
|     name: "Test Button" |     name: "Test Button" | ||||||
|     on_press: |     on_press: | ||||||
|       - logger.log: "Button pressed" |       - logger.log: "Button pressed" | ||||||
|  |  | ||||||
|  | # Date, Time, and DateTime entities | ||||||
|  | datetime: | ||||||
|  |   - platform: template | ||||||
|  |     type: date | ||||||
|  |     name: "Test Date" | ||||||
|  |     initial_value: "2023-05-13" | ||||||
|  |     optimistic: true | ||||||
|  |   - platform: template | ||||||
|  |     type: time | ||||||
|  |     name: "Test Time" | ||||||
|  |     initial_value: "12:30:00" | ||||||
|  |     optimistic: true | ||||||
|  |   - platform: template | ||||||
|  |     type: datetime | ||||||
|  |     name: "Test DateTime" | ||||||
|  |     optimistic: true | ||||||
|   | |||||||
| @@ -4,7 +4,17 @@ from __future__ import annotations | |||||||
|  |  | ||||||
| import asyncio | import asyncio | ||||||
|  |  | ||||||
| from aioesphomeapi import ClimateInfo, EntityState, SensorState | from aioesphomeapi import ( | ||||||
|  |     ClimateInfo, | ||||||
|  |     DateInfo, | ||||||
|  |     DateState, | ||||||
|  |     DateTimeInfo, | ||||||
|  |     DateTimeState, | ||||||
|  |     EntityState, | ||||||
|  |     SensorState, | ||||||
|  |     TimeInfo, | ||||||
|  |     TimeState, | ||||||
|  | ) | ||||||
| import pytest | import pytest | ||||||
|  |  | ||||||
| from .types import APIClientConnectedFactory, RunCompiledFunction | from .types import APIClientConnectedFactory, RunCompiledFunction | ||||||
| @@ -22,34 +32,56 @@ async def test_host_mode_many_entities( | |||||||
|     async with run_compiled(yaml_config), api_client_connected() as client: |     async with run_compiled(yaml_config), api_client_connected() as client: | ||||||
|         # Subscribe to state changes |         # Subscribe to state changes | ||||||
|         states: dict[int, EntityState] = {} |         states: dict[int, EntityState] = {} | ||||||
|         sensor_count_future: asyncio.Future[int] = loop.create_future() |         minimum_states_future: asyncio.Future[None] = loop.create_future() | ||||||
|  |  | ||||||
|         def on_state(state: EntityState) -> None: |         def on_state(state: EntityState) -> None: | ||||||
|             states[state.key] = state |             states[state.key] = state | ||||||
|             # Count sensor states specifically |             # Check if we have received minimum expected states | ||||||
|             sensor_states = [ |             sensor_states = [ | ||||||
|                 s |                 s | ||||||
|                 for s in states.values() |                 for s in states.values() | ||||||
|                 if isinstance(s, SensorState) and isinstance(s.state, float) |                 if isinstance(s, SensorState) and isinstance(s.state, float) | ||||||
|             ] |             ] | ||||||
|             # When we have received states from at least 50 sensors, resolve the future |             date_states = [s for s in states.values() if isinstance(s, DateState)] | ||||||
|             if len(sensor_states) >= 50 and not sensor_count_future.done(): |             time_states = [s for s in states.values() if isinstance(s, TimeState)] | ||||||
|                 sensor_count_future.set_result(len(sensor_states)) |             datetime_states = [ | ||||||
|  |                 s for s in states.values() if isinstance(s, DateTimeState) | ||||||
|  |             ] | ||||||
|  |  | ||||||
|  |             # We expect at least 50 sensors and 1 of each datetime entity type | ||||||
|  |             if ( | ||||||
|  |                 len(sensor_states) >= 50 | ||||||
|  |                 and len(date_states) >= 1 | ||||||
|  |                 and len(time_states) >= 1 | ||||||
|  |                 and len(datetime_states) >= 1 | ||||||
|  |                 and not minimum_states_future.done() | ||||||
|  |             ): | ||||||
|  |                 minimum_states_future.set_result(None) | ||||||
|  |  | ||||||
|         client.subscribe_states(on_state) |         client.subscribe_states(on_state) | ||||||
|  |  | ||||||
|         # Wait for states from at least 50 sensors with timeout |         # Wait for minimum states with timeout | ||||||
|         try: |         try: | ||||||
|             sensor_count = await asyncio.wait_for(sensor_count_future, timeout=10.0) |             await asyncio.wait_for(minimum_states_future, timeout=10.0) | ||||||
|         except TimeoutError: |         except TimeoutError: | ||||||
|             sensor_states = [ |             sensor_states = [ | ||||||
|                 s |                 s | ||||||
|                 for s in states.values() |                 for s in states.values() | ||||||
|                 if isinstance(s, SensorState) and isinstance(s.state, float) |                 if isinstance(s, SensorState) and isinstance(s.state, float) | ||||||
|             ] |             ] | ||||||
|  |             date_states = [s for s in states.values() if isinstance(s, DateState)] | ||||||
|  |             time_states = [s for s in states.values() if isinstance(s, TimeState)] | ||||||
|  |             datetime_states = [ | ||||||
|  |                 s for s in states.values() if isinstance(s, DateTimeState) | ||||||
|  |             ] | ||||||
|  |  | ||||||
|             pytest.fail( |             pytest.fail( | ||||||
|                 f"Did not receive states from at least 50 sensors within 10 seconds. " |                 f"Did not receive expected states within 10 seconds. " | ||||||
|                 f"Received {len(sensor_states)} sensor states out of {len(states)} total states" |                 f"Received: {len(sensor_states)} sensor states (expected >=50), " | ||||||
|  |                 f"{len(date_states)} date states (expected >=1), " | ||||||
|  |                 f"{len(time_states)} time states (expected >=1), " | ||||||
|  |                 f"{len(datetime_states)} datetime states (expected >=1). " | ||||||
|  |                 f"Total states: {len(states)}" | ||||||
|             ) |             ) | ||||||
|  |  | ||||||
|         # Verify we received a good number of entity states |         # Verify we received a good number of entity states | ||||||
| @@ -64,13 +96,25 @@ async def test_host_mode_many_entities( | |||||||
|             if isinstance(s, SensorState) and isinstance(s.state, float) |             if isinstance(s, SensorState) and isinstance(s.state, float) | ||||||
|         ] |         ] | ||||||
|  |  | ||||||
|         assert sensor_count >= 50, ( |  | ||||||
|             f"Expected at least 50 sensor states, got {sensor_count}" |  | ||||||
|         ) |  | ||||||
|         assert len(sensor_states) >= 50, ( |         assert len(sensor_states) >= 50, ( | ||||||
|             f"Expected at least 50 sensor states, got {len(sensor_states)}" |             f"Expected at least 50 sensor states, got {len(sensor_states)}" | ||||||
|         ) |         ) | ||||||
|  |  | ||||||
|  |         # Verify we received datetime entity states | ||||||
|  |         date_states = [s for s in states.values() if isinstance(s, DateState)] | ||||||
|  |         time_states = [s for s in states.values() if isinstance(s, TimeState)] | ||||||
|  |         datetime_states = [s for s in states.values() if isinstance(s, DateTimeState)] | ||||||
|  |  | ||||||
|  |         assert len(date_states) >= 1, ( | ||||||
|  |             f"Expected at least 1 date state, got {len(date_states)}" | ||||||
|  |         ) | ||||||
|  |         assert len(time_states) >= 1, ( | ||||||
|  |             f"Expected at least 1 time state, got {len(time_states)}" | ||||||
|  |         ) | ||||||
|  |         assert len(datetime_states) >= 1, ( | ||||||
|  |             f"Expected at least 1 datetime state, got {len(datetime_states)}" | ||||||
|  |         ) | ||||||
|  |  | ||||||
|         # Get entity info to verify climate entity details |         # Get entity info to verify climate entity details | ||||||
|         entities = await client.list_entities_services() |         entities = await client.list_entities_services() | ||||||
|         climate_infos = [e for e in entities[0] if isinstance(e, ClimateInfo)] |         climate_infos = [e for e in entities[0] if isinstance(e, ClimateInfo)] | ||||||
| @@ -89,3 +133,28 @@ async def test_host_mode_many_entities( | |||||||
|         assert "HOME" in preset_names, f"Expected 'HOME' preset, got {preset_names}" |         assert "HOME" in preset_names, f"Expected 'HOME' preset, got {preset_names}" | ||||||
|         assert "AWAY" in preset_names, f"Expected 'AWAY' preset, got {preset_names}" |         assert "AWAY" in preset_names, f"Expected 'AWAY' preset, got {preset_names}" | ||||||
|         assert "SLEEP" in preset_names, f"Expected 'SLEEP' preset, got {preset_names}" |         assert "SLEEP" in preset_names, f"Expected 'SLEEP' preset, got {preset_names}" | ||||||
|  |  | ||||||
|  |         # Verify datetime entities exist | ||||||
|  |         date_infos = [e for e in entities[0] if isinstance(e, DateInfo)] | ||||||
|  |         time_infos = [e for e in entities[0] if isinstance(e, TimeInfo)] | ||||||
|  |         datetime_infos = [e for e in entities[0] if isinstance(e, DateTimeInfo)] | ||||||
|  |  | ||||||
|  |         assert len(date_infos) >= 1, "Expected at least 1 date entity" | ||||||
|  |         assert len(time_infos) >= 1, "Expected at least 1 time entity" | ||||||
|  |         assert len(datetime_infos) >= 1, "Expected at least 1 datetime entity" | ||||||
|  |  | ||||||
|  |         # Verify the entity names | ||||||
|  |         date_info = date_infos[0] | ||||||
|  |         assert date_info.name == "Test Date", ( | ||||||
|  |             f"Expected date entity name 'Test Date', got {date_info.name}" | ||||||
|  |         ) | ||||||
|  |  | ||||||
|  |         time_info = time_infos[0] | ||||||
|  |         assert time_info.name == "Test Time", ( | ||||||
|  |             f"Expected time entity name 'Test Time', got {time_info.name}" | ||||||
|  |         ) | ||||||
|  |  | ||||||
|  |         datetime_info = datetime_infos[0] | ||||||
|  |         assert datetime_info.name == "Test DateTime", ( | ||||||
|  |             f"Expected datetime entity name 'Test DateTime', got {datetime_info.name}" | ||||||
|  |         ) | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user