mirror of
https://github.com/home-assistant/core.git
synced 2025-07-19 11:17:21 +00:00
Reolink translate errors (#132301)
This commit is contained in:
parent
c8f050ecbc
commit
19e6867f1a
@ -73,7 +73,9 @@ async def async_setup_entry(
|
|||||||
) as err:
|
) as err:
|
||||||
await host.stop()
|
await host.stop()
|
||||||
raise ConfigEntryNotReady(
|
raise ConfigEntryNotReady(
|
||||||
f"Error while trying to setup {host.api.host}:{host.api.port}: {err!s}"
|
translation_domain=DOMAIN,
|
||||||
|
translation_key="config_entry_not_ready",
|
||||||
|
translation_placeholders={"host": host.api.host, "err": str(err)},
|
||||||
) from err
|
) from err
|
||||||
except BaseException:
|
except BaseException:
|
||||||
await host.stop()
|
await host.stop()
|
||||||
|
@ -7,7 +7,6 @@ from dataclasses import dataclass
|
|||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from reolink_aio.api import GuardEnum, Host, PtzEnum
|
from reolink_aio.api import GuardEnum, Host, PtzEnum
|
||||||
from reolink_aio.exceptions import ReolinkError
|
|
||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
|
|
||||||
from homeassistant.components.button import (
|
from homeassistant.components.button import (
|
||||||
@ -18,7 +17,6 @@ from homeassistant.components.button import (
|
|||||||
from homeassistant.components.camera import CameraEntityFeature
|
from homeassistant.components.camera import CameraEntityFeature
|
||||||
from homeassistant.const import EntityCategory
|
from homeassistant.const import EntityCategory
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.exceptions import HomeAssistantError
|
|
||||||
from homeassistant.helpers import config_validation as cv
|
from homeassistant.helpers import config_validation as cv
|
||||||
from homeassistant.helpers.entity_platform import (
|
from homeassistant.helpers.entity_platform import (
|
||||||
AddEntitiesCallback,
|
AddEntitiesCallback,
|
||||||
@ -31,7 +29,7 @@ from .entity import (
|
|||||||
ReolinkHostCoordinatorEntity,
|
ReolinkHostCoordinatorEntity,
|
||||||
ReolinkHostEntityDescription,
|
ReolinkHostEntityDescription,
|
||||||
)
|
)
|
||||||
from .util import ReolinkConfigEntry, ReolinkData
|
from .util import ReolinkConfigEntry, ReolinkData, raise_translated_error
|
||||||
|
|
||||||
PARALLEL_UPDATES = 0
|
PARALLEL_UPDATES = 0
|
||||||
ATTR_SPEED = "speed"
|
ATTR_SPEED = "speed"
|
||||||
@ -205,22 +203,18 @@ class ReolinkButtonEntity(ReolinkChannelCoordinatorEntity, ButtonEntity):
|
|||||||
):
|
):
|
||||||
self._attr_supported_features = SUPPORT_PTZ_SPEED
|
self._attr_supported_features = SUPPORT_PTZ_SPEED
|
||||||
|
|
||||||
|
@raise_translated_error
|
||||||
async def async_press(self) -> None:
|
async def async_press(self) -> None:
|
||||||
"""Execute the button action."""
|
"""Execute the button action."""
|
||||||
try:
|
|
||||||
await self.entity_description.method(self._host.api, self._channel)
|
await self.entity_description.method(self._host.api, self._channel)
|
||||||
except ReolinkError as err:
|
|
||||||
raise HomeAssistantError(err) from err
|
|
||||||
|
|
||||||
|
@raise_translated_error
|
||||||
async def async_ptz_move(self, **kwargs: Any) -> None:
|
async def async_ptz_move(self, **kwargs: Any) -> None:
|
||||||
"""PTZ move with speed."""
|
"""PTZ move with speed."""
|
||||||
speed = kwargs[ATTR_SPEED]
|
speed = kwargs[ATTR_SPEED]
|
||||||
try:
|
|
||||||
await self._host.api.set_ptz_command(
|
await self._host.api.set_ptz_command(
|
||||||
self._channel, command=self.entity_description.ptz_cmd, speed=speed
|
self._channel, command=self.entity_description.ptz_cmd, speed=speed
|
||||||
)
|
)
|
||||||
except ReolinkError as err:
|
|
||||||
raise HomeAssistantError(err) from err
|
|
||||||
|
|
||||||
|
|
||||||
class ReolinkHostButtonEntity(ReolinkHostCoordinatorEntity, ButtonEntity):
|
class ReolinkHostButtonEntity(ReolinkHostCoordinatorEntity, ButtonEntity):
|
||||||
@ -237,9 +231,7 @@ class ReolinkHostButtonEntity(ReolinkHostCoordinatorEntity, ButtonEntity):
|
|||||||
self.entity_description = entity_description
|
self.entity_description = entity_description
|
||||||
super().__init__(reolink_data)
|
super().__init__(reolink_data)
|
||||||
|
|
||||||
|
@raise_translated_error
|
||||||
async def async_press(self) -> None:
|
async def async_press(self) -> None:
|
||||||
"""Execute the button action."""
|
"""Execute the button action."""
|
||||||
try:
|
|
||||||
await self.entity_description.method(self._host.api)
|
await self.entity_description.method(self._host.api)
|
||||||
except ReolinkError as err:
|
|
||||||
raise HomeAssistantError(err) from err
|
|
||||||
|
@ -6,7 +6,6 @@ from dataclasses import dataclass
|
|||||||
import logging
|
import logging
|
||||||
|
|
||||||
from reolink_aio.api import DUAL_LENS_MODELS
|
from reolink_aio.api import DUAL_LENS_MODELS
|
||||||
from reolink_aio.exceptions import ReolinkError
|
|
||||||
|
|
||||||
from homeassistant.components.camera import (
|
from homeassistant.components.camera import (
|
||||||
Camera,
|
Camera,
|
||||||
@ -14,11 +13,10 @@ from homeassistant.components.camera import (
|
|||||||
CameraEntityFeature,
|
CameraEntityFeature,
|
||||||
)
|
)
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.exceptions import HomeAssistantError
|
|
||||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
|
|
||||||
from .entity import ReolinkChannelCoordinatorEntity, ReolinkChannelEntityDescription
|
from .entity import ReolinkChannelCoordinatorEntity, ReolinkChannelEntityDescription
|
||||||
from .util import ReolinkConfigEntry, ReolinkData
|
from .util import ReolinkConfigEntry, ReolinkData, raise_translated_error
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
PARALLEL_UPDATES = 0
|
PARALLEL_UPDATES = 0
|
||||||
@ -142,13 +140,11 @@ class ReolinkCamera(ReolinkChannelCoordinatorEntity, Camera):
|
|||||||
self._channel, self.entity_description.stream
|
self._channel, self.entity_description.stream
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@raise_translated_error
|
||||||
async def async_camera_image(
|
async def async_camera_image(
|
||||||
self, width: int | None = None, height: int | None = None
|
self, width: int | None = None, height: int | None = None
|
||||||
) -> bytes | None:
|
) -> bytes | None:
|
||||||
"""Return a still image response from the camera."""
|
"""Return a still image response from the camera."""
|
||||||
try:
|
|
||||||
return await self._host.api.get_snapshot(
|
return await self._host.api.get_snapshot(
|
||||||
self._channel, self.entity_description.stream
|
self._channel, self.entity_description.stream
|
||||||
)
|
)
|
||||||
except ReolinkError as err:
|
|
||||||
raise HomeAssistantError(err) from err
|
|
||||||
|
@ -7,7 +7,6 @@ from dataclasses import dataclass
|
|||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from reolink_aio.api import Host
|
from reolink_aio.api import Host
|
||||||
from reolink_aio.exceptions import InvalidParameterError, ReolinkError
|
|
||||||
|
|
||||||
from homeassistant.components.light import (
|
from homeassistant.components.light import (
|
||||||
ATTR_BRIGHTNESS,
|
ATTR_BRIGHTNESS,
|
||||||
@ -17,7 +16,6 @@ from homeassistant.components.light import (
|
|||||||
)
|
)
|
||||||
from homeassistant.const import EntityCategory
|
from homeassistant.const import EntityCategory
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.exceptions import HomeAssistantError, ServiceValidationError
|
|
||||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
|
|
||||||
from .entity import (
|
from .entity import (
|
||||||
@ -26,7 +24,7 @@ from .entity import (
|
|||||||
ReolinkHostCoordinatorEntity,
|
ReolinkHostCoordinatorEntity,
|
||||||
ReolinkHostEntityDescription,
|
ReolinkHostEntityDescription,
|
||||||
)
|
)
|
||||||
from .util import ReolinkConfigEntry, ReolinkData
|
from .util import ReolinkConfigEntry, ReolinkData, raise_translated_error
|
||||||
|
|
||||||
PARALLEL_UPDATES = 0
|
PARALLEL_UPDATES = 0
|
||||||
|
|
||||||
@ -154,37 +152,28 @@ class ReolinkLightEntity(ReolinkChannelCoordinatorEntity, LightEntity):
|
|||||||
|
|
||||||
return round(255 * bright_pct / 100.0)
|
return round(255 * bright_pct / 100.0)
|
||||||
|
|
||||||
|
@raise_translated_error
|
||||||
async def async_turn_off(self, **kwargs: Any) -> None:
|
async def async_turn_off(self, **kwargs: Any) -> None:
|
||||||
"""Turn light off."""
|
"""Turn light off."""
|
||||||
try:
|
|
||||||
await self.entity_description.turn_on_off_fn(
|
await self.entity_description.turn_on_off_fn(
|
||||||
self._host.api, self._channel, False
|
self._host.api, self._channel, False
|
||||||
)
|
)
|
||||||
except ReolinkError as err:
|
|
||||||
raise HomeAssistantError(err) from err
|
|
||||||
self.async_write_ha_state()
|
self.async_write_ha_state()
|
||||||
|
|
||||||
|
@raise_translated_error
|
||||||
async def async_turn_on(self, **kwargs: Any) -> None:
|
async def async_turn_on(self, **kwargs: Any) -> None:
|
||||||
"""Turn light on."""
|
"""Turn light on."""
|
||||||
if (
|
if (
|
||||||
brightness := kwargs.get(ATTR_BRIGHTNESS)
|
brightness := kwargs.get(ATTR_BRIGHTNESS)
|
||||||
) is not None and self.entity_description.set_brightness_fn is not None:
|
) is not None and self.entity_description.set_brightness_fn is not None:
|
||||||
brightness_pct = int(brightness / 255.0 * 100)
|
brightness_pct = int(brightness / 255.0 * 100)
|
||||||
try:
|
|
||||||
await self.entity_description.set_brightness_fn(
|
await self.entity_description.set_brightness_fn(
|
||||||
self._host.api, self._channel, brightness_pct
|
self._host.api, self._channel, brightness_pct
|
||||||
)
|
)
|
||||||
except InvalidParameterError as err:
|
|
||||||
raise ServiceValidationError(err) from err
|
|
||||||
except ReolinkError as err:
|
|
||||||
raise HomeAssistantError(err) from err
|
|
||||||
|
|
||||||
try:
|
|
||||||
await self.entity_description.turn_on_off_fn(
|
await self.entity_description.turn_on_off_fn(
|
||||||
self._host.api, self._channel, True
|
self._host.api, self._channel, True
|
||||||
)
|
)
|
||||||
except ReolinkError as err:
|
|
||||||
raise HomeAssistantError(err) from err
|
|
||||||
self.async_write_ha_state()
|
self.async_write_ha_state()
|
||||||
|
|
||||||
|
|
||||||
@ -209,18 +198,14 @@ class ReolinkHostLightEntity(ReolinkHostCoordinatorEntity, LightEntity):
|
|||||||
"""Return true if light is on."""
|
"""Return true if light is on."""
|
||||||
return self.entity_description.is_on_fn(self._host.api)
|
return self.entity_description.is_on_fn(self._host.api)
|
||||||
|
|
||||||
|
@raise_translated_error
|
||||||
async def async_turn_off(self, **kwargs: Any) -> None:
|
async def async_turn_off(self, **kwargs: Any) -> None:
|
||||||
"""Turn light off."""
|
"""Turn light off."""
|
||||||
try:
|
|
||||||
await self.entity_description.turn_on_off_fn(self._host.api, False)
|
await self.entity_description.turn_on_off_fn(self._host.api, False)
|
||||||
except ReolinkError as err:
|
|
||||||
raise HomeAssistantError(err) from err
|
|
||||||
self.async_write_ha_state()
|
self.async_write_ha_state()
|
||||||
|
|
||||||
|
@raise_translated_error
|
||||||
async def async_turn_on(self, **kwargs: Any) -> None:
|
async def async_turn_on(self, **kwargs: Any) -> None:
|
||||||
"""Turn light on."""
|
"""Turn light on."""
|
||||||
try:
|
|
||||||
await self.entity_description.turn_on_off_fn(self._host.api, True)
|
await self.entity_description.turn_on_off_fn(self._host.api, True)
|
||||||
except ReolinkError as err:
|
|
||||||
raise HomeAssistantError(err) from err
|
|
||||||
self.async_write_ha_state()
|
self.async_write_ha_state()
|
||||||
|
@ -7,7 +7,6 @@ from dataclasses import dataclass
|
|||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from reolink_aio.api import Chime, Host
|
from reolink_aio.api import Chime, Host
|
||||||
from reolink_aio.exceptions import InvalidParameterError, ReolinkError
|
|
||||||
|
|
||||||
from homeassistant.components.number import (
|
from homeassistant.components.number import (
|
||||||
NumberEntity,
|
NumberEntity,
|
||||||
@ -16,7 +15,6 @@ from homeassistant.components.number import (
|
|||||||
)
|
)
|
||||||
from homeassistant.const import EntityCategory, UnitOfTime
|
from homeassistant.const import EntityCategory, UnitOfTime
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.exceptions import HomeAssistantError, ServiceValidationError
|
|
||||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
|
|
||||||
from .entity import (
|
from .entity import (
|
||||||
@ -27,7 +25,7 @@ from .entity import (
|
|||||||
ReolinkHostCoordinatorEntity,
|
ReolinkHostCoordinatorEntity,
|
||||||
ReolinkHostEntityDescription,
|
ReolinkHostEntityDescription,
|
||||||
)
|
)
|
||||||
from .util import ReolinkConfigEntry, ReolinkData
|
from .util import ReolinkConfigEntry, ReolinkData, raise_translated_error
|
||||||
|
|
||||||
PARALLEL_UPDATES = 0
|
PARALLEL_UPDATES = 0
|
||||||
|
|
||||||
@ -589,14 +587,10 @@ class ReolinkNumberEntity(ReolinkChannelCoordinatorEntity, NumberEntity):
|
|||||||
"""State of the number entity."""
|
"""State of the number entity."""
|
||||||
return self.entity_description.value(self._host.api, self._channel)
|
return self.entity_description.value(self._host.api, self._channel)
|
||||||
|
|
||||||
|
@raise_translated_error
|
||||||
async def async_set_native_value(self, value: float) -> None:
|
async def async_set_native_value(self, value: float) -> None:
|
||||||
"""Update the current value."""
|
"""Update the current value."""
|
||||||
try:
|
|
||||||
await self.entity_description.method(self._host.api, self._channel, value)
|
await self.entity_description.method(self._host.api, self._channel, value)
|
||||||
except InvalidParameterError as err:
|
|
||||||
raise ServiceValidationError(err) from err
|
|
||||||
except ReolinkError as err:
|
|
||||||
raise HomeAssistantError(err) from err
|
|
||||||
self.async_write_ha_state()
|
self.async_write_ha_state()
|
||||||
|
|
||||||
|
|
||||||
@ -621,14 +615,10 @@ class ReolinkHostNumberEntity(ReolinkHostCoordinatorEntity, NumberEntity):
|
|||||||
"""State of the number entity."""
|
"""State of the number entity."""
|
||||||
return self.entity_description.value(self._host.api)
|
return self.entity_description.value(self._host.api)
|
||||||
|
|
||||||
|
@raise_translated_error
|
||||||
async def async_set_native_value(self, value: float) -> None:
|
async def async_set_native_value(self, value: float) -> None:
|
||||||
"""Update the current value."""
|
"""Update the current value."""
|
||||||
try:
|
|
||||||
await self.entity_description.method(self._host.api, value)
|
await self.entity_description.method(self._host.api, value)
|
||||||
except InvalidParameterError as err:
|
|
||||||
raise ServiceValidationError(err) from err
|
|
||||||
except ReolinkError as err:
|
|
||||||
raise HomeAssistantError(err) from err
|
|
||||||
self.async_write_ha_state()
|
self.async_write_ha_state()
|
||||||
|
|
||||||
|
|
||||||
@ -654,12 +644,8 @@ class ReolinkChimeNumberEntity(ReolinkChimeCoordinatorEntity, NumberEntity):
|
|||||||
"""State of the number entity."""
|
"""State of the number entity."""
|
||||||
return self.entity_description.value(self._chime)
|
return self.entity_description.value(self._chime)
|
||||||
|
|
||||||
|
@raise_translated_error
|
||||||
async def async_set_native_value(self, value: float) -> None:
|
async def async_set_native_value(self, value: float) -> None:
|
||||||
"""Update the current value."""
|
"""Update the current value."""
|
||||||
try:
|
|
||||||
await self.entity_description.method(self._chime, value)
|
await self.entity_description.method(self._chime, value)
|
||||||
except InvalidParameterError as err:
|
|
||||||
raise ServiceValidationError(err) from err
|
|
||||||
except ReolinkError as err:
|
|
||||||
raise HomeAssistantError(err) from err
|
|
||||||
self.async_write_ha_state()
|
self.async_write_ha_state()
|
||||||
|
@ -54,7 +54,7 @@ rules:
|
|||||||
entity-device-class: done
|
entity-device-class: done
|
||||||
entity-disabled-by-default: done
|
entity-disabled-by-default: done
|
||||||
entity-translations: done
|
entity-translations: done
|
||||||
exception-translations: todo
|
exception-translations: done
|
||||||
icon-translations: done
|
icon-translations: done
|
||||||
reconfiguration-flow: done
|
reconfiguration-flow: done
|
||||||
repair-issues: done
|
repair-issues: done
|
||||||
|
@ -19,12 +19,10 @@ from reolink_aio.api import (
|
|||||||
StatusLedEnum,
|
StatusLedEnum,
|
||||||
TrackMethodEnum,
|
TrackMethodEnum,
|
||||||
)
|
)
|
||||||
from reolink_aio.exceptions import InvalidParameterError, ReolinkError
|
|
||||||
|
|
||||||
from homeassistant.components.select import SelectEntity, SelectEntityDescription
|
from homeassistant.components.select import SelectEntity, SelectEntityDescription
|
||||||
from homeassistant.const import EntityCategory, UnitOfDataRate, UnitOfFrequency
|
from homeassistant.const import EntityCategory, UnitOfDataRate, UnitOfFrequency
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.exceptions import HomeAssistantError, ServiceValidationError
|
|
||||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
|
|
||||||
from .entity import (
|
from .entity import (
|
||||||
@ -33,7 +31,7 @@ from .entity import (
|
|||||||
ReolinkChimeCoordinatorEntity,
|
ReolinkChimeCoordinatorEntity,
|
||||||
ReolinkChimeEntityDescription,
|
ReolinkChimeEntityDescription,
|
||||||
)
|
)
|
||||||
from .util import ReolinkConfigEntry, ReolinkData
|
from .util import ReolinkConfigEntry, ReolinkData, raise_translated_error
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
PARALLEL_UPDATES = 0
|
PARALLEL_UPDATES = 0
|
||||||
@ -354,14 +352,10 @@ class ReolinkSelectEntity(ReolinkChannelCoordinatorEntity, SelectEntity):
|
|||||||
self._log_error = True
|
self._log_error = True
|
||||||
return option
|
return option
|
||||||
|
|
||||||
|
@raise_translated_error
|
||||||
async def async_select_option(self, option: str) -> None:
|
async def async_select_option(self, option: str) -> None:
|
||||||
"""Change the selected option."""
|
"""Change the selected option."""
|
||||||
try:
|
|
||||||
await self.entity_description.method(self._host.api, self._channel, option)
|
await self.entity_description.method(self._host.api, self._channel, option)
|
||||||
except InvalidParameterError as err:
|
|
||||||
raise ServiceValidationError(err) from err
|
|
||||||
except ReolinkError as err:
|
|
||||||
raise HomeAssistantError(err) from err
|
|
||||||
self.async_write_ha_state()
|
self.async_write_ha_state()
|
||||||
|
|
||||||
|
|
||||||
@ -396,12 +390,8 @@ class ReolinkChimeSelectEntity(ReolinkChimeCoordinatorEntity, SelectEntity):
|
|||||||
self._log_error = True
|
self._log_error = True
|
||||||
return option
|
return option
|
||||||
|
|
||||||
|
@raise_translated_error
|
||||||
async def async_select_option(self, option: str) -> None:
|
async def async_select_option(self, option: str) -> None:
|
||||||
"""Change the selected option."""
|
"""Change the selected option."""
|
||||||
try:
|
|
||||||
await self.entity_description.method(self._chime, option)
|
await self.entity_description.method(self._chime, option)
|
||||||
except InvalidParameterError as err:
|
|
||||||
raise ServiceValidationError(err) from err
|
|
||||||
except ReolinkError as err:
|
|
||||||
raise HomeAssistantError(err) from err
|
|
||||||
self.async_write_ha_state()
|
self.async_write_ha_state()
|
||||||
|
@ -4,18 +4,17 @@ from __future__ import annotations
|
|||||||
|
|
||||||
from reolink_aio.api import Chime
|
from reolink_aio.api import Chime
|
||||||
from reolink_aio.enums import ChimeToneEnum
|
from reolink_aio.enums import ChimeToneEnum
|
||||||
from reolink_aio.exceptions import InvalidParameterError, ReolinkError
|
|
||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
|
|
||||||
from homeassistant.config_entries import ConfigEntryState
|
from homeassistant.config_entries import ConfigEntryState
|
||||||
from homeassistant.const import ATTR_DEVICE_ID
|
from homeassistant.const import ATTR_DEVICE_ID
|
||||||
from homeassistant.core import HomeAssistant, ServiceCall, callback
|
from homeassistant.core import HomeAssistant, ServiceCall, callback
|
||||||
from homeassistant.exceptions import HomeAssistantError, ServiceValidationError
|
from homeassistant.exceptions import ServiceValidationError
|
||||||
from homeassistant.helpers import device_registry as dr
|
from homeassistant.helpers import device_registry as dr
|
||||||
|
|
||||||
from .const import DOMAIN
|
from .const import DOMAIN
|
||||||
from .host import ReolinkHost
|
from .host import ReolinkHost
|
||||||
from .util import get_device_uid_and_ch
|
from .util import get_device_uid_and_ch, raise_translated_error
|
||||||
|
|
||||||
ATTR_RINGTONE = "ringtone"
|
ATTR_RINGTONE = "ringtone"
|
||||||
|
|
||||||
@ -24,6 +23,7 @@ ATTR_RINGTONE = "ringtone"
|
|||||||
def async_setup_services(hass: HomeAssistant) -> None:
|
def async_setup_services(hass: HomeAssistant) -> None:
|
||||||
"""Set up Reolink services."""
|
"""Set up Reolink services."""
|
||||||
|
|
||||||
|
@raise_translated_error
|
||||||
async def async_play_chime(service_call: ServiceCall) -> None:
|
async def async_play_chime(service_call: ServiceCall) -> None:
|
||||||
"""Play a ringtone."""
|
"""Play a ringtone."""
|
||||||
service_data = service_call.data
|
service_data = service_call.data
|
||||||
@ -58,12 +58,7 @@ def async_setup_services(hass: HomeAssistant) -> None:
|
|||||||
)
|
)
|
||||||
|
|
||||||
ringtone = service_data[ATTR_RINGTONE]
|
ringtone = service_data[ATTR_RINGTONE]
|
||||||
try:
|
|
||||||
await chime.play(ChimeToneEnum[ringtone].value)
|
await chime.play(ChimeToneEnum[ringtone].value)
|
||||||
except InvalidParameterError as err:
|
|
||||||
raise ServiceValidationError(err) from err
|
|
||||||
except ReolinkError as err:
|
|
||||||
raise HomeAssistantError(err) from err
|
|
||||||
|
|
||||||
hass.services.async_register(
|
hass.services.async_register(
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
|
@ -5,8 +5,6 @@ from __future__ import annotations
|
|||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from reolink_aio.exceptions import InvalidParameterError, ReolinkError
|
|
||||||
|
|
||||||
from homeassistant.components.siren import (
|
from homeassistant.components.siren import (
|
||||||
ATTR_DURATION,
|
ATTR_DURATION,
|
||||||
ATTR_VOLUME_LEVEL,
|
ATTR_VOLUME_LEVEL,
|
||||||
@ -15,11 +13,10 @@ from homeassistant.components.siren import (
|
|||||||
SirenEntityFeature,
|
SirenEntityFeature,
|
||||||
)
|
)
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.exceptions import HomeAssistantError, ServiceValidationError
|
|
||||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
|
|
||||||
from .entity import ReolinkChannelCoordinatorEntity, ReolinkChannelEntityDescription
|
from .entity import ReolinkChannelCoordinatorEntity, ReolinkChannelEntityDescription
|
||||||
from .util import ReolinkConfigEntry, ReolinkData
|
from .util import ReolinkConfigEntry, ReolinkData, raise_translated_error
|
||||||
|
|
||||||
PARALLEL_UPDATES = 0
|
PARALLEL_UPDATES = 0
|
||||||
|
|
||||||
@ -77,26 +74,15 @@ class ReolinkSirenEntity(ReolinkChannelCoordinatorEntity, SirenEntity):
|
|||||||
self.entity_description = entity_description
|
self.entity_description = entity_description
|
||||||
super().__init__(reolink_data, channel)
|
super().__init__(reolink_data, channel)
|
||||||
|
|
||||||
|
@raise_translated_error
|
||||||
async def async_turn_on(self, **kwargs: Any) -> None:
|
async def async_turn_on(self, **kwargs: Any) -> None:
|
||||||
"""Turn on the siren."""
|
"""Turn on the siren."""
|
||||||
if (volume := kwargs.get(ATTR_VOLUME_LEVEL)) is not None:
|
if (volume := kwargs.get(ATTR_VOLUME_LEVEL)) is not None:
|
||||||
try:
|
|
||||||
await self._host.api.set_volume(self._channel, int(volume * 100))
|
await self._host.api.set_volume(self._channel, int(volume * 100))
|
||||||
except InvalidParameterError as err:
|
|
||||||
raise ServiceValidationError(err) from err
|
|
||||||
except ReolinkError as err:
|
|
||||||
raise HomeAssistantError(err) from err
|
|
||||||
duration = kwargs.get(ATTR_DURATION)
|
duration = kwargs.get(ATTR_DURATION)
|
||||||
try:
|
|
||||||
await self._host.api.set_siren(self._channel, True, duration)
|
await self._host.api.set_siren(self._channel, True, duration)
|
||||||
except InvalidParameterError as err:
|
|
||||||
raise ServiceValidationError(err) from err
|
|
||||||
except ReolinkError as err:
|
|
||||||
raise HomeAssistantError(err) from err
|
|
||||||
|
|
||||||
|
@raise_translated_error
|
||||||
async def async_turn_off(self, **kwargs: Any) -> None:
|
async def async_turn_off(self, **kwargs: Any) -> None:
|
||||||
"""Turn off the siren."""
|
"""Turn off the siren."""
|
||||||
try:
|
|
||||||
await self._host.api.set_siren(self._channel, False, None)
|
await self._host.api.set_siren(self._channel, False, None)
|
||||||
except ReolinkError as err:
|
|
||||||
raise HomeAssistantError(err) from err
|
|
||||||
|
@ -55,6 +55,45 @@
|
|||||||
},
|
},
|
||||||
"service_not_chime": {
|
"service_not_chime": {
|
||||||
"message": "Reolink play_chime error: {device_name} is not a chime"
|
"message": "Reolink play_chime error: {device_name} is not a chime"
|
||||||
|
},
|
||||||
|
"invalid_parameter": {
|
||||||
|
"message": "Invalid input parameter: {err}"
|
||||||
|
},
|
||||||
|
"api_error": {
|
||||||
|
"message": "The device responded with a error: {err}"
|
||||||
|
},
|
||||||
|
"invalid_content_type": {
|
||||||
|
"message": "Received a different content type than expected: {err}"
|
||||||
|
},
|
||||||
|
"invalid_credentials": {
|
||||||
|
"message": "Invalid credentials: {err}"
|
||||||
|
},
|
||||||
|
"login_error": {
|
||||||
|
"message": "Error during login attempt: {err}"
|
||||||
|
},
|
||||||
|
"no_data": {
|
||||||
|
"message": "Device returned no data: {err}"
|
||||||
|
},
|
||||||
|
"unexpected_data": {
|
||||||
|
"message": "Device returned unexpected data: {err}"
|
||||||
|
},
|
||||||
|
"not_supported": {
|
||||||
|
"message": "Function not supported by this device: {err}"
|
||||||
|
},
|
||||||
|
"subscription_error": {
|
||||||
|
"message": "Error during ONVIF subscription: {err}"
|
||||||
|
},
|
||||||
|
"connection_error": {
|
||||||
|
"message": "Could not connect to the device: {err}"
|
||||||
|
},
|
||||||
|
"timeout": {
|
||||||
|
"message": "Timeout waiting on a response: {err}"
|
||||||
|
},
|
||||||
|
"firmware_install_error": {
|
||||||
|
"message": "Error trying to update Reolink firmware: {err}"
|
||||||
|
},
|
||||||
|
"config_entry_not_ready": {
|
||||||
|
"message": "Error while trying to setup {host}: {err}"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"issues": {
|
"issues": {
|
||||||
|
@ -7,12 +7,10 @@ from dataclasses import dataclass
|
|||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from reolink_aio.api import Chime, Host
|
from reolink_aio.api import Chime, Host
|
||||||
from reolink_aio.exceptions import ReolinkError
|
|
||||||
|
|
||||||
from homeassistant.components.switch import SwitchEntity, SwitchEntityDescription
|
from homeassistant.components.switch import SwitchEntity, SwitchEntityDescription
|
||||||
from homeassistant.const import EntityCategory
|
from homeassistant.const import EntityCategory
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.exceptions import HomeAssistantError
|
|
||||||
from homeassistant.helpers import entity_registry as er, issue_registry as ir
|
from homeassistant.helpers import entity_registry as er, issue_registry as ir
|
||||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
|
|
||||||
@ -25,7 +23,7 @@ from .entity import (
|
|||||||
ReolinkHostCoordinatorEntity,
|
ReolinkHostCoordinatorEntity,
|
||||||
ReolinkHostEntityDescription,
|
ReolinkHostEntityDescription,
|
||||||
)
|
)
|
||||||
from .util import ReolinkConfigEntry, ReolinkData
|
from .util import ReolinkConfigEntry, ReolinkData, raise_translated_error
|
||||||
|
|
||||||
PARALLEL_UPDATES = 0
|
PARALLEL_UPDATES = 0
|
||||||
|
|
||||||
@ -430,20 +428,16 @@ class ReolinkSwitchEntity(ReolinkChannelCoordinatorEntity, SwitchEntity):
|
|||||||
"""Return true if switch is on."""
|
"""Return true if switch is on."""
|
||||||
return self.entity_description.value(self._host.api, self._channel)
|
return self.entity_description.value(self._host.api, self._channel)
|
||||||
|
|
||||||
|
@raise_translated_error
|
||||||
async def async_turn_on(self, **kwargs: Any) -> None:
|
async def async_turn_on(self, **kwargs: Any) -> None:
|
||||||
"""Turn the entity on."""
|
"""Turn the entity on."""
|
||||||
try:
|
|
||||||
await self.entity_description.method(self._host.api, self._channel, True)
|
await self.entity_description.method(self._host.api, self._channel, True)
|
||||||
except ReolinkError as err:
|
|
||||||
raise HomeAssistantError(err) from err
|
|
||||||
self.async_write_ha_state()
|
self.async_write_ha_state()
|
||||||
|
|
||||||
|
@raise_translated_error
|
||||||
async def async_turn_off(self, **kwargs: Any) -> None:
|
async def async_turn_off(self, **kwargs: Any) -> None:
|
||||||
"""Turn the entity off."""
|
"""Turn the entity off."""
|
||||||
try:
|
|
||||||
await self.entity_description.method(self._host.api, self._channel, False)
|
await self.entity_description.method(self._host.api, self._channel, False)
|
||||||
except ReolinkError as err:
|
|
||||||
raise HomeAssistantError(err) from err
|
|
||||||
self.async_write_ha_state()
|
self.async_write_ha_state()
|
||||||
|
|
||||||
|
|
||||||
@ -466,20 +460,16 @@ class ReolinkNVRSwitchEntity(ReolinkHostCoordinatorEntity, SwitchEntity):
|
|||||||
"""Return true if switch is on."""
|
"""Return true if switch is on."""
|
||||||
return self.entity_description.value(self._host.api)
|
return self.entity_description.value(self._host.api)
|
||||||
|
|
||||||
|
@raise_translated_error
|
||||||
async def async_turn_on(self, **kwargs: Any) -> None:
|
async def async_turn_on(self, **kwargs: Any) -> None:
|
||||||
"""Turn the entity on."""
|
"""Turn the entity on."""
|
||||||
try:
|
|
||||||
await self.entity_description.method(self._host.api, True)
|
await self.entity_description.method(self._host.api, True)
|
||||||
except ReolinkError as err:
|
|
||||||
raise HomeAssistantError(err) from err
|
|
||||||
self.async_write_ha_state()
|
self.async_write_ha_state()
|
||||||
|
|
||||||
|
@raise_translated_error
|
||||||
async def async_turn_off(self, **kwargs: Any) -> None:
|
async def async_turn_off(self, **kwargs: Any) -> None:
|
||||||
"""Turn the entity off."""
|
"""Turn the entity off."""
|
||||||
try:
|
|
||||||
await self.entity_description.method(self._host.api, False)
|
await self.entity_description.method(self._host.api, False)
|
||||||
except ReolinkError as err:
|
|
||||||
raise HomeAssistantError(err) from err
|
|
||||||
self.async_write_ha_state()
|
self.async_write_ha_state()
|
||||||
|
|
||||||
|
|
||||||
@ -503,18 +493,14 @@ class ReolinkChimeSwitchEntity(ReolinkChimeCoordinatorEntity, SwitchEntity):
|
|||||||
"""Return true if switch is on."""
|
"""Return true if switch is on."""
|
||||||
return self.entity_description.value(self._chime)
|
return self.entity_description.value(self._chime)
|
||||||
|
|
||||||
|
@raise_translated_error
|
||||||
async def async_turn_on(self, **kwargs: Any) -> None:
|
async def async_turn_on(self, **kwargs: Any) -> None:
|
||||||
"""Turn the entity on."""
|
"""Turn the entity on."""
|
||||||
try:
|
|
||||||
await self.entity_description.method(self._chime, True)
|
await self.entity_description.method(self._chime, True)
|
||||||
except ReolinkError as err:
|
|
||||||
raise HomeAssistantError(err) from err
|
|
||||||
self.async_write_ha_state()
|
self.async_write_ha_state()
|
||||||
|
|
||||||
|
@raise_translated_error
|
||||||
async def async_turn_off(self, **kwargs: Any) -> None:
|
async def async_turn_off(self, **kwargs: Any) -> None:
|
||||||
"""Turn the entity off."""
|
"""Turn the entity off."""
|
||||||
try:
|
|
||||||
await self.entity_description.method(self._chime, False)
|
await self.entity_description.method(self._chime, False)
|
||||||
except ReolinkError as err:
|
|
||||||
raise HomeAssistantError(err) from err
|
|
||||||
self.async_write_ha_state()
|
self.async_write_ha_state()
|
||||||
|
@ -24,6 +24,7 @@ from homeassistant.helpers.update_coordinator import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
from . import DEVICE_UPDATE_INTERVAL
|
from . import DEVICE_UPDATE_INTERVAL
|
||||||
|
from .const import DOMAIN
|
||||||
from .entity import (
|
from .entity import (
|
||||||
ReolinkChannelCoordinatorEntity,
|
ReolinkChannelCoordinatorEntity,
|
||||||
ReolinkChannelEntityDescription,
|
ReolinkChannelEntityDescription,
|
||||||
@ -196,7 +197,9 @@ class ReolinkUpdateBaseEntity(
|
|||||||
await self._host.api.update_firmware(self._channel)
|
await self._host.api.update_firmware(self._channel)
|
||||||
except ReolinkError as err:
|
except ReolinkError as err:
|
||||||
raise HomeAssistantError(
|
raise HomeAssistantError(
|
||||||
f"Error trying to update Reolink firmware: {err}"
|
translation_domain=DOMAIN,
|
||||||
|
translation_key="firmware_install_error",
|
||||||
|
translation_placeholders={"err": str(err)},
|
||||||
) from err
|
) from err
|
||||||
finally:
|
finally:
|
||||||
self.async_write_ha_state()
|
self.async_write_ha_state()
|
||||||
|
@ -2,10 +2,28 @@
|
|||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from collections.abc import Awaitable, Callable, Coroutine
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
|
from typing import Any, ParamSpec, TypeVar
|
||||||
|
|
||||||
|
from reolink_aio.exceptions import (
|
||||||
|
ApiError,
|
||||||
|
CredentialsInvalidError,
|
||||||
|
InvalidContentTypeError,
|
||||||
|
InvalidParameterError,
|
||||||
|
LoginError,
|
||||||
|
NoDataError,
|
||||||
|
NotSupportedError,
|
||||||
|
ReolinkConnectionError,
|
||||||
|
ReolinkError,
|
||||||
|
ReolinkTimeoutError,
|
||||||
|
SubscriptionError,
|
||||||
|
UnexpectedDataError,
|
||||||
|
)
|
||||||
|
|
||||||
from homeassistant import config_entries
|
from homeassistant import config_entries
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
|
from homeassistant.exceptions import HomeAssistantError, ServiceValidationError
|
||||||
from homeassistant.helpers import device_registry as dr
|
from homeassistant.helpers import device_registry as dr
|
||||||
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
|
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
|
||||||
|
|
||||||
@ -53,3 +71,89 @@ def get_device_uid_and_ch(
|
|||||||
else:
|
else:
|
||||||
ch = host.api.channel_for_uid(device_uid[1])
|
ch = host.api.channel_for_uid(device_uid[1])
|
||||||
return (device_uid, ch, is_chime)
|
return (device_uid, ch, is_chime)
|
||||||
|
|
||||||
|
|
||||||
|
T = TypeVar("T")
|
||||||
|
P = ParamSpec("P")
|
||||||
|
|
||||||
|
|
||||||
|
# Decorators
|
||||||
|
def raise_translated_error(
|
||||||
|
func: Callable[P, Awaitable[T]],
|
||||||
|
) -> Callable[P, Coroutine[Any, Any, T]]:
|
||||||
|
"""Wrap a reolink-aio function to translate any potential errors."""
|
||||||
|
|
||||||
|
async def decorator_raise_translated_error(*args: P.args, **kwargs: P.kwargs) -> T:
|
||||||
|
"""Try a reolink-aio function and translate any potential errors."""
|
||||||
|
try:
|
||||||
|
return await func(*args, **kwargs)
|
||||||
|
except InvalidParameterError as err:
|
||||||
|
raise ServiceValidationError(
|
||||||
|
translation_domain=DOMAIN,
|
||||||
|
translation_key="invalid_parameter",
|
||||||
|
translation_placeholders={"err": str(err)},
|
||||||
|
) from err
|
||||||
|
except ApiError as err:
|
||||||
|
raise HomeAssistantError(
|
||||||
|
translation_domain=DOMAIN,
|
||||||
|
translation_key="api_error",
|
||||||
|
translation_placeholders={"err": str(err)},
|
||||||
|
) from err
|
||||||
|
except InvalidContentTypeError as err:
|
||||||
|
raise HomeAssistantError(
|
||||||
|
translation_domain=DOMAIN,
|
||||||
|
translation_key="invalid_content_type",
|
||||||
|
translation_placeholders={"err": str(err)},
|
||||||
|
) from err
|
||||||
|
except CredentialsInvalidError as err:
|
||||||
|
raise HomeAssistantError(
|
||||||
|
translation_domain=DOMAIN,
|
||||||
|
translation_key="invalid_credentials",
|
||||||
|
translation_placeholders={"err": str(err)},
|
||||||
|
) from err
|
||||||
|
except LoginError as err:
|
||||||
|
raise HomeAssistantError(
|
||||||
|
translation_domain=DOMAIN,
|
||||||
|
translation_key="login_error",
|
||||||
|
translation_placeholders={"err": str(err)},
|
||||||
|
) from err
|
||||||
|
except NoDataError as err:
|
||||||
|
raise HomeAssistantError(
|
||||||
|
translation_domain=DOMAIN,
|
||||||
|
translation_key="no_data",
|
||||||
|
translation_placeholders={"err": str(err)},
|
||||||
|
) from err
|
||||||
|
except UnexpectedDataError as err:
|
||||||
|
raise HomeAssistantError(
|
||||||
|
translation_domain=DOMAIN,
|
||||||
|
translation_key="unexpected_data",
|
||||||
|
translation_placeholders={"err": str(err)},
|
||||||
|
) from err
|
||||||
|
except NotSupportedError as err:
|
||||||
|
raise HomeAssistantError(
|
||||||
|
translation_domain=DOMAIN,
|
||||||
|
translation_key="not_supported",
|
||||||
|
translation_placeholders={"err": str(err)},
|
||||||
|
) from err
|
||||||
|
except SubscriptionError as err:
|
||||||
|
raise HomeAssistantError(
|
||||||
|
translation_domain=DOMAIN,
|
||||||
|
translation_key="subscription_error",
|
||||||
|
translation_placeholders={"err": str(err)},
|
||||||
|
) from err
|
||||||
|
except ReolinkConnectionError as err:
|
||||||
|
raise HomeAssistantError(
|
||||||
|
translation_domain=DOMAIN,
|
||||||
|
translation_key="connection_error",
|
||||||
|
translation_placeholders={"err": str(err)},
|
||||||
|
) from err
|
||||||
|
except ReolinkTimeoutError as err:
|
||||||
|
raise HomeAssistantError(
|
||||||
|
translation_domain=DOMAIN,
|
||||||
|
translation_key="timeout",
|
||||||
|
translation_placeholders={"err": str(err)},
|
||||||
|
) from err
|
||||||
|
except ReolinkError as err:
|
||||||
|
raise HomeAssistantError(err) from err
|
||||||
|
|
||||||
|
return decorator_raise_translated_error
|
||||||
|
115
tests/components/reolink/test_util.py
Normal file
115
tests/components/reolink/test_util.py
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
"""Test the Reolink util functions."""
|
||||||
|
|
||||||
|
from unittest.mock import MagicMock, patch
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
from reolink_aio.exceptions import (
|
||||||
|
ApiError,
|
||||||
|
CredentialsInvalidError,
|
||||||
|
InvalidContentTypeError,
|
||||||
|
InvalidParameterError,
|
||||||
|
LoginError,
|
||||||
|
NoDataError,
|
||||||
|
NotSupportedError,
|
||||||
|
ReolinkConnectionError,
|
||||||
|
ReolinkError,
|
||||||
|
ReolinkTimeoutError,
|
||||||
|
SubscriptionError,
|
||||||
|
UnexpectedDataError,
|
||||||
|
)
|
||||||
|
|
||||||
|
from homeassistant.components.number import (
|
||||||
|
ATTR_VALUE,
|
||||||
|
DOMAIN as NUMBER_DOMAIN,
|
||||||
|
SERVICE_SET_VALUE,
|
||||||
|
)
|
||||||
|
from homeassistant.config_entries import ConfigEntryState
|
||||||
|
from homeassistant.const import ATTR_ENTITY_ID, Platform
|
||||||
|
from homeassistant.core import HomeAssistant
|
||||||
|
from homeassistant.exceptions import HomeAssistantError, ServiceValidationError
|
||||||
|
|
||||||
|
from .conftest import TEST_NVR_NAME
|
||||||
|
|
||||||
|
from tests.common import MockConfigEntry
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
("side_effect", "expected"),
|
||||||
|
[
|
||||||
|
(
|
||||||
|
ApiError("Test error"),
|
||||||
|
HomeAssistantError,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
CredentialsInvalidError("Test error"),
|
||||||
|
HomeAssistantError,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
InvalidContentTypeError("Test error"),
|
||||||
|
HomeAssistantError,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
InvalidParameterError("Test error"),
|
||||||
|
ServiceValidationError,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
LoginError("Test error"),
|
||||||
|
HomeAssistantError,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
NoDataError("Test error"),
|
||||||
|
HomeAssistantError,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
NotSupportedError("Test error"),
|
||||||
|
HomeAssistantError,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
ReolinkConnectionError("Test error"),
|
||||||
|
HomeAssistantError,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
ReolinkError("Test error"),
|
||||||
|
HomeAssistantError,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
ReolinkTimeoutError("Test error"),
|
||||||
|
HomeAssistantError,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
SubscriptionError("Test error"),
|
||||||
|
HomeAssistantError,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
UnexpectedDataError("Test error"),
|
||||||
|
HomeAssistantError,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
async def test_try_function(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
config_entry: MockConfigEntry,
|
||||||
|
reolink_connect: MagicMock,
|
||||||
|
side_effect: ReolinkError,
|
||||||
|
expected: Exception,
|
||||||
|
) -> None:
|
||||||
|
"""Test try_function error translations using number entity."""
|
||||||
|
reolink_connect.volume.return_value = 80
|
||||||
|
|
||||||
|
with patch("homeassistant.components.reolink.PLATFORMS", [Platform.NUMBER]):
|
||||||
|
assert await hass.config_entries.async_setup(config_entry.entry_id)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
assert config_entry.state is ConfigEntryState.LOADED
|
||||||
|
|
||||||
|
entity_id = f"{Platform.NUMBER}.{TEST_NVR_NAME}_volume"
|
||||||
|
|
||||||
|
reolink_connect.set_volume.side_effect = side_effect
|
||||||
|
with pytest.raises(expected):
|
||||||
|
await hass.services.async_call(
|
||||||
|
NUMBER_DOMAIN,
|
||||||
|
SERVICE_SET_VALUE,
|
||||||
|
{ATTR_ENTITY_ID: entity_id, ATTR_VALUE: 50},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
reolink_connect.set_volume.reset_mock(side_effect=True)
|
Loading…
x
Reference in New Issue
Block a user