mirror of
https://github.com/home-assistant/core.git
synced 2025-07-23 13:17:32 +00:00
Avoid homekit crash when temperature is clamped above max value (#37746)
This commit is contained in:
parent
9ecaa10e51
commit
f5cbae0cd5
@ -120,21 +120,12 @@ class Thermostat(HomeAccessory):
|
|||||||
self._state_updates = 0
|
self._state_updates = 0
|
||||||
self.hc_homekit_to_hass = None
|
self.hc_homekit_to_hass = None
|
||||||
self.hc_hass_to_homekit = None
|
self.hc_hass_to_homekit = None
|
||||||
min_temp, max_temp = self.get_temperature_range()
|
hc_min_temp, hc_max_temp = self.get_temperature_range()
|
||||||
|
|
||||||
# Homekit only supports 10-38, overwriting
|
|
||||||
# the max to appears to work, but less than 0 causes
|
|
||||||
# a crash on the home app
|
|
||||||
hc_min_temp = max(min_temp, 0)
|
|
||||||
hc_max_temp = max_temp
|
|
||||||
|
|
||||||
min_humidity = self.hass.states.get(self.entity_id).attributes.get(
|
|
||||||
ATTR_MIN_HUMIDITY, DEFAULT_MIN_HUMIDITY
|
|
||||||
)
|
|
||||||
|
|
||||||
# Add additional characteristics if auto mode is supported
|
# Add additional characteristics if auto mode is supported
|
||||||
self.chars = []
|
self.chars = []
|
||||||
state = self.hass.states.get(self.entity_id)
|
state = self.hass.states.get(self.entity_id)
|
||||||
|
min_humidity = state.attributes.get(ATTR_MIN_HUMIDITY, DEFAULT_MIN_HUMIDITY)
|
||||||
features = state.attributes.get(ATTR_SUPPORTED_FEATURES, 0)
|
features = state.attributes.get(ATTR_SUPPORTED_FEATURES, 0)
|
||||||
|
|
||||||
if features & SUPPORT_TARGET_TEMPERATURE_RANGE:
|
if features & SUPPORT_TARGET_TEMPERATURE_RANGE:
|
||||||
@ -370,19 +361,12 @@ class Thermostat(HomeAccessory):
|
|||||||
|
|
||||||
def get_temperature_range(self):
|
def get_temperature_range(self):
|
||||||
"""Return min and max temperature range."""
|
"""Return min and max temperature range."""
|
||||||
max_temp = self.hass.states.get(self.entity_id).attributes.get(ATTR_MAX_TEMP)
|
return _get_temperature_range_from_state(
|
||||||
max_temp = (
|
self.hass.states.get(self.entity_id),
|
||||||
self._temperature_to_homekit(max_temp) if max_temp else DEFAULT_MAX_TEMP
|
self._unit,
|
||||||
|
DEFAULT_MIN_TEMP,
|
||||||
|
DEFAULT_MAX_TEMP,
|
||||||
)
|
)
|
||||||
max_temp = round(max_temp * 2) / 2
|
|
||||||
|
|
||||||
min_temp = self.hass.states.get(self.entity_id).attributes.get(ATTR_MIN_TEMP)
|
|
||||||
min_temp = (
|
|
||||||
self._temperature_to_homekit(min_temp) if min_temp else DEFAULT_MIN_TEMP
|
|
||||||
)
|
|
||||||
min_temp = round(min_temp * 2) / 2
|
|
||||||
|
|
||||||
return min_temp, max_temp
|
|
||||||
|
|
||||||
def set_target_humidity(self, value):
|
def set_target_humidity(self, value):
|
||||||
"""Set target humidity to value if call came from HomeKit."""
|
"""Set target humidity to value if call came from HomeKit."""
|
||||||
@ -551,23 +535,12 @@ class WaterHeater(HomeAccessory):
|
|||||||
|
|
||||||
def get_temperature_range(self):
|
def get_temperature_range(self):
|
||||||
"""Return min and max temperature range."""
|
"""Return min and max temperature range."""
|
||||||
max_temp = self.hass.states.get(self.entity_id).attributes.get(ATTR_MAX_TEMP)
|
return _get_temperature_range_from_state(
|
||||||
max_temp = (
|
self.hass.states.get(self.entity_id),
|
||||||
temperature_to_homekit(max_temp, self._unit)
|
self._unit,
|
||||||
if max_temp
|
DEFAULT_MIN_TEMP_WATER_HEATER,
|
||||||
else DEFAULT_MAX_TEMP_WATER_HEATER
|
DEFAULT_MAX_TEMP_WATER_HEATER,
|
||||||
)
|
)
|
||||||
max_temp = round(max_temp * 2) / 2
|
|
||||||
|
|
||||||
min_temp = self.hass.states.get(self.entity_id).attributes.get(ATTR_MIN_TEMP)
|
|
||||||
min_temp = (
|
|
||||||
temperature_to_homekit(min_temp, self._unit)
|
|
||||||
if min_temp
|
|
||||||
else DEFAULT_MIN_TEMP_WATER_HEATER
|
|
||||||
)
|
|
||||||
min_temp = round(min_temp * 2) / 2
|
|
||||||
|
|
||||||
return min_temp, max_temp
|
|
||||||
|
|
||||||
def set_heat_cool(self, value):
|
def set_heat_cool(self, value):
|
||||||
"""Change operation mode to value if call came from HomeKit."""
|
"""Change operation mode to value if call came from HomeKit."""
|
||||||
@ -609,3 +582,27 @@ class WaterHeater(HomeAccessory):
|
|||||||
operation_mode = new_state.state
|
operation_mode = new_state.state
|
||||||
if operation_mode and self.char_target_heat_cool.value != 1:
|
if operation_mode and self.char_target_heat_cool.value != 1:
|
||||||
self.char_target_heat_cool.set_value(1) # Heat
|
self.char_target_heat_cool.set_value(1) # Heat
|
||||||
|
|
||||||
|
|
||||||
|
def _get_temperature_range_from_state(state, unit, default_min, default_max):
|
||||||
|
"""Calculate the temperature range from a state."""
|
||||||
|
min_temp = state.attributes.get(ATTR_MIN_TEMP)
|
||||||
|
if min_temp:
|
||||||
|
min_temp = round(temperature_to_homekit(min_temp, unit) * 2) / 2
|
||||||
|
else:
|
||||||
|
min_temp = default_min
|
||||||
|
|
||||||
|
max_temp = state.attributes.get(ATTR_MAX_TEMP)
|
||||||
|
if max_temp:
|
||||||
|
max_temp = round(temperature_to_homekit(max_temp, unit) * 2) / 2
|
||||||
|
else:
|
||||||
|
max_temp = default_max
|
||||||
|
|
||||||
|
# Homekit only supports 10-38, overwriting
|
||||||
|
# the max to appears to work, but less than 0 causes
|
||||||
|
# a crash on the home app
|
||||||
|
min_temp = max(min_temp, 0)
|
||||||
|
if min_temp > max_temp:
|
||||||
|
max_temp = min_temp
|
||||||
|
|
||||||
|
return min_temp, max_temp
|
||||||
|
@ -1617,3 +1617,57 @@ async def test_thermostat_with_no_off_after_recheck(hass, hk_driver, cls, events
|
|||||||
assert acc.char_target_heat_cool.value == 3
|
assert acc.char_target_heat_cool.value == 3
|
||||||
assert acc.char_current_temp.value == 18.0
|
assert acc.char_current_temp.value == 18.0
|
||||||
assert acc.char_display_units.value == 0
|
assert acc.char_display_units.value == 0
|
||||||
|
|
||||||
|
|
||||||
|
async def test_thermostat_with_temp_clamps(hass, hk_driver, cls, events):
|
||||||
|
"""Test that tempatures are clamped to valid values to prevent homekit crash."""
|
||||||
|
entity_id = "climate.test"
|
||||||
|
|
||||||
|
hass.states.async_set(
|
||||||
|
entity_id,
|
||||||
|
HVAC_MODE_COOL,
|
||||||
|
{
|
||||||
|
ATTR_SUPPORTED_FEATURES: SUPPORT_TARGET_TEMPERATURE
|
||||||
|
| SUPPORT_TARGET_TEMPERATURE_RANGE,
|
||||||
|
ATTR_HVAC_MODES: [],
|
||||||
|
ATTR_MAX_TEMP: 50,
|
||||||
|
ATTR_MIN_TEMP: 100,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
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 == 100
|
||||||
|
assert acc.char_heating_thresh_temp.value == 100
|
||||||
|
|
||||||
|
assert acc.char_cooling_thresh_temp.properties[PROP_MAX_VALUE] == 100
|
||||||
|
assert acc.char_cooling_thresh_temp.properties[PROP_MIN_VALUE] == 100
|
||||||
|
assert acc.char_cooling_thresh_temp.properties[PROP_MIN_STEP] == 0.1
|
||||||
|
assert acc.char_heating_thresh_temp.properties[PROP_MAX_VALUE] == 100
|
||||||
|
assert acc.char_heating_thresh_temp.properties[PROP_MIN_VALUE] == 100
|
||||||
|
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: 822.0,
|
||||||
|
ATTR_TARGET_TEMP_LOW: 20.0,
|
||||||
|
ATTR_CURRENT_TEMPERATURE: 9918.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 == 100.0
|
||||||
|
assert acc.char_cooling_thresh_temp.value == 100.0
|
||||||
|
assert acc.char_current_heat_cool.value == 1
|
||||||
|
assert acc.char_target_heat_cool.value == 3
|
||||||
|
assert acc.char_current_temp.value == 1000
|
||||||
|
assert acc.char_display_units.value == 0
|
||||||
|
Loading…
x
Reference in New Issue
Block a user