Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add tado service set temperature offset #45014

Merged
merged 12 commits into from Jan 26, 2021
14 changes: 14 additions & 0 deletions homeassistant/components/tado/__init__.py
Expand Up @@ -22,7 +22,9 @@
CONF_FALLBACK,
DATA,
DOMAIN,
INSIDE_TEMPERATURE_MEASUREMENT,
SIGNAL_TADO_UPDATE_RECEIVED,
TEMP_OFFSET,
UPDATE_LISTENER,
UPDATE_TRACK,
)
Expand Down Expand Up @@ -205,6 +207,11 @@ def update_sensor(self, sensor_type, sensor):
try:
if sensor_type == "device":
data = self.tado.getDeviceInfo(sensor)
if (
INSIDE_TEMPERATURE_MEASUREMENT
in data["characteristics"]["capabilities"]
):
data[TEMP_OFFSET] = self.tado.getDeviceInfo(sensor, TEMP_OFFSET)
elif sensor_type == "zone":
data = self.tado.getZoneState(sensor)
else:
Expand Down Expand Up @@ -303,3 +310,10 @@ def set_zone_off(self, zone_id, overlay_mode, device_type="HEATING"):
_LOGGER.error("Could not set zone overlay: %s", exc)

self.update_sensor("zone", zone_id)

def set_temperature_offset(self, device_id, offset):
"""Set temperature offset of device."""
try:
self.tado.setTempOffset(device_id, offset)
except RequestException as exc:
_LOGGER.error("Could not set temperature offset: %s", exc)
53 changes: 51 additions & 2 deletions homeassistant/components/tado/climate.py
Expand Up @@ -46,6 +46,8 @@
TADO_SWING_ON,
TADO_TO_HA_FAN_MODE_MAP,
TADO_TO_HA_HVAC_MODE_MAP,
TADO_TO_HA_OFFSET_MAP,
TEMP_OFFSET,
TYPE_AIR_CONDITIONING,
TYPE_HEATING,
)
Expand All @@ -63,6 +65,13 @@
vol.Required(ATTR_TEMPERATURE): vol.Coerce(float),
}

SERVICE_TEMP_OFFSET = "set_climate_temperature_offset"
ATTR_OFFSET = "offset"

CLIMATE_TEMP_OFFSET_SCHEMA = {
vol.Required(ATTR_OFFSET, default=0): vol.Coerce(float),
}


async def async_setup_entry(
hass: HomeAssistant, entry: ConfigEntry, async_add_entities
Expand All @@ -80,6 +89,12 @@ async def async_setup_entry(
"set_timer",
)

platform.async_register_entity_service(
SERVICE_TEMP_OFFSET,
CLIMATE_TEMP_OFFSET_SCHEMA,
"set_temp_offset",
)

if entities:
async_add_entities(entities, True)

Expand All @@ -89,13 +104,15 @@ def _generate_entities(tado):
entities = []
for zone in tado.zones:
if zone["type"] in [TYPE_HEATING, TYPE_AIR_CONDITIONING]:
entity = create_climate_entity(tado, zone["name"], zone["id"])
entity = create_climate_entity(
tado, zone["name"], zone["id"], zone["devices"][0]
)
if entity:
entities.append(entity)
return entities


def create_climate_entity(tado, name: str, zone_id: int):
def create_climate_entity(tado, name: str, zone_id: int, device_info: dict):
"""Create a Tado climate entity."""
capabilities = tado.get_capabilities(zone_id)
_LOGGER.debug("Capabilities for zone %s: %s", zone_id, capabilities)
Expand Down Expand Up @@ -178,6 +195,7 @@ def create_climate_entity(tado, name: str, zone_id: int):
supported_hvac_modes,
supported_fan_modes,
support_flags,
device_info,
)
return entity

Expand All @@ -200,6 +218,7 @@ def __init__(
supported_hvac_modes,
supported_fan_modes,
support_flags,
device_info,
):
"""Initialize of Tado climate entity."""
self._tado = tado
Expand All @@ -208,6 +227,8 @@ def __init__(
self.zone_id = zone_id
self.zone_type = zone_type
self._unique_id = f"{zone_type} {zone_id} {tado.home_id}"
self._device_info = device_info
self._device_id = self._device_info["shortSerialNo"]

self._ac_device = zone_type == TYPE_AIR_CONDITIONING
self._supported_hvac_modes = supported_hvac_modes
Expand Down Expand Up @@ -236,6 +257,8 @@ def __init__(

self._tado_zone_data = None

self._tado_zone_temp_offset = {}

self._async_update_zone_data()

async def async_added_to_hass(self):
Expand Down Expand Up @@ -362,6 +385,17 @@ def set_timer(self, time_period, temperature=None):
hvac_mode=CONST_MODE_HEAT, target_temp=temperature, duration=time_period
)

def set_temp_offset(self, offset):
"""Set offset on the entity."""

_LOGGER.debug(
"Setting temperature offset for device %s setting to (%d)",
self._device_id,
offset,
)

self._tado.set_temperature_offset(self._device_id, offset)

def set_temperature(self, **kwargs):
"""Set new target temperature."""
temperature = kwargs.get(ATTR_TEMPERATURE)
Expand Down Expand Up @@ -427,6 +461,11 @@ def swing_modes(self):
return [TADO_SWING_ON, TADO_SWING_OFF]
return None

@property
def device_state_attributes(self):
"""Return temperature offset."""
return self._tado_zone_temp_offset

def set_swing_mode(self, swing_mode):
"""Set swing modes for the device."""
self._control_hvac(swing_mode=swing_mode)
Expand All @@ -435,6 +474,16 @@ def set_swing_mode(self, swing_mode):
def _async_update_zone_data(self):
"""Load tado data into zone."""
self._tado_zone_data = self._tado.data["zone"][self.zone_id]
# Assign offset values to mapped attributes
for offset_key, attr in TADO_TO_HA_OFFSET_MAP.items():
if (
self._device_id in self._tado.data["device"]
and offset_key
in self._tado.data["device"][self._device_id][TEMP_OFFSET]
):
self._tado_zone_temp_offset[attr] = self._tado.data["device"][
self._device_id
][TEMP_OFFSET][offset_key]
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
Expand Down
12 changes: 12 additions & 0 deletions homeassistant/components/tado/const.py
Expand Up @@ -150,3 +150,15 @@
TADO_ZONE = "Zone"

UPDATE_LISTENER = "update_listener"

# Constants for Temperature Offset
INSIDE_TEMPERATURE_MEASUREMENT = "INSIDE_TEMPERATURE_MEASUREMENT"
TEMP_OFFSET = "temperatureOffset"
TADO_OFFSET_CELSIUS = "celsius"
HA_OFFSET_CELSIUS = "offset_celsius"
TADO_OFFSET_FAHRENHEIT = "fahrenheit"
HA_OFFSET_FAHRENHEIT = "offset_fahrenheit"
TADO_TO_HA_OFFSET_MAP = {
TADO_OFFSET_CELSIUS: HA_OFFSET_CELSIUS,
TADO_OFFSET_FAHRENHEIT: HA_OFFSET_FAHRENHEIT,
}
10 changes: 10 additions & 0 deletions homeassistant/components/tado/services.yaml
Expand Up @@ -23,3 +23,13 @@ set_water_heater_timer:
temperature:
description: Temperature to set heater to
example: 25

set_climate_temperature_offset:
description: Set the temperature offset of climate entities
fields:
entity_id:
description: Entity ID for the tado component to set the temperature offset
example: climate.heating
offset:
description: Offset you would like, can be to 2 decimal places (depending on your device) positive or negative
example: -1.2
11 changes: 11 additions & 0 deletions tests/components/tado/util.py
Expand Up @@ -43,6 +43,9 @@ async def async_init_integration(
zone_1_state_fixture = "tado/tadov2.heating.manual_mode.json"
zone_1_capabilities_fixture = "tado/tadov2.zone_capabilities.json"

# Device Temp Offset
device_temp_offset = "tado/device_temp_offset.json"

with requests_mock.mock() as m:
m.post("https://auth.tado.com/oauth/token", text=load_fixture(token_fixture))
m.get(
Expand All @@ -57,6 +60,14 @@ async def async_init_integration(
"https://my.tado.com/api/v2/devices/WR1/",
text=load_fixture(device_wr1_fixture),
)
m.get(
"https://my.tado.com/api/v2/devices/WR1/temperatureOffset",
text=load_fixture(device_temp_offset),
)
m.get(
"https://my.tado.com/api/v2/devices/WR4/temperatureOffset",
text=load_fixture(device_temp_offset),
)
m.get(
"https://my.tado.com/api/v2/homes/1/zones",
text=load_fixture(zones_fixture),
Expand Down
1 change: 1 addition & 0 deletions tests/fixtures/tado/device_temp_offset.json
@@ -0,0 +1 @@
{"celsius": -1.0, "fahrenheit": -1.8}