mirror of
https://github.com/home-assistant/core.git
synced 2025-07-19 03:07:37 +00:00
Add error handling to Tailwind service methods (#106463)
This commit is contained in:
parent
68ac4717dc
commit
a78ecb3895
@ -5,7 +5,7 @@ from collections.abc import Awaitable, Callable
|
||||
from dataclasses import dataclass
|
||||
from typing import Any
|
||||
|
||||
from gotailwind import Tailwind
|
||||
from gotailwind import Tailwind, TailwindError
|
||||
|
||||
from homeassistant.components.button import (
|
||||
ButtonDeviceClass,
|
||||
@ -15,6 +15,7 @@ from homeassistant.components.button import (
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import EntityCategory
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
|
||||
from .const import DOMAIN
|
||||
@ -62,4 +63,11 @@ class TailwindButtonEntity(TailwindEntity, ButtonEntity):
|
||||
|
||||
async def async_press(self) -> None:
|
||||
"""Trigger button press on the Tailwind device."""
|
||||
try:
|
||||
await self.entity_description.press_fn(self.coordinator.tailwind)
|
||||
except TailwindError as exc:
|
||||
raise HomeAssistantError(
|
||||
str(exc),
|
||||
translation_domain=DOMAIN,
|
||||
translation_key="communication_error",
|
||||
) from exc
|
||||
|
@ -3,7 +3,13 @@ from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
|
||||
from gotailwind import TailwindDoorOperationCommand, TailwindDoorState
|
||||
from gotailwind import (
|
||||
TailwindDoorDisabledError,
|
||||
TailwindDoorLockedOutError,
|
||||
TailwindDoorOperationCommand,
|
||||
TailwindDoorState,
|
||||
TailwindError,
|
||||
)
|
||||
|
||||
from homeassistant.components.cover import (
|
||||
CoverDeviceClass,
|
||||
@ -12,6 +18,7 @@ from homeassistant.components.cover import (
|
||||
)
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
|
||||
from .const import DOMAIN
|
||||
@ -56,10 +63,30 @@ class TailwindDoorCoverEntity(TailwindDoorEntity, CoverEntity):
|
||||
"""
|
||||
self._attr_is_opening = True
|
||||
self.async_write_ha_state()
|
||||
try:
|
||||
await self.coordinator.tailwind.operate(
|
||||
door=self.coordinator.data.doors[self.door_id],
|
||||
operation=TailwindDoorOperationCommand.OPEN,
|
||||
)
|
||||
except TailwindDoorDisabledError as exc:
|
||||
raise HomeAssistantError(
|
||||
str(exc),
|
||||
translation_domain=DOMAIN,
|
||||
translation_key="door_disabled",
|
||||
) from exc
|
||||
except TailwindDoorLockedOutError as exc:
|
||||
raise HomeAssistantError(
|
||||
str(exc),
|
||||
translation_domain=DOMAIN,
|
||||
translation_key="door_locked_out",
|
||||
) from exc
|
||||
except TailwindError as exc:
|
||||
raise HomeAssistantError(
|
||||
str(exc),
|
||||
translation_domain=DOMAIN,
|
||||
translation_key="communication_error",
|
||||
) from exc
|
||||
finally:
|
||||
self._attr_is_opening = False
|
||||
await self.coordinator.async_request_refresh()
|
||||
|
||||
@ -71,9 +98,28 @@ class TailwindDoorCoverEntity(TailwindDoorEntity, CoverEntity):
|
||||
"""
|
||||
self._attr_is_closing = True
|
||||
self.async_write_ha_state()
|
||||
try:
|
||||
await self.coordinator.tailwind.operate(
|
||||
door=self.coordinator.data.doors[self.door_id],
|
||||
operation=TailwindDoorOperationCommand.CLOSE,
|
||||
)
|
||||
except TailwindDoorDisabledError as exc:
|
||||
raise HomeAssistantError(
|
||||
str(exc),
|
||||
translation_domain=DOMAIN,
|
||||
translation_key="door_disabled",
|
||||
) from exc
|
||||
except TailwindDoorLockedOutError as exc:
|
||||
raise HomeAssistantError(
|
||||
str(exc),
|
||||
translation_domain=DOMAIN,
|
||||
translation_key="door_locked_out",
|
||||
) from exc
|
||||
except TailwindError as exc:
|
||||
raise HomeAssistantError(
|
||||
str(exc),
|
||||
translation_domain=DOMAIN,
|
||||
translation_key="communication_error",
|
||||
) from exc
|
||||
self._attr_is_closing = False
|
||||
await self.coordinator.async_request_refresh()
|
||||
|
@ -5,12 +5,13 @@ from collections.abc import Awaitable, Callable
|
||||
from dataclasses import dataclass
|
||||
from typing import Any
|
||||
|
||||
from gotailwind import Tailwind, TailwindDeviceStatus
|
||||
from gotailwind import Tailwind, TailwindDeviceStatus, TailwindError
|
||||
|
||||
from homeassistant.components.number import NumberEntity, NumberEntityDescription
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import PERCENTAGE, EntityCategory
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
|
||||
from .const import DOMAIN
|
||||
@ -72,5 +73,12 @@ class TailwindNumberEntity(TailwindEntity, NumberEntity):
|
||||
|
||||
async def async_set_native_value(self, value: float) -> None:
|
||||
"""Change to new number value."""
|
||||
try:
|
||||
await self.entity_description.set_value_fn(self.coordinator.tailwind, value)
|
||||
except TailwindError as exc:
|
||||
raise HomeAssistantError(
|
||||
str(exc),
|
||||
translation_domain=DOMAIN,
|
||||
translation_key="communication_error",
|
||||
) from exc
|
||||
await self.coordinator.async_request_refresh()
|
||||
|
@ -60,5 +60,16 @@
|
||||
"name": "Status LED brightness"
|
||||
}
|
||||
}
|
||||
},
|
||||
"exceptions": {
|
||||
"communication_error": {
|
||||
"message": "An error occurred while communicating with the Tailwind device."
|
||||
},
|
||||
"door_disabled": {
|
||||
"message": "The door is disabled and cannot be operated."
|
||||
},
|
||||
"door_locked_out": {
|
||||
"message": "The door is locked out and cannot be operated."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,12 +1,15 @@
|
||||
"""Tests for button entities provided by the Tailwind integration."""
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
from gotailwind import TailwindError
|
||||
import pytest
|
||||
from syrupy.assertion import SnapshotAssertion
|
||||
|
||||
from homeassistant.components.button import DOMAIN as BUTTON_DOMAIN, SERVICE_PRESS
|
||||
from homeassistant.components.tailwind.const import DOMAIN
|
||||
from homeassistant.const import ATTR_ENTITY_ID
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
from homeassistant.helpers import device_registry as dr, entity_registry as er
|
||||
|
||||
pytestmark = [
|
||||
@ -46,3 +49,17 @@ async def test_number_entities(
|
||||
|
||||
assert (state := hass.states.get(state.entity_id))
|
||||
assert state.state == "2023-12-17T15:25:00+00:00"
|
||||
|
||||
# Test error handling
|
||||
mock_tailwind.identify.side_effect = TailwindError("Some error")
|
||||
|
||||
with pytest.raises(HomeAssistantError, match="Some error") as excinfo:
|
||||
await hass.services.async_call(
|
||||
BUTTON_DOMAIN,
|
||||
SERVICE_PRESS,
|
||||
{ATTR_ENTITY_ID: state.entity_id},
|
||||
blocking=True,
|
||||
)
|
||||
|
||||
assert excinfo.value.translation_domain == DOMAIN
|
||||
assert excinfo.value.translation_key == "communication_error"
|
||||
|
@ -1,7 +1,12 @@
|
||||
"""Tests for cover entities provided by the Tailwind integration."""
|
||||
from unittest.mock import ANY, MagicMock
|
||||
|
||||
from gotailwind import TailwindDoorOperationCommand
|
||||
from gotailwind import (
|
||||
TailwindDoorDisabledError,
|
||||
TailwindDoorLockedOutError,
|
||||
TailwindDoorOperationCommand,
|
||||
TailwindError,
|
||||
)
|
||||
import pytest
|
||||
from syrupy.assertion import SnapshotAssertion
|
||||
|
||||
@ -10,8 +15,10 @@ from homeassistant.components.cover import (
|
||||
SERVICE_CLOSE_COVER,
|
||||
SERVICE_OPEN_COVER,
|
||||
)
|
||||
from homeassistant.components.tailwind.const import DOMAIN
|
||||
from homeassistant.const import ATTR_ENTITY_ID
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
from homeassistant.helpers import device_registry as dr, entity_registry as er
|
||||
|
||||
pytestmark = pytest.mark.usefixtures("init_integration")
|
||||
@ -74,3 +81,90 @@ async def test_cover_operations(
|
||||
mock_tailwind.operate.assert_called_with(
|
||||
door=ANY, operation=TailwindDoorOperationCommand.CLOSE
|
||||
)
|
||||
|
||||
# Test door disabled error handling
|
||||
mock_tailwind.operate.side_effect = TailwindDoorDisabledError("Door disabled")
|
||||
|
||||
with pytest.raises(HomeAssistantError, match="Door disabled") as excinfo:
|
||||
await hass.services.async_call(
|
||||
COVER_DOMAIN,
|
||||
SERVICE_OPEN_COVER,
|
||||
{
|
||||
ATTR_ENTITY_ID: "cover.door_1",
|
||||
},
|
||||
blocking=True,
|
||||
)
|
||||
|
||||
assert excinfo.value.translation_domain == DOMAIN
|
||||
assert excinfo.value.translation_key == "door_disabled"
|
||||
|
||||
with pytest.raises(HomeAssistantError, match="Door disabled") as excinfo:
|
||||
await hass.services.async_call(
|
||||
COVER_DOMAIN,
|
||||
SERVICE_CLOSE_COVER,
|
||||
{
|
||||
ATTR_ENTITY_ID: "cover.door_1",
|
||||
},
|
||||
blocking=True,
|
||||
)
|
||||
|
||||
assert excinfo.value.translation_domain == DOMAIN
|
||||
assert excinfo.value.translation_key == "door_disabled"
|
||||
|
||||
# Test door locked out error handling
|
||||
mock_tailwind.operate.side_effect = TailwindDoorLockedOutError("Door locked out")
|
||||
|
||||
with pytest.raises(HomeAssistantError, match="Door locked out") as excinfo:
|
||||
await hass.services.async_call(
|
||||
COVER_DOMAIN,
|
||||
SERVICE_OPEN_COVER,
|
||||
{
|
||||
ATTR_ENTITY_ID: "cover.door_1",
|
||||
},
|
||||
blocking=True,
|
||||
)
|
||||
|
||||
assert excinfo.value.translation_domain == DOMAIN
|
||||
assert excinfo.value.translation_key == "door_locked_out"
|
||||
|
||||
with pytest.raises(HomeAssistantError, match="Door locked out") as excinfo:
|
||||
await hass.services.async_call(
|
||||
COVER_DOMAIN,
|
||||
SERVICE_CLOSE_COVER,
|
||||
{
|
||||
ATTR_ENTITY_ID: "cover.door_1",
|
||||
},
|
||||
blocking=True,
|
||||
)
|
||||
|
||||
assert excinfo.value.translation_domain == DOMAIN
|
||||
assert excinfo.value.translation_key == "door_locked_out"
|
||||
|
||||
# Test door error handling
|
||||
mock_tailwind.operate.side_effect = TailwindError("Some error")
|
||||
|
||||
with pytest.raises(HomeAssistantError, match="Some error") as excinfo:
|
||||
await hass.services.async_call(
|
||||
COVER_DOMAIN,
|
||||
SERVICE_OPEN_COVER,
|
||||
{
|
||||
ATTR_ENTITY_ID: "cover.door_1",
|
||||
},
|
||||
blocking=True,
|
||||
)
|
||||
|
||||
assert excinfo.value.translation_domain == DOMAIN
|
||||
assert excinfo.value.translation_key == "communication_error"
|
||||
|
||||
with pytest.raises(HomeAssistantError, match="Some error") as excinfo:
|
||||
await hass.services.async_call(
|
||||
COVER_DOMAIN,
|
||||
SERVICE_CLOSE_COVER,
|
||||
{
|
||||
ATTR_ENTITY_ID: "cover.door_1",
|
||||
},
|
||||
blocking=True,
|
||||
)
|
||||
|
||||
assert excinfo.value.translation_domain == DOMAIN
|
||||
assert excinfo.value.translation_key == "communication_error"
|
||||
|
@ -1,13 +1,16 @@
|
||||
"""Tests for number entities provided by the Tailwind integration."""
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
from gotailwind import TailwindError
|
||||
import pytest
|
||||
from syrupy.assertion import SnapshotAssertion
|
||||
|
||||
from homeassistant.components import number
|
||||
from homeassistant.components.number import ATTR_VALUE, SERVICE_SET_VALUE
|
||||
from homeassistant.components.tailwind.const import DOMAIN
|
||||
from homeassistant.const import ATTR_ENTITY_ID
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
from homeassistant.helpers import device_registry as dr, entity_registry as er
|
||||
|
||||
pytestmark = pytest.mark.usefixtures("init_integration")
|
||||
@ -44,3 +47,20 @@ async def test_number_entities(
|
||||
|
||||
assert len(mock_tailwind.status_led.mock_calls) == 1
|
||||
mock_tailwind.status_led.assert_called_with(brightness=42)
|
||||
|
||||
# Test error handling
|
||||
mock_tailwind.status_led.side_effect = TailwindError("Some error")
|
||||
|
||||
with pytest.raises(HomeAssistantError, match="Some error") as excinfo:
|
||||
await hass.services.async_call(
|
||||
number.DOMAIN,
|
||||
SERVICE_SET_VALUE,
|
||||
{
|
||||
ATTR_ENTITY_ID: state.entity_id,
|
||||
ATTR_VALUE: 42,
|
||||
},
|
||||
blocking=True,
|
||||
)
|
||||
|
||||
assert excinfo.value.translation_domain == DOMAIN
|
||||
assert excinfo.value.translation_key == "communication_error"
|
||||
|
Loading…
x
Reference in New Issue
Block a user