Refresh Home Connect program entities possible options when an appliance gets connected (#143213)

Refresh options when an appliance gets connected
This commit is contained in:
J. Diego Rodríguez Royo 2025-04-29 13:12:21 +02:00 committed by GitHub
parent da6fb91886
commit 15aff9662c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 77 additions and 3 deletions

View File

@ -11,7 +11,7 @@ from aiohomeconnect.model.error import HomeConnectError
from aiohomeconnect.model.program import Execution from aiohomeconnect.model.program import Execution
from homeassistant.components.select import SelectEntity, SelectEntityDescription from homeassistant.components.select import SelectEntity, SelectEntityDescription
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant, callback
from homeassistant.exceptions import HomeAssistantError from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
@ -366,16 +366,37 @@ class HomeConnectProgramSelectEntity(HomeConnectEntity, SelectEntity):
appliance, appliance,
desc, desc,
) )
self.set_options()
def set_options(self) -> None:
"""Set the options for the entity."""
self._attr_options = [ self._attr_options = [
PROGRAMS_TRANSLATION_KEYS_MAP[program.key] PROGRAMS_TRANSLATION_KEYS_MAP[program.key]
for program in appliance.programs for program in self.appliance.programs
if program.key != ProgramKey.UNKNOWN if program.key != ProgramKey.UNKNOWN
and ( and (
program.constraints is None program.constraints is None
or program.constraints.execution in desc.allowed_executions or program.constraints.execution
in self.entity_description.allowed_executions
) )
] ]
@callback
def refresh_options(self) -> None:
"""Refresh the options for the entity."""
self.set_options()
self.async_write_ha_state()
async def async_added_to_hass(self) -> None:
"""When entity is added to hass."""
await super().async_added_to_hass()
self.async_on_remove(
self.coordinator.async_add_listener(
self.refresh_options,
(self.appliance.info.ha_id, EventKey.BSH_COMMON_APPLIANCE_CONNECTED),
)
)
def update_native_value(self) -> None: def update_native_value(self) -> None:
"""Set the program value.""" """Set the program value."""
event = self.appliance.events.get(cast(EventKey, self.bsh_key)) event = self.appliance.events.get(cast(EventKey, self.bsh_key))

View File

@ -486,6 +486,59 @@ async def test_select_exception_handling(
assert getattr(client_with_exception, mock_attr).call_count == 2 assert getattr(client_with_exception, mock_attr).call_count == 2
@pytest.mark.parametrize("appliance", ["Washer"], indirect=True)
async def test_programs_updated_on_connect(
appliance: HomeAppliance,
hass: HomeAssistant,
config_entry: MockConfigEntry,
integration_setup: Callable[[MagicMock], Awaitable[bool]],
setup_credentials: None,
client: MagicMock,
) -> None:
"""Test that devices reconnected.
Specifically those devices whose settings, status, etc. could
not be obtained while disconnected and once connected, the entities are added.
"""
get_all_programs_mock = client.get_all_programs
returned_programs = (
await get_all_programs_mock.side_effect(appliance.ha_id)
).programs
assert len(returned_programs) > 1
async def get_all_programs_side_effect(ha_id: str):
if ha_id == appliance.ha_id:
return ArrayOfPrograms(returned_programs[:1])
return await get_all_programs_mock.side_effect(ha_id)
client.get_all_programs = AsyncMock(side_effect=get_all_programs_side_effect)
assert config_entry.state == ConfigEntryState.NOT_LOADED
assert await integration_setup(client)
assert config_entry.state == ConfigEntryState.LOADED
client.get_all_programs = get_all_programs_mock
state = hass.states.get("select.washer_active_program")
assert state
programs = state.attributes[ATTR_OPTIONS]
await client.add_events(
[
EventMessage(
appliance.ha_id,
EventType.CONNECTED,
data=ArrayOfEvents([]),
)
]
)
await hass.async_block_till_done()
state = hass.states.get("select.washer_active_program")
assert state
assert state.attributes[ATTR_OPTIONS] != programs
assert len(state.attributes[ATTR_OPTIONS]) > len(programs)
@pytest.mark.parametrize("appliance", ["Hood"], indirect=True) @pytest.mark.parametrize("appliance", ["Hood"], indirect=True)
@pytest.mark.parametrize( @pytest.mark.parametrize(
( (