mirror of
https://github.com/home-assistant/core.git
synced 2025-07-23 05:07:41 +00:00
Fix fetch options error for Home connect (#139392)
* Handle errors when obtaining options definitions * Don't fetch program options if the program key is unknown * Test to ensure that available program endpoint is not called on unknown program
This commit is contained in:
parent
585b950a46
commit
fa6d7d5e3c
@ -440,13 +440,27 @@ class HomeConnectCoordinator(
|
|||||||
self, ha_id: str, program_key: ProgramKey
|
self, ha_id: str, program_key: ProgramKey
|
||||||
) -> dict[OptionKey, ProgramDefinitionOption]:
|
) -> dict[OptionKey, ProgramDefinitionOption]:
|
||||||
"""Get options with constraints for appliance."""
|
"""Get options with constraints for appliance."""
|
||||||
|
if program_key is ProgramKey.UNKNOWN:
|
||||||
|
return {}
|
||||||
|
try:
|
||||||
return {
|
return {
|
||||||
option.key: option
|
option.key: option
|
||||||
for option in (
|
for option in (
|
||||||
await self.client.get_available_program(ha_id, program_key=program_key)
|
await self.client.get_available_program(
|
||||||
|
ha_id, program_key=program_key
|
||||||
|
)
|
||||||
).options
|
).options
|
||||||
or []
|
or []
|
||||||
}
|
}
|
||||||
|
except HomeConnectError as error:
|
||||||
|
_LOGGER.debug(
|
||||||
|
"Error fetching options for %s: %s",
|
||||||
|
ha_id,
|
||||||
|
error
|
||||||
|
if isinstance(error, HomeConnectApiError)
|
||||||
|
else type(error).__name__,
|
||||||
|
)
|
||||||
|
return {}
|
||||||
|
|
||||||
async def update_options(
|
async def update_options(
|
||||||
self, ha_id: str, event_key: EventKey, program_key: ProgramKey
|
self, ha_id: str, event_key: EventKey, program_key: ProgramKey
|
||||||
@ -456,7 +470,6 @@ class HomeConnectCoordinator(
|
|||||||
events = self.data[ha_id].events
|
events = self.data[ha_id].events
|
||||||
options_to_notify = options.copy()
|
options_to_notify = options.copy()
|
||||||
options.clear()
|
options.clear()
|
||||||
if program_key is not ProgramKey.UNKNOWN:
|
|
||||||
options.update(await self.get_options_definitions(ha_id, program_key))
|
options.update(await self.get_options_definitions(ha_id, program_key))
|
||||||
|
|
||||||
for option in options.values():
|
for option in options.values():
|
||||||
|
@ -75,21 +75,35 @@ async def test_coordinator_update_failing_get_appliances(
|
|||||||
assert config_entry.state == ConfigEntryState.SETUP_RETRY
|
assert config_entry.state == ConfigEntryState.SETUP_RETRY
|
||||||
|
|
||||||
|
|
||||||
async def test_coordinator_update_failing_get_settings_status(
|
@pytest.mark.parametrize(
|
||||||
|
"mock_method",
|
||||||
|
[
|
||||||
|
"get_settings",
|
||||||
|
"get_status",
|
||||||
|
"get_all_programs",
|
||||||
|
"get_available_commands",
|
||||||
|
"get_available_program",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
async def test_coordinator_update_failing(
|
||||||
|
mock_method: str,
|
||||||
config_entry: MockConfigEntry,
|
config_entry: MockConfigEntry,
|
||||||
integration_setup: Callable[[MagicMock], Awaitable[bool]],
|
integration_setup: Callable[[MagicMock], Awaitable[bool]],
|
||||||
setup_credentials: None,
|
setup_credentials: None,
|
||||||
client_with_exception: MagicMock,
|
client: MagicMock,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test that although is not possible to get settings and status, the config entry is loaded.
|
"""Test that although is not possible to get settings and status, the config entry is loaded.
|
||||||
|
|
||||||
This is for cases where some appliances are reachable and some are not in the same configuration entry.
|
This is for cases where some appliances are reachable and some are not in the same configuration entry.
|
||||||
"""
|
"""
|
||||||
# Get home appliances does pass at client_with_exception.get_home_appliances mock, so no need to mock it again
|
setattr(client, mock_method, AsyncMock(side_effect=HomeConnectError()))
|
||||||
|
|
||||||
assert config_entry.state == ConfigEntryState.NOT_LOADED
|
assert config_entry.state == ConfigEntryState.NOT_LOADED
|
||||||
await integration_setup(client_with_exception)
|
await integration_setup(client)
|
||||||
assert config_entry.state == ConfigEntryState.LOADED
|
assert config_entry.state == ConfigEntryState.LOADED
|
||||||
|
|
||||||
|
getattr(client, mock_method).assert_called()
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("appliance_ha_id", ["Dishwasher"], indirect=True)
|
@pytest.mark.parametrize("appliance_ha_id", ["Dishwasher"], indirect=True)
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
|
@ -23,6 +23,7 @@ from aiohomeconnect.model.error import (
|
|||||||
SelectedProgramNotSetError,
|
SelectedProgramNotSetError,
|
||||||
)
|
)
|
||||||
from aiohomeconnect.model.program import (
|
from aiohomeconnect.model.program import (
|
||||||
|
EnumerateProgram,
|
||||||
ProgramDefinitionConstraints,
|
ProgramDefinitionConstraints,
|
||||||
ProgramDefinitionOption,
|
ProgramDefinitionOption,
|
||||||
)
|
)
|
||||||
@ -234,6 +235,78 @@ async def test_program_options_retrieval(
|
|||||||
assert hass.states.is_state(entity_id, STATE_UNKNOWN)
|
assert hass.states.is_state(entity_id, STATE_UNKNOWN)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
("array_of_programs_program_arg", "event_key"),
|
||||||
|
[
|
||||||
|
(
|
||||||
|
"active",
|
||||||
|
EventKey.BSH_COMMON_ROOT_ACTIVE_PROGRAM,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"selected",
|
||||||
|
EventKey.BSH_COMMON_ROOT_SELECTED_PROGRAM,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
async def test_no_options_retrieval_on_unknown_program(
|
||||||
|
array_of_programs_program_arg: str,
|
||||||
|
event_key: EventKey,
|
||||||
|
appliance_ha_id: str,
|
||||||
|
hass: HomeAssistant,
|
||||||
|
config_entry: MockConfigEntry,
|
||||||
|
integration_setup: Callable[[MagicMock], Awaitable[bool]],
|
||||||
|
setup_credentials: None,
|
||||||
|
client: MagicMock,
|
||||||
|
) -> None:
|
||||||
|
"""Test that no options are retrieved when the program is unknown."""
|
||||||
|
|
||||||
|
async def get_all_programs_with_options_mock(ha_id: str) -> ArrayOfPrograms:
|
||||||
|
return ArrayOfPrograms(
|
||||||
|
**(
|
||||||
|
{
|
||||||
|
"programs": [
|
||||||
|
EnumerateProgram(ProgramKey.UNKNOWN, "unknown program")
|
||||||
|
],
|
||||||
|
array_of_programs_program_arg: Program(
|
||||||
|
ProgramKey.UNKNOWN, options=[]
|
||||||
|
),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
client.get_all_programs = AsyncMock(side_effect=get_all_programs_with_options_mock)
|
||||||
|
|
||||||
|
assert config_entry.state == ConfigEntryState.NOT_LOADED
|
||||||
|
assert await integration_setup(client)
|
||||||
|
assert config_entry.state == ConfigEntryState.LOADED
|
||||||
|
|
||||||
|
assert client.get_available_program.call_count == 0
|
||||||
|
|
||||||
|
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.UNKNOWN,
|
||||||
|
)
|
||||||
|
]
|
||||||
|
),
|
||||||
|
)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
assert client.get_available_program.call_count == 0
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
"event_key",
|
"event_key",
|
||||||
[
|
[
|
||||||
|
Loading…
x
Reference in New Issue
Block a user