mirror of https://github.com/home-assistant/core
382 lines
13 KiB
Python
382 lines
13 KiB
Python
"""Test the Whirlpool Sixth Sense climate domain."""
|
|
|
|
from unittest.mock import MagicMock
|
|
|
|
from attr import dataclass
|
|
import pytest
|
|
import whirlpool
|
|
|
|
from homeassistant.components.climate import (
|
|
ATTR_CURRENT_HUMIDITY,
|
|
ATTR_CURRENT_TEMPERATURE,
|
|
ATTR_FAN_MODE,
|
|
ATTR_FAN_MODES,
|
|
ATTR_HVAC_MODE,
|
|
ATTR_HVAC_MODES,
|
|
ATTR_MAX_TEMP,
|
|
ATTR_MIN_TEMP,
|
|
ATTR_SWING_MODE,
|
|
ATTR_SWING_MODES,
|
|
ATTR_TARGET_TEMP_STEP,
|
|
DOMAIN as CLIMATE_DOMAIN,
|
|
FAN_AUTO,
|
|
FAN_HIGH,
|
|
FAN_LOW,
|
|
FAN_MEDIUM,
|
|
FAN_MIDDLE,
|
|
FAN_OFF,
|
|
SERVICE_SET_FAN_MODE,
|
|
SERVICE_SET_HVAC_MODE,
|
|
SERVICE_SET_SWING_MODE,
|
|
SERVICE_SET_TEMPERATURE,
|
|
SWING_HORIZONTAL,
|
|
SWING_OFF,
|
|
ClimateEntityFeature,
|
|
HVACMode,
|
|
)
|
|
from homeassistant.const import (
|
|
ATTR_ENTITY_ID,
|
|
ATTR_FRIENDLY_NAME,
|
|
ATTR_SUPPORTED_FEATURES,
|
|
ATTR_TEMPERATURE,
|
|
SERVICE_TURN_OFF,
|
|
SERVICE_TURN_ON,
|
|
STATE_UNAVAILABLE,
|
|
)
|
|
from homeassistant.core import HomeAssistant
|
|
from homeassistant.exceptions import ServiceValidationError
|
|
from homeassistant.helpers import entity_registry as er
|
|
|
|
from . import init_integration
|
|
|
|
|
|
async def update_ac_state(
|
|
hass: HomeAssistant,
|
|
entity_id: str,
|
|
mock_aircon_api_instance: MagicMock,
|
|
):
|
|
"""Simulate an update trigger from the API."""
|
|
for call in mock_aircon_api_instance.register_attr_callback.call_args_list:
|
|
update_ha_state_cb = call[0][0]
|
|
update_ha_state_cb()
|
|
await hass.async_block_till_done()
|
|
return hass.states.get(entity_id)
|
|
|
|
|
|
async def test_no_appliances(
|
|
hass: HomeAssistant, mock_appliances_manager_api: MagicMock
|
|
) -> None:
|
|
"""Test the setup of the climate entities when there are no appliances available."""
|
|
mock_appliances_manager_api.return_value.aircons = []
|
|
await init_integration(hass)
|
|
assert len(hass.states.async_all()) == 0
|
|
|
|
|
|
async def test_static_attributes(
|
|
hass: HomeAssistant,
|
|
entity_registry: er.EntityRegistry,
|
|
mock_aircon1_api: MagicMock,
|
|
mock_aircon_api_instances: MagicMock,
|
|
) -> None:
|
|
"""Test static climate attributes."""
|
|
await init_integration(hass)
|
|
|
|
for entity_id in ("climate.said1", "climate.said2"):
|
|
entry = entity_registry.async_get(entity_id)
|
|
assert entry
|
|
assert entry.unique_id == entity_id.split(".")[1]
|
|
|
|
state = hass.states.get(entity_id)
|
|
assert state is not None
|
|
assert state.state != STATE_UNAVAILABLE
|
|
assert state.state == HVACMode.COOL
|
|
|
|
attributes = state.attributes
|
|
assert attributes[ATTR_FRIENDLY_NAME] == "TestZone"
|
|
|
|
assert (
|
|
attributes[ATTR_SUPPORTED_FEATURES]
|
|
== ClimateEntityFeature.TARGET_TEMPERATURE
|
|
| ClimateEntityFeature.FAN_MODE
|
|
| ClimateEntityFeature.SWING_MODE
|
|
| ClimateEntityFeature.TURN_OFF
|
|
| ClimateEntityFeature.TURN_ON
|
|
)
|
|
assert attributes[ATTR_HVAC_MODES] == [
|
|
HVACMode.COOL,
|
|
HVACMode.HEAT,
|
|
HVACMode.FAN_ONLY,
|
|
HVACMode.OFF,
|
|
]
|
|
assert attributes[ATTR_FAN_MODES] == [
|
|
FAN_AUTO,
|
|
FAN_HIGH,
|
|
FAN_MEDIUM,
|
|
FAN_LOW,
|
|
FAN_OFF,
|
|
]
|
|
assert attributes[ATTR_SWING_MODES] == [SWING_HORIZONTAL, SWING_OFF]
|
|
assert attributes[ATTR_TARGET_TEMP_STEP] == 1
|
|
assert attributes[ATTR_MIN_TEMP] == 16
|
|
assert attributes[ATTR_MAX_TEMP] == 30
|
|
|
|
|
|
async def test_dynamic_attributes(
|
|
hass: HomeAssistant,
|
|
mock_aircon_api_instances: MagicMock,
|
|
mock_aircon1_api: MagicMock,
|
|
mock_aircon2_api: MagicMock,
|
|
) -> None:
|
|
"""Test dynamic attributes."""
|
|
await init_integration(hass)
|
|
|
|
@dataclass
|
|
class ClimateTestInstance:
|
|
"""Helper class for multiple climate and mock instances."""
|
|
|
|
entity_id: str
|
|
mock_instance: MagicMock
|
|
mock_instance_idx: int
|
|
|
|
for clim_test_instance in (
|
|
ClimateTestInstance("climate.said1", mock_aircon1_api, 0),
|
|
ClimateTestInstance("climate.said2", mock_aircon2_api, 1),
|
|
):
|
|
entity_id = clim_test_instance.entity_id
|
|
mock_instance = clim_test_instance.mock_instance
|
|
state = hass.states.get(entity_id)
|
|
assert state is not None
|
|
assert state.state == HVACMode.COOL
|
|
|
|
mock_instance.get_power_on.return_value = False
|
|
state = await update_ac_state(hass, entity_id, mock_instance)
|
|
assert state.state == HVACMode.OFF
|
|
|
|
mock_instance.get_online.return_value = False
|
|
state = await update_ac_state(hass, entity_id, mock_instance)
|
|
assert state.state == STATE_UNAVAILABLE
|
|
|
|
mock_instance.get_power_on.return_value = True
|
|
mock_instance.get_online.return_value = True
|
|
state = await update_ac_state(hass, entity_id, mock_instance)
|
|
assert state.state == HVACMode.COOL
|
|
|
|
mock_instance.get_mode.return_value = whirlpool.aircon.Mode.Heat
|
|
state = await update_ac_state(hass, entity_id, mock_instance)
|
|
assert state.state == HVACMode.HEAT
|
|
|
|
mock_instance.get_mode.return_value = whirlpool.aircon.Mode.Fan
|
|
state = await update_ac_state(hass, entity_id, mock_instance)
|
|
assert state.state == HVACMode.FAN_ONLY
|
|
|
|
mock_instance.get_fanspeed.return_value = whirlpool.aircon.FanSpeed.Auto
|
|
state = await update_ac_state(hass, entity_id, mock_instance)
|
|
assert state.attributes[ATTR_FAN_MODE] == HVACMode.AUTO
|
|
|
|
mock_instance.get_fanspeed.return_value = whirlpool.aircon.FanSpeed.Low
|
|
state = await update_ac_state(hass, entity_id, mock_instance)
|
|
assert state.attributes[ATTR_FAN_MODE] == FAN_LOW
|
|
|
|
mock_instance.get_fanspeed.return_value = whirlpool.aircon.FanSpeed.Medium
|
|
state = await update_ac_state(hass, entity_id, mock_instance)
|
|
assert state.attributes[ATTR_FAN_MODE] == FAN_MEDIUM
|
|
|
|
mock_instance.get_fanspeed.return_value = whirlpool.aircon.FanSpeed.High
|
|
state = await update_ac_state(hass, entity_id, mock_instance)
|
|
assert state.attributes[ATTR_FAN_MODE] == FAN_HIGH
|
|
|
|
mock_instance.get_fanspeed.return_value = whirlpool.aircon.FanSpeed.Off
|
|
state = await update_ac_state(hass, entity_id, mock_instance)
|
|
assert state.attributes[ATTR_FAN_MODE] == FAN_OFF
|
|
|
|
mock_instance.get_current_temp.return_value = 15
|
|
mock_instance.get_temp.return_value = 20
|
|
mock_instance.get_current_humidity.return_value = 80
|
|
mock_instance.get_h_louver_swing.return_value = True
|
|
attributes = (await update_ac_state(hass, entity_id, mock_instance)).attributes
|
|
assert attributes[ATTR_CURRENT_TEMPERATURE] == 15
|
|
assert attributes[ATTR_TEMPERATURE] == 20
|
|
assert attributes[ATTR_CURRENT_HUMIDITY] == 80
|
|
assert attributes[ATTR_SWING_MODE] == SWING_HORIZONTAL
|
|
|
|
mock_instance.get_current_temp.return_value = 16
|
|
mock_instance.get_temp.return_value = 21
|
|
mock_instance.get_current_humidity.return_value = 70
|
|
mock_instance.get_h_louver_swing.return_value = False
|
|
attributes = (await update_ac_state(hass, entity_id, mock_instance)).attributes
|
|
assert attributes[ATTR_CURRENT_TEMPERATURE] == 16
|
|
assert attributes[ATTR_TEMPERATURE] == 21
|
|
assert attributes[ATTR_CURRENT_HUMIDITY] == 70
|
|
assert attributes[ATTR_SWING_MODE] == SWING_OFF
|
|
|
|
|
|
async def test_service_calls(
|
|
hass: HomeAssistant,
|
|
mock_aircon_api_instances: MagicMock,
|
|
mock_aircon1_api: MagicMock,
|
|
mock_aircon2_api: MagicMock,
|
|
) -> None:
|
|
"""Test controlling the entity through service calls."""
|
|
await init_integration(hass)
|
|
|
|
@dataclass
|
|
class ClimateInstancesData:
|
|
"""Helper class for multiple climate and mock instances."""
|
|
|
|
entity_id: str
|
|
mock_instance: MagicMock
|
|
|
|
for clim_test_instance in (
|
|
ClimateInstancesData("climate.said1", mock_aircon1_api),
|
|
ClimateInstancesData("climate.said2", mock_aircon2_api),
|
|
):
|
|
mock_instance = clim_test_instance.mock_instance
|
|
entity_id = clim_test_instance.entity_id
|
|
|
|
await hass.services.async_call(
|
|
CLIMATE_DOMAIN,
|
|
SERVICE_TURN_OFF,
|
|
{ATTR_ENTITY_ID: entity_id},
|
|
blocking=True,
|
|
)
|
|
mock_instance.set_power_on.assert_called_once_with(False)
|
|
|
|
mock_instance.set_power_on.reset_mock()
|
|
await hass.services.async_call(
|
|
CLIMATE_DOMAIN,
|
|
SERVICE_TURN_ON,
|
|
{ATTR_ENTITY_ID: entity_id},
|
|
blocking=True,
|
|
)
|
|
mock_instance.set_power_on.assert_called_once_with(True)
|
|
|
|
mock_instance.set_power_on.reset_mock()
|
|
mock_instance.get_power_on.return_value = False
|
|
await hass.services.async_call(
|
|
CLIMATE_DOMAIN,
|
|
SERVICE_SET_HVAC_MODE,
|
|
{ATTR_ENTITY_ID: entity_id, ATTR_HVAC_MODE: HVACMode.COOL},
|
|
blocking=True,
|
|
)
|
|
mock_instance.set_power_on.assert_called_once_with(True)
|
|
|
|
mock_instance.set_temp.reset_mock()
|
|
await hass.services.async_call(
|
|
CLIMATE_DOMAIN,
|
|
SERVICE_SET_TEMPERATURE,
|
|
{ATTR_ENTITY_ID: entity_id, ATTR_TEMPERATURE: 16},
|
|
blocking=True,
|
|
)
|
|
mock_instance.set_temp.assert_called_once_with(16)
|
|
|
|
mock_instance.set_mode.reset_mock()
|
|
await hass.services.async_call(
|
|
CLIMATE_DOMAIN,
|
|
SERVICE_SET_HVAC_MODE,
|
|
{ATTR_ENTITY_ID: entity_id, ATTR_HVAC_MODE: HVACMode.COOL},
|
|
blocking=True,
|
|
)
|
|
mock_instance.set_mode.assert_called_once_with(whirlpool.aircon.Mode.Cool)
|
|
|
|
mock_instance.set_mode.reset_mock()
|
|
await hass.services.async_call(
|
|
CLIMATE_DOMAIN,
|
|
SERVICE_SET_HVAC_MODE,
|
|
{ATTR_ENTITY_ID: entity_id, ATTR_HVAC_MODE: HVACMode.HEAT},
|
|
blocking=True,
|
|
)
|
|
mock_instance.set_mode.assert_called_once_with(whirlpool.aircon.Mode.Heat)
|
|
|
|
mock_instance.set_mode.reset_mock()
|
|
# HVACMode.DRY is not supported
|
|
with pytest.raises(ValueError):
|
|
await hass.services.async_call(
|
|
CLIMATE_DOMAIN,
|
|
SERVICE_SET_HVAC_MODE,
|
|
{ATTR_ENTITY_ID: entity_id, ATTR_HVAC_MODE: HVACMode.DRY},
|
|
blocking=True,
|
|
)
|
|
mock_instance.set_mode.assert_not_called()
|
|
|
|
mock_instance.set_mode.reset_mock()
|
|
await hass.services.async_call(
|
|
CLIMATE_DOMAIN,
|
|
SERVICE_SET_HVAC_MODE,
|
|
{ATTR_ENTITY_ID: entity_id, ATTR_HVAC_MODE: HVACMode.FAN_ONLY},
|
|
blocking=True,
|
|
)
|
|
mock_instance.set_mode.assert_called_once_with(whirlpool.aircon.Mode.Fan)
|
|
|
|
mock_instance.set_fanspeed.reset_mock()
|
|
await hass.services.async_call(
|
|
CLIMATE_DOMAIN,
|
|
SERVICE_SET_FAN_MODE,
|
|
{ATTR_ENTITY_ID: entity_id, ATTR_FAN_MODE: FAN_AUTO},
|
|
blocking=True,
|
|
)
|
|
mock_instance.set_fanspeed.assert_called_once_with(
|
|
whirlpool.aircon.FanSpeed.Auto
|
|
)
|
|
|
|
mock_instance.set_fanspeed.reset_mock()
|
|
await hass.services.async_call(
|
|
CLIMATE_DOMAIN,
|
|
SERVICE_SET_FAN_MODE,
|
|
{ATTR_ENTITY_ID: entity_id, ATTR_FAN_MODE: FAN_LOW},
|
|
blocking=True,
|
|
)
|
|
mock_instance.set_fanspeed.assert_called_once_with(
|
|
whirlpool.aircon.FanSpeed.Low
|
|
)
|
|
|
|
mock_instance.set_fanspeed.reset_mock()
|
|
await hass.services.async_call(
|
|
CLIMATE_DOMAIN,
|
|
SERVICE_SET_FAN_MODE,
|
|
{ATTR_ENTITY_ID: entity_id, ATTR_FAN_MODE: FAN_MEDIUM},
|
|
blocking=True,
|
|
)
|
|
mock_instance.set_fanspeed.assert_called_once_with(
|
|
whirlpool.aircon.FanSpeed.Medium
|
|
)
|
|
|
|
mock_instance.set_fanspeed.reset_mock()
|
|
# FAN_MIDDLE is not supported
|
|
with pytest.raises(ServiceValidationError):
|
|
await hass.services.async_call(
|
|
CLIMATE_DOMAIN,
|
|
SERVICE_SET_FAN_MODE,
|
|
{ATTR_ENTITY_ID: entity_id, ATTR_FAN_MODE: FAN_MIDDLE},
|
|
blocking=True,
|
|
)
|
|
mock_instance.set_fanspeed.assert_not_called()
|
|
|
|
mock_instance.set_fanspeed.reset_mock()
|
|
await hass.services.async_call(
|
|
CLIMATE_DOMAIN,
|
|
SERVICE_SET_FAN_MODE,
|
|
{ATTR_ENTITY_ID: entity_id, ATTR_FAN_MODE: FAN_HIGH},
|
|
blocking=True,
|
|
)
|
|
mock_instance.set_fanspeed.assert_called_once_with(
|
|
whirlpool.aircon.FanSpeed.High
|
|
)
|
|
|
|
mock_instance.set_h_louver_swing.reset_mock()
|
|
await hass.services.async_call(
|
|
CLIMATE_DOMAIN,
|
|
SERVICE_SET_SWING_MODE,
|
|
{ATTR_ENTITY_ID: entity_id, ATTR_SWING_MODE: SWING_HORIZONTAL},
|
|
blocking=True,
|
|
)
|
|
mock_instance.set_h_louver_swing.assert_called_with(True)
|
|
|
|
mock_instance.set_h_louver_swing.reset_mock()
|
|
await hass.services.async_call(
|
|
CLIMATE_DOMAIN,
|
|
SERVICE_SET_SWING_MODE,
|
|
{ATTR_ENTITY_ID: entity_id, ATTR_SWING_MODE: SWING_OFF},
|
|
blocking=True,
|
|
)
|
|
mock_instance.set_h_louver_swing.assert_called_with(False)
|