Use SmartThings cooling setpoint range for air conditioners (#178430)

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
StellarSea
2026-08-07 13:37:14 +02:00
committed by GitHub
co-authored by Claude Opus 5
parent 1e2209c618
commit 44f553e761
3 changed files with 77 additions and 8 deletions
@@ -582,6 +582,39 @@ class SmartThingsAirConditioner(SmartThingsEntity, ClimateEntity):
Capability.THERMOSTAT_COOLING_SETPOINT, Attribute.COOLING_SETPOINT
)
def _get_setpoint_range_value(self, key: str) -> float | None:
"""Return a value from the cooling setpoint range, if the device reports it."""
if (
setpoint_range := self.get_attribute_value(
Capability.THERMOSTAT_COOLING_SETPOINT,
Attribute.COOLING_SETPOINT_RANGE,
)
) is None:
return None
return setpoint_range.get(key)
@property
@override
def target_temperature_step(self) -> float | None:
"""Return the supported step of target temperature."""
return self._get_setpoint_range_value("step")
@property
@override
def min_temp(self) -> float:
"""Return the minimum temperature."""
if (minimum := self._get_setpoint_range_value("minimum")) is None:
return DEFAULT_MIN_TEMP
return minimum
@property
@override
def max_temp(self) -> float:
"""Return the maximum temperature."""
if (maximum := self._get_setpoint_range_value("maximum")) is None:
return DEFAULT_MAX_TEMP
return maximum
@property
@override
def temperature_unit(self) -> str:
@@ -155,8 +155,8 @@
<HVACMode.FAN_ONLY: 'fan_only'>,
<HVACMode.HEAT: 'heat'>,
]),
<ClimateEntityCapabilityAttribute.MAX_TEMP: 'max_temp'>: 35,
<ClimateEntityCapabilityAttribute.MIN_TEMP: 'min_temp'>: 7,
<ClimateEntityCapabilityAttribute.MAX_TEMP: 'max_temp'>: 30,
<ClimateEntityCapabilityAttribute.MIN_TEMP: 'min_temp'>: 18,
<ClimateEntityCapabilityAttribute.PRESET_MODES: 'preset_modes'>: list([
'none',
'wind_free',
@@ -171,6 +171,7 @@
'horizontal',
'both',
]),
<ClimateEntityCapabilityAttribute.TARGET_TEMP_STEP: 'target_temp_step'>: 0.5,
}),
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
@@ -226,8 +227,8 @@
<HVACMode.FAN_ONLY: 'fan_only'>,
<HVACMode.HEAT: 'heat'>,
]),
<ClimateEntityCapabilityAttribute.MAX_TEMP: 'max_temp'>: 35,
<ClimateEntityCapabilityAttribute.MIN_TEMP: 'min_temp'>: 7,
<ClimateEntityCapabilityAttribute.MAX_TEMP: 'max_temp'>: 30,
<ClimateEntityCapabilityAttribute.MIN_TEMP: 'min_temp'>: 18,
<ClimateEntityStateAttribute.PRESET_MODE: 'preset_mode'>: 'none',
<ClimateEntityCapabilityAttribute.PRESET_MODES: 'preset_modes'>: list([
'none',
@@ -245,6 +246,7 @@
'horizontal',
'both',
]),
<ClimateEntityCapabilityAttribute.TARGET_TEMP_STEP: 'target_temp_step'>: 0.5,
<ClimateEntityStateAttribute.TARGET_TEMPERATURE: 'temperature'>: 20,
}),
'context': <ANY>,
@@ -581,8 +583,8 @@
<HVACMode.FAN_ONLY: 'fan_only'>,
<HVACMode.HEAT: 'heat'>,
]),
<ClimateEntityCapabilityAttribute.MAX_TEMP: 'max_temp'>: 35,
<ClimateEntityCapabilityAttribute.MIN_TEMP: 'min_temp'>: 7,
<ClimateEntityCapabilityAttribute.MAX_TEMP: 'max_temp'>: 30,
<ClimateEntityCapabilityAttribute.MIN_TEMP: 'min_temp'>: 16,
<ClimateEntityCapabilityAttribute.PRESET_MODES: 'preset_modes'>: list([
'none',
'sleep',
@@ -598,6 +600,7 @@
'horizontal',
'both',
]),
<ClimateEntityCapabilityAttribute.TARGET_TEMP_STEP: 'target_temp_step'>: 1,
}),
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
@@ -654,8 +657,8 @@
<HVACMode.FAN_ONLY: 'fan_only'>,
<HVACMode.HEAT: 'heat'>,
]),
<ClimateEntityCapabilityAttribute.MAX_TEMP: 'max_temp'>: 35,
<ClimateEntityCapabilityAttribute.MIN_TEMP: 'min_temp'>: 7,
<ClimateEntityCapabilityAttribute.MAX_TEMP: 'max_temp'>: 30,
<ClimateEntityCapabilityAttribute.MIN_TEMP: 'min_temp'>: 16,
<ClimateEntityStateAttribute.PRESET_MODE: 'preset_mode'>: 'none',
<ClimateEntityCapabilityAttribute.PRESET_MODES: 'preset_modes'>: list([
'none',
@@ -674,6 +677,7 @@
'horizontal',
'both',
]),
<ClimateEntityCapabilityAttribute.TARGET_TEMP_STEP: 'target_temp_step'>: 1,
<ClimateEntityStateAttribute.TARGET_TEMPERATURE: 'temperature'>: 23,
}),
'context': <ANY>,
@@ -22,6 +22,9 @@ from homeassistant.components.climate import (
ATTR_SWING_MODE,
ATTR_TARGET_TEMP_HIGH,
ATTR_TARGET_TEMP_LOW,
ATTR_TARGET_TEMP_STEP,
DEFAULT_MAX_TEMP,
DEFAULT_MIN_TEMP,
DOMAIN as CLIMATE_DOMAIN,
PRESET_BOOST,
PRESET_NONE,
@@ -616,6 +619,35 @@ async def test_ac_state_attributes_update(
)
@pytest.mark.parametrize("device_fixture", ["da_ac_rac_000001"])
async def test_ac_setpoint_range_update(
hass: HomeAssistant,
devices: AsyncMock,
mock_config_entry: MockConfigEntry,
) -> None:
"""Test the setpoint range is used when the device reports one."""
await setup_integration(hass, mock_config_entry)
state = hass.states.get("climate.theater_ac_office_granit")
assert state.attributes[ATTR_MIN_TEMP] == DEFAULT_MIN_TEMP
assert state.attributes[ATTR_MAX_TEMP] == DEFAULT_MAX_TEMP
assert ATTR_TARGET_TEMP_STEP not in state.attributes
await trigger_update(
hass,
devices,
"96a5ef74-5832-a84b-f1f7-ca799957065d",
Capability.THERMOSTAT_COOLING_SETPOINT,
Attribute.COOLING_SETPOINT_RANGE,
{"minimum": 16, "maximum": 30, "step": 1},
)
state = hass.states.get("climate.theater_ac_office_granit")
assert state.attributes[ATTR_MIN_TEMP] == 16
assert state.attributes[ATTR_MAX_TEMP] == 30
assert state.attributes[ATTR_TARGET_TEMP_STEP] == 1
@pytest.mark.parametrize("device_fixture", ["virtual_thermostat"])
async def test_thermostat_set_fan_mode(
hass: HomeAssistant,