mirror of https://github.com/home-assistant/core
378 lines
11 KiB
Python
378 lines
11 KiB
Python
"""Test the Nibe Heat Pump config flow."""
|
|
|
|
from typing import Any
|
|
from unittest.mock import call, patch
|
|
|
|
from nibe.coil import CoilData
|
|
from nibe.coil_groups import (
|
|
CLIMATE_COILGROUPS,
|
|
UNIT_COILGROUPS,
|
|
ClimateCoilGroup,
|
|
UnitCoilGroup,
|
|
)
|
|
from nibe.heatpump import Model
|
|
import pytest
|
|
from syrupy import SnapshotAssertion
|
|
|
|
from homeassistant.components.climate import (
|
|
ATTR_HVAC_MODE,
|
|
ATTR_TARGET_TEMP_HIGH,
|
|
ATTR_TARGET_TEMP_LOW,
|
|
ATTR_TEMPERATURE,
|
|
DOMAIN as PLATFORM_DOMAIN,
|
|
SERVICE_SET_HVAC_MODE,
|
|
SERVICE_SET_TEMPERATURE,
|
|
HVACMode,
|
|
)
|
|
from homeassistant.const import ATTR_ENTITY_ID, Platform
|
|
from homeassistant.core import HomeAssistant
|
|
from homeassistant.exceptions import ServiceValidationError
|
|
|
|
from . import MockConnection, async_add_model
|
|
|
|
|
|
@pytest.fixture(autouse=True)
|
|
async def fixture_single_platform():
|
|
"""Only allow this platform to load."""
|
|
with patch("homeassistant.components.nibe_heatpump.PLATFORMS", [Platform.CLIMATE]):
|
|
yield
|
|
|
|
|
|
def _setup_climate_group(
|
|
coils: dict[int, Any], model: Model, climate_id: str
|
|
) -> tuple[ClimateCoilGroup, UnitCoilGroup]:
|
|
"""Initialize coils for a climate group, with some default values."""
|
|
climate = CLIMATE_COILGROUPS[model.series][climate_id]
|
|
unit = UNIT_COILGROUPS[model.series]["main"]
|
|
|
|
if climate.active_accessory is not None:
|
|
coils[climate.active_accessory] = "ON"
|
|
coils[climate.current] = 20.5
|
|
coils[climate.setpoint_heat] = 21.0
|
|
coils[climate.setpoint_cool] = 30.0
|
|
coils[climate.mixing_valve_state] = 20
|
|
coils[climate.use_room_sensor] = "ON"
|
|
coils[unit.prio] = "OFF"
|
|
coils[unit.cooling_with_room_sensor] = "ON"
|
|
|
|
return climate, unit
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
("model", "climate_id", "entity_id"),
|
|
[
|
|
(Model.S320, "s1", "climate.climate_system_s1"),
|
|
(Model.F1155, "s2", "climate.climate_system_s2"),
|
|
(Model.F730, "s1", "climate.climate_system_s1"),
|
|
],
|
|
)
|
|
@pytest.mark.usefixtures("entity_registry_enabled_by_default")
|
|
async def test_basic(
|
|
hass: HomeAssistant,
|
|
mock_connection: MockConnection,
|
|
model: Model,
|
|
climate_id: str,
|
|
entity_id: str,
|
|
coils: dict[int, Any],
|
|
snapshot: SnapshotAssertion,
|
|
) -> None:
|
|
"""Test setting of value."""
|
|
climate, unit = _setup_climate_group(coils, model, climate_id)
|
|
|
|
await async_add_model(hass, model)
|
|
|
|
assert hass.states.get(entity_id) == snapshot(name="initial")
|
|
|
|
mock_connection.mock_coil_update(unit.prio, "COOLING")
|
|
assert hass.states.get(entity_id) == snapshot(name="cooling")
|
|
|
|
mock_connection.mock_coil_update(unit.prio, "HEAT")
|
|
assert hass.states.get(entity_id) == snapshot(name="heating")
|
|
|
|
mock_connection.mock_coil_update(climate.mixing_valve_state, 30)
|
|
assert hass.states.get(entity_id) == snapshot(name="idle (mixing valve)")
|
|
|
|
mock_connection.mock_coil_update(climate.mixing_valve_state, 20)
|
|
mock_connection.mock_coil_update(unit.cooling_with_room_sensor, "OFF")
|
|
assert hass.states.get(entity_id) == snapshot(name="heating (only)")
|
|
|
|
mock_connection.mock_coil_update(climate.use_room_sensor, "OFF")
|
|
assert hass.states.get(entity_id) == snapshot(name="heating (auto)")
|
|
|
|
mock_connection.mock_coil_update(unit.prio, None)
|
|
assert hass.states.get(entity_id) == snapshot(name="off (auto)")
|
|
|
|
coils.clear()
|
|
assert hass.states.get(entity_id) == snapshot(name="unavailable")
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
("model", "climate_id", "entity_id"),
|
|
[
|
|
(Model.F1155, "s2", "climate.climate_system_s2"),
|
|
(Model.F1155, "s3", "climate.climate_system_s3"),
|
|
],
|
|
)
|
|
@pytest.mark.usefixtures("entity_registry_enabled_by_default")
|
|
async def test_active_accessory(
|
|
hass: HomeAssistant,
|
|
mock_connection: MockConnection,
|
|
model: Model,
|
|
climate_id: str,
|
|
entity_id: str,
|
|
coils: dict[int, Any],
|
|
snapshot: SnapshotAssertion,
|
|
) -> None:
|
|
"""Test climate groups that can be deactivated by configuration."""
|
|
climate, unit = _setup_climate_group(coils, model, climate_id)
|
|
|
|
await async_add_model(hass, model)
|
|
|
|
assert hass.states.get(entity_id) == snapshot(name="initial")
|
|
|
|
mock_connection.mock_coil_update(climate.active_accessory, "OFF")
|
|
assert hass.states.get(entity_id) == snapshot(name="unavailable (not supported)")
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
("model", "climate_id", "entity_id"),
|
|
[
|
|
(Model.S320, "s1", "climate.climate_system_s1"),
|
|
(Model.F1155, "s2", "climate.climate_system_s2"),
|
|
],
|
|
)
|
|
@pytest.mark.usefixtures("entity_registry_enabled_by_default")
|
|
async def test_set_temperature_supported_cooling(
|
|
hass: HomeAssistant,
|
|
mock_connection: MockConnection,
|
|
model: Model,
|
|
climate_id: str,
|
|
entity_id: str,
|
|
coils: dict[int, Any],
|
|
snapshot: SnapshotAssertion,
|
|
) -> None:
|
|
"""Test setting temperature for models with cooling support."""
|
|
climate, _ = _setup_climate_group(coils, model, climate_id)
|
|
|
|
await async_add_model(hass, model)
|
|
|
|
coil_setpoint_heat = mock_connection.heatpump.get_coil_by_address(
|
|
climate.setpoint_heat
|
|
)
|
|
coil_setpoint_cool = mock_connection.heatpump.get_coil_by_address(
|
|
climate.setpoint_cool
|
|
)
|
|
|
|
await hass.services.async_call(
|
|
PLATFORM_DOMAIN,
|
|
SERVICE_SET_TEMPERATURE,
|
|
{
|
|
ATTR_ENTITY_ID: entity_id,
|
|
ATTR_TEMPERATURE: 22,
|
|
ATTR_HVAC_MODE: HVACMode.HEAT,
|
|
},
|
|
blocking=True,
|
|
)
|
|
await hass.async_block_till_done()
|
|
|
|
assert mock_connection.write_coil.mock_calls == [
|
|
call(CoilData(coil_setpoint_heat, 22))
|
|
]
|
|
mock_connection.write_coil.reset_mock()
|
|
|
|
await hass.services.async_call(
|
|
PLATFORM_DOMAIN,
|
|
SERVICE_SET_TEMPERATURE,
|
|
{
|
|
ATTR_ENTITY_ID: entity_id,
|
|
ATTR_TEMPERATURE: 22,
|
|
ATTR_HVAC_MODE: HVACMode.COOL,
|
|
},
|
|
blocking=True,
|
|
)
|
|
await hass.async_block_till_done()
|
|
|
|
assert mock_connection.write_coil.mock_calls == [
|
|
call(CoilData(coil_setpoint_cool, 22))
|
|
]
|
|
mock_connection.write_coil.reset_mock()
|
|
|
|
with pytest.raises(ServiceValidationError):
|
|
await hass.services.async_call(
|
|
PLATFORM_DOMAIN,
|
|
SERVICE_SET_TEMPERATURE,
|
|
{
|
|
ATTR_ENTITY_ID: entity_id,
|
|
ATTR_TEMPERATURE: 22,
|
|
},
|
|
blocking=True,
|
|
)
|
|
|
|
await hass.services.async_call(
|
|
PLATFORM_DOMAIN,
|
|
SERVICE_SET_TEMPERATURE,
|
|
{
|
|
ATTR_ENTITY_ID: entity_id,
|
|
ATTR_TARGET_TEMP_HIGH: 30,
|
|
ATTR_TARGET_TEMP_LOW: 22,
|
|
},
|
|
blocking=True,
|
|
)
|
|
await hass.async_block_till_done()
|
|
|
|
assert mock_connection.write_coil.mock_calls == [
|
|
call(CoilData(coil_setpoint_heat, 22)),
|
|
call(CoilData(coil_setpoint_cool, 30)),
|
|
]
|
|
|
|
mock_connection.write_coil.reset_mock()
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
("model", "climate_id", "entity_id"),
|
|
[
|
|
(Model.F730, "s1", "climate.climate_system_s1"),
|
|
],
|
|
)
|
|
@pytest.mark.usefixtures("entity_registry_enabled_by_default")
|
|
async def test_set_temperature_unsupported_cooling(
|
|
hass: HomeAssistant,
|
|
mock_connection: MockConnection,
|
|
model: Model,
|
|
climate_id: str,
|
|
entity_id: str,
|
|
coils: dict[int, Any],
|
|
snapshot: SnapshotAssertion,
|
|
) -> None:
|
|
"""Test setting temperature for models that do not support cooling."""
|
|
climate, _ = _setup_climate_group(coils, model, climate_id)
|
|
|
|
await async_add_model(hass, model)
|
|
|
|
coil_setpoint_heat = mock_connection.heatpump.get_coil_by_address(
|
|
climate.setpoint_heat
|
|
)
|
|
|
|
# Set temperature to heat
|
|
await hass.services.async_call(
|
|
PLATFORM_DOMAIN,
|
|
SERVICE_SET_TEMPERATURE,
|
|
{
|
|
ATTR_ENTITY_ID: entity_id,
|
|
ATTR_TEMPERATURE: 22,
|
|
ATTR_HVAC_MODE: HVACMode.HEAT,
|
|
},
|
|
blocking=True,
|
|
)
|
|
await hass.async_block_till_done()
|
|
assert mock_connection.write_coil.mock_calls == [
|
|
call(CoilData(coil_setpoint_heat, 22))
|
|
]
|
|
|
|
# Attempt to set temperature to cool should raise ServiceValidationError
|
|
with pytest.raises(ServiceValidationError):
|
|
await hass.services.async_call(
|
|
PLATFORM_DOMAIN,
|
|
SERVICE_SET_TEMPERATURE,
|
|
{
|
|
ATTR_ENTITY_ID: entity_id,
|
|
ATTR_TEMPERATURE: 22,
|
|
ATTR_HVAC_MODE: HVACMode.COOL,
|
|
},
|
|
blocking=True,
|
|
)
|
|
mock_connection.write_coil.reset_mock()
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
("hvac_mode", "cooling_with_room_sensor", "use_room_sensor"),
|
|
[
|
|
(HVACMode.HEAT_COOL, "ON", "ON"),
|
|
(HVACMode.HEAT, "OFF", "ON"),
|
|
(HVACMode.AUTO, "OFF", "OFF"),
|
|
],
|
|
)
|
|
@pytest.mark.parametrize(
|
|
("model", "climate_id", "entity_id"),
|
|
[
|
|
(Model.S320, "s1", "climate.climate_system_s1"),
|
|
(Model.F1155, "s2", "climate.climate_system_s2"),
|
|
(Model.F730, "s1", "climate.climate_system_s1"),
|
|
],
|
|
)
|
|
@pytest.mark.usefixtures("entity_registry_enabled_by_default")
|
|
async def test_set_hvac_mode(
|
|
hass: HomeAssistant,
|
|
mock_connection: MockConnection,
|
|
model: Model,
|
|
climate_id: str,
|
|
entity_id: str,
|
|
cooling_with_room_sensor: str,
|
|
use_room_sensor: str,
|
|
hvac_mode: HVACMode,
|
|
coils: dict[int, Any],
|
|
) -> None:
|
|
"""Test setting a hvac mode."""
|
|
climate, unit = _setup_climate_group(coils, model, climate_id)
|
|
|
|
await async_add_model(hass, model)
|
|
|
|
coil_use_room_sensor = mock_connection.heatpump.get_coil_by_address(
|
|
climate.use_room_sensor
|
|
)
|
|
coil_cooling_with_room_sensor = mock_connection.heatpump.get_coil_by_address(
|
|
unit.cooling_with_room_sensor
|
|
)
|
|
|
|
await hass.services.async_call(
|
|
PLATFORM_DOMAIN,
|
|
SERVICE_SET_HVAC_MODE,
|
|
{
|
|
ATTR_ENTITY_ID: entity_id,
|
|
ATTR_HVAC_MODE: hvac_mode,
|
|
},
|
|
blocking=True,
|
|
)
|
|
await hass.async_block_till_done()
|
|
|
|
assert mock_connection.write_coil.mock_calls == [
|
|
call(CoilData(coil_cooling_with_room_sensor, cooling_with_room_sensor)),
|
|
call(CoilData(coil_use_room_sensor, use_room_sensor)),
|
|
]
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
("model", "climate_id", "entity_id", "unsupported_mode"),
|
|
[
|
|
(Model.S320, "s1", "climate.climate_system_s1", HVACMode.DRY),
|
|
(Model.F1155, "s2", "climate.climate_system_s2", HVACMode.DRY),
|
|
(Model.F730, "s1", "climate.climate_system_s1", HVACMode.COOL),
|
|
],
|
|
)
|
|
@pytest.mark.usefixtures("entity_registry_enabled_by_default")
|
|
async def test_set_invalid_hvac_mode(
|
|
hass: HomeAssistant,
|
|
mock_connection: MockConnection,
|
|
model: Model,
|
|
climate_id: str,
|
|
entity_id: str,
|
|
unsupported_mode: str,
|
|
coils: dict[int, Any],
|
|
) -> None:
|
|
"""Test setting an invalid hvac mode."""
|
|
_setup_climate_group(coils, model, climate_id)
|
|
|
|
await async_add_model(hass, model)
|
|
with pytest.raises(ServiceValidationError):
|
|
await hass.services.async_call(
|
|
PLATFORM_DOMAIN,
|
|
SERVICE_SET_HVAC_MODE,
|
|
{
|
|
ATTR_ENTITY_ID: entity_id,
|
|
ATTR_HVAC_MODE: unsupported_mode,
|
|
},
|
|
blocking=True,
|
|
)
|
|
|
|
assert mock_connection.write_coil.mock_calls == []
|