mirror of
https://github.com/home-assistant/core.git
synced 2026-10-06 22:38:02 -04:00
Handle MELCloud Home climate action errors (#183646)
This commit is contained in:
@@ -20,7 +20,7 @@ from homeassistant.const import ATTR_TEMPERATURE, UnitOfTemperature
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
|
||||
from .common import async_setup_unit_entities
|
||||
from .common import async_setup_unit_entities, perform_action
|
||||
from .coordinator import MelCloudHomeConfigEntry, MelCloudHomeCoordinator
|
||||
from .entity import MelCloudHomeATAUnitEntity, MelCloudHomeATWZoneEntity
|
||||
|
||||
@@ -253,22 +253,29 @@ class ATAClimateEntity(MelCloudHomeATAUnitEntity, ClimateEntity):
|
||||
async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None:
|
||||
"""Set the HVAC mode."""
|
||||
if hvac_mode == HVACMode.OFF:
|
||||
await self.coordinator.client.control_ata_unit(self._unit_id, power=False)
|
||||
await perform_action(
|
||||
self.coordinator,
|
||||
self.coordinator.client.control_ata_unit(self._unit_id, power=False),
|
||||
)
|
||||
else:
|
||||
await self.coordinator.client.control_ata_unit(
|
||||
self._unit_id,
|
||||
power=True,
|
||||
operation_mode=ATA_HVAC_MODE_TO_OPERATION[hvac_mode],
|
||||
await perform_action(
|
||||
self.coordinator,
|
||||
self.coordinator.client.control_ata_unit(
|
||||
self._unit_id,
|
||||
power=True,
|
||||
operation_mode=ATA_HVAC_MODE_TO_OPERATION[hvac_mode],
|
||||
),
|
||||
)
|
||||
await self.coordinator.async_request_refresh()
|
||||
|
||||
@override
|
||||
async def async_set_temperature(self, **kwargs: Any) -> None:
|
||||
"""Set the target temperature."""
|
||||
await self.coordinator.client.control_ata_unit(
|
||||
self._unit_id, set_temperature=kwargs[ATTR_TEMPERATURE]
|
||||
await perform_action(
|
||||
self.coordinator,
|
||||
self.coordinator.client.control_ata_unit(
|
||||
self._unit_id, set_temperature=kwargs[ATTR_TEMPERATURE]
|
||||
),
|
||||
)
|
||||
await self.coordinator.async_request_refresh()
|
||||
|
||||
@property
|
||||
@override
|
||||
@@ -285,39 +292,52 @@ class ATAClimateEntity(MelCloudHomeATAUnitEntity, ClimateEntity):
|
||||
@override
|
||||
async def async_set_swing_horizontal_mode(self, swing_horizontal_mode: str) -> None:
|
||||
"""Set the horizontal vane direction."""
|
||||
await self.coordinator.client.control_ata_unit(
|
||||
self._unit_id,
|
||||
vane_horizontal_direction=HA_VANE_HORIZONTAL_TO_ATA[swing_horizontal_mode],
|
||||
await perform_action(
|
||||
self.coordinator,
|
||||
self.coordinator.client.control_ata_unit(
|
||||
self._unit_id,
|
||||
vane_horizontal_direction=HA_VANE_HORIZONTAL_TO_ATA[
|
||||
swing_horizontal_mode
|
||||
],
|
||||
),
|
||||
)
|
||||
await self.coordinator.async_request_refresh()
|
||||
|
||||
@override
|
||||
async def async_set_swing_mode(self, swing_mode: str) -> None:
|
||||
"""Set the vertical vane direction."""
|
||||
await self.coordinator.client.control_ata_unit(
|
||||
self._unit_id, vane_vertical_direction=HA_VANE_VERTICAL_TO_ATA[swing_mode]
|
||||
await perform_action(
|
||||
self.coordinator,
|
||||
self.coordinator.client.control_ata_unit(
|
||||
self._unit_id,
|
||||
vane_vertical_direction=HA_VANE_VERTICAL_TO_ATA[swing_mode],
|
||||
),
|
||||
)
|
||||
await self.coordinator.async_request_refresh()
|
||||
|
||||
@override
|
||||
async def async_set_fan_mode(self, fan_mode: str) -> None:
|
||||
"""Set the fan mode."""
|
||||
await self.coordinator.client.control_ata_unit(
|
||||
self._unit_id, set_fan_speed=HA_FAN_SPEED_TO_ATA[fan_mode]
|
||||
await perform_action(
|
||||
self.coordinator,
|
||||
self.coordinator.client.control_ata_unit(
|
||||
self._unit_id, set_fan_speed=HA_FAN_SPEED_TO_ATA[fan_mode]
|
||||
),
|
||||
)
|
||||
await self.coordinator.async_request_refresh()
|
||||
|
||||
@override
|
||||
async def async_turn_on(self) -> None:
|
||||
"""Turn the unit on."""
|
||||
await self.coordinator.client.control_ata_unit(self._unit_id, power=True)
|
||||
await self.coordinator.async_request_refresh()
|
||||
await perform_action(
|
||||
self.coordinator,
|
||||
self.coordinator.client.control_ata_unit(self._unit_id, power=True),
|
||||
)
|
||||
|
||||
@override
|
||||
async def async_turn_off(self) -> None:
|
||||
"""Turn the unit off."""
|
||||
await self.coordinator.client.control_ata_unit(self._unit_id, power=False)
|
||||
await self.coordinator.async_request_refresh()
|
||||
await perform_action(
|
||||
self.coordinator,
|
||||
self.coordinator.client.control_ata_unit(self._unit_id, power=False),
|
||||
)
|
||||
|
||||
|
||||
class ATWZoneClimateEntity(MelCloudHomeATWZoneEntity, ClimateEntity):
|
||||
@@ -414,45 +434,62 @@ class ATWZoneClimateEntity(MelCloudHomeATWZoneEntity, ClimateEntity):
|
||||
async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None:
|
||||
"""Set the HVAC mode."""
|
||||
if hvac_mode == HVACMode.OFF:
|
||||
await self.coordinator.client.control_atw_unit(self._unit_id, power=False)
|
||||
await perform_action(
|
||||
self.coordinator,
|
||||
self.coordinator.client.control_atw_unit(self._unit_id, power=False),
|
||||
)
|
||||
else:
|
||||
zone_mode = HVAC_MODE_TO_ATW_ZONE_MODE[hvac_mode]
|
||||
if self.zone_number == 1:
|
||||
await self.coordinator.client.control_atw_unit(
|
||||
self._unit_id,
|
||||
power=True,
|
||||
operation_mode_zone1=zone_mode,
|
||||
await perform_action(
|
||||
self.coordinator,
|
||||
self.coordinator.client.control_atw_unit(
|
||||
self._unit_id,
|
||||
power=True,
|
||||
operation_mode_zone1=zone_mode,
|
||||
),
|
||||
)
|
||||
else:
|
||||
await self.coordinator.client.control_atw_unit(
|
||||
self._unit_id,
|
||||
power=True,
|
||||
operation_mode_zone2=zone_mode,
|
||||
await perform_action(
|
||||
self.coordinator,
|
||||
self.coordinator.client.control_atw_unit(
|
||||
self._unit_id,
|
||||
power=True,
|
||||
operation_mode_zone2=zone_mode,
|
||||
),
|
||||
)
|
||||
await self.coordinator.async_request_refresh()
|
||||
|
||||
@override
|
||||
async def async_set_temperature(self, **kwargs: Any) -> None:
|
||||
"""Set the target temperature."""
|
||||
temperature = kwargs[ATTR_TEMPERATURE]
|
||||
if self.zone_number == 1:
|
||||
await self.coordinator.client.control_atw_unit(
|
||||
self._unit_id, set_temperature_zone1=temperature
|
||||
await perform_action(
|
||||
self.coordinator,
|
||||
self.coordinator.client.control_atw_unit(
|
||||
self._unit_id, set_temperature_zone1=temperature
|
||||
),
|
||||
)
|
||||
else:
|
||||
await self.coordinator.client.control_atw_unit(
|
||||
self._unit_id, set_temperature_zone2=temperature
|
||||
await perform_action(
|
||||
self.coordinator,
|
||||
self.coordinator.client.control_atw_unit(
|
||||
self._unit_id, set_temperature_zone2=temperature
|
||||
),
|
||||
)
|
||||
await self.coordinator.async_request_refresh()
|
||||
|
||||
@override
|
||||
async def async_turn_on(self) -> None:
|
||||
"""Turn the zone on."""
|
||||
await self.coordinator.client.control_atw_unit(self._unit_id, power=True)
|
||||
await self.coordinator.async_request_refresh()
|
||||
await perform_action(
|
||||
self.coordinator,
|
||||
self.coordinator.client.control_atw_unit(self._unit_id, power=True),
|
||||
)
|
||||
|
||||
@override
|
||||
async def async_turn_off(self) -> None:
|
||||
"""Turn the zone off."""
|
||||
await self.coordinator.client.control_atw_unit(self._unit_id, power=False)
|
||||
await self.coordinator.async_request_refresh()
|
||||
await perform_action(
|
||||
self.coordinator,
|
||||
self.coordinator.client.control_atw_unit(self._unit_id, power=False),
|
||||
)
|
||||
|
||||
@@ -10,6 +10,9 @@ from aiomelcloudhome import (
|
||||
ATAVaneHorizontal,
|
||||
ATAVaneVertical,
|
||||
ATWZoneMode,
|
||||
MelCloudHomeAuthenticationError,
|
||||
MelCloudHomeConnectionError,
|
||||
MelCloudHomeTimeoutError,
|
||||
UserContext,
|
||||
)
|
||||
import pytest
|
||||
@@ -36,6 +39,7 @@ from homeassistant.const import (
|
||||
Platform,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
|
||||
from . import setup_integration
|
||||
@@ -521,3 +525,112 @@ async def test_atw_zone_temperature_range(
|
||||
assert (state2 := hass.states.get(ATW_ZONE2_ENTITY_ID))
|
||||
assert state2.attributes["min_temp"] == 12.0
|
||||
assert state2.attributes["max_temp"] == 28.0
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("entity_id", "method", "service", "service_data"),
|
||||
[
|
||||
pytest.param(
|
||||
ATA_ENTITY_ID,
|
||||
"control_ata_unit",
|
||||
SERVICE_SET_HVAC_MODE,
|
||||
{ATTR_HVAC_MODE: HVACMode.HEAT},
|
||||
id="ata_set_hvac_mode",
|
||||
),
|
||||
pytest.param(
|
||||
ATA_ENTITY_ID,
|
||||
"control_ata_unit",
|
||||
SERVICE_SET_TEMPERATURE,
|
||||
{ATTR_TEMPERATURE: 23.0},
|
||||
id="ata_set_temperature",
|
||||
),
|
||||
pytest.param(
|
||||
ATA_ENTITY_ID,
|
||||
"control_ata_unit",
|
||||
SERVICE_SET_FAN_MODE,
|
||||
{ATTR_FAN_MODE: "auto"},
|
||||
id="ata_set_fan_mode",
|
||||
),
|
||||
pytest.param(
|
||||
ATA_ENTITY_ID,
|
||||
"control_ata_unit",
|
||||
SERVICE_SET_SWING_MODE,
|
||||
{ATTR_SWING_MODE: "auto"},
|
||||
id="ata_set_swing_mode",
|
||||
),
|
||||
pytest.param(
|
||||
ATA_ENTITY_ID,
|
||||
"control_ata_unit",
|
||||
SERVICE_SET_SWING_HORIZONTAL_MODE,
|
||||
{ATTR_SWING_HORIZONTAL_MODE: "auto"},
|
||||
id="ata_set_swing_horizontal_mode",
|
||||
),
|
||||
pytest.param(
|
||||
ATA_ENTITY_ID, "control_ata_unit", SERVICE_TURN_ON, {}, id="ata_turn_on"
|
||||
),
|
||||
pytest.param(
|
||||
ATA_ENTITY_ID, "control_ata_unit", SERVICE_TURN_OFF, {}, id="ata_turn_off"
|
||||
),
|
||||
pytest.param(
|
||||
ATW_ZONE1_ENTITY_ID,
|
||||
"control_atw_unit",
|
||||
SERVICE_SET_HVAC_MODE,
|
||||
{ATTR_HVAC_MODE: HVACMode.HEAT},
|
||||
id="atw_set_hvac_mode",
|
||||
),
|
||||
pytest.param(
|
||||
ATW_ZONE1_ENTITY_ID,
|
||||
"control_atw_unit",
|
||||
SERVICE_SET_TEMPERATURE,
|
||||
{ATTR_TEMPERATURE: 23.0},
|
||||
id="atw_set_temperature",
|
||||
),
|
||||
pytest.param(
|
||||
ATW_ZONE1_ENTITY_ID,
|
||||
"control_atw_unit",
|
||||
SERVICE_TURN_ON,
|
||||
{},
|
||||
id="atw_turn_on",
|
||||
),
|
||||
pytest.param(
|
||||
ATW_ZONE1_ENTITY_ID,
|
||||
"control_atw_unit",
|
||||
SERVICE_TURN_OFF,
|
||||
{},
|
||||
id="atw_turn_off",
|
||||
),
|
||||
],
|
||||
)
|
||||
@pytest.mark.parametrize(
|
||||
("raise_exception", "translation_key"),
|
||||
[
|
||||
(MelCloudHomeAuthenticationError, "invalid_auth"),
|
||||
(MelCloudHomeConnectionError, "cannot_connect"),
|
||||
(MelCloudHomeTimeoutError, "timeout_connect"),
|
||||
],
|
||||
)
|
||||
async def test_action_exceptions(
|
||||
hass: HomeAssistant,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
mock_melcloud_client: AsyncMock,
|
||||
entity_id: str,
|
||||
method: str,
|
||||
service: str,
|
||||
service_data: dict[str, Any],
|
||||
raise_exception: type[Exception],
|
||||
translation_key: str,
|
||||
) -> None:
|
||||
"""Test climate actions raise translated errors on client errors."""
|
||||
await setup_integration(hass, mock_config_entry)
|
||||
|
||||
getattr(mock_melcloud_client, method).side_effect = raise_exception
|
||||
|
||||
with pytest.raises(HomeAssistantError) as exc_info:
|
||||
await hass.services.async_call(
|
||||
CLIMATE_DOMAIN,
|
||||
service,
|
||||
{ATTR_ENTITY_ID: entity_id, **service_data},
|
||||
blocking=True,
|
||||
)
|
||||
|
||||
assert exc_info.value.translation_key == translation_key
|
||||
|
||||
Reference in New Issue
Block a user