Skip to content

Commit

Permalink
Use integration fallback configuration for tado water heater fallback (
Browse files Browse the repository at this point in the history
…#111014)

* 103619 tado water heater fallback

* extracted a method to remove code duplication

* test cases and suggested changes

* tests

* util method for connector

* Update homeassistant/components/tado/climate.py

Co-authored-by: Andriy Kushnir <me@orhideous.name>

* missing import after applies suggestion

* early return

* simplify if statements

* simplify pr

* pr requested changes

* better docstring

---------

Co-authored-by: Andriy Kushnir <me@orhideous.name>
  • Loading branch information
ethemcemozkan and Orhideous committed May 14, 2024
1 parent ad6e6a1 commit b684801
Show file tree
Hide file tree
Showing 4 changed files with 98 additions and 25 deletions.
26 changes: 7 additions & 19 deletions homeassistant/components/tado/climate.py
Expand Up @@ -36,8 +36,6 @@
CONST_MODE_OFF,
CONST_MODE_SMART_SCHEDULE,
CONST_OVERLAY_MANUAL,
CONST_OVERLAY_TADO_DEFAULT,
CONST_OVERLAY_TADO_MODE,
CONST_OVERLAY_TADO_OPTIONS,
CONST_OVERLAY_TIMER,
DATA,
Expand Down Expand Up @@ -67,6 +65,7 @@
TYPE_HEATING,
)
from .entity import TadoZoneEntity
from .helper import decide_overlay_mode

_LOGGER = logging.getLogger(__name__)

Expand Down Expand Up @@ -598,23 +597,12 @@ def _control_hvac(
self._tado.reset_zone_overlay(self.zone_id)
return

# If user gave duration then overlay mode needs to be timer
if duration:
overlay_mode = CONST_OVERLAY_TIMER
# If no duration or timer set to fallback setting
if overlay_mode is None:
overlay_mode = (
self._tado.fallback
if self._tado.fallback is not None
else CONST_OVERLAY_TADO_MODE
)
# If default is Tado default then look it up
if overlay_mode == CONST_OVERLAY_TADO_DEFAULT:
overlay_mode = (
self._tado_zone_data.default_overlay_termination_type
if self._tado_zone_data.default_overlay_termination_type is not None
else CONST_OVERLAY_TADO_MODE
)
overlay_mode = decide_overlay_mode(
tado=self._tado,
duration=duration,
overlay_mode=overlay_mode,
zone_id=self.zone_id,
)
# If we ended up with a timer but no duration, set a default duration
if overlay_mode == CONST_OVERLAY_TIMER and duration is None:
duration = (
Expand Down
31 changes: 31 additions & 0 deletions homeassistant/components/tado/helper.py
@@ -0,0 +1,31 @@
"""Helper methods for Tado."""

from . import TadoConnector
from .const import (
CONST_OVERLAY_TADO_DEFAULT,
CONST_OVERLAY_TADO_MODE,
CONST_OVERLAY_TIMER,
)


def decide_overlay_mode(
tado: TadoConnector,
duration: int | None,
zone_id: int,
overlay_mode: str | None = None,
) -> str:
"""Return correct overlay mode based on the action and defaults."""
# If user gave duration then overlay mode needs to be timer
if duration:
return CONST_OVERLAY_TIMER
# If no duration or timer set to fallback setting
if overlay_mode is None:
overlay_mode = tado.fallback or CONST_OVERLAY_TADO_MODE
# If default is Tado default then look it up
if overlay_mode == CONST_OVERLAY_TADO_DEFAULT:
overlay_mode = (
tado.data["zone"][zone_id].default_overlay_termination_type
or CONST_OVERLAY_TADO_MODE
)

return overlay_mode
12 changes: 6 additions & 6 deletions homeassistant/components/tado/water_heater.py
Expand Up @@ -32,6 +32,7 @@
TYPE_HOT_WATER,
)
from .entity import TadoZoneEntity
from .helper import decide_overlay_mode

_LOGGER = logging.getLogger(__name__)

Expand Down Expand Up @@ -277,12 +278,11 @@ def _control_heater(
self._tado.set_zone_off(self.zone_id, CONST_OVERLAY_MANUAL, TYPE_HOT_WATER)
return

overlay_mode = CONST_OVERLAY_MANUAL
if duration:
overlay_mode = CONST_OVERLAY_TIMER
elif self._tado.fallback:
# Fallback to Smart Schedule at next Schedule switch if we have fallback enabled
overlay_mode = CONST_OVERLAY_TADO_MODE
overlay_mode = decide_overlay_mode(
tado=self._tado,
duration=duration,
zone_id=self.zone_id,
)

_LOGGER.debug(
"Switching to %s for zone %s (%d) with temperature %s",
Expand Down
54 changes: 54 additions & 0 deletions tests/components/tado/test_helper.py
@@ -0,0 +1,54 @@
"""Helper method tests."""

from unittest.mock import patch

from homeassistant.components.tado import TadoConnector
from homeassistant.components.tado.const import (
CONST_OVERLAY_MANUAL,
CONST_OVERLAY_TADO_DEFAULT,
CONST_OVERLAY_TADO_MODE,
CONST_OVERLAY_TIMER,
)
from homeassistant.components.tado.helper import decide_overlay_mode
from homeassistant.core import HomeAssistant


def dummy_tado_connector(hass: HomeAssistant, fallback) -> TadoConnector:
"""Return dummy tado connector."""
return TadoConnector(hass, username="dummy", password="dummy", fallback=fallback)


async def test_overlay_mode_duration_set(hass: HomeAssistant) -> None:
"""Test overlay method selection when duration is set."""
tado = dummy_tado_connector(hass=hass, fallback=CONST_OVERLAY_TADO_MODE)
overlay_mode = decide_overlay_mode(tado=tado, duration="01:00:00", zone_id=1)
# Must select TIMER overlay
assert overlay_mode == CONST_OVERLAY_TIMER


async def test_overlay_mode_next_time_block_fallback(hass: HomeAssistant) -> None:
"""Test overlay method selection when duration is not set."""
integration_fallback = CONST_OVERLAY_TADO_MODE
tado = dummy_tado_connector(hass=hass, fallback=integration_fallback)
overlay_mode = decide_overlay_mode(tado=tado, duration=None, zone_id=1)
# Must fallback to integration wide setting
assert overlay_mode == integration_fallback


async def test_overlay_mode_tado_default_fallback(hass: HomeAssistant) -> None:
"""Test overlay method selection when tado default is selected."""
integration_fallback = CONST_OVERLAY_TADO_DEFAULT
zone_fallback = CONST_OVERLAY_MANUAL
tado = dummy_tado_connector(hass=hass, fallback=integration_fallback)

class MockZoneData:
def __init__(self) -> None:
self.default_overlay_termination_type = zone_fallback

zone_id = 1

zone_data = {"zone": {zone_id: MockZoneData()}}
with patch.dict(tado.data, zone_data):
overlay_mode = decide_overlay_mode(tado=tado, duration=None, zone_id=zone_id)
# Must fallback to zone setting
assert overlay_mode == zone_fallback

0 comments on commit b684801

Please sign in to comment.