diff --git a/custom_components/dual_smart_thermostat/climate.py b/custom_components/dual_smart_thermostat/climate.py index b4bed9f..a6ed10f 100644 --- a/custom_components/dual_smart_thermostat/climate.py +++ b/custom_components/dual_smart_thermostat/climate.py @@ -579,7 +579,7 @@ async def _async_startup(*_) -> None: self.environment.set_default_target_temps( self.features.is_target_mode, self.features.is_range_mode, - self.hvac_device.hvac_modes, + self._hvac_mode, ) # restore previous preset mode if available @@ -612,7 +612,7 @@ async def _async_startup(*_) -> None: self.environment.set_default_target_temps( self.features.is_target_mode, self.features.is_range_mode, - self.hvac_device.hvac_modes, + self._hvac_mode, ) if self.environment.max_floor_temp is None: @@ -903,6 +903,17 @@ def _set_temperatures_dual_mode(self, temperatures: TargetTemperatures) -> None: elif self.features.is_range_mode: self.environment.set_temperature_range(temperature, temp_low, temp_high) + + # setting saved targets to current so while changing hvac mode + # other hvac modes can pick them up + if self.presets.preset_mode == PRESET_NONE: + self.environment.saved_target_temp_low = ( + self.environment.target_temp_low + ) + self.environment.saved_target_temp_high = ( + self.environment.target_temp_high + ) + self._target_temp = self.environment.target_temp self._target_temp_low = self.environment.target_temp_low self._target_temp_high = self.environment.target_temp_high diff --git a/custom_components/dual_smart_thermostat/managers/environment_manager.py b/custom_components/dual_smart_thermostat/managers/environment_manager.py index db1d58c..495b04b 100644 --- a/custom_components/dual_smart_thermostat/managers/environment_manager.py +++ b/custom_components/dual_smart_thermostat/managers/environment_manager.py @@ -159,6 +159,7 @@ def target_temp_low(self) -> float: @target_temp_low.setter def target_temp_low(self, temp: float) -> None: + _LOGGER.debug("Setting target temperature low: %s", temp) self._target_temp_low = temp @property @@ -187,7 +188,6 @@ def max_floor_temp(self) -> float: @max_floor_temp.setter def max_floor_temp(self, temp: float) -> None: - _LOGGER.debug("Setting max floor temp property: %s", temp) self._max_floor_temp = temp @property @@ -208,6 +208,7 @@ def saved_target_temp_low(self) -> float: @saved_target_temp_low.setter def saved_target_temp_low(self, temp: float) -> None: + _LOGGER.debug("Setting saved target temp low: %s", temp) self._saved_target_temp_low = temp @property @@ -277,8 +278,13 @@ def set_temperature_target(self, temperature: float) -> None: def set_temperature_range( self, temperature: float, temp_low: float, temp_high: float ) -> None: - # if temp_low is None or temp_high is None: - # return + + _LOGGER.debug( + "Setting target temperature range: %s, %s, %s", + temperature, + temp_low, + temp_high, + ) if temp_low is None: temp_low = temperature - PRECISION_WHOLE @@ -490,47 +496,66 @@ def set_default_target_humidity(self) -> None: self._target_humidity = 50 def set_default_target_temps( - self, is_target_mode: bool, is_range_mode: bool, hvac_modes: list[HVACMode] + self, is_target_mode: bool, is_range_mode: bool, hvac_mode: HVACMode ) -> None: """Set default values for target temperatures.""" _LOGGER.debug( "Setting default target temperatures, target mode: %s, range mode: %s, hvac_mode: %s", is_target_mode, is_range_mode, - hvac_modes, + hvac_mode, ) if is_target_mode: - self._set_default_temps_target_mode(hvac_modes) + self._set_default_temps_target_mode(hvac_mode) elif is_range_mode: self._set_default_temps_range_mode() - def _set_default_temps_target_mode(self, hvac_modes: list[HVACMode]) -> None: - if self._target_temp is not None: - return + def _set_default_temps_target_mode(self, hvac_mode: HVACMode) -> None: - _LOGGER.info("Setting default target temperature target mode: %s", hvac_modes) + _LOGGER.info( + "Setting default target temperature target mode: %s, target_temp: %s", + hvac_mode, + self._target_temp, + ) + _LOGGER.debug( + "saved target temp low: %s, saved target temp high: %s", + self._saved_target_temp_low, + self._saved_target_temp_high, + ) - # if HVACMode.COOL in hvac_device.hvac_modes or hvac_mode == HVACMode.COOL: - if HVACMode.COOL in hvac_modes or HVACMode.FAN_ONLY in hvac_modes: - if self._target_temp_high is None: + if hvac_mode == HVACMode.COOL or hvac_mode == HVACMode.FAN_ONLY: + if self._saved_target_temp_high is None: + if self._target_temp is not None: + return self._target_temp = self.max_temp _LOGGER.warning( - "Undefined target temperature, falling back to %s", + "Undefined target high temperature, falling back to %s", self._target_temp, ) else: - self._target_temp = self._target_temp_high - return + _LOGGER.debug( + "Setting target temp to saved target temp high: %s", + self._saved_target_temp_high, + ) + self._target_temp = self._saved_target_temp_high + # return - if self._target_temp_low is None: - self._target_temp = self.min_temp - _LOGGER.warning( - "Undefined target temperature, falling back to %s", - self._target_temp, - ) - else: - self._target_temp = self._target_temp_low + if hvac_mode == HVACMode.HEAT: + if self._saved_target_temp_low is None: + if self._target_temp is not None: + return + self._target_temp = self.min_temp + _LOGGER.warning( + "Undefined target low temperature, falling back to %s", + self._target_temp, + ) + else: + _LOGGER.debug( + "Setting target temp to saved target temp low: %s", + self._saved_target_temp_low, + ) + self._target_temp = self._saved_target_temp_low def _set_default_temps_range_mode(self) -> None: if self._target_temp_low is not None and self._target_temp_high is not None: diff --git a/custom_components/dual_smart_thermostat/managers/feature_manager.py b/custom_components/dual_smart_thermostat/managers/feature_manager.py index b66fec2..5e193d1 100644 --- a/custom_components/dual_smart_thermostat/managers/feature_manager.py +++ b/custom_components/dual_smart_thermostat/managers/feature_manager.py @@ -214,7 +214,7 @@ def set_support_flags( self._supported_features, ) self.environment.set_default_target_temps( - self.is_target_mode, self.is_range_mode, hvac_modes + self.is_target_mode, self.is_range_mode, current_hvac_mode ) if self.is_configured_for_dryer_mode: diff --git a/custom_components/dual_smart_thermostat/managers/preset_manager.py b/custom_components/dual_smart_thermostat/managers/preset_manager.py index 3c2c585..8476df3 100644 --- a/custom_components/dual_smart_thermostat/managers/preset_manager.py +++ b/custom_components/dual_smart_thermostat/managers/preset_manager.py @@ -132,6 +132,12 @@ def set_preset_mode(self, preset_mode: str) -> None: def _set_presets_when_no_preset_mode(self): """Sets target environment when preset is none.""" _LOGGER.debug("Setting presets when no preset mode") + _LOGGER.debug( + "saved_target_temp_low: %s", self._environment.saved_target_temp_low + ) + _LOGGER.debug( + "saved_target_temp_high: %s", self._environment.saved_target_temp_high + ) self._preset_mode = PRESET_NONE if self._features.is_range_mode: self._environment.target_temp_low = self._environment.saved_target_temp_low diff --git a/tests/test_cooler_mode.py b/tests/test_cooler_mode.py index 92f14c0..7dca339 100644 --- a/tests/test_cooler_mode.py +++ b/tests/test_cooler_mode.py @@ -324,9 +324,9 @@ async def test_set_target_temp_ac_off( """Test if target temperature turn ac off.""" calls = setup_switch(hass, True) setup_sensor(hass, 25) - await hass.async_block_till_done() await common.async_set_temperature(hass, 30) - assert len(calls) == 2 + await hass.async_block_till_done() + assert len(calls) == 1 call = calls[0] assert call.domain == HASS_DOMAIN assert call.service == SERVICE_TURN_OFF diff --git a/tests/test_dual_mode.py b/tests/test_dual_mode.py index 1410617..3e02416 100644 --- a/tests/test_dual_mode.py +++ b/tests/test_dual_mode.py @@ -340,7 +340,7 @@ async def test_dual_default_setup_params( state = hass.states.get(common.ENTITY) assert state.attributes.get("min_temp") == 7 assert state.attributes.get("max_temp") == 35 - assert state.attributes.get("temperature") == 35 + assert state.attributes.get("temperature") == 7 async def test_heat_cool_default_setup_params( @@ -1094,6 +1094,8 @@ async def test_heat_cool_set_preset_mode_set_temp_keeps_preset_mode( test_target_temp_low = 3 test_target_temp_high = 33 await common.async_set_temperature(hass, 18, common.ENTITY, 22, 18) + await hass.async_block_till_done() + await common.async_set_preset_mode(hass, preset) state = hass.states.get(common.ENTITY) assert state.attributes.get("target_temp_low") == temp_low @@ -1110,6 +1112,7 @@ async def test_heat_cool_set_preset_mode_set_temp_keeps_preset_mode( assert state.attributes.get("target_temp_high") == test_target_temp_high assert state.attributes.get("preset_mode") == preset assert state.attributes.get("supported_features") == 402 + await common.async_set_preset_mode(hass, PRESET_NONE) state = hass.states.get(common.ENTITY) if preset == PRESET_NONE: @@ -1217,7 +1220,7 @@ async def test_heat_cool_fan_set_preset_mode_change_hvac_mode( state = hass.states.get(common.ENTITY) assert state.attributes.get("preset_mode") == preset - assert state.attributes.get("temperature") == 18 + assert state.attributes.get("temperature") == 22 assert state.attributes.get("target_temp_low") is None assert state.attributes.get("target_temp_high") is None @@ -1226,7 +1229,7 @@ async def test_heat_cool_fan_set_preset_mode_change_hvac_mode( state = hass.states.get(common.ENTITY) assert state.attributes.get("preset_mode") == preset - assert state.attributes.get("temperature") == 18 + assert state.attributes.get("temperature") == 22 assert state.attributes.get("target_temp_low") is None assert state.attributes.get("target_temp_high") is None @@ -2062,6 +2065,77 @@ async def test_hvac_mode_mode_heat_cool_hvac_modes_temps_avoid_unrealism( assert state.attributes["target_temp_high"] == 21 # temp_low + precision +async def test_hvac_mode_mode_heat_cool_hvac_modes_temps_picks_range_values( + hass: HomeAssistant, setup_comp_1 # noqa: F811 +): + """Test thermostat target tempreratures get from range mode + + when switched from heat-cool mode to heat or cool mode""" + + heater_switch = "input_boolean.heater" + cooler_switch = "input_boolean.cooler" + assert await async_setup_component( + hass, + input_boolean.DOMAIN, + {"input_boolean": {"heater": None, "cooler": None}}, + ) + + assert await async_setup_component( + hass, + input_number.DOMAIN, + { + "input_number": { + "temp": {"name": "test", "initial": 10, "min": 0, "max": 40, "step": 1} + } + }, + ) + + assert await async_setup_component( + hass, + CLIMATE, + { + "climate": { + "platform": DOMAIN, + "name": "test", + "cooler": cooler_switch, + "heater": heater_switch, + "heat_cool_mode": True, + "target_sensor": common.ENT_SENSOR, + } + }, + ) + await hass.async_block_till_done() + + state = hass.states.get(common.ENTITY) + assert state.attributes["supported_features"] == 386 + + assert hass.states.get(heater_switch).state == STATE_OFF + assert hass.states.get(cooler_switch).state == STATE_OFF + + await common.async_set_hvac_mode(hass, HVACMode.HEAT_COOL) + await common.async_set_temperature(hass, 18, ENTITY_MATCH_ALL, 25, 22) + await hass.async_block_till_done() + + state = hass.states.get(common.ENTITY) + assert state.attributes["target_temp_low"] == 22 + assert state.attributes["target_temp_high"] == 25 + assert state.attributes.get("temperature") is None + + # switch to heat only mode + await common.async_set_hvac_mode(hass, HVACMode.HEAT) + await hass.async_block_till_done() + + state = hass.states.get(common.ENTITY) + assert state.attributes.get("temperature") == 22 + + # switch to cool only mode + await common.async_set_hvac_mode(hass, HVACMode.COOL) + await hass.async_block_till_done() + + state = hass.states.get(common.ENTITY) + assert state.attributes.get("temperature") == 25 + + async def test_hvac_mode_heat_cool_floor_temp( hass: HomeAssistant, setup_comp_1 # noqa: F811 ): diff --git a/tests/test_fan_mode.py b/tests/test_fan_mode.py index 00f5dfc..772e61f 100644 --- a/tests/test_fan_mode.py +++ b/tests/test_fan_mode.py @@ -728,9 +728,9 @@ async def test_set_target_temp_fan_off( """Test if target temperature turn fan off.""" calls = setup_switch(hass, True) setup_sensor(hass, 25) - await hass.async_block_till_done() await common.async_set_temperature(hass, 30) - assert len(calls) == 2 + await hass.async_block_till_done() + assert len(calls) == 1 call = calls[0] assert call.domain == HASS_DOMAIN assert call.service == SERVICE_TURN_OFF @@ -782,8 +782,8 @@ async def test_set_target_temp_cooler_on( setup_sensor(hass, 30) # only turns on if in COOL mode await common.async_set_hvac_mode(hass, HVACMode.COOL) - await hass.async_block_till_done() await common.async_set_temperature(hass, 25) + await hass.async_block_till_done() assert len(calls) == 1 call = calls[0] assert call.domain == HASS_DOMAIN @@ -799,8 +799,8 @@ async def test_set_target_temp_cooler_fan_on( setup_sensor(hass, 30) # only turns on if in COOL mode await common.async_set_hvac_mode(hass, HVACMode.FAN_ONLY) - await hass.async_block_till_done() await common.async_set_temperature(hass, 25) + await hass.async_block_till_done() assert len(calls) == 1 call = calls[0] assert call.domain == HASS_DOMAIN @@ -2343,9 +2343,9 @@ async def test_set_target_temp_ac_fan_on( calls = setup_fan(hass, False) await common.async_set_hvac_mode(hass, HVACMode.FAN_ONLY) setup_sensor(hass, 30) + await common.async_set_temperature(hass, 25) await hass.async_block_till_done() - await common.async_set_temperature(hass, 25) assert len(calls) == 1 call = calls[0] assert call.domain == HASS_DOMAIN @@ -2360,9 +2360,9 @@ async def test_set_target_temp_ac_on_after_fan_tolerance( calls = setup_switch_dual(hass, common.ENT_FAN, False, False) await common.async_set_hvac_mode(hass, HVACMode.COOL) setup_sensor(hass, 26) + await common.async_set_temperature(hass, 21) await hass.async_block_till_done() - await common.async_set_temperature(hass, 21) assert len(calls) == 1 call = calls[0] assert call.domain == HASS_DOMAIN