Fix handling homekit thermostat states (#34905)
This commit is contained in:
parent
fcd58b7c9b
commit
e01ceb1a57
2 changed files with 319 additions and 58 deletions
|
@ -117,12 +117,15 @@ class Thermostat(HomeAccessory):
|
|||
"""Initialize a Thermostat accessory object."""
|
||||
super().__init__(*args, category=CATEGORY_THERMOSTAT)
|
||||
self._unit = self.hass.config.units.temperature_unit
|
||||
self._state_updates = 0
|
||||
self.hc_homekit_to_hass = None
|
||||
self.hc_hass_to_homekit = None
|
||||
min_temp, max_temp = self.get_temperature_range()
|
||||
|
||||
# Homekit only supports 10-38, overwriting
|
||||
# the max to appears to work, but less than 10 causes
|
||||
# the max to appears to work, but less than 0 causes
|
||||
# a crash on the home app
|
||||
hc_min_temp = max(min_temp, HC_MIN_TEMP)
|
||||
hc_min_temp = max(min_temp, 0)
|
||||
hc_max_temp = max_temp
|
||||
|
||||
min_humidity = self.hass.states.get(self.entity_id).attributes.get(
|
||||
|
@ -149,48 +152,17 @@ class Thermostat(HomeAccessory):
|
|||
CHAR_CURRENT_HEATING_COOLING, value=0
|
||||
)
|
||||
|
||||
# Target mode characteristics
|
||||
hc_modes = state.attributes.get(ATTR_HVAC_MODES)
|
||||
if hc_modes is None:
|
||||
_LOGGER.error(
|
||||
"%s: HVAC modes not yet available. Please disable auto start for homekit.",
|
||||
self.entity_id,
|
||||
)
|
||||
hc_modes = (
|
||||
HVAC_MODE_HEAT,
|
||||
HVAC_MODE_COOL,
|
||||
HVAC_MODE_HEAT_COOL,
|
||||
HVAC_MODE_OFF,
|
||||
)
|
||||
|
||||
# Determine available modes for this entity,
|
||||
# Prefer HEAT_COOL over AUTO and COOL over FAN_ONLY, DRY
|
||||
#
|
||||
# HEAT_COOL is preferred over auto because HomeKit Accessory Protocol describes
|
||||
# heating or cooling comes on to maintain a target temp which is closest to
|
||||
# the Home Assistant spec
|
||||
#
|
||||
# HVAC_MODE_HEAT_COOL: The device supports heating/cooling to a range
|
||||
self.hc_homekit_to_hass = {
|
||||
c: s
|
||||
for s, c in HC_HASS_TO_HOMEKIT.items()
|
||||
if (
|
||||
s in hc_modes
|
||||
and not (
|
||||
(s == HVAC_MODE_AUTO and HVAC_MODE_HEAT_COOL in hc_modes)
|
||||
or (
|
||||
s in (HVAC_MODE_DRY, HVAC_MODE_FAN_ONLY)
|
||||
and HVAC_MODE_COOL in hc_modes
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
hc_valid_values = {k: v for v, k in self.hc_homekit_to_hass.items()}
|
||||
|
||||
self._configure_hvac_modes(state)
|
||||
# Must set the value first as setting
|
||||
# valid_values happens before setting
|
||||
# the value and if 0 is not a valid
|
||||
# value this will throw
|
||||
self.char_target_heat_cool = serv_thermostat.configure_char(
|
||||
CHAR_TARGET_HEATING_COOLING, valid_values=hc_valid_values,
|
||||
CHAR_TARGET_HEATING_COOLING, value=list(self.hc_homekit_to_hass)[0]
|
||||
)
|
||||
self.char_target_heat_cool.override_properties(
|
||||
valid_values=self.hc_hass_to_homekit
|
||||
)
|
||||
|
||||
# Current and target temperature characteristics
|
||||
|
||||
self.char_current_temp = serv_thermostat.configure_char(
|
||||
|
@ -249,7 +221,7 @@ class Thermostat(HomeAccessory):
|
|||
CHAR_CURRENT_HUMIDITY, value=50
|
||||
)
|
||||
|
||||
self.update_state(state)
|
||||
self._update_state(state)
|
||||
|
||||
serv_thermostat.setter_callback = self._set_chars
|
||||
|
||||
|
@ -356,6 +328,46 @@ class Thermostat(HomeAccessory):
|
|||
if CHAR_TARGET_HUMIDITY in char_values:
|
||||
self.set_target_humidity(char_values[CHAR_TARGET_HUMIDITY])
|
||||
|
||||
def _configure_hvac_modes(self, state):
|
||||
"""Configure target mode characteristics."""
|
||||
hc_modes = state.attributes.get(ATTR_HVAC_MODES)
|
||||
if not hc_modes:
|
||||
# This cannot be none OR an empty list
|
||||
_LOGGER.error(
|
||||
"%s: HVAC modes not yet available. Please disable auto start for homekit.",
|
||||
self.entity_id,
|
||||
)
|
||||
hc_modes = (
|
||||
HVAC_MODE_HEAT,
|
||||
HVAC_MODE_COOL,
|
||||
HVAC_MODE_HEAT_COOL,
|
||||
HVAC_MODE_OFF,
|
||||
)
|
||||
|
||||
# Determine available modes for this entity,
|
||||
# Prefer HEAT_COOL over AUTO and COOL over FAN_ONLY, DRY
|
||||
#
|
||||
# HEAT_COOL is preferred over auto because HomeKit Accessory Protocol describes
|
||||
# heating or cooling comes on to maintain a target temp which is closest to
|
||||
# the Home Assistant spec
|
||||
#
|
||||
# HVAC_MODE_HEAT_COOL: The device supports heating/cooling to a range
|
||||
self.hc_homekit_to_hass = {
|
||||
c: s
|
||||
for s, c in HC_HASS_TO_HOMEKIT.items()
|
||||
if (
|
||||
s in hc_modes
|
||||
and not (
|
||||
(s == HVAC_MODE_AUTO and HVAC_MODE_HEAT_COOL in hc_modes)
|
||||
or (
|
||||
s in (HVAC_MODE_DRY, HVAC_MODE_FAN_ONLY)
|
||||
and HVAC_MODE_COOL in hc_modes
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
self.hc_hass_to_homekit = {k: v for v, k in self.hc_homekit_to_hass.items()}
|
||||
|
||||
def get_temperature_range(self):
|
||||
"""Return min and max temperature range."""
|
||||
max_temp = self.hass.states.get(self.entity_id).attributes.get(ATTR_MAX_TEMP)
|
||||
|
@ -382,14 +394,46 @@ class Thermostat(HomeAccessory):
|
|||
|
||||
def update_state(self, new_state):
|
||||
"""Update thermostat state after state changed."""
|
||||
if self._state_updates < 3:
|
||||
# When we get the first state updates
|
||||
# we recheck valid hvac modes as the entity
|
||||
# may not have been fully setup when we saw it the
|
||||
# first time
|
||||
original_hc_hass_to_homekit = self.hc_hass_to_homekit
|
||||
self._configure_hvac_modes(new_state)
|
||||
if self.hc_hass_to_homekit != original_hc_hass_to_homekit:
|
||||
if self.char_target_heat_cool.value not in self.hc_homekit_to_hass:
|
||||
# We must make sure the char value is
|
||||
# in the new valid values before
|
||||
# setting the new valid values or
|
||||
# changing them with throw
|
||||
self.char_target_heat_cool.set_value(
|
||||
list(self.hc_homekit_to_hass)[0], should_notify=False
|
||||
)
|
||||
self.char_target_heat_cool.override_properties(
|
||||
valid_values=self.hc_hass_to_homekit
|
||||
)
|
||||
self._state_updates += 1
|
||||
|
||||
self._update_state(new_state)
|
||||
|
||||
def _update_state(self, new_state):
|
||||
"""Update state without rechecking the device features."""
|
||||
features = new_state.attributes.get(ATTR_SUPPORTED_FEATURES, 0)
|
||||
|
||||
# Update target operation mode FIRST
|
||||
hvac_mode = new_state.state
|
||||
if hvac_mode and hvac_mode in HC_HASS_TO_HOMEKIT:
|
||||
homekit_hvac_mode = HC_HASS_TO_HOMEKIT[hvac_mode]
|
||||
if self.char_target_heat_cool.value != homekit_hvac_mode:
|
||||
self.char_target_heat_cool.set_value(homekit_hvac_mode)
|
||||
if homekit_hvac_mode in self.hc_homekit_to_hass:
|
||||
if self.char_target_heat_cool.value != homekit_hvac_mode:
|
||||
self.char_target_heat_cool.set_value(homekit_hvac_mode)
|
||||
else:
|
||||
_LOGGER.error(
|
||||
"Cannot map hvac target mode: %s to homekit as only %s modes are supported",
|
||||
hvac_mode,
|
||||
self.hc_homekit_to_hass,
|
||||
)
|
||||
|
||||
# Set current operation mode for supported thermostats
|
||||
hvac_action = new_state.attributes.get(ATTR_HVAC_ACTION)
|
||||
|
@ -444,13 +488,13 @@ class Thermostat(HomeAccessory):
|
|||
# even if the device does not support it
|
||||
hc_hvac_mode = self.char_target_heat_cool.value
|
||||
if hc_hvac_mode == HC_HEAT_COOL_HEAT:
|
||||
target_temp = self._temperature_to_homekit(
|
||||
new_state.attributes.get(ATTR_TARGET_TEMP_LOW)
|
||||
)
|
||||
temp_low = new_state.attributes.get(ATTR_TARGET_TEMP_LOW)
|
||||
if isinstance(temp_low, (int, float)):
|
||||
target_temp = self._temperature_to_homekit(temp_low)
|
||||
elif hc_hvac_mode == HC_HEAT_COOL_COOL:
|
||||
target_temp = self._temperature_to_homekit(
|
||||
new_state.attributes.get(ATTR_TARGET_TEMP_HIGH)
|
||||
)
|
||||
temp_high = new_state.attributes.get(ATTR_TARGET_TEMP_HIGH)
|
||||
if isinstance(temp_high, (int, float)):
|
||||
target_temp = self._temperature_to_homekit(temp_high)
|
||||
if target_temp and self.char_target_temp.value != target_temp:
|
||||
self.char_target_temp.set_value(target_temp)
|
||||
|
||||
|
|
|
@ -43,7 +43,6 @@ from homeassistant.components.homekit.const import (
|
|||
PROP_MIN_STEP,
|
||||
PROP_MIN_VALUE,
|
||||
)
|
||||
from homeassistant.components.homekit.type_thermostats import HC_MIN_TEMP
|
||||
from homeassistant.components.water_heater import DOMAIN as DOMAIN_WATER_HEATER
|
||||
from homeassistant.const import (
|
||||
ATTR_ENTITY_ID,
|
||||
|
@ -116,7 +115,7 @@ async def test_thermostat(hass, hk_driver, cls, events):
|
|||
assert acc.char_current_humidity is None
|
||||
|
||||
assert acc.char_target_temp.properties[PROP_MAX_VALUE] == DEFAULT_MAX_TEMP
|
||||
assert acc.char_target_temp.properties[PROP_MIN_VALUE] == HC_MIN_TEMP
|
||||
assert acc.char_target_temp.properties[PROP_MIN_VALUE] == 7.0
|
||||
assert acc.char_target_temp.properties[PROP_MIN_STEP] == 0.1
|
||||
|
||||
hass.states.async_set(
|
||||
|
@ -126,6 +125,14 @@ async def test_thermostat(hass, hk_driver, cls, events):
|
|||
ATTR_TEMPERATURE: 22.2,
|
||||
ATTR_CURRENT_TEMPERATURE: 17.8,
|
||||
ATTR_HVAC_ACTION: CURRENT_HVAC_HEAT,
|
||||
ATTR_HVAC_MODES: [
|
||||
HVAC_MODE_HEAT,
|
||||
HVAC_MODE_HEAT_COOL,
|
||||
HVAC_MODE_FAN_ONLY,
|
||||
HVAC_MODE_COOL,
|
||||
HVAC_MODE_OFF,
|
||||
HVAC_MODE_AUTO,
|
||||
],
|
||||
},
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
|
@ -142,6 +149,14 @@ async def test_thermostat(hass, hk_driver, cls, events):
|
|||
ATTR_TEMPERATURE: 22.0,
|
||||
ATTR_CURRENT_TEMPERATURE: 23.0,
|
||||
ATTR_HVAC_ACTION: CURRENT_HVAC_IDLE,
|
||||
ATTR_HVAC_MODES: [
|
||||
HVAC_MODE_HEAT,
|
||||
HVAC_MODE_HEAT_COOL,
|
||||
HVAC_MODE_FAN_ONLY,
|
||||
HVAC_MODE_COOL,
|
||||
HVAC_MODE_OFF,
|
||||
HVAC_MODE_AUTO,
|
||||
],
|
||||
},
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
|
@ -158,6 +173,14 @@ async def test_thermostat(hass, hk_driver, cls, events):
|
|||
ATTR_TEMPERATURE: 20.0,
|
||||
ATTR_CURRENT_TEMPERATURE: 25.0,
|
||||
ATTR_HVAC_ACTION: CURRENT_HVAC_COOL,
|
||||
ATTR_HVAC_MODES: [
|
||||
HVAC_MODE_HEAT,
|
||||
HVAC_MODE_HEAT_COOL,
|
||||
HVAC_MODE_FAN_ONLY,
|
||||
HVAC_MODE_COOL,
|
||||
HVAC_MODE_OFF,
|
||||
HVAC_MODE_AUTO,
|
||||
],
|
||||
},
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
|
@ -202,6 +225,14 @@ async def test_thermostat(hass, hk_driver, cls, events):
|
|||
ATTR_TEMPERATURE: 22.0,
|
||||
ATTR_CURRENT_TEMPERATURE: 18.0,
|
||||
ATTR_HVAC_ACTION: CURRENT_HVAC_HEAT,
|
||||
ATTR_HVAC_MODES: [
|
||||
HVAC_MODE_HEAT,
|
||||
HVAC_MODE_HEAT_COOL,
|
||||
HVAC_MODE_FAN_ONLY,
|
||||
HVAC_MODE_COOL,
|
||||
HVAC_MODE_OFF,
|
||||
HVAC_MODE_AUTO,
|
||||
],
|
||||
},
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
|
@ -218,6 +249,14 @@ async def test_thermostat(hass, hk_driver, cls, events):
|
|||
ATTR_TEMPERATURE: 22.0,
|
||||
ATTR_CURRENT_TEMPERATURE: 25.0,
|
||||
ATTR_HVAC_ACTION: CURRENT_HVAC_COOL,
|
||||
ATTR_HVAC_MODES: [
|
||||
HVAC_MODE_HEAT,
|
||||
HVAC_MODE_HEAT_COOL,
|
||||
HVAC_MODE_FAN_ONLY,
|
||||
HVAC_MODE_COOL,
|
||||
HVAC_MODE_OFF,
|
||||
HVAC_MODE_AUTO,
|
||||
],
|
||||
},
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
|
@ -234,6 +273,14 @@ async def test_thermostat(hass, hk_driver, cls, events):
|
|||
ATTR_TEMPERATURE: 22.0,
|
||||
ATTR_CURRENT_TEMPERATURE: 22.0,
|
||||
ATTR_HVAC_ACTION: CURRENT_HVAC_IDLE,
|
||||
ATTR_HVAC_MODES: [
|
||||
HVAC_MODE_HEAT,
|
||||
HVAC_MODE_HEAT_COOL,
|
||||
HVAC_MODE_FAN_ONLY,
|
||||
HVAC_MODE_COOL,
|
||||
HVAC_MODE_OFF,
|
||||
HVAC_MODE_AUTO,
|
||||
],
|
||||
},
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
|
@ -250,6 +297,14 @@ async def test_thermostat(hass, hk_driver, cls, events):
|
|||
ATTR_TEMPERATURE: 22.0,
|
||||
ATTR_CURRENT_TEMPERATURE: 22.0,
|
||||
ATTR_HVAC_ACTION: CURRENT_HVAC_FAN,
|
||||
ATTR_HVAC_MODES: [
|
||||
HVAC_MODE_HEAT,
|
||||
HVAC_MODE_HEAT_COOL,
|
||||
HVAC_MODE_FAN_ONLY,
|
||||
HVAC_MODE_COOL,
|
||||
HVAC_MODE_OFF,
|
||||
HVAC_MODE_AUTO,
|
||||
],
|
||||
},
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
|
@ -369,7 +424,15 @@ async def test_thermostat_auto(hass, hk_driver, cls, events):
|
|||
HVAC_MODE_OFF,
|
||||
{
|
||||
ATTR_SUPPORTED_FEATURES: SUPPORT_TARGET_TEMPERATURE
|
||||
| SUPPORT_TARGET_TEMPERATURE_RANGE
|
||||
| SUPPORT_TARGET_TEMPERATURE_RANGE,
|
||||
ATTR_HVAC_MODES: [
|
||||
HVAC_MODE_HEAT,
|
||||
HVAC_MODE_HEAT_COOL,
|
||||
HVAC_MODE_FAN_ONLY,
|
||||
HVAC_MODE_COOL,
|
||||
HVAC_MODE_OFF,
|
||||
HVAC_MODE_AUTO,
|
||||
],
|
||||
},
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
|
@ -383,10 +446,10 @@ async def test_thermostat_auto(hass, hk_driver, cls, events):
|
|||
assert acc.char_heating_thresh_temp.value == 19.0
|
||||
|
||||
assert acc.char_cooling_thresh_temp.properties[PROP_MAX_VALUE] == DEFAULT_MAX_TEMP
|
||||
assert acc.char_cooling_thresh_temp.properties[PROP_MIN_VALUE] == HC_MIN_TEMP
|
||||
assert acc.char_cooling_thresh_temp.properties[PROP_MIN_VALUE] == 7.0
|
||||
assert acc.char_cooling_thresh_temp.properties[PROP_MIN_STEP] == 0.1
|
||||
assert acc.char_heating_thresh_temp.properties[PROP_MAX_VALUE] == DEFAULT_MAX_TEMP
|
||||
assert acc.char_heating_thresh_temp.properties[PROP_MIN_VALUE] == HC_MIN_TEMP
|
||||
assert acc.char_heating_thresh_temp.properties[PROP_MIN_VALUE] == 7.0
|
||||
assert acc.char_heating_thresh_temp.properties[PROP_MIN_STEP] == 0.1
|
||||
|
||||
hass.states.async_set(
|
||||
|
@ -397,6 +460,14 @@ async def test_thermostat_auto(hass, hk_driver, cls, events):
|
|||
ATTR_TARGET_TEMP_LOW: 20.0,
|
||||
ATTR_CURRENT_TEMPERATURE: 18.0,
|
||||
ATTR_HVAC_ACTION: CURRENT_HVAC_HEAT,
|
||||
ATTR_HVAC_MODES: [
|
||||
HVAC_MODE_HEAT,
|
||||
HVAC_MODE_HEAT_COOL,
|
||||
HVAC_MODE_FAN_ONLY,
|
||||
HVAC_MODE_COOL,
|
||||
HVAC_MODE_OFF,
|
||||
HVAC_MODE_AUTO,
|
||||
],
|
||||
},
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
|
@ -415,6 +486,14 @@ async def test_thermostat_auto(hass, hk_driver, cls, events):
|
|||
ATTR_TARGET_TEMP_LOW: 19.0,
|
||||
ATTR_CURRENT_TEMPERATURE: 24.0,
|
||||
ATTR_HVAC_ACTION: CURRENT_HVAC_COOL,
|
||||
ATTR_HVAC_MODES: [
|
||||
HVAC_MODE_HEAT,
|
||||
HVAC_MODE_HEAT_COOL,
|
||||
HVAC_MODE_FAN_ONLY,
|
||||
HVAC_MODE_COOL,
|
||||
HVAC_MODE_OFF,
|
||||
HVAC_MODE_AUTO,
|
||||
],
|
||||
},
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
|
@ -433,6 +512,14 @@ async def test_thermostat_auto(hass, hk_driver, cls, events):
|
|||
ATTR_TARGET_TEMP_LOW: 19.0,
|
||||
ATTR_CURRENT_TEMPERATURE: 21.0,
|
||||
ATTR_HVAC_ACTION: CURRENT_HVAC_IDLE,
|
||||
ATTR_HVAC_MODES: [
|
||||
HVAC_MODE_HEAT,
|
||||
HVAC_MODE_HEAT_COOL,
|
||||
HVAC_MODE_FAN_ONLY,
|
||||
HVAC_MODE_COOL,
|
||||
HVAC_MODE_OFF,
|
||||
HVAC_MODE_AUTO,
|
||||
],
|
||||
},
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
|
@ -1094,10 +1181,10 @@ async def test_thermostat_without_target_temp_only_range(hass, hk_driver, cls, e
|
|||
assert acc.char_heating_thresh_temp.value == 19.0
|
||||
|
||||
assert acc.char_cooling_thresh_temp.properties[PROP_MAX_VALUE] == DEFAULT_MAX_TEMP
|
||||
assert acc.char_cooling_thresh_temp.properties[PROP_MIN_VALUE] == HC_MIN_TEMP
|
||||
assert acc.char_cooling_thresh_temp.properties[PROP_MIN_VALUE] == 7.0
|
||||
assert acc.char_cooling_thresh_temp.properties[PROP_MIN_STEP] == 0.1
|
||||
assert acc.char_heating_thresh_temp.properties[PROP_MAX_VALUE] == DEFAULT_MAX_TEMP
|
||||
assert acc.char_heating_thresh_temp.properties[PROP_MIN_VALUE] == HC_MIN_TEMP
|
||||
assert acc.char_heating_thresh_temp.properties[PROP_MIN_VALUE] == 7.0
|
||||
assert acc.char_heating_thresh_temp.properties[PROP_MIN_STEP] == 0.1
|
||||
|
||||
hass.states.async_set(
|
||||
|
@ -1109,6 +1196,14 @@ async def test_thermostat_without_target_temp_only_range(hass, hk_driver, cls, e
|
|||
ATTR_CURRENT_TEMPERATURE: 18.0,
|
||||
ATTR_HVAC_ACTION: CURRENT_HVAC_HEAT,
|
||||
ATTR_SUPPORTED_FEATURES: SUPPORT_TARGET_TEMPERATURE_RANGE,
|
||||
ATTR_HVAC_MODES: [
|
||||
HVAC_MODE_HEAT,
|
||||
HVAC_MODE_HEAT_COOL,
|
||||
HVAC_MODE_FAN_ONLY,
|
||||
HVAC_MODE_COOL,
|
||||
HVAC_MODE_OFF,
|
||||
HVAC_MODE_AUTO,
|
||||
],
|
||||
},
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
|
@ -1128,6 +1223,14 @@ async def test_thermostat_without_target_temp_only_range(hass, hk_driver, cls, e
|
|||
ATTR_CURRENT_TEMPERATURE: 24.0,
|
||||
ATTR_HVAC_ACTION: CURRENT_HVAC_COOL,
|
||||
ATTR_SUPPORTED_FEATURES: SUPPORT_TARGET_TEMPERATURE_RANGE,
|
||||
ATTR_HVAC_MODES: [
|
||||
HVAC_MODE_HEAT,
|
||||
HVAC_MODE_HEAT_COOL,
|
||||
HVAC_MODE_FAN_ONLY,
|
||||
HVAC_MODE_COOL,
|
||||
HVAC_MODE_OFF,
|
||||
HVAC_MODE_AUTO,
|
||||
],
|
||||
},
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
|
@ -1147,6 +1250,14 @@ async def test_thermostat_without_target_temp_only_range(hass, hk_driver, cls, e
|
|||
ATTR_CURRENT_TEMPERATURE: 21.0,
|
||||
ATTR_HVAC_ACTION: CURRENT_HVAC_IDLE,
|
||||
ATTR_SUPPORTED_FEATURES: SUPPORT_TARGET_TEMPERATURE_RANGE,
|
||||
ATTR_HVAC_MODES: [
|
||||
HVAC_MODE_HEAT,
|
||||
HVAC_MODE_HEAT_COOL,
|
||||
HVAC_MODE_FAN_ONLY,
|
||||
HVAC_MODE_COOL,
|
||||
HVAC_MODE_OFF,
|
||||
HVAC_MODE_AUTO,
|
||||
],
|
||||
},
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
|
@ -1400,3 +1511,109 @@ async def test_water_heater_restore(hass, hk_driver, cls, events):
|
|||
"Heat",
|
||||
"Off",
|
||||
}
|
||||
|
||||
|
||||
async def test_thermostat_with_no_modes_when_we_first_see(hass, hk_driver, cls, events):
|
||||
"""Test if a thermostat that is not ready when we first see it."""
|
||||
entity_id = "climate.test"
|
||||
|
||||
# support_auto = True
|
||||
hass.states.async_set(
|
||||
entity_id,
|
||||
HVAC_MODE_OFF,
|
||||
{
|
||||
ATTR_SUPPORTED_FEATURES: SUPPORT_TARGET_TEMPERATURE
|
||||
| SUPPORT_TARGET_TEMPERATURE_RANGE,
|
||||
ATTR_HVAC_MODES: [],
|
||||
},
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
acc = cls.thermostat(hass, hk_driver, "Climate", entity_id, 1, None)
|
||||
hk_driver.add_accessory(acc)
|
||||
|
||||
await acc.run_handler()
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert acc.char_cooling_thresh_temp.value == 23.0
|
||||
assert acc.char_heating_thresh_temp.value == 19.0
|
||||
|
||||
assert acc.char_cooling_thresh_temp.properties[PROP_MAX_VALUE] == DEFAULT_MAX_TEMP
|
||||
assert acc.char_cooling_thresh_temp.properties[PROP_MIN_VALUE] == 7.0
|
||||
assert acc.char_cooling_thresh_temp.properties[PROP_MIN_STEP] == 0.1
|
||||
assert acc.char_heating_thresh_temp.properties[PROP_MAX_VALUE] == DEFAULT_MAX_TEMP
|
||||
assert acc.char_heating_thresh_temp.properties[PROP_MIN_VALUE] == 7.0
|
||||
assert acc.char_heating_thresh_temp.properties[PROP_MIN_STEP] == 0.1
|
||||
|
||||
assert acc.char_target_heat_cool.value == 0
|
||||
|
||||
hass.states.async_set(
|
||||
entity_id,
|
||||
HVAC_MODE_HEAT_COOL,
|
||||
{
|
||||
ATTR_TARGET_TEMP_HIGH: 22.0,
|
||||
ATTR_TARGET_TEMP_LOW: 20.0,
|
||||
ATTR_CURRENT_TEMPERATURE: 18.0,
|
||||
ATTR_HVAC_ACTION: CURRENT_HVAC_HEAT,
|
||||
ATTR_HVAC_MODES: [HVAC_MODE_HEAT_COOL, HVAC_MODE_OFF, HVAC_MODE_AUTO],
|
||||
},
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
assert acc.char_heating_thresh_temp.value == 20.0
|
||||
assert acc.char_cooling_thresh_temp.value == 22.0
|
||||
assert acc.char_current_heat_cool.value == 1
|
||||
assert acc.char_target_heat_cool.value == 3
|
||||
assert acc.char_current_temp.value == 18.0
|
||||
assert acc.char_display_units.value == 0
|
||||
|
||||
|
||||
async def test_thermostat_with_no_off_after_recheck(hass, hk_driver, cls, events):
|
||||
"""Test if a thermostat that is not ready when we first see it that actually does not have off."""
|
||||
entity_id = "climate.test"
|
||||
|
||||
# support_auto = True
|
||||
hass.states.async_set(
|
||||
entity_id,
|
||||
HVAC_MODE_COOL,
|
||||
{
|
||||
ATTR_SUPPORTED_FEATURES: SUPPORT_TARGET_TEMPERATURE
|
||||
| SUPPORT_TARGET_TEMPERATURE_RANGE,
|
||||
ATTR_HVAC_MODES: [],
|
||||
},
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
acc = cls.thermostat(hass, hk_driver, "Climate", entity_id, 1, None)
|
||||
hk_driver.add_accessory(acc)
|
||||
|
||||
await acc.run_handler()
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert acc.char_cooling_thresh_temp.value == 23.0
|
||||
assert acc.char_heating_thresh_temp.value == 19.0
|
||||
|
||||
assert acc.char_cooling_thresh_temp.properties[PROP_MAX_VALUE] == DEFAULT_MAX_TEMP
|
||||
assert acc.char_cooling_thresh_temp.properties[PROP_MIN_VALUE] == 7.0
|
||||
assert acc.char_cooling_thresh_temp.properties[PROP_MIN_STEP] == 0.1
|
||||
assert acc.char_heating_thresh_temp.properties[PROP_MAX_VALUE] == DEFAULT_MAX_TEMP
|
||||
assert acc.char_heating_thresh_temp.properties[PROP_MIN_VALUE] == 7.0
|
||||
assert acc.char_heating_thresh_temp.properties[PROP_MIN_STEP] == 0.1
|
||||
|
||||
assert acc.char_target_heat_cool.value == 2
|
||||
|
||||
hass.states.async_set(
|
||||
entity_id,
|
||||
HVAC_MODE_HEAT_COOL,
|
||||
{
|
||||
ATTR_TARGET_TEMP_HIGH: 22.0,
|
||||
ATTR_TARGET_TEMP_LOW: 20.0,
|
||||
ATTR_CURRENT_TEMPERATURE: 18.0,
|
||||
ATTR_HVAC_ACTION: CURRENT_HVAC_HEAT,
|
||||
ATTR_HVAC_MODES: [HVAC_MODE_HEAT_COOL, HVAC_MODE_AUTO],
|
||||
},
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
assert acc.char_heating_thresh_temp.value == 20.0
|
||||
assert acc.char_cooling_thresh_temp.value == 22.0
|
||||
assert acc.char_current_heat_cool.value == 1
|
||||
assert acc.char_target_heat_cool.value == 3
|
||||
assert acc.char_current_temp.value == 18.0
|
||||
assert acc.char_display_units.value == 0
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue