Skip to content

Commit

Permalink
fix: hat and cool mode not workin in dual mode
Browse files Browse the repository at this point in the history
Fixes #150
  • Loading branch information
= authored and swingerman committed Apr 16, 2024
1 parent ec64006 commit c6548c3
Show file tree
Hide file tree
Showing 6 changed files with 345 additions and 22 deletions.
17 changes: 15 additions & 2 deletions config/configuration.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -166,8 +166,8 @@ climate:
precision: 0.1

- platform: dual_smart_thermostat
name: Edge Case 1
unique_id: edge_case_1
name: Edge Case 80
unique_id: edge_case_80
heater: switch.heater
cooler: switch.cooler
target_sensor: sensor.room_temp
Expand All @@ -180,6 +180,19 @@ climate:
target_temp_low: 0
target_temp_high: 50

- platform: dual_smart_thermostat
name: Edge Case 150
unique_id: edge_case_150
heater: switch.heater
cooler: switch.cooler
target_sensor: sensor.room_temp
min_cycle_duration: 60
precision: 1.0
min_temp: 58
max_temp: 80
cold_tolerance: 1.0,
hot_tolerance: 1.0,


- platform: dual_smart_thermostat
name: AUX Heat Room
Expand Down
37 changes: 30 additions & 7 deletions custom_components/dual_smart_thermostat/climate.py
Original file line number Diff line number Diff line change
Expand Up @@ -633,6 +633,7 @@ def _set_support_flags(self) -> None:
self.presets.presets,
self.hvac_device.hvac_modes,
self.presets.presets_range,
self._hvac_mode,
)
self._attr_supported_features = self.features.supported_features
_LOGGER.debug("Supported features: %s", self._attr_supported_features)
Expand All @@ -647,6 +648,7 @@ async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None:

await self.hvac_device.async_set_hvac_mode(hvac_mode)
self._hvac_mode = hvac_mode
self._set_support_flags()

self._HVACActionReason = self.hvac_device.HVACActionReason

Expand All @@ -663,18 +665,39 @@ async def async_set_temperature(self, **kwargs) -> None:
_LOGGER.debug("Setting temperature low: %s", temp_low)
_LOGGER.debug("Setting temperature high: %s", temp_high)

if self.features.is_target_mode:
if self.features.is_configured_for_heat_cool_mode:
if self.features.is_target_mode:
if temperature is None:
return
self.temperatures.set_temperature_target(temperature)
self._target_temp = self.temperatures.target_temp

if self.hvac_device.hvac_mode == HVACMode.HEAT:
self.temperatures.set_temperature_range(
temperature, temperature, self.temperatures.target_temp_high
)
self._target_temp_low = self.temperatures.target_temp_low

else:
self.temperatures.set_temperature_range(
temperature, self.temperatures.target_temp_low, temperature
)
self._target_temp_high = self.temperatures.target_temp_high

elif self.features.is_range_mode:
self.temperatures.set_temperature_range(
temperature, temp_low, temp_high
)
self._target_temp = self.temperatures.target_temp
self._target_temp_low = self.temperatures.target_temp_low
self._target_temp_high = self.temperatures.target_temp_high

else:
if temperature is None:
return
self.temperatures.set_temperature_target(temperature)
self._target_temp = self.temperatures.target_temp

elif self.features.is_range_mode:
self.temperatures.set_temperature_range(temperature, temp_low, temp_high)
self._target_temp = self.temperatures.target_temp
self._target_temp_low = self.temperatures.target_temp_low
self._target_temp_high = self.temperatures.target_temp_high

await self._async_control_climate(force=True)
self.async_write_ha_state()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,39 @@ def is_cold_or_hot(self) -> tuple[bool, bool, ToleranceDevice]:
tolerance_device = ToleranceDevice.AUTO
return too_cold, too_hot, tolerance_device

async def async_set_hvac_mode(self, hvac_mode: HVACMode):
_LOGGER.info("Setting hvac mode to %s of %s", hvac_mode, self.hvac_modes)
if hvac_mode in self.hvac_modes:
_LOGGER.debug("hvac mode found")
self._hvac_mode = hvac_mode

if hvac_mode is not HVACMode.OFF:
# handles HVACmode.HEAT
if hvac_mode in self.heater_device.hvac_modes:
self.heater_device.hvac_mode = hvac_mode
elif hvac_mode == HVACMode.HEAT_COOL:
self.heater_device.hvac_mode = HVACMode.HEAT
# handles HVACmode.COOL
if hvac_mode in self.cooler_device.hvac_modes:
self.cooler_device.hvac_mode = hvac_mode
elif hvac_mode == HVACMode.HEAT_COOL:
self.cooler_device.hvac_mode = HVACMode.COOL
else:
self.heater_device.hvac_mode = hvac_mode
self.cooler_device.hvac_mode = hvac_mode

else:
_LOGGER.debug("Hvac mode %s is not in %s", hvac_mode, self.hvac_modes)
self._hvac_mode = HVACMode.OFF

if self._hvac_mode == HVACMode.OFF:
await self.async_turn_off()
self._HVACActionReason = HVACActionReason.NONE
else:
await self.async_control_hvac(self, force=True)

_LOGGER.info("Hvac mode set to %s", self._hvac_mode)

async def _async_control_heat_cool(self, time=None, force=False) -> None:
"""Check if we need to turn heating on or off."""

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
)
from homeassistant.core import DOMAIN as HA_DOMAIN, Context, HomeAssistant
from homeassistant.helpers import condition
import homeassistant.util.dt as dt_util

from custom_components.dual_smart_thermostat.hvac_action_reason.hvac_action_reason import (
HVACActionReason,
Expand Down Expand Up @@ -92,13 +93,18 @@ def is_active(self) -> bool:
return True
return False

@property
# @property
def _ran_long_enough(self) -> bool:
if self.is_active:
current_state = STATE_ON
else:
current_state = HVACMode.OFF

_LOGGER.info("Checking if device ran long enough: %s", self.entity_id)
_LOGGER.info("current_state: %s", current_state)
_LOGGER.info("min_cycle_duration: %s", self.min_cycle_duration)
_LOGGER.info("time: %s", dt_util.utcnow())

long_enough = condition.state(
self.hass,
self.entity_id,
Expand Down Expand Up @@ -143,9 +149,16 @@ def _needs_control(self, time=None, force=False) -> bool:
# If the `time` argument is not none, we were invoked for
# keep-alive purposes, and `min_cycle_duration` is irrelevant.
if self.min_cycle_duration:
return self._ran_long_enough
_LOGGER.debug(
"Checking if device ran long enough: %s", self._ran_long_enough()
)
return self._ran_long_enough()
return True

# def needs_cycle(self) -> bool:
# """Determines if the device needs to cycle."""
# return self._ran_long_enough

async def async_control_hvac(self, time=None, force=False):
"""Controls the HVAC of the device."""

Expand Down Expand Up @@ -177,6 +190,7 @@ async def async_control_hvac(self, time=None, force=False):
await self._async_control_when_inactive(time)

async def _async_control_when_active(self, time=None) -> None:
_LOGGER.debug("%s _async_control_when_active", self.__class__.__name__)
too_cold = self.temperatures.is_too_cold(self._target_temp_attr)
any_opening_open = self.openings.any_opening_open

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,12 @@
from homeassistant.helpers.typing import ConfigType

from custom_components.dual_smart_thermostat.const import (
CONF_AC_MODE,
CONF_AUX_HEATER,
CONF_AUX_HEATING_TIMEOUT,
CONF_COOLER,
CONF_HEAT_COOL_MODE,
CONF_HEATER,
)
from custom_components.dual_smart_thermostat.managers.state_manager import StateManager
from custom_components.dual_smart_thermostat.managers.temperature_manager import (
Expand All @@ -31,6 +34,9 @@ def __init__(
self.hass = hass
self.temperatures = temperatures
self._supported_features = 0
self._cooler_entity_id = config.get(CONF_COOLER)
self._heater_entity_id = config.get(CONF_HEATER)
self._ac_mode = config.get(CONF_AC_MODE)

self._aux_heater_entity_id = config.get(CONF_AUX_HEATER)
self._aux_heater_timeout = config.get(CONF_AUX_HEATING_TIMEOUT)
Expand Down Expand Up @@ -63,9 +69,16 @@ def is_range_mode(self) -> bool:
@property
def is_configured_for_heat_cool_mode(self) -> bool:
"""Checks if the configuration is complete for heat/cool mode."""
return self._heat_cool_mode or (
self.temperatures.target_temp_high is not None
and self.temperatures.target_temp_low is not None
return (
self._heat_cool_mode
or (
self.temperatures.target_temp_high is not None
and self.temperatures.target_temp_low is not None
)
or (
self._heater_entity_id is not None
and self._cooler_entity_id is not None
)
)

@property
Expand All @@ -80,7 +93,11 @@ def _is_configured_for_aux_heating_mode(self) -> bool:
return True

def set_support_flags(
self, presets: dict[str, Any], hvac_modes: list[HVACMode], presets_range
self,
presets: dict[str, Any],
hvac_modes: list[HVACMode],
presets_range,
current_hvac_mode: HVACMode = None,
) -> None:
"""Set the correct support flags based on configuration."""
_LOGGER.debug("Setting support flags")
Expand All @@ -104,10 +121,24 @@ def set_support_flags(
else:
if self.is_target_mode and preset_mode != PRESET_NONE:
self.temperatures.target_temp = self.temperatures.saved_target_temp
self._supported_features = (
self._default_support_flags
| ClimateEntityFeature.TARGET_TEMPERATURE_RANGE
)

if current_hvac_mode not in [None, HVACMode.OFF, HVACMode.HEAT_COOL]:
self._supported_features = (
self._default_support_flags
| ClimateEntityFeature.TARGET_TEMPERATURE
)

if current_hvac_mode == HVACMode.HEAT:
self.temperatures.target_temp = self.temperatures.target_temp_low

else: # can be COOL, FAN_ONLY
self.temperatures.target_temp = self.temperatures.target_temp_high

else:
self._supported_features = (
self._default_support_flags
| ClimateEntityFeature.TARGET_TEMPERATURE_RANGE
)
_LOGGER.debug("Setting support flags to %s", self._supported_features)
if len(presets_range):
self._supported_features |= ClimateEntityFeature.PRESET_MODE
Expand Down
Loading

0 comments on commit c6548c3

Please sign in to comment.