mirror of https://github.com/home-assistant/core
344 lines
10 KiB
Python
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]
|