Fix HomeKit power control for Daikin zone climates (#178408)

This commit is contained in:
James
2026-09-03 13:00:53 +02:00
committed by GitHub
parent 45615ec7c4
commit c9d17c6c15
2 changed files with 57 additions and 13 deletions
+12 -3
View File
@@ -416,8 +416,11 @@ class DaikinZoneClimate(DaikinEntity, ClimateEntity):
@property
@override
def hvac_modes(self) -> list[HVACMode]:
"""Return the hvac modes (mirrors the main unit)."""
return [self._main_hvac_mode]
"""Return the main unit HVAC mode and zone power off."""
main_mode = self._main_hvac_mode
if main_mode == HVACMode.OFF:
return [HVACMode.OFF]
return [main_mode, HVACMode.OFF]
@property
@override
@@ -549,7 +552,13 @@ class DaikinZoneClimate(DaikinEntity, ClimateEntity):
@override
async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None:
"""Disallow changing HVAC mode via zone climate."""
"""Set zone power without changing the main unit HVAC mode."""
if hvac_mode == HVACMode.OFF:
await self.async_turn_off()
return
if hvac_mode == self._main_hvac_mode:
await self.async_turn_on()
return
raise HomeAssistantError(
translation_domain=DOMAIN,
translation_key="zone_hvac_read_only",
+45 -10
View File
@@ -279,29 +279,31 @@ async def test_zone_climate_parameters_unavailable(
assert state.state == STATE_UNAVAILABLE
async def test_zone_climate_hvac_modes_read_only(
async def test_zone_climate_rejects_main_mode_change(
hass: HomeAssistant,
entity_registry: er.EntityRegistry,
zone_device: ZoneDevice,
) -> None:
"""Changing HVAC mode through a zone climate is blocked."""
"""Changing the main HVAC mode through a zone climate is blocked."""
configure_zone_device(zone_device, zones=[["Living", "1", 22]])
await _async_setup_daikin(hass, zone_device)
entity_id = _zone_entity_id(entity_registry, zone_device, 0)
assert entity_id is not None
with pytest.raises(HomeAssistantError) as err:
with pytest.raises(ServiceValidationError) as err:
await hass.services.async_call(
CLIMATE_DOMAIN,
SERVICE_SET_HVAC_MODE,
{
ATTR_ENTITY_ID: entity_id,
ATTR_HVAC_MODE: HVACMode.HEAT,
ATTR_HVAC_MODE: HVACMode.COOL,
},
blocking=True,
)
assert err.value.translation_key == "zone_hvac_read_only"
assert err.value.translation_key == "not_valid_hvac_mode"
zone_device.set_zone.assert_not_awaited()
zone_device.set.assert_not_awaited()
async def test_zone_climate_set_temperature_requires_heat_or_cool(
@@ -360,7 +362,7 @@ async def test_zone_climate_properties(
assert state.attributes[ATTR_TEMPERATURE] == 18.0
assert state.attributes[ATTR_MIN_TEMP] == 22.0
assert state.attributes[ATTR_MAX_TEMP] == 26.0
assert state.attributes[ATTR_HVAC_MODES] == [HVACMode.COOL]
assert state.attributes[ATTR_HVAC_MODES] == [HVACMode.COOL, HVACMode.OFF]
assert state.attributes[ATTR_SUPPORTED_FEATURES] == (
ClimateEntityFeature.TARGET_TEMPERATURE
| ClimateEntityFeature.TURN_OFF
@@ -377,6 +379,7 @@ async def test_zone_climate_properties(
"expected_climate_state",
"expected_switch_state",
"main_mode",
"service_data",
),
[
pytest.param(
@@ -386,6 +389,7 @@ async def test_zone_climate_properties(
HVACMode.COOL,
STATE_ON,
"cool",
{},
id="climate-turn-on",
),
pytest.param(
@@ -395,6 +399,7 @@ async def test_zone_climate_properties(
HVACMode.OFF,
STATE_OFF,
"cool",
{},
id="climate-turn-off",
),
pytest.param(
@@ -404,6 +409,7 @@ async def test_zone_climate_properties(
HVACMode.OFF,
STATE_OFF,
"cool",
{},
id="climate-toggle-off",
),
pytest.param(
@@ -413,8 +419,29 @@ async def test_zone_climate_properties(
HVACMode.OFF,
STATE_OFF,
"off",
{},
id="climate-toggle-zone-on-main-off",
),
pytest.param(
SERVICE_SET_HVAC_MODE,
"0",
"1",
HVACMode.HEAT,
STATE_ON,
"hot",
{ATTR_HVAC_MODE: HVACMode.HEAT},
id="hvac-mode-turn-on",
),
pytest.param(
SERVICE_SET_HVAC_MODE,
"1",
"0",
HVACMode.OFF,
STATE_OFF,
"hot",
{ATTR_HVAC_MODE: HVACMode.OFF},
id="hvac-mode-turn-off",
),
],
)
async def test_zone_climate_power_controls(
@@ -427,6 +454,7 @@ async def test_zone_climate_power_controls(
expected_climate_state: HVACMode,
expected_switch_state: str,
main_mode: str,
service_data: dict[str, HVACMode],
) -> None:
"""Zone climate and switch power controls stay synchronized."""
configure_zone_device(
@@ -449,7 +477,7 @@ async def test_zone_climate_power_controls(
await hass.services.async_call(
CLIMATE_DOMAIN,
service,
{ATTR_ENTITY_ID: climate_entity_id},
{ATTR_ENTITY_ID: climate_entity_id, **service_data},
blocking=True,
)
@@ -504,10 +532,15 @@ async def test_zone_switch_updates_zone_climate(
@pytest.mark.parametrize(
("mode", "expected_state"),
("mode", "expected_state", "expected_modes"),
[
pytest.param("auto", HVACMode.HEAT_COOL, id="auto"),
pytest.param("off", HVACMode.OFF, id="off"),
pytest.param(
"auto",
HVACMode.HEAT_COOL,
[HVACMode.HEAT_COOL, HVACMode.OFF],
id="auto",
),
pytest.param("off", HVACMode.OFF, [HVACMode.OFF], id="off"),
],
)
async def test_zone_climate_target_temperature_inactive_mode(
@@ -516,6 +549,7 @@ async def test_zone_climate_target_temperature_inactive_mode(
zone_device: ZoneDevice,
mode: str,
expected_state: HVACMode,
expected_modes: list[HVACMode],
) -> None:
"""In non-heating/cooling modes, zone target temperature is None."""
configure_zone_device(
@@ -532,6 +566,7 @@ async def test_zone_climate_target_temperature_inactive_mode(
state = hass.states.get(entity_id)
assert state is not None
assert state.state == expected_state
assert state.attributes[ATTR_HVAC_MODES] == expected_modes
assert state.attributes[ATTR_TEMPERATURE] is None