From fa5af8f187a1b3cfaebb9438a55f96e535e0ff6a Mon Sep 17 00:00:00 2001 From: Luke Lashley Date: Tue, 16 Jan 2024 15:00:20 -0500 Subject: [PATCH] Add Translation for Roborock exceptions (#105427) * add translations to exceptions * Make errors more user understandable * make command not ternary operator * removed non-user facing exceptions * Add user facing exceptions and code coverage * add match * fix linting * Apply suggestions from code review Co-authored-by: Franck Nijhof --------- Co-authored-by: Franck Nijhof --- homeassistant/components/roborock/__init__.py | 18 +++++++++++++--- homeassistant/components/roborock/device.py | 13 ++++++++++-- homeassistant/components/roborock/image.py | 6 +++++- .../components/roborock/strings.json | 17 +++++++++++++++ tests/components/roborock/test_vacuum.py | 21 +++++++++++++++++++ 5 files changed, 69 insertions(+), 6 deletions(-) diff --git a/homeassistant/components/roborock/__init__.py b/homeassistant/components/roborock/__init__.py index 25c1fbb041f..0b4dfa29e78 100644 --- a/homeassistant/components/roborock/__init__.py +++ b/homeassistant/components/roborock/__init__.py @@ -35,9 +35,17 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: try: home_data = await api_client.get_home_data(user_data) except RoborockInvalidCredentials as err: - raise ConfigEntryAuthFailed("Invalid credentials.") from err + raise ConfigEntryAuthFailed( + "Invalid credentials", + translation_domain=DOMAIN, + translation_key="invalid_credentials", + ) from err except RoborockException as err: - raise ConfigEntryNotReady("Failed getting Roborock home_data.") from err + raise ConfigEntryNotReady( + "Failed to get Roborock home data", + translation_domain=DOMAIN, + translation_key="home_data_fail", + ) from err _LOGGER.debug("Got home data %s", home_data) device_map: dict[str, HomeDataDevice] = { device.duid: device for device in home_data.devices + home_data.received_devices @@ -57,7 +65,11 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: if isinstance(coord, RoborockDataUpdateCoordinator) ] if len(valid_coordinators) == 0: - raise ConfigEntryNotReady("No coordinators were able to successfully setup.") + raise ConfigEntryNotReady( + "No devices were able to successfully setup", + translation_domain=DOMAIN, + translation_key="no_coordinators", + ) hass.data.setdefault(DOMAIN, {})[entry.entry_id] = { coordinator.roborock_device_info.device.duid: coordinator for coordinator in valid_coordinators diff --git a/homeassistant/components/roborock/device.py b/homeassistant/components/roborock/device.py index 71376dd600e..17531f6c627 100644 --- a/homeassistant/components/roborock/device.py +++ b/homeassistant/components/roborock/device.py @@ -15,6 +15,7 @@ from homeassistant.helpers.entity import Entity from homeassistant.helpers.update_coordinator import CoordinatorEntity from . import RoborockDataUpdateCoordinator +from .const import DOMAIN class RoborockEntity(Entity): @@ -48,10 +49,18 @@ class RoborockEntity(Entity): try: response: dict = await self._api.send_command(command, params) except RoborockException as err: + if isinstance(command, RoborockCommand): + command_name = command.name + else: + command_name = command raise HomeAssistantError( - f"Error while calling {command.name if isinstance(command, RoborockCommand) else command} with {params}" + f"Error while calling {command}", + translation_domain=DOMAIN, + translation_key="command_failed", + translation_placeholders={ + "command": command_name, + }, ) from err - return response diff --git a/homeassistant/components/roborock/image.py b/homeassistant/components/roborock/image.py index 5e61bb1d408..b2a14b57819 100644 --- a/homeassistant/components/roborock/image.py +++ b/homeassistant/components/roborock/image.py @@ -109,7 +109,11 @@ class RoborockMap(RoborockCoordinatedEntity, ImageEntity): """Create an image using the map parser.""" parsed_map = self.parser.parse(map_bytes) if parsed_map.image is None: - raise HomeAssistantError("Something went wrong creating the map.") + raise HomeAssistantError( + "Something went wrong creating the map", + translation_domain=DOMAIN, + translation_key="map_failure", + ) img_byte_arr = io.BytesIO() parsed_map.image.data.save(img_byte_arr, format="PNG") return img_byte_arr.getvalue() diff --git a/homeassistant/components/roborock/strings.json b/homeassistant/components/roborock/strings.json index b24b3501ed8..7c457a1935b 100644 --- a/homeassistant/components/roborock/strings.json +++ b/homeassistant/components/roborock/strings.json @@ -276,5 +276,22 @@ } } } + }, + "exceptions": { + "command_failed": { + "message": "Error while calling {command}" + }, + "home_data_fail": { + "message": "Failed to get Roborock home data" + }, + "invalid_credentials": { + "message": "Invalid credentials." + }, + "map_failure": { + "message": "Something went wrong creating the map" + }, + "no_coordinators": { + "message": "No devices were able to successfully setup" + } } } diff --git a/tests/components/roborock/test_vacuum.py b/tests/components/roborock/test_vacuum.py index c8970517dce..ecc501cc542 100644 --- a/tests/components/roborock/test_vacuum.py +++ b/tests/components/roborock/test_vacuum.py @@ -5,6 +5,7 @@ from typing import Any from unittest.mock import patch import pytest +from roborock import RoborockException from roborock.roborock_typing import RoborockCommand from homeassistant.components.vacuum import ( @@ -19,6 +20,7 @@ from homeassistant.components.vacuum import ( ) from homeassistant.const import ATTR_ENTITY_ID, Platform from homeassistant.core import HomeAssistant +from homeassistant.exceptions import HomeAssistantError from homeassistant.helpers import entity_registry as er from tests.common import MockConfigEntry @@ -86,3 +88,22 @@ async def test_commands( assert mock_send_command.call_count == 1 assert mock_send_command.call_args[0][0] == command assert mock_send_command.call_args[0][1] == called_params + + +async def test_failed_user_command( + hass: HomeAssistant, + bypass_api_fixture, + setup_entry: MockConfigEntry, +) -> None: + """Test that when a user sends an invalid command, we raise HomeAssistantError.""" + data = {ATTR_ENTITY_ID: ENTITY_ID, **{"command": "fake_command"}} + with patch( + "homeassistant.components.roborock.coordinator.RoborockLocalClient.send_command", + side_effect=RoborockException(), + ), pytest.raises(HomeAssistantError, match="Error while calling fake_command"): + await hass.services.async_call( + Platform.VACUUM, + SERVICE_SEND_COMMAND, + data, + blocking=True, + )