diff --git a/homeassistant/components/home_connect/select.py b/homeassistant/components/home_connect/select.py index c7408094aed..2df5718fa53 100644 --- a/homeassistant/components/home_connect/select.py +++ b/homeassistant/components/home_connect/select.py @@ -1,9 +1,13 @@ """Provides a select platform for Home Connect.""" -from typing import cast +from collections.abc import Callable, Coroutine +from dataclasses import dataclass +from typing import Any, cast +from aiohomeconnect.client import Client as HomeConnectClient from aiohomeconnect.model import EventKey, ProgramKey from aiohomeconnect.model.error import HomeConnectError +from aiohomeconnect.model.program import Execution from homeassistant.components.select import SelectEntity, SelectEntityDescription from homeassistant.core import HomeAssistant @@ -29,14 +33,38 @@ PROGRAMS_TRANSLATION_KEYS_MAP = { value: key for key, value in TRANSLATION_KEYS_PROGRAMS_MAP.items() } + +@dataclass(frozen=True, kw_only=True) +class HomeConnectProgramSelectEntityDescription( + SelectEntityDescription, +): + """Entity Description class for select entities for programs.""" + + allowed_executions: tuple[Execution, ...] + set_program_fn: Callable[ + [HomeConnectClient, str, ProgramKey], Coroutine[Any, Any, None] + ] + error_translation_key: str + + PROGRAM_SELECT_ENTITY_DESCRIPTIONS = ( - SelectEntityDescription( + HomeConnectProgramSelectEntityDescription( key=EventKey.BSH_COMMON_ROOT_ACTIVE_PROGRAM, translation_key="active_program", + allowed_executions=(Execution.SELECT_AND_START, Execution.START_ONLY), + set_program_fn=lambda client, ha_id, program_key: client.start_program( + ha_id, program_key=program_key + ), + error_translation_key="start_program", ), - SelectEntityDescription( + HomeConnectProgramSelectEntityDescription( key=EventKey.BSH_COMMON_ROOT_SELECTED_PROGRAM, translation_key="selected_program", + allowed_executions=(Execution.SELECT_AND_START, Execution.SELECT_ONLY), + set_program_fn=lambda client, ha_id, program_key: client.set_selected_program( + ha_id, program_key=program_key + ), + error_translation_key="select_program", ), ) @@ -59,11 +87,13 @@ async def async_setup_entry( class HomeConnectProgramSelectEntity(HomeConnectEntity, SelectEntity): """Select class for Home Connect programs.""" + entity_description: HomeConnectProgramSelectEntityDescription + def __init__( self, coordinator: HomeConnectCoordinator, appliance: HomeConnectApplianceData, - desc: SelectEntityDescription, + desc: HomeConnectProgramSelectEntityDescription, ) -> None: """Initialize the entity.""" super().__init__( @@ -75,8 +105,11 @@ class HomeConnectProgramSelectEntity(HomeConnectEntity, SelectEntity): PROGRAMS_TRANSLATION_KEYS_MAP[program.key] for program in appliance.programs if program.key != ProgramKey.UNKNOWN + and ( + program.constraints is None + or program.constraints.execution in desc.allowed_executions + ) ] - self.start_on_select = desc.key == EventKey.BSH_COMMON_ROOT_ACTIVE_PROGRAM self._attr_current_option = None def update_native_value(self) -> None: @@ -92,22 +125,15 @@ class HomeConnectProgramSelectEntity(HomeConnectEntity, SelectEntity): """Select new program.""" program_key = TRANSLATION_KEYS_PROGRAMS_MAP[option] try: - if self.start_on_select: - await self.coordinator.client.start_program( - self.appliance.info.ha_id, program_key=program_key - ) - else: - await self.coordinator.client.set_selected_program( - self.appliance.info.ha_id, program_key=program_key - ) + await self.entity_description.set_program_fn( + self.coordinator.client, + self.appliance.info.ha_id, + program_key, + ) except HomeConnectError as err: - if self.start_on_select: - translation_key = "start_program" - else: - translation_key = "select_program" raise HomeAssistantError( translation_domain=DOMAIN, - translation_key=translation_key, + translation_key=self.entity_description.error_translation_key, translation_placeholders={ **get_dict_from_home_connect_error(err), SVE_TRANSLATION_PLACEHOLDER_PROGRAM: program_key.value, diff --git a/tests/components/home_connect/test_select.py b/tests/components/home_connect/test_select.py index a0cdd15bf31..fb75e4fbc22 100644 --- a/tests/components/home_connect/test_select.py +++ b/tests/components/home_connect/test_select.py @@ -13,7 +13,11 @@ from aiohomeconnect.model import ( ProgramKey, ) from aiohomeconnect.model.error import HomeConnectError -from aiohomeconnect.model.program import EnumerateProgram +from aiohomeconnect.model.program import ( + EnumerateProgram, + EnumerateProgramConstraints, + Execution, +) import pytest from homeassistant.components.select import ( @@ -53,25 +57,42 @@ async def test_select( assert config_entry.state is ConfigEntryState.LOADED -async def test_filter_unknown_programs( +async def test_filter_programs( config_entry: MockConfigEntry, integration_setup: Callable[[MagicMock], Awaitable[bool]], setup_credentials: None, client: MagicMock, entity_registry: er.EntityRegistry, ) -> None: - """Test select that only known programs are shown.""" + """Test select that only right programs are shown.""" client.get_all_programs.side_effect = None client.get_all_programs.return_value = ArrayOfPrograms( [ EnumerateProgram( key=ProgramKey.DISHCARE_DISHWASHER_ECO_50, raw_key=ProgramKey.DISHCARE_DISHWASHER_ECO_50.value, + constraints=EnumerateProgramConstraints( + execution=Execution.SELECT_ONLY, + ), ), EnumerateProgram( key=ProgramKey.UNKNOWN, raw_key="an unknown program", ), + EnumerateProgram( + key=ProgramKey.DISHCARE_DISHWASHER_QUICK_45, + raw_key=ProgramKey.DISHCARE_DISHWASHER_QUICK_45.value, + constraints=EnumerateProgramConstraints( + execution=Execution.START_ONLY, + ), + ), + EnumerateProgram( + key=ProgramKey.DISHCARE_DISHWASHER_AUTO_1, + raw_key=ProgramKey.DISHCARE_DISHWASHER_AUTO_1.value, + constraints=EnumerateProgramConstraints( + execution=Execution.SELECT_AND_START, + ), + ), ] ) @@ -82,7 +103,18 @@ async def test_filter_unknown_programs( entity = entity_registry.async_get("select.dishwasher_selected_program") assert entity assert entity.capabilities - assert entity.capabilities[ATTR_OPTIONS] == ["dishcare_dishwasher_program_eco_50"] + assert entity.capabilities[ATTR_OPTIONS] == [ + "dishcare_dishwasher_program_eco_50", + "dishcare_dishwasher_program_auto_1", + ] + + entity = entity_registry.async_get("select.dishwasher_active_program") + assert entity + assert entity.capabilities + assert entity.capabilities[ATTR_OPTIONS] == [ + "dishcare_dishwasher_program_quick_45", + "dishcare_dishwasher_program_auto_1", + ] @pytest.mark.parametrize(