From f2a8ccdbaeb9ee31c7316dcbbecfe991f26ca8cb Mon Sep 17 00:00:00 2001 From: north3221 Date: Tue, 26 Jan 2021 08:11:29 +0000 Subject: [PATCH] Add tado service set temperature offset (#45014) --- homeassistant/components/tado/__init__.py | 14 ++++++ homeassistant/components/tado/climate.py | 53 ++++++++++++++++++++- homeassistant/components/tado/const.py | 12 +++++ homeassistant/components/tado/services.yaml | 10 ++++ tests/components/tado/util.py | 11 +++++ tests/fixtures/tado/device_temp_offset.json | 1 + 6 files changed, 99 insertions(+), 2 deletions(-) create mode 100644 tests/fixtures/tado/device_temp_offset.json diff --git a/homeassistant/components/tado/__init__.py b/homeassistant/components/tado/__init__.py index c7b765b32c2..e88fb4c60b8 100644 --- a/homeassistant/components/tado/__init__.py +++ b/homeassistant/components/tado/__init__.py @@ -21,7 +21,9 @@ from .const import ( CONF_FALLBACK, DATA, DOMAIN, + INSIDE_TEMPERATURE_MEASUREMENT, SIGNAL_TADO_UPDATE_RECEIVED, + TEMP_OFFSET, UPDATE_LISTENER, UPDATE_TRACK, ) @@ -178,6 +180,11 @@ class TadoConnector: 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: @@ -276,3 +283,10 @@ class TadoConnector: _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) diff --git a/homeassistant/components/tado/climate.py b/homeassistant/components/tado/climate.py index 423205f15b2..9547617a36b 100644 --- a/homeassistant/components/tado/climate.py +++ b/homeassistant/components/tado/climate.py @@ -46,6 +46,8 @@ from .const import ( 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, ) @@ -63,6 +65,13 @@ CLIMATE_TIMER_SCHEMA = { 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 @@ -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) @@ -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) @@ -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 @@ -200,6 +218,7 @@ class TadoClimate(TadoZoneEntity, ClimateEntity): supported_hvac_modes, supported_fan_modes, support_flags, + device_info, ): """Initialize of Tado climate entity.""" self._tado = tado @@ -208,6 +227,8 @@ class TadoClimate(TadoZoneEntity, ClimateEntity): 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 @@ -236,6 +257,8 @@ class TadoClimate(TadoZoneEntity, ClimateEntity): self._tado_zone_data = None + self._tado_zone_temp_offset = {} + self._async_update_zone_data() async def async_added_to_hass(self): @@ -362,6 +385,17 @@ class TadoClimate(TadoZoneEntity, ClimateEntity): 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) @@ -427,6 +461,11 @@ class TadoClimate(TadoZoneEntity, ClimateEntity): 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) @@ -435,6 +474,16 @@ class TadoClimate(TadoZoneEntity, ClimateEntity): 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 diff --git a/homeassistant/components/tado/const.py b/homeassistant/components/tado/const.py index cb27cd491d9..6e009df7ca2 100644 --- a/homeassistant/components/tado/const.py +++ b/homeassistant/components/tado/const.py @@ -152,3 +152,15 @@ DEFAULT_NAME = "Tado" 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, +} diff --git a/homeassistant/components/tado/services.yaml b/homeassistant/components/tado/services.yaml index 864511982a3..c9bba7c0ea8 100644 --- a/homeassistant/components/tado/services.yaml +++ b/homeassistant/components/tado/services.yaml @@ -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 diff --git a/tests/components/tado/util.py b/tests/components/tado/util.py index 187c0f269bf..d27ede47a63 100644 --- a/tests/components/tado/util.py +++ b/tests/components/tado/util.py @@ -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( @@ -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), diff --git a/tests/fixtures/tado/device_temp_offset.json b/tests/fixtures/tado/device_temp_offset.json new file mode 100644 index 00000000000..79e25745cbb --- /dev/null +++ b/tests/fixtures/tado/device_temp_offset.json @@ -0,0 +1 @@ +{"celsius": -1.0, "fahrenheit": -1.8}