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/smartpull/33434/head
parent
eee0a6e9f4
commit
f42804805c
|
@ -369,7 +369,7 @@ homeassistant/components/switchmate/* @danielhiversen
|
|||
homeassistant/components/syncthru/* @nielstron
|
||||
homeassistant/components/synology_srm/* @aerialls
|
||||
homeassistant/components/syslog/* @fabaff
|
||||
homeassistant/components/tado/* @michaelarnauts
|
||||
homeassistant/components/tado/* @michaelarnauts @bdraco
|
||||
homeassistant/components/tahoma/* @philklei
|
||||
homeassistant/components/tankerkoenig/* @guillempages
|
||||
homeassistant/components/tautulli/* @ludeeus
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
"""Support for the (unofficial) Tado API."""
|
||||
from datetime import timedelta
|
||||
import logging
|
||||
import urllib
|
||||
|
||||
from PyTado.interface import Tado
|
||||
from requests import RequestException
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.components.climate.const import PRESET_AWAY, PRESET_HOME
|
||||
|
@ -110,7 +110,7 @@ class TadoConnector:
|
|||
"""Connect to Tado and fetch the zones."""
|
||||
try:
|
||||
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)
|
||||
return False
|
||||
|
||||
|
@ -135,9 +135,14 @@ class TadoConnector:
|
|||
_LOGGER.debug("Updating %s %s", sensor_type, sensor)
|
||||
try:
|
||||
if sensor_type == "zone":
|
||||
data = self.tado.getState(sensor)
|
||||
data = self.tado.getZoneState(sensor)
|
||||
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:
|
||||
_LOGGER.debug("Unknown sensor: %s", sensor_type)
|
||||
return
|
||||
|
@ -174,29 +179,40 @@ class TadoConnector:
|
|||
|
||||
def set_zone_overlay(
|
||||
self,
|
||||
zone_id,
|
||||
overlay_mode,
|
||||
zone_id=None,
|
||||
overlay_mode=None,
|
||||
temperature=None,
|
||||
duration=None,
|
||||
device_type="HEATING",
|
||||
mode=None,
|
||||
fan_speed=None,
|
||||
):
|
||||
"""Set a zone overlay."""
|
||||
_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,
|
||||
overlay_mode,
|
||||
temperature,
|
||||
duration,
|
||||
device_type,
|
||||
mode,
|
||||
fan_speed,
|
||||
)
|
||||
|
||||
try:
|
||||
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)
|
||||
|
||||
|
@ -206,7 +222,7 @@ class TadoConnector:
|
|||
self.tado.setZoneOverlay(
|
||||
zone_id, overlay_mode, None, None, device_type, "OFF"
|
||||
)
|
||||
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)
|
||||
|
|
|
@ -3,21 +3,13 @@ import logging
|
|||
|
||||
from homeassistant.components.climate import ClimateDevice
|
||||
from homeassistant.components.climate.const import (
|
||||
CURRENT_HVAC_COOL,
|
||||
CURRENT_HVAC_HEAT,
|
||||
CURRENT_HVAC_IDLE,
|
||||
CURRENT_HVAC_OFF,
|
||||
FAN_HIGH,
|
||||
FAN_LOW,
|
||||
FAN_MIDDLE,
|
||||
FAN_OFF,
|
||||
HVAC_MODE_AUTO,
|
||||
HVAC_MODE_COOL,
|
||||
FAN_AUTO,
|
||||
HVAC_MODE_HEAT,
|
||||
HVAC_MODE_HEAT_COOL,
|
||||
HVAC_MODE_OFF,
|
||||
PRESET_AWAY,
|
||||
PRESET_HOME,
|
||||
SUPPORT_FAN_MODE,
|
||||
SUPPORT_PRESET_MODE,
|
||||
SUPPORT_TARGET_TEMPERATURE,
|
||||
)
|
||||
|
@ -27,49 +19,30 @@ from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
|||
|
||||
from . import DOMAIN, SIGNAL_TADO_UPDATE_RECEIVED
|
||||
from .const import (
|
||||
CONST_FAN_AUTO,
|
||||
CONST_FAN_OFF,
|
||||
CONST_MODE_AUTO,
|
||||
CONST_MODE_COOL,
|
||||
CONST_MODE_HEAT,
|
||||
CONST_MODE_OFF,
|
||||
CONST_MODE_SMART_SCHEDULE,
|
||||
CONST_OVERLAY_MANUAL,
|
||||
CONST_OVERLAY_TADO_MODE,
|
||||
CONST_OVERLAY_TIMER,
|
||||
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_HEATING,
|
||||
)
|
||||
|
||||
_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):
|
||||
"""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)
|
||||
|
||||
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:
|
||||
# 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
|
||||
if "HEAT" in capabilities:
|
||||
temperatures = capabilities["HEAT"]["temperatures"]
|
||||
ac_support_heat = True
|
||||
else:
|
||||
temperatures = capabilities["COOL"]["temperatures"]
|
||||
elif "temperatures" in capabilities:
|
||||
temperatures = capabilities["temperatures"]
|
||||
for mode in ORDERED_KNOWN_TADO_MODES:
|
||||
if mode not in capabilities:
|
||||
continue
|
||||
|
||||
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:
|
||||
_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
|
||||
|
||||
min_temp = float(temperatures["celsius"]["min"])
|
||||
max_temp = float(temperatures["celsius"]["max"])
|
||||
step = temperatures["celsius"].get("step", PRECISION_TENTHS)
|
||||
heat_min_temp = None
|
||||
heat_max_temp = None
|
||||
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(
|
||||
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
|
||||
|
||||
|
@ -132,10 +156,15 @@ class TadoClimate(ClimateDevice):
|
|||
zone_name,
|
||||
zone_id,
|
||||
zone_type,
|
||||
min_temp,
|
||||
max_temp,
|
||||
step,
|
||||
ac_support_heat,
|
||||
heat_min_temp,
|
||||
heat_max_temp,
|
||||
heat_step,
|
||||
cool_min_temp,
|
||||
cool_max_temp,
|
||||
cool_step,
|
||||
supported_hvac_modes,
|
||||
supported_fan_modes,
|
||||
support_flags,
|
||||
):
|
||||
"""Initialize of Tado climate entity."""
|
||||
self._tado = tado
|
||||
|
@ -146,49 +175,51 @@ class TadoClimate(ClimateDevice):
|
|||
self._unique_id = f"{zone_type} {zone_id} {tado.device_id}"
|
||||
|
||||
self._ac_device = zone_type == TYPE_AIR_CONDITIONING
|
||||
self._ac_support_heat = ac_support_heat
|
||||
self._cooling = False
|
||||
self._supported_hvac_modes = supported_hvac_modes
|
||||
self._supported_fan_modes = supported_fan_modes
|
||||
self._support_flags = support_flags
|
||||
|
||||
self._active = False
|
||||
self._device_is_active = False
|
||||
self._available = False
|
||||
|
||||
self._cur_temp = None
|
||||
self._cur_humidity = None
|
||||
self._is_away = False
|
||||
self._min_temp = min_temp
|
||||
self._max_temp = max_temp
|
||||
self._step = step
|
||||
|
||||
self._heat_min_temp = heat_min_temp
|
||||
self._heat_max_temp = heat_max_temp
|
||||
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
|
||||
|
||||
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_tado_fan_speed = CONST_FAN_OFF
|
||||
self._current_tado_hvac_mode = CONST_MODE_OFF
|
||||
self._current_tado_hvac_action = CURRENT_HVAC_OFF
|
||||
|
||||
self._current_fan = CONST_MODE_OFF
|
||||
self._current_operation = CONST_MODE_SMART_SCHEDULE
|
||||
self._overlay_mode = CONST_MODE_SMART_SCHEDULE
|
||||
self._undo_dispatcher = None
|
||||
self._tado_zone_data = None
|
||||
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):
|
||||
"""Register for sensor updates."""
|
||||
|
||||
@callback
|
||||
def async_update_callback():
|
||||
"""Schedule an entity update."""
|
||||
self.async_schedule_update_ha_state(True)
|
||||
|
||||
async_dispatcher_connect(
|
||||
self._undo_dispatcher = async_dispatcher_connect(
|
||||
self.hass,
|
||||
SIGNAL_TADO_UPDATE_RECEIVED.format("zone", self.zone_id),
|
||||
async_update_callback,
|
||||
self._async_update_callback,
|
||||
)
|
||||
|
||||
@property
|
||||
def supported_features(self):
|
||||
"""Return the list of supported features."""
|
||||
return SUPPORT_FLAGS
|
||||
return self._support_flags
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
|
@ -208,12 +239,12 @@ class TadoClimate(ClimateDevice):
|
|||
@property
|
||||
def current_humidity(self):
|
||||
"""Return the current humidity."""
|
||||
return self._cur_humidity
|
||||
return self._tado_zone_data.current_humidity
|
||||
|
||||
@property
|
||||
def current_temperature(self):
|
||||
"""Return the sensor temperature."""
|
||||
return self._cur_temp
|
||||
return self._tado_zone_data.current_temp
|
||||
|
||||
@property
|
||||
def hvac_mode(self):
|
||||
|
@ -221,11 +252,7 @@ class TadoClimate(ClimateDevice):
|
|||
|
||||
Need to be one of HVAC_MODE_*.
|
||||
"""
|
||||
if self._ac_device and self._ac_support_heat:
|
||||
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)
|
||||
return TADO_TO_HA_HVAC_MODE_MAP.get(self._current_tado_hvac_mode, HVAC_MODE_OFF)
|
||||
|
||||
@property
|
||||
def hvac_modes(self):
|
||||
|
@ -233,11 +260,7 @@ class TadoClimate(ClimateDevice):
|
|||
|
||||
Need to be a subset of HVAC_MODES.
|
||||
"""
|
||||
if self._ac_device:
|
||||
if self._ac_support_heat:
|
||||
return SUPPORT_HVAC_HEAT_COOL
|
||||
return SUPPORT_HVAC_COOL
|
||||
return SUPPORT_HVAC_HEAT
|
||||
return self._supported_hvac_modes
|
||||
|
||||
@property
|
||||
def hvac_action(self):
|
||||
|
@ -245,40 +268,30 @@ class TadoClimate(ClimateDevice):
|
|||
|
||||
Need to be one of CURRENT_HVAC_*.
|
||||
"""
|
||||
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
|
||||
return TADO_HVAC_ACTION_TO_HA_HVAC_ACTION.get(
|
||||
self._tado_zone_data.current_hvac_action, CURRENT_HVAC_OFF
|
||||
)
|
||||
|
||||
@property
|
||||
def fan_mode(self):
|
||||
"""Return the fan setting."""
|
||||
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
|
||||
|
||||
@property
|
||||
def fan_modes(self):
|
||||
"""List of available fan modes."""
|
||||
if self._ac_device:
|
||||
return SUPPORT_FAN
|
||||
return None
|
||||
return self._supported_fan_modes
|
||||
|
||||
def set_fan_mode(self, fan_mode: str):
|
||||
"""Turn fan on/off."""
|
||||
pass
|
||||
self._control_hvac(fan_mode=HA_TO_TADO_FAN_MODE_MAP[fan_mode])
|
||||
|
||||
@property
|
||||
def preset_mode(self):
|
||||
"""Return the current preset mode (home, away)."""
|
||||
if self._is_away:
|
||||
if self._tado_zone_data.is_away:
|
||||
return PRESET_AWAY
|
||||
return PRESET_HOME
|
||||
|
||||
|
@ -299,12 +312,18 @@ class TadoClimate(ClimateDevice):
|
|||
@property
|
||||
def target_temperature_step(self):
|
||||
"""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
|
||||
def target_temperature(self):
|
||||
"""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):
|
||||
"""Set new target temperature."""
|
||||
|
@ -312,174 +331,149 @@ class TadoClimate(ClimateDevice):
|
|||
if temperature is None:
|
||||
return
|
||||
|
||||
self._current_operation = self._default_overlay
|
||||
self._overlay_mode = None
|
||||
self._target_temp = temperature
|
||||
self._control_heating()
|
||||
if self._current_tado_hvac_mode not in (
|
||||
CONST_MODE_OFF,
|
||||
CONST_MODE_AUTO,
|
||||
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):
|
||||
"""Set new target hvac mode."""
|
||||
mode = None
|
||||
|
||||
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
|
||||
self._control_hvac(hvac_mode=HA_TO_TADO_HVAC_MODE_MAP[hvac_mode])
|
||||
|
||||
self._current_operation = mode
|
||||
self._overlay_mode = None
|
||||
|
||||
# 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
|
||||
def available(self):
|
||||
"""Return if the device is available."""
|
||||
return self._tado_zone_data.available
|
||||
|
||||
@property
|
||||
def min_temp(self):
|
||||
"""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
|
||||
def max_temp(self):
|
||||
"""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 (
|
||||
"temperature" in data["setting"]
|
||||
and data["setting"]["temperature"] is not None
|
||||
self._current_tado_hvac_mode == CONST_MODE_HEAT
|
||||
and self._heat_max_temp is not None
|
||||
):
|
||||
setting = float(data["setting"]["temperature"]["celsius"])
|
||||
self._target_temp = setting
|
||||
return self._heat_max_temp
|
||||
if self._heat_max_temp is not None:
|
||||
return self._heat_max_temp
|
||||
|
||||
if "tadoMode" in data:
|
||||
mode = data["tadoMode"]
|
||||
self._is_away = mode == "AWAY"
|
||||
return self._heat_max_temp
|
||||
|
||||
if "setting" in data:
|
||||
power = data["setting"]["power"]
|
||||
if power == "OFF":
|
||||
self._current_operation = CONST_MODE_OFF
|
||||
self._current_fan = 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
|
||||
@callback
|
||||
def _async_update_zone_data(self):
|
||||
"""Load tado data into zone."""
|
||||
self._tado_zone_data = self._tado.data["zone"][self.zone_id]
|
||||
self._current_tado_fan_speed = self._tado_zone_data.current_fan_speed
|
||||
self._current_tado_hvac_mode = self._tado_zone_data.current_hvac_mode
|
||||
self._current_tado_hvac_action = self._tado_zone_data.current_hvac_action
|
||||
|
||||
active = False
|
||||
if "activityDataPoints" in data:
|
||||
activity_data = data["activityDataPoints"]
|
||||
if self._ac_device:
|
||||
if "acPower" in activity_data and activity_data["acPower"] is not None:
|
||||
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
|
||||
@callback
|
||||
def _async_update_callback(self):
|
||||
"""Load tado data and update state."""
|
||||
self._async_update_zone_data()
|
||||
self.async_write_ha_state()
|
||||
|
||||
overlay = False
|
||||
overlay_data = None
|
||||
termination = CONST_MODE_SMART_SCHEDULE
|
||||
cooling = False
|
||||
fan_speed = CONST_MODE_OFF
|
||||
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:
|
||||
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:
|
||||
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):
|
||||
def _control_hvac(self, hvac_mode=None, target_temp=None, fan_mode=None):
|
||||
"""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(
|
||||
"Switching to SMART_SCHEDULE for zone %s (%d)",
|
||||
self.zone_name,
|
||||
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
|
||||
|
||||
_LOGGER.debug(
|
||||
"Switching to %s for zone %s (%d) with temperature %s °C",
|
||||
self._current_operation,
|
||||
self._current_tado_hvac_mode,
|
||||
self.zone_name,
|
||||
self.zone_id,
|
||||
self._target_temp,
|
||||
)
|
||||
self._tado.set_zone_overlay(
|
||||
self.zone_id,
|
||||
self._current_operation,
|
||||
self._target_temp,
|
||||
None,
|
||||
self.zone_type,
|
||||
"COOL" if self._ac_device else None,
|
||||
|
||||
# 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(
|
||||
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."""
|
||||
|
||||
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
|
||||
CONF_FALLBACK = "fallback"
|
||||
DATA = "data"
|
||||
|
@ -10,10 +53,81 @@ TYPE_HEATING = "HEATING"
|
|||
TYPE_HOT_WATER = "HOT_WATER"
|
||||
|
||||
# Base modes
|
||||
CONST_MODE_OFF = "OFF"
|
||||
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
|
||||
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_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": [],
|
||||
"codeowners": [
|
||||
"@michaelarnauts"
|
||||
"@michaelarnauts", "@bdraco"
|
||||
]
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@ ZONE_SENSORS = {
|
|||
"ac",
|
||||
"tado mode",
|
||||
"overlay",
|
||||
"open window",
|
||||
],
|
||||
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:
|
||||
# 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(
|
||||
[
|
||||
create_zone_sensor(tado, zone["name"], zone["id"], variable)
|
||||
for variable in ZONE_SENSORS.get(zone["type"])
|
||||
TadoZoneSensor(tado, zone["name"], zone["id"], variable)
|
||||
for variable in ZONE_SENSORS[zone_type]
|
||||
]
|
||||
)
|
||||
|
||||
# Create device sensors
|
||||
for home in tado.devices:
|
||||
for device in devices:
|
||||
entities.extend(
|
||||
[
|
||||
create_device_sensor(tado, home["name"], home["id"], variable)
|
||||
TadoDeviceSensor(tado, device["name"], device["id"], variable)
|
||||
for variable in DEVICE_SENSORS
|
||||
]
|
||||
)
|
||||
|
@ -67,46 +75,38 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
|
|||
add_entities(entities, True)
|
||||
|
||||
|
||||
def create_zone_sensor(tado, name, zone_id, variable):
|
||||
"""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):
|
||||
class TadoZoneSensor(Entity):
|
||||
"""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."""
|
||||
self._tado = tado
|
||||
|
||||
self.zone_name = zone_name
|
||||
self.zone_id = zone_id
|
||||
self.zone_variable = zone_variable
|
||||
self.sensor_type = sensor_type
|
||||
|
||||
self._unique_id = f"{zone_variable} {zone_id} {tado.device_id}"
|
||||
|
||||
self._state = 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):
|
||||
"""Register for sensor updates."""
|
||||
|
||||
@callback
|
||||
def async_update_callback():
|
||||
"""Schedule an entity update."""
|
||||
self.async_schedule_update_ha_state(True)
|
||||
|
||||
async_dispatcher_connect(
|
||||
self._undo_dispatcher = async_dispatcher_connect(
|
||||
self.hass,
|
||||
SIGNAL_TADO_UPDATE_RECEIVED.format(self.sensor_type, self.zone_id),
|
||||
async_update_callback,
|
||||
SIGNAL_TADO_UPDATE_RECEIVED.format("zone", self.zone_id),
|
||||
self._async_update_callback,
|
||||
)
|
||||
self._async_update_zone_data()
|
||||
|
||||
@property
|
||||
def unique_id(self):
|
||||
|
@ -138,7 +138,7 @@ class TadoSensor(Entity):
|
|||
if self.zone_variable == "heating":
|
||||
return UNIT_PERCENTAGE
|
||||
if self.zone_variable == "ac":
|
||||
return ""
|
||||
return None
|
||||
|
||||
@property
|
||||
def icon(self):
|
||||
|
@ -149,97 +149,143 @@ class TadoSensor(Entity):
|
|||
return "mdi:water-percent"
|
||||
|
||||
@property
|
||||
def should_poll(self) -> bool:
|
||||
def should_poll(self):
|
||||
"""Do not poll."""
|
||||
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."""
|
||||
try:
|
||||
data = self._tado.data[self.sensor_type][self.zone_id]
|
||||
self._tado_zone_data = self._tado.data["zone"][self.zone_id]
|
||||
except KeyError:
|
||||
return
|
||||
|
||||
unit = TEMP_CELSIUS
|
||||
|
||||
if self.zone_variable == "temperature":
|
||||
if "sensorDataPoints" in data:
|
||||
sensor_data = data["sensorDataPoints"]
|
||||
temperature = float(sensor_data["insideTemperature"]["celsius"])
|
||||
|
||||
self._state = self.hass.config.units.temperature(temperature, unit)
|
||||
self._state_attributes = {
|
||||
"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)
|
||||
self._state = self.hass.config.units.temperature(
|
||||
self._tado_zone_data.current_temp, TEMP_CELSIUS
|
||||
)
|
||||
self._state_attributes = {
|
||||
"time": self._tado_zone_data.current_temp_timestamp,
|
||||
"setting": 0, # setting is used in climate device
|
||||
}
|
||||
|
||||
elif self.zone_variable == "humidity":
|
||||
if "sensorDataPoints" in data:
|
||||
sensor_data = data["sensorDataPoints"]
|
||||
self._state = float(sensor_data["humidity"]["percentage"])
|
||||
self._state_attributes = {"time": sensor_data["humidity"]["timestamp"]}
|
||||
self._state = self._tado_zone_data.current_humidity
|
||||
self._state_attributes = {
|
||||
"time": self._tado_zone_data.current_humidity_timestamp
|
||||
}
|
||||
|
||||
elif self.zone_variable == "power":
|
||||
if "setting" in data:
|
||||
self._state = data["setting"]["power"]
|
||||
self._state = self._tado_zone_data.power
|
||||
|
||||
elif self.zone_variable == "link":
|
||||
if "link" in data:
|
||||
self._state = data["link"]["state"]
|
||||
self._state = self._tado_zone_data.link
|
||||
|
||||
elif self.zone_variable == "heating":
|
||||
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 = {
|
||||
"time": activity_data["heatingPower"]["timestamp"]
|
||||
}
|
||||
self._state = self._tado_zone_data.heating_power_percentage
|
||||
self._state_attributes = {
|
||||
"time": self._tado_zone_data.heating_power_timestamp
|
||||
}
|
||||
|
||||
elif self.zone_variable == "ac":
|
||||
if "activityDataPoints" in data:
|
||||
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"]
|
||||
}
|
||||
self._state = self._tado_zone_data.ac_power
|
||||
self._state_attributes = {"time": self._tado_zone_data.ac_power_timestamp}
|
||||
|
||||
elif self.zone_variable == "tado bridge status":
|
||||
if "connectionState" in data:
|
||||
self._state = data["connectionState"]["value"]
|
||||
self._state = self._tado_zone_data.connection
|
||||
|
||||
elif self.zone_variable == "tado mode":
|
||||
if "tadoMode" in data:
|
||||
self._state = data["tadoMode"]
|
||||
self._state = self._tado_zone_data.tado_mode
|
||||
|
||||
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 = (
|
||||
{"termination": data["overlay"]["termination"]["type"]}
|
||||
if self._state
|
||||
{"termination": self._tado_zone_data.overlay_termination_type}
|
||||
if self._tado_zone_data.overlay_active
|
||||
else {}
|
||||
)
|
||||
|
||||
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":
|
||||
self._state = "openWindow" in data and data["openWindow"] is not None
|
||||
self._state_attributes = data["openWindow"] if self._state else {}
|
||||
self._state = self._tado_zone_data.open_window
|
||||
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 .const import (
|
||||
CONST_HVAC_HEAT,
|
||||
CONST_MODE_AUTO,
|
||||
CONST_MODE_HEAT,
|
||||
CONST_MODE_OFF,
|
||||
CONST_MODE_SMART_SCHEDULE,
|
||||
CONST_OVERLAY_MANUAL,
|
||||
|
@ -33,6 +36,7 @@ WATER_HEATER_MAP_TADO = {
|
|||
CONST_OVERLAY_MANUAL: MODE_HEAT,
|
||||
CONST_OVERLAY_TIMER: MODE_HEAT,
|
||||
CONST_OVERLAY_TADO_MODE: MODE_HEAT,
|
||||
CONST_HVAC_HEAT: MODE_HEAT,
|
||||
CONST_MODE_SMART_SCHEDULE: MODE_AUTO,
|
||||
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 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"])
|
||||
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):
|
||||
"""Create a Tado water heater device."""
|
||||
capabilities = tado.get_capabilities(zone_id)
|
||||
|
||||
supports_temperature_control = capabilities["canSetTemperature"]
|
||||
|
||||
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._device_is_active = False
|
||||
self._is_away = False
|
||||
|
||||
self._supports_temperature_control = supports_temperature_control
|
||||
self._min_temperature = min_temp
|
||||
|
@ -110,29 +114,25 @@ class TadoWaterHeater(WaterHeaterDevice):
|
|||
if self._supports_temperature_control:
|
||||
self._supported_features |= SUPPORT_TARGET_TEMPERATURE
|
||||
|
||||
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._current_tado_hvac_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):
|
||||
"""Register for sensor updates."""
|
||||
|
||||
@callback
|
||||
def async_update_callback():
|
||||
"""Schedule an entity update."""
|
||||
self.async_schedule_update_ha_state(True)
|
||||
|
||||
async_dispatcher_connect(
|
||||
self._undo_dispatcher = async_dispatcher_connect(
|
||||
self.hass,
|
||||
SIGNAL_TADO_UPDATE_RECEIVED.format("zone", self.zone_id),
|
||||
async_update_callback,
|
||||
self._async_update_callback,
|
||||
)
|
||||
self._async_update_data()
|
||||
|
||||
@property
|
||||
def supported_features(self):
|
||||
|
@ -157,17 +157,17 @@ class TadoWaterHeater(WaterHeaterDevice):
|
|||
@property
|
||||
def current_operation(self):
|
||||
"""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
|
||||
def target_temperature(self):
|
||||
"""Return the temperature we try to reach."""
|
||||
return self._target_temp
|
||||
return self._tado_zone_data.target_temp
|
||||
|
||||
@property
|
||||
def is_away_mode_on(self):
|
||||
"""Return true if away mode is on."""
|
||||
return self._is_away
|
||||
return self._tado_zone_data.is_away
|
||||
|
||||
@property
|
||||
def operation_list(self):
|
||||
|
@ -198,16 +198,9 @@ class TadoWaterHeater(WaterHeaterDevice):
|
|||
elif operation_mode == MODE_AUTO:
|
||||
mode = CONST_MODE_SMART_SCHEDULE
|
||||
elif operation_mode == MODE_HEAT:
|
||||
mode = self._default_overlay
|
||||
mode = CONST_MODE_HEAT
|
||||
|
||||
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()
|
||||
self._control_heater(hvac_mode=mode)
|
||||
|
||||
def set_temperature(self, **kwargs):
|
||||
"""Set new target temperature."""
|
||||
|
@ -215,88 +208,75 @@ class TadoWaterHeater(WaterHeaterDevice):
|
|||
if not self._supports_temperature_control or temperature is None:
|
||||
return
|
||||
|
||||
self._current_operation = self._default_overlay
|
||||
self._overlay_mode = None
|
||||
self._target_temp = temperature
|
||||
self._control_heater()
|
||||
|
||||
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
|
||||
if self._current_tado_hvac_mode not in (
|
||||
CONST_MODE_OFF,
|
||||
CONST_MODE_AUTO,
|
||||
CONST_MODE_SMART_SCHEDULE,
|
||||
):
|
||||
setting = float(data["setting"]["temperature"]["celsius"])
|
||||
self._target_temp = setting
|
||||
self._control_heater(target_temp=temperature)
|
||||
return
|
||||
|
||||
overlay = False
|
||||
overlay_data = None
|
||||
termination = CONST_MODE_SMART_SCHEDULE
|
||||
self._control_heater(target_temp=temperature, hvac_mode=CONST_MODE_HEAT)
|
||||
|
||||
if "overlay" in data:
|
||||
overlay_data = data["overlay"]
|
||||
overlay = overlay_data is not None
|
||||
@callback
|
||||
def _async_update_callback(self):
|
||||
"""Load tado data and update state."""
|
||||
self._async_update_data()
|
||||
self.async_write_ha_state()
|
||||
|
||||
if overlay:
|
||||
termination = overlay_data["termination"]["type"]
|
||||
@callback
|
||||
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:
|
||||
# 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):
|
||||
def _control_heater(self, hvac_mode=None, target_temp=None):
|
||||
"""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(
|
||||
"Switching to SMART_SCHEDULE for zone %s (%d)",
|
||||
self.zone_name,
|
||||
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:
|
||||
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, TYPE_HOT_WATER)
|
||||
self._overlay_mode = self._current_operation
|
||||
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(
|
||||
"Switching to %s for zone %s (%d) with temperature %s",
|
||||
self._current_operation,
|
||||
self._current_tado_hvac_mode,
|
||||
self.zone_name,
|
||||
self.zone_id,
|
||||
self._target_temp,
|
||||
)
|
||||
self._tado.set_zone_overlay(
|
||||
self.zone_id,
|
||||
self._current_operation,
|
||||
self._target_temp,
|
||||
None,
|
||||
TYPE_HOT_WATER,
|
||||
zone_id=self.zone_id,
|
||||
overlay_mode=overlay_mode,
|
||||
temperature=self._target_temp,
|
||||
duration=None,
|
||||
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
|
||||
python-nest==4.1.0
|
||||
|
||||
# homeassistant.components.tado
|
||||
python-tado==0.5.0
|
||||
|
||||
# homeassistant.components.twitch
|
||||
python-twitch-client==0.6.0
|
||||
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
"""Tests for the tado integration."""
|
|
@ -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())
|
|
@ -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"
|
|
@ -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())
|
|
@ -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()
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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"
|
||||
}
|
||||
]
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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"
|
||||
}
|
|
@ -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"
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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"
|
||||
}
|
||||
}
|
|
@ -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"
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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"
|
||||
}
|
||||
}
|
|
@ -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"
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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": {}
|
||||
}
|
|
@ -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"
|
||||
}
|
||||
}
|
|
@ -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": {}
|
||||
}
|
|
@ -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": {}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
{
|
||||
"type" : "HEATING",
|
||||
"HEAT" : {
|
||||
"temperatures" : {
|
||||
"celsius" : {
|
||||
"max" : 31,
|
||||
"step" : 1,
|
||||
"min" : 16
|
||||
},
|
||||
"fahrenheit" : {
|
||||
"step" : 1,
|
||||
"max" : 88,
|
||||
"min" : 61
|
||||
}
|
||||
}
|
||||
},
|
||||
"AUTO" : {},
|
||||
"FAN" : {}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"expires_in" : 599,
|
||||
"scope" : "home.user",
|
||||
"token_type" : "bearer",
|
||||
"refresh_token" : "refresh",
|
||||
"access_token" : "access",
|
||||
"jti" : "jti"
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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"
|
||||
]
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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…
Reference in New Issue