Skip to content

Commit

Permalink
feat: "hot_tolerance" not woking as expected when in heat_cool mode
Browse files Browse the repository at this point in the history
enables the termostat to use the tolerancees both for heater and cooler when in heat_cool mode

Fixes #48
  • Loading branch information
= committed Jul 4, 2023
1 parent ea216f3 commit 9a7fed7
Show file tree
Hide file tree
Showing 5 changed files with 284 additions and 25 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/linting.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ jobs:
- name: Setup Python
uses: actions/setup-python@v1
with:
python-version: 3.9
python-version: 3.10.12

- name: Install dependencies
run: |
Expand Down
75 changes: 52 additions & 23 deletions custom_components/dual_smart_thermostat/climate.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@
HVACAction,
HVACMode,
PRESET_ANTI_FREEZE,
TOLERANCE_DEVICE,
)
from . import DOMAIN, PLATFORMS

Expand Down Expand Up @@ -874,16 +875,17 @@ async def _async_control_heat_cool(self, time=None, force=False):
if not self._needs_control(time, force, dual=True):
return

too_cold = self._is_too_cold("_target_temp_low")
too_hot = self._is_too_hot("_target_temp_high")
too_cold, too_hot, tolerance_device = self._is_cold_or_hot()

if self._is_opening_open:
await self._async_heater_turn_off()
await self._async_cooler_turn_off()
elif self._is_floor_hot:
await self._async_heater_turn_off()
else:
await self.async_heater_cooler_toggle(too_cold, too_hot)
await self.async_heater_cooler_toggle(
tolerance_device, too_cold, too_hot
)

if time is not None:
# The time argument is passed only in keep-alive case
Expand All @@ -892,10 +894,35 @@ async def _async_control_heat_cool(self, time=None, force=False):
self.heater_entity_id,
self.cooler_entity_id,
)
await self.async_heater_cooler_toggle(too_cold, too_hot)
await self.async_heater_cooler_toggle(
tolerance_device, too_cold, too_hot
)

async def async_heater_cooler_toggle(self, tolerance_device, too_cold, too_hot):
"""Toggle heater cooler based on temp and tolarance."""
match tolerance_device:
case TOLERANCE_DEVICE.HEATER:
await self._async_heater_toggle(too_cold, too_hot)
case TOLERANCE_DEVICE.COOLER:
await self._async_cooler_toggle(too_cold, too_hot)
case _:
await self._async_auto_toggle(too_cold, too_hot)

async def _async_heater_toggle(self, too_cold, too_hot):
"""Toggle heater based on temp."""
if too_cold:
await self._async_heater_turn_on()
elif too_hot:
await self._async_heater_turn_off()

async def async_heater_cooler_toggle(self, too_cold, too_hot):
"""Toggle heater cooler based on device state"""
async def _async_cooler_toggle(self, too_cold, too_hot):
"""Toggle cooler based on temp."""
if too_cold:
await self._async_cooler_turn_off()
elif too_hot:
await self._async_cooler_turn_on()

async def _async_auto_toggle(self, too_cold, too_hot):
if too_cold:
if not self._is_opening_open:
await self._async_heater_turn_on()
Expand All @@ -914,7 +941,6 @@ def _is_opening_open(self):
_is_open = False
if self.opening_entities:
for opening in self.opening_entities:

if self.hass.states.is_state(
opening, STATE_OPEN
) or self.hass.states.is_state(opening, STATE_ON):
Expand Down Expand Up @@ -965,33 +991,21 @@ def supported_features(self):

async def _async_heater_turn_on(self):
"""Turn heater toggleable device on."""
data = {ATTR_ENTITY_ID: self.heater_entity_id}
await self.hass.services.async_call(
HA_DOMAIN, SERVICE_TURN_ON, data, context=self._context
)
await self._async_switch_turn_on(self.heater_entity_id)

async def _async_heater_turn_off(self):
"""Turn heater toggleable device off."""
data = {ATTR_ENTITY_ID: self.heater_entity_id}
await self.hass.services.async_call(
HA_DOMAIN, SERVICE_TURN_OFF, data, context=self._context
)
await self._async_switch_turn_off(self.heater_entity_id)

async def _async_cooler_turn_on(self):
"""Turn cooler toggleable device on."""
if self.cooler_entity_id is not None and not self._is_cooler_active:
data = {ATTR_ENTITY_ID: self.cooler_entity_id}
await self.hass.services.async_call(
HA_DOMAIN, SERVICE_TURN_ON, data, context=self._context
)
await self._async_switch_turn_on(self.cooler_entity_id)

async def _async_cooler_turn_off(self):
"""Turn cooler toggleable device off."""
if self.cooler_entity_id is not None and self._is_cooler_active:
data = {ATTR_ENTITY_ID: self.cooler_entity_id}
await self.hass.services.async_call(
HA_DOMAIN, SERVICE_TURN_OFF, data, context=self._context
)
await self._async_switch_turn_off(self.cooler_entity_id)

async def _async_switch_turn_off(self, entity_id):
"""Turn toggleable device off."""
Expand Down Expand Up @@ -1086,6 +1100,21 @@ def _is_too_hot(self, target_attr="_target_temp") -> bool:
target_temp = getattr(self, target_attr)
return self._cur_temp >= target_temp + self._hot_tolerance

def _is_cold_or_hot(self):
if self._is_heater_active:
too_cold = self._is_too_cold("_target_temp_low")
too_hot = self._is_too_hot("_target_temp_low")
tolerance_device = TOLERANCE_DEVICE.HEATER
elif self._is_cooler_active:
too_cold = self._is_too_cold("_target_temp_high")
too_hot = self._is_too_hot("_target_temp_high")
tolerance_device = TOLERANCE_DEVICE.COOLER
else:
too_cold = self._is_too_cold("_target_temp_low")
too_hot = self._is_too_hot("_target_temp_high")
tolerance_device = TOLERANCE_DEVICE.AUTO
return too_cold, too_hot, tolerance_device

def _is_configured_for_heat_cool(self) -> bool:
"""checks if the configuration is complete for heat/cool mode"""
return self._heat_cool_mode or (
Expand Down
8 changes: 8 additions & 0 deletions custom_components/dual_smart_thermostat/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,3 +66,11 @@ class HVACAction(StrEnum):
HEATING = "heating"
IDLE = "idle"
OFF = "off"


class TOLERANCE_DEVICE(StrEnum):
"""Tolerance device for climate devices."""

HEATER = "heater"
COOLER = "cooler"
AUTO = "auto"
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,4 @@ voluptuous-serialize==2.5.0
yarl==1.7.2
pre-commit
isort
black==22.1.0
black
Loading

0 comments on commit 9a7fed7

Please sign in to comment.