core/tests/components/bryant_evolution/test_climate.py

260 lines
9.6 KiB
Python

"""Test the BryantEvolutionClient type."""
from collections.abc import Generator
from datetime import timedelta
import logging
from unittest.mock import AsyncMock
from freezegun.api import FrozenDateTimeFactory
import pytest
from syrupy.assertion import SnapshotAssertion
from homeassistant.components.bryant_evolution.climate import SCAN_INTERVAL
from homeassistant.components.climate import (
ATTR_FAN_MODE,
ATTR_HVAC_ACTION,
ATTR_HVAC_MODE,
ATTR_TEMPERATURE,
DOMAIN as CLIMATE_DOMAIN,
SERVICE_SET_FAN_MODE,
SERVICE_SET_HVAC_MODE,
SERVICE_SET_TEMPERATURE,
HVACAction,
)
from homeassistant.const import ATTR_ENTITY_ID
from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry as er
from tests.common import MockConfigEntry, async_fire_time_changed, snapshot_platform
_LOGGER = logging.getLogger(__name__)
async def trigger_polling(hass: HomeAssistant, freezer: FrozenDateTimeFactory) -> None:
"""Trigger a polling event."""
freezer.tick(SCAN_INTERVAL + timedelta(seconds=1))
async_fire_time_changed(hass)
await hass.async_block_till_done()
async def test_setup_integration_success(
hass: HomeAssistant,
entity_registry: er.EntityRegistry,
mock_evolution_entry: MockConfigEntry,
snapshot: SnapshotAssertion,
) -> None:
"""Test that an instance can be constructed."""
await snapshot_platform(
hass, entity_registry, snapshot, mock_evolution_entry.entry_id
)
async def test_set_temperature_mode_cool(
hass: HomeAssistant,
mock_evolution_entry: MockConfigEntry,
mock_evolution_client_factory: Generator[AsyncMock],
freezer: FrozenDateTimeFactory,
) -> None:
"""Test setting the temperature in cool mode."""
# Start with known initial conditions
client = await mock_evolution_client_factory(1, 1, "/dev/unused")
client.read_hvac_mode.return_value = ("COOL", False)
client.read_cooling_setpoint.return_value = 75
await trigger_polling(hass, freezer)
state = hass.states.get("climate.system_1_zone_1")
assert state.attributes["temperature"] == 75, state.attributes
# Make the call, modifting the mock client to throw an exception on
# read to ensure that the update is visible iff we call
# async_update_ha_state.
data = {ATTR_TEMPERATURE: 70}
data[ATTR_ENTITY_ID] = "climate.system_1_zone_1"
client.read_cooling_setpoint.side_effect = Exception("fake failure")
await hass.services.async_call(
CLIMATE_DOMAIN, SERVICE_SET_TEMPERATURE, data, blocking=True
)
# Verify effect.
client.set_cooling_setpoint.assert_called_once_with(70)
state = hass.states.get("climate.system_1_zone_1")
assert state.attributes["temperature"] == 70
async def test_set_temperature_mode_heat(
hass: HomeAssistant,
mock_evolution_entry: MockConfigEntry,
mock_evolution_client_factory: Generator[AsyncMock],
freezer: FrozenDateTimeFactory,
) -> None:
"""Test setting the temperature in heat mode."""
# Start with known initial conditions
client = await mock_evolution_client_factory(1, 1, "/dev/unused")
client.read_hvac_mode.return_value = ("HEAT", False)
client.read_heating_setpoint.return_value = 60
await trigger_polling(hass, freezer)
# Make the call, modifting the mock client to throw an exception on
# read to ensure that the update is visible iff we call
# async_update_ha_state.
data = {"temperature": 65}
data[ATTR_ENTITY_ID] = "climate.system_1_zone_1"
client.read_heating_setpoint.side_effect = Exception("fake failure")
await hass.services.async_call(
CLIMATE_DOMAIN, SERVICE_SET_TEMPERATURE, data, blocking=True
)
# Verify effect.
state = hass.states.get("climate.system_1_zone_1")
assert state.attributes["temperature"] == 65, state.attributes
async def test_set_temperature_mode_heat_cool(
hass: HomeAssistant,
mock_evolution_entry: MockConfigEntry,
mock_evolution_client_factory: Generator[AsyncMock],
freezer: FrozenDateTimeFactory,
) -> None:
"""Test setting the temperature in heat_cool mode."""
# Enter heat_cool with known setpoints
mock_client = await mock_evolution_client_factory(1, 1, "/dev/unused")
mock_client.read_hvac_mode.return_value = ("AUTO", False)
mock_client.read_cooling_setpoint.return_value = 90
mock_client.read_heating_setpoint.return_value = 40
await trigger_polling(hass, freezer)
state = hass.states.get("climate.system_1_zone_1")
assert state.state == "heat_cool"
assert state.attributes["target_temp_low"] == 40
assert state.attributes["target_temp_high"] == 90
# Make the call, modifting the mock client to throw an exception on
# read to ensure that the update is visible iff we call
# async_update_ha_state.
mock_client.read_heating_setpoint.side_effect = Exception("fake failure")
mock_client.read_cooling_setpoint.side_effect = Exception("fake failure")
data = {"target_temp_low": 70, "target_temp_high": 80}
data[ATTR_ENTITY_ID] = "climate.system_1_zone_1"
await hass.services.async_call(
CLIMATE_DOMAIN, SERVICE_SET_TEMPERATURE, data, blocking=True
)
state = hass.states.get("climate.system_1_zone_1")
assert state.attributes["target_temp_low"] == 70, state.attributes
assert state.attributes["target_temp_high"] == 80, state.attributes
mock_client.set_cooling_setpoint.assert_called_once_with(80)
mock_client.set_heating_setpoint.assert_called_once_with(70)
async def test_set_fan_mode(
hass: HomeAssistant,
mock_evolution_entry: MockConfigEntry,
mock_evolution_client_factory: Generator[AsyncMock],
) -> None:
"""Test that setting fan mode works."""
mock_client = await mock_evolution_client_factory(1, 1, "/dev/unused")
fan_modes = ["auto", "low", "med", "high"]
for mode in fan_modes:
# Make the call, modifting the mock client to throw an exception on
# read to ensure that the update is visible iff we call
# async_update_ha_state.
mock_client.read_fan_mode.side_effect = Exception("fake failure")
data = {ATTR_FAN_MODE: mode}
data[ATTR_ENTITY_ID] = "climate.system_1_zone_1"
await hass.services.async_call(
CLIMATE_DOMAIN, SERVICE_SET_FAN_MODE, data, blocking=True
)
assert (
hass.states.get("climate.system_1_zone_1").attributes[ATTR_FAN_MODE] == mode
)
mock_client.set_fan_mode.assert_called_with(mode)
@pytest.mark.parametrize(
("hvac_mode", "evolution_mode"),
[("heat_cool", "auto"), ("heat", "heat"), ("cool", "cool"), ("off", "off")],
)
async def test_set_hvac_mode(
hass: HomeAssistant,
mock_evolution_entry: MockConfigEntry,
mock_evolution_client_factory: Generator[AsyncMock],
hvac_mode,
evolution_mode,
) -> None:
"""Test that setting HVAC mode works."""
mock_client = await mock_evolution_client_factory(1, 1, "/dev/unused")
# Make the call, modifting the mock client to throw an exception on
# read to ensure that the update is visible iff we call
# async_update_ha_state.
data = {ATTR_HVAC_MODE: hvac_mode}
data[ATTR_ENTITY_ID] = "climate.system_1_zone_1"
mock_client.read_hvac_mode.side_effect = Exception("fake failure")
await hass.services.async_call(
CLIMATE_DOMAIN, SERVICE_SET_HVAC_MODE, data, blocking=True
)
await hass.async_block_till_done()
assert hass.states.get("climate.system_1_zone_1").state == evolution_mode
mock_client.set_hvac_mode.assert_called_with(evolution_mode)
@pytest.mark.parametrize(
("curr_temp", "expected_action"),
[(62, HVACAction.HEATING), (70, HVACAction.OFF), (80, HVACAction.COOLING)],
)
async def test_read_hvac_action_heat_cool(
hass: HomeAssistant,
mock_evolution_entry: MockConfigEntry,
mock_evolution_client_factory: Generator[AsyncMock],
freezer: FrozenDateTimeFactory,
curr_temp: int,
expected_action: HVACAction,
) -> None:
"""Test that we can read the current HVAC action in heat_cool mode."""
htsp = 68
clsp = 72
mock_client = await mock_evolution_client_factory(1, 1, "/dev/unused")
mock_client.read_heating_setpoint.return_value = htsp
mock_client.read_cooling_setpoint.return_value = clsp
is_active = curr_temp < htsp or curr_temp > clsp
mock_client.read_hvac_mode.return_value = ("auto", is_active)
mock_client.read_current_temperature.return_value = curr_temp
await trigger_polling(hass, freezer)
state = hass.states.get("climate.system_1_zone_1")
assert state.attributes[ATTR_HVAC_ACTION] == expected_action
@pytest.mark.parametrize(
("mode", "active", "expected_action"),
[
("heat", True, "heating"),
("heat", False, "off"),
("cool", True, "cooling"),
("cool", False, "off"),
("off", False, "off"),
],
)
async def test_read_hvac_action(
hass: HomeAssistant,
mock_evolution_entry: MockConfigEntry,
mock_evolution_client_factory: Generator[AsyncMock],
freezer: FrozenDateTimeFactory,
mode: str,
active: bool,
expected_action: str,
) -> None:
"""Test that we can read the current HVAC action."""
# Initial state should be no action.
assert (
hass.states.get("climate.system_1_zone_1").attributes[ATTR_HVAC_ACTION]
== HVACAction.OFF
)
# Perturb the system and verify we see an action.
mock_client = await mock_evolution_client_factory(1, 1, "/dev/unused")
mock_client.read_heating_setpoint.return_value = 75 # Needed if mode == heat
mock_client.read_hvac_mode.return_value = (mode, active)
await trigger_polling(hass, freezer)
assert (
hass.states.get("climate.system_1_zone_1").attributes[ATTR_HVAC_ACTION]
== expected_action
)