Revert "Breakout tado zone code into a single place (#32564)" (#32639)

This reverts commit c2b03332a0e08d0a4347aaad3c233908029e9864.
This commit is contained in:
Michaël Arnauts 2020-03-10 09:32:56 +01:00 committed by GitHub
parent ac9c9377c2
commit 8c52e2c923
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 410 additions and 1999 deletions

View File

@ -350,7 +350,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 @bdraco homeassistant/components/tado/* @michaelarnauts
homeassistant/components/tahoma/* @philklei homeassistant/components/tahoma/* @philklei
homeassistant/components/tankerkoenig/* @guillempages homeassistant/components/tankerkoenig/* @guillempages
homeassistant/components/tautulli/* @ludeeus homeassistant/components/tautulli/* @ludeeus

View File

@ -1,13 +1,12 @@
"""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.const import CONF_PASSWORD, CONF_USERNAME from homeassistant.const import CONF_PASSWORD, CONF_USERNAME
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers import config_validation as cv from homeassistant.helpers import config_validation as cv
from homeassistant.helpers.discovery import load_platform from homeassistant.helpers.discovery import load_platform
from homeassistant.helpers.dispatcher import dispatcher_send from homeassistant.helpers.dispatcher import dispatcher_send
@ -110,7 +109,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, RequestException) as exc: except (RuntimeError, urllib.error.HTTPError) as exc:
_LOGGER.error("Unable to connect: %s", exc) _LOGGER.error("Unable to connect: %s", exc)
return False return False
@ -137,12 +136,7 @@ class TadoConnector:
if sensor_type == "zone": if sensor_type == "zone":
data = self.tado.getState(sensor) data = self.tado.getState(sensor)
elif sensor_type == "device": elif sensor_type == "device":
devices_data = self.tado.getDevices() data = self.tado.getDevices()[0]
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
@ -168,62 +162,31 @@ class TadoConnector:
self.tado.resetZoneOverlay(zone_id) self.tado.resetZoneOverlay(zone_id)
self.update_sensor("zone", zone_id) self.update_sensor("zone", zone_id)
def set_home(self):
"""Put tado in home mode."""
response_json = None
try:
response_json = self.tado.setHome()
except RequestException as exc:
_LOGGER.error("Could not set home: %s", exc)
_raise_home_away_errors(response_json)
def set_away(self):
"""Put tado in away mode."""
response_json = None
try:
response_json = self.tado.setAway()
except RequestException as exc:
_LOGGER.error("Could not set away: %s", exc)
_raise_home_away_errors(response_json)
def set_zone_overlay( def set_zone_overlay(
self, self,
zone_id=None, zone_id,
overlay_mode=None, overlay_mode,
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: overlay_mode=%s, temp=%s, duration=%s, type=%s, mode=%s fan_speed=%s", "Set overlay for zone %s: mode=%s, temp=%s, duration=%s, type=%s, mode=%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, zone_id, overlay_mode, temperature, duration, device_type, "ON", mode
overlay_mode,
temperature,
duration,
device_type,
"ON",
mode,
fan_speed,
) )
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)
@ -233,18 +196,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 RequestException as exc: except urllib.error.HTTPError as exc:
_LOGGER.error("Could not set zone overlay: %s", exc) _LOGGER.error("Could not set zone overlay: %s", exc.read())
self.update_sensor("zone", zone_id) self.update_sensor("zone", zone_id)
def _raise_home_away_errors(response_json):
if response_json is None:
return
# Likely we are displaying to the user:
# Tried to update to HOME though all mobile devices are detected outside the home fence
if "errors" in response_json and len(response_json["errors"]) > 0:
error_list = response_json["errors"]
raise HomeAssistantError(error_list[0]["title"])

View File

@ -3,12 +3,21 @@ 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_AUTO, FAN_HIGH,
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,
PRESET_AWAY, PRESET_AWAY,
PRESET_HOME, PRESET_HOME,
SUPPORT_FAN_MODE,
SUPPORT_PRESET_MODE, SUPPORT_PRESET_MODE,
SUPPORT_TARGET_TEMPERATURE, SUPPORT_TARGET_TEMPERATURE,
) )
@ -18,29 +27,49 @@ 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_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_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,
) )
from .tado_adapter import TadoZoneData
_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."""
@ -67,80 +96,29 @@ 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
for mode in ORDERED_KNOWN_TADO_MODES: if "HEAT" in capabilities:
if mode not in capabilities: temperatures = capabilities["HEAT"]["temperatures"]
continue ac_support_heat = True
supported_hvac_modes.append(TADO_TO_HA_HVAC_MODE_MAP[mode])
if not capabilities[mode].get("fanSpeeds"):
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:
supported_hvac_modes.append(HVAC_MODE_HEAT) temperatures = capabilities["COOL"]["temperatures"]
elif "temperatures" in capabilities:
if CONST_MODE_HEAT in capabilities: temperatures = capabilities["temperatures"]
heat_temperatures = capabilities[CONST_MODE_HEAT]["temperatures"] else:
_LOGGER.debug("Not adding zone %s since it has no temperature", name)
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
heat_min_temp = None min_temp = float(temperatures["celsius"]["min"])
heat_max_temp = None max_temp = float(temperatures["celsius"]["max"])
heat_step = None step = temperatures["celsius"].get("step", PRECISION_TENTHS)
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, tado, name, zone_id, zone_type, min_temp, max_temp, step, ac_support_heat,
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
@ -154,15 +132,10 @@ class TadoClimate(ClimateDevice):
zone_name, zone_name,
zone_id, zone_id,
zone_type, zone_type,
heat_min_temp, min_temp,
heat_max_temp, max_temp,
heat_step, step,
cool_min_temp, ac_support_heat,
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
@ -173,45 +146,49 @@ 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._supported_hvac_modes = supported_hvac_modes self._ac_support_heat = ac_support_heat
self._supported_fan_modes = supported_fan_modes self._cooling = False
self._support_flags = support_flags
self._available = False self._active = 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._heat_min_temp = heat_min_temp self._min_temp = min_temp
self._heat_max_temp = heat_max_temp self._max_temp = max_temp
self._heat_step = heat_step self._step = 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
self._current_tado_fan_speed = CONST_FAN_OFF if tado.fallback:
self._current_tado_hvac_mode = CONST_MODE_OFF # Fallback to Smart Schedule at next Schedule switch
self._current_hvac_action = CURRENT_HVAC_OFF 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._tado_zone_data = None self._current_fan = CONST_MODE_OFF
self._async_update_zone_data() self._current_operation = CONST_MODE_SMART_SCHEDULE
self._overlay_mode = CONST_MODE_SMART_SCHEDULE
async def async_added_to_hass(self): async def async_added_to_hass(self):
"""Register for sensor updates.""" """Register for sensor updates."""
@callback
def async_update_callback():
"""Schedule an entity update."""
self.async_schedule_update_ha_state(True)
async_dispatcher_connect( 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),
self._async_update_callback, 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 self._support_flags return SUPPORT_FLAGS
@property @property
def name(self): def name(self):
@ -231,12 +208,12 @@ class TadoClimate(ClimateDevice):
@property @property
def current_humidity(self): def current_humidity(self):
"""Return the current humidity.""" """Return the current humidity."""
return self._tado_zone_data.current_humidity return self._cur_humidity
@property @property
def current_temperature(self): def current_temperature(self):
"""Return the sensor temperature.""" """Return the sensor temperature."""
return self._tado_zone_data.current_temp return self._cur_temp
@property @property
def hvac_mode(self): def hvac_mode(self):
@ -244,9 +221,11 @@ class TadoClimate(ClimateDevice):
Need to be one of HVAC_MODE_*. Need to be one of HVAC_MODE_*.
""" """
return TADO_TO_HA_HVAC_MODE_MAP.get( if self._ac_device and self._ac_support_heat:
self._tado_zone_data.current_tado_hvac_mode, CURRENT_HVAC_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):
@ -254,7 +233,11 @@ class TadoClimate(ClimateDevice):
Need to be a subset of HVAC_MODES. Need to be a subset of HVAC_MODES.
""" """
return self._supported_hvac_modes if self._ac_device:
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):
@ -262,28 +245,40 @@ class TadoClimate(ClimateDevice):
Need to be one of CURRENT_HVAC_*. Need to be one of CURRENT_HVAC_*.
""" """
return self._tado_zone_data.current_hvac_action if not self._device_is_active:
return 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 TADO_TO_HA_FAN_MODE_MAP.get(self._current_tado_fan_speed, FAN_AUTO) return FAN_MAP_TADO.get(self._current_fan)
return None return None
@property @property
def fan_modes(self): def fan_modes(self):
"""List of available fan modes.""" """List of available fan modes."""
return self._supported_fan_modes if self._ac_device:
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."""
self._control_hvac(fan_mode=HA_TO_TADO_FAN_MODE_MAP[fan_mode]) pass
@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._tado_zone_data.is_away: if self._is_away:
return PRESET_AWAY return PRESET_AWAY
return PRESET_HOME return PRESET_HOME
@ -294,10 +289,7 @@ class TadoClimate(ClimateDevice):
def set_preset_mode(self, preset_mode): def set_preset_mode(self, preset_mode):
"""Set new preset mode.""" """Set new preset mode."""
if preset_mode == PRESET_HOME: pass
self._tado.set_home()
else:
self._tado.set_away()
@property @property
def temperature_unit(self): def temperature_unit(self):
@ -307,14 +299,12 @@ 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."""
if self._tado_zone_data.current_tado_hvac_mode == CONST_MODE_COOL: return self._step
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._tado_zone_data.target_temp return self._target_temp
def set_temperature(self, **kwargs): def set_temperature(self, **kwargs):
"""Set new target temperature.""" """Set new target temperature."""
@ -322,142 +312,174 @@ class TadoClimate(ClimateDevice):
if temperature is None: if temperature is None:
return return
self._control_hvac(target_temp=temperature) self._current_operation = self._default_overlay
self._overlay_mode = None
self._target_temp = temperature
self._control_heating()
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
self._control_hvac(hvac_mode=HA_TO_TADO_HVAC_MODE_MAP[hvac_mode]) if hvac_mode == HVAC_MODE_OFF:
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
@property self._current_operation = mode
def available(self): self._overlay_mode = None
"""Return if the device is available."""
return self._tado_zone_data.available # Set a target temperature if we don't have any
# 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."""
if ( return self._min_temp
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 (
self._current_tado_hvac_mode == CONST_MODE_HEAT "temperature" in data["setting"]
and self._heat_max_temp is not None and data["setting"]["temperature"] is not None
): ):
return self._heat_max_temp setting = float(data["setting"]["temperature"]["celsius"])
if self._heat_max_temp is not None: self._target_temp = setting
return self._heat_max_temp
return self._heat_max_temp if "tadoMode" in data:
mode = data["tadoMode"]
self._is_away = mode == "AWAY"
@callback if "setting" in data:
def _async_update_zone_data(self): power = data["setting"]["power"]
"""Load tado data into zone.""" if power == "OFF":
self._tado_zone_data = TadoZoneData( self._current_operation = CONST_MODE_OFF
self._tado.data["zone"][self.zone_id], self.zone_id self._current_fan = CONST_MODE_OFF
) # There is no overlay, the mode will always be
# "SMART_SCHEDULE"
@callback self._overlay_mode = CONST_MODE_SMART_SCHEDULE
def _async_update_callback(self): self._device_is_active = False
"""Load tado data and update state."""
self._async_update_zone_data()
self.async_write_ha_state()
def _normalize_target_temp_for_hvac_mode(self):
# Set a target temperature if we don't have any
# This can happen when we switch from Off to On
if self._target_temp is None:
if self._current_tado_hvac_mode == CONST_MODE_COOL:
self._target_temp = self._cool_max_temp
else: else:
self._target_temp = self._heat_min_temp self._device_is_active = True
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
def _control_hvac(self, hvac_mode=None, target_temp=None, fan_mode=None): active = False
"""Send new target temperature to Tado.""" if "activityDataPoints" in data:
activity_data = data["activityDataPoints"]
if hvac_mode: if self._ac_device:
self._current_tado_hvac_mode = hvac_mode if "acPower" in activity_data and activity_data["acPower"] is not None:
if not activity_data["acPower"]["value"] == "OFF":
if target_temp: active = True
self._target_temp = target_temp else:
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 ( if (
self._current_tado_fan_speed == CONST_FAN_OFF "heatingPower" in activity_data
and self._current_tado_hvac_mode != CONST_MODE_OFF and activity_data["heatingPower"] is not None
): ):
self._current_tado_fan_speed = CONST_FAN_AUTO if float(activity_data["heatingPower"]["percentage"]) > 0.0:
active = True
self._active = active
if self._current_tado_hvac_mode == CONST_MODE_OFF: overlay = False
_LOGGER.debug( overlay_data = None
"Switching to OFF for zone %s (%d)", self.zone_name, self.zone_id termination = CONST_MODE_SMART_SCHEDULE
) cooling = False
self._tado.set_zone_off(self.zone_id, CONST_OVERLAY_MANUAL, self.zone_type) fan_speed = CONST_MODE_OFF
return
if self._current_tado_hvac_mode == CONST_MODE_SMART_SCHEDULE: if "overlay" in data:
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."""
if self._current_operation == 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_tado_hvac_mode, self._current_operation,
self.zone_name, self.zone_name,
self.zone_id, self.zone_id,
self._target_temp, self._target_temp,
) )
# 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
)
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( self._tado.set_zone_overlay(
zone_id=self.zone_id, self.zone_id,
overlay_mode=overlay_mode, # What to do when the period ends self._current_operation,
temperature=temperature_to_send, self._target_temp,
duration=None, None,
device_type=self.zone_type, self.zone_type,
mode=self._current_tado_hvac_mode, "COOL" if self._ac_device else None,
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

View File

@ -1,26 +1,5 @@
"""Constant values for the Tado component.""" """Constant values for the Tado component."""
from homeassistant.components.climate.const import (
CURRENT_HVAC_COOL,
CURRENT_HVAC_DRY,
CURRENT_HVAC_FAN,
CURRENT_HVAC_HEAT,
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,
)
# Configuration # Configuration
CONF_FALLBACK = "fallback" CONF_FALLBACK = "fallback"
DATA = "data" DATA = "data"
@ -31,81 +10,10 @@ 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_AUTO = "AUTO" CONST_MODE_OFF = "OFF" # Switch off heating in a zone
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]

View File

@ -3,10 +3,10 @@
"name": "Tado", "name": "Tado",
"documentation": "https://www.home-assistant.io/integrations/tado", "documentation": "https://www.home-assistant.io/integrations/tado",
"requirements": [ "requirements": [
"python-tado==0.4.0" "python-tado==0.3.0"
], ],
"dependencies": [], "dependencies": [],
"codeowners": [ "codeowners": [
"@michaelarnauts", "@bdraco" "@michaelarnauts"
] ]
} }

View File

@ -8,7 +8,6 @@ from homeassistant.helpers.entity import Entity
from . import DATA, DOMAIN, SIGNAL_TADO_UPDATE_RECEIVED from . import DATA, DOMAIN, SIGNAL_TADO_UPDATE_RECEIVED
from .const import TYPE_AIR_CONDITIONING, TYPE_HEATING, TYPE_HOT_WATER from .const import TYPE_AIR_CONDITIONING, TYPE_HEATING, TYPE_HOT_WATER
from .tado_adapter import TadoZoneData
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@ -51,7 +50,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
for zone in tado.zones: for zone in tado.zones:
entities.extend( entities.extend(
[ [
create_zone_sensor(hass, tado, zone["name"], zone["id"], variable) create_zone_sensor(tado, zone["name"], zone["id"], variable)
for variable in ZONE_SENSORS.get(zone["type"]) for variable in ZONE_SENSORS.get(zone["type"])
] ]
) )
@ -60,7 +59,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
for home in tado.devices: for home in tado.devices:
entities.extend( entities.extend(
[ [
create_device_sensor(hass, tado, home["name"], home["id"], variable) create_device_sensor(tado, home["name"], home["id"], variable)
for variable in DEVICE_SENSORS for variable in DEVICE_SENSORS
] ]
) )
@ -68,22 +67,21 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
add_entities(entities, True) add_entities(entities, True)
def create_zone_sensor(hass, tado, name, zone_id, variable): def create_zone_sensor(tado, name, zone_id, variable):
"""Create a zone sensor.""" """Create a zone sensor."""
return TadoSensor(hass, tado, name, "zone", zone_id, variable) return TadoSensor(tado, name, "zone", zone_id, variable)
def create_device_sensor(hass, tado, name, device_id, variable): def create_device_sensor(tado, name, device_id, variable):
"""Create a device sensor.""" """Create a device sensor."""
return TadoSensor(hass, tado, name, "device", device_id, variable) return TadoSensor(tado, name, "device", device_id, variable)
class TadoSensor(Entity): class TadoSensor(Entity):
"""Representation of a tado Sensor.""" """Representation of a tado Sensor."""
def __init__(self, hass, tado, zone_name, sensor_type, zone_id, zone_variable): def __init__(self, tado, zone_name, sensor_type, zone_id, zone_variable):
"""Initialize of the Tado Sensor.""" """Initialize of the Tado Sensor."""
self.hass = hass
self._tado = tado self._tado = tado
self.zone_name = zone_name self.zone_name = zone_name
@ -95,16 +93,19 @@ class TadoSensor(Entity):
self._state = None self._state = None
self._state_attributes = None self._state_attributes = None
self._tado_zone_data = None
self._async_update_zone_data()
async def async_added_to_hass(self): async def async_added_to_hass(self):
"""Register for sensor updates.""" """Register for sensor updates."""
@callback
def async_update_callback():
"""Schedule an entity update."""
self.async_schedule_update_ha_state(True)
async_dispatcher_connect( async_dispatcher_connect(
self.hass, self.hass,
SIGNAL_TADO_UPDATE_RECEIVED.format(self.sensor_type, self.zone_id), SIGNAL_TADO_UPDATE_RECEIVED.format(self.sensor_type, self.zone_id),
self._async_update_callback, async_update_callback,
) )
@property @property
@ -148,74 +149,97 @@ class TadoSensor(Entity):
return "mdi:water-percent" return "mdi:water-percent"
@property @property
def should_poll(self): def should_poll(self) -> bool:
"""Do not poll.""" """Do not poll."""
return False return False
@callback def update(self):
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] data = self._tado.data[self.sensor_type][self.zone_id]
except KeyError: except KeyError:
return return
self._tado_zone_data = TadoZoneData(data, self.zone_id) unit = TEMP_CELSIUS
if self.zone_variable == "temperature": if self.zone_variable == "temperature":
self._state = self.hass.config.units.temperature( if "sensorDataPoints" in data:
self._tado_zone_data.current_temp, TEMP_CELSIUS sensor_data = data["sensorDataPoints"]
) temperature = float(sensor_data["insideTemperature"]["celsius"])
self._state = self.hass.config.units.temperature(temperature, unit)
self._state_attributes = { self._state_attributes = {
"time": self._tado_zone_data.current_temp_timestamp, "time": sensor_data["insideTemperature"]["timestamp"],
"setting": 0, # setting is used in climate device "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":
self._state = self._tado_zone_data.current_humidity if "sensorDataPoints" in data:
self._state_attributes = { sensor_data = data["sensorDataPoints"]
"time": self._tado_zone_data.current_humidity_timestamp self._state = float(sensor_data["humidity"]["percentage"])
} self._state_attributes = {"time": sensor_data["humidity"]["timestamp"]}
elif self.zone_variable == "power": elif self.zone_variable == "power":
self._state = self._tado_zone_data.power if "setting" in data:
self._state = data["setting"]["power"]
elif self.zone_variable == "link": elif self.zone_variable == "link":
self._state = self._tado_zone_data.link if "link" in data:
self._state = data["link"]["state"]
elif self.zone_variable == "heating": elif self.zone_variable == "heating":
self._state = self._tado_zone_data.heating_power_percentage if "activityDataPoints" in data:
activity_data = data["activityDataPoints"]
if (
"heatingPower" in activity_data
and activity_data["heatingPower"] is not None
):
self._state = float(activity_data["heatingPower"]["percentage"])
self._state_attributes = { self._state_attributes = {
"time": self._tado_zone_data.heating_power_timestamp "time": activity_data["heatingPower"]["timestamp"]
} }
elif self.zone_variable == "ac": elif self.zone_variable == "ac":
self._state = self._tado_zone_data.ac_power if "activityDataPoints" in data:
self._state_attributes = {"time": self._tado_zone_data.ac_power_timestamp} activity_data = data["activityDataPoints"]
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":
self._state = self._tado_zone_data.connection if "connectionState" in data:
self._state = data["connectionState"]["value"]
elif self.zone_variable == "tado mode": elif self.zone_variable == "tado mode":
self._state = self._tado_zone_data.tado_mode if "tadoMode" in data:
self._state = data["tadoMode"]
elif self.zone_variable == "overlay": elif self.zone_variable == "overlay":
self._state = self._tado_zone_data.overlay_active self._state = "overlay" in data and data["overlay"] is not None
self._state_attributes = ( self._state_attributes = (
{"termination": self._tado_zone_data.overlay_termination_type} {"termination": data["overlay"]["termination"]["type"]}
if self._tado_zone_data.overlay_active if self._state
else {} else {}
) )
elif self.zone_variable == "early start": elif self.zone_variable == "early start":
self._state = self._tado_zone_data.preparation is not None self._state = "preparation" in data and data["preparation"] is not None
elif self.zone_variable == "open window": elif self.zone_variable == "open window":
self._state = self._tado_zone_data.open_window is not None self._state = "openWindow" in data and data["openWindow"] is not None
self._state_attributes = self._tado_zone_data.open_window_attr self._state_attributes = data["openWindow"] if self._state else {}

View File

@ -1,285 +0,0 @@
"""Adapter to represent a tado zones and state."""
import logging
from homeassistant.components.climate.const import (
CURRENT_HVAC_COOL,
CURRENT_HVAC_HEAT,
CURRENT_HVAC_IDLE,
CURRENT_HVAC_OFF,
)
from .const import (
CONST_FAN_AUTO,
CONST_FAN_OFF,
CONST_LINK_OFFLINE,
CONST_MODE_OFF,
CONST_MODE_SMART_SCHEDULE,
DEFAULT_TADO_PRECISION,
TADO_MODES_TO_HA_CURRENT_HVAC_ACTION,
)
_LOGGER = logging.getLogger(__name__)
class TadoZoneData:
"""Represent a tado zone."""
def __init__(self, data, zone_id):
"""Create a tado zone."""
self._data = data
self._zone_id = zone_id
self._current_temp = None
self._connection = None
self._current_temp_timestamp = None
self._current_humidity = None
self._is_away = False
self._current_hvac_action = None
self._current_tado_fan_speed = None
self._current_tado_hvac_mode = None
self._target_temp = None
self._available = False
self._power = None
self._link = None
self._ac_power_timestamp = None
self._heating_power_timestamp = None
self._ac_power = None
self._heating_power = None
self._heating_power_percentage = None
self._tado_mode = None
self._overlay_active = None
self._overlay_termination_type = None
self._preparation = None
self._open_window = None
self._open_window_attr = None
self._precision = DEFAULT_TADO_PRECISION
self.update_data(data)
@property
def preparation(self):
"""Zone is preparing to heat."""
return self._preparation
@property
def open_window(self):
"""Window is open."""
return self._open_window
@property
def open_window_attr(self):
"""Window open attributes."""
return self._open_window_attr
@property
def current_temp(self):
"""Temperature of the zone."""
return self._current_temp
@property
def current_temp_timestamp(self):
"""Temperature of the zone timestamp."""
return self._current_temp_timestamp
@property
def connection(self):
"""Up or down internet connection."""
return self._connection
@property
def tado_mode(self):
"""Tado mode."""
return self._tado_mode
@property
def overlay_active(self):
"""Overlay acitive."""
return self._current_tado_hvac_mode != CONST_MODE_SMART_SCHEDULE
@property
def overlay_termination_type(self):
"""Overlay termination type (what happens when period ends)."""
return self._overlay_termination_type
@property
def current_humidity(self):
"""Humidity of the zone."""
return self._current_humidity
@property
def current_humidity_timestamp(self):
"""Humidity of the zone timestamp."""
return self._current_humidity_timestamp
@property
def ac_power_timestamp(self):
"""AC power timestamp."""
return self._ac_power_timestamp
@property
def heating_power_timestamp(self):
"""Heating power timestamp."""
return self._heating_power_timestamp
@property
def ac_power(self):
"""AC power."""
return self._ac_power
@property
def heating_power(self):
"""Heating power."""
return self._heating_power
@property
def heating_power_percentage(self):
"""Heating power percentage."""
return self._heating_power_percentage
@property
def is_away(self):
"""Is Away (not home)."""
return self._is_away
@property
def power(self):
"""Power is on."""
return self._power
@property
def current_hvac_action(self):
"""HVAC Action (home assistant const)."""
return self._current_hvac_action
@property
def current_tado_fan_speed(self):
"""TADO Fan speed (tado const)."""
return self._current_tado_fan_speed
@property
def link(self):
"""Link (internet connection state)."""
return self._link
@property
def precision(self):
"""Precision of temp units."""
return self._precision
@property
def current_tado_hvac_mode(self):
"""TADO HVAC Mode (tado const)."""
return self._current_tado_hvac_mode
@property
def target_temp(self):
"""Target temperature (C)."""
return self._target_temp
@property
def available(self):
"""Device is available and link is up."""
return self._available
def update_data(self, data):
"""Handle update callbacks."""
_LOGGER.debug("Updating climate platform for zone %d", self._zone_id)
if "sensorDataPoints" in data:
sensor_data = data["sensorDataPoints"]
if "insideTemperature" in sensor_data:
temperature = float(sensor_data["insideTemperature"]["celsius"])
self._current_temp = temperature
self._current_temp_timestamp = sensor_data["insideTemperature"][
"timestamp"
]
if "precision" in sensor_data["insideTemperature"]:
self._precision = sensor_data["insideTemperature"]["precision"][
"celsius"
]
if "humidity" in sensor_data:
humidity = float(sensor_data["humidity"]["percentage"])
self._current_humidity = humidity
self._current_humidity_timestamp = sensor_data["humidity"]["timestamp"]
self._is_away = None
self._tado_mode = None
if "tadoMode" in data:
self._is_away = data["tadoMode"] == "AWAY"
self._tado_mode = data["tadoMode"]
self._link = None
if "link" in data:
self._link = data["link"]["state"]
self._current_hvac_action = CURRENT_HVAC_OFF
if "setting" in data:
# 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._target_temp = setting
setting = data["setting"]
self._current_tado_fan_speed = CONST_FAN_OFF
# If there is no overlay, the mode will always be
# "SMART_SCHEDULE"
if "mode" in setting:
self._current_tado_hvac_mode = setting["mode"]
else:
self._current_tado_hvac_mode = CONST_MODE_OFF
self._power = setting["power"]
if self._power == "ON":
# Not all devices have fans
self._current_tado_fan_speed = setting.get("fanSpeed", CONST_FAN_AUTO)
self._current_hvac_action = CURRENT_HVAC_IDLE
self._preparation = "preparation" in data and data["preparation"] is not None
self._open_window = "openWindow" in data and data["openWindow"] is not None
self._open_window_attr = data["openWindow"] if self._open_window else {}
if "activityDataPoints" in data:
activity_data = data["activityDataPoints"]
if "acPower" in activity_data and activity_data["acPower"] is not None:
self._ac_power = activity_data["acPower"]["value"]
self._ac_power_timestamp = activity_data["acPower"]["timestamp"]
if activity_data["acPower"]["value"] == "ON" and self._power == "ON":
# acPower means the unit has power so we need to map the mode
self._current_hvac_action = TADO_MODES_TO_HA_CURRENT_HVAC_ACTION.get(
self._current_tado_hvac_mode, CURRENT_HVAC_COOL
)
if (
"heatingPower" in activity_data
and activity_data["heatingPower"] is not None
):
self._heating_power = activity_data["heatingPower"].get("value", None)
self._heating_power_timestamp = activity_data["heatingPower"][
"timestamp"
]
self._heating_power_percentage = float(
activity_data["heatingPower"].get("percentage", 0)
)
if self._heating_power_percentage > 0.0 and self._power == "ON":
self._current_hvac_action = CURRENT_HVAC_HEAT
# If there is no overlay
# then we are running the smart schedule
self._overlay_termination_type = None
if "overlay" in data and data["overlay"] is not None:
if (
"termination" in data["overlay"]
and "type" in data["overlay"]["termination"]
):
self._overlay_termination_type = data["overlay"]["termination"]["type"]
else:
self._current_tado_hvac_mode = CONST_MODE_SMART_SCHEDULE
self._connection = (
data["connectionState"]["value"] if "connectionState" in data else None
)
self._available = self._link != CONST_LINK_OFFLINE

View File

@ -12,7 +12,6 @@ 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_MODE_HEAT,
CONST_MODE_OFF, CONST_MODE_OFF,
CONST_MODE_SMART_SCHEDULE, CONST_MODE_SMART_SCHEDULE,
CONST_OVERLAY_MANUAL, CONST_OVERLAY_MANUAL,
@ -52,16 +51,14 @@ 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"] in [TYPE_HOT_WATER]:
entity = create_water_heater_entity( entity = create_water_heater_entity(tado, zone["name"], zone["id"])
hass, tado, zone["name"], zone["id"]
)
entities.append(entity) entities.append(entity)
if entities: if entities:
add_entities(entities, True) add_entities(entities, True)
def create_water_heater_entity(hass, 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"]
@ -75,7 +72,7 @@ def create_water_heater_entity(hass, tado, name: str, zone_id: int):
max_temp = None max_temp = None
entity = TadoWaterHeater( entity = TadoWaterHeater(
hass, tado, name, zone_id, supports_temperature_control, min_temp, max_temp tado, name, zone_id, supports_temperature_control, min_temp, max_temp
) )
return entity return entity
@ -86,7 +83,6 @@ class TadoWaterHeater(WaterHeaterDevice):
def __init__( def __init__(
self, self,
hass,
tado, tado,
zone_name, zone_name,
zone_id, zone_id,
@ -95,7 +91,6 @@ class TadoWaterHeater(WaterHeaterDevice):
max_temp, max_temp,
): ):
"""Initialize of Tado water heater entity.""" """Initialize of Tado water heater entity."""
self.hass = hass
self._tado = tado self._tado = tado
self.zone_name = zone_name self.zone_name = zone_name
@ -115,17 +110,28 @@ 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
self._current_tado_heat_mode = CONST_MODE_SMART_SCHEDULE if tado.fallback:
# 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._async_update_data()
async def async_added_to_hass(self): async def async_added_to_hass(self):
"""Register for sensor updates.""" """Register for sensor updates."""
@callback
def async_update_callback():
"""Schedule an entity update."""
self.async_schedule_update_ha_state(True)
async_dispatcher_connect( 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),
self._async_update_callback, async_update_callback,
) )
@property @property
@ -151,7 +157,7 @@ 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_tado_heat_mode) return WATER_HEATER_MAP_TADO.get(self._current_operation)
@property @property
def target_temperature(self): def target_temperature(self):
@ -192,9 +198,16 @@ 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 = CONST_MODE_HEAT mode = self._default_overlay
self._control_heater(heat_mode=mode) self._current_operation = 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."""
@ -202,17 +215,13 @@ 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._control_heater(target_temp=temperature) self._current_operation = self._default_overlay
self._overlay_mode = None
self._target_temp = temperature
self._control_heater()
@callback def update(self):
def _async_update_callback(self): """Handle update callbacks."""
"""Load tado data and update state."""
self._async_update_data()
self.async_write_ha_state()
@callback
def _async_update_data(self):
"""Load tado data."""
_LOGGER.debug("Updating water_heater platform for zone %d", self.zone_id) _LOGGER.debug("Updating water_heater platform for zone %d", self.zone_id)
data = self._tado.data["zone"][self.zone_id] data = self._tado.data["zone"][self.zone_id]
@ -223,70 +232,71 @@ class TadoWaterHeater(WaterHeaterDevice):
if "setting" in data: if "setting" in data:
power = data["setting"]["power"] power = data["setting"]["power"]
if power == "OFF": if power == "OFF":
self._current_tado_heat_mode = CONST_MODE_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: else:
self._current_tado_heat_mode = CONST_MODE_HEAT self._device_is_active = True
# temperature setting will not exist when device is off # temperature setting will not exist when device is off
if ( if (
"temperature" in data["setting"] "temperature" in data["setting"]
and data["setting"]["temperature"] is not None and data["setting"]["temperature"] is not None
): ):
self._target_temp = float(data["setting"]["temperature"]["celsius"]) setting = float(data["setting"]["temperature"]["celsius"])
self._target_temp = setting
# If there is no overlay overlay = False
# then we are running the smart schedule overlay_data = None
if "overlay" in data and data["overlay"] is None: termination = CONST_MODE_SMART_SCHEDULE
self._current_tado_heat_mode = CONST_MODE_SMART_SCHEDULE
self.async_write_ha_state() if "overlay" in data:
overlay_data = data["overlay"]
overlay = overlay_data is not None
def _control_heater(self, heat_mode=None, target_temp=None): if overlay:
termination = overlay_data["termination"]["type"]
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
def _control_heater(self):
"""Send new target temperature.""" """Send new target temperature."""
if self._current_operation == CONST_MODE_SMART_SCHEDULE:
if heat_mode:
self._current_tado_heat_mode = heat_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_heat_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_tado_heat_mode == CONST_MODE_OFF: if self._current_operation == 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_tado_heat_mode, self._current_operation,
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(
zone_id=self.zone_id, self.zone_id,
overlay_mode=overlay_mode, self._current_operation,
temperature=self._target_temp, self._target_temp,
duration=None, None,
device_type=TYPE_HOT_WATER, TYPE_HOT_WATER,
) )
self._overlay_mode = self._current_tado_heat_mode self._overlay_mode = self._current_operation

View File

@ -1650,7 +1650,7 @@ python-songpal==0.11.2
python-synology==0.4.0 python-synology==0.4.0
# homeassistant.components.tado # homeassistant.components.tado
python-tado==0.4.0 python-tado==0.3.0
# homeassistant.components.telegram_bot # homeassistant.components.telegram_bot
python-telegram-bot==11.1.0 python-telegram-bot==11.1.0

View File

@ -580,9 +580,6 @@ 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.4.0
# homeassistant.components.twitch # homeassistant.components.twitch
python-twitch-client==0.6.0 python-twitch-client==0.6.0

View File

@ -1,18 +0,0 @@
"""Mocks for the tado component."""
import json
import os
from homeassistant.components.tado.tado_adapter import TadoZoneData
from tests.common import load_fixture
async def _mock_tado_climate_zone_from_fixture(hass, file):
return TadoZoneData(await _load_json_fixture(hass, file), 1)
async def _load_json_fixture(hass, path):
fixture = await hass.async_add_executor_job(
load_fixture, os.path.join("tado", path)
)
return json.loads(fixture)

View File

@ -1,423 +0,0 @@
"""The tado_adapter tests for the tado platform."""
from tests.components.tado.mocks import _mock_tado_climate_zone_from_fixture
async def test_ac_issue_32294_heat_mode(hass):
"""Test smart ac cool mode."""
ac_issue_32294_heat_mode = await _mock_tado_climate_zone_from_fixture(
hass, "ac_issue_32294.heat_mode.json"
)
assert ac_issue_32294_heat_mode.preparation is False
assert ac_issue_32294_heat_mode.open_window is False
assert ac_issue_32294_heat_mode.open_window_attr == {}
assert ac_issue_32294_heat_mode.current_temp == 21.82
assert ac_issue_32294_heat_mode.current_temp_timestamp == "2020-02-29T22:51:05.016Z"
assert ac_issue_32294_heat_mode.connection is None
assert ac_issue_32294_heat_mode.tado_mode == "HOME"
assert ac_issue_32294_heat_mode.overlay_active is False
assert ac_issue_32294_heat_mode.overlay_termination_type is None
assert ac_issue_32294_heat_mode.current_humidity == 40.4
assert (
ac_issue_32294_heat_mode.current_humidity_timestamp
== "2020-02-29T22:51:05.016Z"
)
assert ac_issue_32294_heat_mode.ac_power_timestamp == "2020-02-29T22:50:34.850Z"
assert ac_issue_32294_heat_mode.heating_power_timestamp is None
assert ac_issue_32294_heat_mode.ac_power == "ON"
assert ac_issue_32294_heat_mode.heating_power is None
assert ac_issue_32294_heat_mode.heating_power_percentage is None
assert ac_issue_32294_heat_mode.is_away is False
assert ac_issue_32294_heat_mode.power == "ON"
assert ac_issue_32294_heat_mode.current_hvac_action == "heating"
assert ac_issue_32294_heat_mode.current_tado_fan_speed == "AUTO"
assert ac_issue_32294_heat_mode.link == "ONLINE"
assert ac_issue_32294_heat_mode.current_tado_hvac_mode == "SMART_SCHEDULE"
assert ac_issue_32294_heat_mode.target_temp == 25.0
assert ac_issue_32294_heat_mode.available is True
assert ac_issue_32294_heat_mode.precision == 0.1
async def test_smartac3_smart_mode(hass):
"""Test smart ac smart mode."""
smartac3_smart_mode = await _mock_tado_climate_zone_from_fixture(
hass, "smartac3.smart_mode.json"
)
assert smartac3_smart_mode.preparation is False
assert smartac3_smart_mode.open_window is False
assert smartac3_smart_mode.open_window_attr == {}
assert smartac3_smart_mode.current_temp == 24.43
assert smartac3_smart_mode.current_temp_timestamp == "2020-03-05T03:50:24.769Z"
assert smartac3_smart_mode.connection is None
assert smartac3_smart_mode.tado_mode == "HOME"
assert smartac3_smart_mode.overlay_active is False
assert smartac3_smart_mode.overlay_termination_type is None
assert smartac3_smart_mode.current_humidity == 60.0
assert smartac3_smart_mode.current_humidity_timestamp == "2020-03-05T03:50:24.769Z"
assert smartac3_smart_mode.ac_power_timestamp == "2020-03-05T03:52:22.253Z"
assert smartac3_smart_mode.heating_power_timestamp is None
assert smartac3_smart_mode.ac_power == "OFF"
assert smartac3_smart_mode.heating_power is None
assert smartac3_smart_mode.heating_power_percentage is None
assert smartac3_smart_mode.is_away is False
assert smartac3_smart_mode.power == "ON"
assert smartac3_smart_mode.current_hvac_action == "idle"
assert smartac3_smart_mode.current_tado_fan_speed == "MIDDLE"
assert smartac3_smart_mode.link == "ONLINE"
assert smartac3_smart_mode.current_tado_hvac_mode == "SMART_SCHEDULE"
assert smartac3_smart_mode.target_temp == 20.0
assert smartac3_smart_mode.available is True
assert smartac3_smart_mode.precision == 0.1
async def test_smartac3_cool_mode(hass):
"""Test smart ac cool mode."""
smartac3_cool_mode = await _mock_tado_climate_zone_from_fixture(
hass, "smartac3.cool_mode.json"
)
assert smartac3_cool_mode.preparation is False
assert smartac3_cool_mode.open_window is False
assert smartac3_cool_mode.open_window_attr == {}
assert smartac3_cool_mode.current_temp == 24.76
assert smartac3_cool_mode.current_temp_timestamp == "2020-03-05T03:57:38.850Z"
assert smartac3_cool_mode.connection is None
assert smartac3_cool_mode.tado_mode == "HOME"
assert smartac3_cool_mode.overlay_active is True
assert smartac3_cool_mode.overlay_termination_type == "TADO_MODE"
assert smartac3_cool_mode.current_humidity == 60.9
assert smartac3_cool_mode.current_humidity_timestamp == "2020-03-05T03:57:38.850Z"
assert smartac3_cool_mode.ac_power_timestamp == "2020-03-05T04:01:07.162Z"
assert smartac3_cool_mode.heating_power_timestamp is None
assert smartac3_cool_mode.ac_power == "ON"
assert smartac3_cool_mode.heating_power is None
assert smartac3_cool_mode.heating_power_percentage is None
assert smartac3_cool_mode.is_away is False
assert smartac3_cool_mode.power == "ON"
assert smartac3_cool_mode.current_hvac_action == "cooling"
assert smartac3_cool_mode.current_tado_fan_speed == "AUTO"
assert smartac3_cool_mode.link == "ONLINE"
assert smartac3_cool_mode.current_tado_hvac_mode == "COOL"
assert smartac3_cool_mode.target_temp == 17.78
assert smartac3_cool_mode.available is True
assert smartac3_cool_mode.precision == 0.1
async def test_smartac3_auto_mode(hass):
"""Test smart ac cool mode."""
smartac3_auto_mode = await _mock_tado_climate_zone_from_fixture(
hass, "smartac3.auto_mode.json"
)
assert smartac3_auto_mode.preparation is False
assert smartac3_auto_mode.open_window is False
assert smartac3_auto_mode.open_window_attr == {}
assert smartac3_auto_mode.current_temp == 24.8
assert smartac3_auto_mode.current_temp_timestamp == "2020-03-05T03:55:38.160Z"
assert smartac3_auto_mode.connection is None
assert smartac3_auto_mode.tado_mode == "HOME"
assert smartac3_auto_mode.overlay_active is True
assert smartac3_auto_mode.overlay_termination_type == "TADO_MODE"
assert smartac3_auto_mode.current_humidity == 62.5
assert smartac3_auto_mode.current_humidity_timestamp == "2020-03-05T03:55:38.160Z"
assert smartac3_auto_mode.ac_power_timestamp == "2020-03-05T03:56:38.627Z"
assert smartac3_auto_mode.heating_power_timestamp is None
assert smartac3_auto_mode.ac_power == "ON"
assert smartac3_auto_mode.heating_power is None
assert smartac3_auto_mode.heating_power_percentage is None
assert smartac3_auto_mode.is_away is False
assert smartac3_auto_mode.power == "ON"
assert smartac3_auto_mode.current_hvac_action == "cooling"
assert smartac3_auto_mode.current_tado_fan_speed == "AUTO"
assert smartac3_auto_mode.link == "ONLINE"
assert smartac3_auto_mode.current_tado_hvac_mode == "AUTO"
assert smartac3_auto_mode.target_temp is None
assert smartac3_auto_mode.available is True
assert smartac3_auto_mode.precision == 0.1
async def test_smartac3_dry_mode(hass):
"""Test smart ac cool mode."""
smartac3_dry_mode = await _mock_tado_climate_zone_from_fixture(
hass, "smartac3.dry_mode.json"
)
assert smartac3_dry_mode.preparation is False
assert smartac3_dry_mode.open_window is False
assert smartac3_dry_mode.open_window_attr == {}
assert smartac3_dry_mode.current_temp == 25.01
assert smartac3_dry_mode.current_temp_timestamp == "2020-03-05T04:02:07.396Z"
assert smartac3_dry_mode.connection is None
assert smartac3_dry_mode.tado_mode == "HOME"
assert smartac3_dry_mode.overlay_active is True
assert smartac3_dry_mode.overlay_termination_type == "TADO_MODE"
assert smartac3_dry_mode.current_humidity == 62.0
assert smartac3_dry_mode.current_humidity_timestamp == "2020-03-05T04:02:07.396Z"
assert smartac3_dry_mode.ac_power_timestamp == "2020-03-05T04:02:40.867Z"
assert smartac3_dry_mode.heating_power_timestamp is None
assert smartac3_dry_mode.ac_power == "ON"
assert smartac3_dry_mode.heating_power is None
assert smartac3_dry_mode.heating_power_percentage is None
assert smartac3_dry_mode.is_away is False
assert smartac3_dry_mode.power == "ON"
assert smartac3_dry_mode.current_hvac_action == "drying"
assert smartac3_dry_mode.current_tado_fan_speed == "AUTO"
assert smartac3_dry_mode.link == "ONLINE"
assert smartac3_dry_mode.current_tado_hvac_mode == "DRY"
assert smartac3_dry_mode.target_temp is None
assert smartac3_dry_mode.available is True
assert smartac3_dry_mode.precision == 0.1
async def test_smartac3_fan_mode(hass):
"""Test smart ac cool mode."""
smartac3_fan_mode = await _mock_tado_climate_zone_from_fixture(
hass, "smartac3.fan_mode.json"
)
assert smartac3_fan_mode.preparation is False
assert smartac3_fan_mode.open_window is False
assert smartac3_fan_mode.open_window_attr == {}
assert smartac3_fan_mode.current_temp == 25.01
assert smartac3_fan_mode.current_temp_timestamp == "2020-03-05T04:02:07.396Z"
assert smartac3_fan_mode.connection is None
assert smartac3_fan_mode.tado_mode == "HOME"
assert smartac3_fan_mode.overlay_active is True
assert smartac3_fan_mode.overlay_termination_type == "TADO_MODE"
assert smartac3_fan_mode.current_humidity == 62.0
assert smartac3_fan_mode.current_humidity_timestamp == "2020-03-05T04:02:07.396Z"
assert smartac3_fan_mode.ac_power_timestamp == "2020-03-05T04:03:44.328Z"
assert smartac3_fan_mode.heating_power_timestamp is None
assert smartac3_fan_mode.ac_power == "ON"
assert smartac3_fan_mode.heating_power is None
assert smartac3_fan_mode.heating_power_percentage is None
assert smartac3_fan_mode.is_away is False
assert smartac3_fan_mode.power == "ON"
assert smartac3_fan_mode.current_hvac_action == "fan"
assert smartac3_fan_mode.current_tado_fan_speed == "AUTO"
assert smartac3_fan_mode.link == "ONLINE"
assert smartac3_fan_mode.current_tado_hvac_mode == "FAN"
assert smartac3_fan_mode.target_temp is None
assert smartac3_fan_mode.available is True
assert smartac3_fan_mode.precision == 0.1
async def test_smartac3_heat_mode(hass):
"""Test smart ac cool mode."""
smartac3_heat_mode = await _mock_tado_climate_zone_from_fixture(
hass, "smartac3.heat_mode.json"
)
assert smartac3_heat_mode.preparation is False
assert smartac3_heat_mode.open_window is False
assert smartac3_heat_mode.open_window_attr == {}
assert smartac3_heat_mode.current_temp == 24.76
assert smartac3_heat_mode.current_temp_timestamp == "2020-03-05T03:57:38.850Z"
assert smartac3_heat_mode.connection is None
assert smartac3_heat_mode.tado_mode == "HOME"
assert smartac3_heat_mode.overlay_active is True
assert smartac3_heat_mode.overlay_termination_type == "TADO_MODE"
assert smartac3_heat_mode.current_humidity == 60.9
assert smartac3_heat_mode.current_humidity_timestamp == "2020-03-05T03:57:38.850Z"
assert smartac3_heat_mode.ac_power_timestamp == "2020-03-05T03:59:36.390Z"
assert smartac3_heat_mode.heating_power_timestamp is None
assert smartac3_heat_mode.ac_power == "ON"
assert smartac3_heat_mode.heating_power is None
assert smartac3_heat_mode.heating_power_percentage is None
assert smartac3_heat_mode.is_away is False
assert smartac3_heat_mode.power == "ON"
assert smartac3_heat_mode.current_hvac_action == "heating"
assert smartac3_heat_mode.current_tado_fan_speed == "AUTO"
assert smartac3_heat_mode.link == "ONLINE"
assert smartac3_heat_mode.current_tado_hvac_mode == "HEAT"
assert smartac3_heat_mode.target_temp == 16.11
assert smartac3_heat_mode.available is True
assert smartac3_heat_mode.precision == 0.1
async def test_smartac3_hvac_off(hass):
"""Test smart ac cool mode."""
smartac3_hvac_off = await _mock_tado_climate_zone_from_fixture(
hass, "smartac3.hvac_off.json"
)
assert smartac3_hvac_off.preparation is False
assert smartac3_hvac_off.open_window is False
assert smartac3_hvac_off.open_window_attr == {}
assert smartac3_hvac_off.current_temp == 21.44
assert smartac3_hvac_off.current_temp_timestamp == "2020-03-05T01:21:44.089Z"
assert smartac3_hvac_off.connection is None
assert smartac3_hvac_off.tado_mode == "AWAY"
assert smartac3_hvac_off.overlay_active is True
assert smartac3_hvac_off.overlay_termination_type == "MANUAL"
assert smartac3_hvac_off.current_humidity == 48.2
assert smartac3_hvac_off.current_humidity_timestamp == "2020-03-05T01:21:44.089Z"
assert smartac3_hvac_off.ac_power_timestamp == "2020-02-29T05:34:10.318Z"
assert smartac3_hvac_off.heating_power_timestamp is None
assert smartac3_hvac_off.ac_power == "OFF"
assert smartac3_hvac_off.heating_power is None
assert smartac3_hvac_off.heating_power_percentage is None
assert smartac3_hvac_off.is_away is True
assert smartac3_hvac_off.power == "OFF"
assert smartac3_hvac_off.current_hvac_action == "off"
assert smartac3_hvac_off.current_tado_fan_speed == "OFF"
assert smartac3_hvac_off.link == "ONLINE"
assert smartac3_hvac_off.current_tado_hvac_mode == "OFF"
assert smartac3_hvac_off.target_temp is None
assert smartac3_hvac_off.available is True
assert smartac3_hvac_off.precision == 0.1
async def test_smartac3_manual_off(hass):
"""Test smart ac cool mode."""
smartac3_manual_off = await _mock_tado_climate_zone_from_fixture(
hass, "smartac3.manual_off.json"
)
assert smartac3_manual_off.preparation is False
assert smartac3_manual_off.open_window is False
assert smartac3_manual_off.open_window_attr == {}
assert smartac3_manual_off.current_temp == 25.01
assert smartac3_manual_off.current_temp_timestamp == "2020-03-05T04:02:07.396Z"
assert smartac3_manual_off.connection is None
assert smartac3_manual_off.tado_mode == "HOME"
assert smartac3_manual_off.overlay_active is True
assert smartac3_manual_off.overlay_termination_type == "MANUAL"
assert smartac3_manual_off.current_humidity == 62.0
assert smartac3_manual_off.current_humidity_timestamp == "2020-03-05T04:02:07.396Z"
assert smartac3_manual_off.ac_power_timestamp == "2020-03-05T04:05:08.804Z"
assert smartac3_manual_off.heating_power_timestamp is None
assert smartac3_manual_off.ac_power == "OFF"
assert smartac3_manual_off.heating_power is None
assert smartac3_manual_off.heating_power_percentage is None
assert smartac3_manual_off.is_away is False
assert smartac3_manual_off.power == "OFF"
assert smartac3_manual_off.current_hvac_action == "off"
assert smartac3_manual_off.current_tado_fan_speed == "OFF"
assert smartac3_manual_off.link == "ONLINE"
assert smartac3_manual_off.current_tado_hvac_mode == "OFF"
assert smartac3_manual_off.target_temp is None
assert smartac3_manual_off.available is True
assert smartac3_manual_off.precision == 0.1
async def test_smartac3_offline(hass):
"""Test smart ac cool mode."""
smartac3_offline = await _mock_tado_climate_zone_from_fixture(
hass, "smartac3.offline.json"
)
assert smartac3_offline.preparation is False
assert smartac3_offline.open_window is False
assert smartac3_offline.open_window_attr == {}
assert smartac3_offline.current_temp == 25.05
assert smartac3_offline.current_temp_timestamp == "2020-03-03T21:23:57.846Z"
assert smartac3_offline.connection is None
assert smartac3_offline.tado_mode == "HOME"
assert smartac3_offline.overlay_active is True
assert smartac3_offline.overlay_termination_type == "TADO_MODE"
assert smartac3_offline.current_humidity == 61.6
assert smartac3_offline.current_humidity_timestamp == "2020-03-03T21:23:57.846Z"
assert smartac3_offline.ac_power_timestamp == "2020-02-29T18:42:26.683Z"
assert smartac3_offline.heating_power_timestamp is None
assert smartac3_offline.ac_power == "OFF"
assert smartac3_offline.heating_power is None
assert smartac3_offline.heating_power_percentage is None
assert smartac3_offline.is_away is False
assert smartac3_offline.power == "ON"
assert smartac3_offline.current_hvac_action == "idle"
assert smartac3_offline.current_tado_fan_speed == "AUTO"
assert smartac3_offline.link == "OFFLINE"
assert smartac3_offline.current_tado_hvac_mode == "COOL"
assert smartac3_offline.target_temp == 17.78
assert smartac3_offline.available is False
assert smartac3_offline.precision == 0.1
async def test_hvac_action_heat(hass):
"""Test smart ac cool mode."""
hvac_action_heat = await _mock_tado_climate_zone_from_fixture(
hass, "hvac_action_heat.json"
)
assert hvac_action_heat.preparation is False
assert hvac_action_heat.open_window is False
assert hvac_action_heat.open_window_attr == {}
assert hvac_action_heat.current_temp == 21.4
assert hvac_action_heat.current_temp_timestamp == "2020-03-06T18:06:09.546Z"
assert hvac_action_heat.connection is None
assert hvac_action_heat.tado_mode == "HOME"
assert hvac_action_heat.overlay_active is True
assert hvac_action_heat.overlay_termination_type == "TADO_MODE"
assert hvac_action_heat.current_humidity == 50.4
assert hvac_action_heat.current_humidity_timestamp == "2020-03-06T18:06:09.546Z"
assert hvac_action_heat.ac_power_timestamp == "2020-03-06T17:38:30.302Z"
assert hvac_action_heat.heating_power_timestamp is None
assert hvac_action_heat.ac_power == "OFF"
assert hvac_action_heat.heating_power is None
assert hvac_action_heat.heating_power_percentage is None
assert hvac_action_heat.is_away is False
assert hvac_action_heat.power == "ON"
assert hvac_action_heat.current_hvac_action == "idle"
assert hvac_action_heat.current_tado_fan_speed == "AUTO"
assert hvac_action_heat.link == "ONLINE"
assert hvac_action_heat.current_tado_hvac_mode == "HEAT"
assert hvac_action_heat.target_temp == 16.11
assert hvac_action_heat.available is True
assert hvac_action_heat.precision == 0.1
async def test_smartac3_turning_off(hass):
"""Test smart ac cool mode."""
smartac3_turning_off = await _mock_tado_climate_zone_from_fixture(
hass, "smartac3.turning_off.json"
)
assert smartac3_turning_off.preparation is False
assert smartac3_turning_off.open_window is False
assert smartac3_turning_off.open_window_attr == {}
assert smartac3_turning_off.current_temp == 21.4
assert smartac3_turning_off.current_temp_timestamp == "2020-03-06T19:06:13.185Z"
assert smartac3_turning_off.connection is None
assert smartac3_turning_off.tado_mode == "HOME"
assert smartac3_turning_off.overlay_active is True
assert smartac3_turning_off.overlay_termination_type == "MANUAL"
assert smartac3_turning_off.current_humidity == 49.2
assert smartac3_turning_off.current_humidity_timestamp == "2020-03-06T19:06:13.185Z"
assert smartac3_turning_off.ac_power_timestamp == "2020-03-06T19:05:21.835Z"
assert smartac3_turning_off.heating_power_timestamp is None
assert smartac3_turning_off.ac_power == "ON"
assert smartac3_turning_off.heating_power is None
assert smartac3_turning_off.heating_power_percentage is None
assert smartac3_turning_off.is_away is False
assert smartac3_turning_off.power == "OFF"
assert smartac3_turning_off.current_hvac_action == "off"
assert smartac3_turning_off.current_tado_fan_speed == "OFF"
assert smartac3_turning_off.link == "ONLINE"
assert smartac3_turning_off.current_tado_hvac_mode == "OFF"
assert smartac3_turning_off.target_temp is None
assert smartac3_turning_off.available is True
assert smartac3_turning_off.precision == 0.1
async def test_michael_heat_mode(hass):
"""Test michael's tado."""
michael_heat_mode = await _mock_tado_climate_zone_from_fixture(
hass, "michael_heat_mode.json"
)
assert michael_heat_mode.preparation is False
assert michael_heat_mode.open_window is False
assert michael_heat_mode.open_window_attr == {}
assert michael_heat_mode.current_temp == 20.06
assert michael_heat_mode.current_temp_timestamp == "2020-03-09T08:16:49.271Z"
assert michael_heat_mode.connection is None
assert michael_heat_mode.tado_mode == "HOME"
assert michael_heat_mode.overlay_active is False
assert michael_heat_mode.overlay_termination_type is None
assert michael_heat_mode.current_humidity == 41.8
assert michael_heat_mode.current_humidity_timestamp == "2020-03-09T08:16:49.271Z"
assert michael_heat_mode.ac_power_timestamp is None
assert michael_heat_mode.heating_power_timestamp == "2020-03-09T08:20:47.299Z"
assert michael_heat_mode.ac_power is None
assert michael_heat_mode.heating_power is None
assert michael_heat_mode.heating_power_percentage == 0.0
assert michael_heat_mode.is_away is False
assert michael_heat_mode.power == "ON"
assert michael_heat_mode.current_hvac_action == "idle"
assert michael_heat_mode.current_tado_fan_speed == "AUTO"
assert michael_heat_mode.link == "ONLINE"
assert michael_heat_mode.current_tado_hvac_mode == "SMART_SCHEDULE"
assert michael_heat_mode.target_temp == 20.0
assert michael_heat_mode.available is True
assert michael_heat_mode.precision == 0.1

View File

@ -1,60 +0,0 @@
{
"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
}
}
}

View File

@ -1,67 +0,0 @@
{
"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"
}
}
}

View File

@ -1,58 +0,0 @@
{
"tadoMode": "HOME",
"geolocationOverride": false,
"geolocationOverrideDisableTime": null,
"preparation": null,
"setting": {
"type": "HEATING",
"power": "ON",
"temperature": {
"celsius": 20.0,
"fahrenheit": 68.0
}
},
"overlayType": null,
"overlay": null,
"openWindow": null,
"nextScheduleChange": {
"start": "2020-03-09T17:00:00Z",
"setting": {
"type": "HEATING",
"power": "ON",
"temperature": {
"celsius": 21.0,
"fahrenheit": 69.8
}
}
},
"nextTimeBlock": {
"start": "2020-03-09T17:00:00.000Z"
},
"link": {
"state": "ONLINE"
},
"activityDataPoints": {
"heatingPower": {
"type": "PERCENTAGE",
"percentage": 0.0,
"timestamp": "2020-03-09T08:20:47.299Z"
}
},
"sensorDataPoints": {
"insideTemperature": {
"celsius": 20.06,
"fahrenheit": 68.11,
"timestamp": "2020-03-09T08:16:49.271Z",
"type": "TEMPERATURE",
"precision": {
"celsius": 0.1,
"fahrenheit": 0.1
}
},
"humidity": {
"type": "PERCENTAGE",
"percentage": 41.8,
"timestamp": "2020-03-09T08:16:49.271Z"
}
}
}

View File

@ -1,57 +0,0 @@
{
"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"
}
}

View File

@ -1,67 +0,0 @@
{
"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
}
}
}

View File

@ -1,57 +0,0 @@
{
"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"
}
}

View File

@ -1,57 +0,0 @@
{
"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"
}
}

View File

@ -1,67 +0,0 @@
{
"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
}
}
}

View File

@ -1,55 +0,0 @@
{
"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"
}
}

View File

@ -1,55 +0,0 @@
{
"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"
}
}

View File

@ -1,71 +0,0 @@
{
"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
}
}
}

View File

@ -1,50 +0,0 @@
{
"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
}
}
}

View File

@ -1,55 +0,0 @@
{
"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"
}
}
}