hass-core/tests/components/maxcube/test_maxcube_climate.py
J. Nick Koston 9a79320861
Mark executor jobs as background unless created from a tracked task (#114450)
* Mark executor jobs as background unless created from a tracked task

If the current task is not tracked the executor job should not
be a background task to avoid delaying startup and shutdown.

Currently any executor job created in a untracked task or
background task would end up being tracked and delaying
startup/shutdown

* import exec has the same issue

* Avoid tracking import executor jobs

There is no reason to track these jobs as they are always awaited
and we do not want to support fire and forget import executor jobs

* fix xiaomi_miio

* lots of fire time changed without background await

* revert changes moved to other PR

* more

* more

* more

* m

* m

* p

* fix fire and forget tests

* scrape

* sonos

* system

* more

* capture callback before block

* coverage

* more

* more races

* more races

* more

* missed some

* more fixes

* missed some more

* fix

* remove unneeded

* one more race

* two
2024-03-30 00:16:53 -04:00

432 lines
15 KiB
Python

"""Test EQ3 Max! Thermostats."""
from datetime import timedelta
from maxcube.cube import MaxCube
from maxcube.device import (
MAX_DEVICE_MODE_AUTOMATIC,
MAX_DEVICE_MODE_BOOST,
MAX_DEVICE_MODE_MANUAL,
MAX_DEVICE_MODE_VACATION,
)
from maxcube.thermostat import MaxThermostat
from maxcube.wallthermostat import MaxWallThermostat
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,
ATTR_PRESET_MODE,
ATTR_PRESET_MODES,
ATTR_TARGET_TEMP_HIGH,
ATTR_TARGET_TEMP_LOW,
DOMAIN as CLIMATE_DOMAIN,
PRESET_AWAY,
PRESET_BOOST,
PRESET_COMFORT,
PRESET_ECO,
PRESET_NONE,
SERVICE_SET_HVAC_MODE,
SERVICE_SET_PRESET_MODE,
SERVICE_SET_TEMPERATURE,
ClimateEntityFeature,
HVACAction,
HVACMode,
)
from homeassistant.components.maxcube.climate import (
MAX_TEMPERATURE,
MIN_TEMPERATURE,
OFF_TEMPERATURE,
ON_TEMPERATURE,
PRESET_ON,
)
from homeassistant.const import (
ATTR_ENTITY_ID,
ATTR_FRIENDLY_NAME,
ATTR_SUPPORTED_FEATURES,
ATTR_TEMPERATURE,
)
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ServiceValidationError
from homeassistant.helpers import entity_registry as er
from homeassistant.util import utcnow
from tests.common import async_fire_time_changed
ENTITY_ID = "climate.testroom_testthermostat"
WALL_ENTITY_ID = "climate.testroom_testwallthermostat"
VALVE_POSITION = "valve_position"
async def test_setup_thermostat(
hass: HomeAssistant, entity_registry: er.EntityRegistry, cube: MaxCube
) -> None:
"""Test a successful setup of a thermostat device."""
assert entity_registry.async_is_registered(ENTITY_ID)
entity = entity_registry.async_get(ENTITY_ID)
assert entity.unique_id == "AABBCCDD01"
state = hass.states.get(ENTITY_ID)
assert state.state == HVACMode.AUTO
assert state.attributes.get(ATTR_FRIENDLY_NAME) == "TestRoom TestThermostat"
assert state.attributes.get(ATTR_HVAC_ACTION) == HVACAction.HEATING
assert state.attributes.get(ATTR_HVAC_MODES) == [
HVACMode.OFF,
HVACMode.AUTO,
HVACMode.HEAT,
]
assert state.attributes.get(ATTR_PRESET_MODES) == [
PRESET_NONE,
PRESET_BOOST,
PRESET_COMFORT,
PRESET_ECO,
PRESET_AWAY,
PRESET_ON,
]
assert state.attributes.get(ATTR_PRESET_MODE) == PRESET_NONE
assert (
state.attributes.get(ATTR_SUPPORTED_FEATURES)
== ClimateEntityFeature.TARGET_TEMPERATURE
| ClimateEntityFeature.PRESET_MODE
| ClimateEntityFeature.TURN_OFF
| ClimateEntityFeature.TURN_ON
)
assert state.attributes.get(ATTR_MAX_TEMP) == MAX_TEMPERATURE
assert state.attributes.get(ATTR_MIN_TEMP) == 5.0
assert state.attributes.get(ATTR_CURRENT_TEMPERATURE) == 19.0
assert state.attributes.get(ATTR_TEMPERATURE) == 20.5
assert state.attributes.get(VALVE_POSITION) == 25
async def test_setup_wallthermostat(
hass: HomeAssistant, entity_registry: er.EntityRegistry, cube: MaxCube
) -> None:
"""Test a successful setup of a wall thermostat device."""
assert entity_registry.async_is_registered(WALL_ENTITY_ID)
entity = entity_registry.async_get(WALL_ENTITY_ID)
assert entity.unique_id == "AABBCCDD02"
state = hass.states.get(WALL_ENTITY_ID)
assert state.state == HVACMode.OFF
assert state.attributes.get(ATTR_FRIENDLY_NAME) == "TestRoom TestWallThermostat"
assert state.attributes.get(ATTR_HVAC_ACTION) == HVACAction.HEATING
assert state.attributes.get(ATTR_PRESET_MODE) == PRESET_NONE
assert state.attributes.get(ATTR_MAX_TEMP) == 29.0
assert state.attributes.get(ATTR_MIN_TEMP) == 5.0
assert state.attributes.get(ATTR_CURRENT_TEMPERATURE) == 19.0
assert state.attributes.get(ATTR_TEMPERATURE) is None
async def test_thermostat_set_hvac_mode_off(
hass: HomeAssistant, cube: MaxCube, thermostat: MaxThermostat
) -> None:
"""Turn off thermostat."""
await hass.services.async_call(
CLIMATE_DOMAIN,
SERVICE_SET_HVAC_MODE,
{ATTR_ENTITY_ID: ENTITY_ID, ATTR_HVAC_MODE: HVACMode.OFF},
blocking=True,
)
cube.set_temperature_mode.assert_called_once_with(
thermostat, OFF_TEMPERATURE, MAX_DEVICE_MODE_MANUAL
)
thermostat.mode = MAX_DEVICE_MODE_MANUAL
thermostat.target_temperature = OFF_TEMPERATURE
thermostat.valve_position = 0
async_fire_time_changed(hass, utcnow() + timedelta(minutes=5))
await hass.async_block_till_done(wait_background_tasks=True)
state = hass.states.get(ENTITY_ID)
assert state.state == HVACMode.OFF
assert state.attributes.get(ATTR_TEMPERATURE) is None
assert state.attributes.get(ATTR_HVAC_ACTION) == HVACAction.OFF
assert state.attributes.get(VALVE_POSITION) == 0
wall_state = hass.states.get(WALL_ENTITY_ID)
assert wall_state.attributes.get(ATTR_HVAC_ACTION) == HVACAction.OFF
async def test_thermostat_set_hvac_mode_heat(
hass: HomeAssistant, cube: MaxCube, thermostat: MaxThermostat
) -> None:
"""Set hvac mode to heat."""
await hass.services.async_call(
CLIMATE_DOMAIN,
SERVICE_SET_HVAC_MODE,
{ATTR_ENTITY_ID: ENTITY_ID, ATTR_HVAC_MODE: HVACMode.HEAT},
blocking=True,
)
cube.set_temperature_mode.assert_called_once_with(
thermostat, 20.5, MAX_DEVICE_MODE_MANUAL
)
thermostat.mode = MAX_DEVICE_MODE_MANUAL
async_fire_time_changed(hass, utcnow() + timedelta(minutes=5))
await hass.async_block_till_done(wait_background_tasks=True)
await hass.async_block_till_done(wait_background_tasks=True)
state = hass.states.get(ENTITY_ID)
assert state.state == HVACMode.HEAT
async def test_thermostat_set_invalid_hvac_mode(
hass: HomeAssistant, cube: MaxCube, thermostat: MaxThermostat
) -> None:
"""Set hvac mode to heat."""
with pytest.raises(ValueError):
await hass.services.async_call(
CLIMATE_DOMAIN,
SERVICE_SET_HVAC_MODE,
{ATTR_ENTITY_ID: ENTITY_ID, ATTR_HVAC_MODE: HVACMode.DRY},
blocking=True,
)
cube.set_temperature_mode.assert_not_called()
async def test_thermostat_set_temperature(
hass: HomeAssistant, cube: MaxCube, thermostat: MaxThermostat
) -> None:
"""Set hvac mode to heat."""
await hass.services.async_call(
CLIMATE_DOMAIN,
SERVICE_SET_TEMPERATURE,
{ATTR_ENTITY_ID: ENTITY_ID, ATTR_TEMPERATURE: 10.0},
blocking=True,
)
cube.set_temperature_mode.assert_called_once_with(thermostat, 10.0, None)
thermostat.target_temperature = 10.0
thermostat.valve_position = 0
async_fire_time_changed(hass, utcnow() + timedelta(minutes=5))
await hass.async_block_till_done(wait_background_tasks=True)
state = hass.states.get(ENTITY_ID)
assert state.state == HVACMode.AUTO
assert state.attributes.get(ATTR_TEMPERATURE) == 10.0
assert state.attributes.get(ATTR_HVAC_ACTION) == HVACAction.IDLE
async def test_thermostat_set_no_temperature(
hass: HomeAssistant, cube: MaxCube, thermostat: MaxThermostat
) -> None:
"""Set hvac mode to heat."""
with pytest.raises(ValueError):
await hass.services.async_call(
CLIMATE_DOMAIN,
SERVICE_SET_TEMPERATURE,
{
ATTR_ENTITY_ID: ENTITY_ID,
ATTR_TARGET_TEMP_HIGH: 29.0,
ATTR_TARGET_TEMP_LOW: 10.0,
},
blocking=True,
)
cube.set_temperature_mode.assert_not_called()
async def test_thermostat_set_preset_on(
hass: HomeAssistant, cube: MaxCube, thermostat: MaxThermostat
) -> None:
"""Set preset mode to on."""
await hass.services.async_call(
CLIMATE_DOMAIN,
SERVICE_SET_PRESET_MODE,
{ATTR_ENTITY_ID: ENTITY_ID, ATTR_PRESET_MODE: PRESET_ON},
blocking=True,
)
cube.set_temperature_mode.assert_called_once_with(
thermostat, ON_TEMPERATURE, MAX_DEVICE_MODE_MANUAL
)
thermostat.mode = MAX_DEVICE_MODE_MANUAL
thermostat.target_temperature = ON_TEMPERATURE
async_fire_time_changed(hass, utcnow() + timedelta(minutes=5))
await hass.async_block_till_done(wait_background_tasks=True)
state = hass.states.get(ENTITY_ID)
assert state.state == HVACMode.HEAT
assert state.attributes.get(ATTR_TEMPERATURE) is None
assert state.attributes.get(ATTR_PRESET_MODE) == PRESET_ON
async def test_thermostat_set_preset_comfort(
hass: HomeAssistant, cube: MaxCube, thermostat: MaxThermostat
) -> None:
"""Set preset mode to comfort."""
await hass.services.async_call(
CLIMATE_DOMAIN,
SERVICE_SET_PRESET_MODE,
{ATTR_ENTITY_ID: ENTITY_ID, ATTR_PRESET_MODE: PRESET_COMFORT},
blocking=True,
)
cube.set_temperature_mode.assert_called_once_with(
thermostat, thermostat.comfort_temperature, MAX_DEVICE_MODE_MANUAL
)
thermostat.mode = MAX_DEVICE_MODE_MANUAL
thermostat.target_temperature = thermostat.comfort_temperature
async_fire_time_changed(hass, utcnow() + timedelta(minutes=5))
await hass.async_block_till_done(wait_background_tasks=True)
state = hass.states.get(ENTITY_ID)
assert state.state == HVACMode.HEAT
assert state.attributes.get(ATTR_TEMPERATURE) == thermostat.comfort_temperature
assert state.attributes.get(ATTR_PRESET_MODE) == PRESET_COMFORT
async def test_thermostat_set_preset_eco(
hass: HomeAssistant, cube: MaxCube, thermostat: MaxThermostat
) -> None:
"""Set preset mode to eco."""
await hass.services.async_call(
CLIMATE_DOMAIN,
SERVICE_SET_PRESET_MODE,
{ATTR_ENTITY_ID: ENTITY_ID, ATTR_PRESET_MODE: PRESET_ECO},
blocking=True,
)
cube.set_temperature_mode.assert_called_once_with(
thermostat, thermostat.eco_temperature, MAX_DEVICE_MODE_MANUAL
)
thermostat.mode = MAX_DEVICE_MODE_MANUAL
thermostat.target_temperature = thermostat.eco_temperature
async_fire_time_changed(hass, utcnow() + timedelta(minutes=5))
await hass.async_block_till_done(wait_background_tasks=True)
state = hass.states.get(ENTITY_ID)
assert state.state == HVACMode.HEAT
assert state.attributes.get(ATTR_TEMPERATURE) == thermostat.eco_temperature
assert state.attributes.get(ATTR_PRESET_MODE) == PRESET_ECO
async def test_thermostat_set_preset_away(
hass: HomeAssistant, cube: MaxCube, thermostat: MaxThermostat
) -> None:
"""Set preset mode to away."""
await hass.services.async_call(
CLIMATE_DOMAIN,
SERVICE_SET_PRESET_MODE,
{ATTR_ENTITY_ID: ENTITY_ID, ATTR_PRESET_MODE: PRESET_AWAY},
blocking=True,
)
cube.set_temperature_mode.assert_called_once_with(
thermostat, None, MAX_DEVICE_MODE_VACATION
)
thermostat.mode = MAX_DEVICE_MODE_VACATION
thermostat.target_temperature = thermostat.eco_temperature
async_fire_time_changed(hass, utcnow() + timedelta(minutes=5))
await hass.async_block_till_done(wait_background_tasks=True)
state = hass.states.get(ENTITY_ID)
assert state.state == HVACMode.HEAT
assert state.attributes.get(ATTR_TEMPERATURE) == thermostat.eco_temperature
assert state.attributes.get(ATTR_PRESET_MODE) == PRESET_AWAY
async def test_thermostat_set_preset_boost(
hass: HomeAssistant, cube: MaxCube, thermostat: MaxThermostat
) -> None:
"""Set preset mode to boost."""
await hass.services.async_call(
CLIMATE_DOMAIN,
SERVICE_SET_PRESET_MODE,
{ATTR_ENTITY_ID: ENTITY_ID, ATTR_PRESET_MODE: PRESET_BOOST},
blocking=True,
)
cube.set_temperature_mode.assert_called_once_with(
thermostat, None, MAX_DEVICE_MODE_BOOST
)
thermostat.mode = MAX_DEVICE_MODE_BOOST
thermostat.target_temperature = thermostat.eco_temperature
async_fire_time_changed(hass, utcnow() + timedelta(minutes=5))
await hass.async_block_till_done(wait_background_tasks=True)
state = hass.states.get(ENTITY_ID)
assert state.state == HVACMode.AUTO
assert state.attributes.get(ATTR_TEMPERATURE) == thermostat.eco_temperature
assert state.attributes.get(ATTR_PRESET_MODE) == PRESET_BOOST
async def test_thermostat_set_preset_none(
hass: HomeAssistant, cube: MaxCube, thermostat: MaxThermostat
) -> None:
"""Set preset mode to boost."""
await hass.services.async_call(
CLIMATE_DOMAIN,
SERVICE_SET_PRESET_MODE,
{ATTR_ENTITY_ID: ENTITY_ID, ATTR_PRESET_MODE: PRESET_NONE},
blocking=True,
)
cube.set_temperature_mode.assert_called_once_with(
thermostat, None, MAX_DEVICE_MODE_AUTOMATIC
)
async def test_thermostat_set_invalid_preset(
hass: HomeAssistant, cube: MaxCube, thermostat: MaxThermostat
) -> None:
"""Set hvac mode to heat."""
with pytest.raises(ServiceValidationError):
await hass.services.async_call(
CLIMATE_DOMAIN,
SERVICE_SET_PRESET_MODE,
{ATTR_ENTITY_ID: ENTITY_ID, ATTR_PRESET_MODE: "invalid"},
blocking=True,
)
cube.set_temperature_mode.assert_not_called()
async def test_wallthermostat_set_hvac_mode_heat(
hass: HomeAssistant, cube: MaxCube, wallthermostat: MaxWallThermostat
) -> None:
"""Set wall thermostat hvac mode to heat."""
await hass.services.async_call(
CLIMATE_DOMAIN,
SERVICE_SET_HVAC_MODE,
{ATTR_ENTITY_ID: WALL_ENTITY_ID, ATTR_HVAC_MODE: HVACMode.HEAT},
blocking=True,
)
cube.set_temperature_mode.assert_called_once_with(
wallthermostat, MIN_TEMPERATURE, MAX_DEVICE_MODE_MANUAL
)
wallthermostat.target_temperature = MIN_TEMPERATURE
async_fire_time_changed(hass, utcnow() + timedelta(minutes=5))
await hass.async_block_till_done(wait_background_tasks=True)
state = hass.states.get(WALL_ENTITY_ID)
assert state.state == HVACMode.HEAT
assert state.attributes.get(ATTR_TEMPERATURE) == MIN_TEMPERATURE
async def test_wallthermostat_set_hvac_mode_auto(
hass: HomeAssistant, cube: MaxCube, wallthermostat: MaxWallThermostat
) -> None:
"""Set wall thermostat hvac mode to auto."""
await hass.services.async_call(
CLIMATE_DOMAIN,
SERVICE_SET_HVAC_MODE,
{ATTR_ENTITY_ID: WALL_ENTITY_ID, ATTR_HVAC_MODE: HVACMode.AUTO},
blocking=True,
)
cube.set_temperature_mode.assert_called_once_with(
wallthermostat, None, MAX_DEVICE_MODE_AUTOMATIC
)
wallthermostat.mode = MAX_DEVICE_MODE_AUTOMATIC
wallthermostat.target_temperature = 23.0
async_fire_time_changed(hass, utcnow() + timedelta(minutes=5))
await hass.async_block_till_done(wait_background_tasks=True)
state = hass.states.get(WALL_ENTITY_ID)
assert state.state == HVACMode.AUTO
assert state.attributes.get(ATTR_TEMPERATURE) == 23.0