diff --git a/homeassistant/components/home_connect/common.py b/homeassistant/components/home_connect/common.py index a9f48eea5ba..f52b59bc213 100644 --- a/homeassistant/components/home_connect/common.py +++ b/homeassistant/components/home_connect/common.py @@ -72,22 +72,27 @@ def _handle_paired_or_connected_appliance( for entity in get_option_entities_for_appliance(entry, appliance) if entity.unique_id not in known_entity_unique_ids ) - changed_options_listener_remove_callback = ( - entry.runtime_data.async_add_listener( - partial( - _create_option_entities, - entry, - appliance, - known_entity_unique_ids, - get_option_entities_for_appliance, - async_add_entities, - ), + for event_key in ( + EventKey.BSH_COMMON_ROOT_ACTIVE_PROGRAM, + EventKey.BSH_COMMON_ROOT_SELECTED_PROGRAM, + ): + changed_options_listener_remove_callback = ( + entry.runtime_data.async_add_listener( + partial( + _create_option_entities, + entry, + appliance, + known_entity_unique_ids, + get_option_entities_for_appliance, + async_add_entities, + ), + (appliance.info.ha_id, event_key), + ) + ) + entry.async_on_unload(changed_options_listener_remove_callback) + changed_options_listener_remove_callbacks[appliance.info.ha_id].append( + changed_options_listener_remove_callback ) - ) - entry.async_on_unload(changed_options_listener_remove_callback) - changed_options_listener_remove_callbacks[appliance.info.ha_id].append( - changed_options_listener_remove_callback - ) known_entity_unique_ids.update( { cast(str, entity.unique_id): appliance.info.ha_id diff --git a/tests/components/home_connect/test_entity.py b/tests/components/home_connect/test_entity.py index 272fc21ba62..f173cda0b0c 100644 --- a/tests/components/home_connect/test_entity.py +++ b/tests/components/home_connect/test_entity.py @@ -5,6 +5,7 @@ from unittest.mock import AsyncMock, MagicMock from aiohomeconnect.model import ( ArrayOfEvents, + ArrayOfHomeAppliances, ArrayOfPrograms, Event, EventKey, @@ -233,6 +234,126 @@ async def test_program_options_retrieval( assert hass.states.is_state(entity_id, STATE_UNKNOWN) +@pytest.mark.parametrize( + "event_key", + [ + EventKey.BSH_COMMON_ROOT_ACTIVE_PROGRAM, + EventKey.BSH_COMMON_ROOT_SELECTED_PROGRAM, + ], +) +@pytest.mark.parametrize( + ("appliance_ha_id", "option_key", "option_entity_id"), + [ + ( + "Dishwasher", + OptionKey.DISHCARE_DISHWASHER_HALF_LOAD, + "switch.dishwasher_half_load", + ) + ], + indirect=["appliance_ha_id"], +) +async def test_program_options_retrieval_after_appliance_connection( + event_key: EventKey, + appliance_ha_id: str, + option_key: OptionKey, + option_entity_id: str, + hass: HomeAssistant, + config_entry: MockConfigEntry, + integration_setup: Callable[[MagicMock], Awaitable[bool]], + setup_credentials: None, + client: MagicMock, +) -> None: + """Test that the options are correctly retrieved at the start and updated on program updates.""" + array_of_home_appliances = client.get_home_appliances.return_value + + async def get_home_appliances_with_options_mock() -> ArrayOfHomeAppliances: + return ArrayOfHomeAppliances( + [ + appliance + for appliance in array_of_home_appliances.homeappliances + if appliance.ha_id != appliance_ha_id + ] + ) + + client.get_home_appliances = AsyncMock( + side_effect=get_home_appliances_with_options_mock + ) + client.get_available_program = AsyncMock( + return_value=ProgramDefinition( + ProgramKey.UNKNOWN, + options=[], + ) + ) + + assert config_entry.state == ConfigEntryState.NOT_LOADED + assert await integration_setup(client) + assert config_entry.state == ConfigEntryState.LOADED + + assert not hass.states.get(option_entity_id) + + await client.add_events( + [ + EventMessage( + appliance_ha_id, + EventType.CONNECTED, + data=ArrayOfEvents( + [ + Event( + key=EventKey.BSH_COMMON_APPLIANCE_CONNECTED, + raw_key=EventKey.BSH_COMMON_APPLIANCE_CONNECTED.value, + timestamp=0, + level="", + handling="", + value="", + ) + ] + ), + ) + ] + ) + await hass.async_block_till_done() + + assert not hass.states.get(option_entity_id) + + client.get_available_program = AsyncMock( + return_value=ProgramDefinition( + ProgramKey.UNKNOWN, + options=[ + ProgramDefinitionOption( + option_key, + "Boolean", + constraints=ProgramDefinitionConstraints( + default=False, + ), + ), + ], + ) + ) + await client.add_events( + [ + EventMessage( + appliance_ha_id, + EventType.NOTIFY, + data=ArrayOfEvents( + [ + Event( + key=event_key, + raw_key=event_key.value, + timestamp=0, + level="", + handling="", + value=ProgramKey.DISHCARE_DISHWASHER_AUTO_1, + ) + ] + ), + ) + ] + ) + await hass.async_block_till_done() + + assert hass.states.get(option_entity_id) + + @pytest.mark.parametrize( ( "set_active_program_option_side_effect",