mirror of
https://github.com/esphome/esphome.git
synced 2025-10-31 23:21:54 +00:00
remove
This commit is contained in:
@@ -41,17 +41,6 @@ select:
|
|||||||
- "" # Empty string at the end
|
- "" # Empty string at the end
|
||||||
initial_option: "Choice X"
|
initial_option: "Choice X"
|
||||||
|
|
||||||
- platform: template
|
|
||||||
name: "Select Initial Option Test"
|
|
||||||
id: select_initial_option_test
|
|
||||||
optimistic: true
|
|
||||||
options:
|
|
||||||
- "First"
|
|
||||||
- "Second"
|
|
||||||
- "Third"
|
|
||||||
- "Fourth"
|
|
||||||
initial_option: "Third" # Test non-default initial option
|
|
||||||
|
|
||||||
# Add a sensor to ensure we have other entities in the list
|
# Add a sensor to ensure we have other entities in the list
|
||||||
sensor:
|
sensor:
|
||||||
- platform: template
|
- platform: template
|
||||||
|
|||||||
@@ -44,7 +44,6 @@ class InitialStateHelper:
|
|||||||
helper = InitialStateHelper(entities)
|
helper = InitialStateHelper(entities)
|
||||||
client.subscribe_states(helper.on_state_wrapper(user_callback))
|
client.subscribe_states(helper.on_state_wrapper(user_callback))
|
||||||
await helper.wait_for_initial_states()
|
await helper.wait_for_initial_states()
|
||||||
# Access initial states via helper.initial_states[key]
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, entities: list[EntityInfo]) -> None:
|
def __init__(self, entities: list[EntityInfo]) -> None:
|
||||||
@@ -64,8 +63,6 @@ class InitialStateHelper:
|
|||||||
self._entities_by_id = {
|
self._entities_by_id = {
|
||||||
(entity.device_id, entity.key): entity for entity in entities
|
(entity.device_id, entity.key): entity for entity in entities
|
||||||
}
|
}
|
||||||
# Store initial states by key for test access
|
|
||||||
self.initial_states: dict[int, EntityState] = {}
|
|
||||||
|
|
||||||
# Log all entities
|
# Log all entities
|
||||||
_LOGGER.debug(
|
_LOGGER.debug(
|
||||||
@@ -130,9 +127,6 @@ class InitialStateHelper:
|
|||||||
|
|
||||||
# If this entity is waiting for initial state
|
# If this entity is waiting for initial state
|
||||||
if entity_id in self._wait_initial_states:
|
if entity_id in self._wait_initial_states:
|
||||||
# Store the initial state for test access
|
|
||||||
self.initial_states[state.key] = state
|
|
||||||
|
|
||||||
# Remove from waiting set
|
# Remove from waiting set
|
||||||
self._wait_initial_states.discard(entity_id)
|
self._wait_initial_states.discard(entity_id)
|
||||||
|
|
||||||
|
|||||||
@@ -2,11 +2,12 @@
|
|||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import asyncio
|
||||||
|
|
||||||
import aioesphomeapi
|
import aioesphomeapi
|
||||||
from aioesphomeapi import ClimateAction, ClimateInfo, ClimateMode, ClimatePreset
|
from aioesphomeapi import ClimateAction, ClimateMode, ClimatePreset, EntityState
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from .state_utils import InitialStateHelper
|
|
||||||
from .types import APIClientConnectedFactory, RunCompiledFunction
|
from .types import APIClientConnectedFactory, RunCompiledFunction
|
||||||
|
|
||||||
|
|
||||||
@@ -17,27 +18,26 @@ async def test_host_mode_climate_basic_state(
|
|||||||
api_client_connected: APIClientConnectedFactory,
|
api_client_connected: APIClientConnectedFactory,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test basic climate state reporting."""
|
"""Test basic climate state reporting."""
|
||||||
|
loop = asyncio.get_running_loop()
|
||||||
async with run_compiled(yaml_config), api_client_connected() as client:
|
async with run_compiled(yaml_config), api_client_connected() as client:
|
||||||
# Get entities and set up state synchronization
|
states: dict[int, EntityState] = {}
|
||||||
entities, services = await client.list_entities_services()
|
climate_future: asyncio.Future[EntityState] = loop.create_future()
|
||||||
initial_state_helper = InitialStateHelper(entities)
|
|
||||||
climate_infos = [e for e in entities if isinstance(e, ClimateInfo)]
|
|
||||||
assert len(climate_infos) >= 1, "Expected at least 1 climate entity"
|
|
||||||
|
|
||||||
# Subscribe with the wrapper (no-op callback since we just want initial states)
|
def on_state(state: EntityState) -> None:
|
||||||
client.subscribe_states(initial_state_helper.on_state_wrapper(lambda _: None))
|
states[state.key] = state
|
||||||
|
if (
|
||||||
|
isinstance(state, aioesphomeapi.ClimateState)
|
||||||
|
and not climate_future.done()
|
||||||
|
):
|
||||||
|
climate_future.set_result(state)
|
||||||
|
|
||||||
|
client.subscribe_states(on_state)
|
||||||
|
|
||||||
# Wait for all initial states to be broadcast
|
|
||||||
try:
|
try:
|
||||||
await initial_state_helper.wait_for_initial_states()
|
climate_state = await asyncio.wait_for(climate_future, timeout=5.0)
|
||||||
except TimeoutError:
|
except TimeoutError:
|
||||||
pytest.fail("Timeout waiting for initial states")
|
pytest.fail("Climate state not received within 5 seconds")
|
||||||
|
|
||||||
# Get the climate entity and its initial state
|
|
||||||
test_climate = climate_infos[0]
|
|
||||||
climate_state = initial_state_helper.initial_states.get(test_climate.key)
|
|
||||||
|
|
||||||
assert climate_state is not None, "Climate initial state not found"
|
|
||||||
assert isinstance(climate_state, aioesphomeapi.ClimateState)
|
assert isinstance(climate_state, aioesphomeapi.ClimateState)
|
||||||
assert climate_state.mode == ClimateMode.OFF
|
assert climate_state.mode == ClimateMode.OFF
|
||||||
assert climate_state.action == ClimateAction.OFF
|
assert climate_state.action == ClimateAction.OFF
|
||||||
|
|||||||
@@ -36,8 +36,8 @@ async def test_host_mode_empty_string_options(
|
|||||||
|
|
||||||
# Find our select entities
|
# Find our select entities
|
||||||
select_entities = [e for e in entity_info if isinstance(e, SelectInfo)]
|
select_entities = [e for e in entity_info if isinstance(e, SelectInfo)]
|
||||||
assert len(select_entities) == 4, (
|
assert len(select_entities) == 3, (
|
||||||
f"Expected 4 select entities, got {len(select_entities)}"
|
f"Expected 3 select entities, got {len(select_entities)}"
|
||||||
)
|
)
|
||||||
|
|
||||||
# Verify each select entity by name and check their options
|
# Verify each select entity by name and check their options
|
||||||
@@ -71,15 +71,6 @@ async def test_host_mode_empty_string_options(
|
|||||||
assert empty_last.options[2] == "Choice Z"
|
assert empty_last.options[2] == "Choice Z"
|
||||||
assert empty_last.options[3] == "" # Empty string at end
|
assert empty_last.options[3] == "" # Empty string at end
|
||||||
|
|
||||||
# Check "Select Initial Option Test" - verify non-default initial option
|
|
||||||
assert "Select Initial Option Test" in selects_by_name
|
|
||||||
initial_option_test = selects_by_name["Select Initial Option Test"]
|
|
||||||
assert len(initial_option_test.options) == 4
|
|
||||||
assert initial_option_test.options[0] == "First"
|
|
||||||
assert initial_option_test.options[1] == "Second"
|
|
||||||
assert initial_option_test.options[2] == "Third"
|
|
||||||
assert initial_option_test.options[3] == "Fourth"
|
|
||||||
|
|
||||||
# If we got here without protobuf decoding errors, the fix is working
|
# If we got here without protobuf decoding errors, the fix is working
|
||||||
# The bug would have caused "Invalid protobuf message" errors with trailing bytes
|
# The bug would have caused "Invalid protobuf message" errors with trailing bytes
|
||||||
|
|
||||||
@@ -87,12 +78,7 @@ async def test_host_mode_empty_string_options(
|
|||||||
# This ensures empty strings work properly in state messages too
|
# This ensures empty strings work properly in state messages too
|
||||||
states: dict[int, EntityState] = {}
|
states: dict[int, EntityState] = {}
|
||||||
states_received_future: asyncio.Future[None] = loop.create_future()
|
states_received_future: asyncio.Future[None] = loop.create_future()
|
||||||
expected_select_keys = {
|
expected_select_keys = {empty_first.key, empty_middle.key, empty_last.key}
|
||||||
empty_first.key,
|
|
||||||
empty_middle.key,
|
|
||||||
empty_last.key,
|
|
||||||
initial_option_test.key,
|
|
||||||
}
|
|
||||||
received_select_keys = set()
|
received_select_keys = set()
|
||||||
|
|
||||||
def on_state(state: EntityState) -> None:
|
def on_state(state: EntityState) -> None:
|
||||||
@@ -123,14 +109,6 @@ async def test_host_mode_empty_string_options(
|
|||||||
assert empty_first.key in states
|
assert empty_first.key in states
|
||||||
assert empty_middle.key in states
|
assert empty_middle.key in states
|
||||||
assert empty_last.key in states
|
assert empty_last.key in states
|
||||||
assert initial_option_test.key in states
|
|
||||||
|
|
||||||
# Verify the initial option is set correctly to "Third" (not the default "First")
|
|
||||||
initial_state = states[initial_option_test.key]
|
|
||||||
assert initial_state.state == "Third", (
|
|
||||||
f"Expected initial state 'Third' but got '{initial_state.state}' - "
|
|
||||||
f"initial_option not correctly applied"
|
|
||||||
)
|
|
||||||
|
|
||||||
# The main test is that we got here without protobuf errors
|
# The main test is that we got here without protobuf errors
|
||||||
# The select entities with empty string options were properly encoded
|
# The select entities with empty string options were properly encoded
|
||||||
|
|||||||
Reference in New Issue
Block a user