1
mirror of https://github.com/home-assistant/core synced 2024-08-02 23:40:32 +02:00

Fix HomeKit requests with hvac mode and temperature in the same call (#56239)

This commit is contained in:
J. Nick Koston 2021-09-17 19:47:06 -10:00 committed by GitHub
parent aaadd42539
commit 7524daad86
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 125 additions and 5 deletions

View File

@ -245,7 +245,7 @@ class Thermostat(HomeAccessory):
def _set_chars(self, char_values):
_LOGGER.debug("Thermostat _set_chars: %s", char_values)
events = []
params = {}
params = {ATTR_ENTITY_ID: self.entity_id}
service = None
state = self.hass.states.get(self.entity_id)
features = state.attributes.get(ATTR_SUPPORTED_FEATURES, 0)
@ -285,12 +285,20 @@ class Thermostat(HomeAccessory):
target_hc = hc_fallback
break
service = SERVICE_SET_HVAC_MODE_THERMOSTAT
hass_value = self.hc_homekit_to_hass[target_hc]
params = {ATTR_HVAC_MODE: hass_value}
params[ATTR_HVAC_MODE] = self.hc_homekit_to_hass[target_hc]
events.append(
f"{CHAR_TARGET_HEATING_COOLING} to {char_values[CHAR_TARGET_HEATING_COOLING]}"
)
# Many integrations do not actually implement `hvac_mode` for the
# `SERVICE_SET_TEMPERATURE_THERMOSTAT` service so we made a call to
# `SERVICE_SET_HVAC_MODE_THERMOSTAT` before calling `SERVICE_SET_TEMPERATURE_THERMOSTAT`
# to ensure the device is in the right mode before setting the temp.
self.async_call_service(
DOMAIN_CLIMATE,
SERVICE_SET_HVAC_MODE_THERMOSTAT,
params.copy(),
", ".join(events),
)
if CHAR_TARGET_TEMPERATURE in char_values:
hc_target_temp = char_values[CHAR_TARGET_TEMPERATURE]
@ -357,7 +365,6 @@ class Thermostat(HomeAccessory):
)
if service:
params[ATTR_ENTITY_ID] = self.entity_id
self.async_call_service(
DOMAIN_CLIMATE,
service,

View File

@ -560,6 +560,119 @@ async def test_thermostat_auto(hass, hk_driver, events):
)
async def test_thermostat_mode_and_temp_change(hass, hk_driver, events):
"""Test if accessory where the mode and temp change in the same call."""
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: [
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()
acc = Thermostat(hass, hk_driver, "Climate", entity_id, 1, None)
hk_driver.add_accessory(acc)
await acc.run()
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
hass.states.async_set(
entity_id,
HVAC_MODE_COOL,
{
ATTR_TARGET_TEMP_HIGH: 23.0,
ATTR_TARGET_TEMP_LOW: 19.0,
ATTR_CURRENT_TEMPERATURE: 21.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()
assert acc.char_heating_thresh_temp.value == 19.0
assert acc.char_cooling_thresh_temp.value == 23.0
assert acc.char_current_heat_cool.value == HC_HEAT_COOL_COOL
assert acc.char_target_heat_cool.value == HC_HEAT_COOL_COOL
assert acc.char_current_temp.value == 21.0
assert acc.char_display_units.value == 0
# Set from HomeKit
call_set_temperature = async_mock_service(hass, DOMAIN_CLIMATE, "set_temperature")
call_set_hvac_mode = async_mock_service(hass, DOMAIN_CLIMATE, "set_hvac_mode")
char_heating_thresh_temp_iid = acc.char_heating_thresh_temp.to_HAP()[HAP_REPR_IID]
char_cooling_thresh_temp_iid = acc.char_cooling_thresh_temp.to_HAP()[HAP_REPR_IID]
char_target_heat_cool_iid = acc.char_target_heat_cool.to_HAP()[HAP_REPR_IID]
hk_driver.set_characteristics(
{
HAP_REPR_CHARS: [
{
HAP_REPR_AID: acc.aid,
HAP_REPR_IID: char_heating_thresh_temp_iid,
HAP_REPR_VALUE: 20.0,
},
{
HAP_REPR_AID: acc.aid,
HAP_REPR_IID: char_cooling_thresh_temp_iid,
HAP_REPR_VALUE: 25.0,
},
{
HAP_REPR_AID: acc.aid,
HAP_REPR_IID: char_target_heat_cool_iid,
HAP_REPR_VALUE: HC_HEAT_COOL_AUTO,
},
]
},
"mock_addr",
)
await hass.async_block_till_done()
assert call_set_hvac_mode[0]
assert call_set_hvac_mode[0].data[ATTR_ENTITY_ID] == entity_id
assert call_set_hvac_mode[0].data[ATTR_HVAC_MODE] == HVAC_MODE_HEAT_COOL
assert call_set_temperature[0]
assert call_set_temperature[0].data[ATTR_ENTITY_ID] == entity_id
assert call_set_temperature[0].data[ATTR_TARGET_TEMP_LOW] == 20.0
assert call_set_temperature[0].data[ATTR_TARGET_TEMP_HIGH] == 25.0
assert acc.char_heating_thresh_temp.value == 20.0
assert acc.char_cooling_thresh_temp.value == 25.0
assert len(events) == 2
assert events[-2].data[ATTR_VALUE] == "TargetHeatingCoolingState to 3"
assert (
events[-1].data[ATTR_VALUE]
== "TargetHeatingCoolingState to 3, CoolingThresholdTemperature to 25.0°C, HeatingThresholdTemperature to 20.0°C"
)
async def test_thermostat_humidity(hass, hk_driver, events):
"""Test if accessory and HA are updated accordingly with humidity."""
entity_id = "climate.test"