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:
kpine 2022-10-04 02:54:13 -07:00 committed by GitHub
parent 78f64ac3af
commit c040a7a152
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 46 additions and 21 deletions

View file

@ -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)

View file

@ -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