mirror of
https://github.com/home-assistant/core.git
synced 2025-07-18 18:57:06 +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:
|
||||
await host.stop()
|
||||
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
|
||||
except BaseException:
|
||||
await host.stop()
|
||||
|
@ -7,7 +7,6 @@ from dataclasses import dataclass
|
||||
from typing import Any
|
||||
|
||||
from reolink_aio.api import GuardEnum, Host, PtzEnum
|
||||
from reolink_aio.exceptions import ReolinkError
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.components.button import (
|
||||
@ -18,7 +17,6 @@ from homeassistant.components.button import (
|
||||
from homeassistant.components.camera import CameraEntityFeature
|
||||
from homeassistant.const import EntityCategory
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
from homeassistant.helpers import config_validation as cv
|
||||
from homeassistant.helpers.entity_platform import (
|
||||
AddEntitiesCallback,
|
||||
@ -31,7 +29,7 @@ from .entity import (
|
||||
ReolinkHostCoordinatorEntity,
|
||||
ReolinkHostEntityDescription,
|
||||
)
|
||||
from .util import ReolinkConfigEntry, ReolinkData
|
||||
from .util import ReolinkConfigEntry, ReolinkData, raise_translated_error
|
||||
|
||||
PARALLEL_UPDATES = 0
|
||||
ATTR_SPEED = "speed"
|
||||
@ -205,22 +203,18 @@ class ReolinkButtonEntity(ReolinkChannelCoordinatorEntity, ButtonEntity):
|
||||
):
|
||||
self._attr_supported_features = SUPPORT_PTZ_SPEED
|
||||
|
||||
@raise_translated_error
|
||||
async def async_press(self) -> None:
|
||||
"""Execute the button action."""
|
||||
try:
|
||||
await self.entity_description.method(self._host.api, self._channel)
|
||||
except ReolinkError as err:
|
||||
raise HomeAssistantError(err) from err
|
||||
await self.entity_description.method(self._host.api, self._channel)
|
||||
|
||||
@raise_translated_error
|
||||
async def async_ptz_move(self, **kwargs: Any) -> None:
|
||||
"""PTZ move with speed."""
|
||||
speed = kwargs[ATTR_SPEED]
|
||||
try:
|
||||
await self._host.api.set_ptz_command(
|
||||
self._channel, command=self.entity_description.ptz_cmd, speed=speed
|
||||
)
|
||||
except ReolinkError as err:
|
||||
raise HomeAssistantError(err) from err
|
||||
await self._host.api.set_ptz_command(
|
||||
self._channel, command=self.entity_description.ptz_cmd, speed=speed
|
||||
)
|
||||
|
||||
|
||||
class ReolinkHostButtonEntity(ReolinkHostCoordinatorEntity, ButtonEntity):
|
||||
@ -237,9 +231,7 @@ class ReolinkHostButtonEntity(ReolinkHostCoordinatorEntity, ButtonEntity):
|
||||
self.entity_description = entity_description
|
||||
super().__init__(reolink_data)
|
||||
|
||||
@raise_translated_error
|
||||
async def async_press(self) -> None:
|
||||
"""Execute the button action."""
|
||||
try:
|
||||
await self.entity_description.method(self._host.api)
|
||||
except ReolinkError as err:
|
||||
raise HomeAssistantError(err) from err
|
||||
await self.entity_description.method(self._host.api)
|
||||
|
@ -6,7 +6,6 @@ from dataclasses import dataclass
|
||||
import logging
|
||||
|
||||
from reolink_aio.api import DUAL_LENS_MODELS
|
||||
from reolink_aio.exceptions import ReolinkError
|
||||
|
||||
from homeassistant.components.camera import (
|
||||
Camera,
|
||||
@ -14,11 +13,10 @@ from homeassistant.components.camera import (
|
||||
CameraEntityFeature,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
|
||||
from .entity import ReolinkChannelCoordinatorEntity, ReolinkChannelEntityDescription
|
||||
from .util import ReolinkConfigEntry, ReolinkData
|
||||
from .util import ReolinkConfigEntry, ReolinkData, raise_translated_error
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
PARALLEL_UPDATES = 0
|
||||
@ -142,13 +140,11 @@ class ReolinkCamera(ReolinkChannelCoordinatorEntity, Camera):
|
||||
self._channel, self.entity_description.stream
|
||||
)
|
||||
|
||||
@raise_translated_error
|
||||
async def async_camera_image(
|
||||
self, width: int | None = None, height: int | None = None
|
||||
) -> bytes | None:
|
||||
"""Return a still image response from the camera."""
|
||||
try:
|
||||
return await self._host.api.get_snapshot(
|
||||
self._channel, self.entity_description.stream
|
||||
)
|
||||
except ReolinkError as err:
|
||||
raise HomeAssistantError(err) from err
|
||||
return await self._host.api.get_snapshot(
|
||||
self._channel, self.entity_description.stream
|
||||
)
|
||||
|
@ -7,7 +7,6 @@ from dataclasses import dataclass
|
||||
from typing import Any
|
||||
|
||||
from reolink_aio.api import Host
|
||||
from reolink_aio.exceptions import InvalidParameterError, ReolinkError
|
||||
|
||||
from homeassistant.components.light import (
|
||||
ATTR_BRIGHTNESS,
|
||||
@ -17,7 +16,6 @@ from homeassistant.components.light import (
|
||||
)
|
||||
from homeassistant.const import EntityCategory
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.exceptions import HomeAssistantError, ServiceValidationError
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
|
||||
from .entity import (
|
||||
@ -26,7 +24,7 @@ from .entity import (
|
||||
ReolinkHostCoordinatorEntity,
|
||||
ReolinkHostEntityDescription,
|
||||
)
|
||||
from .util import ReolinkConfigEntry, ReolinkData
|
||||
from .util import ReolinkConfigEntry, ReolinkData, raise_translated_error
|
||||
|
||||
PARALLEL_UPDATES = 0
|
||||
|
||||
@ -154,37 +152,28 @@ class ReolinkLightEntity(ReolinkChannelCoordinatorEntity, LightEntity):
|
||||
|
||||
return round(255 * bright_pct / 100.0)
|
||||
|
||||
@raise_translated_error
|
||||
async def async_turn_off(self, **kwargs: Any) -> None:
|
||||
"""Turn light off."""
|
||||
try:
|
||||
await self.entity_description.turn_on_off_fn(
|
||||
self._host.api, self._channel, False
|
||||
)
|
||||
except ReolinkError as err:
|
||||
raise HomeAssistantError(err) from err
|
||||
await self.entity_description.turn_on_off_fn(
|
||||
self._host.api, self._channel, False
|
||||
)
|
||||
self.async_write_ha_state()
|
||||
|
||||
@raise_translated_error
|
||||
async def async_turn_on(self, **kwargs: Any) -> None:
|
||||
"""Turn light on."""
|
||||
if (
|
||||
brightness := kwargs.get(ATTR_BRIGHTNESS)
|
||||
) is not None and self.entity_description.set_brightness_fn is not None:
|
||||
brightness_pct = int(brightness / 255.0 * 100)
|
||||
try:
|
||||
await self.entity_description.set_brightness_fn(
|
||||
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(
|
||||
self._host.api, self._channel, True
|
||||
await self.entity_description.set_brightness_fn(
|
||||
self._host.api, self._channel, brightness_pct
|
||||
)
|
||||
except ReolinkError as err:
|
||||
raise HomeAssistantError(err) from err
|
||||
|
||||
await self.entity_description.turn_on_off_fn(
|
||||
self._host.api, self._channel, True
|
||||
)
|
||||
self.async_write_ha_state()
|
||||
|
||||
|
||||
@ -209,18 +198,14 @@ class ReolinkHostLightEntity(ReolinkHostCoordinatorEntity, LightEntity):
|
||||
"""Return true if light is on."""
|
||||
return self.entity_description.is_on_fn(self._host.api)
|
||||
|
||||
@raise_translated_error
|
||||
async def async_turn_off(self, **kwargs: Any) -> None:
|
||||
"""Turn light off."""
|
||||
try:
|
||||
await self.entity_description.turn_on_off_fn(self._host.api, False)
|
||||
except ReolinkError as err:
|
||||
raise HomeAssistantError(err) from err
|
||||
await self.entity_description.turn_on_off_fn(self._host.api, False)
|
||||
self.async_write_ha_state()
|
||||
|
||||
@raise_translated_error
|
||||
async def async_turn_on(self, **kwargs: Any) -> None:
|
||||
"""Turn light on."""
|
||||
try:
|
||||
await self.entity_description.turn_on_off_fn(self._host.api, True)
|
||||
except ReolinkError as err:
|
||||
raise HomeAssistantError(err) from err
|
||||
await self.entity_description.turn_on_off_fn(self._host.api, True)
|
||||
self.async_write_ha_state()
|
||||
|
@ -7,7 +7,6 @@ from dataclasses import dataclass
|
||||
from typing import Any
|
||||
|
||||
from reolink_aio.api import Chime, Host
|
||||
from reolink_aio.exceptions import InvalidParameterError, ReolinkError
|
||||
|
||||
from homeassistant.components.number import (
|
||||
NumberEntity,
|
||||
@ -16,7 +15,6 @@ from homeassistant.components.number import (
|
||||
)
|
||||
from homeassistant.const import EntityCategory, UnitOfTime
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.exceptions import HomeAssistantError, ServiceValidationError
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
|
||||
from .entity import (
|
||||
@ -27,7 +25,7 @@ from .entity import (
|
||||
ReolinkHostCoordinatorEntity,
|
||||
ReolinkHostEntityDescription,
|
||||
)
|
||||
from .util import ReolinkConfigEntry, ReolinkData
|
||||
from .util import ReolinkConfigEntry, ReolinkData, raise_translated_error
|
||||
|
||||
PARALLEL_UPDATES = 0
|
||||
|
||||
@ -589,14 +587,10 @@ class ReolinkNumberEntity(ReolinkChannelCoordinatorEntity, NumberEntity):
|
||||
"""State of the number entity."""
|
||||
return self.entity_description.value(self._host.api, self._channel)
|
||||
|
||||
@raise_translated_error
|
||||
async def async_set_native_value(self, value: float) -> None:
|
||||
"""Update the current value."""
|
||||
try:
|
||||
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
|
||||
await self.entity_description.method(self._host.api, self._channel, value)
|
||||
self.async_write_ha_state()
|
||||
|
||||
|
||||
@ -621,14 +615,10 @@ class ReolinkHostNumberEntity(ReolinkHostCoordinatorEntity, NumberEntity):
|
||||
"""State of the number entity."""
|
||||
return self.entity_description.value(self._host.api)
|
||||
|
||||
@raise_translated_error
|
||||
async def async_set_native_value(self, value: float) -> None:
|
||||
"""Update the current value."""
|
||||
try:
|
||||
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
|
||||
await self.entity_description.method(self._host.api, value)
|
||||
self.async_write_ha_state()
|
||||
|
||||
|
||||
@ -654,12 +644,8 @@ class ReolinkChimeNumberEntity(ReolinkChimeCoordinatorEntity, NumberEntity):
|
||||
"""State of the number entity."""
|
||||
return self.entity_description.value(self._chime)
|
||||
|
||||
@raise_translated_error
|
||||
async def async_set_native_value(self, value: float) -> None:
|
||||
"""Update the current value."""
|
||||
try:
|
||||
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
|
||||
await self.entity_description.method(self._chime, value)
|
||||
self.async_write_ha_state()
|
||||
|
@ -54,7 +54,7 @@ rules:
|
||||
entity-device-class: done
|
||||
entity-disabled-by-default: done
|
||||
entity-translations: done
|
||||
exception-translations: todo
|
||||
exception-translations: done
|
||||
icon-translations: done
|
||||
reconfiguration-flow: done
|
||||
repair-issues: done
|
||||
|
@ -19,12 +19,10 @@ from reolink_aio.api import (
|
||||
StatusLedEnum,
|
||||
TrackMethodEnum,
|
||||
)
|
||||
from reolink_aio.exceptions import InvalidParameterError, ReolinkError
|
||||
|
||||
from homeassistant.components.select import SelectEntity, SelectEntityDescription
|
||||
from homeassistant.const import EntityCategory, UnitOfDataRate, UnitOfFrequency
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.exceptions import HomeAssistantError, ServiceValidationError
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
|
||||
from .entity import (
|
||||
@ -33,7 +31,7 @@ from .entity import (
|
||||
ReolinkChimeCoordinatorEntity,
|
||||
ReolinkChimeEntityDescription,
|
||||
)
|
||||
from .util import ReolinkConfigEntry, ReolinkData
|
||||
from .util import ReolinkConfigEntry, ReolinkData, raise_translated_error
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
PARALLEL_UPDATES = 0
|
||||
@ -354,14 +352,10 @@ class ReolinkSelectEntity(ReolinkChannelCoordinatorEntity, SelectEntity):
|
||||
self._log_error = True
|
||||
return option
|
||||
|
||||
@raise_translated_error
|
||||
async def async_select_option(self, option: str) -> None:
|
||||
"""Change the selected option."""
|
||||
try:
|
||||
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
|
||||
await self.entity_description.method(self._host.api, self._channel, option)
|
||||
self.async_write_ha_state()
|
||||
|
||||
|
||||
@ -396,12 +390,8 @@ class ReolinkChimeSelectEntity(ReolinkChimeCoordinatorEntity, SelectEntity):
|
||||
self._log_error = True
|
||||
return option
|
||||
|
||||
@raise_translated_error
|
||||
async def async_select_option(self, option: str) -> None:
|
||||
"""Change the selected option."""
|
||||
try:
|
||||
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
|
||||
await self.entity_description.method(self._chime, option)
|
||||
self.async_write_ha_state()
|
||||
|
@ -4,18 +4,17 @@ from __future__ import annotations
|
||||
|
||||
from reolink_aio.api import Chime
|
||||
from reolink_aio.enums import ChimeToneEnum
|
||||
from reolink_aio.exceptions import InvalidParameterError, ReolinkError
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.config_entries import ConfigEntryState
|
||||
from homeassistant.const import ATTR_DEVICE_ID
|
||||
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 .const import DOMAIN
|
||||
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"
|
||||
|
||||
@ -24,6 +23,7 @@ ATTR_RINGTONE = "ringtone"
|
||||
def async_setup_services(hass: HomeAssistant) -> None:
|
||||
"""Set up Reolink services."""
|
||||
|
||||
@raise_translated_error
|
||||
async def async_play_chime(service_call: ServiceCall) -> None:
|
||||
"""Play a ringtone."""
|
||||
service_data = service_call.data
|
||||
@ -58,12 +58,7 @@ def async_setup_services(hass: HomeAssistant) -> None:
|
||||
)
|
||||
|
||||
ringtone = service_data[ATTR_RINGTONE]
|
||||
try:
|
||||
await chime.play(ChimeToneEnum[ringtone].value)
|
||||
except InvalidParameterError as err:
|
||||
raise ServiceValidationError(err) from err
|
||||
except ReolinkError as err:
|
||||
raise HomeAssistantError(err) from err
|
||||
await chime.play(ChimeToneEnum[ringtone].value)
|
||||
|
||||
hass.services.async_register(
|
||||
DOMAIN,
|
||||
|
@ -5,8 +5,6 @@ from __future__ import annotations
|
||||
from dataclasses import dataclass
|
||||
from typing import Any
|
||||
|
||||
from reolink_aio.exceptions import InvalidParameterError, ReolinkError
|
||||
|
||||
from homeassistant.components.siren import (
|
||||
ATTR_DURATION,
|
||||
ATTR_VOLUME_LEVEL,
|
||||
@ -15,11 +13,10 @@ from homeassistant.components.siren import (
|
||||
SirenEntityFeature,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.exceptions import HomeAssistantError, ServiceValidationError
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
|
||||
from .entity import ReolinkChannelCoordinatorEntity, ReolinkChannelEntityDescription
|
||||
from .util import ReolinkConfigEntry, ReolinkData
|
||||
from .util import ReolinkConfigEntry, ReolinkData, raise_translated_error
|
||||
|
||||
PARALLEL_UPDATES = 0
|
||||
|
||||
@ -77,26 +74,15 @@ class ReolinkSirenEntity(ReolinkChannelCoordinatorEntity, SirenEntity):
|
||||
self.entity_description = entity_description
|
||||
super().__init__(reolink_data, channel)
|
||||
|
||||
@raise_translated_error
|
||||
async def async_turn_on(self, **kwargs: Any) -> None:
|
||||
"""Turn on the siren."""
|
||||
if (volume := kwargs.get(ATTR_VOLUME_LEVEL)) is not None:
|
||||
try:
|
||||
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
|
||||
await self._host.api.set_volume(self._channel, int(volume * 100))
|
||||
duration = kwargs.get(ATTR_DURATION)
|
||||
try:
|
||||
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
|
||||
await self._host.api.set_siren(self._channel, True, duration)
|
||||
|
||||
@raise_translated_error
|
||||
async def async_turn_off(self, **kwargs: Any) -> None:
|
||||
"""Turn off the siren."""
|
||||
try:
|
||||
await self._host.api.set_siren(self._channel, False, None)
|
||||
except ReolinkError as err:
|
||||
raise HomeAssistantError(err) from err
|
||||
await self._host.api.set_siren(self._channel, False, None)
|
||||
|
@ -55,6 +55,45 @@
|
||||
},
|
||||
"service_not_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": {
|
||||
|
@ -7,12 +7,10 @@ from dataclasses import dataclass
|
||||
from typing import Any
|
||||
|
||||
from reolink_aio.api import Chime, Host
|
||||
from reolink_aio.exceptions import ReolinkError
|
||||
|
||||
from homeassistant.components.switch import SwitchEntity, SwitchEntityDescription
|
||||
from homeassistant.const import EntityCategory
|
||||
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.entity_platform import AddEntitiesCallback
|
||||
|
||||
@ -25,7 +23,7 @@ from .entity import (
|
||||
ReolinkHostCoordinatorEntity,
|
||||
ReolinkHostEntityDescription,
|
||||
)
|
||||
from .util import ReolinkConfigEntry, ReolinkData
|
||||
from .util import ReolinkConfigEntry, ReolinkData, raise_translated_error
|
||||
|
||||
PARALLEL_UPDATES = 0
|
||||
|
||||
@ -430,20 +428,16 @@ class ReolinkSwitchEntity(ReolinkChannelCoordinatorEntity, SwitchEntity):
|
||||
"""Return true if switch is on."""
|
||||
return self.entity_description.value(self._host.api, self._channel)
|
||||
|
||||
@raise_translated_error
|
||||
async def async_turn_on(self, **kwargs: Any) -> None:
|
||||
"""Turn the entity on."""
|
||||
try:
|
||||
await self.entity_description.method(self._host.api, self._channel, True)
|
||||
except ReolinkError as err:
|
||||
raise HomeAssistantError(err) from err
|
||||
await self.entity_description.method(self._host.api, self._channel, True)
|
||||
self.async_write_ha_state()
|
||||
|
||||
@raise_translated_error
|
||||
async def async_turn_off(self, **kwargs: Any) -> None:
|
||||
"""Turn the entity off."""
|
||||
try:
|
||||
await self.entity_description.method(self._host.api, self._channel, False)
|
||||
except ReolinkError as err:
|
||||
raise HomeAssistantError(err) from err
|
||||
await self.entity_description.method(self._host.api, self._channel, False)
|
||||
self.async_write_ha_state()
|
||||
|
||||
|
||||
@ -466,20 +460,16 @@ class ReolinkNVRSwitchEntity(ReolinkHostCoordinatorEntity, SwitchEntity):
|
||||
"""Return true if switch is on."""
|
||||
return self.entity_description.value(self._host.api)
|
||||
|
||||
@raise_translated_error
|
||||
async def async_turn_on(self, **kwargs: Any) -> None:
|
||||
"""Turn the entity on."""
|
||||
try:
|
||||
await self.entity_description.method(self._host.api, True)
|
||||
except ReolinkError as err:
|
||||
raise HomeAssistantError(err) from err
|
||||
await self.entity_description.method(self._host.api, True)
|
||||
self.async_write_ha_state()
|
||||
|
||||
@raise_translated_error
|
||||
async def async_turn_off(self, **kwargs: Any) -> None:
|
||||
"""Turn the entity off."""
|
||||
try:
|
||||
await self.entity_description.method(self._host.api, False)
|
||||
except ReolinkError as err:
|
||||
raise HomeAssistantError(err) from err
|
||||
await self.entity_description.method(self._host.api, False)
|
||||
self.async_write_ha_state()
|
||||
|
||||
|
||||
@ -503,18 +493,14 @@ class ReolinkChimeSwitchEntity(ReolinkChimeCoordinatorEntity, SwitchEntity):
|
||||
"""Return true if switch is on."""
|
||||
return self.entity_description.value(self._chime)
|
||||
|
||||
@raise_translated_error
|
||||
async def async_turn_on(self, **kwargs: Any) -> None:
|
||||
"""Turn the entity on."""
|
||||
try:
|
||||
await self.entity_description.method(self._chime, True)
|
||||
except ReolinkError as err:
|
||||
raise HomeAssistantError(err) from err
|
||||
await self.entity_description.method(self._chime, True)
|
||||
self.async_write_ha_state()
|
||||
|
||||
@raise_translated_error
|
||||
async def async_turn_off(self, **kwargs: Any) -> None:
|
||||
"""Turn the entity off."""
|
||||
try:
|
||||
await self.entity_description.method(self._chime, False)
|
||||
except ReolinkError as err:
|
||||
raise HomeAssistantError(err) from err
|
||||
await self.entity_description.method(self._chime, False)
|
||||
self.async_write_ha_state()
|
||||
|
@ -24,6 +24,7 @@ from homeassistant.helpers.update_coordinator import (
|
||||
)
|
||||
|
||||
from . import DEVICE_UPDATE_INTERVAL
|
||||
from .const import DOMAIN
|
||||
from .entity import (
|
||||
ReolinkChannelCoordinatorEntity,
|
||||
ReolinkChannelEntityDescription,
|
||||
@ -196,7 +197,9 @@ class ReolinkUpdateBaseEntity(
|
||||
await self._host.api.update_firmware(self._channel)
|
||||
except ReolinkError as err:
|
||||
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
|
||||
finally:
|
||||
self.async_write_ha_state()
|
||||
|
@ -2,10 +2,28 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from collections.abc import Awaitable, Callable, Coroutine
|
||||
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.core import HomeAssistant
|
||||
from homeassistant.exceptions import HomeAssistantError, ServiceValidationError
|
||||
from homeassistant.helpers import device_registry as dr
|
||||
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
|
||||
|
||||
@ -53,3 +71,89 @@ def get_device_uid_and_ch(
|
||||
else:
|
||||
ch = host.api.channel_for_uid(device_uid[1])
|
||||
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