Support Ecobee climate Aux Heat on/off (#86100)
Co-authored-by: J. Nick Koston <nick@koston.org>
This commit is contained in:
parent
f0af0e2b42
commit
84763c793d
5 changed files with 272 additions and 34 deletions
|
@ -35,6 +35,7 @@ from homeassistant.helpers.entity import DeviceInfo
|
||||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
from homeassistant.util.unit_conversion import TemperatureConverter
|
from homeassistant.util.unit_conversion import TemperatureConverter
|
||||||
|
|
||||||
|
from . import EcobeeData
|
||||||
from .const import _LOGGER, DOMAIN, ECOBEE_MODEL_TO_NAME, MANUFACTURER
|
from .const import _LOGGER, DOMAIN, ECOBEE_MODEL_TO_NAME, MANUFACTURER
|
||||||
from .util import ecobee_date, ecobee_time
|
from .util import ecobee_date, ecobee_time
|
||||||
|
|
||||||
|
@ -61,11 +62,14 @@ PRESET_HOLD_INDEFINITE = "indefinite"
|
||||||
AWAY_MODE = "awayMode"
|
AWAY_MODE = "awayMode"
|
||||||
PRESET_HOME = "home"
|
PRESET_HOME = "home"
|
||||||
PRESET_SLEEP = "sleep"
|
PRESET_SLEEP = "sleep"
|
||||||
|
HAS_HEAT_PUMP = "hasHeatPump"
|
||||||
|
|
||||||
DEFAULT_MIN_HUMIDITY = 15
|
DEFAULT_MIN_HUMIDITY = 15
|
||||||
DEFAULT_MAX_HUMIDITY = 50
|
DEFAULT_MAX_HUMIDITY = 50
|
||||||
HUMIDIFIER_MANUAL_MODE = "manual"
|
HUMIDIFIER_MANUAL_MODE = "manual"
|
||||||
|
|
||||||
|
ECOBEE_AUX_HEAT_ONLY = "auxHeatOnly"
|
||||||
|
|
||||||
|
|
||||||
# Order matters, because for reverse mapping we don't want to map HEAT to AUX
|
# Order matters, because for reverse mapping we don't want to map HEAT to AUX
|
||||||
ECOBEE_HVAC_TO_HASS = collections.OrderedDict(
|
ECOBEE_HVAC_TO_HASS = collections.OrderedDict(
|
||||||
|
@ -161,7 +165,6 @@ SET_FAN_MIN_ON_TIME_SCHEMA = vol.Schema(
|
||||||
SUPPORT_FLAGS = (
|
SUPPORT_FLAGS = (
|
||||||
ClimateEntityFeature.TARGET_TEMPERATURE
|
ClimateEntityFeature.TARGET_TEMPERATURE
|
||||||
| ClimateEntityFeature.PRESET_MODE
|
| ClimateEntityFeature.PRESET_MODE
|
||||||
| ClimateEntityFeature.AUX_HEAT
|
|
||||||
| ClimateEntityFeature.TARGET_TEMPERATURE_RANGE
|
| ClimateEntityFeature.TARGET_TEMPERATURE_RANGE
|
||||||
| ClimateEntityFeature.FAN_MODE
|
| ClimateEntityFeature.FAN_MODE
|
||||||
)
|
)
|
||||||
|
@ -308,7 +311,9 @@ class Thermostat(ClimateEntity):
|
||||||
_attr_precision = PRECISION_TENTHS
|
_attr_precision = PRECISION_TENTHS
|
||||||
_attr_temperature_unit = UnitOfTemperature.FAHRENHEIT
|
_attr_temperature_unit = UnitOfTemperature.FAHRENHEIT
|
||||||
|
|
||||||
def __init__(self, data, thermostat_index, thermostat):
|
def __init__(
|
||||||
|
self, data: EcobeeData, thermostat_index: int, thermostat: dict
|
||||||
|
) -> None:
|
||||||
"""Initialize the thermostat."""
|
"""Initialize the thermostat."""
|
||||||
self.data = data
|
self.data = data
|
||||||
self.thermostat_index = thermostat_index
|
self.thermostat_index = thermostat_index
|
||||||
|
@ -318,12 +323,9 @@ class Thermostat(ClimateEntity):
|
||||||
self._last_active_hvac_mode = HVACMode.HEAT_COOL
|
self._last_active_hvac_mode = HVACMode.HEAT_COOL
|
||||||
|
|
||||||
self._operation_list = []
|
self._operation_list = []
|
||||||
if (
|
if self.settings["heatStages"] or self.settings["hasHeatPump"]:
|
||||||
self.thermostat["settings"]["heatStages"]
|
|
||||||
or self.thermostat["settings"]["hasHeatPump"]
|
|
||||||
):
|
|
||||||
self._operation_list.append(HVACMode.HEAT)
|
self._operation_list.append(HVACMode.HEAT)
|
||||||
if self.thermostat["settings"]["coolStages"]:
|
if self.settings["coolStages"]:
|
||||||
self._operation_list.append(HVACMode.COOL)
|
self._operation_list.append(HVACMode.COOL)
|
||||||
if len(self._operation_list) == 2:
|
if len(self._operation_list) == 2:
|
||||||
self._operation_list.insert(0, HVACMode.HEAT_COOL)
|
self._operation_list.insert(0, HVACMode.HEAT_COOL)
|
||||||
|
@ -355,9 +357,12 @@ class Thermostat(ClimateEntity):
|
||||||
@property
|
@property
|
||||||
def supported_features(self) -> ClimateEntityFeature:
|
def supported_features(self) -> ClimateEntityFeature:
|
||||||
"""Return the list of supported features."""
|
"""Return the list of supported features."""
|
||||||
|
supported = SUPPORT_FLAGS
|
||||||
if self.has_humidifier_control:
|
if self.has_humidifier_control:
|
||||||
return SUPPORT_FLAGS | ClimateEntityFeature.TARGET_HUMIDITY
|
supported = supported | ClimateEntityFeature.TARGET_HUMIDITY
|
||||||
return SUPPORT_FLAGS
|
if self.has_aux_heat:
|
||||||
|
supported = supported | ClimateEntityFeature.AUX_HEAT
|
||||||
|
return supported
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def name(self):
|
def name(self):
|
||||||
|
@ -411,13 +416,23 @@ class Thermostat(ClimateEntity):
|
||||||
return PRECISION_HALVES
|
return PRECISION_HALVES
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def has_humidifier_control(self):
|
def settings(self) -> dict[str, Any]:
|
||||||
|
"""Return the settings of the thermostat."""
|
||||||
|
return self.thermostat["settings"]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def has_humidifier_control(self) -> bool:
|
||||||
"""Return true if humidifier connected to thermostat and set to manual/on mode."""
|
"""Return true if humidifier connected to thermostat and set to manual/on mode."""
|
||||||
return (
|
return (
|
||||||
self.thermostat["settings"]["hasHumidifier"]
|
bool(self.settings.get("hasHumidifier"))
|
||||||
and self.thermostat["settings"]["humidifierMode"] == HUMIDIFIER_MANUAL_MODE
|
and self.settings.get("humidifierMode") == HUMIDIFIER_MANUAL_MODE
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def has_aux_heat(self) -> bool:
|
||||||
|
"""Return true if the ecobee has a heat pump."""
|
||||||
|
return bool(self.settings.get(HAS_HEAT_PUMP))
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def target_humidity(self) -> int | None:
|
def target_humidity(self) -> int | None:
|
||||||
"""Return the desired humidity set point."""
|
"""Return the desired humidity set point."""
|
||||||
|
@ -489,7 +504,7 @@ class Thermostat(ClimateEntity):
|
||||||
@property
|
@property
|
||||||
def hvac_mode(self):
|
def hvac_mode(self):
|
||||||
"""Return current operation."""
|
"""Return current operation."""
|
||||||
return ECOBEE_HVAC_TO_HASS[self.thermostat["settings"]["hvacMode"]]
|
return ECOBEE_HVAC_TO_HASS[self.settings["hvacMode"]]
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def hvac_modes(self):
|
def hvac_modes(self):
|
||||||
|
@ -541,23 +556,25 @@ class Thermostat(ClimateEntity):
|
||||||
self.thermostat["program"]["currentClimateRef"]
|
self.thermostat["program"]["currentClimateRef"]
|
||||||
],
|
],
|
||||||
"equipment_running": status,
|
"equipment_running": status,
|
||||||
"fan_min_on_time": self.thermostat["settings"]["fanMinOnTime"],
|
"fan_min_on_time": self.settings["fanMinOnTime"],
|
||||||
}
|
}
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_aux_heat(self):
|
def is_aux_heat(self) -> bool:
|
||||||
"""Return true if aux heater."""
|
"""Return true if aux heater."""
|
||||||
return "auxHeat" in self.thermostat["equipmentStatus"]
|
return self.settings["hvacMode"] == ECOBEE_AUX_HEAT_ONLY
|
||||||
|
|
||||||
async def async_turn_aux_heat_on(self) -> None:
|
def turn_aux_heat_on(self) -> None:
|
||||||
"""Turn auxiliary heater on."""
|
"""Turn auxiliary heater on."""
|
||||||
if not self.is_aux_heat:
|
_LOGGER.debug("Setting HVAC mode to auxHeatOnly to turn on aux heat")
|
||||||
_LOGGER.warning("# Changing aux heat is not supported")
|
self.data.ecobee.set_hvac_mode(self.thermostat_index, ECOBEE_AUX_HEAT_ONLY)
|
||||||
|
self.update_without_throttle = True
|
||||||
|
|
||||||
async def async_turn_aux_heat_off(self) -> None:
|
def turn_aux_heat_off(self) -> None:
|
||||||
"""Turn auxiliary heater off."""
|
"""Turn auxiliary heater off."""
|
||||||
if self.is_aux_heat:
|
_LOGGER.debug("Setting HVAC mode to last mode to disable aux heat")
|
||||||
_LOGGER.warning("# Changing aux heat is not supported")
|
self.set_hvac_mode(self._last_active_hvac_mode)
|
||||||
|
self.update_without_throttle = True
|
||||||
|
|
||||||
def set_preset_mode(self, preset_mode: str) -> None:
|
def set_preset_mode(self, preset_mode: str) -> None:
|
||||||
"""Activate a preset."""
|
"""Activate a preset."""
|
||||||
|
@ -680,7 +697,7 @@ class Thermostat(ClimateEntity):
|
||||||
heat_temp = temp
|
heat_temp = temp
|
||||||
cool_temp = temp
|
cool_temp = temp
|
||||||
else:
|
else:
|
||||||
delta = self.thermostat["settings"]["heatCoolMinDelta"] / 10.0
|
delta = self.settings["heatCoolMinDelta"] / 10.0
|
||||||
heat_temp = temp - delta
|
heat_temp = temp - delta
|
||||||
cool_temp = temp + delta
|
cool_temp = temp + delta
|
||||||
self.set_auto_temp_hold(heat_temp, cool_temp)
|
self.set_auto_temp_hold(heat_temp, cool_temp)
|
||||||
|
@ -739,7 +756,7 @@ class Thermostat(ClimateEntity):
|
||||||
# "useEndTime2hour", "useEndTime4hour"
|
# "useEndTime2hour", "useEndTime4hour"
|
||||||
# "nextPeriod", "askMe"
|
# "nextPeriod", "askMe"
|
||||||
# "indefinite"
|
# "indefinite"
|
||||||
device_preference = self.thermostat["settings"]["holdAction"]
|
device_preference = self.settings["holdAction"]
|
||||||
# Currently supported pyecobee holdTypes:
|
# Currently supported pyecobee holdTypes:
|
||||||
# dateTime, nextTransition, indefinite, holdHours
|
# dateTime, nextTransition, indefinite, holdHours
|
||||||
hold_pref_map = {
|
hold_pref_map = {
|
||||||
|
@ -755,7 +772,7 @@ class Thermostat(ClimateEntity):
|
||||||
# "useEndTime2hour", "useEndTime4hour"
|
# "useEndTime2hour", "useEndTime4hour"
|
||||||
# "nextPeriod", "askMe"
|
# "nextPeriod", "askMe"
|
||||||
# "indefinite"
|
# "indefinite"
|
||||||
device_preference = self.thermostat["settings"]["holdAction"]
|
device_preference = self.settings["holdAction"]
|
||||||
hold_hours_map = {
|
hold_hours_map = {
|
||||||
"useEndTime2hour": 2,
|
"useEndTime2hour": 2,
|
||||||
"useEndTime4hour": 4,
|
"useEndTime4hour": 4,
|
||||||
|
|
|
@ -1 +1,119 @@
|
||||||
"""Tests for Ecobee integration."""
|
"""Tests for Ecobee integration."""
|
||||||
|
|
||||||
|
GENERIC_THERMOSTAT_INFO = {
|
||||||
|
"identifier": 8675309,
|
||||||
|
"name": "ecobee",
|
||||||
|
"modelNumber": "athenaSmart",
|
||||||
|
"program": {
|
||||||
|
"climates": [
|
||||||
|
{"name": "Climate1", "climateRef": "c1"},
|
||||||
|
{"name": "Climate2", "climateRef": "c2"},
|
||||||
|
],
|
||||||
|
"currentClimateRef": "c1",
|
||||||
|
},
|
||||||
|
"runtime": {
|
||||||
|
"connected": True,
|
||||||
|
"actualTemperature": 300,
|
||||||
|
"actualHumidity": 15,
|
||||||
|
"desiredHeat": 400,
|
||||||
|
"desiredCool": 200,
|
||||||
|
"desiredFanMode": "on",
|
||||||
|
"desiredHumidity": 40,
|
||||||
|
},
|
||||||
|
"settings": {
|
||||||
|
"hvacMode": "auto",
|
||||||
|
"heatStages": 1,
|
||||||
|
"coolStages": 1,
|
||||||
|
"fanMinOnTime": 10,
|
||||||
|
"heatCoolMinDelta": 50,
|
||||||
|
"holdAction": "nextTransition",
|
||||||
|
"hasHumidifier": False,
|
||||||
|
"humidifierMode": "manual",
|
||||||
|
"humidity": "30",
|
||||||
|
"ventilatorType": "none",
|
||||||
|
},
|
||||||
|
"equipmentStatus": "fan",
|
||||||
|
"events": [
|
||||||
|
{
|
||||||
|
"name": "Event1",
|
||||||
|
"running": True,
|
||||||
|
"type": "hold",
|
||||||
|
"holdClimateRef": "away",
|
||||||
|
"endDate": "2022-01-01 10:00:00",
|
||||||
|
"startDate": "2022-02-02 11:00:00",
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"remoteSensors": [
|
||||||
|
{
|
||||||
|
"id": "rs:100",
|
||||||
|
"name": "Remote Sensor 1",
|
||||||
|
"type": "ecobee3_remote_sensor",
|
||||||
|
"code": "WKRP",
|
||||||
|
"inUse": False,
|
||||||
|
"capability": [
|
||||||
|
{"id": "1", "type": "temperature", "value": "782"},
|
||||||
|
{"id": "2", "type": "occupancy", "value": "false"},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
GENERIC_THERMOSTAT_INFO_WITH_HEATPUMP = {
|
||||||
|
"identifier": 8675309,
|
||||||
|
"name": "ecobee",
|
||||||
|
"modelNumber": "athenaSmart",
|
||||||
|
"program": {
|
||||||
|
"climates": [
|
||||||
|
{"name": "Climate1", "climateRef": "c1"},
|
||||||
|
{"name": "Climate2", "climateRef": "c2"},
|
||||||
|
],
|
||||||
|
"currentClimateRef": "c1",
|
||||||
|
},
|
||||||
|
"runtime": {
|
||||||
|
"connected": True,
|
||||||
|
"actualTemperature": 300,
|
||||||
|
"actualHumidity": 15,
|
||||||
|
"desiredHeat": 400,
|
||||||
|
"desiredCool": 200,
|
||||||
|
"desiredFanMode": "on",
|
||||||
|
"desiredHumidity": 40,
|
||||||
|
},
|
||||||
|
"settings": {
|
||||||
|
"hvacMode": "auto",
|
||||||
|
"heatStages": 1,
|
||||||
|
"coolStages": 1,
|
||||||
|
"fanMinOnTime": 10,
|
||||||
|
"heatCoolMinDelta": 50,
|
||||||
|
"holdAction": "nextTransition",
|
||||||
|
"hasHumidifier": False,
|
||||||
|
"humidifierMode": "manual",
|
||||||
|
"humidity": "30",
|
||||||
|
"hasHeatPump": True,
|
||||||
|
"ventilatorType": "none",
|
||||||
|
},
|
||||||
|
"equipmentStatus": "fan",
|
||||||
|
"events": [
|
||||||
|
{
|
||||||
|
"name": "Event1",
|
||||||
|
"running": True,
|
||||||
|
"type": "hold",
|
||||||
|
"holdClimateRef": "away",
|
||||||
|
"endDate": "2022-01-01 10:00:00",
|
||||||
|
"startDate": "2022-02-02 11:00:00",
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"remoteSensors": [
|
||||||
|
{
|
||||||
|
"id": "rs:100",
|
||||||
|
"name": "Remote Sensor 1",
|
||||||
|
"type": "ecobee3_remote_sensor",
|
||||||
|
"code": "WKRP",
|
||||||
|
"inUse": False,
|
||||||
|
"capability": [
|
||||||
|
{"id": "1", "type": "temperature", "value": "782"},
|
||||||
|
{"id": "2", "type": "occupancy", "value": "false"},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ from homeassistant.setup import async_setup_component
|
||||||
from tests.common import MockConfigEntry
|
from tests.common import MockConfigEntry
|
||||||
|
|
||||||
|
|
||||||
async def setup_platform(hass, platform):
|
async def setup_platform(hass, platform) -> MockConfigEntry:
|
||||||
"""Set up the ecobee platform."""
|
"""Set up the ecobee platform."""
|
||||||
mock_entry = MockConfigEntry(
|
mock_entry = MockConfigEntry(
|
||||||
domain=DOMAIN,
|
domain=DOMAIN,
|
||||||
|
|
|
@ -1,6 +1,10 @@
|
||||||
"""Fixtures for tests."""
|
"""Fixtures for tests."""
|
||||||
|
from unittest.mock import MagicMock, patch
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
from homeassistant.components.ecobee import ECOBEE_API_KEY, ECOBEE_REFRESH_TOKEN
|
||||||
|
|
||||||
from tests.common import load_fixture
|
from tests.common import load_fixture
|
||||||
|
|
||||||
|
|
||||||
|
@ -15,3 +19,15 @@ def requests_mock_fixture(requests_mock):
|
||||||
"https://api.ecobee.com/token",
|
"https://api.ecobee.com/token",
|
||||||
text=load_fixture("ecobee/ecobee-token.json"),
|
text=load_fixture("ecobee/ecobee-token.json"),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def mock_ecobee():
|
||||||
|
"""Mock an Ecobee object."""
|
||||||
|
ecobee = MagicMock()
|
||||||
|
ecobee.request_pin.return_value = True
|
||||||
|
ecobee.refresh_tokens.return_value = True
|
||||||
|
|
||||||
|
ecobee.config = {ECOBEE_API_KEY: "mocked_key", ECOBEE_REFRESH_TOKEN: "mocked_token"}
|
||||||
|
with patch("homeassistant.components.ecobee.Ecobee", return_value=ecobee):
|
||||||
|
yield ecobee
|
||||||
|
|
|
@ -1,12 +1,22 @@
|
||||||
"""The test for the Ecobee thermostat module."""
|
"""The test for the Ecobee thermostat module."""
|
||||||
|
import copy
|
||||||
from http import HTTPStatus
|
from http import HTTPStatus
|
||||||
from unittest import mock
|
from unittest import mock
|
||||||
|
from unittest.mock import MagicMock
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from homeassistant.components.ecobee import climate as ecobee
|
from homeassistant.components import climate
|
||||||
|
from homeassistant.components.climate import ClimateEntityFeature
|
||||||
|
from homeassistant.components.ecobee.climate import ECOBEE_AUX_HEAT_ONLY, Thermostat
|
||||||
import homeassistant.const as const
|
import homeassistant.const as const
|
||||||
from homeassistant.const import STATE_OFF
|
from homeassistant.const import ATTR_ENTITY_ID, ATTR_SUPPORTED_FEATURES, STATE_OFF
|
||||||
|
from homeassistant.core import HomeAssistant
|
||||||
|
|
||||||
|
from tests.components.ecobee import GENERIC_THERMOSTAT_INFO_WITH_HEATPUMP
|
||||||
|
from tests.components.ecobee.common import setup_platform
|
||||||
|
|
||||||
|
ENTITY_ID = "climate.ecobee"
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
|
@ -68,7 +78,7 @@ def data_fixture(ecobee_fixture):
|
||||||
def thermostat_fixture(data):
|
def thermostat_fixture(data):
|
||||||
"""Set up ecobee thermostat object."""
|
"""Set up ecobee thermostat object."""
|
||||||
thermostat = data.ecobee.get_thermostat(1)
|
thermostat = data.ecobee.get_thermostat(1)
|
||||||
return ecobee.Thermostat(data, 1, thermostat)
|
return Thermostat(data, 1, thermostat)
|
||||||
|
|
||||||
|
|
||||||
async def test_name(thermostat) -> None:
|
async def test_name(thermostat) -> None:
|
||||||
|
@ -76,6 +86,37 @@ async def test_name(thermostat) -> None:
|
||||||
assert thermostat.name == "Ecobee"
|
assert thermostat.name == "Ecobee"
|
||||||
|
|
||||||
|
|
||||||
|
async def test_aux_heat_not_supported_by_default(hass):
|
||||||
|
"""Default setup should not support Aux heat."""
|
||||||
|
await setup_platform(hass, const.Platform.CLIMATE)
|
||||||
|
state = hass.states.get(ENTITY_ID)
|
||||||
|
assert (
|
||||||
|
state.attributes.get(ATTR_SUPPORTED_FEATURES)
|
||||||
|
== ClimateEntityFeature.PRESET_MODE
|
||||||
|
| ClimateEntityFeature.FAN_MODE
|
||||||
|
| ClimateEntityFeature.TARGET_HUMIDITY
|
||||||
|
| ClimateEntityFeature.TARGET_TEMPERATURE_RANGE
|
||||||
|
| ClimateEntityFeature.TARGET_TEMPERATURE
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def test_aux_heat_supported_with_heat_pump(hass):
|
||||||
|
"""Aux Heat should be supported if thermostat has heatpump."""
|
||||||
|
mock_get_thermostat = mock.Mock()
|
||||||
|
mock_get_thermostat.return_value = GENERIC_THERMOSTAT_INFO_WITH_HEATPUMP
|
||||||
|
with mock.patch("pyecobee.Ecobee.get_thermostat", mock_get_thermostat):
|
||||||
|
await setup_platform(hass, const.Platform.CLIMATE)
|
||||||
|
state = hass.states.get(ENTITY_ID)
|
||||||
|
assert (
|
||||||
|
state.attributes.get(ATTR_SUPPORTED_FEATURES)
|
||||||
|
== ClimateEntityFeature.PRESET_MODE
|
||||||
|
| ClimateEntityFeature.FAN_MODE
|
||||||
|
| ClimateEntityFeature.TARGET_TEMPERATURE_RANGE
|
||||||
|
| ClimateEntityFeature.TARGET_TEMPERATURE
|
||||||
|
| ClimateEntityFeature.AUX_HEAT
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
async def test_current_temperature(ecobee_fixture, thermostat) -> None:
|
async def test_current_temperature(ecobee_fixture, thermostat) -> None:
|
||||||
"""Test current temperature."""
|
"""Test current temperature."""
|
||||||
assert thermostat.current_temperature == 30
|
assert thermostat.current_temperature == 30
|
||||||
|
@ -201,11 +242,27 @@ async def test_extra_state_attributes(ecobee_fixture, thermostat) -> None:
|
||||||
} == thermostat.extra_state_attributes
|
} == thermostat.extra_state_attributes
|
||||||
|
|
||||||
|
|
||||||
async def test_is_aux_heat_on(ecobee_fixture, thermostat) -> None:
|
async def test_is_aux_heat_on(hass):
|
||||||
"""Test aux heat property."""
|
"""Test aux heat property is only enabled for auxHeatOnly."""
|
||||||
assert not thermostat.is_aux_heat
|
mock_get_thermostat = mock.Mock()
|
||||||
ecobee_fixture["equipmentStatus"] = "fan, auxHeat"
|
mock_get_thermostat.return_value = copy.deepcopy(
|
||||||
assert thermostat.is_aux_heat
|
GENERIC_THERMOSTAT_INFO_WITH_HEATPUMP
|
||||||
|
)
|
||||||
|
mock_get_thermostat.return_value["settings"]["hvacMode"] = "auxHeatOnly"
|
||||||
|
with mock.patch("pyecobee.Ecobee.get_thermostat", mock_get_thermostat):
|
||||||
|
await setup_platform(hass, const.Platform.CLIMATE)
|
||||||
|
state = hass.states.get(ENTITY_ID)
|
||||||
|
assert state.attributes[climate.ATTR_AUX_HEAT] == "on"
|
||||||
|
|
||||||
|
|
||||||
|
async def test_is_aux_heat_off(hass):
|
||||||
|
"""Test aux heat property is only enabled for auxHeatOnly."""
|
||||||
|
mock_get_thermostat = mock.Mock()
|
||||||
|
mock_get_thermostat.return_value = GENERIC_THERMOSTAT_INFO_WITH_HEATPUMP
|
||||||
|
with mock.patch("pyecobee.Ecobee.get_thermostat", mock_get_thermostat):
|
||||||
|
await setup_platform(hass, const.Platform.CLIMATE)
|
||||||
|
state = hass.states.get(ENTITY_ID)
|
||||||
|
assert state.attributes[climate.ATTR_AUX_HEAT] == "off"
|
||||||
|
|
||||||
|
|
||||||
async def test_set_temperature(ecobee_fixture, thermostat, data) -> None:
|
async def test_set_temperature(ecobee_fixture, thermostat, data) -> None:
|
||||||
|
@ -335,3 +392,33 @@ async def test_set_fan_mode_auto(thermostat, data) -> None:
|
||||||
data.ecobee.set_fan_mode.assert_has_calls(
|
data.ecobee.set_fan_mode.assert_has_calls(
|
||||||
[mock.call(1, "auto", "nextTransition", holdHours=None)]
|
[mock.call(1, "auto", "nextTransition", holdHours=None)]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def test_turn_aux_heat_on(hass: HomeAssistant, mock_ecobee: MagicMock) -> None:
|
||||||
|
"""Test when aux heat is set on. This must change the HVAC mode."""
|
||||||
|
mock_ecobee.get_thermostat.return_value = GENERIC_THERMOSTAT_INFO_WITH_HEATPUMP
|
||||||
|
mock_ecobee.thermostats = [GENERIC_THERMOSTAT_INFO_WITH_HEATPUMP]
|
||||||
|
await setup_platform(hass, const.Platform.CLIMATE)
|
||||||
|
await hass.services.async_call(
|
||||||
|
climate.DOMAIN,
|
||||||
|
climate.SERVICE_SET_AUX_HEAT,
|
||||||
|
{ATTR_ENTITY_ID: ENTITY_ID, climate.ATTR_AUX_HEAT: True},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
assert mock_ecobee.set_hvac_mode.call_count == 1
|
||||||
|
assert mock_ecobee.set_hvac_mode.call_args == mock.call(0, ECOBEE_AUX_HEAT_ONLY)
|
||||||
|
|
||||||
|
|
||||||
|
async def test_turn_aux_heat_off(hass: HomeAssistant, mock_ecobee: MagicMock) -> None:
|
||||||
|
"""Test when aux heat is tuned off. Must change HVAC mode back to last used."""
|
||||||
|
mock_ecobee.get_thermostat.return_value = GENERIC_THERMOSTAT_INFO_WITH_HEATPUMP
|
||||||
|
mock_ecobee.thermostats = [GENERIC_THERMOSTAT_INFO_WITH_HEATPUMP]
|
||||||
|
await setup_platform(hass, const.Platform.CLIMATE)
|
||||||
|
await hass.services.async_call(
|
||||||
|
climate.DOMAIN,
|
||||||
|
climate.SERVICE_SET_AUX_HEAT,
|
||||||
|
{ATTR_ENTITY_ID: ENTITY_ID, climate.ATTR_AUX_HEAT: False},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
assert mock_ecobee.set_hvac_mode.call_count == 1
|
||||||
|
assert mock_ecobee.set_hvac_mode.call_args == mock.call(0, "auto")
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue