Set zwave_js climate entity target temp attributes based on current mode (#79575)
* Report temperature correctly * DRY * Add test assertions * Don't catch TypeError (revert)
This commit is contained in:
parent
78f64ac3af
commit
c040a7a152
2 changed files with 46 additions and 21 deletions
|
@ -201,13 +201,25 @@ class ZWaveClimate(ZWaveBaseEntity, ClimateEntity):
|
||||||
if self._fan_mode:
|
if self._fan_mode:
|
||||||
self._attr_supported_features |= ClimateEntityFeature.FAN_MODE
|
self._attr_supported_features |= ClimateEntityFeature.FAN_MODE
|
||||||
|
|
||||||
def _setpoint_value(self, setpoint_type: ThermostatSetpointType) -> ZwaveValue:
|
def _setpoint_value_or_raise(
|
||||||
"""Optionally return a ZwaveValue for a setpoint."""
|
self, setpoint_type: ThermostatSetpointType
|
||||||
|
) -> ZwaveValue:
|
||||||
|
"""Return a ZwaveValue for a setpoint or raise if not available."""
|
||||||
if (val := self._setpoint_values[setpoint_type]) is None:
|
if (val := self._setpoint_values[setpoint_type]) is None:
|
||||||
raise ValueError("Value requested is not available")
|
raise ValueError("Value requested is not available")
|
||||||
|
|
||||||
return val
|
return val
|
||||||
|
|
||||||
|
def _setpoint_temperature(
|
||||||
|
self, setpoint_type: ThermostatSetpointType
|
||||||
|
) -> float | None:
|
||||||
|
"""Optionally return the temperature value of a setpoint."""
|
||||||
|
try:
|
||||||
|
temp = self._setpoint_value_or_raise(setpoint_type)
|
||||||
|
except (IndexError, ValueError):
|
||||||
|
return None
|
||||||
|
return get_value_of_zwave_value(temp)
|
||||||
|
|
||||||
def _set_modes_and_presets(self) -> None:
|
def _set_modes_and_presets(self) -> None:
|
||||||
"""Convert Z-Wave Thermostat modes into Home Assistant modes and presets."""
|
"""Convert Z-Wave Thermostat modes into Home Assistant modes and presets."""
|
||||||
all_modes: dict[HVACMode, int | None] = {}
|
all_modes: dict[HVACMode, int | None] = {}
|
||||||
|
@ -290,36 +302,44 @@ class ZWaveClimate(ZWaveBaseEntity, ClimateEntity):
|
||||||
@property
|
@property
|
||||||
def target_temperature(self) -> float | None:
|
def target_temperature(self) -> float | None:
|
||||||
"""Return the temperature we try to reach."""
|
"""Return the temperature we try to reach."""
|
||||||
if self._current_mode and self._current_mode.value is None:
|
if (
|
||||||
|
self._current_mode and self._current_mode.value is None
|
||||||
|
) or not self._current_mode_setpoint_enums:
|
||||||
# guard missing value
|
# guard missing value
|
||||||
return None
|
return None
|
||||||
try:
|
if len(self._current_mode_setpoint_enums) > 1:
|
||||||
temp = self._setpoint_value(self._current_mode_setpoint_enums[0])
|
# current mode has a temperature range
|
||||||
except (IndexError, ValueError):
|
|
||||||
return None
|
return None
|
||||||
return get_value_of_zwave_value(temp)
|
|
||||||
|
return self._setpoint_temperature(self._current_mode_setpoint_enums[0])
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def target_temperature_high(self) -> float | None:
|
def target_temperature_high(self) -> float | None:
|
||||||
"""Return the highbound target temperature we try to reach."""
|
"""Return the highbound target temperature we try to reach."""
|
||||||
if self._current_mode and self._current_mode.value is None:
|
if (
|
||||||
|
self._current_mode and self._current_mode.value is None
|
||||||
|
) or not self._current_mode_setpoint_enums:
|
||||||
# guard missing value
|
# guard missing value
|
||||||
return None
|
return None
|
||||||
try:
|
if len(self._current_mode_setpoint_enums) < 2:
|
||||||
temp = self._setpoint_value(self._current_mode_setpoint_enums[1])
|
# current mode has a single temperature
|
||||||
except (IndexError, ValueError):
|
|
||||||
return None
|
return None
|
||||||
return get_value_of_zwave_value(temp)
|
|
||||||
|
return self._setpoint_temperature(self._current_mode_setpoint_enums[1])
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def target_temperature_low(self) -> float | None:
|
def target_temperature_low(self) -> float | None:
|
||||||
"""Return the lowbound target temperature we try to reach."""
|
"""Return the lowbound target temperature we try to reach."""
|
||||||
if self._current_mode and self._current_mode.value is None:
|
if (
|
||||||
|
self._current_mode and self._current_mode.value is None
|
||||||
|
) or not self._current_mode_setpoint_enums:
|
||||||
# guard missing value
|
# guard missing value
|
||||||
return None
|
return None
|
||||||
if len(self._current_mode_setpoint_enums) > 1:
|
if len(self._current_mode_setpoint_enums) < 2:
|
||||||
return self.target_temperature
|
# current mode has a single temperature
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
return self._setpoint_temperature(self._current_mode_setpoint_enums[0])
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def preset_mode(self) -> str | None:
|
def preset_mode(self) -> str | None:
|
||||||
|
@ -380,7 +400,7 @@ class ZWaveClimate(ZWaveBaseEntity, ClimateEntity):
|
||||||
min_temp = DEFAULT_MIN_TEMP
|
min_temp = DEFAULT_MIN_TEMP
|
||||||
base_unit = TEMP_CELSIUS
|
base_unit = TEMP_CELSIUS
|
||||||
try:
|
try:
|
||||||
temp = self._setpoint_value(self._current_mode_setpoint_enums[0])
|
temp = self._setpoint_value_or_raise(self._current_mode_setpoint_enums[0])
|
||||||
if temp.metadata.min:
|
if temp.metadata.min:
|
||||||
min_temp = temp.metadata.min
|
min_temp = temp.metadata.min
|
||||||
base_unit = self.temperature_unit
|
base_unit = self.temperature_unit
|
||||||
|
@ -396,7 +416,7 @@ class ZWaveClimate(ZWaveBaseEntity, ClimateEntity):
|
||||||
max_temp = DEFAULT_MAX_TEMP
|
max_temp = DEFAULT_MAX_TEMP
|
||||||
base_unit = TEMP_CELSIUS
|
base_unit = TEMP_CELSIUS
|
||||||
try:
|
try:
|
||||||
temp = self._setpoint_value(self._current_mode_setpoint_enums[0])
|
temp = self._setpoint_value_or_raise(self._current_mode_setpoint_enums[0])
|
||||||
if temp.metadata.max:
|
if temp.metadata.max:
|
||||||
max_temp = temp.metadata.max
|
max_temp = temp.metadata.max
|
||||||
base_unit = self.temperature_unit
|
base_unit = self.temperature_unit
|
||||||
|
@ -431,17 +451,17 @@ class ZWaveClimate(ZWaveBaseEntity, ClimateEntity):
|
||||||
if hvac_mode is not None:
|
if hvac_mode is not None:
|
||||||
await self.async_set_hvac_mode(hvac_mode)
|
await self.async_set_hvac_mode(hvac_mode)
|
||||||
if len(self._current_mode_setpoint_enums) == 1:
|
if len(self._current_mode_setpoint_enums) == 1:
|
||||||
setpoint: ZwaveValue = self._setpoint_value(
|
setpoint: ZwaveValue = self._setpoint_value_or_raise(
|
||||||
self._current_mode_setpoint_enums[0]
|
self._current_mode_setpoint_enums[0]
|
||||||
)
|
)
|
||||||
target_temp: float | None = kwargs.get(ATTR_TEMPERATURE)
|
target_temp: float | None = kwargs.get(ATTR_TEMPERATURE)
|
||||||
if target_temp is not None:
|
if target_temp is not None:
|
||||||
await self.info.node.async_set_value(setpoint, target_temp)
|
await self.info.node.async_set_value(setpoint, target_temp)
|
||||||
elif len(self._current_mode_setpoint_enums) == 2:
|
elif len(self._current_mode_setpoint_enums) == 2:
|
||||||
setpoint_low: ZwaveValue = self._setpoint_value(
|
setpoint_low: ZwaveValue = self._setpoint_value_or_raise(
|
||||||
self._current_mode_setpoint_enums[0]
|
self._current_mode_setpoint_enums[0]
|
||||||
)
|
)
|
||||||
setpoint_high: ZwaveValue = self._setpoint_value(
|
setpoint_high: ZwaveValue = self._setpoint_value_or_raise(
|
||||||
self._current_mode_setpoint_enums[1]
|
self._current_mode_setpoint_enums[1]
|
||||||
)
|
)
|
||||||
target_temp_low: float | None = kwargs.get(ATTR_TARGET_TEMP_LOW)
|
target_temp_low: float | None = kwargs.get(ATTR_TARGET_TEMP_LOW)
|
||||||
|
|
|
@ -65,6 +65,8 @@ async def test_thermostat_v2(
|
||||||
assert state.attributes[ATTR_CURRENT_HUMIDITY] == 30
|
assert state.attributes[ATTR_CURRENT_HUMIDITY] == 30
|
||||||
assert state.attributes[ATTR_CURRENT_TEMPERATURE] == 22.2
|
assert state.attributes[ATTR_CURRENT_TEMPERATURE] == 22.2
|
||||||
assert state.attributes[ATTR_TEMPERATURE] == 22.2
|
assert state.attributes[ATTR_TEMPERATURE] == 22.2
|
||||||
|
assert state.attributes[ATTR_TARGET_TEMP_HIGH] is None
|
||||||
|
assert state.attributes[ATTR_TARGET_TEMP_LOW] is None
|
||||||
assert state.attributes[ATTR_HVAC_ACTION] == HVACAction.IDLE
|
assert state.attributes[ATTR_HVAC_ACTION] == HVACAction.IDLE
|
||||||
assert state.attributes[ATTR_FAN_MODE] == "Auto low"
|
assert state.attributes[ATTR_FAN_MODE] == "Auto low"
|
||||||
assert state.attributes[ATTR_FAN_STATE] == "Idle / off"
|
assert state.attributes[ATTR_FAN_STATE] == "Idle / off"
|
||||||
|
@ -159,6 +161,8 @@ async def test_thermostat_v2(
|
||||||
state = hass.states.get(CLIMATE_RADIO_THERMOSTAT_ENTITY)
|
state = hass.states.get(CLIMATE_RADIO_THERMOSTAT_ENTITY)
|
||||||
assert state.state == HVACMode.COOL
|
assert state.state == HVACMode.COOL
|
||||||
assert state.attributes[ATTR_TEMPERATURE] == 22.8
|
assert state.attributes[ATTR_TEMPERATURE] == 22.8
|
||||||
|
assert state.attributes[ATTR_TARGET_TEMP_HIGH] is None
|
||||||
|
assert state.attributes[ATTR_TARGET_TEMP_LOW] is None
|
||||||
|
|
||||||
# Test heat_cool mode update from value updated event
|
# Test heat_cool mode update from value updated event
|
||||||
event = Event(
|
event = Event(
|
||||||
|
@ -182,6 +186,7 @@ async def test_thermostat_v2(
|
||||||
|
|
||||||
state = hass.states.get(CLIMATE_RADIO_THERMOSTAT_ENTITY)
|
state = hass.states.get(CLIMATE_RADIO_THERMOSTAT_ENTITY)
|
||||||
assert state.state == HVACMode.HEAT_COOL
|
assert state.state == HVACMode.HEAT_COOL
|
||||||
|
assert state.attributes[ATTR_TEMPERATURE] is None
|
||||||
assert state.attributes[ATTR_TARGET_TEMP_HIGH] == 22.8
|
assert state.attributes[ATTR_TARGET_TEMP_HIGH] == 22.8
|
||||||
assert state.attributes[ATTR_TARGET_TEMP_LOW] == 22.2
|
assert state.attributes[ATTR_TARGET_TEMP_LOW] == 22.2
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue