Add ServiceValidationError to Home Connect (#129309)

Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
This commit is contained in:
J. Diego Rodríguez Royo 2024-10-28 16:48:56 +01:00 committed by GitHub
parent cbfa3bb56d
commit 668626b920
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 285 additions and 60 deletions

View File

@ -303,3 +303,14 @@ async def async_migrate_entry(hass: HomeAssistant, config_entry: ConfigEntry) ->
_LOGGER.debug("Migration to version %s successful", config_entry.version)
return True
def get_dict_from_home_connect_error(err: api.HomeConnectError) -> dict[str, Any]:
"""Return a dict from a Home Connect error."""
return (
err.args[0]
if len(err.args) > 0 and isinstance(err.args[0], dict)
else {"description": err.args[0]}
if len(err.args) > 0 and isinstance(err.args[0], str)
else {}
)

View File

@ -114,6 +114,11 @@ ATTR_STEPSIZE = "stepsize"
ATTR_UNIT = "unit"
ATTR_VALUE = "value"
SVE_TRANSLATION_PLACEHOLDER_APPLIANCE_NAME = "appliance_name"
SVE_TRANSLATION_PLACEHOLDER_ENTITY_ID = "entity_id"
SVE_TRANSLATION_PLACEHOLDER_SETTING_KEY = "setting_key"
SVE_TRANSLATION_PLACEHOLDER_VALUE = "value"
OLD_NEW_UNIQUE_ID_SUFFIX_MAP = {
"ChildLock": BSH_CHILD_LOCK_STATE,
"Operation State": BSH_OPERATION_STATE,

View File

@ -17,9 +17,11 @@ from homeassistant.components.light import (
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ServiceValidationError
from homeassistant.helpers.entity_platform import AddEntitiesCallback
import homeassistant.util.color as color_util
from . import get_dict_from_home_connect_error
from .api import ConfigEntryAuth, HomeConnectDevice
from .const import (
ATTR_VALUE,
@ -35,6 +37,7 @@ from .const import (
REFRIGERATION_EXTERNAL_LIGHT_POWER,
REFRIGERATION_INTERNAL_LIGHT_BRIGHTNESS,
REFRIGERATION_INTERNAL_LIGHT_POWER,
SVE_TRANSLATION_PLACEHOLDER_ENTITY_ID,
)
from .entity import HomeConnectEntity
@ -149,8 +152,14 @@ class HomeConnectLight(HomeConnectEntity, LightEntity):
self.device.appliance.set_setting, self.bsh_key, True
)
except HomeConnectError as err:
_LOGGER.error("Error while trying to turn on light: %s", err)
return
raise ServiceValidationError(
translation_domain=DOMAIN,
translation_key="turn_on_light",
translation_placeholders={
**get_dict_from_home_connect_error(err),
SVE_TRANSLATION_PLACEHOLDER_ENTITY_ID: self.entity_id,
},
) from err
if self._custom_color_key:
if (
ATTR_RGB_COLOR in kwargs or ATTR_HS_COLOR in kwargs
@ -162,8 +171,14 @@ class HomeConnectLight(HomeConnectEntity, LightEntity):
self._enable_custom_color_value_key,
)
except HomeConnectError as err:
_LOGGER.error("Error while trying selecting custom color: %s", err)
return
raise ServiceValidationError(
translation_domain=DOMAIN,
translation_key="select_light_custom_color",
translation_placeholders={
**get_dict_from_home_connect_error(err),
SVE_TRANSLATION_PLACEHOLDER_ENTITY_ID: self.entity_id,
},
) from err
if ATTR_RGB_COLOR in kwargs:
hex_val = color_util.color_rgb_to_hex(*kwargs[ATTR_RGB_COLOR])
@ -174,7 +189,14 @@ class HomeConnectLight(HomeConnectEntity, LightEntity):
f"#{hex_val}",
)
except HomeConnectError as err:
_LOGGER.error("Error while trying setting the color: %s", err)
raise ServiceValidationError(
translation_domain=DOMAIN,
translation_key="set_light_color",
translation_placeholders={
**get_dict_from_home_connect_error(err),
SVE_TRANSLATION_PLACEHOLDER_ENTITY_ID: self.entity_id,
},
) from err
elif (ATTR_BRIGHTNESS in kwargs or ATTR_HS_COLOR in kwargs) and (
self._attr_brightness is not None or ATTR_BRIGHTNESS in kwargs
):
@ -199,7 +221,14 @@ class HomeConnectLight(HomeConnectEntity, LightEntity):
f"#{hex_val}",
)
except HomeConnectError as err:
_LOGGER.error("Error while trying setting the color: %s", err)
raise ServiceValidationError(
translation_domain=DOMAIN,
translation_key="set_light_color",
translation_placeholders={
**get_dict_from_home_connect_error(err),
SVE_TRANSLATION_PLACEHOLDER_ENTITY_ID: self.entity_id,
},
) from err
elif self._brightness_key and ATTR_BRIGHTNESS in kwargs:
_LOGGER.debug(
@ -217,7 +246,14 @@ class HomeConnectLight(HomeConnectEntity, LightEntity):
self.device.appliance.set_setting, self._brightness_key, brightness
)
except HomeConnectError as err:
_LOGGER.error("Error while trying set the brightness: %s", err)
raise ServiceValidationError(
translation_domain=DOMAIN,
translation_key="set_light_brightness",
translation_placeholders={
**get_dict_from_home_connect_error(err),
SVE_TRANSLATION_PLACEHOLDER_ENTITY_ID: self.entity_id,
},
) from err
self.async_entity_update()
@ -229,7 +265,14 @@ class HomeConnectLight(HomeConnectEntity, LightEntity):
self.device.appliance.set_setting, self.bsh_key, False
)
except HomeConnectError as err:
_LOGGER.error("Error while trying to turn off light: %s", err)
raise ServiceValidationError(
translation_domain=DOMAIN,
translation_key="turn_off_light",
translation_placeholders={
**get_dict_from_home_connect_error(err),
SVE_TRANSLATION_PLACEHOLDER_ENTITY_ID: self.entity_id,
},
) from err
self.async_entity_update()
async def async_update(self) -> None:

View File

@ -13,10 +13,21 @@ from homeassistant.components.number import (
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ServiceValidationError
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from . import get_dict_from_home_connect_error
from .api import ConfigEntryAuth
from .const import ATTR_CONSTRAINTS, ATTR_STEPSIZE, ATTR_UNIT, ATTR_VALUE, DOMAIN
from .const import (
ATTR_CONSTRAINTS,
ATTR_STEPSIZE,
ATTR_UNIT,
ATTR_VALUE,
DOMAIN,
SVE_TRANSLATION_PLACEHOLDER_ENTITY_ID,
SVE_TRANSLATION_PLACEHOLDER_SETTING_KEY,
SVE_TRANSLATION_PLACEHOLDER_VALUE,
)
from .entity import HomeConnectEntity
_LOGGER = logging.getLogger(__name__)
@ -109,13 +120,16 @@ class HomeConnectNumberEntity(HomeConnectEntity, NumberEntity):
value,
)
except HomeConnectError as err:
_LOGGER.error(
"Error setting value %s to %s for %s: %s",
value,
self.bsh_key,
self.entity_id,
err,
)
raise ServiceValidationError(
translation_domain=DOMAIN,
translation_key="set_setting",
translation_placeholders={
**get_dict_from_home_connect_error(err),
SVE_TRANSLATION_PLACEHOLDER_ENTITY_ID: self.entity_id,
SVE_TRANSLATION_PLACEHOLDER_SETTING_KEY: self.bsh_key,
SVE_TRANSLATION_PLACEHOLDER_VALUE: str(value),
},
) from err
async def async_fetch_constraints(self) -> None:
"""Fetch the max and min values and step for the number entity."""

View File

@ -21,6 +21,50 @@
"default": "[%key:common::config_flow::create_entry::authenticated%]"
}
},
"exceptions": {
"turn_on_light": {
"message": "Error while trying to turn on {entity_id}: {description}"
},
"turn_off_light": {
"message": "Error while trying to turn off {entity_id}: {description}"
},
"set_light_brightness": {
"message": "Error while trying to set brightness of {entity_id}: {description}"
},
"select_light_custom_color": {
"message": "Error while trying to select custom color of {entity_id}: {description}"
},
"set_light_color": {
"message": "Error while trying to set color of {entity_id}: {description}"
},
"set_light_effect": {
"message": "Error while trying to set effect of {entity_id}: {description}"
},
"set_setting": {
"message": "Error while trying to set \"{value}\" to \"{key}\" setting for {entity_id}: {description}"
},
"turn_on": {
"message": "Error while trying to turn on {entity_id} ({key}): {description}"
},
"turn_off": {
"message": "Error while trying to turn off {entity_id} ({key}): {description}"
},
"start_program": {
"message": "Error while trying to start program {program}: {description}"
},
"stop_program": {
"message": "Error while trying to stop program {program}: {description}"
},
"power_on": {
"message": "Error while trying to turn on {appliance_name}: {description}"
},
"power_off": {
"message": "Error while trying to turn off {appliance_name} with value \"{value}\": {description}"
},
"turn_off_not_supported": {
"message": "{appliance_name} does not support turning off or entering standby mode."
}
},
"services": {
"start_program": {
"name": "Start program",

View File

@ -9,8 +9,10 @@ from homeconnect.api import HomeConnectError
from homeassistant.components.switch import SwitchEntity, SwitchEntityDescription
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ServiceValidationError
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from . import get_dict_from_home_connect_error
from .api import ConfigEntryAuth
from .const import (
ATTR_VALUE,
@ -25,6 +27,10 @@ from .const import (
REFRIGERATION_DISPENSER,
REFRIGERATION_SUPERMODEFREEZER,
REFRIGERATION_SUPERMODEREFRIGERATOR,
SVE_TRANSLATION_PLACEHOLDER_APPLIANCE_NAME,
SVE_TRANSLATION_PLACEHOLDER_ENTITY_ID,
SVE_TRANSLATION_PLACEHOLDER_SETTING_KEY,
SVE_TRANSLATION_PLACEHOLDER_VALUE,
)
from .entity import HomeConnectDevice, HomeConnectEntity
@ -139,9 +145,16 @@ class HomeConnectSwitch(HomeConnectEntity, SwitchEntity):
self.device.appliance.set_setting, self.entity_description.key, True
)
except HomeConnectError as err:
_LOGGER.error("Error while trying to turn on: %s", err)
self._attr_available = False
return
raise ServiceValidationError(
translation_domain=DOMAIN,
translation_key="turn_on",
translation_placeholders={
**get_dict_from_home_connect_error(err),
SVE_TRANSLATION_PLACEHOLDER_ENTITY_ID: self.entity_id,
SVE_TRANSLATION_PLACEHOLDER_SETTING_KEY: self.bsh_key,
},
) from err
self._attr_available = True
self.async_entity_update()
@ -157,7 +170,15 @@ class HomeConnectSwitch(HomeConnectEntity, SwitchEntity):
except HomeConnectError as err:
_LOGGER.error("Error while trying to turn off: %s", err)
self._attr_available = False
return
raise ServiceValidationError(
translation_domain=DOMAIN,
translation_key="turn_off",
translation_placeholders={
**get_dict_from_home_connect_error(err),
SVE_TRANSLATION_PLACEHOLDER_ENTITY_ID: self.entity_id,
SVE_TRANSLATION_PLACEHOLDER_SETTING_KEY: self.bsh_key,
},
) from err
self._attr_available = True
self.async_entity_update()
@ -200,7 +221,14 @@ class HomeConnectProgramSwitch(HomeConnectEntity, SwitchEntity):
self.device.appliance.start_program, self.program_name
)
except HomeConnectError as err:
_LOGGER.error("Error while trying to start program: %s", err)
raise ServiceValidationError(
translation_domain=DOMAIN,
translation_key="start_program",
translation_placeholders={
**get_dict_from_home_connect_error(err),
"program": self.program_name,
},
) from err
self.async_entity_update()
async def async_turn_off(self, **kwargs: Any) -> None:
@ -209,7 +237,14 @@ class HomeConnectProgramSwitch(HomeConnectEntity, SwitchEntity):
try:
await self.hass.async_add_executor_job(self.device.appliance.stop_program)
except HomeConnectError as err:
_LOGGER.error("Error while trying to stop program: %s", err)
raise ServiceValidationError(
translation_domain=DOMAIN,
translation_key="stop_program",
translation_placeholders={
**get_dict_from_home_connect_error(err),
"program": self.program_name,
},
) from err
self.async_entity_update()
async def async_update(self) -> None:
@ -255,15 +290,27 @@ class HomeConnectPowerSwitch(HomeConnectEntity, SwitchEntity):
self.device.appliance.set_setting, BSH_POWER_STATE, BSH_POWER_ON
)
except HomeConnectError as err:
_LOGGER.error("Error while trying to turn on device: %s", err)
self._attr_is_on = False
raise ServiceValidationError(
translation_domain=DOMAIN,
translation_key="power_on",
translation_placeholders={
**get_dict_from_home_connect_error(err),
SVE_TRANSLATION_PLACEHOLDER_APPLIANCE_NAME: self.device.appliance.name,
},
) from err
self.async_entity_update()
async def async_turn_off(self, **kwargs: Any) -> None:
"""Switch the device off."""
if self.power_off_state is None:
_LOGGER.debug("This appliance type does not support turning off")
return
raise ServiceValidationError(
translation_domain=DOMAIN,
translation_key="turn_off_not_supported",
translation_placeholders={
SVE_TRANSLATION_PLACEHOLDER_APPLIANCE_NAME: self.device.appliance.name
},
)
_LOGGER.debug("tried to switch off %s", self.name)
try:
await self.hass.async_add_executor_job(
@ -272,8 +319,16 @@ class HomeConnectPowerSwitch(HomeConnectEntity, SwitchEntity):
self.power_off_state,
)
except HomeConnectError as err:
_LOGGER.error("Error while trying to turn off device: %s", err)
self._attr_is_on = True
raise ServiceValidationError(
translation_domain=DOMAIN,
translation_key="power_off",
translation_placeholders={
**get_dict_from_home_connect_error(err),
SVE_TRANSLATION_PLACEHOLDER_APPLIANCE_NAME: self.device.appliance.name,
SVE_TRANSLATION_PLACEHOLDER_VALUE: self.power_off_state,
},
) from err
self.async_entity_update()
async def async_update(self) -> None:

View File

@ -8,10 +8,18 @@ from homeconnect.api import HomeConnectError
from homeassistant.components.time import TimeEntity, TimeEntityDescription
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ServiceValidationError
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from . import get_dict_from_home_connect_error
from .api import ConfigEntryAuth
from .const import ATTR_VALUE, DOMAIN
from .const import (
ATTR_VALUE,
DOMAIN,
SVE_TRANSLATION_PLACEHOLDER_ENTITY_ID,
SVE_TRANSLATION_PLACEHOLDER_SETTING_KEY,
SVE_TRANSLATION_PLACEHOLDER_VALUE,
)
from .entity import HomeConnectEntity
_LOGGER = logging.getLogger(__name__)
@ -75,13 +83,16 @@ class HomeConnectTimeEntity(HomeConnectEntity, TimeEntity):
time_to_seconds(value),
)
except HomeConnectError as err:
_LOGGER.error(
"Error setting value %s to %s for %s: %s",
value,
self.bsh_key,
self.entity_id,
err,
)
raise ServiceValidationError(
translation_domain=DOMAIN,
translation_key="set_setting",
translation_placeholders={
**get_dict_from_home_connect_error(err),
SVE_TRANSLATION_PLACEHOLDER_ENTITY_ID: self.entity_id,
SVE_TRANSLATION_PLACEHOLDER_SETTING_KEY: self.bsh_key,
SVE_TRANSLATION_PLACEHOLDER_VALUE: str(value),
},
) from err
async def async_update(self) -> None:
"""Update the Time setting status."""

View File

@ -27,6 +27,7 @@ from homeassistant.const import (
Platform,
)
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ServiceValidationError
from .conftest import get_all_appliances
@ -232,6 +233,7 @@ async def test_light_functionality(
"mock_attr",
"attr_side_effect",
"problematic_appliance",
"exception_match",
),
[
(
@ -246,6 +248,7 @@ async def test_light_functionality(
"set_setting",
[HomeConnectError, HomeConnectError],
"Hood",
r"Error.*turn.*on.*",
),
(
"light.hood_functional_light",
@ -260,6 +263,7 @@ async def test_light_functionality(
"set_setting",
[HomeConnectError, HomeConnectError],
"Hood",
r"Error.*turn.*on.*",
),
(
"light.hood_functional_light",
@ -271,6 +275,7 @@ async def test_light_functionality(
"set_setting",
[HomeConnectError, HomeConnectError],
"Hood",
r"Error.*turn.*off.*",
),
(
"light.hood_ambient_light",
@ -285,6 +290,7 @@ async def test_light_functionality(
"set_setting",
[HomeConnectError, HomeConnectError],
"Hood",
r"Error.*turn.*on.*",
),
(
"light.hood_ambient_light",
@ -299,6 +305,7 @@ async def test_light_functionality(
"set_setting",
[HomeConnectError, None, HomeConnectError],
"Hood",
r"Error.*set.*color.*",
),
],
indirect=["problematic_appliance"],
@ -311,6 +318,7 @@ async def test_switch_exception_handling(
mock_attr: str,
attr_side_effect: list,
problematic_appliance: Mock,
exception_match: str,
bypass_throttle: Generator[None],
hass: HomeAssistant,
integration_setup: Callable[[], Awaitable[bool]],
@ -333,5 +341,8 @@ async def test_switch_exception_handling(
problematic_appliance.status.update(status)
service_data["entity_id"] = entity_id
await hass.services.async_call(LIGHT_DOMAIN, service, service_data, blocking=True)
with pytest.raises(ServiceValidationError, match=exception_match):
await hass.services.async_call(
LIGHT_DOMAIN, service, service_data, blocking=True
)
assert getattr(problematic_appliance, mock_attr).call_count == len(attr_side_effect)

View File

@ -24,6 +24,7 @@ from homeassistant.components.number import (
from homeassistant.config_entries import ConfigEntryState
from homeassistant.const import ATTR_ENTITY_ID, Platform
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ServiceValidationError
from .conftest import get_all_appliances
@ -160,13 +161,14 @@ async def test_number_entity_error(
with pytest.raises(HomeConnectError):
getattr(problematic_appliance, mock_attr)()
await hass.services.async_call(
NUMBER_DOMAIN,
SERVICE_SET_VALUE,
{
ATTR_ENTITY_ID: entity_id,
SERVICE_ATTR_VALUE: DEFAULT_MIN_VALUE,
},
blocking=True,
)
with pytest.raises(ServiceValidationError, match=r"Error.*set.*setting.*"):
await hass.services.async_call(
NUMBER_DOMAIN,
SERVICE_SET_VALUE,
{
ATTR_ENTITY_ID: entity_id,
SERVICE_ATTR_VALUE: DEFAULT_MIN_VALUE,
},
blocking=True,
)
assert getattr(problematic_appliance, mock_attr).call_count == 2

View File

@ -26,6 +26,7 @@ from homeassistant.const import (
Platform,
)
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ServiceValidationError
from .conftest import get_all_appliances
@ -153,7 +154,14 @@ async def test_switch_functionality(
@pytest.mark.parametrize(
("entity_id", "status", "service", "mock_attr", "problematic_appliance"),
(
"entity_id",
"status",
"service",
"mock_attr",
"problematic_appliance",
"exception_match",
),
[
(
"switch.dishwasher_program_mix",
@ -161,6 +169,7 @@ async def test_switch_functionality(
SERVICE_TURN_ON,
"start_program",
"Dishwasher",
r"Error.*start.*program.*",
),
(
"switch.dishwasher_program_mix",
@ -168,6 +177,7 @@ async def test_switch_functionality(
SERVICE_TURN_OFF,
"stop_program",
"Dishwasher",
r"Error.*stop.*program.*",
),
(
"switch.dishwasher_power",
@ -175,6 +185,7 @@ async def test_switch_functionality(
SERVICE_TURN_ON,
"set_setting",
"Dishwasher",
r"Error.*turn.*on.*appliance.*",
),
(
"switch.dishwasher_power",
@ -182,6 +193,7 @@ async def test_switch_functionality(
SERVICE_TURN_OFF,
"set_setting",
"Dishwasher",
r"Error.*turn.*off.*appliance.*value.*",
),
(
"switch.dishwasher_child_lock",
@ -189,6 +201,7 @@ async def test_switch_functionality(
SERVICE_TURN_ON,
"set_setting",
"Dishwasher",
r"Error.*turn.*on.*key.*",
),
(
"switch.dishwasher_child_lock",
@ -196,6 +209,7 @@ async def test_switch_functionality(
SERVICE_TURN_OFF,
"set_setting",
"Dishwasher",
r"Error.*turn.*off.*key.*",
),
],
indirect=["problematic_appliance"],
@ -205,6 +219,7 @@ async def test_switch_exception_handling(
status: dict,
service: str,
mock_attr: str,
exception_match: str,
bypass_throttle: Generator[None],
hass: HomeAssistant,
integration_setup: Callable[[], Awaitable[bool]],
@ -227,9 +242,10 @@ async def test_switch_exception_handling(
with pytest.raises(HomeConnectError):
getattr(problematic_appliance, mock_attr)()
await hass.services.async_call(
SWITCH_DOMAIN, service, {"entity_id": entity_id}, blocking=True
)
with pytest.raises(ServiceValidationError, match=exception_match):
await hass.services.async_call(
SWITCH_DOMAIN, service, {"entity_id": entity_id}, blocking=True
)
assert getattr(problematic_appliance, mock_attr).call_count == 2
@ -289,7 +305,14 @@ async def test_ent_desc_switch_functionality(
@pytest.mark.parametrize(
("entity_id", "status", "service", "mock_attr", "problematic_appliance"),
(
"entity_id",
"status",
"service",
"mock_attr",
"problematic_appliance",
"exception_match",
),
[
(
"switch.fridgefreezer_freezer_super_mode",
@ -297,6 +320,7 @@ async def test_ent_desc_switch_functionality(
SERVICE_TURN_ON,
"set_setting",
"FridgeFreezer",
r"Error.*turn.*on.*key.*",
),
(
"switch.fridgefreezer_freezer_super_mode",
@ -304,6 +328,7 @@ async def test_ent_desc_switch_functionality(
SERVICE_TURN_OFF,
"set_setting",
"FridgeFreezer",
r"Error.*turn.*off.*key.*",
),
],
indirect=["problematic_appliance"],
@ -313,6 +338,7 @@ async def test_ent_desc_switch_exception_handling(
status: dict,
service: str,
mock_attr: str,
exception_match: str,
bypass_throttle: Generator[None],
hass: HomeAssistant,
integration_setup: Callable[[], Awaitable[bool]],
@ -341,7 +367,8 @@ async def test_ent_desc_switch_exception_handling(
getattr(problematic_appliance, mock_attr)()
problematic_appliance.status.update(status)
await hass.services.async_call(
SWITCH_DOMAIN, service, {ATTR_ENTITY_ID: entity_id}, blocking=True
)
with pytest.raises(ServiceValidationError, match=exception_match):
await hass.services.async_call(
SWITCH_DOMAIN, service, {ATTR_ENTITY_ID: entity_id}, blocking=True
)
assert getattr(problematic_appliance, mock_attr).call_count == 2

View File

@ -12,6 +12,7 @@ from homeassistant.components.time import DOMAIN as TIME_DOMAIN, SERVICE_SET_VAL
from homeassistant.config_entries import ConfigEntryState
from homeassistant.const import ATTR_ENTITY_ID, ATTR_TIME, Platform
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ServiceValidationError
from .conftest import get_all_appliances
@ -134,13 +135,14 @@ async def test_time_entity_error(
with pytest.raises(HomeConnectError):
getattr(problematic_appliance, mock_attr)()
await hass.services.async_call(
TIME_DOMAIN,
SERVICE_SET_VALUE,
{
ATTR_ENTITY_ID: entity_id,
ATTR_TIME: time(minute=1),
},
blocking=True,
)
with pytest.raises(ServiceValidationError, match=r"Error.*set.*setting.*"):
await hass.services.async_call(
TIME_DOMAIN,
SERVICE_SET_VALUE,
{
ATTR_ENTITY_ID: entity_id,
ATTR_TIME: time(minute=1),
},
blocking=True,
)
assert getattr(problematic_appliance, mock_attr).call_count == 2