mirror of
https://github.com/home-assistant/core.git
synced 2025-07-25 14:17:45 +00:00
Move Tado zone state handling into upstream python-tado library (#33195)
* Tado climate state moved to python-tado * Resolve various incorrect states and add tests for known tado zone states * Write state instead of calling for an update This is a redux of pr #32564 with all of the zone state now moved into python-tado and tests added for the various states. * stale string * add missing undos to dispachers * remove unneeded hass * naming * rearrange * fix water heater, add test * fix water heater, add test * switch hvac mode when changing temp if in auto/off/smart
This commit is contained in:
parent
eee0a6e9f4
commit
f42804805c
@ -369,7 +369,7 @@ homeassistant/components/switchmate/* @danielhiversen
|
|||||||
homeassistant/components/syncthru/* @nielstron
|
homeassistant/components/syncthru/* @nielstron
|
||||||
homeassistant/components/synology_srm/* @aerialls
|
homeassistant/components/synology_srm/* @aerialls
|
||||||
homeassistant/components/syslog/* @fabaff
|
homeassistant/components/syslog/* @fabaff
|
||||||
homeassistant/components/tado/* @michaelarnauts
|
homeassistant/components/tado/* @michaelarnauts @bdraco
|
||||||
homeassistant/components/tahoma/* @philklei
|
homeassistant/components/tahoma/* @philklei
|
||||||
homeassistant/components/tankerkoenig/* @guillempages
|
homeassistant/components/tankerkoenig/* @guillempages
|
||||||
homeassistant/components/tautulli/* @ludeeus
|
homeassistant/components/tautulli/* @ludeeus
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
"""Support for the (unofficial) Tado API."""
|
"""Support for the (unofficial) Tado API."""
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
import logging
|
import logging
|
||||||
import urllib
|
|
||||||
|
|
||||||
from PyTado.interface import Tado
|
from PyTado.interface import Tado
|
||||||
|
from requests import RequestException
|
||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
|
|
||||||
from homeassistant.components.climate.const import PRESET_AWAY, PRESET_HOME
|
from homeassistant.components.climate.const import PRESET_AWAY, PRESET_HOME
|
||||||
@ -110,7 +110,7 @@ class TadoConnector:
|
|||||||
"""Connect to Tado and fetch the zones."""
|
"""Connect to Tado and fetch the zones."""
|
||||||
try:
|
try:
|
||||||
self.tado = Tado(self._username, self._password)
|
self.tado = Tado(self._username, self._password)
|
||||||
except (RuntimeError, urllib.error.HTTPError) as exc:
|
except (RuntimeError, RequestException) as exc:
|
||||||
_LOGGER.error("Unable to connect: %s", exc)
|
_LOGGER.error("Unable to connect: %s", exc)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@ -135,9 +135,14 @@ class TadoConnector:
|
|||||||
_LOGGER.debug("Updating %s %s", sensor_type, sensor)
|
_LOGGER.debug("Updating %s %s", sensor_type, sensor)
|
||||||
try:
|
try:
|
||||||
if sensor_type == "zone":
|
if sensor_type == "zone":
|
||||||
data = self.tado.getState(sensor)
|
data = self.tado.getZoneState(sensor)
|
||||||
elif sensor_type == "device":
|
elif sensor_type == "device":
|
||||||
data = self.tado.getDevices()[0]
|
devices_data = self.tado.getDevices()
|
||||||
|
if not devices_data:
|
||||||
|
_LOGGER.info("There are no devices to setup on this tado account.")
|
||||||
|
return
|
||||||
|
|
||||||
|
data = devices_data[0]
|
||||||
else:
|
else:
|
||||||
_LOGGER.debug("Unknown sensor: %s", sensor_type)
|
_LOGGER.debug("Unknown sensor: %s", sensor_type)
|
||||||
return
|
return
|
||||||
@ -174,29 +179,40 @@ class TadoConnector:
|
|||||||
|
|
||||||
def set_zone_overlay(
|
def set_zone_overlay(
|
||||||
self,
|
self,
|
||||||
zone_id,
|
zone_id=None,
|
||||||
overlay_mode,
|
overlay_mode=None,
|
||||||
temperature=None,
|
temperature=None,
|
||||||
duration=None,
|
duration=None,
|
||||||
device_type="HEATING",
|
device_type="HEATING",
|
||||||
mode=None,
|
mode=None,
|
||||||
|
fan_speed=None,
|
||||||
):
|
):
|
||||||
"""Set a zone overlay."""
|
"""Set a zone overlay."""
|
||||||
_LOGGER.debug(
|
_LOGGER.debug(
|
||||||
"Set overlay for zone %s: mode=%s, temp=%s, duration=%s, type=%s, mode=%s",
|
"Set overlay for zone %s: overlay_mode=%s, temp=%s, duration=%s, type=%s, mode=%s fan_speed=%s",
|
||||||
zone_id,
|
zone_id,
|
||||||
overlay_mode,
|
overlay_mode,
|
||||||
temperature,
|
temperature,
|
||||||
duration,
|
duration,
|
||||||
device_type,
|
device_type,
|
||||||
mode,
|
mode,
|
||||||
|
fan_speed,
|
||||||
)
|
)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.tado.setZoneOverlay(
|
self.tado.setZoneOverlay(
|
||||||
zone_id, overlay_mode, temperature, duration, device_type, "ON", mode
|
zone_id,
|
||||||
|
overlay_mode,
|
||||||
|
temperature,
|
||||||
|
duration,
|
||||||
|
device_type,
|
||||||
|
"ON",
|
||||||
|
mode,
|
||||||
|
fan_speed,
|
||||||
)
|
)
|
||||||
except urllib.error.HTTPError as exc:
|
|
||||||
_LOGGER.error("Could not set zone overlay: %s", exc.read())
|
except RequestException as exc:
|
||||||
|
_LOGGER.error("Could not set zone overlay: %s", exc)
|
||||||
|
|
||||||
self.update_sensor("zone", zone_id)
|
self.update_sensor("zone", zone_id)
|
||||||
|
|
||||||
@ -206,7 +222,7 @@ class TadoConnector:
|
|||||||
self.tado.setZoneOverlay(
|
self.tado.setZoneOverlay(
|
||||||
zone_id, overlay_mode, None, None, device_type, "OFF"
|
zone_id, overlay_mode, None, None, device_type, "OFF"
|
||||||
)
|
)
|
||||||
except urllib.error.HTTPError as exc:
|
except RequestException as exc:
|
||||||
_LOGGER.error("Could not set zone overlay: %s", exc.read())
|
_LOGGER.error("Could not set zone overlay: %s", exc)
|
||||||
|
|
||||||
self.update_sensor("zone", zone_id)
|
self.update_sensor("zone", zone_id)
|
||||||
|
@ -3,21 +3,13 @@ import logging
|
|||||||
|
|
||||||
from homeassistant.components.climate import ClimateDevice
|
from homeassistant.components.climate import ClimateDevice
|
||||||
from homeassistant.components.climate.const import (
|
from homeassistant.components.climate.const import (
|
||||||
CURRENT_HVAC_COOL,
|
|
||||||
CURRENT_HVAC_HEAT,
|
|
||||||
CURRENT_HVAC_IDLE,
|
|
||||||
CURRENT_HVAC_OFF,
|
CURRENT_HVAC_OFF,
|
||||||
FAN_HIGH,
|
FAN_AUTO,
|
||||||
FAN_LOW,
|
|
||||||
FAN_MIDDLE,
|
|
||||||
FAN_OFF,
|
|
||||||
HVAC_MODE_AUTO,
|
|
||||||
HVAC_MODE_COOL,
|
|
||||||
HVAC_MODE_HEAT,
|
HVAC_MODE_HEAT,
|
||||||
HVAC_MODE_HEAT_COOL,
|
|
||||||
HVAC_MODE_OFF,
|
HVAC_MODE_OFF,
|
||||||
PRESET_AWAY,
|
PRESET_AWAY,
|
||||||
PRESET_HOME,
|
PRESET_HOME,
|
||||||
|
SUPPORT_FAN_MODE,
|
||||||
SUPPORT_PRESET_MODE,
|
SUPPORT_PRESET_MODE,
|
||||||
SUPPORT_TARGET_TEMPERATURE,
|
SUPPORT_TARGET_TEMPERATURE,
|
||||||
)
|
)
|
||||||
@ -27,49 +19,30 @@ from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
|||||||
|
|
||||||
from . import DOMAIN, SIGNAL_TADO_UPDATE_RECEIVED
|
from . import DOMAIN, SIGNAL_TADO_UPDATE_RECEIVED
|
||||||
from .const import (
|
from .const import (
|
||||||
|
CONST_FAN_AUTO,
|
||||||
|
CONST_FAN_OFF,
|
||||||
|
CONST_MODE_AUTO,
|
||||||
|
CONST_MODE_COOL,
|
||||||
|
CONST_MODE_HEAT,
|
||||||
CONST_MODE_OFF,
|
CONST_MODE_OFF,
|
||||||
CONST_MODE_SMART_SCHEDULE,
|
CONST_MODE_SMART_SCHEDULE,
|
||||||
CONST_OVERLAY_MANUAL,
|
CONST_OVERLAY_MANUAL,
|
||||||
CONST_OVERLAY_TADO_MODE,
|
CONST_OVERLAY_TADO_MODE,
|
||||||
CONST_OVERLAY_TIMER,
|
|
||||||
DATA,
|
DATA,
|
||||||
|
HA_TO_TADO_FAN_MODE_MAP,
|
||||||
|
HA_TO_TADO_HVAC_MODE_MAP,
|
||||||
|
ORDERED_KNOWN_TADO_MODES,
|
||||||
|
SUPPORT_PRESET,
|
||||||
|
TADO_HVAC_ACTION_TO_HA_HVAC_ACTION,
|
||||||
|
TADO_MODES_WITH_NO_TEMP_SETTING,
|
||||||
|
TADO_TO_HA_FAN_MODE_MAP,
|
||||||
|
TADO_TO_HA_HVAC_MODE_MAP,
|
||||||
TYPE_AIR_CONDITIONING,
|
TYPE_AIR_CONDITIONING,
|
||||||
TYPE_HEATING,
|
TYPE_HEATING,
|
||||||
)
|
)
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
FAN_MAP_TADO = {"HIGH": FAN_HIGH, "MIDDLE": FAN_MIDDLE, "LOW": FAN_LOW}
|
|
||||||
|
|
||||||
HVAC_MAP_TADO_HEAT = {
|
|
||||||
CONST_OVERLAY_MANUAL: HVAC_MODE_HEAT,
|
|
||||||
CONST_OVERLAY_TIMER: HVAC_MODE_HEAT,
|
|
||||||
CONST_OVERLAY_TADO_MODE: HVAC_MODE_HEAT,
|
|
||||||
CONST_MODE_SMART_SCHEDULE: HVAC_MODE_AUTO,
|
|
||||||
CONST_MODE_OFF: HVAC_MODE_OFF,
|
|
||||||
}
|
|
||||||
HVAC_MAP_TADO_COOL = {
|
|
||||||
CONST_OVERLAY_MANUAL: HVAC_MODE_COOL,
|
|
||||||
CONST_OVERLAY_TIMER: HVAC_MODE_COOL,
|
|
||||||
CONST_OVERLAY_TADO_MODE: HVAC_MODE_COOL,
|
|
||||||
CONST_MODE_SMART_SCHEDULE: HVAC_MODE_AUTO,
|
|
||||||
CONST_MODE_OFF: HVAC_MODE_OFF,
|
|
||||||
}
|
|
||||||
HVAC_MAP_TADO_HEAT_COOL = {
|
|
||||||
CONST_OVERLAY_MANUAL: HVAC_MODE_HEAT_COOL,
|
|
||||||
CONST_OVERLAY_TIMER: HVAC_MODE_HEAT_COOL,
|
|
||||||
CONST_OVERLAY_TADO_MODE: HVAC_MODE_HEAT_COOL,
|
|
||||||
CONST_MODE_SMART_SCHEDULE: HVAC_MODE_AUTO,
|
|
||||||
CONST_MODE_OFF: HVAC_MODE_OFF,
|
|
||||||
}
|
|
||||||
|
|
||||||
SUPPORT_FLAGS = SUPPORT_TARGET_TEMPERATURE | SUPPORT_PRESET_MODE
|
|
||||||
SUPPORT_HVAC_HEAT = [HVAC_MODE_HEAT, HVAC_MODE_AUTO, HVAC_MODE_OFF]
|
|
||||||
SUPPORT_HVAC_COOL = [HVAC_MODE_COOL, HVAC_MODE_AUTO, HVAC_MODE_OFF]
|
|
||||||
SUPPORT_HVAC_HEAT_COOL = [HVAC_MODE_HEAT_COOL, HVAC_MODE_AUTO, HVAC_MODE_OFF]
|
|
||||||
SUPPORT_FAN = [FAN_HIGH, FAN_MIDDLE, FAN_LOW, FAN_OFF]
|
|
||||||
SUPPORT_PRESET = [PRESET_AWAY, PRESET_HOME]
|
|
||||||
|
|
||||||
|
|
||||||
def setup_platform(hass, config, add_entities, discovery_info=None):
|
def setup_platform(hass, config, add_entities, discovery_info=None):
|
||||||
"""Set up the Tado climate platform."""
|
"""Set up the Tado climate platform."""
|
||||||
@ -96,29 +69,80 @@ def create_climate_entity(tado, name: str, zone_id: int):
|
|||||||
_LOGGER.debug("Capabilities for zone %s: %s", zone_id, capabilities)
|
_LOGGER.debug("Capabilities for zone %s: %s", zone_id, capabilities)
|
||||||
|
|
||||||
zone_type = capabilities["type"]
|
zone_type = capabilities["type"]
|
||||||
|
support_flags = SUPPORT_PRESET_MODE | SUPPORT_TARGET_TEMPERATURE
|
||||||
|
supported_hvac_modes = [
|
||||||
|
TADO_TO_HA_HVAC_MODE_MAP[CONST_MODE_OFF],
|
||||||
|
TADO_TO_HA_HVAC_MODE_MAP[CONST_MODE_SMART_SCHEDULE],
|
||||||
|
]
|
||||||
|
supported_fan_modes = None
|
||||||
|
heat_temperatures = None
|
||||||
|
cool_temperatures = None
|
||||||
|
|
||||||
ac_support_heat = False
|
|
||||||
if zone_type == TYPE_AIR_CONDITIONING:
|
if zone_type == TYPE_AIR_CONDITIONING:
|
||||||
# Only use heat if available
|
|
||||||
# (you don't have to setup a heat mode, but cool is required)
|
|
||||||
# Heat is preferred as it generally has a lower minimum temperature
|
# Heat is preferred as it generally has a lower minimum temperature
|
||||||
if "HEAT" in capabilities:
|
for mode in ORDERED_KNOWN_TADO_MODES:
|
||||||
temperatures = capabilities["HEAT"]["temperatures"]
|
if mode not in capabilities:
|
||||||
ac_support_heat = True
|
continue
|
||||||
else:
|
|
||||||
temperatures = capabilities["COOL"]["temperatures"]
|
supported_hvac_modes.append(TADO_TO_HA_HVAC_MODE_MAP[mode])
|
||||||
elif "temperatures" in capabilities:
|
if not capabilities[mode].get("fanSpeeds"):
|
||||||
temperatures = capabilities["temperatures"]
|
continue
|
||||||
|
|
||||||
|
support_flags |= SUPPORT_FAN_MODE
|
||||||
|
|
||||||
|
if supported_fan_modes:
|
||||||
|
continue
|
||||||
|
|
||||||
|
supported_fan_modes = [
|
||||||
|
TADO_TO_HA_FAN_MODE_MAP[speed]
|
||||||
|
for speed in capabilities[mode]["fanSpeeds"]
|
||||||
|
]
|
||||||
|
|
||||||
|
cool_temperatures = capabilities[CONST_MODE_COOL]["temperatures"]
|
||||||
else:
|
else:
|
||||||
_LOGGER.debug("Not adding zone %s since it has no temperature", name)
|
supported_hvac_modes.append(HVAC_MODE_HEAT)
|
||||||
|
|
||||||
|
if CONST_MODE_HEAT in capabilities:
|
||||||
|
heat_temperatures = capabilities[CONST_MODE_HEAT]["temperatures"]
|
||||||
|
|
||||||
|
if heat_temperatures is None and "temperatures" in capabilities:
|
||||||
|
heat_temperatures = capabilities["temperatures"]
|
||||||
|
|
||||||
|
if cool_temperatures is None and heat_temperatures is None:
|
||||||
|
_LOGGER.debug("Not adding zone %s since it has no temperatures", name)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
min_temp = float(temperatures["celsius"]["min"])
|
heat_min_temp = None
|
||||||
max_temp = float(temperatures["celsius"]["max"])
|
heat_max_temp = None
|
||||||
step = temperatures["celsius"].get("step", PRECISION_TENTHS)
|
heat_step = None
|
||||||
|
cool_min_temp = None
|
||||||
|
cool_max_temp = None
|
||||||
|
cool_step = None
|
||||||
|
|
||||||
|
if heat_temperatures is not None:
|
||||||
|
heat_min_temp = float(heat_temperatures["celsius"]["min"])
|
||||||
|
heat_max_temp = float(heat_temperatures["celsius"]["max"])
|
||||||
|
heat_step = heat_temperatures["celsius"].get("step", PRECISION_TENTHS)
|
||||||
|
|
||||||
|
if cool_temperatures is not None:
|
||||||
|
cool_min_temp = float(cool_temperatures["celsius"]["min"])
|
||||||
|
cool_max_temp = float(cool_temperatures["celsius"]["max"])
|
||||||
|
cool_step = cool_temperatures["celsius"].get("step", PRECISION_TENTHS)
|
||||||
|
|
||||||
entity = TadoClimate(
|
entity = TadoClimate(
|
||||||
tado, name, zone_id, zone_type, min_temp, max_temp, step, ac_support_heat,
|
tado,
|
||||||
|
name,
|
||||||
|
zone_id,
|
||||||
|
zone_type,
|
||||||
|
heat_min_temp,
|
||||||
|
heat_max_temp,
|
||||||
|
heat_step,
|
||||||
|
cool_min_temp,
|
||||||
|
cool_max_temp,
|
||||||
|
cool_step,
|
||||||
|
supported_hvac_modes,
|
||||||
|
supported_fan_modes,
|
||||||
|
support_flags,
|
||||||
)
|
)
|
||||||
return entity
|
return entity
|
||||||
|
|
||||||
@ -132,10 +156,15 @@ class TadoClimate(ClimateDevice):
|
|||||||
zone_name,
|
zone_name,
|
||||||
zone_id,
|
zone_id,
|
||||||
zone_type,
|
zone_type,
|
||||||
min_temp,
|
heat_min_temp,
|
||||||
max_temp,
|
heat_max_temp,
|
||||||
step,
|
heat_step,
|
||||||
ac_support_heat,
|
cool_min_temp,
|
||||||
|
cool_max_temp,
|
||||||
|
cool_step,
|
||||||
|
supported_hvac_modes,
|
||||||
|
supported_fan_modes,
|
||||||
|
support_flags,
|
||||||
):
|
):
|
||||||
"""Initialize of Tado climate entity."""
|
"""Initialize of Tado climate entity."""
|
||||||
self._tado = tado
|
self._tado = tado
|
||||||
@ -146,49 +175,51 @@ class TadoClimate(ClimateDevice):
|
|||||||
self._unique_id = f"{zone_type} {zone_id} {tado.device_id}"
|
self._unique_id = f"{zone_type} {zone_id} {tado.device_id}"
|
||||||
|
|
||||||
self._ac_device = zone_type == TYPE_AIR_CONDITIONING
|
self._ac_device = zone_type == TYPE_AIR_CONDITIONING
|
||||||
self._ac_support_heat = ac_support_heat
|
self._supported_hvac_modes = supported_hvac_modes
|
||||||
self._cooling = False
|
self._supported_fan_modes = supported_fan_modes
|
||||||
|
self._support_flags = support_flags
|
||||||
|
|
||||||
self._active = False
|
self._available = False
|
||||||
self._device_is_active = False
|
|
||||||
|
|
||||||
self._cur_temp = None
|
self._cur_temp = None
|
||||||
self._cur_humidity = None
|
self._cur_humidity = None
|
||||||
self._is_away = False
|
|
||||||
self._min_temp = min_temp
|
self._heat_min_temp = heat_min_temp
|
||||||
self._max_temp = max_temp
|
self._heat_max_temp = heat_max_temp
|
||||||
self._step = step
|
self._heat_step = heat_step
|
||||||
|
|
||||||
|
self._cool_min_temp = cool_min_temp
|
||||||
|
self._cool_max_temp = cool_max_temp
|
||||||
|
self._cool_step = cool_step
|
||||||
|
|
||||||
self._target_temp = None
|
self._target_temp = None
|
||||||
|
|
||||||
if tado.fallback:
|
self._current_tado_fan_speed = CONST_FAN_OFF
|
||||||
# Fallback to Smart Schedule at next Schedule switch
|
self._current_tado_hvac_mode = CONST_MODE_OFF
|
||||||
self._default_overlay = CONST_OVERLAY_TADO_MODE
|
self._current_tado_hvac_action = CURRENT_HVAC_OFF
|
||||||
else:
|
|
||||||
# Don't fallback to Smart Schedule, but keep in manual mode
|
|
||||||
self._default_overlay = CONST_OVERLAY_MANUAL
|
|
||||||
|
|
||||||
self._current_fan = CONST_MODE_OFF
|
self._undo_dispatcher = None
|
||||||
self._current_operation = CONST_MODE_SMART_SCHEDULE
|
self._tado_zone_data = None
|
||||||
self._overlay_mode = CONST_MODE_SMART_SCHEDULE
|
self._async_update_zone_data()
|
||||||
|
|
||||||
|
async def async_will_remove_from_hass(self):
|
||||||
|
"""When entity will be removed from hass."""
|
||||||
|
if self._undo_dispatcher:
|
||||||
|
self._undo_dispatcher()
|
||||||
|
|
||||||
async def async_added_to_hass(self):
|
async def async_added_to_hass(self):
|
||||||
"""Register for sensor updates."""
|
"""Register for sensor updates."""
|
||||||
|
|
||||||
@callback
|
self._undo_dispatcher = async_dispatcher_connect(
|
||||||
def async_update_callback():
|
|
||||||
"""Schedule an entity update."""
|
|
||||||
self.async_schedule_update_ha_state(True)
|
|
||||||
|
|
||||||
async_dispatcher_connect(
|
|
||||||
self.hass,
|
self.hass,
|
||||||
SIGNAL_TADO_UPDATE_RECEIVED.format("zone", self.zone_id),
|
SIGNAL_TADO_UPDATE_RECEIVED.format("zone", self.zone_id),
|
||||||
async_update_callback,
|
self._async_update_callback,
|
||||||
)
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def supported_features(self):
|
def supported_features(self):
|
||||||
"""Return the list of supported features."""
|
"""Return the list of supported features."""
|
||||||
return SUPPORT_FLAGS
|
return self._support_flags
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def name(self):
|
def name(self):
|
||||||
@ -208,12 +239,12 @@ class TadoClimate(ClimateDevice):
|
|||||||
@property
|
@property
|
||||||
def current_humidity(self):
|
def current_humidity(self):
|
||||||
"""Return the current humidity."""
|
"""Return the current humidity."""
|
||||||
return self._cur_humidity
|
return self._tado_zone_data.current_humidity
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def current_temperature(self):
|
def current_temperature(self):
|
||||||
"""Return the sensor temperature."""
|
"""Return the sensor temperature."""
|
||||||
return self._cur_temp
|
return self._tado_zone_data.current_temp
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def hvac_mode(self):
|
def hvac_mode(self):
|
||||||
@ -221,11 +252,7 @@ class TadoClimate(ClimateDevice):
|
|||||||
|
|
||||||
Need to be one of HVAC_MODE_*.
|
Need to be one of HVAC_MODE_*.
|
||||||
"""
|
"""
|
||||||
if self._ac_device and self._ac_support_heat:
|
return TADO_TO_HA_HVAC_MODE_MAP.get(self._current_tado_hvac_mode, HVAC_MODE_OFF)
|
||||||
return HVAC_MAP_TADO_HEAT_COOL.get(self._current_operation)
|
|
||||||
if self._ac_device and not self._ac_support_heat:
|
|
||||||
return HVAC_MAP_TADO_COOL.get(self._current_operation)
|
|
||||||
return HVAC_MAP_TADO_HEAT.get(self._current_operation)
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def hvac_modes(self):
|
def hvac_modes(self):
|
||||||
@ -233,11 +260,7 @@ class TadoClimate(ClimateDevice):
|
|||||||
|
|
||||||
Need to be a subset of HVAC_MODES.
|
Need to be a subset of HVAC_MODES.
|
||||||
"""
|
"""
|
||||||
if self._ac_device:
|
return self._supported_hvac_modes
|
||||||
if self._ac_support_heat:
|
|
||||||
return SUPPORT_HVAC_HEAT_COOL
|
|
||||||
return SUPPORT_HVAC_COOL
|
|
||||||
return SUPPORT_HVAC_HEAT
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def hvac_action(self):
|
def hvac_action(self):
|
||||||
@ -245,40 +268,30 @@ class TadoClimate(ClimateDevice):
|
|||||||
|
|
||||||
Need to be one of CURRENT_HVAC_*.
|
Need to be one of CURRENT_HVAC_*.
|
||||||
"""
|
"""
|
||||||
if not self._device_is_active:
|
return TADO_HVAC_ACTION_TO_HA_HVAC_ACTION.get(
|
||||||
return CURRENT_HVAC_OFF
|
self._tado_zone_data.current_hvac_action, CURRENT_HVAC_OFF
|
||||||
if self._ac_device:
|
)
|
||||||
if self._active:
|
|
||||||
if self._ac_support_heat and not self._cooling:
|
|
||||||
return CURRENT_HVAC_HEAT
|
|
||||||
return CURRENT_HVAC_COOL
|
|
||||||
return CURRENT_HVAC_IDLE
|
|
||||||
if self._active:
|
|
||||||
return CURRENT_HVAC_HEAT
|
|
||||||
return CURRENT_HVAC_IDLE
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def fan_mode(self):
|
def fan_mode(self):
|
||||||
"""Return the fan setting."""
|
"""Return the fan setting."""
|
||||||
if self._ac_device:
|
if self._ac_device:
|
||||||
return FAN_MAP_TADO.get(self._current_fan)
|
return TADO_TO_HA_FAN_MODE_MAP.get(self._current_tado_fan_speed, FAN_AUTO)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def fan_modes(self):
|
def fan_modes(self):
|
||||||
"""List of available fan modes."""
|
"""List of available fan modes."""
|
||||||
if self._ac_device:
|
return self._supported_fan_modes
|
||||||
return SUPPORT_FAN
|
|
||||||
return None
|
|
||||||
|
|
||||||
def set_fan_mode(self, fan_mode: str):
|
def set_fan_mode(self, fan_mode: str):
|
||||||
"""Turn fan on/off."""
|
"""Turn fan on/off."""
|
||||||
pass
|
self._control_hvac(fan_mode=HA_TO_TADO_FAN_MODE_MAP[fan_mode])
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def preset_mode(self):
|
def preset_mode(self):
|
||||||
"""Return the current preset mode (home, away)."""
|
"""Return the current preset mode (home, away)."""
|
||||||
if self._is_away:
|
if self._tado_zone_data.is_away:
|
||||||
return PRESET_AWAY
|
return PRESET_AWAY
|
||||||
return PRESET_HOME
|
return PRESET_HOME
|
||||||
|
|
||||||
@ -299,12 +312,18 @@ class TadoClimate(ClimateDevice):
|
|||||||
@property
|
@property
|
||||||
def target_temperature_step(self):
|
def target_temperature_step(self):
|
||||||
"""Return the supported step of target temperature."""
|
"""Return the supported step of target temperature."""
|
||||||
return self._step
|
if self._tado_zone_data.current_hvac_mode == CONST_MODE_COOL:
|
||||||
|
return self._cool_step or self._heat_step
|
||||||
|
return self._heat_step or self._cool_step
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def target_temperature(self):
|
def target_temperature(self):
|
||||||
"""Return the temperature we try to reach."""
|
"""Return the temperature we try to reach."""
|
||||||
return self._target_temp
|
# If the target temperature will be None
|
||||||
|
# if the device is performing an action
|
||||||
|
# that does not affect the temperature or
|
||||||
|
# the device is switching states
|
||||||
|
return self._tado_zone_data.target_temp or self._tado_zone_data.current_temp
|
||||||
|
|
||||||
def set_temperature(self, **kwargs):
|
def set_temperature(self, **kwargs):
|
||||||
"""Set new target temperature."""
|
"""Set new target temperature."""
|
||||||
@ -312,174 +331,149 @@ class TadoClimate(ClimateDevice):
|
|||||||
if temperature is None:
|
if temperature is None:
|
||||||
return
|
return
|
||||||
|
|
||||||
self._current_operation = self._default_overlay
|
if self._current_tado_hvac_mode not in (
|
||||||
self._overlay_mode = None
|
CONST_MODE_OFF,
|
||||||
self._target_temp = temperature
|
CONST_MODE_AUTO,
|
||||||
self._control_heating()
|
CONST_MODE_SMART_SCHEDULE,
|
||||||
|
):
|
||||||
|
self._control_hvac(target_temp=temperature)
|
||||||
|
return
|
||||||
|
|
||||||
|
new_hvac_mode = CONST_MODE_COOL if self._ac_device else CONST_MODE_HEAT
|
||||||
|
self._control_hvac(target_temp=temperature, hvac_mode=new_hvac_mode)
|
||||||
|
|
||||||
def set_hvac_mode(self, hvac_mode):
|
def set_hvac_mode(self, hvac_mode):
|
||||||
"""Set new target hvac mode."""
|
"""Set new target hvac mode."""
|
||||||
mode = None
|
|
||||||
|
|
||||||
if hvac_mode == HVAC_MODE_OFF:
|
self._control_hvac(hvac_mode=HA_TO_TADO_HVAC_MODE_MAP[hvac_mode])
|
||||||
mode = CONST_MODE_OFF
|
|
||||||
elif hvac_mode == HVAC_MODE_AUTO:
|
|
||||||
mode = CONST_MODE_SMART_SCHEDULE
|
|
||||||
elif hvac_mode == HVAC_MODE_HEAT:
|
|
||||||
mode = self._default_overlay
|
|
||||||
elif hvac_mode == HVAC_MODE_COOL:
|
|
||||||
mode = self._default_overlay
|
|
||||||
elif hvac_mode == HVAC_MODE_HEAT_COOL:
|
|
||||||
mode = self._default_overlay
|
|
||||||
|
|
||||||
self._current_operation = mode
|
@property
|
||||||
self._overlay_mode = None
|
def available(self):
|
||||||
|
"""Return if the device is available."""
|
||||||
# Set a target temperature if we don't have any
|
return self._tado_zone_data.available
|
||||||
# This can happen when we switch from Off to On
|
|
||||||
if self._target_temp is None:
|
|
||||||
if self._ac_device:
|
|
||||||
self._target_temp = self.max_temp
|
|
||||||
else:
|
|
||||||
self._target_temp = self.min_temp
|
|
||||||
self.schedule_update_ha_state()
|
|
||||||
|
|
||||||
self._control_heating()
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def min_temp(self):
|
def min_temp(self):
|
||||||
"""Return the minimum temperature."""
|
"""Return the minimum temperature."""
|
||||||
return self._min_temp
|
if (
|
||||||
|
self._current_tado_hvac_mode == CONST_MODE_COOL
|
||||||
|
and self._cool_min_temp is not None
|
||||||
|
):
|
||||||
|
return self._cool_min_temp
|
||||||
|
if self._heat_min_temp is not None:
|
||||||
|
return self._heat_min_temp
|
||||||
|
|
||||||
|
return self._cool_min_temp
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def max_temp(self):
|
def max_temp(self):
|
||||||
"""Return the maximum temperature."""
|
"""Return the maximum temperature."""
|
||||||
return self._max_temp
|
|
||||||
|
|
||||||
def update(self):
|
|
||||||
"""Handle update callbacks."""
|
|
||||||
_LOGGER.debug("Updating climate platform for zone %d", self.zone_id)
|
|
||||||
data = self._tado.data["zone"][self.zone_id]
|
|
||||||
|
|
||||||
if "sensorDataPoints" in data:
|
|
||||||
sensor_data = data["sensorDataPoints"]
|
|
||||||
|
|
||||||
if "insideTemperature" in sensor_data:
|
|
||||||
temperature = float(sensor_data["insideTemperature"]["celsius"])
|
|
||||||
self._cur_temp = temperature
|
|
||||||
|
|
||||||
if "humidity" in sensor_data:
|
|
||||||
humidity = float(sensor_data["humidity"]["percentage"])
|
|
||||||
self._cur_humidity = humidity
|
|
||||||
|
|
||||||
# temperature setting will not exist when device is off
|
|
||||||
if (
|
if (
|
||||||
"temperature" in data["setting"]
|
self._current_tado_hvac_mode == CONST_MODE_HEAT
|
||||||
and data["setting"]["temperature"] is not None
|
and self._heat_max_temp is not None
|
||||||
):
|
):
|
||||||
setting = float(data["setting"]["temperature"]["celsius"])
|
return self._heat_max_temp
|
||||||
self._target_temp = setting
|
if self._heat_max_temp is not None:
|
||||||
|
return self._heat_max_temp
|
||||||
|
|
||||||
if "tadoMode" in data:
|
return self._heat_max_temp
|
||||||
mode = data["tadoMode"]
|
|
||||||
self._is_away = mode == "AWAY"
|
|
||||||
|
|
||||||
if "setting" in data:
|
@callback
|
||||||
power = data["setting"]["power"]
|
def _async_update_zone_data(self):
|
||||||
if power == "OFF":
|
"""Load tado data into zone."""
|
||||||
self._current_operation = CONST_MODE_OFF
|
self._tado_zone_data = self._tado.data["zone"][self.zone_id]
|
||||||
self._current_fan = CONST_MODE_OFF
|
self._current_tado_fan_speed = self._tado_zone_data.current_fan_speed
|
||||||
# There is no overlay, the mode will always be
|
self._current_tado_hvac_mode = self._tado_zone_data.current_hvac_mode
|
||||||
# "SMART_SCHEDULE"
|
self._current_tado_hvac_action = self._tado_zone_data.current_hvac_action
|
||||||
self._overlay_mode = CONST_MODE_SMART_SCHEDULE
|
|
||||||
self._device_is_active = False
|
|
||||||
else:
|
|
||||||
self._device_is_active = True
|
|
||||||
|
|
||||||
active = False
|
@callback
|
||||||
if "activityDataPoints" in data:
|
def _async_update_callback(self):
|
||||||
activity_data = data["activityDataPoints"]
|
"""Load tado data and update state."""
|
||||||
if self._ac_device:
|
self._async_update_zone_data()
|
||||||
if "acPower" in activity_data and activity_data["acPower"] is not None:
|
self.async_write_ha_state()
|
||||||
if not activity_data["acPower"]["value"] == "OFF":
|
|
||||||
active = True
|
|
||||||
else:
|
|
||||||
if (
|
|
||||||
"heatingPower" in activity_data
|
|
||||||
and activity_data["heatingPower"] is not None
|
|
||||||
):
|
|
||||||
if float(activity_data["heatingPower"]["percentage"]) > 0.0:
|
|
||||||
active = True
|
|
||||||
self._active = active
|
|
||||||
|
|
||||||
overlay = False
|
def _normalize_target_temp_for_hvac_mode(self):
|
||||||
overlay_data = None
|
# Set a target temperature if we don't have any
|
||||||
termination = CONST_MODE_SMART_SCHEDULE
|
# This can happen when we switch from Off to On
|
||||||
cooling = False
|
if self._target_temp is None:
|
||||||
fan_speed = CONST_MODE_OFF
|
self._target_temp = self._tado_zone_data.current_temp
|
||||||
|
elif self._current_tado_hvac_mode == CONST_MODE_COOL:
|
||||||
|
if self._target_temp > self._cool_max_temp:
|
||||||
|
self._target_temp = self._cool_max_temp
|
||||||
|
elif self._target_temp < self._cool_min_temp:
|
||||||
|
self._target_temp = self._cool_min_temp
|
||||||
|
elif self._current_tado_hvac_mode == CONST_MODE_HEAT:
|
||||||
|
if self._target_temp > self._heat_max_temp:
|
||||||
|
self._target_temp = self._heat_max_temp
|
||||||
|
elif self._target_temp < self._heat_min_temp:
|
||||||
|
self._target_temp = self._heat_min_temp
|
||||||
|
|
||||||
if "overlay" in data:
|
def _control_hvac(self, hvac_mode=None, target_temp=None, fan_mode=None):
|
||||||
overlay_data = data["overlay"]
|
|
||||||
overlay = overlay_data is not None
|
|
||||||
|
|
||||||
if overlay:
|
|
||||||
termination = overlay_data["termination"]["type"]
|
|
||||||
setting = False
|
|
||||||
setting_data = None
|
|
||||||
|
|
||||||
if "setting" in overlay_data:
|
|
||||||
setting_data = overlay_data["setting"]
|
|
||||||
setting = setting_data is not None
|
|
||||||
|
|
||||||
if setting:
|
|
||||||
if "mode" in setting_data:
|
|
||||||
cooling = setting_data["mode"] == "COOL"
|
|
||||||
|
|
||||||
if "fanSpeed" in setting_data:
|
|
||||||
fan_speed = setting_data["fanSpeed"]
|
|
||||||
|
|
||||||
if self._device_is_active:
|
|
||||||
# If you set mode manually to off, there will be an overlay
|
|
||||||
# and a termination, but we want to see the mode "OFF"
|
|
||||||
self._overlay_mode = termination
|
|
||||||
self._current_operation = termination
|
|
||||||
|
|
||||||
self._cooling = cooling
|
|
||||||
self._current_fan = fan_speed
|
|
||||||
|
|
||||||
def _control_heating(self):
|
|
||||||
"""Send new target temperature to Tado."""
|
"""Send new target temperature to Tado."""
|
||||||
if self._current_operation == CONST_MODE_SMART_SCHEDULE:
|
|
||||||
|
if hvac_mode:
|
||||||
|
self._current_tado_hvac_mode = hvac_mode
|
||||||
|
|
||||||
|
if target_temp:
|
||||||
|
self._target_temp = target_temp
|
||||||
|
|
||||||
|
if fan_mode:
|
||||||
|
self._current_tado_fan_speed = fan_mode
|
||||||
|
|
||||||
|
self._normalize_target_temp_for_hvac_mode()
|
||||||
|
|
||||||
|
# tado does not permit setting the fan speed to
|
||||||
|
# off, you must turn off the device
|
||||||
|
if (
|
||||||
|
self._current_tado_fan_speed == CONST_FAN_OFF
|
||||||
|
and self._current_tado_hvac_mode != CONST_MODE_OFF
|
||||||
|
):
|
||||||
|
self._current_tado_fan_speed = CONST_FAN_AUTO
|
||||||
|
|
||||||
|
if self._current_tado_hvac_mode == CONST_MODE_OFF:
|
||||||
|
_LOGGER.debug(
|
||||||
|
"Switching to OFF for zone %s (%d)", self.zone_name, self.zone_id
|
||||||
|
)
|
||||||
|
self._tado.set_zone_off(self.zone_id, CONST_OVERLAY_MANUAL, self.zone_type)
|
||||||
|
return
|
||||||
|
|
||||||
|
if self._current_tado_hvac_mode == CONST_MODE_SMART_SCHEDULE:
|
||||||
_LOGGER.debug(
|
_LOGGER.debug(
|
||||||
"Switching to SMART_SCHEDULE for zone %s (%d)",
|
"Switching to SMART_SCHEDULE for zone %s (%d)",
|
||||||
self.zone_name,
|
self.zone_name,
|
||||||
self.zone_id,
|
self.zone_id,
|
||||||
)
|
)
|
||||||
self._tado.reset_zone_overlay(self.zone_id)
|
self._tado.reset_zone_overlay(self.zone_id)
|
||||||
self._overlay_mode = self._current_operation
|
|
||||||
return
|
|
||||||
|
|
||||||
if self._current_operation == CONST_MODE_OFF:
|
|
||||||
_LOGGER.debug(
|
|
||||||
"Switching to OFF for zone %s (%d)", self.zone_name, self.zone_id
|
|
||||||
)
|
|
||||||
self._tado.set_zone_off(self.zone_id, CONST_OVERLAY_MANUAL, self.zone_type)
|
|
||||||
self._overlay_mode = self._current_operation
|
|
||||||
return
|
return
|
||||||
|
|
||||||
_LOGGER.debug(
|
_LOGGER.debug(
|
||||||
"Switching to %s for zone %s (%d) with temperature %s °C",
|
"Switching to %s for zone %s (%d) with temperature %s °C",
|
||||||
self._current_operation,
|
self._current_tado_hvac_mode,
|
||||||
self.zone_name,
|
self.zone_name,
|
||||||
self.zone_id,
|
self.zone_id,
|
||||||
self._target_temp,
|
self._target_temp,
|
||||||
)
|
)
|
||||||
self._tado.set_zone_overlay(
|
|
||||||
self.zone_id,
|
# Fallback to Smart Schedule at next Schedule switch if we have fallback enabled
|
||||||
self._current_operation,
|
overlay_mode = (
|
||||||
self._target_temp,
|
CONST_OVERLAY_TADO_MODE if self._tado.fallback else CONST_OVERLAY_MANUAL
|
||||||
None,
|
)
|
||||||
self.zone_type,
|
|
||||||
"COOL" if self._ac_device else None,
|
temperature_to_send = self._target_temp
|
||||||
|
if self._current_tado_hvac_mode in TADO_MODES_WITH_NO_TEMP_SETTING:
|
||||||
|
# A temperature cannot be passed with these modes
|
||||||
|
temperature_to_send = None
|
||||||
|
|
||||||
|
self._tado.set_zone_overlay(
|
||||||
|
zone_id=self.zone_id,
|
||||||
|
overlay_mode=overlay_mode, # What to do when the period ends
|
||||||
|
temperature=temperature_to_send,
|
||||||
|
duration=None,
|
||||||
|
device_type=self.zone_type,
|
||||||
|
mode=self._current_tado_hvac_mode,
|
||||||
|
fan_speed=(
|
||||||
|
self._current_tado_fan_speed
|
||||||
|
if (self._support_flags & SUPPORT_FAN_MODE)
|
||||||
|
else None
|
||||||
|
), # api defaults to not sending fanSpeed if not specified
|
||||||
)
|
)
|
||||||
self._overlay_mode = self._current_operation
|
|
||||||
|
@ -1,5 +1,48 @@
|
|||||||
"""Constant values for the Tado component."""
|
"""Constant values for the Tado component."""
|
||||||
|
|
||||||
|
from PyTado.const import (
|
||||||
|
CONST_HVAC_COOL,
|
||||||
|
CONST_HVAC_DRY,
|
||||||
|
CONST_HVAC_FAN,
|
||||||
|
CONST_HVAC_HEAT,
|
||||||
|
CONST_HVAC_HOT_WATER,
|
||||||
|
CONST_HVAC_IDLE,
|
||||||
|
CONST_HVAC_OFF,
|
||||||
|
)
|
||||||
|
|
||||||
|
from homeassistant.components.climate.const import (
|
||||||
|
CURRENT_HVAC_COOL,
|
||||||
|
CURRENT_HVAC_DRY,
|
||||||
|
CURRENT_HVAC_FAN,
|
||||||
|
CURRENT_HVAC_HEAT,
|
||||||
|
CURRENT_HVAC_IDLE,
|
||||||
|
CURRENT_HVAC_OFF,
|
||||||
|
FAN_AUTO,
|
||||||
|
FAN_HIGH,
|
||||||
|
FAN_LOW,
|
||||||
|
FAN_MEDIUM,
|
||||||
|
FAN_OFF,
|
||||||
|
HVAC_MODE_AUTO,
|
||||||
|
HVAC_MODE_COOL,
|
||||||
|
HVAC_MODE_DRY,
|
||||||
|
HVAC_MODE_FAN_ONLY,
|
||||||
|
HVAC_MODE_HEAT,
|
||||||
|
HVAC_MODE_HEAT_COOL,
|
||||||
|
HVAC_MODE_OFF,
|
||||||
|
PRESET_AWAY,
|
||||||
|
PRESET_HOME,
|
||||||
|
)
|
||||||
|
|
||||||
|
TADO_HVAC_ACTION_TO_HA_HVAC_ACTION = {
|
||||||
|
CONST_HVAC_HEAT: CURRENT_HVAC_HEAT,
|
||||||
|
CONST_HVAC_DRY: CURRENT_HVAC_DRY,
|
||||||
|
CONST_HVAC_FAN: CURRENT_HVAC_FAN,
|
||||||
|
CONST_HVAC_COOL: CURRENT_HVAC_COOL,
|
||||||
|
CONST_HVAC_IDLE: CURRENT_HVAC_IDLE,
|
||||||
|
CONST_HVAC_OFF: CURRENT_HVAC_OFF,
|
||||||
|
CONST_HVAC_HOT_WATER: CURRENT_HVAC_HEAT,
|
||||||
|
}
|
||||||
|
|
||||||
# Configuration
|
# Configuration
|
||||||
CONF_FALLBACK = "fallback"
|
CONF_FALLBACK = "fallback"
|
||||||
DATA = "data"
|
DATA = "data"
|
||||||
@ -10,10 +53,81 @@ TYPE_HEATING = "HEATING"
|
|||||||
TYPE_HOT_WATER = "HOT_WATER"
|
TYPE_HOT_WATER = "HOT_WATER"
|
||||||
|
|
||||||
# Base modes
|
# Base modes
|
||||||
|
CONST_MODE_OFF = "OFF"
|
||||||
CONST_MODE_SMART_SCHEDULE = "SMART_SCHEDULE" # Use the schedule
|
CONST_MODE_SMART_SCHEDULE = "SMART_SCHEDULE" # Use the schedule
|
||||||
CONST_MODE_OFF = "OFF" # Switch off heating in a zone
|
CONST_MODE_AUTO = "AUTO"
|
||||||
|
CONST_MODE_COOL = "COOL"
|
||||||
|
CONST_MODE_HEAT = "HEAT"
|
||||||
|
CONST_MODE_DRY = "DRY"
|
||||||
|
CONST_MODE_FAN = "FAN"
|
||||||
|
|
||||||
|
CONST_LINK_OFFLINE = "OFFLINE"
|
||||||
|
|
||||||
|
CONST_FAN_OFF = "OFF"
|
||||||
|
CONST_FAN_AUTO = "AUTO"
|
||||||
|
CONST_FAN_LOW = "LOW"
|
||||||
|
CONST_FAN_MIDDLE = "MIDDLE"
|
||||||
|
CONST_FAN_HIGH = "HIGH"
|
||||||
|
|
||||||
|
|
||||||
# When we change the temperature setting, we need an overlay mode
|
# When we change the temperature setting, we need an overlay mode
|
||||||
CONST_OVERLAY_TADO_MODE = "TADO_MODE" # wait until tado changes the mode automatic
|
CONST_OVERLAY_TADO_MODE = "TADO_MODE" # wait until tado changes the mode automatic
|
||||||
CONST_OVERLAY_MANUAL = "MANUAL" # the user has change the temperature or mode manually
|
CONST_OVERLAY_MANUAL = "MANUAL" # the user has change the temperature or mode manually
|
||||||
CONST_OVERLAY_TIMER = "TIMER" # the temperature will be reset after a timespan
|
CONST_OVERLAY_TIMER = "TIMER" # the temperature will be reset after a timespan
|
||||||
|
|
||||||
|
|
||||||
|
# Heat always comes first since we get the
|
||||||
|
# min and max tempatures for the zone from
|
||||||
|
# it.
|
||||||
|
# Heat is preferred as it generally has a lower minimum temperature
|
||||||
|
ORDERED_KNOWN_TADO_MODES = [
|
||||||
|
CONST_MODE_HEAT,
|
||||||
|
CONST_MODE_COOL,
|
||||||
|
CONST_MODE_AUTO,
|
||||||
|
CONST_MODE_DRY,
|
||||||
|
CONST_MODE_FAN,
|
||||||
|
]
|
||||||
|
|
||||||
|
TADO_MODES_TO_HA_CURRENT_HVAC_ACTION = {
|
||||||
|
CONST_MODE_HEAT: CURRENT_HVAC_HEAT,
|
||||||
|
CONST_MODE_DRY: CURRENT_HVAC_DRY,
|
||||||
|
CONST_MODE_FAN: CURRENT_HVAC_FAN,
|
||||||
|
CONST_MODE_COOL: CURRENT_HVAC_COOL,
|
||||||
|
}
|
||||||
|
|
||||||
|
# These modes will not allow a temp to be set
|
||||||
|
TADO_MODES_WITH_NO_TEMP_SETTING = [CONST_MODE_AUTO, CONST_MODE_DRY, CONST_MODE_FAN]
|
||||||
|
#
|
||||||
|
# HVAC_MODE_HEAT_COOL is mapped to CONST_MODE_AUTO
|
||||||
|
# This lets tado decide on a temp
|
||||||
|
#
|
||||||
|
# HVAC_MODE_AUTO is mapped to CONST_MODE_SMART_SCHEDULE
|
||||||
|
# This runs the smart schedule
|
||||||
|
#
|
||||||
|
HA_TO_TADO_HVAC_MODE_MAP = {
|
||||||
|
HVAC_MODE_OFF: CONST_MODE_OFF,
|
||||||
|
HVAC_MODE_HEAT_COOL: CONST_MODE_AUTO,
|
||||||
|
HVAC_MODE_AUTO: CONST_MODE_SMART_SCHEDULE,
|
||||||
|
HVAC_MODE_HEAT: CONST_MODE_HEAT,
|
||||||
|
HVAC_MODE_COOL: CONST_MODE_COOL,
|
||||||
|
HVAC_MODE_DRY: CONST_MODE_DRY,
|
||||||
|
HVAC_MODE_FAN_ONLY: CONST_MODE_FAN,
|
||||||
|
}
|
||||||
|
|
||||||
|
HA_TO_TADO_FAN_MODE_MAP = {
|
||||||
|
FAN_AUTO: CONST_FAN_AUTO,
|
||||||
|
FAN_OFF: CONST_FAN_OFF,
|
||||||
|
FAN_LOW: CONST_FAN_LOW,
|
||||||
|
FAN_MEDIUM: CONST_FAN_MIDDLE,
|
||||||
|
FAN_HIGH: CONST_FAN_HIGH,
|
||||||
|
}
|
||||||
|
|
||||||
|
TADO_TO_HA_HVAC_MODE_MAP = {
|
||||||
|
value: key for key, value in HA_TO_TADO_HVAC_MODE_MAP.items()
|
||||||
|
}
|
||||||
|
|
||||||
|
TADO_TO_HA_FAN_MODE_MAP = {value: key for key, value in HA_TO_TADO_FAN_MODE_MAP.items()}
|
||||||
|
|
||||||
|
DEFAULT_TADO_PRECISION = 0.1
|
||||||
|
|
||||||
|
SUPPORT_PRESET = [PRESET_AWAY, PRESET_HOME]
|
||||||
|
@ -7,6 +7,6 @@
|
|||||||
],
|
],
|
||||||
"dependencies": [],
|
"dependencies": [],
|
||||||
"codeowners": [
|
"codeowners": [
|
||||||
"@michaelarnauts"
|
"@michaelarnauts", "@bdraco"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -31,6 +31,7 @@ ZONE_SENSORS = {
|
|||||||
"ac",
|
"ac",
|
||||||
"tado mode",
|
"tado mode",
|
||||||
"overlay",
|
"overlay",
|
||||||
|
"open window",
|
||||||
],
|
],
|
||||||
TYPE_HOT_WATER: ["power", "link", "tado mode", "overlay"],
|
TYPE_HOT_WATER: ["power", "link", "tado mode", "overlay"],
|
||||||
}
|
}
|
||||||
@ -46,20 +47,27 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
|
|||||||
|
|
||||||
for tado in api_list:
|
for tado in api_list:
|
||||||
# Create zone sensors
|
# Create zone sensors
|
||||||
|
zones = tado.zones
|
||||||
|
devices = tado.devices
|
||||||
|
|
||||||
|
for zone in zones:
|
||||||
|
zone_type = zone["type"]
|
||||||
|
if zone_type not in ZONE_SENSORS:
|
||||||
|
_LOGGER.warning("Unknown zone type skipped: %s", zone_type)
|
||||||
|
continue
|
||||||
|
|
||||||
for zone in tado.zones:
|
|
||||||
entities.extend(
|
entities.extend(
|
||||||
[
|
[
|
||||||
create_zone_sensor(tado, zone["name"], zone["id"], variable)
|
TadoZoneSensor(tado, zone["name"], zone["id"], variable)
|
||||||
for variable in ZONE_SENSORS.get(zone["type"])
|
for variable in ZONE_SENSORS[zone_type]
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
# Create device sensors
|
# Create device sensors
|
||||||
for home in tado.devices:
|
for device in devices:
|
||||||
entities.extend(
|
entities.extend(
|
||||||
[
|
[
|
||||||
create_device_sensor(tado, home["name"], home["id"], variable)
|
TadoDeviceSensor(tado, device["name"], device["id"], variable)
|
||||||
for variable in DEVICE_SENSORS
|
for variable in DEVICE_SENSORS
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
@ -67,46 +75,38 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
|
|||||||
add_entities(entities, True)
|
add_entities(entities, True)
|
||||||
|
|
||||||
|
|
||||||
def create_zone_sensor(tado, name, zone_id, variable):
|
class TadoZoneSensor(Entity):
|
||||||
"""Create a zone sensor."""
|
|
||||||
return TadoSensor(tado, name, "zone", zone_id, variable)
|
|
||||||
|
|
||||||
|
|
||||||
def create_device_sensor(tado, name, device_id, variable):
|
|
||||||
"""Create a device sensor."""
|
|
||||||
return TadoSensor(tado, name, "device", device_id, variable)
|
|
||||||
|
|
||||||
|
|
||||||
class TadoSensor(Entity):
|
|
||||||
"""Representation of a tado Sensor."""
|
"""Representation of a tado Sensor."""
|
||||||
|
|
||||||
def __init__(self, tado, zone_name, sensor_type, zone_id, zone_variable):
|
def __init__(self, tado, zone_name, zone_id, zone_variable):
|
||||||
"""Initialize of the Tado Sensor."""
|
"""Initialize of the Tado Sensor."""
|
||||||
self._tado = tado
|
self._tado = tado
|
||||||
|
|
||||||
self.zone_name = zone_name
|
self.zone_name = zone_name
|
||||||
self.zone_id = zone_id
|
self.zone_id = zone_id
|
||||||
self.zone_variable = zone_variable
|
self.zone_variable = zone_variable
|
||||||
self.sensor_type = sensor_type
|
|
||||||
|
|
||||||
self._unique_id = f"{zone_variable} {zone_id} {tado.device_id}"
|
self._unique_id = f"{zone_variable} {zone_id} {tado.device_id}"
|
||||||
|
|
||||||
self._state = None
|
self._state = None
|
||||||
self._state_attributes = None
|
self._state_attributes = None
|
||||||
|
self._tado_zone_data = None
|
||||||
|
self._undo_dispatcher = None
|
||||||
|
|
||||||
|
async def async_will_remove_from_hass(self):
|
||||||
|
"""When entity will be removed from hass."""
|
||||||
|
if self._undo_dispatcher:
|
||||||
|
self._undo_dispatcher()
|
||||||
|
|
||||||
async def async_added_to_hass(self):
|
async def async_added_to_hass(self):
|
||||||
"""Register for sensor updates."""
|
"""Register for sensor updates."""
|
||||||
|
|
||||||
@callback
|
self._undo_dispatcher = async_dispatcher_connect(
|
||||||
def async_update_callback():
|
|
||||||
"""Schedule an entity update."""
|
|
||||||
self.async_schedule_update_ha_state(True)
|
|
||||||
|
|
||||||
async_dispatcher_connect(
|
|
||||||
self.hass,
|
self.hass,
|
||||||
SIGNAL_TADO_UPDATE_RECEIVED.format(self.sensor_type, self.zone_id),
|
SIGNAL_TADO_UPDATE_RECEIVED.format("zone", self.zone_id),
|
||||||
async_update_callback,
|
self._async_update_callback,
|
||||||
)
|
)
|
||||||
|
self._async_update_zone_data()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def unique_id(self):
|
def unique_id(self):
|
||||||
@ -138,7 +138,7 @@ class TadoSensor(Entity):
|
|||||||
if self.zone_variable == "heating":
|
if self.zone_variable == "heating":
|
||||||
return UNIT_PERCENTAGE
|
return UNIT_PERCENTAGE
|
||||||
if self.zone_variable == "ac":
|
if self.zone_variable == "ac":
|
||||||
return ""
|
return None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def icon(self):
|
def icon(self):
|
||||||
@ -149,97 +149,143 @@ class TadoSensor(Entity):
|
|||||||
return "mdi:water-percent"
|
return "mdi:water-percent"
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def should_poll(self) -> bool:
|
def should_poll(self):
|
||||||
"""Do not poll."""
|
"""Do not poll."""
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def update(self):
|
@callback
|
||||||
|
def _async_update_callback(self):
|
||||||
|
"""Update and write state."""
|
||||||
|
self._async_update_zone_data()
|
||||||
|
self.async_write_ha_state()
|
||||||
|
|
||||||
|
@callback
|
||||||
|
def _async_update_zone_data(self):
|
||||||
"""Handle update callbacks."""
|
"""Handle update callbacks."""
|
||||||
try:
|
try:
|
||||||
data = self._tado.data[self.sensor_type][self.zone_id]
|
self._tado_zone_data = self._tado.data["zone"][self.zone_id]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
return
|
return
|
||||||
|
|
||||||
unit = TEMP_CELSIUS
|
|
||||||
|
|
||||||
if self.zone_variable == "temperature":
|
if self.zone_variable == "temperature":
|
||||||
if "sensorDataPoints" in data:
|
self._state = self.hass.config.units.temperature(
|
||||||
sensor_data = data["sensorDataPoints"]
|
self._tado_zone_data.current_temp, TEMP_CELSIUS
|
||||||
temperature = float(sensor_data["insideTemperature"]["celsius"])
|
)
|
||||||
|
self._state_attributes = {
|
||||||
self._state = self.hass.config.units.temperature(temperature, unit)
|
"time": self._tado_zone_data.current_temp_timestamp,
|
||||||
self._state_attributes = {
|
"setting": 0, # setting is used in climate device
|
||||||
"time": sensor_data["insideTemperature"]["timestamp"],
|
}
|
||||||
"setting": 0, # setting is used in climate device
|
|
||||||
}
|
|
||||||
|
|
||||||
# temperature setting will not exist when device is off
|
|
||||||
if (
|
|
||||||
"temperature" in data["setting"]
|
|
||||||
and data["setting"]["temperature"] is not None
|
|
||||||
):
|
|
||||||
temperature = float(data["setting"]["temperature"]["celsius"])
|
|
||||||
|
|
||||||
self._state_attributes[
|
|
||||||
"setting"
|
|
||||||
] = self.hass.config.units.temperature(temperature, unit)
|
|
||||||
|
|
||||||
elif self.zone_variable == "humidity":
|
elif self.zone_variable == "humidity":
|
||||||
if "sensorDataPoints" in data:
|
self._state = self._tado_zone_data.current_humidity
|
||||||
sensor_data = data["sensorDataPoints"]
|
self._state_attributes = {
|
||||||
self._state = float(sensor_data["humidity"]["percentage"])
|
"time": self._tado_zone_data.current_humidity_timestamp
|
||||||
self._state_attributes = {"time": sensor_data["humidity"]["timestamp"]}
|
}
|
||||||
|
|
||||||
elif self.zone_variable == "power":
|
elif self.zone_variable == "power":
|
||||||
if "setting" in data:
|
self._state = self._tado_zone_data.power
|
||||||
self._state = data["setting"]["power"]
|
|
||||||
|
|
||||||
elif self.zone_variable == "link":
|
elif self.zone_variable == "link":
|
||||||
if "link" in data:
|
self._state = self._tado_zone_data.link
|
||||||
self._state = data["link"]["state"]
|
|
||||||
|
|
||||||
elif self.zone_variable == "heating":
|
elif self.zone_variable == "heating":
|
||||||
if "activityDataPoints" in data:
|
self._state = self._tado_zone_data.heating_power_percentage
|
||||||
activity_data = data["activityDataPoints"]
|
self._state_attributes = {
|
||||||
|
"time": self._tado_zone_data.heating_power_timestamp
|
||||||
if (
|
}
|
||||||
"heatingPower" in activity_data
|
|
||||||
and activity_data["heatingPower"] is not None
|
|
||||||
):
|
|
||||||
self._state = float(activity_data["heatingPower"]["percentage"])
|
|
||||||
self._state_attributes = {
|
|
||||||
"time": activity_data["heatingPower"]["timestamp"]
|
|
||||||
}
|
|
||||||
|
|
||||||
elif self.zone_variable == "ac":
|
elif self.zone_variable == "ac":
|
||||||
if "activityDataPoints" in data:
|
self._state = self._tado_zone_data.ac_power
|
||||||
activity_data = data["activityDataPoints"]
|
self._state_attributes = {"time": self._tado_zone_data.ac_power_timestamp}
|
||||||
|
|
||||||
if "acPower" in activity_data and activity_data["acPower"] is not None:
|
|
||||||
self._state = activity_data["acPower"]["value"]
|
|
||||||
self._state_attributes = {
|
|
||||||
"time": activity_data["acPower"]["timestamp"]
|
|
||||||
}
|
|
||||||
|
|
||||||
elif self.zone_variable == "tado bridge status":
|
elif self.zone_variable == "tado bridge status":
|
||||||
if "connectionState" in data:
|
self._state = self._tado_zone_data.connection
|
||||||
self._state = data["connectionState"]["value"]
|
|
||||||
|
|
||||||
elif self.zone_variable == "tado mode":
|
elif self.zone_variable == "tado mode":
|
||||||
if "tadoMode" in data:
|
self._state = self._tado_zone_data.tado_mode
|
||||||
self._state = data["tadoMode"]
|
|
||||||
|
|
||||||
elif self.zone_variable == "overlay":
|
elif self.zone_variable == "overlay":
|
||||||
self._state = "overlay" in data and data["overlay"] is not None
|
self._state = self._tado_zone_data.overlay_active
|
||||||
self._state_attributes = (
|
self._state_attributes = (
|
||||||
{"termination": data["overlay"]["termination"]["type"]}
|
{"termination": self._tado_zone_data.overlay_termination_type}
|
||||||
if self._state
|
if self._tado_zone_data.overlay_active
|
||||||
else {}
|
else {}
|
||||||
)
|
)
|
||||||
|
|
||||||
elif self.zone_variable == "early start":
|
elif self.zone_variable == "early start":
|
||||||
self._state = "preparation" in data and data["preparation"] is not None
|
self._state = self._tado_zone_data.preparation
|
||||||
|
|
||||||
elif self.zone_variable == "open window":
|
elif self.zone_variable == "open window":
|
||||||
self._state = "openWindow" in data and data["openWindow"] is not None
|
self._state = self._tado_zone_data.open_window
|
||||||
self._state_attributes = data["openWindow"] if self._state else {}
|
self._state_attributes = self._tado_zone_data.open_window_attr
|
||||||
|
|
||||||
|
|
||||||
|
class TadoDeviceSensor(Entity):
|
||||||
|
"""Representation of a tado Sensor."""
|
||||||
|
|
||||||
|
def __init__(self, tado, device_name, device_id, device_variable):
|
||||||
|
"""Initialize of the Tado Sensor."""
|
||||||
|
self._tado = tado
|
||||||
|
|
||||||
|
self.device_name = device_name
|
||||||
|
self.device_id = device_id
|
||||||
|
self.device_variable = device_variable
|
||||||
|
|
||||||
|
self._unique_id = f"{device_variable} {device_id} {tado.device_id}"
|
||||||
|
|
||||||
|
self._state = None
|
||||||
|
self._state_attributes = None
|
||||||
|
self._tado_device_data = None
|
||||||
|
self._undo_dispatcher = None
|
||||||
|
|
||||||
|
async def async_will_remove_from_hass(self):
|
||||||
|
"""When entity will be removed from hass."""
|
||||||
|
if self._undo_dispatcher:
|
||||||
|
self._undo_dispatcher()
|
||||||
|
|
||||||
|
async def async_added_to_hass(self):
|
||||||
|
"""Register for sensor updates."""
|
||||||
|
|
||||||
|
self._undo_dispatcher = async_dispatcher_connect(
|
||||||
|
self.hass,
|
||||||
|
SIGNAL_TADO_UPDATE_RECEIVED.format("device", self.device_id),
|
||||||
|
self._async_update_callback,
|
||||||
|
)
|
||||||
|
self._async_update_device_data()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def unique_id(self):
|
||||||
|
"""Return the unique id."""
|
||||||
|
return self._unique_id
|
||||||
|
|
||||||
|
@property
|
||||||
|
def name(self):
|
||||||
|
"""Return the name of the sensor."""
|
||||||
|
return f"{self.device_name} {self.device_variable}"
|
||||||
|
|
||||||
|
@property
|
||||||
|
def state(self):
|
||||||
|
"""Return the state of the sensor."""
|
||||||
|
return self._state
|
||||||
|
|
||||||
|
@property
|
||||||
|
def should_poll(self):
|
||||||
|
"""Do not poll."""
|
||||||
|
return False
|
||||||
|
|
||||||
|
@callback
|
||||||
|
def _async_update_callback(self):
|
||||||
|
"""Update and write state."""
|
||||||
|
self._async_update_device_data()
|
||||||
|
self.async_write_ha_state()
|
||||||
|
|
||||||
|
@callback
|
||||||
|
def _async_update_device_data(self):
|
||||||
|
"""Handle update callbacks."""
|
||||||
|
try:
|
||||||
|
data = self._tado.data["device"][self.device_id]
|
||||||
|
except KeyError:
|
||||||
|
return
|
||||||
|
|
||||||
|
if self.device_variable == "tado bridge status":
|
||||||
|
self._state = data.get("connectionState", {}).get("value", False)
|
||||||
|
@ -12,6 +12,9 @@ from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
|||||||
|
|
||||||
from . import DOMAIN, SIGNAL_TADO_UPDATE_RECEIVED
|
from . import DOMAIN, SIGNAL_TADO_UPDATE_RECEIVED
|
||||||
from .const import (
|
from .const import (
|
||||||
|
CONST_HVAC_HEAT,
|
||||||
|
CONST_MODE_AUTO,
|
||||||
|
CONST_MODE_HEAT,
|
||||||
CONST_MODE_OFF,
|
CONST_MODE_OFF,
|
||||||
CONST_MODE_SMART_SCHEDULE,
|
CONST_MODE_SMART_SCHEDULE,
|
||||||
CONST_OVERLAY_MANUAL,
|
CONST_OVERLAY_MANUAL,
|
||||||
@ -33,6 +36,7 @@ WATER_HEATER_MAP_TADO = {
|
|||||||
CONST_OVERLAY_MANUAL: MODE_HEAT,
|
CONST_OVERLAY_MANUAL: MODE_HEAT,
|
||||||
CONST_OVERLAY_TIMER: MODE_HEAT,
|
CONST_OVERLAY_TIMER: MODE_HEAT,
|
||||||
CONST_OVERLAY_TADO_MODE: MODE_HEAT,
|
CONST_OVERLAY_TADO_MODE: MODE_HEAT,
|
||||||
|
CONST_HVAC_HEAT: MODE_HEAT,
|
||||||
CONST_MODE_SMART_SCHEDULE: MODE_AUTO,
|
CONST_MODE_SMART_SCHEDULE: MODE_AUTO,
|
||||||
CONST_MODE_OFF: MODE_OFF,
|
CONST_MODE_OFF: MODE_OFF,
|
||||||
}
|
}
|
||||||
@ -50,7 +54,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
|
|||||||
|
|
||||||
for tado in api_list:
|
for tado in api_list:
|
||||||
for zone in tado.zones:
|
for zone in tado.zones:
|
||||||
if zone["type"] in [TYPE_HOT_WATER]:
|
if zone["type"] == TYPE_HOT_WATER:
|
||||||
entity = create_water_heater_entity(tado, zone["name"], zone["id"])
|
entity = create_water_heater_entity(tado, zone["name"], zone["id"])
|
||||||
entities.append(entity)
|
entities.append(entity)
|
||||||
|
|
||||||
@ -61,6 +65,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
|
|||||||
def create_water_heater_entity(tado, name: str, zone_id: int):
|
def create_water_heater_entity(tado, name: str, zone_id: int):
|
||||||
"""Create a Tado water heater device."""
|
"""Create a Tado water heater device."""
|
||||||
capabilities = tado.get_capabilities(zone_id)
|
capabilities = tado.get_capabilities(zone_id)
|
||||||
|
|
||||||
supports_temperature_control = capabilities["canSetTemperature"]
|
supports_temperature_control = capabilities["canSetTemperature"]
|
||||||
|
|
||||||
if supports_temperature_control and "temperatures" in capabilities:
|
if supports_temperature_control and "temperatures" in capabilities:
|
||||||
@ -98,7 +103,6 @@ class TadoWaterHeater(WaterHeaterDevice):
|
|||||||
self._unique_id = f"{zone_id} {tado.device_id}"
|
self._unique_id = f"{zone_id} {tado.device_id}"
|
||||||
|
|
||||||
self._device_is_active = False
|
self._device_is_active = False
|
||||||
self._is_away = False
|
|
||||||
|
|
||||||
self._supports_temperature_control = supports_temperature_control
|
self._supports_temperature_control = supports_temperature_control
|
||||||
self._min_temperature = min_temp
|
self._min_temperature = min_temp
|
||||||
@ -110,29 +114,25 @@ class TadoWaterHeater(WaterHeaterDevice):
|
|||||||
if self._supports_temperature_control:
|
if self._supports_temperature_control:
|
||||||
self._supported_features |= SUPPORT_TARGET_TEMPERATURE
|
self._supported_features |= SUPPORT_TARGET_TEMPERATURE
|
||||||
|
|
||||||
if tado.fallback:
|
self._current_tado_hvac_mode = CONST_MODE_SMART_SCHEDULE
|
||||||
# Fallback to Smart Schedule at next Schedule switch
|
|
||||||
self._default_overlay = CONST_OVERLAY_TADO_MODE
|
|
||||||
else:
|
|
||||||
# Don't fallback to Smart Schedule, but keep in manual mode
|
|
||||||
self._default_overlay = CONST_OVERLAY_MANUAL
|
|
||||||
|
|
||||||
self._current_operation = CONST_MODE_SMART_SCHEDULE
|
|
||||||
self._overlay_mode = CONST_MODE_SMART_SCHEDULE
|
self._overlay_mode = CONST_MODE_SMART_SCHEDULE
|
||||||
|
self._tado_zone_data = None
|
||||||
|
self._undo_dispatcher = None
|
||||||
|
|
||||||
|
async def async_will_remove_from_hass(self):
|
||||||
|
"""When entity will be removed from hass."""
|
||||||
|
if self._undo_dispatcher:
|
||||||
|
self._undo_dispatcher()
|
||||||
|
|
||||||
async def async_added_to_hass(self):
|
async def async_added_to_hass(self):
|
||||||
"""Register for sensor updates."""
|
"""Register for sensor updates."""
|
||||||
|
|
||||||
@callback
|
self._undo_dispatcher = async_dispatcher_connect(
|
||||||
def async_update_callback():
|
|
||||||
"""Schedule an entity update."""
|
|
||||||
self.async_schedule_update_ha_state(True)
|
|
||||||
|
|
||||||
async_dispatcher_connect(
|
|
||||||
self.hass,
|
self.hass,
|
||||||
SIGNAL_TADO_UPDATE_RECEIVED.format("zone", self.zone_id),
|
SIGNAL_TADO_UPDATE_RECEIVED.format("zone", self.zone_id),
|
||||||
async_update_callback,
|
self._async_update_callback,
|
||||||
)
|
)
|
||||||
|
self._async_update_data()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def supported_features(self):
|
def supported_features(self):
|
||||||
@ -157,17 +157,17 @@ class TadoWaterHeater(WaterHeaterDevice):
|
|||||||
@property
|
@property
|
||||||
def current_operation(self):
|
def current_operation(self):
|
||||||
"""Return current readable operation mode."""
|
"""Return current readable operation mode."""
|
||||||
return WATER_HEATER_MAP_TADO.get(self._current_operation)
|
return WATER_HEATER_MAP_TADO.get(self._current_tado_hvac_mode)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def target_temperature(self):
|
def target_temperature(self):
|
||||||
"""Return the temperature we try to reach."""
|
"""Return the temperature we try to reach."""
|
||||||
return self._target_temp
|
return self._tado_zone_data.target_temp
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_away_mode_on(self):
|
def is_away_mode_on(self):
|
||||||
"""Return true if away mode is on."""
|
"""Return true if away mode is on."""
|
||||||
return self._is_away
|
return self._tado_zone_data.is_away
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def operation_list(self):
|
def operation_list(self):
|
||||||
@ -198,16 +198,9 @@ class TadoWaterHeater(WaterHeaterDevice):
|
|||||||
elif operation_mode == MODE_AUTO:
|
elif operation_mode == MODE_AUTO:
|
||||||
mode = CONST_MODE_SMART_SCHEDULE
|
mode = CONST_MODE_SMART_SCHEDULE
|
||||||
elif operation_mode == MODE_HEAT:
|
elif operation_mode == MODE_HEAT:
|
||||||
mode = self._default_overlay
|
mode = CONST_MODE_HEAT
|
||||||
|
|
||||||
self._current_operation = mode
|
self._control_heater(hvac_mode=mode)
|
||||||
self._overlay_mode = None
|
|
||||||
|
|
||||||
# Set a target temperature if we don't have any
|
|
||||||
if mode == CONST_OVERLAY_TADO_MODE and self._target_temp is None:
|
|
||||||
self._target_temp = self.min_temp
|
|
||||||
|
|
||||||
self._control_heater()
|
|
||||||
|
|
||||||
def set_temperature(self, **kwargs):
|
def set_temperature(self, **kwargs):
|
||||||
"""Set new target temperature."""
|
"""Set new target temperature."""
|
||||||
@ -215,88 +208,75 @@ class TadoWaterHeater(WaterHeaterDevice):
|
|||||||
if not self._supports_temperature_control or temperature is None:
|
if not self._supports_temperature_control or temperature is None:
|
||||||
return
|
return
|
||||||
|
|
||||||
self._current_operation = self._default_overlay
|
if self._current_tado_hvac_mode not in (
|
||||||
self._overlay_mode = None
|
CONST_MODE_OFF,
|
||||||
self._target_temp = temperature
|
CONST_MODE_AUTO,
|
||||||
self._control_heater()
|
CONST_MODE_SMART_SCHEDULE,
|
||||||
|
|
||||||
def update(self):
|
|
||||||
"""Handle update callbacks."""
|
|
||||||
_LOGGER.debug("Updating water_heater platform for zone %d", self.zone_id)
|
|
||||||
data = self._tado.data["zone"][self.zone_id]
|
|
||||||
|
|
||||||
if "tadoMode" in data:
|
|
||||||
mode = data["tadoMode"]
|
|
||||||
self._is_away = mode == "AWAY"
|
|
||||||
|
|
||||||
if "setting" in data:
|
|
||||||
power = data["setting"]["power"]
|
|
||||||
if power == "OFF":
|
|
||||||
self._current_operation = CONST_MODE_OFF
|
|
||||||
# There is no overlay, the mode will always be
|
|
||||||
# "SMART_SCHEDULE"
|
|
||||||
self._overlay_mode = CONST_MODE_SMART_SCHEDULE
|
|
||||||
self._device_is_active = False
|
|
||||||
else:
|
|
||||||
self._device_is_active = True
|
|
||||||
|
|
||||||
# temperature setting will not exist when device is off
|
|
||||||
if (
|
|
||||||
"temperature" in data["setting"]
|
|
||||||
and data["setting"]["temperature"] is not None
|
|
||||||
):
|
):
|
||||||
setting = float(data["setting"]["temperature"]["celsius"])
|
self._control_heater(target_temp=temperature)
|
||||||
self._target_temp = setting
|
return
|
||||||
|
|
||||||
overlay = False
|
self._control_heater(target_temp=temperature, hvac_mode=CONST_MODE_HEAT)
|
||||||
overlay_data = None
|
|
||||||
termination = CONST_MODE_SMART_SCHEDULE
|
|
||||||
|
|
||||||
if "overlay" in data:
|
@callback
|
||||||
overlay_data = data["overlay"]
|
def _async_update_callback(self):
|
||||||
overlay = overlay_data is not None
|
"""Load tado data and update state."""
|
||||||
|
self._async_update_data()
|
||||||
|
self.async_write_ha_state()
|
||||||
|
|
||||||
if overlay:
|
@callback
|
||||||
termination = overlay_data["termination"]["type"]
|
def _async_update_data(self):
|
||||||
|
"""Load tado data."""
|
||||||
|
_LOGGER.debug("Updating water_heater platform for zone %d", self.zone_id)
|
||||||
|
self._tado_zone_data = self._tado.data["zone"][self.zone_id]
|
||||||
|
self._current_tado_hvac_mode = self._tado_zone_data.current_hvac_mode
|
||||||
|
|
||||||
if self._device_is_active:
|
def _control_heater(self, hvac_mode=None, target_temp=None):
|
||||||
# If you set mode manually to off, there will be an overlay
|
|
||||||
# and a termination, but we want to see the mode "OFF"
|
|
||||||
self._overlay_mode = termination
|
|
||||||
self._current_operation = termination
|
|
||||||
|
|
||||||
def _control_heater(self):
|
|
||||||
"""Send new target temperature."""
|
"""Send new target temperature."""
|
||||||
if self._current_operation == CONST_MODE_SMART_SCHEDULE:
|
|
||||||
|
if hvac_mode:
|
||||||
|
self._current_tado_hvac_mode = hvac_mode
|
||||||
|
|
||||||
|
if target_temp:
|
||||||
|
self._target_temp = target_temp
|
||||||
|
|
||||||
|
# Set a target temperature if we don't have any
|
||||||
|
if self._target_temp is None:
|
||||||
|
self._target_temp = self.min_temp
|
||||||
|
|
||||||
|
if self._current_tado_hvac_mode == CONST_MODE_SMART_SCHEDULE:
|
||||||
_LOGGER.debug(
|
_LOGGER.debug(
|
||||||
"Switching to SMART_SCHEDULE for zone %s (%d)",
|
"Switching to SMART_SCHEDULE for zone %s (%d)",
|
||||||
self.zone_name,
|
self.zone_name,
|
||||||
self.zone_id,
|
self.zone_id,
|
||||||
)
|
)
|
||||||
self._tado.reset_zone_overlay(self.zone_id)
|
self._tado.reset_zone_overlay(self.zone_id)
|
||||||
self._overlay_mode = self._current_operation
|
|
||||||
return
|
return
|
||||||
|
|
||||||
if self._current_operation == CONST_MODE_OFF:
|
if self._current_tado_hvac_mode == CONST_MODE_OFF:
|
||||||
_LOGGER.debug(
|
_LOGGER.debug(
|
||||||
"Switching to OFF for zone %s (%d)", self.zone_name, self.zone_id
|
"Switching to OFF for zone %s (%d)", self.zone_name, self.zone_id
|
||||||
)
|
)
|
||||||
self._tado.set_zone_off(self.zone_id, CONST_OVERLAY_MANUAL, TYPE_HOT_WATER)
|
self._tado.set_zone_off(self.zone_id, CONST_OVERLAY_MANUAL, TYPE_HOT_WATER)
|
||||||
self._overlay_mode = self._current_operation
|
|
||||||
return
|
return
|
||||||
|
|
||||||
|
# Fallback to Smart Schedule at next Schedule switch if we have fallback enabled
|
||||||
|
overlay_mode = (
|
||||||
|
CONST_OVERLAY_TADO_MODE if self._tado.fallback else CONST_OVERLAY_MANUAL
|
||||||
|
)
|
||||||
|
|
||||||
_LOGGER.debug(
|
_LOGGER.debug(
|
||||||
"Switching to %s for zone %s (%d) with temperature %s",
|
"Switching to %s for zone %s (%d) with temperature %s",
|
||||||
self._current_operation,
|
self._current_tado_hvac_mode,
|
||||||
self.zone_name,
|
self.zone_name,
|
||||||
self.zone_id,
|
self.zone_id,
|
||||||
self._target_temp,
|
self._target_temp,
|
||||||
)
|
)
|
||||||
self._tado.set_zone_overlay(
|
self._tado.set_zone_overlay(
|
||||||
self.zone_id,
|
zone_id=self.zone_id,
|
||||||
self._current_operation,
|
overlay_mode=overlay_mode,
|
||||||
self._target_temp,
|
temperature=self._target_temp,
|
||||||
None,
|
duration=None,
|
||||||
TYPE_HOT_WATER,
|
device_type=TYPE_HOT_WATER,
|
||||||
)
|
)
|
||||||
self._overlay_mode = self._current_operation
|
self._overlay_mode = self._current_tado_hvac_mode
|
||||||
|
@ -616,6 +616,9 @@ python-miio==0.4.8
|
|||||||
# homeassistant.components.nest
|
# homeassistant.components.nest
|
||||||
python-nest==4.1.0
|
python-nest==4.1.0
|
||||||
|
|
||||||
|
# homeassistant.components.tado
|
||||||
|
python-tado==0.5.0
|
||||||
|
|
||||||
# homeassistant.components.twitch
|
# homeassistant.components.twitch
|
||||||
python-twitch-client==0.6.0
|
python-twitch-client==0.6.0
|
||||||
|
|
||||||
|
1
tests/components/tado/__init__.py
Normal file
1
tests/components/tado/__init__.py
Normal file
@ -0,0 +1 @@
|
|||||||
|
"""Tests for the tado integration."""
|
59
tests/components/tado/test_climate.py
Normal file
59
tests/components/tado/test_climate.py
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
"""The sensor tests for the tado platform."""
|
||||||
|
|
||||||
|
from .util import async_init_integration
|
||||||
|
|
||||||
|
|
||||||
|
async def test_air_con(hass):
|
||||||
|
"""Test creation of aircon climate."""
|
||||||
|
|
||||||
|
await async_init_integration(hass)
|
||||||
|
|
||||||
|
state = hass.states.get("climate.air_conditioning")
|
||||||
|
assert state.state == "cool"
|
||||||
|
|
||||||
|
expected_attributes = {
|
||||||
|
"current_humidity": 60.9,
|
||||||
|
"current_temperature": 24.8,
|
||||||
|
"fan_mode": "auto",
|
||||||
|
"fan_modes": ["auto", "high", "medium", "low"],
|
||||||
|
"friendly_name": "Air Conditioning",
|
||||||
|
"hvac_action": "cooling",
|
||||||
|
"hvac_modes": ["off", "auto", "heat", "cool", "heat_cool", "dry", "fan_only"],
|
||||||
|
"max_temp": 31.0,
|
||||||
|
"min_temp": 16.0,
|
||||||
|
"preset_mode": "home",
|
||||||
|
"preset_modes": ["away", "home"],
|
||||||
|
"supported_features": 25,
|
||||||
|
"target_temp_step": 1,
|
||||||
|
"temperature": 17.8,
|
||||||
|
}
|
||||||
|
# Only test for a subset of attributes in case
|
||||||
|
# HA changes the implementation and a new one appears
|
||||||
|
assert all(item in state.attributes.items() for item in expected_attributes.items())
|
||||||
|
|
||||||
|
|
||||||
|
async def test_heater(hass):
|
||||||
|
"""Test creation of heater climate."""
|
||||||
|
|
||||||
|
await async_init_integration(hass)
|
||||||
|
|
||||||
|
state = hass.states.get("climate.baseboard_heater")
|
||||||
|
assert state.state == "heat"
|
||||||
|
|
||||||
|
expected_attributes = {
|
||||||
|
"current_humidity": 45.2,
|
||||||
|
"current_temperature": 20.6,
|
||||||
|
"friendly_name": "Baseboard Heater",
|
||||||
|
"hvac_action": "idle",
|
||||||
|
"hvac_modes": ["off", "auto", "heat"],
|
||||||
|
"max_temp": 31.0,
|
||||||
|
"min_temp": 16.0,
|
||||||
|
"preset_mode": "home",
|
||||||
|
"preset_modes": ["away", "home"],
|
||||||
|
"supported_features": 17,
|
||||||
|
"target_temp_step": 1,
|
||||||
|
"temperature": 20.5,
|
||||||
|
}
|
||||||
|
# Only test for a subset of attributes in case
|
||||||
|
# HA changes the implementation and a new one appears
|
||||||
|
assert all(item in state.attributes.items() for item in expected_attributes.items())
|
96
tests/components/tado/test_sensor.py
Normal file
96
tests/components/tado/test_sensor.py
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
"""The sensor tests for the tado platform."""
|
||||||
|
|
||||||
|
from .util import async_init_integration
|
||||||
|
|
||||||
|
|
||||||
|
async def test_air_con_create_sensors(hass):
|
||||||
|
"""Test creation of aircon sensors."""
|
||||||
|
|
||||||
|
await async_init_integration(hass)
|
||||||
|
|
||||||
|
state = hass.states.get("sensor.air_conditioning_power")
|
||||||
|
assert state.state == "ON"
|
||||||
|
|
||||||
|
state = hass.states.get("sensor.air_conditioning_link")
|
||||||
|
assert state.state == "ONLINE"
|
||||||
|
|
||||||
|
state = hass.states.get("sensor.air_conditioning_link")
|
||||||
|
assert state.state == "ONLINE"
|
||||||
|
|
||||||
|
state = hass.states.get("sensor.air_conditioning_tado_mode")
|
||||||
|
assert state.state == "HOME"
|
||||||
|
|
||||||
|
state = hass.states.get("sensor.air_conditioning_temperature")
|
||||||
|
assert state.state == "24.76"
|
||||||
|
|
||||||
|
state = hass.states.get("sensor.air_conditioning_ac")
|
||||||
|
assert state.state == "ON"
|
||||||
|
|
||||||
|
state = hass.states.get("sensor.air_conditioning_overlay")
|
||||||
|
assert state.state == "True"
|
||||||
|
|
||||||
|
state = hass.states.get("sensor.air_conditioning_humidity")
|
||||||
|
assert state.state == "60.9"
|
||||||
|
|
||||||
|
state = hass.states.get("sensor.air_conditioning_open_window")
|
||||||
|
assert state.state == "False"
|
||||||
|
|
||||||
|
|
||||||
|
async def test_heater_create_sensors(hass):
|
||||||
|
"""Test creation of heater sensors."""
|
||||||
|
|
||||||
|
await async_init_integration(hass)
|
||||||
|
|
||||||
|
state = hass.states.get("sensor.baseboard_heater_power")
|
||||||
|
assert state.state == "ON"
|
||||||
|
|
||||||
|
state = hass.states.get("sensor.baseboard_heater_link")
|
||||||
|
assert state.state == "ONLINE"
|
||||||
|
|
||||||
|
state = hass.states.get("sensor.baseboard_heater_link")
|
||||||
|
assert state.state == "ONLINE"
|
||||||
|
|
||||||
|
state = hass.states.get("sensor.baseboard_heater_tado_mode")
|
||||||
|
assert state.state == "HOME"
|
||||||
|
|
||||||
|
state = hass.states.get("sensor.baseboard_heater_temperature")
|
||||||
|
assert state.state == "20.65"
|
||||||
|
|
||||||
|
state = hass.states.get("sensor.baseboard_heater_early_start")
|
||||||
|
assert state.state == "False"
|
||||||
|
|
||||||
|
state = hass.states.get("sensor.baseboard_heater_overlay")
|
||||||
|
assert state.state == "True"
|
||||||
|
|
||||||
|
state = hass.states.get("sensor.baseboard_heater_humidity")
|
||||||
|
assert state.state == "45.2"
|
||||||
|
|
||||||
|
state = hass.states.get("sensor.baseboard_heater_open_window")
|
||||||
|
assert state.state == "False"
|
||||||
|
|
||||||
|
|
||||||
|
async def test_water_heater_create_sensors(hass):
|
||||||
|
"""Test creation of water heater sensors."""
|
||||||
|
|
||||||
|
await async_init_integration(hass)
|
||||||
|
|
||||||
|
state = hass.states.get("sensor.water_heater_tado_mode")
|
||||||
|
assert state.state == "HOME"
|
||||||
|
|
||||||
|
state = hass.states.get("sensor.water_heater_link")
|
||||||
|
assert state.state == "ONLINE"
|
||||||
|
|
||||||
|
state = hass.states.get("sensor.water_heater_overlay")
|
||||||
|
assert state.state == "False"
|
||||||
|
|
||||||
|
state = hass.states.get("sensor.water_heater_power")
|
||||||
|
assert state.state == "ON"
|
||||||
|
|
||||||
|
|
||||||
|
async def test_home_create_sensors(hass):
|
||||||
|
"""Test creation of home sensors."""
|
||||||
|
|
||||||
|
await async_init_integration(hass)
|
||||||
|
|
||||||
|
state = hass.states.get("sensor.home_name_tado_bridge_status")
|
||||||
|
assert state.state == "True"
|
47
tests/components/tado/test_water_heater.py
Normal file
47
tests/components/tado/test_water_heater.py
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
"""The sensor tests for the tado platform."""
|
||||||
|
|
||||||
|
from .util import async_init_integration
|
||||||
|
|
||||||
|
|
||||||
|
async def test_water_heater_create_sensors(hass):
|
||||||
|
"""Test creation of water heater."""
|
||||||
|
|
||||||
|
await async_init_integration(hass)
|
||||||
|
|
||||||
|
state = hass.states.get("water_heater.water_heater")
|
||||||
|
assert state.state == "auto"
|
||||||
|
|
||||||
|
expected_attributes = {
|
||||||
|
"current_temperature": None,
|
||||||
|
"friendly_name": "Water Heater",
|
||||||
|
"max_temp": 31.0,
|
||||||
|
"min_temp": 16.0,
|
||||||
|
"operation_list": ["auto", "heat", "off"],
|
||||||
|
"operation_mode": "auto",
|
||||||
|
"supported_features": 3,
|
||||||
|
"target_temp_high": None,
|
||||||
|
"target_temp_low": None,
|
||||||
|
"temperature": 65.0,
|
||||||
|
}
|
||||||
|
# Only test for a subset of attributes in case
|
||||||
|
# HA changes the implementation and a new one appears
|
||||||
|
assert all(item in state.attributes.items() for item in expected_attributes.items())
|
||||||
|
|
||||||
|
state = hass.states.get("water_heater.second_water_heater")
|
||||||
|
assert state.state == "heat"
|
||||||
|
|
||||||
|
expected_attributes = {
|
||||||
|
"current_temperature": None,
|
||||||
|
"friendly_name": "Second Water Heater",
|
||||||
|
"max_temp": 31.0,
|
||||||
|
"min_temp": 16.0,
|
||||||
|
"operation_list": ["auto", "heat", "off"],
|
||||||
|
"operation_mode": "heat",
|
||||||
|
"supported_features": 3,
|
||||||
|
"target_temp_high": None,
|
||||||
|
"target_temp_low": None,
|
||||||
|
"temperature": 30.0,
|
||||||
|
}
|
||||||
|
# Only test for a subset of attributes in case
|
||||||
|
# HA changes the implementation and a new one appears
|
||||||
|
assert all(item in state.attributes.items() for item in expected_attributes.items())
|
86
tests/components/tado/util.py
Normal file
86
tests/components/tado/util.py
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
"""Tests for the tado integration."""
|
||||||
|
|
||||||
|
import requests_mock
|
||||||
|
|
||||||
|
from homeassistant.components.tado import DOMAIN
|
||||||
|
from homeassistant.const import CONF_PASSWORD, CONF_USERNAME
|
||||||
|
from homeassistant.core import HomeAssistant
|
||||||
|
from homeassistant.setup import async_setup_component
|
||||||
|
|
||||||
|
from tests.common import load_fixture
|
||||||
|
|
||||||
|
|
||||||
|
async def async_init_integration(
|
||||||
|
hass: HomeAssistant, skip_setup: bool = False,
|
||||||
|
):
|
||||||
|
"""Set up the tado integration in Home Assistant."""
|
||||||
|
|
||||||
|
token_fixture = "tado/token.json"
|
||||||
|
devices_fixture = "tado/devices.json"
|
||||||
|
me_fixture = "tado/me.json"
|
||||||
|
zones_fixture = "tado/zones.json"
|
||||||
|
# Water Heater 2
|
||||||
|
zone_4_state_fixture = "tado/tadov2.water_heater.heating.json"
|
||||||
|
zone_4_capabilities_fixture = "tado/water_heater_zone_capabilities.json"
|
||||||
|
|
||||||
|
# Smart AC
|
||||||
|
zone_3_state_fixture = "tado/smartac3.cool_mode.json"
|
||||||
|
zone_3_capabilities_fixture = "tado/zone_capabilities.json"
|
||||||
|
|
||||||
|
# Water Heater
|
||||||
|
zone_2_state_fixture = "tado/tadov2.water_heater.auto_mode.json"
|
||||||
|
zone_2_capabilities_fixture = "tado/water_heater_zone_capabilities.json"
|
||||||
|
|
||||||
|
zone_1_state_fixture = "tado/tadov2.heating.manual_mode.json"
|
||||||
|
zone_1_capabilities_fixture = "tado/tadov2.zone_capabilities.json"
|
||||||
|
|
||||||
|
with requests_mock.mock() as m:
|
||||||
|
m.post("https://auth.tado.com/oauth/token", text=load_fixture(token_fixture))
|
||||||
|
m.get(
|
||||||
|
"https://my.tado.com/api/v2/me", text=load_fixture(me_fixture),
|
||||||
|
)
|
||||||
|
m.get(
|
||||||
|
"https://my.tado.com/api/v2/homes/1/devices",
|
||||||
|
text=load_fixture(devices_fixture),
|
||||||
|
)
|
||||||
|
m.get(
|
||||||
|
"https://my.tado.com/api/v2/homes/1/zones",
|
||||||
|
text=load_fixture(zones_fixture),
|
||||||
|
)
|
||||||
|
m.get(
|
||||||
|
"https://my.tado.com/api/v2/homes/1/zones/4/capabilities",
|
||||||
|
text=load_fixture(zone_4_capabilities_fixture),
|
||||||
|
)
|
||||||
|
m.get(
|
||||||
|
"https://my.tado.com/api/v2/homes/1/zones/3/capabilities",
|
||||||
|
text=load_fixture(zone_3_capabilities_fixture),
|
||||||
|
)
|
||||||
|
m.get(
|
||||||
|
"https://my.tado.com/api/v2/homes/1/zones/2/capabilities",
|
||||||
|
text=load_fixture(zone_2_capabilities_fixture),
|
||||||
|
)
|
||||||
|
m.get(
|
||||||
|
"https://my.tado.com/api/v2/homes/1/zones/1/capabilities",
|
||||||
|
text=load_fixture(zone_1_capabilities_fixture),
|
||||||
|
)
|
||||||
|
m.get(
|
||||||
|
"https://my.tado.com/api/v2/homes/1/zones/4/state",
|
||||||
|
text=load_fixture(zone_4_state_fixture),
|
||||||
|
)
|
||||||
|
m.get(
|
||||||
|
"https://my.tado.com/api/v2/homes/1/zones/3/state",
|
||||||
|
text=load_fixture(zone_3_state_fixture),
|
||||||
|
)
|
||||||
|
m.get(
|
||||||
|
"https://my.tado.com/api/v2/homes/1/zones/2/state",
|
||||||
|
text=load_fixture(zone_2_state_fixture),
|
||||||
|
)
|
||||||
|
m.get(
|
||||||
|
"https://my.tado.com/api/v2/homes/1/zones/1/state",
|
||||||
|
text=load_fixture(zone_1_state_fixture),
|
||||||
|
)
|
||||||
|
if not skip_setup:
|
||||||
|
assert await async_setup_component(
|
||||||
|
hass, DOMAIN, {DOMAIN: {CONF_USERNAME: "mock", CONF_PASSWORD: "mock"}}
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
60
tests/fixtures/tado/ac_issue_32294.heat_mode.json
vendored
Normal file
60
tests/fixtures/tado/ac_issue_32294.heat_mode.json
vendored
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
{
|
||||||
|
"tadoMode": "HOME",
|
||||||
|
"sensorDataPoints": {
|
||||||
|
"insideTemperature": {
|
||||||
|
"fahrenheit": 71.28,
|
||||||
|
"timestamp": "2020-02-29T22:51:05.016Z",
|
||||||
|
"celsius": 21.82,
|
||||||
|
"type": "TEMPERATURE",
|
||||||
|
"precision": {
|
||||||
|
"fahrenheit": 0.1,
|
||||||
|
"celsius": 0.1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"humidity": {
|
||||||
|
"timestamp": "2020-02-29T22:51:05.016Z",
|
||||||
|
"percentage": 40.4,
|
||||||
|
"type": "PERCENTAGE"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"link": {
|
||||||
|
"state": "ONLINE"
|
||||||
|
},
|
||||||
|
"openWindow": null,
|
||||||
|
"geolocationOverride": false,
|
||||||
|
"geolocationOverrideDisableTime": null,
|
||||||
|
"overlay": null,
|
||||||
|
"activityDataPoints": {
|
||||||
|
"acPower": {
|
||||||
|
"timestamp": "2020-02-29T22:50:34.850Z",
|
||||||
|
"type": "POWER",
|
||||||
|
"value": "ON"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nextTimeBlock": {
|
||||||
|
"start": "2020-03-01T00:00:00.000Z"
|
||||||
|
},
|
||||||
|
"preparation": null,
|
||||||
|
"overlayType": null,
|
||||||
|
"nextScheduleChange": {
|
||||||
|
"start": "2020-03-01T00:00:00Z",
|
||||||
|
"setting": {
|
||||||
|
"type": "AIR_CONDITIONING",
|
||||||
|
"mode": "HEAT",
|
||||||
|
"power": "ON",
|
||||||
|
"temperature": {
|
||||||
|
"fahrenheit": 59.0,
|
||||||
|
"celsius": 15.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"setting": {
|
||||||
|
"type": "AIR_CONDITIONING",
|
||||||
|
"mode": "HEAT",
|
||||||
|
"power": "ON",
|
||||||
|
"temperature": {
|
||||||
|
"fahrenheit": 77.0,
|
||||||
|
"celsius": 25.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
22
tests/fixtures/tado/devices.json
vendored
Normal file
22
tests/fixtures/tado/devices.json
vendored
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"deviceType" : "WR02",
|
||||||
|
"currentFwVersion" : "59.4",
|
||||||
|
"accessPointWiFi" : {
|
||||||
|
"ssid" : "tado8480"
|
||||||
|
},
|
||||||
|
"characteristics" : {
|
||||||
|
"capabilities" : [
|
||||||
|
"INSIDE_TEMPERATURE_MEASUREMENT",
|
||||||
|
"IDENTIFY"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"serialNo" : "WR1",
|
||||||
|
"commandTableUploadState" : "FINISHED",
|
||||||
|
"connectionState" : {
|
||||||
|
"timestamp" : "2020-03-23T18:30:07.377Z",
|
||||||
|
"value" : true
|
||||||
|
},
|
||||||
|
"shortSerialNo" : "WR1"
|
||||||
|
}
|
||||||
|
]
|
67
tests/fixtures/tado/hvac_action_heat.json
vendored
Normal file
67
tests/fixtures/tado/hvac_action_heat.json
vendored
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
{
|
||||||
|
"tadoMode": "HOME",
|
||||||
|
"geolocationOverride": false,
|
||||||
|
"geolocationOverrideDisableTime": null,
|
||||||
|
"preparation": null,
|
||||||
|
"setting": {
|
||||||
|
"type": "AIR_CONDITIONING",
|
||||||
|
"power": "ON",
|
||||||
|
"mode": "HEAT",
|
||||||
|
"temperature": {
|
||||||
|
"celsius": 16.11,
|
||||||
|
"fahrenheit": 61.00
|
||||||
|
},
|
||||||
|
"fanSpeed": "AUTO"
|
||||||
|
},
|
||||||
|
"overlayType": "MANUAL",
|
||||||
|
"overlay": {
|
||||||
|
"type": "MANUAL",
|
||||||
|
"setting": {
|
||||||
|
"type": "AIR_CONDITIONING",
|
||||||
|
"power": "ON",
|
||||||
|
"mode": "HEAT",
|
||||||
|
"temperature": {
|
||||||
|
"celsius": 16.11,
|
||||||
|
"fahrenheit": 61.00
|
||||||
|
},
|
||||||
|
"fanSpeed": "AUTO"
|
||||||
|
},
|
||||||
|
"termination": {
|
||||||
|
"type": "TADO_MODE",
|
||||||
|
"typeSkillBasedApp": "TADO_MODE",
|
||||||
|
"projectedExpiry": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"openWindow": null,
|
||||||
|
"nextScheduleChange": null,
|
||||||
|
"nextTimeBlock": {
|
||||||
|
"start": "2020-03-07T04:00:00.000Z"
|
||||||
|
},
|
||||||
|
"link": {
|
||||||
|
"state": "ONLINE"
|
||||||
|
},
|
||||||
|
"activityDataPoints": {
|
||||||
|
"acPower": {
|
||||||
|
"timestamp": "2020-03-06T17:38:30.302Z",
|
||||||
|
"type": "POWER",
|
||||||
|
"value": "OFF"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"sensorDataPoints": {
|
||||||
|
"insideTemperature": {
|
||||||
|
"celsius": 21.40,
|
||||||
|
"fahrenheit": 70.52,
|
||||||
|
"timestamp": "2020-03-06T18:06:09.546Z",
|
||||||
|
"type": "TEMPERATURE",
|
||||||
|
"precision": {
|
||||||
|
"celsius": 0.1,
|
||||||
|
"fahrenheit": 0.1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"humidity": {
|
||||||
|
"type": "PERCENTAGE",
|
||||||
|
"percentage": 50.40,
|
||||||
|
"timestamp": "2020-03-06T18:06:09.546Z"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
28
tests/fixtures/tado/me.json
vendored
Normal file
28
tests/fixtures/tado/me.json
vendored
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
{
|
||||||
|
"id" : "5",
|
||||||
|
"mobileDevices" : [
|
||||||
|
{
|
||||||
|
"name" : "nick Android",
|
||||||
|
"deviceMetadata" : {
|
||||||
|
"platform" : "Android",
|
||||||
|
"locale" : "en",
|
||||||
|
"osVersion" : "10",
|
||||||
|
"model" : "OnePlus_GM1917"
|
||||||
|
},
|
||||||
|
"settings" : {
|
||||||
|
"geoTrackingEnabled" : false
|
||||||
|
},
|
||||||
|
"id" : 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"homes" : [
|
||||||
|
{
|
||||||
|
"name" : "home name",
|
||||||
|
"id" : 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name" : "name",
|
||||||
|
"locale" : "en_US",
|
||||||
|
"email" : "user@domain.tld",
|
||||||
|
"username" : "user@domain.tld"
|
||||||
|
}
|
57
tests/fixtures/tado/smartac3.auto_mode.json
vendored
Normal file
57
tests/fixtures/tado/smartac3.auto_mode.json
vendored
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
{
|
||||||
|
"tadoMode": "HOME",
|
||||||
|
"sensorDataPoints": {
|
||||||
|
"insideTemperature": {
|
||||||
|
"fahrenheit": 76.64,
|
||||||
|
"timestamp": "2020-03-05T03:55:38.160Z",
|
||||||
|
"celsius": 24.8,
|
||||||
|
"type": "TEMPERATURE",
|
||||||
|
"precision": {
|
||||||
|
"fahrenheit": 0.1,
|
||||||
|
"celsius": 0.1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"humidity": {
|
||||||
|
"timestamp": "2020-03-05T03:55:38.160Z",
|
||||||
|
"percentage": 62.5,
|
||||||
|
"type": "PERCENTAGE"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"link": {
|
||||||
|
"state": "ONLINE"
|
||||||
|
},
|
||||||
|
"openWindow": null,
|
||||||
|
"geolocationOverride": false,
|
||||||
|
"geolocationOverrideDisableTime": null,
|
||||||
|
"overlay": {
|
||||||
|
"termination": {
|
||||||
|
"typeSkillBasedApp": "TADO_MODE",
|
||||||
|
"projectedExpiry": null,
|
||||||
|
"type": "TADO_MODE"
|
||||||
|
},
|
||||||
|
"setting": {
|
||||||
|
"type": "AIR_CONDITIONING",
|
||||||
|
"mode": "AUTO",
|
||||||
|
"power": "ON"
|
||||||
|
},
|
||||||
|
"type": "MANUAL"
|
||||||
|
},
|
||||||
|
"activityDataPoints": {
|
||||||
|
"acPower": {
|
||||||
|
"timestamp": "2020-03-05T03:56:38.627Z",
|
||||||
|
"type": "POWER",
|
||||||
|
"value": "ON"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nextTimeBlock": {
|
||||||
|
"start": "2020-03-05T08:00:00.000Z"
|
||||||
|
},
|
||||||
|
"preparation": null,
|
||||||
|
"overlayType": "MANUAL",
|
||||||
|
"nextScheduleChange": null,
|
||||||
|
"setting": {
|
||||||
|
"type": "AIR_CONDITIONING",
|
||||||
|
"mode": "AUTO",
|
||||||
|
"power": "ON"
|
||||||
|
}
|
||||||
|
}
|
67
tests/fixtures/tado/smartac3.cool_mode.json
vendored
Normal file
67
tests/fixtures/tado/smartac3.cool_mode.json
vendored
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
{
|
||||||
|
"tadoMode": "HOME",
|
||||||
|
"sensorDataPoints": {
|
||||||
|
"insideTemperature": {
|
||||||
|
"fahrenheit": 76.57,
|
||||||
|
"timestamp": "2020-03-05T03:57:38.850Z",
|
||||||
|
"celsius": 24.76,
|
||||||
|
"type": "TEMPERATURE",
|
||||||
|
"precision": {
|
||||||
|
"fahrenheit": 0.1,
|
||||||
|
"celsius": 0.1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"humidity": {
|
||||||
|
"timestamp": "2020-03-05T03:57:38.850Z",
|
||||||
|
"percentage": 60.9,
|
||||||
|
"type": "PERCENTAGE"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"link": {
|
||||||
|
"state": "ONLINE"
|
||||||
|
},
|
||||||
|
"openWindow": null,
|
||||||
|
"geolocationOverride": false,
|
||||||
|
"geolocationOverrideDisableTime": null,
|
||||||
|
"overlay": {
|
||||||
|
"termination": {
|
||||||
|
"typeSkillBasedApp": "TADO_MODE",
|
||||||
|
"projectedExpiry": null,
|
||||||
|
"type": "TADO_MODE"
|
||||||
|
},
|
||||||
|
"setting": {
|
||||||
|
"fanSpeed": "AUTO",
|
||||||
|
"type": "AIR_CONDITIONING",
|
||||||
|
"mode": "COOL",
|
||||||
|
"power": "ON",
|
||||||
|
"temperature": {
|
||||||
|
"fahrenheit": 64.0,
|
||||||
|
"celsius": 17.78
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"type": "MANUAL"
|
||||||
|
},
|
||||||
|
"activityDataPoints": {
|
||||||
|
"acPower": {
|
||||||
|
"timestamp": "2020-03-05T04:01:07.162Z",
|
||||||
|
"type": "POWER",
|
||||||
|
"value": "ON"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nextTimeBlock": {
|
||||||
|
"start": "2020-03-05T08:00:00.000Z"
|
||||||
|
},
|
||||||
|
"preparation": null,
|
||||||
|
"overlayType": "MANUAL",
|
||||||
|
"nextScheduleChange": null,
|
||||||
|
"setting": {
|
||||||
|
"fanSpeed": "AUTO",
|
||||||
|
"type": "AIR_CONDITIONING",
|
||||||
|
"mode": "COOL",
|
||||||
|
"power": "ON",
|
||||||
|
"temperature": {
|
||||||
|
"fahrenheit": 64.0,
|
||||||
|
"celsius": 17.78
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
57
tests/fixtures/tado/smartac3.dry_mode.json
vendored
Normal file
57
tests/fixtures/tado/smartac3.dry_mode.json
vendored
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
{
|
||||||
|
"tadoMode": "HOME",
|
||||||
|
"sensorDataPoints": {
|
||||||
|
"insideTemperature": {
|
||||||
|
"fahrenheit": 77.02,
|
||||||
|
"timestamp": "2020-03-05T04:02:07.396Z",
|
||||||
|
"celsius": 25.01,
|
||||||
|
"type": "TEMPERATURE",
|
||||||
|
"precision": {
|
||||||
|
"fahrenheit": 0.1,
|
||||||
|
"celsius": 0.1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"humidity": {
|
||||||
|
"timestamp": "2020-03-05T04:02:07.396Z",
|
||||||
|
"percentage": 62.0,
|
||||||
|
"type": "PERCENTAGE"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"link": {
|
||||||
|
"state": "ONLINE"
|
||||||
|
},
|
||||||
|
"openWindow": null,
|
||||||
|
"geolocationOverride": false,
|
||||||
|
"geolocationOverrideDisableTime": null,
|
||||||
|
"overlay": {
|
||||||
|
"termination": {
|
||||||
|
"typeSkillBasedApp": "TADO_MODE",
|
||||||
|
"projectedExpiry": null,
|
||||||
|
"type": "TADO_MODE"
|
||||||
|
},
|
||||||
|
"setting": {
|
||||||
|
"type": "AIR_CONDITIONING",
|
||||||
|
"mode": "DRY",
|
||||||
|
"power": "ON"
|
||||||
|
},
|
||||||
|
"type": "MANUAL"
|
||||||
|
},
|
||||||
|
"activityDataPoints": {
|
||||||
|
"acPower": {
|
||||||
|
"timestamp": "2020-03-05T04:02:40.867Z",
|
||||||
|
"type": "POWER",
|
||||||
|
"value": "ON"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nextTimeBlock": {
|
||||||
|
"start": "2020-03-05T08:00:00.000Z"
|
||||||
|
},
|
||||||
|
"preparation": null,
|
||||||
|
"overlayType": "MANUAL",
|
||||||
|
"nextScheduleChange": null,
|
||||||
|
"setting": {
|
||||||
|
"type": "AIR_CONDITIONING",
|
||||||
|
"mode": "DRY",
|
||||||
|
"power": "ON"
|
||||||
|
}
|
||||||
|
}
|
57
tests/fixtures/tado/smartac3.fan_mode.json
vendored
Normal file
57
tests/fixtures/tado/smartac3.fan_mode.json
vendored
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
{
|
||||||
|
"tadoMode": "HOME",
|
||||||
|
"sensorDataPoints": {
|
||||||
|
"insideTemperature": {
|
||||||
|
"fahrenheit": 77.02,
|
||||||
|
"timestamp": "2020-03-05T04:02:07.396Z",
|
||||||
|
"celsius": 25.01,
|
||||||
|
"type": "TEMPERATURE",
|
||||||
|
"precision": {
|
||||||
|
"fahrenheit": 0.1,
|
||||||
|
"celsius": 0.1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"humidity": {
|
||||||
|
"timestamp": "2020-03-05T04:02:07.396Z",
|
||||||
|
"percentage": 62.0,
|
||||||
|
"type": "PERCENTAGE"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"link": {
|
||||||
|
"state": "ONLINE"
|
||||||
|
},
|
||||||
|
"openWindow": null,
|
||||||
|
"geolocationOverride": false,
|
||||||
|
"geolocationOverrideDisableTime": null,
|
||||||
|
"overlay": {
|
||||||
|
"termination": {
|
||||||
|
"typeSkillBasedApp": "TADO_MODE",
|
||||||
|
"projectedExpiry": null,
|
||||||
|
"type": "TADO_MODE"
|
||||||
|
},
|
||||||
|
"setting": {
|
||||||
|
"type": "AIR_CONDITIONING",
|
||||||
|
"mode": "FAN",
|
||||||
|
"power": "ON"
|
||||||
|
},
|
||||||
|
"type": "MANUAL"
|
||||||
|
},
|
||||||
|
"activityDataPoints": {
|
||||||
|
"acPower": {
|
||||||
|
"timestamp": "2020-03-05T04:03:44.328Z",
|
||||||
|
"type": "POWER",
|
||||||
|
"value": "ON"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nextTimeBlock": {
|
||||||
|
"start": "2020-03-05T08:00:00.000Z"
|
||||||
|
},
|
||||||
|
"preparation": null,
|
||||||
|
"overlayType": "MANUAL",
|
||||||
|
"nextScheduleChange": null,
|
||||||
|
"setting": {
|
||||||
|
"type": "AIR_CONDITIONING",
|
||||||
|
"mode": "FAN",
|
||||||
|
"power": "ON"
|
||||||
|
}
|
||||||
|
}
|
67
tests/fixtures/tado/smartac3.heat_mode.json
vendored
Normal file
67
tests/fixtures/tado/smartac3.heat_mode.json
vendored
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
{
|
||||||
|
"tadoMode": "HOME",
|
||||||
|
"sensorDataPoints": {
|
||||||
|
"insideTemperature": {
|
||||||
|
"fahrenheit": 76.57,
|
||||||
|
"timestamp": "2020-03-05T03:57:38.850Z",
|
||||||
|
"celsius": 24.76,
|
||||||
|
"type": "TEMPERATURE",
|
||||||
|
"precision": {
|
||||||
|
"fahrenheit": 0.1,
|
||||||
|
"celsius": 0.1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"humidity": {
|
||||||
|
"timestamp": "2020-03-05T03:57:38.850Z",
|
||||||
|
"percentage": 60.9,
|
||||||
|
"type": "PERCENTAGE"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"link": {
|
||||||
|
"state": "ONLINE"
|
||||||
|
},
|
||||||
|
"openWindow": null,
|
||||||
|
"geolocationOverride": false,
|
||||||
|
"geolocationOverrideDisableTime": null,
|
||||||
|
"overlay": {
|
||||||
|
"termination": {
|
||||||
|
"typeSkillBasedApp": "TADO_MODE",
|
||||||
|
"projectedExpiry": null,
|
||||||
|
"type": "TADO_MODE"
|
||||||
|
},
|
||||||
|
"setting": {
|
||||||
|
"fanSpeed": "AUTO",
|
||||||
|
"type": "AIR_CONDITIONING",
|
||||||
|
"mode": "HEAT",
|
||||||
|
"power": "ON",
|
||||||
|
"temperature": {
|
||||||
|
"fahrenheit": 61.0,
|
||||||
|
"celsius": 16.11
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"type": "MANUAL"
|
||||||
|
},
|
||||||
|
"activityDataPoints": {
|
||||||
|
"acPower": {
|
||||||
|
"timestamp": "2020-03-05T03:59:36.390Z",
|
||||||
|
"type": "POWER",
|
||||||
|
"value": "ON"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nextTimeBlock": {
|
||||||
|
"start": "2020-03-05T08:00:00.000Z"
|
||||||
|
},
|
||||||
|
"preparation": null,
|
||||||
|
"overlayType": "MANUAL",
|
||||||
|
"nextScheduleChange": null,
|
||||||
|
"setting": {
|
||||||
|
"fanSpeed": "AUTO",
|
||||||
|
"type": "AIR_CONDITIONING",
|
||||||
|
"mode": "HEAT",
|
||||||
|
"power": "ON",
|
||||||
|
"temperature": {
|
||||||
|
"fahrenheit": 61.0,
|
||||||
|
"celsius": 16.11
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
55
tests/fixtures/tado/smartac3.hvac_off.json
vendored
Normal file
55
tests/fixtures/tado/smartac3.hvac_off.json
vendored
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
{
|
||||||
|
"tadoMode": "AWAY",
|
||||||
|
"sensorDataPoints": {
|
||||||
|
"insideTemperature": {
|
||||||
|
"fahrenheit": 70.59,
|
||||||
|
"timestamp": "2020-03-05T01:21:44.089Z",
|
||||||
|
"celsius": 21.44,
|
||||||
|
"type": "TEMPERATURE",
|
||||||
|
"precision": {
|
||||||
|
"fahrenheit": 0.1,
|
||||||
|
"celsius": 0.1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"humidity": {
|
||||||
|
"timestamp": "2020-03-05T01:21:44.089Z",
|
||||||
|
"percentage": 48.2,
|
||||||
|
"type": "PERCENTAGE"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"link": {
|
||||||
|
"state": "ONLINE"
|
||||||
|
},
|
||||||
|
"openWindow": null,
|
||||||
|
"geolocationOverride": false,
|
||||||
|
"geolocationOverrideDisableTime": null,
|
||||||
|
"overlay": {
|
||||||
|
"termination": {
|
||||||
|
"typeSkillBasedApp": "MANUAL",
|
||||||
|
"projectedExpiry": null,
|
||||||
|
"type": "MANUAL"
|
||||||
|
},
|
||||||
|
"setting": {
|
||||||
|
"type": "AIR_CONDITIONING",
|
||||||
|
"power": "OFF"
|
||||||
|
},
|
||||||
|
"type": "MANUAL"
|
||||||
|
},
|
||||||
|
"activityDataPoints": {
|
||||||
|
"acPower": {
|
||||||
|
"timestamp": "2020-02-29T05:34:10.318Z",
|
||||||
|
"type": "POWER",
|
||||||
|
"value": "OFF"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nextTimeBlock": {
|
||||||
|
"start": "2020-03-05T04:00:00.000Z"
|
||||||
|
},
|
||||||
|
"preparation": null,
|
||||||
|
"overlayType": "MANUAL",
|
||||||
|
"nextScheduleChange": null,
|
||||||
|
"setting": {
|
||||||
|
"type": "AIR_CONDITIONING",
|
||||||
|
"power": "OFF"
|
||||||
|
}
|
||||||
|
}
|
55
tests/fixtures/tado/smartac3.manual_off.json
vendored
Normal file
55
tests/fixtures/tado/smartac3.manual_off.json
vendored
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
{
|
||||||
|
"tadoMode": "HOME",
|
||||||
|
"sensorDataPoints": {
|
||||||
|
"insideTemperature": {
|
||||||
|
"fahrenheit": 77.02,
|
||||||
|
"timestamp": "2020-03-05T04:02:07.396Z",
|
||||||
|
"celsius": 25.01,
|
||||||
|
"type": "TEMPERATURE",
|
||||||
|
"precision": {
|
||||||
|
"fahrenheit": 0.1,
|
||||||
|
"celsius": 0.1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"humidity": {
|
||||||
|
"timestamp": "2020-03-05T04:02:07.396Z",
|
||||||
|
"percentage": 62.0,
|
||||||
|
"type": "PERCENTAGE"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"link": {
|
||||||
|
"state": "ONLINE"
|
||||||
|
},
|
||||||
|
"openWindow": null,
|
||||||
|
"geolocationOverride": false,
|
||||||
|
"geolocationOverrideDisableTime": null,
|
||||||
|
"overlay": {
|
||||||
|
"termination": {
|
||||||
|
"typeSkillBasedApp": "MANUAL",
|
||||||
|
"projectedExpiry": null,
|
||||||
|
"type": "MANUAL"
|
||||||
|
},
|
||||||
|
"setting": {
|
||||||
|
"type": "AIR_CONDITIONING",
|
||||||
|
"power": "OFF"
|
||||||
|
},
|
||||||
|
"type": "MANUAL"
|
||||||
|
},
|
||||||
|
"activityDataPoints": {
|
||||||
|
"acPower": {
|
||||||
|
"timestamp": "2020-03-05T04:05:08.804Z",
|
||||||
|
"type": "POWER",
|
||||||
|
"value": "OFF"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nextTimeBlock": {
|
||||||
|
"start": "2020-03-05T08:00:00.000Z"
|
||||||
|
},
|
||||||
|
"preparation": null,
|
||||||
|
"overlayType": "MANUAL",
|
||||||
|
"nextScheduleChange": null,
|
||||||
|
"setting": {
|
||||||
|
"type": "AIR_CONDITIONING",
|
||||||
|
"power": "OFF"
|
||||||
|
}
|
||||||
|
}
|
71
tests/fixtures/tado/smartac3.offline.json
vendored
Normal file
71
tests/fixtures/tado/smartac3.offline.json
vendored
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
{
|
||||||
|
"tadoMode": "HOME",
|
||||||
|
"sensorDataPoints": {
|
||||||
|
"insideTemperature": {
|
||||||
|
"fahrenheit": 77.09,
|
||||||
|
"timestamp": "2020-03-03T21:23:57.846Z",
|
||||||
|
"celsius": 25.05,
|
||||||
|
"type": "TEMPERATURE",
|
||||||
|
"precision": {
|
||||||
|
"fahrenheit": 0.1,
|
||||||
|
"celsius": 0.1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"humidity": {
|
||||||
|
"timestamp": "2020-03-03T21:23:57.846Z",
|
||||||
|
"percentage": 61.6,
|
||||||
|
"type": "PERCENTAGE"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"link": {
|
||||||
|
"state": "OFFLINE",
|
||||||
|
"reason": {
|
||||||
|
"code": "disconnectedDevice",
|
||||||
|
"title": "There is a disconnected device."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"openWindow": null,
|
||||||
|
"geolocationOverride": false,
|
||||||
|
"geolocationOverrideDisableTime": null,
|
||||||
|
"overlay": {
|
||||||
|
"termination": {
|
||||||
|
"typeSkillBasedApp": "TADO_MODE",
|
||||||
|
"projectedExpiry": null,
|
||||||
|
"type": "TADO_MODE"
|
||||||
|
},
|
||||||
|
"setting": {
|
||||||
|
"fanSpeed": "AUTO",
|
||||||
|
"type": "AIR_CONDITIONING",
|
||||||
|
"mode": "COOL",
|
||||||
|
"power": "ON",
|
||||||
|
"temperature": {
|
||||||
|
"fahrenheit": 64.0,
|
||||||
|
"celsius": 17.78
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"type": "MANUAL"
|
||||||
|
},
|
||||||
|
"activityDataPoints": {
|
||||||
|
"acPower": {
|
||||||
|
"timestamp": "2020-02-29T18:42:26.683Z",
|
||||||
|
"type": "POWER",
|
||||||
|
"value": "OFF"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nextTimeBlock": {
|
||||||
|
"start": "2020-03-05T08:00:00.000Z"
|
||||||
|
},
|
||||||
|
"preparation": null,
|
||||||
|
"overlayType": "MANUAL",
|
||||||
|
"nextScheduleChange": null,
|
||||||
|
"setting": {
|
||||||
|
"fanSpeed": "AUTO",
|
||||||
|
"type": "AIR_CONDITIONING",
|
||||||
|
"mode": "COOL",
|
||||||
|
"power": "ON",
|
||||||
|
"temperature": {
|
||||||
|
"fahrenheit": 64.0,
|
||||||
|
"celsius": 17.78
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
50
tests/fixtures/tado/smartac3.smart_mode.json
vendored
Normal file
50
tests/fixtures/tado/smartac3.smart_mode.json
vendored
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
{
|
||||||
|
"tadoMode": "HOME",
|
||||||
|
"sensorDataPoints": {
|
||||||
|
"insideTemperature": {
|
||||||
|
"fahrenheit": 75.97,
|
||||||
|
"timestamp": "2020-03-05T03:50:24.769Z",
|
||||||
|
"celsius": 24.43,
|
||||||
|
"type": "TEMPERATURE",
|
||||||
|
"precision": {
|
||||||
|
"fahrenheit": 0.1,
|
||||||
|
"celsius": 0.1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"humidity": {
|
||||||
|
"timestamp": "2020-03-05T03:50:24.769Z",
|
||||||
|
"percentage": 60.0,
|
||||||
|
"type": "PERCENTAGE"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"link": {
|
||||||
|
"state": "ONLINE"
|
||||||
|
},
|
||||||
|
"openWindow": null,
|
||||||
|
"geolocationOverride": false,
|
||||||
|
"geolocationOverrideDisableTime": null,
|
||||||
|
"overlay": null,
|
||||||
|
"activityDataPoints": {
|
||||||
|
"acPower": {
|
||||||
|
"timestamp": "2020-03-05T03:52:22.253Z",
|
||||||
|
"type": "POWER",
|
||||||
|
"value": "OFF"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nextTimeBlock": {
|
||||||
|
"start": "2020-03-05T08:00:00.000Z"
|
||||||
|
},
|
||||||
|
"preparation": null,
|
||||||
|
"overlayType": null,
|
||||||
|
"nextScheduleChange": null,
|
||||||
|
"setting": {
|
||||||
|
"fanSpeed": "MIDDLE",
|
||||||
|
"type": "AIR_CONDITIONING",
|
||||||
|
"mode": "COOL",
|
||||||
|
"power": "ON",
|
||||||
|
"temperature": {
|
||||||
|
"fahrenheit": 68.0,
|
||||||
|
"celsius": 20.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
55
tests/fixtures/tado/smartac3.turning_off.json
vendored
Normal file
55
tests/fixtures/tado/smartac3.turning_off.json
vendored
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
{
|
||||||
|
"tadoMode": "HOME",
|
||||||
|
"geolocationOverride": false,
|
||||||
|
"geolocationOverrideDisableTime": null,
|
||||||
|
"preparation": null,
|
||||||
|
"setting": {
|
||||||
|
"type": "AIR_CONDITIONING",
|
||||||
|
"power": "OFF"
|
||||||
|
},
|
||||||
|
"overlayType": "MANUAL",
|
||||||
|
"overlay": {
|
||||||
|
"type": "MANUAL",
|
||||||
|
"setting": {
|
||||||
|
"type": "AIR_CONDITIONING",
|
||||||
|
"power": "OFF"
|
||||||
|
},
|
||||||
|
"termination": {
|
||||||
|
"type": "MANUAL",
|
||||||
|
"typeSkillBasedApp": "MANUAL",
|
||||||
|
"projectedExpiry": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"openWindow": null,
|
||||||
|
"nextScheduleChange": null,
|
||||||
|
"nextTimeBlock": {
|
||||||
|
"start": "2020-03-07T04:00:00.000Z"
|
||||||
|
},
|
||||||
|
"link": {
|
||||||
|
"state": "ONLINE"
|
||||||
|
},
|
||||||
|
"activityDataPoints": {
|
||||||
|
"acPower": {
|
||||||
|
"timestamp": "2020-03-06T19:05:21.835Z",
|
||||||
|
"type": "POWER",
|
||||||
|
"value": "ON"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"sensorDataPoints": {
|
||||||
|
"insideTemperature": {
|
||||||
|
"celsius": 21.40,
|
||||||
|
"fahrenheit": 70.52,
|
||||||
|
"timestamp": "2020-03-06T19:06:13.185Z",
|
||||||
|
"type": "TEMPERATURE",
|
||||||
|
"precision": {
|
||||||
|
"celsius": 0.1,
|
||||||
|
"fahrenheit": 0.1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"humidity": {
|
||||||
|
"type": "PERCENTAGE",
|
||||||
|
"percentage": 49.20,
|
||||||
|
"timestamp": "2020-03-06T19:06:13.185Z"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
58
tests/fixtures/tado/tadov2.heating.auto_mode.json
vendored
Normal file
58
tests/fixtures/tado/tadov2.heating.auto_mode.json
vendored
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
{
|
||||||
|
"tadoMode": "HOME",
|
||||||
|
"geolocationOverride": false,
|
||||||
|
"geolocationOverrideDisableTime": null,
|
||||||
|
"preparation": null,
|
||||||
|
"setting": {
|
||||||
|
"type": "HEATING",
|
||||||
|
"power": "ON",
|
||||||
|
"temperature": {
|
||||||
|
"celsius": 20.00,
|
||||||
|
"fahrenheit": 68.00
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"overlayType": null,
|
||||||
|
"overlay": null,
|
||||||
|
"openWindow": null,
|
||||||
|
"nextScheduleChange": {
|
||||||
|
"start": "2020-03-10T17:00:00Z",
|
||||||
|
"setting": {
|
||||||
|
"type": "HEATING",
|
||||||
|
"power": "ON",
|
||||||
|
"temperature": {
|
||||||
|
"celsius": 21.00,
|
||||||
|
"fahrenheit": 69.80
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nextTimeBlock": {
|
||||||
|
"start": "2020-03-10T17:00:00.000Z"
|
||||||
|
},
|
||||||
|
"link": {
|
||||||
|
"state": "ONLINE"
|
||||||
|
},
|
||||||
|
"activityDataPoints": {
|
||||||
|
"heatingPower": {
|
||||||
|
"type": "PERCENTAGE",
|
||||||
|
"percentage": 0.00,
|
||||||
|
"timestamp": "2020-03-10T07:47:45.978Z"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"sensorDataPoints": {
|
||||||
|
"insideTemperature": {
|
||||||
|
"celsius": 20.65,
|
||||||
|
"fahrenheit": 69.17,
|
||||||
|
"timestamp": "2020-03-10T07:44:11.947Z",
|
||||||
|
"type": "TEMPERATURE",
|
||||||
|
"precision": {
|
||||||
|
"celsius": 0.1,
|
||||||
|
"fahrenheit": 0.1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"humidity": {
|
||||||
|
"type": "PERCENTAGE",
|
||||||
|
"percentage": 45.20,
|
||||||
|
"timestamp": "2020-03-10T07:44:11.947Z"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
73
tests/fixtures/tado/tadov2.heating.manual_mode.json
vendored
Normal file
73
tests/fixtures/tado/tadov2.heating.manual_mode.json
vendored
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
{
|
||||||
|
"tadoMode": "HOME",
|
||||||
|
"geolocationOverride": false,
|
||||||
|
"geolocationOverrideDisableTime": null,
|
||||||
|
"preparation": null,
|
||||||
|
"setting": {
|
||||||
|
"type": "HEATING",
|
||||||
|
"power": "ON",
|
||||||
|
"temperature": {
|
||||||
|
"celsius": 20.50,
|
||||||
|
"fahrenheit": 68.90
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"overlayType": "MANUAL",
|
||||||
|
"overlay": {
|
||||||
|
"type": "MANUAL",
|
||||||
|
"setting": {
|
||||||
|
"type": "HEATING",
|
||||||
|
"power": "ON",
|
||||||
|
"temperature": {
|
||||||
|
"celsius": 20.50,
|
||||||
|
"fahrenheit": 68.90
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"termination": {
|
||||||
|
"type": "MANUAL",
|
||||||
|
"typeSkillBasedApp": "MANUAL",
|
||||||
|
"projectedExpiry": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"openWindow": null,
|
||||||
|
"nextScheduleChange": {
|
||||||
|
"start": "2020-03-10T17:00:00Z",
|
||||||
|
"setting": {
|
||||||
|
"type": "HEATING",
|
||||||
|
"power": "ON",
|
||||||
|
"temperature": {
|
||||||
|
"celsius": 21.00,
|
||||||
|
"fahrenheit": 69.80
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nextTimeBlock": {
|
||||||
|
"start": "2020-03-10T17:00:00.000Z"
|
||||||
|
},
|
||||||
|
"link": {
|
||||||
|
"state": "ONLINE"
|
||||||
|
},
|
||||||
|
"activityDataPoints": {
|
||||||
|
"heatingPower": {
|
||||||
|
"type": "PERCENTAGE",
|
||||||
|
"percentage": 0.00,
|
||||||
|
"timestamp": "2020-03-10T07:47:45.978Z"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"sensorDataPoints": {
|
||||||
|
"insideTemperature": {
|
||||||
|
"celsius": 20.65,
|
||||||
|
"fahrenheit": 69.17,
|
||||||
|
"timestamp": "2020-03-10T07:44:11.947Z",
|
||||||
|
"type": "TEMPERATURE",
|
||||||
|
"precision": {
|
||||||
|
"celsius": 0.1,
|
||||||
|
"fahrenheit": 0.1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"humidity": {
|
||||||
|
"type": "PERCENTAGE",
|
||||||
|
"percentage": 45.20,
|
||||||
|
"timestamp": "2020-03-10T07:44:11.947Z"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
67
tests/fixtures/tado/tadov2.heating.off_mode.json
vendored
Normal file
67
tests/fixtures/tado/tadov2.heating.off_mode.json
vendored
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
{
|
||||||
|
"tadoMode": "HOME",
|
||||||
|
"geolocationOverride": false,
|
||||||
|
"geolocationOverrideDisableTime": null,
|
||||||
|
"preparation": null,
|
||||||
|
"setting": {
|
||||||
|
"type": "HEATING",
|
||||||
|
"power": "OFF",
|
||||||
|
"temperature": null
|
||||||
|
},
|
||||||
|
"overlayType": "MANUAL",
|
||||||
|
"overlay": {
|
||||||
|
"type": "MANUAL",
|
||||||
|
"setting": {
|
||||||
|
"type": "HEATING",
|
||||||
|
"power": "OFF",
|
||||||
|
"temperature": null
|
||||||
|
},
|
||||||
|
"termination": {
|
||||||
|
"type": "MANUAL",
|
||||||
|
"typeSkillBasedApp": "MANUAL",
|
||||||
|
"projectedExpiry": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"openWindow": null,
|
||||||
|
"nextScheduleChange": {
|
||||||
|
"start": "2020-03-10T17:00:00Z",
|
||||||
|
"setting": {
|
||||||
|
"type": "HEATING",
|
||||||
|
"power": "ON",
|
||||||
|
"temperature": {
|
||||||
|
"celsius": 21.00,
|
||||||
|
"fahrenheit": 69.80
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nextTimeBlock": {
|
||||||
|
"start": "2020-03-10T17:00:00.000Z"
|
||||||
|
},
|
||||||
|
"link": {
|
||||||
|
"state": "ONLINE"
|
||||||
|
},
|
||||||
|
"activityDataPoints": {
|
||||||
|
"heatingPower": {
|
||||||
|
"type": "PERCENTAGE",
|
||||||
|
"percentage": 0.00,
|
||||||
|
"timestamp": "2020-03-10T07:47:45.978Z"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"sensorDataPoints": {
|
||||||
|
"insideTemperature": {
|
||||||
|
"celsius": 20.65,
|
||||||
|
"fahrenheit": 69.17,
|
||||||
|
"timestamp": "2020-03-10T07:44:11.947Z",
|
||||||
|
"type": "TEMPERATURE",
|
||||||
|
"precision": {
|
||||||
|
"celsius": 0.1,
|
||||||
|
"fahrenheit": 0.1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"humidity": {
|
||||||
|
"type": "PERCENTAGE",
|
||||||
|
"percentage": 45.20,
|
||||||
|
"timestamp": "2020-03-10T07:44:11.947Z"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
33
tests/fixtures/tado/tadov2.water_heater.auto_mode.json
vendored
Normal file
33
tests/fixtures/tado/tadov2.water_heater.auto_mode.json
vendored
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
{
|
||||||
|
"tadoMode": "HOME",
|
||||||
|
"geolocationOverride": false,
|
||||||
|
"geolocationOverrideDisableTime": null,
|
||||||
|
"preparation": null,
|
||||||
|
"setting": {
|
||||||
|
"type": "HOT_WATER",
|
||||||
|
"power": "ON",
|
||||||
|
"temperature": {
|
||||||
|
"celsius": 65.00,
|
||||||
|
"fahrenheit": 149.00
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"overlayType": null,
|
||||||
|
"overlay": null,
|
||||||
|
"openWindow": null,
|
||||||
|
"nextScheduleChange": {
|
||||||
|
"start": "2020-03-10T22:00:00Z",
|
||||||
|
"setting": {
|
||||||
|
"type": "HOT_WATER",
|
||||||
|
"power": "OFF",
|
||||||
|
"temperature": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nextTimeBlock": {
|
||||||
|
"start": "2020-03-10T22:00:00.000Z"
|
||||||
|
},
|
||||||
|
"link": {
|
||||||
|
"state": "ONLINE"
|
||||||
|
},
|
||||||
|
"activityDataPoints": {},
|
||||||
|
"sensorDataPoints": {}
|
||||||
|
}
|
51
tests/fixtures/tado/tadov2.water_heater.heating.json
vendored
Normal file
51
tests/fixtures/tado/tadov2.water_heater.heating.json
vendored
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
{
|
||||||
|
"activityDataPoints" : {},
|
||||||
|
"preparation" : null,
|
||||||
|
"openWindow" : null,
|
||||||
|
"tadoMode" : "HOME",
|
||||||
|
"nextScheduleChange" : {
|
||||||
|
"setting" : {
|
||||||
|
"temperature" : {
|
||||||
|
"fahrenheit" : 149,
|
||||||
|
"celsius" : 65
|
||||||
|
},
|
||||||
|
"type" : "HOT_WATER",
|
||||||
|
"power" : "ON"
|
||||||
|
},
|
||||||
|
"start" : "2020-03-26T05:00:00Z"
|
||||||
|
},
|
||||||
|
"nextTimeBlock" : {
|
||||||
|
"start" : "2020-03-26T05:00:00.000Z"
|
||||||
|
},
|
||||||
|
"overlay" : {
|
||||||
|
"setting" : {
|
||||||
|
"temperature" : {
|
||||||
|
"celsius" : 30,
|
||||||
|
"fahrenheit" : 86
|
||||||
|
},
|
||||||
|
"type" : "HOT_WATER",
|
||||||
|
"power" : "ON"
|
||||||
|
},
|
||||||
|
"termination" : {
|
||||||
|
"type" : "TADO_MODE",
|
||||||
|
"projectedExpiry" : "2020-03-26T05:00:00Z",
|
||||||
|
"typeSkillBasedApp" : "TADO_MODE"
|
||||||
|
},
|
||||||
|
"type" : "MANUAL"
|
||||||
|
},
|
||||||
|
"geolocationOverride" : false,
|
||||||
|
"geolocationOverrideDisableTime" : null,
|
||||||
|
"sensorDataPoints" : {},
|
||||||
|
"overlayType" : "MANUAL",
|
||||||
|
"link" : {
|
||||||
|
"state" : "ONLINE"
|
||||||
|
},
|
||||||
|
"setting" : {
|
||||||
|
"type" : "HOT_WATER",
|
||||||
|
"temperature" : {
|
||||||
|
"fahrenheit" : 86,
|
||||||
|
"celsius" : 30
|
||||||
|
},
|
||||||
|
"power" : "ON"
|
||||||
|
}
|
||||||
|
}
|
48
tests/fixtures/tado/tadov2.water_heater.manual_mode.json
vendored
Normal file
48
tests/fixtures/tado/tadov2.water_heater.manual_mode.json
vendored
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
{
|
||||||
|
"tadoMode": "HOME",
|
||||||
|
"geolocationOverride": false,
|
||||||
|
"geolocationOverrideDisableTime": null,
|
||||||
|
"preparation": null,
|
||||||
|
"setting": {
|
||||||
|
"type": "HOT_WATER",
|
||||||
|
"power": "ON",
|
||||||
|
"temperature": {
|
||||||
|
"celsius": 55.00,
|
||||||
|
"fahrenheit": 131.00
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"overlayType": "MANUAL",
|
||||||
|
"overlay": {
|
||||||
|
"type": "MANUAL",
|
||||||
|
"setting": {
|
||||||
|
"type": "HOT_WATER",
|
||||||
|
"power": "ON",
|
||||||
|
"temperature": {
|
||||||
|
"celsius": 55.00,
|
||||||
|
"fahrenheit": 131.00
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"termination": {
|
||||||
|
"type": "MANUAL",
|
||||||
|
"typeSkillBasedApp": "MANUAL",
|
||||||
|
"projectedExpiry": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"openWindow": null,
|
||||||
|
"nextScheduleChange": {
|
||||||
|
"start": "2020-03-10T22:00:00Z",
|
||||||
|
"setting": {
|
||||||
|
"type": "HOT_WATER",
|
||||||
|
"power": "OFF",
|
||||||
|
"temperature": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nextTimeBlock": {
|
||||||
|
"start": "2020-03-10T22:00:00.000Z"
|
||||||
|
},
|
||||||
|
"link": {
|
||||||
|
"state": "ONLINE"
|
||||||
|
},
|
||||||
|
"activityDataPoints": {},
|
||||||
|
"sensorDataPoints": {}
|
||||||
|
}
|
42
tests/fixtures/tado/tadov2.water_heater.off_mode.json
vendored
Normal file
42
tests/fixtures/tado/tadov2.water_heater.off_mode.json
vendored
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
{
|
||||||
|
"tadoMode": "HOME",
|
||||||
|
"geolocationOverride": false,
|
||||||
|
"geolocationOverrideDisableTime": null,
|
||||||
|
"preparation": null,
|
||||||
|
"setting": {
|
||||||
|
"type": "HOT_WATER",
|
||||||
|
"power": "OFF",
|
||||||
|
"temperature": null
|
||||||
|
},
|
||||||
|
"overlayType": "MANUAL",
|
||||||
|
"overlay": {
|
||||||
|
"type": "MANUAL",
|
||||||
|
"setting": {
|
||||||
|
"type": "HOT_WATER",
|
||||||
|
"power": "OFF",
|
||||||
|
"temperature": null
|
||||||
|
},
|
||||||
|
"termination": {
|
||||||
|
"type": "MANUAL",
|
||||||
|
"typeSkillBasedApp": "MANUAL",
|
||||||
|
"projectedExpiry": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"openWindow": null,
|
||||||
|
"nextScheduleChange": {
|
||||||
|
"start": "2020-03-10T22:00:00Z",
|
||||||
|
"setting": {
|
||||||
|
"type": "HOT_WATER",
|
||||||
|
"power": "OFF",
|
||||||
|
"temperature": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nextTimeBlock": {
|
||||||
|
"start": "2020-03-10T22:00:00.000Z"
|
||||||
|
},
|
||||||
|
"link": {
|
||||||
|
"state": "ONLINE"
|
||||||
|
},
|
||||||
|
"activityDataPoints": {},
|
||||||
|
"sensorDataPoints": {}
|
||||||
|
}
|
19
tests/fixtures/tado/tadov2.zone_capabilities.json
vendored
Normal file
19
tests/fixtures/tado/tadov2.zone_capabilities.json
vendored
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"type" : "HEATING",
|
||||||
|
"HEAT" : {
|
||||||
|
"temperatures" : {
|
||||||
|
"celsius" : {
|
||||||
|
"max" : 31,
|
||||||
|
"step" : 1,
|
||||||
|
"min" : 16
|
||||||
|
},
|
||||||
|
"fahrenheit" : {
|
||||||
|
"step" : 1,
|
||||||
|
"max" : 88,
|
||||||
|
"min" : 61
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"AUTO" : {},
|
||||||
|
"FAN" : {}
|
||||||
|
}
|
8
tests/fixtures/tado/token.json
vendored
Normal file
8
tests/fixtures/tado/token.json
vendored
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"expires_in" : 599,
|
||||||
|
"scope" : "home.user",
|
||||||
|
"token_type" : "bearer",
|
||||||
|
"refresh_token" : "refresh",
|
||||||
|
"access_token" : "access",
|
||||||
|
"jti" : "jti"
|
||||||
|
}
|
17
tests/fixtures/tado/water_heater_zone_capabilities.json
vendored
Normal file
17
tests/fixtures/tado/water_heater_zone_capabilities.json
vendored
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"canSetTemperature" : true,
|
||||||
|
"DRY" : {},
|
||||||
|
"type" : "HOT_WATER",
|
||||||
|
"temperatures" : {
|
||||||
|
"celsius" : {
|
||||||
|
"min" : 16,
|
||||||
|
"max" : 31,
|
||||||
|
"step" : 1
|
||||||
|
},
|
||||||
|
"fahrenheit" : {
|
||||||
|
"step" : 1,
|
||||||
|
"max" : 88,
|
||||||
|
"min" : 61
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
46
tests/fixtures/tado/zone_capabilities.json
vendored
Normal file
46
tests/fixtures/tado/zone_capabilities.json
vendored
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
{
|
||||||
|
"type" : "AIR_CONDITIONING",
|
||||||
|
"HEAT" : {
|
||||||
|
"fanSpeeds" : [
|
||||||
|
"AUTO",
|
||||||
|
"HIGH",
|
||||||
|
"MIDDLE",
|
||||||
|
"LOW"
|
||||||
|
],
|
||||||
|
"temperatures" : {
|
||||||
|
"celsius" : {
|
||||||
|
"max" : 31,
|
||||||
|
"step" : 1,
|
||||||
|
"min" : 16
|
||||||
|
},
|
||||||
|
"fahrenheit" : {
|
||||||
|
"step" : 1,
|
||||||
|
"max" : 88,
|
||||||
|
"min" : 61
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"AUTO" : {},
|
||||||
|
"DRY" : {},
|
||||||
|
"FAN" : {},
|
||||||
|
"COOL" : {
|
||||||
|
"temperatures" : {
|
||||||
|
"celsius" : {
|
||||||
|
"min" : 16,
|
||||||
|
"step" : 1,
|
||||||
|
"max" : 31
|
||||||
|
},
|
||||||
|
"fahrenheit" : {
|
||||||
|
"min" : 61,
|
||||||
|
"max" : 88,
|
||||||
|
"step" : 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"fanSpeeds" : [
|
||||||
|
"AUTO",
|
||||||
|
"HIGH",
|
||||||
|
"MIDDLE",
|
||||||
|
"LOW"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
55
tests/fixtures/tado/zone_state.json
vendored
Normal file
55
tests/fixtures/tado/zone_state.json
vendored
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
{
|
||||||
|
"openWindow" : null,
|
||||||
|
"nextScheduleChange" : null,
|
||||||
|
"geolocationOverrideDisableTime" : null,
|
||||||
|
"sensorDataPoints" : {
|
||||||
|
"insideTemperature" : {
|
||||||
|
"celsius" : 22.43,
|
||||||
|
"type" : "TEMPERATURE",
|
||||||
|
"precision" : {
|
||||||
|
"fahrenheit" : 0.1,
|
||||||
|
"celsius" : 0.1
|
||||||
|
},
|
||||||
|
"timestamp" : "2020-03-23T18:30:07.377Z",
|
||||||
|
"fahrenheit" : 72.37
|
||||||
|
},
|
||||||
|
"humidity" : {
|
||||||
|
"timestamp" : "2020-03-23T18:30:07.377Z",
|
||||||
|
"percentage" : 60.2,
|
||||||
|
"type" : "PERCENTAGE"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"overlay" : {
|
||||||
|
"type" : "MANUAL",
|
||||||
|
"termination" : {
|
||||||
|
"projectedExpiry" : null,
|
||||||
|
"typeSkillBasedApp" : "MANUAL",
|
||||||
|
"type" : "MANUAL"
|
||||||
|
},
|
||||||
|
"setting" : {
|
||||||
|
"power" : "OFF",
|
||||||
|
"type" : "AIR_CONDITIONING"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"geolocationOverride" : false,
|
||||||
|
"overlayType" : "MANUAL",
|
||||||
|
"activityDataPoints" : {
|
||||||
|
"acPower" : {
|
||||||
|
"type" : "POWER",
|
||||||
|
"timestamp" : "2020-03-11T15:08:23.604Z",
|
||||||
|
"value" : "OFF"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tadoMode" : "HOME",
|
||||||
|
"link" : {
|
||||||
|
"state" : "ONLINE"
|
||||||
|
},
|
||||||
|
"setting" : {
|
||||||
|
"power" : "OFF",
|
||||||
|
"type" : "AIR_CONDITIONING"
|
||||||
|
},
|
||||||
|
"nextTimeBlock" : {
|
||||||
|
"start" : "2020-03-24T03:00:00.000Z"
|
||||||
|
},
|
||||||
|
"preparation" : null
|
||||||
|
}
|
179
tests/fixtures/tado/zones.json
vendored
Normal file
179
tests/fixtures/tado/zones.json
vendored
Normal file
@ -0,0 +1,179 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"deviceTypes" : [
|
||||||
|
"WR02"
|
||||||
|
],
|
||||||
|
"type" : "HEATING",
|
||||||
|
"reportAvailable" : false,
|
||||||
|
"dazzleMode" : {
|
||||||
|
"enabled" : true,
|
||||||
|
"supported" : true
|
||||||
|
},
|
||||||
|
"name" : "Baseboard Heater",
|
||||||
|
"supportsDazzle" : true,
|
||||||
|
"id" : 1,
|
||||||
|
"devices" : [
|
||||||
|
{
|
||||||
|
"duties" : [
|
||||||
|
"ZONE_UI",
|
||||||
|
"ZONE_DRIVER",
|
||||||
|
"ZONE_LEADER"
|
||||||
|
],
|
||||||
|
"currentFwVersion" : "59.4",
|
||||||
|
"deviceType" : "WR02",
|
||||||
|
"serialNo" : "WR4",
|
||||||
|
"shortSerialNo" : "WR4",
|
||||||
|
"commandTableUploadState" : "FINISHED",
|
||||||
|
"connectionState" : {
|
||||||
|
"value" : true,
|
||||||
|
"timestamp" : "2020-03-23T18:30:07.377Z"
|
||||||
|
},
|
||||||
|
"accessPointWiFi" : {
|
||||||
|
"ssid" : "tado8480"
|
||||||
|
},
|
||||||
|
"characteristics" : {
|
||||||
|
"capabilities" : [
|
||||||
|
"INSIDE_TEMPERATURE_MEASUREMENT",
|
||||||
|
"IDENTIFY"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"dateCreated" : "2019-11-28T15:58:48.968Z",
|
||||||
|
"dazzleEnabled" : true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type" : "HOT_WATER",
|
||||||
|
"reportAvailable" : false,
|
||||||
|
"deviceTypes" : [
|
||||||
|
"WR02"
|
||||||
|
],
|
||||||
|
"devices" : [
|
||||||
|
{
|
||||||
|
"connectionState" : {
|
||||||
|
"value" : true,
|
||||||
|
"timestamp" : "2020-03-23T18:30:07.377Z"
|
||||||
|
},
|
||||||
|
"accessPointWiFi" : {
|
||||||
|
"ssid" : "tado8480"
|
||||||
|
},
|
||||||
|
"characteristics" : {
|
||||||
|
"capabilities" : [
|
||||||
|
"INSIDE_TEMPERATURE_MEASUREMENT",
|
||||||
|
"IDENTIFY"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"duties" : [
|
||||||
|
"ZONE_UI",
|
||||||
|
"ZONE_DRIVER",
|
||||||
|
"ZONE_LEADER"
|
||||||
|
],
|
||||||
|
"currentFwVersion" : "59.4",
|
||||||
|
"deviceType" : "WR02",
|
||||||
|
"serialNo" : "WR4",
|
||||||
|
"shortSerialNo" : "WR4",
|
||||||
|
"commandTableUploadState" : "FINISHED"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"dazzleEnabled" : true,
|
||||||
|
"dateCreated" : "2019-11-28T15:58:48.968Z",
|
||||||
|
"name" : "Water Heater",
|
||||||
|
"dazzleMode" : {
|
||||||
|
"enabled" : true,
|
||||||
|
"supported" : true
|
||||||
|
},
|
||||||
|
"id" : 2,
|
||||||
|
"supportsDazzle" : true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"dazzleMode" : {
|
||||||
|
"supported" : true,
|
||||||
|
"enabled" : true
|
||||||
|
},
|
||||||
|
"name" : "Air Conditioning",
|
||||||
|
"id" : 3,
|
||||||
|
"supportsDazzle" : true,
|
||||||
|
"devices" : [
|
||||||
|
{
|
||||||
|
"deviceType" : "WR02",
|
||||||
|
"shortSerialNo" : "WR4",
|
||||||
|
"serialNo" : "WR4",
|
||||||
|
"commandTableUploadState" : "FINISHED",
|
||||||
|
"duties" : [
|
||||||
|
"ZONE_UI",
|
||||||
|
"ZONE_DRIVER",
|
||||||
|
"ZONE_LEADER"
|
||||||
|
],
|
||||||
|
"currentFwVersion" : "59.4",
|
||||||
|
"characteristics" : {
|
||||||
|
"capabilities" : [
|
||||||
|
"INSIDE_TEMPERATURE_MEASUREMENT",
|
||||||
|
"IDENTIFY"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"accessPointWiFi" : {
|
||||||
|
"ssid" : "tado8480"
|
||||||
|
},
|
||||||
|
"connectionState" : {
|
||||||
|
"timestamp" : "2020-03-23T18:30:07.377Z",
|
||||||
|
"value" : true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"dazzleEnabled" : true,
|
||||||
|
"dateCreated" : "2019-11-28T15:58:48.968Z",
|
||||||
|
"openWindowDetection" : {
|
||||||
|
"timeoutInSeconds" : 900,
|
||||||
|
"enabled" : true,
|
||||||
|
"supported" : true
|
||||||
|
},
|
||||||
|
"deviceTypes" : [
|
||||||
|
"WR02"
|
||||||
|
],
|
||||||
|
"reportAvailable" : false,
|
||||||
|
"type" : "AIR_CONDITIONING"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type" : "HOT_WATER",
|
||||||
|
"reportAvailable" : false,
|
||||||
|
"deviceTypes" : [
|
||||||
|
"WR02"
|
||||||
|
],
|
||||||
|
"devices" : [
|
||||||
|
{
|
||||||
|
"connectionState" : {
|
||||||
|
"value" : true,
|
||||||
|
"timestamp" : "2020-03-23T18:30:07.377Z"
|
||||||
|
},
|
||||||
|
"accessPointWiFi" : {
|
||||||
|
"ssid" : "tado8480"
|
||||||
|
},
|
||||||
|
"characteristics" : {
|
||||||
|
"capabilities" : [
|
||||||
|
"INSIDE_TEMPERATURE_MEASUREMENT",
|
||||||
|
"IDENTIFY"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"duties" : [
|
||||||
|
"ZONE_UI",
|
||||||
|
"ZONE_DRIVER",
|
||||||
|
"ZONE_LEADER"
|
||||||
|
],
|
||||||
|
"currentFwVersion" : "59.4",
|
||||||
|
"deviceType" : "WR02",
|
||||||
|
"serialNo" : "WR4",
|
||||||
|
"shortSerialNo" : "WR4",
|
||||||
|
"commandTableUploadState" : "FINISHED"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"dazzleEnabled" : true,
|
||||||
|
"dateCreated" : "2019-11-28T15:58:48.968Z",
|
||||||
|
"name" : "Second Water Heater",
|
||||||
|
"dazzleMode" : {
|
||||||
|
"enabled" : true,
|
||||||
|
"supported" : true
|
||||||
|
},
|
||||||
|
"id" : 4,
|
||||||
|
"supportsDazzle" : true
|
||||||
|
}
|
||||||
|
]
|
Loading…
x
Reference in New Issue
Block a user