Switch to using a fixture for evohome Climate tests (of zones) (#129100)

This commit is contained in:
David Bonnes 2024-10-25 09:57:37 +01:00 committed by GitHub
parent 78116f1596
commit 76aa69b9ac
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 259 additions and 232 deletions

View File

@ -11,12 +11,14 @@ from unittest.mock import MagicMock, patch
from aiohttp import ClientSession
from evohomeasync2 import EvohomeClient
from evohomeasync2.broker import Broker
from evohomeasync2.zone import Zone
import pytest
from homeassistant.components.evohome import CONF_PASSWORD, CONF_USERNAME, DOMAIN
from homeassistant.const import Platform
from homeassistant.core import HomeAssistant
from homeassistant.setup import async_setup_component
from homeassistant.util import dt as dt_util
from homeassistant.util import dt as dt_util, slugify
from homeassistant.util.json import JsonArrayType, JsonObjectType
from .const import ACCESS_TOKEN, REFRESH_TOKEN, USERNAME
@ -173,3 +175,18 @@ async def evohome(
async for mock_client in setup_evohome(hass, config, install=install):
yield mock_client
@pytest.fixture
async def zone_id(
hass: HomeAssistant,
config: dict[str, str],
install: MagicMock,
) -> AsyncGenerator[str]:
"""Return the entity_id of the evohome integration' first Climate zone."""
async for mock_client in setup_evohome(hass, config, install=install):
evo: EvohomeClient = mock_client.return_value
zone: Zone = list(evo._get_single_tcs().zones.values())[0]
yield f"{Platform.CLIMATE}.{slugify(zone.name)}"

View File

@ -2,189 +2,170 @@
# name: test_zone_set_hvac_mode[default]
list([
tuple(
dict({
'HeatSetpointValue': 5.0,
'setpointMode': <ZoneMode.PERMANENT_OVERRIDE: 'PermanentOverride'>,
}),
5.0,
),
])
# ---
# name: test_zone_set_hvac_mode[h032585]
list([
tuple(
dict({
'HeatSetpointValue': 4.5,
'setpointMode': <ZoneMode.PERMANENT_OVERRIDE: 'PermanentOverride'>,
}),
4.5,
),
])
# ---
# name: test_zone_set_hvac_mode[h099625]
list([
tuple(
dict({
'HeatSetpointValue': 5.0,
'setpointMode': <ZoneMode.PERMANENT_OVERRIDE: 'PermanentOverride'>,
}),
5.0,
),
])
# ---
# name: test_zone_set_hvac_mode[minimal]
list([
tuple(
dict({
'HeatSetpointValue': 5.0,
'setpointMode': <ZoneMode.PERMANENT_OVERRIDE: 'PermanentOverride'>,
}),
5.0,
),
])
# ---
# name: test_zone_set_hvac_mode[sys_004]
list([
tuple(
dict({
'HeatSetpointValue': 5.0,
'setpointMode': <ZoneMode.PERMANENT_OVERRIDE: 'PermanentOverride'>,
}),
5.0,
),
])
# ---
# name: test_zone_set_preset_mode[default]
list([
tuple(
dict({
'HeatSetpointValue': 17.0,
'setpointMode': <ZoneMode.PERMANENT_OVERRIDE: 'PermanentOverride'>,
}),
17.0,
),
tuple(
dict({
'HeatSetpointValue': 17.0,
'setpointMode': <ZoneMode.TEMPORARY_OVERRIDE: 'TemporaryOverride'>,
'timeUntil': '2024-07-10T21:10:00Z',
}),
17.0,
),
dict({
'until': datetime.datetime(2024, 7, 10, 21, 10, tzinfo=datetime.timezone.utc),
}),
])
# ---
# name: test_zone_set_preset_mode[h032585]
list([
tuple(
dict({
'HeatSetpointValue': 21.5,
'setpointMode': <ZoneMode.PERMANENT_OVERRIDE: 'PermanentOverride'>,
}),
21.5,
),
tuple(
dict({
'HeatSetpointValue': 21.5,
'setpointMode': <ZoneMode.TEMPORARY_OVERRIDE: 'TemporaryOverride'>,
'timeUntil': '2024-07-10T21:10:00Z',
}),
21.5,
),
dict({
'until': datetime.datetime(2024, 7, 10, 21, 10, tzinfo=datetime.timezone.utc),
}),
])
# ---
# name: test_zone_set_preset_mode[h099625]
list([
tuple(
dict({
'HeatSetpointValue': 21.5,
'setpointMode': <ZoneMode.PERMANENT_OVERRIDE: 'PermanentOverride'>,
}),
21.5,
),
tuple(
dict({
'HeatSetpointValue': 21.5,
'setpointMode': <ZoneMode.TEMPORARY_OVERRIDE: 'TemporaryOverride'>,
'timeUntil': '2024-07-10T19:10:00Z',
}),
21.5,
),
dict({
'until': datetime.datetime(2024, 7, 10, 19, 10, tzinfo=datetime.timezone.utc),
}),
])
# ---
# name: test_zone_set_preset_mode[minimal]
list([
tuple(
dict({
'HeatSetpointValue': 17.0,
'setpointMode': <ZoneMode.PERMANENT_OVERRIDE: 'PermanentOverride'>,
}),
17.0,
),
tuple(
dict({
'HeatSetpointValue': 17.0,
'setpointMode': <ZoneMode.TEMPORARY_OVERRIDE: 'TemporaryOverride'>,
'timeUntil': '2024-07-10T21:10:00Z',
}),
17.0,
),
dict({
'until': datetime.datetime(2024, 7, 10, 21, 10, tzinfo=datetime.timezone.utc),
}),
])
# ---
# name: test_zone_set_preset_mode[sys_004]
list([
tuple(
dict({
'HeatSetpointValue': 15.0,
'setpointMode': <ZoneMode.PERMANENT_OVERRIDE: 'PermanentOverride'>,
}),
15.0,
),
tuple(
dict({
'HeatSetpointValue': 15.0,
'setpointMode': <ZoneMode.TEMPORARY_OVERRIDE: 'TemporaryOverride'>,
'timeUntil': '2024-07-10T20:10:00Z',
}),
15.0,
),
dict({
'until': datetime.datetime(2024, 7, 10, 20, 10, tzinfo=datetime.timezone.utc),
}),
])
# ---
# name: test_zone_set_temperature[default]
list([
tuple(
dict({
'HeatSetpointValue': 19.1,
'setpointMode': <ZoneMode.TEMPORARY_OVERRIDE: 'TemporaryOverride'>,
'timeUntil': '2024-07-10T21:10:00Z',
}),
),
dict({
'until': datetime.datetime(2024, 7, 10, 21, 10, tzinfo=datetime.timezone.utc),
}),
])
# ---
# name: test_zone_set_temperature[h032585]
list([
tuple(
dict({
'HeatSetpointValue': 19.1,
'setpointMode': <ZoneMode.TEMPORARY_OVERRIDE: 'TemporaryOverride'>,
'timeUntil': '2024-07-10T21:10:00Z',
}),
),
dict({
'until': datetime.datetime(2024, 7, 10, 21, 10, tzinfo=datetime.timezone.utc),
}),
])
# ---
# name: test_zone_set_temperature[h099625]
list([
tuple(
dict({
'HeatSetpointValue': 19.1,
'setpointMode': <ZoneMode.TEMPORARY_OVERRIDE: 'TemporaryOverride'>,
'timeUntil': '2024-07-10T19:10:00Z',
}),
),
dict({
'until': datetime.datetime(2024, 7, 10, 19, 10, tzinfo=datetime.timezone.utc),
}),
])
# ---
# name: test_zone_set_temperature[minimal]
list([
tuple(
dict({
'HeatSetpointValue': 19.1,
'setpointMode': <ZoneMode.TEMPORARY_OVERRIDE: 'TemporaryOverride'>,
'timeUntil': '2024-07-10T21:10:00Z',
}),
),
dict({
'until': datetime.datetime(2024, 7, 10, 21, 10, tzinfo=datetime.timezone.utc),
}),
])
# ---
# name: test_zone_set_temperature[sys_004]
list([
dict({
'until': None,
}),
])
# ---
# name: test_zone_turn_off[default]
list([
tuple(
dict({
'HeatSetpointValue': 19.1,
'setpointMode': <ZoneMode.PERMANENT_OVERRIDE: 'PermanentOverride'>,
}),
5.0,
),
])
# ---
# name: test_zone_turn_off[h032585]
list([
tuple(
4.5,
),
])
# ---
# name: test_zone_turn_off[h099625]
list([
tuple(
5.0,
),
])
# ---
# name: test_zone_turn_off[minimal]
list([
tuple(
5.0,
),
])
# ---
# name: test_zone_turn_off[sys_004]
list([
tuple(
5.0,
),
])
# ---

View File

@ -11,78 +11,69 @@ from freezegun.api import FrozenDateTimeFactory
import pytest
from syrupy import SnapshotAssertion
from homeassistant.components.climate import HVACMode
from homeassistant.components.evohome import DOMAIN
from homeassistant.components.evohome.climate import EvoZone
from homeassistant.components.evohome.coordinator import EvoBroker
from homeassistant.const import Platform
from homeassistant.components.climate import (
ATTR_HVAC_MODE,
ATTR_PRESET_MODE,
SERVICE_SET_HVAC_MODE,
SERVICE_SET_PRESET_MODE,
SERVICE_SET_TEMPERATURE,
HVACMode,
)
from homeassistant.const import (
ATTR_ENTITY_ID,
ATTR_TEMPERATURE,
SERVICE_TURN_OFF,
SERVICE_TURN_ON,
Platform,
)
from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry as er
from homeassistant.helpers.entity_component import EntityComponent
from homeassistant.util import dt as dt_util
from .conftest import setup_evohome
from .const import TEST_INSTALLS
def get_zone_entity(hass: HomeAssistant) -> EvoZone:
"""Return the entity of the first zone of the evohome system."""
broker: EvoBroker = hass.data[DOMAIN]["broker"]
unique_id = broker.tcs._zones[0]._id
if unique_id == broker.tcs._id:
unique_id += "z" # special case of merged controller/zone
entity_registry = er.async_get(hass)
entity_id = entity_registry.async_get_entity_id(Platform.CLIMATE, DOMAIN, unique_id)
component: EntityComponent = hass.data.get(Platform.CLIMATE) # type: ignore[assignment]
return next(e for e in component.entities if e.entity_id == entity_id) # type: ignore[return-value]
@pytest.mark.parametrize("install", TEST_INSTALLS)
async def test_zone_set_hvac_mode(
hass: HomeAssistant,
config: dict[str, str],
install: str,
zone_id: str,
snapshot: SnapshotAssertion,
) -> None:
"""Test climate methods of a evohome-compatible zone."""
"""Test SERVICE_SET_HVAC_MODE of an evohome zone Climate entity."""
results = []
async for _ in setup_evohome(hass, config, install=install):
zone = get_zone_entity(hass)
# SERVICE_SET_HVAC_MODE: HVACMode.HEAT
with patch("evohomeasync2.zone.Zone.reset_mode") as mock_fcn:
await hass.services.async_call(
Platform.CLIMATE,
SERVICE_SET_HVAC_MODE,
{
ATTR_ENTITY_ID: zone_id,
ATTR_HVAC_MODE: HVACMode.HEAT,
},
blocking=True,
)
assert zone.hvac_modes == [HVACMode.OFF, HVACMode.HEAT]
assert mock_fcn.await_count == 1
assert mock_fcn.await_args.args == ()
assert mock_fcn.await_args.kwargs == {}
# set_hvac_mode(HVACMode.HEAT): FollowSchedule
with patch("evohomeasync2.zone.Zone._set_mode") as mock_fcn:
await zone.async_set_hvac_mode(HVACMode.HEAT)
# SERVICE_SET_HVAC_MODE: HVACMode.OFF
with patch("evohomeasync2.zone.Zone.set_temperature") as mock_fcn:
await hass.services.async_call(
Platform.CLIMATE,
SERVICE_SET_HVAC_MODE,
{
ATTR_ENTITY_ID: zone_id,
ATTR_HVAC_MODE: HVACMode.OFF,
},
blocking=True,
)
assert mock_fcn.await_count == 1
assert install != "default" or mock_fcn.await_args.args == (
{
"setpointMode": "FollowSchedule",
},
)
assert mock_fcn.await_args.kwargs == {}
assert mock_fcn.await_count == 1
assert mock_fcn.await_args.args != () # minimum target temp
assert mock_fcn.await_args.kwargs == {"until": None}
# set_hvac_mode(HVACMode.OFF): PermanentOverride, minHeatSetpoint
with patch("evohomeasync2.zone.Zone._set_mode") as mock_fcn:
await zone.async_set_hvac_mode(HVACMode.OFF)
assert mock_fcn.await_count == 1
assert install != "default" or mock_fcn.await_args.args == (
{
"setpointMode": "PermanentOverride",
"HeatSetpointValue": 5.0, # varies by install
},
)
assert mock_fcn.await_args.kwargs == {}
results.append(mock_fcn.await_args.args)
results.append(mock_fcn.await_args.args)
assert results == snapshot
@ -90,63 +81,67 @@ async def test_zone_set_hvac_mode(
@pytest.mark.parametrize("install", TEST_INSTALLS)
async def test_zone_set_preset_mode(
hass: HomeAssistant,
config: dict[str, str],
install: str,
zone_id: str,
freezer: FrozenDateTimeFactory,
snapshot: SnapshotAssertion,
) -> None:
"""Test climate methods of a evohome-compatible zone."""
"""Test SERVICE_SET_PRESET_MODE of an evohome zone Climate entity."""
freezer.move_to("2024-07-10T12:00:00Z")
results = []
async for _ in setup_evohome(hass, config, install=install):
zone = get_zone_entity(hass)
# SERVICE_SET_PRESET_MODE: none
with patch("evohomeasync2.zone.Zone.reset_mode") as mock_fcn:
await hass.services.async_call(
Platform.CLIMATE,
SERVICE_SET_PRESET_MODE,
{
ATTR_ENTITY_ID: zone_id,
ATTR_PRESET_MODE: "none",
},
blocking=True,
)
assert zone.preset_modes == ["none", "temporary", "permanent"]
assert mock_fcn.await_count == 1
assert mock_fcn.await_args.args == ()
assert mock_fcn.await_args.kwargs == {}
# set_preset_mode(none): FollowSchedule
with patch("evohomeasync2.zone.Zone._set_mode") as mock_fcn:
await zone.async_set_preset_mode("none")
# SERVICE_SET_PRESET_MODE: permanent
with patch("evohomeasync2.zone.Zone.set_temperature") as mock_fcn:
await hass.services.async_call(
Platform.CLIMATE,
SERVICE_SET_PRESET_MODE,
{
ATTR_ENTITY_ID: zone_id,
ATTR_PRESET_MODE: "permanent",
},
blocking=True,
)
assert mock_fcn.await_count == 1
assert mock_fcn.await_args.args == (
{
"setpointMode": "FollowSchedule",
},
)
assert mock_fcn.await_args.kwargs == {}
assert mock_fcn.await_count == 1
assert mock_fcn.await_args.args != () # current target temp
assert mock_fcn.await_args.kwargs == {"until": None}
# set_preset_mode(permanent): PermanentOverride
with patch("evohomeasync2.zone.Zone._set_mode") as mock_fcn:
await zone.async_set_preset_mode("permanent")
results.append(mock_fcn.await_args.args)
assert mock_fcn.await_count == 1
assert install != "default" or mock_fcn.await_args.args == (
{
"setpointMode": "PermanentOverride",
"HeatSetpointValue": 17.0, # varies by install
},
)
assert mock_fcn.await_args.kwargs == {}
# SERVICE_SET_PRESET_MODE: temporary
with patch("evohomeasync2.zone.Zone.set_temperature") as mock_fcn:
await hass.services.async_call(
Platform.CLIMATE,
SERVICE_SET_PRESET_MODE,
{
ATTR_ENTITY_ID: zone_id,
ATTR_PRESET_MODE: "temporary",
},
blocking=True,
)
results.append(mock_fcn.await_args.args)
assert mock_fcn.await_count == 1
assert mock_fcn.await_args.args != () # current target temp
assert mock_fcn.await_args.kwargs != {} # next setpoint dtm
# set_preset_mode(permanent): TemporaryOverride
with patch("evohomeasync2.zone.Zone._set_mode") as mock_fcn:
await zone.async_set_preset_mode("temporary")
assert mock_fcn.await_count == 1
assert install != "default" or mock_fcn.await_args.args == (
{
"setpointMode": "TemporaryOverride",
"HeatSetpointValue": 17.0, # varies by install
"timeUntil": "2024-07-10T21:10:00Z", # varies by install
},
)
assert mock_fcn.await_args.kwargs == {}
results.append(mock_fcn.await_args.args)
results.append(mock_fcn.await_args.args)
results.append(mock_fcn.await_args.kwargs)
assert results == snapshot
@ -154,50 +149,84 @@ async def test_zone_set_preset_mode(
@pytest.mark.parametrize("install", TEST_INSTALLS)
async def test_zone_set_temperature(
hass: HomeAssistant,
config: dict[str, str],
install: str,
zone_id: str,
freezer: FrozenDateTimeFactory,
snapshot: SnapshotAssertion,
) -> None:
"""Test climate methods of a evohome-compatible zone."""
"""Test SERVICE_SET_TEMPERATURE of an evohome zone Climate entity."""
freezer.move_to("2024-07-10T12:00:00Z")
results = []
async for _ in setup_evohome(hass, config, install=install):
zone = get_zone_entity(hass)
# SERVICE_SET_TEMPERATURE: temperature
with patch("evohomeasync2.zone.Zone.set_temperature") as mock_fcn:
await hass.services.async_call(
Platform.CLIMATE,
SERVICE_SET_TEMPERATURE,
{
ATTR_ENTITY_ID: zone_id,
ATTR_TEMPERATURE: 19.1,
},
blocking=True,
)
# set_temperature(temp): TemporaryOverride, advanced
with patch("evohomeasync2.zone.Zone._set_mode") as mock_fcn:
await zone.async_set_temperature(temperature=19.1)
assert mock_fcn.await_count == 1
assert mock_fcn.await_args.args == (19.1,)
assert mock_fcn.await_args.kwargs != {} # next setpoint dtm
assert mock_fcn.await_count == 1
assert install != "default" or mock_fcn.await_args.args == (
{
"setpointMode": "TemporaryOverride",
"HeatSetpointValue": 19.1,
"timeUntil": "2024-07-10T21:10:00Z", # varies by install
},
)
assert mock_fcn.await_args.kwargs == {}
results.append(mock_fcn.await_args.args)
# set_temperature(temp, until): TemporaryOverride, until
with patch("evohomeasync2.zone.Zone._set_mode") as mock_fcn:
await zone.async_set_temperature(
temperature=19.2,
until=dt_util.parse_datetime("2024-07-10T13:30:00Z"),
)
assert mock_fcn.await_count == 1
assert mock_fcn.await_args.args == (
{
"setpointMode": "TemporaryOverride",
"HeatSetpointValue": 19.2,
"timeUntil": "2024-07-10T13:30:00Z",
},
)
assert mock_fcn.await_args.kwargs == {}
results.append(mock_fcn.await_args.kwargs)
assert results == snapshot
@pytest.mark.parametrize("install", TEST_INSTALLS)
async def test_zone_turn_off(
hass: HomeAssistant,
zone_id: str,
snapshot: SnapshotAssertion,
) -> None:
"""Test SERVICE_TURN_OFF of a evohome zone Climate entity."""
results = []
# SERVICE_TURN_OFF
with patch("evohomeasync2.zone.Zone.set_temperature") as mock_fcn:
await hass.services.async_call(
Platform.CLIMATE,
SERVICE_TURN_OFF,
{
ATTR_ENTITY_ID: zone_id,
},
blocking=True,
)
assert mock_fcn.await_count == 1
assert mock_fcn.await_args.args != () # minimum target temp
assert mock_fcn.await_args.kwargs == {"until": None}
results.append(mock_fcn.await_args.args)
assert results == snapshot
@pytest.mark.parametrize("install", TEST_INSTALLS)
async def test_zone_turn_on(
hass: HomeAssistant,
zone_id: str,
) -> None:
"""Test SERVICE_TURN_ON of a evohome zone Climate entity."""
# SERVICE_TURN_ON
with patch("evohomeasync2.zone.Zone.reset_mode") as mock_fcn:
await hass.services.async_call(
Platform.CLIMATE,
SERVICE_TURN_ON,
{
ATTR_ENTITY_ID: zone_id,
},
blocking=True,
)
assert mock_fcn.await_count == 1
assert mock_fcn.await_args.args == ()
assert mock_fcn.await_args.kwargs == {}