core/tests/components/blebox/test_climate.py

344 lines
10 KiB
Python

"""BleBox climate entities tests."""
import logging
from unittest.mock import AsyncMock, PropertyMock
import blebox_uniapi
import pytest
from homeassistant.components.climate import (
ATTR_CURRENT_TEMPERATURE,
ATTR_HVAC_ACTION,
ATTR_HVAC_MODE,
ATTR_HVAC_MODES,
ATTR_MAX_TEMP,
ATTR_MIN_TEMP,
SERVICE_SET_HVAC_MODE,
SERVICE_SET_TEMPERATURE,
ClimateEntityFeature,
HVACAction,
HVACMode,
)
from homeassistant.const import (
ATTR_DEVICE_CLASS,
ATTR_ENTITY_ID,
ATTR_SUPPORTED_FEATURES,
ATTR_TEMPERATURE,
STATE_UNKNOWN,
)
from homeassistant.core import HomeAssistant
from homeassistant.helpers import device_registry as dr
from .conftest import async_setup_entity, mock_feature
@pytest.fixture(name="saunabox")
def saunabox_fixture():
"""Return a default climate entity mock."""
feature = mock_feature(
"climates",
blebox_uniapi.climate.Climate,
unique_id="BleBox-saunaBox-1afe34db9437-thermostat",
full_name="saunaBox-thermostat",
device_class=None,
is_on=None,
desired=None,
current=None,
min_temp=-54.3,
max_temp=124.3,
mode=None,
hvac_action=None,
)
product = feature.product
type(product).name = PropertyMock(return_value="My sauna")
type(product).model = PropertyMock(return_value="saunaBox")
return (feature, "climate.saunabox_thermostat")
@pytest.fixture(name="thermobox")
def thermobox_fixture():
"""Return a default climate entity mock."""
feature = mock_feature(
"climates",
blebox_uniapi.climate.Climate,
unique_id="BleBox-thermoBox-1afe34db9437-thermostat",
full_name="thermoBox-thermostat",
device_class=None,
is_on=None,
desired=None,
current=None,
min_temp=-54.3,
max_temp=124.3,
mode=2,
hvac_action=1,
)
product = feature.product
type(product).name = PropertyMock(return_value="My thermo")
type(product).model = PropertyMock(return_value="thermoBox")
return (feature, "climate.thermobox_thermostat")
async def test_init(
saunabox, hass: HomeAssistant, device_registry: dr.DeviceRegistry
) -> None:
"""Test default state."""
_, entity_id = saunabox
entry = await async_setup_entity(hass, entity_id)
assert entry.unique_id == "BleBox-saunaBox-1afe34db9437-thermostat"
state = hass.states.get(entity_id)
assert state.name == "saunaBox-thermostat"
supported_features = state.attributes[ATTR_SUPPORTED_FEATURES]
assert supported_features & ClimateEntityFeature.TARGET_TEMPERATURE
assert state.attributes[ATTR_HVAC_MODES] == [HVACMode.OFF, None]
assert ATTR_DEVICE_CLASS not in state.attributes
assert ATTR_HVAC_MODE not in state.attributes
assert ATTR_HVAC_ACTION not in state.attributes
assert state.attributes[ATTR_MIN_TEMP] == -54.3
assert state.attributes[ATTR_MAX_TEMP] == 124.3
assert state.attributes[ATTR_TEMPERATURE] is None
assert state.attributes[ATTR_CURRENT_TEMPERATURE] is None
assert state.state == STATE_UNKNOWN
device = device_registry.async_get(entry.device_id)
assert device.name == "My sauna"
assert device.identifiers == {("blebox", "abcd0123ef5678")}
assert device.manufacturer == "BleBox"
assert device.model == "saunaBox"
assert device.sw_version == "1.23"
async def test_update(saunabox, hass: HomeAssistant, config) -> None:
"""Test updating."""
feature_mock, entity_id = saunabox
def initial_update():
feature_mock.is_on = False
feature_mock.desired = 64.3
feature_mock.current = 40.9
feature_mock.async_update = AsyncMock(side_effect=initial_update)
await async_setup_entity(hass, entity_id)
state = hass.states.get(entity_id)
assert state.attributes[ATTR_HVAC_ACTION] == HVACAction.OFF
assert state.attributes[ATTR_TEMPERATURE] == 64.3
assert state.attributes[ATTR_CURRENT_TEMPERATURE] == 40.9
assert state.state == HVACMode.OFF
async def test_on_when_below_desired(saunabox, hass: HomeAssistant) -> None:
"""Test when temperature is below desired."""
feature_mock, entity_id = saunabox
def initial_update():
feature_mock.is_on = False
feature_mock.async_update = AsyncMock(side_effect=initial_update)
await async_setup_entity(hass, entity_id)
feature_mock.async_update = AsyncMock()
def turn_on():
feature_mock.is_on = True
feature_mock.is_heating = True
feature_mock.desired = 64.8
feature_mock.current = 25.7
feature_mock.mode = 1
feature_mock.async_on = AsyncMock(side_effect=turn_on)
await hass.services.async_call(
"climate",
SERVICE_SET_HVAC_MODE,
{"entity_id": entity_id, ATTR_HVAC_MODE: HVACMode.HEAT},
blocking=True,
)
feature_mock.async_off.assert_not_called()
state = hass.states.get(entity_id)
assert state.attributes[ATTR_HVAC_ACTION] == HVACAction.HEATING
assert state.attributes[ATTR_TEMPERATURE] == 64.8
assert state.attributes[ATTR_CURRENT_TEMPERATURE] == 25.7
assert state.state == HVACMode.HEAT
async def test_on_when_above_desired(saunabox, hass: HomeAssistant) -> None:
"""Test when temperature is below desired."""
feature_mock, entity_id = saunabox
def initial_update():
feature_mock.is_on = False
feature_mock.async_update = AsyncMock(side_effect=initial_update)
await async_setup_entity(hass, entity_id)
feature_mock.async_update = AsyncMock()
def turn_on():
feature_mock.is_on = True
feature_mock.is_heating = False
feature_mock.desired = 23.4
feature_mock.current = 28.7
feature_mock.mode = 1
feature_mock.async_on = AsyncMock(side_effect=turn_on)
await hass.services.async_call(
"climate",
SERVICE_SET_HVAC_MODE,
{ATTR_ENTITY_ID: entity_id, ATTR_HVAC_MODE: HVACMode.HEAT},
blocking=True,
)
feature_mock.async_off.assert_not_called()
state = hass.states.get(entity_id)
assert state.attributes[ATTR_TEMPERATURE] == 23.4
assert state.attributes[ATTR_CURRENT_TEMPERATURE] == 28.7
assert state.attributes[ATTR_HVAC_ACTION] == HVACAction.IDLE
assert state.state == HVACMode.HEAT
async def test_off(saunabox, hass: HomeAssistant) -> None:
"""Test turning off."""
feature_mock, entity_id = saunabox
def initial_update():
feature_mock.is_on = True
feature_mock.is_heating = False
feature_mock.async_update = AsyncMock(side_effect=initial_update)
await async_setup_entity(hass, entity_id)
feature_mock.async_update = AsyncMock()
def turn_off():
feature_mock.is_on = False
feature_mock.is_heating = False
feature_mock.desired = 29.8
feature_mock.current = 22.7
feature_mock.async_off = AsyncMock(side_effect=turn_off)
await hass.services.async_call(
"climate",
SERVICE_SET_HVAC_MODE,
{"entity_id": entity_id, ATTR_HVAC_MODE: HVACMode.OFF},
blocking=True,
)
feature_mock.async_on.assert_not_called()
state = hass.states.get(entity_id)
assert state.attributes[ATTR_HVAC_ACTION] == HVACAction.OFF
assert state.attributes[ATTR_TEMPERATURE] == 29.8
assert state.attributes[ATTR_CURRENT_TEMPERATURE] == 22.7
assert state.state == HVACMode.OFF
async def test_set_thermo(saunabox, hass: HomeAssistant) -> None:
"""Test setting thermostat."""
feature_mock, entity_id = saunabox
def update():
feature_mock.is_on = False
feature_mock.is_heating = False
feature_mock.async_update = AsyncMock(side_effect=update)
await async_setup_entity(hass, entity_id)
feature_mock.async_update = AsyncMock()
def set_temp(temp):
feature_mock.is_on = True
feature_mock.is_heating = True
feature_mock.desired = 29.2
feature_mock.current = 29.1
feature_mock.async_set_temperature = AsyncMock(side_effect=set_temp)
await hass.services.async_call(
"climate",
SERVICE_SET_TEMPERATURE,
{"entity_id": entity_id, ATTR_TEMPERATURE: 43.21},
blocking=True,
)
state = hass.states.get(entity_id)
assert state.attributes[ATTR_TEMPERATURE] == 29.2
assert state.attributes[ATTR_CURRENT_TEMPERATURE] == 29.1
assert state.attributes[ATTR_HVAC_ACTION] == HVACAction.HEATING
assert state.state == HVACMode.HEAT
async def test_update_failure(
saunabox, hass: HomeAssistant, caplog: pytest.LogCaptureFixture
) -> None:
"""Test that update failures are logged."""
caplog.set_level(logging.ERROR)
feature_mock, entity_id = saunabox
feature_mock.async_update = AsyncMock(side_effect=blebox_uniapi.error.ClientError)
await async_setup_entity(hass, entity_id)
assert f"Updating '{feature_mock.full_name}' failed: " in caplog.text
async def test_reding_hvac_actions(
saunabox, hass: HomeAssistant, caplog: pytest.LogCaptureFixture
) -> None:
"""Test hvac action for given device(mock) state."""
caplog.set_level(logging.ERROR)
feature_mock, entity_id = saunabox
await async_setup_entity(hass, entity_id)
def set_heating():
feature_mock.is_on = True
feature_mock.hvac_action = 1
feature_mock.mode = 1
feature_mock.async_update = AsyncMock(side_effect=set_heating)
await hass.services.async_call(
"climate",
SERVICE_SET_TEMPERATURE,
{"entity_id": entity_id, ATTR_TEMPERATURE: 43.21},
blocking=True,
)
state = hass.states.get(entity_id)
assert state.attributes[ATTR_HVAC_ACTION] == HVACAction.HEATING
assert state.attributes[ATTR_HVAC_MODES] == [HVACMode.OFF, HVACMode.HEAT]
async def test_thermo_off(
thermobox, hass: HomeAssistant, caplog: pytest.LogCaptureFixture
) -> None:
"""Test hvac action off fir given device state."""
caplog.set_level(logging.ERROR)
feature_mock, entity_id = thermobox
await async_setup_entity(hass, entity_id)
def set_off():
feature_mock.is_on = False
feature_mock.hvac_action = 0
feature_mock.async_update = AsyncMock(side_effect=set_off)
await hass.services.async_call(
"climate",
SERVICE_SET_HVAC_MODE,
{"entity_id": entity_id, ATTR_HVAC_MODE: HVACMode.OFF},
blocking=True,
)
state = hass.states.get(entity_id)
assert state.attributes[ATTR_HVAC_ACTION] == HVACAction.OFF
assert state.attributes[ATTR_HVAC_MODES] == [HVACMode.OFF, HVACMode.COOL]