Limit available heat/cool modes for HomeKit thermostats (#28586)
* Limit available heat/cool modes for HomeKit thermostats. The Home app only shows appropriate modes (heat/cool/auto) for the device. Depending on the climate integration, disabling the auto start might be needed. * Include improved mapping for HVAC modes in tests
This commit is contained in:
parent
27530be46f
commit
c5f4872aea
2 changed files with 115 additions and 29 deletions
|
@ -24,6 +24,8 @@ from homeassistant.components.climate.const import (
|
|||
HVAC_MODE_HEAT,
|
||||
HVAC_MODE_HEAT_COOL,
|
||||
HVAC_MODE_OFF,
|
||||
HVAC_MODE_FAN_ONLY,
|
||||
HVAC_MODE_AUTO,
|
||||
)
|
||||
from homeassistant.components.homekit.const import (
|
||||
ATTR_VALUE,
|
||||
|
@ -64,7 +66,20 @@ async def test_thermostat(hass, hk_driver, cls, events):
|
|||
"""Test if accessory and HA are updated accordingly."""
|
||||
entity_id = "climate.test"
|
||||
|
||||
hass.states.async_set(entity_id, HVAC_MODE_OFF)
|
||||
hass.states.async_set(
|
||||
entity_id,
|
||||
HVAC_MODE_OFF,
|
||||
{
|
||||
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 = cls.thermostat(hass, hk_driver, "Climate", entity_id, 2, None)
|
||||
await hass.async_add_job(acc.run)
|
||||
|
@ -120,7 +135,7 @@ async def test_thermostat(hass, hk_driver, cls, events):
|
|||
|
||||
hass.states.async_set(
|
||||
entity_id,
|
||||
HVAC_MODE_COOL,
|
||||
HVAC_MODE_FAN_ONLY,
|
||||
{
|
||||
ATTR_TEMPERATURE: 20.0,
|
||||
ATTR_CURRENT_TEMPERATURE: 25.0,
|
||||
|
@ -164,9 +179,8 @@ async def test_thermostat(hass, hk_driver, cls, events):
|
|||
|
||||
hass.states.async_set(
|
||||
entity_id,
|
||||
HVAC_MODE_HEAT_COOL,
|
||||
HVAC_MODE_AUTO,
|
||||
{
|
||||
ATTR_HVAC_MODES: [HVAC_MODE_HEAT, HVAC_MODE_COOL],
|
||||
ATTR_TEMPERATURE: 22.0,
|
||||
ATTR_CURRENT_TEMPERATURE: 18.0,
|
||||
ATTR_HVAC_ACTION: CURRENT_HVAC_HEAT,
|
||||
|
@ -183,7 +197,6 @@ async def test_thermostat(hass, hk_driver, cls, events):
|
|||
entity_id,
|
||||
HVAC_MODE_HEAT_COOL,
|
||||
{
|
||||
ATTR_HVAC_MODES: [HVAC_MODE_HEAT, HVAC_MODE_COOL],
|
||||
ATTR_TEMPERATURE: 22.0,
|
||||
ATTR_CURRENT_TEMPERATURE: 25.0,
|
||||
ATTR_HVAC_ACTION: CURRENT_HVAC_COOL,
|
||||
|
@ -198,9 +211,8 @@ async def test_thermostat(hass, hk_driver, cls, events):
|
|||
|
||||
hass.states.async_set(
|
||||
entity_id,
|
||||
HVAC_MODE_HEAT_COOL,
|
||||
HVAC_MODE_AUTO,
|
||||
{
|
||||
ATTR_HVAC_MODES: [HVAC_MODE_HEAT, HVAC_MODE_COOL],
|
||||
ATTR_TEMPERATURE: 22.0,
|
||||
ATTR_CURRENT_TEMPERATURE: 22.0,
|
||||
ATTR_HVAC_ACTION: CURRENT_HVAC_IDLE,
|
||||
|
@ -226,14 +238,23 @@ async def test_thermostat(hass, hk_driver, cls, events):
|
|||
assert len(events) == 1
|
||||
assert events[-1].data[ATTR_VALUE] == "19.0°C"
|
||||
|
||||
await hass.async_add_job(acc.char_target_heat_cool.client_update_value, 1)
|
||||
await hass.async_add_job(acc.char_target_heat_cool.client_update_value, 2)
|
||||
await hass.async_block_till_done()
|
||||
assert call_set_hvac_mode
|
||||
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
|
||||
assert acc.char_target_heat_cool.value == 1
|
||||
assert call_set_hvac_mode[0].data[ATTR_HVAC_MODE] == HVAC_MODE_COOL
|
||||
assert acc.char_target_heat_cool.value == 2
|
||||
assert len(events) == 2
|
||||
assert events[-1].data[ATTR_VALUE] == HVAC_MODE_HEAT
|
||||
assert events[-1].data[ATTR_VALUE] == HVAC_MODE_COOL
|
||||
|
||||
await hass.async_add_job(acc.char_target_heat_cool.client_update_value, 3)
|
||||
await hass.async_block_till_done()
|
||||
assert call_set_hvac_mode
|
||||
assert call_set_hvac_mode[1].data[ATTR_ENTITY_ID] == entity_id
|
||||
assert call_set_hvac_mode[1].data[ATTR_HVAC_MODE] == HVAC_MODE_AUTO
|
||||
assert acc.char_target_heat_cool.value == 3
|
||||
assert len(events) == 3
|
||||
assert events[-1].data[ATTR_VALUE] == HVAC_MODE_AUTO
|
||||
|
||||
|
||||
async def test_thermostat_auto(hass, hk_driver, cls, events):
|
||||
|
@ -261,7 +282,6 @@ async def test_thermostat_auto(hass, hk_driver, cls, events):
|
|||
entity_id,
|
||||
HVAC_MODE_HEAT_COOL,
|
||||
{
|
||||
ATTR_HVAC_MODE: HVAC_MODE_HEAT_COOL,
|
||||
ATTR_TARGET_TEMP_HIGH: 22.0,
|
||||
ATTR_TARGET_TEMP_LOW: 20.0,
|
||||
ATTR_CURRENT_TEMPERATURE: 18.0,
|
||||
|
@ -278,9 +298,8 @@ async def test_thermostat_auto(hass, hk_driver, cls, events):
|
|||
|
||||
hass.states.async_set(
|
||||
entity_id,
|
||||
HVAC_MODE_HEAT_COOL,
|
||||
HVAC_MODE_COOL,
|
||||
{
|
||||
ATTR_HVAC_MODE: HVAC_MODE_HEAT_COOL,
|
||||
ATTR_TARGET_TEMP_HIGH: 23.0,
|
||||
ATTR_TARGET_TEMP_LOW: 19.0,
|
||||
ATTR_CURRENT_TEMPERATURE: 24.0,
|
||||
|
@ -291,15 +310,14 @@ 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.value == 23.0
|
||||
assert acc.char_current_heat_cool.value == 2
|
||||
assert acc.char_target_heat_cool.value == 3
|
||||
assert acc.char_target_heat_cool.value == 2
|
||||
assert acc.char_current_temp.value == 24.0
|
||||
assert acc.char_display_units.value == 0
|
||||
|
||||
hass.states.async_set(
|
||||
entity_id,
|
||||
HVAC_MODE_HEAT_COOL,
|
||||
HVAC_MODE_AUTO,
|
||||
{
|
||||
ATTR_HVAC_MODE: HVAC_MODE_HEAT_COOL,
|
||||
ATTR_TARGET_TEMP_HIGH: 23.0,
|
||||
ATTR_TARGET_TEMP_LOW: 19.0,
|
||||
ATTR_CURRENT_TEMPERATURE: 21.0,
|
||||
|
@ -346,7 +364,6 @@ async def test_thermostat_power_state(hass, hk_driver, cls, events):
|
|||
HVAC_MODE_HEAT,
|
||||
{
|
||||
ATTR_SUPPORTED_FEATURES: 4096,
|
||||
ATTR_HVAC_MODE: HVAC_MODE_HEAT,
|
||||
ATTR_TEMPERATURE: 23.0,
|
||||
ATTR_CURRENT_TEMPERATURE: 18.0,
|
||||
ATTR_HVAC_ACTION: CURRENT_HVAC_HEAT,
|
||||
|
@ -364,7 +381,6 @@ async def test_thermostat_power_state(hass, hk_driver, cls, events):
|
|||
entity_id,
|
||||
HVAC_MODE_OFF,
|
||||
{
|
||||
ATTR_HVAC_MODE: HVAC_MODE_HEAT,
|
||||
ATTR_TEMPERATURE: 23.0,
|
||||
ATTR_CURRENT_TEMPERATURE: 18.0,
|
||||
ATTR_HVAC_ACTION: CURRENT_HVAC_IDLE,
|
||||
|
@ -378,7 +394,6 @@ async def test_thermostat_power_state(hass, hk_driver, cls, events):
|
|||
entity_id,
|
||||
HVAC_MODE_OFF,
|
||||
{
|
||||
ATTR_HVAC_MODE: HVAC_MODE_OFF,
|
||||
ATTR_TEMPERATURE: 23.0,
|
||||
ATTR_CURRENT_TEMPERATURE: 18.0,
|
||||
ATTR_HVAC_ACTION: CURRENT_HVAC_IDLE,
|
||||
|
@ -423,7 +438,6 @@ async def test_thermostat_fahrenheit(hass, hk_driver, cls, events):
|
|||
entity_id,
|
||||
HVAC_MODE_HEAT_COOL,
|
||||
{
|
||||
ATTR_HVAC_MODE: HVAC_MODE_HEAT_COOL,
|
||||
ATTR_TARGET_TEMP_HIGH: 75.2,
|
||||
ATTR_TARGET_TEMP_LOW: 68.1,
|
||||
ATTR_TEMPERATURE: 71.6,
|
||||
|
@ -503,6 +517,34 @@ async def test_thermostat_temperature_step_whole(hass, hk_driver, cls):
|
|||
assert acc.char_target_temp.properties[PROP_MIN_STEP] == 1.0
|
||||
|
||||
|
||||
async def test_thermostat_hvac_modes(hass, hk_driver, cls):
|
||||
"""Test if unsupported HVAC modes are deactivated in HomeKit."""
|
||||
entity_id = "climate.test"
|
||||
|
||||
hass.states.async_set(
|
||||
entity_id, HVAC_MODE_OFF, {ATTR_HVAC_MODES: [HVAC_MODE_HEAT, HVAC_MODE_OFF]}
|
||||
)
|
||||
|
||||
await hass.async_block_till_done()
|
||||
acc = cls.thermostat(hass, hk_driver, "Climate", entity_id, 2, None)
|
||||
await hass.async_add_job(acc.run)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
await hass.async_add_job(acc.char_target_heat_cool.set_value, 3)
|
||||
await hass.async_block_till_done()
|
||||
assert acc.char_target_heat_cool.value == 0
|
||||
|
||||
await hass.async_add_job(acc.char_target_heat_cool.set_value, 1)
|
||||
await hass.async_block_till_done()
|
||||
assert acc.char_target_heat_cool.value == 1
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
await hass.async_add_job(acc.char_target_heat_cool.set_value, 2)
|
||||
await hass.async_block_till_done()
|
||||
assert acc.char_target_heat_cool.value == 1
|
||||
|
||||
|
||||
async def test_water_heater(hass, hk_driver, cls, events):
|
||||
"""Test if accessory and HA are updated accordingly."""
|
||||
entity_id = "water_heater.test"
|
||||
|
@ -571,7 +613,8 @@ async def test_water_heater(hass, hk_driver, cls, events):
|
|||
await hass.async_block_till_done()
|
||||
assert acc.char_target_heat_cool.value == 1
|
||||
|
||||
await hass.async_add_job(acc.char_target_heat_cool.client_update_value, 3)
|
||||
with pytest.raises(ValueError):
|
||||
await hass.async_add_job(acc.char_target_heat_cool.set_value, 3)
|
||||
await hass.async_block_till_done()
|
||||
assert acc.char_target_heat_cool.value == 1
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue