Fix setting zone overlays for tados that support swing (#33439)

* Fix setting zone overlays for tados that support swing

* Support for changing swing mode will come at a later
time as another upstream update is required.

* remove debug

* style
This commit is contained in:
J. Nick Koston 2020-03-31 17:29:45 -05:00 committed by GitHub
parent 774b1d1663
commit 3566803d2e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 253 additions and 11 deletions

View File

@ -186,10 +186,11 @@ class TadoConnector:
device_type="HEATING", device_type="HEATING",
mode=None, mode=None,
fan_speed=None, fan_speed=None,
swing=None,
): ):
"""Set a zone overlay.""" """Set a zone overlay."""
_LOGGER.debug( _LOGGER.debug(
"Set overlay for zone %s: overlay_mode=%s, temp=%s, duration=%s, type=%s, mode=%s fan_speed=%s", "Set overlay for zone %s: overlay_mode=%s, temp=%s, duration=%s, type=%s, mode=%s fan_speed=%s swing=%s",
zone_id, zone_id,
overlay_mode, overlay_mode,
temperature, temperature,
@ -197,6 +198,7 @@ class TadoConnector:
device_type, device_type,
mode, mode,
fan_speed, fan_speed,
swing,
) )
try: try:
@ -208,7 +210,8 @@ class TadoConnector:
device_type, device_type,
"ON", "ON",
mode, mode,
fan_speed, fanSpeed=fan_speed,
swing=swing,
) )
except RequestException as exc: except RequestException as exc:

View File

@ -11,6 +11,7 @@ from homeassistant.components.climate.const import (
PRESET_HOME, PRESET_HOME,
SUPPORT_FAN_MODE, SUPPORT_FAN_MODE,
SUPPORT_PRESET_MODE, SUPPORT_PRESET_MODE,
SUPPORT_SWING_MODE,
SUPPORT_TARGET_TEMPERATURE, SUPPORT_TARGET_TEMPERATURE,
) )
from homeassistant.const import ATTR_TEMPERATURE, PRECISION_TENTHS, TEMP_CELSIUS from homeassistant.const import ATTR_TEMPERATURE, PRECISION_TENTHS, TEMP_CELSIUS
@ -35,6 +36,7 @@ from .const import (
SUPPORT_PRESET, SUPPORT_PRESET,
TADO_HVAC_ACTION_TO_HA_HVAC_ACTION, TADO_HVAC_ACTION_TO_HA_HVAC_ACTION,
TADO_MODES_WITH_NO_TEMP_SETTING, TADO_MODES_WITH_NO_TEMP_SETTING,
TADO_SWING_OFF,
TADO_TO_HA_FAN_MODE_MAP, TADO_TO_HA_FAN_MODE_MAP,
TADO_TO_HA_HVAC_MODE_MAP, TADO_TO_HA_HVAC_MODE_MAP,
TYPE_AIR_CONDITIONING, TYPE_AIR_CONDITIONING,
@ -85,6 +87,9 @@ def create_climate_entity(tado, name: str, zone_id: int):
continue continue
supported_hvac_modes.append(TADO_TO_HA_HVAC_MODE_MAP[mode]) supported_hvac_modes.append(TADO_TO_HA_HVAC_MODE_MAP[mode])
if capabilities[mode].get("swings"):
support_flags |= SUPPORT_SWING_MODE
if not capabilities[mode].get("fanSpeeds"): if not capabilities[mode].get("fanSpeeds"):
continue continue
@ -197,6 +202,7 @@ class TadoClimate(ClimateDevice):
self._current_tado_fan_speed = CONST_FAN_OFF self._current_tado_fan_speed = CONST_FAN_OFF
self._current_tado_hvac_mode = CONST_MODE_OFF self._current_tado_hvac_mode = CONST_MODE_OFF
self._current_tado_hvac_action = CURRENT_HVAC_OFF self._current_tado_hvac_action = CURRENT_HVAC_OFF
self._current_tado_swing_mode = TADO_SWING_OFF
self._undo_dispatcher = None self._undo_dispatcher = None
self._tado_zone_data = None self._tado_zone_data = None
@ -378,6 +384,25 @@ class TadoClimate(ClimateDevice):
return self._heat_max_temp return self._heat_max_temp
@property
def swing_mode(self):
"""Active swing mode for the device."""
return self._current_tado_swing_mode
@property
def swing_modes(self):
"""Swing modes for the device."""
if self._support_flags & SUPPORT_SWING_MODE:
# Currently we only support off.
# On will be added in the future in an update
# to PyTado
return [TADO_SWING_OFF]
return None
def set_swing_mode(self, swing_mode):
"""Set swing modes for the device."""
self._control_hvac(swing_mode=swing_mode)
@callback @callback
def _async_update_zone_data(self): def _async_update_zone_data(self):
"""Load tado data into zone.""" """Load tado data into zone."""
@ -408,7 +433,9 @@ class TadoClimate(ClimateDevice):
elif self._target_temp < self._heat_min_temp: elif self._target_temp < self._heat_min_temp:
self._target_temp = self._heat_min_temp self._target_temp = self._heat_min_temp
def _control_hvac(self, hvac_mode=None, target_temp=None, fan_mode=None): def _control_hvac(
self, hvac_mode=None, target_temp=None, fan_mode=None, swing_mode=None
):
"""Send new target temperature to Tado.""" """Send new target temperature to Tado."""
if hvac_mode: if hvac_mode:
@ -420,6 +447,9 @@ class TadoClimate(ClimateDevice):
if fan_mode: if fan_mode:
self._current_tado_fan_speed = fan_mode self._current_tado_fan_speed = fan_mode
if swing_mode:
self._current_tado_swing_mode = swing_mode
self._normalize_target_temp_for_hvac_mode() self._normalize_target_temp_for_hvac_mode()
# tado does not permit setting the fan speed to # tado does not permit setting the fan speed to
@ -464,6 +494,13 @@ class TadoClimate(ClimateDevice):
# A temperature cannot be passed with these modes # A temperature cannot be passed with these modes
temperature_to_send = None temperature_to_send = None
fan_speed = None
if self._support_flags & SUPPORT_FAN_MODE:
fan_speed = self._current_tado_fan_speed
swing = None
if self._support_flags & SUPPORT_SWING_MODE:
swing = self._current_tado_swing_mode
self._tado.set_zone_overlay( self._tado.set_zone_overlay(
zone_id=self.zone_id, zone_id=self.zone_id,
overlay_mode=overlay_mode, # What to do when the period ends overlay_mode=overlay_mode, # What to do when the period ends
@ -471,9 +508,6 @@ class TadoClimate(ClimateDevice):
duration=None, duration=None,
device_type=self.zone_type, device_type=self.zone_type,
mode=self._current_tado_hvac_mode, mode=self._current_tado_hvac_mode,
fan_speed=( fan_speed=fan_speed, # api defaults to not sending fanSpeed if None specified
self._current_tado_fan_speed swing=swing, # api defaults to not sending swing if None specified
if (self._support_flags & SUPPORT_FAN_MODE)
else None
), # api defaults to not sending fanSpeed if not specified
) )

View File

@ -131,3 +131,7 @@ TADO_TO_HA_FAN_MODE_MAP = {value: key for key, value in HA_TO_TADO_FAN_MODE_MAP.
DEFAULT_TADO_PRECISION = 0.1 DEFAULT_TADO_PRECISION = 0.1
SUPPORT_PRESET = [PRESET_AWAY, PRESET_HOME] SUPPORT_PRESET = [PRESET_AWAY, PRESET_HOME]
TADO_SWING_OFF = "OFF"
TADO_SWING_ON = "ON"

View File

@ -3,7 +3,7 @@
"name": "Tado", "name": "Tado",
"documentation": "https://www.home-assistant.io/integrations/tado", "documentation": "https://www.home-assistant.io/integrations/tado",
"requirements": [ "requirements": [
"python-tado==0.5.0" "python-tado==0.6.0"
], ],
"dependencies": [], "dependencies": [],
"codeowners": [ "codeowners": [

View File

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

View File

@ -620,7 +620,7 @@ python-miio==0.4.8
python-nest==4.1.0 python-nest==4.1.0
# homeassistant.components.tado # homeassistant.components.tado
python-tado==0.5.0 python-tado==0.6.0
# homeassistant.components.twitch # homeassistant.components.twitch
python-twitch-client==0.6.0 python-twitch-client==0.6.0

View File

@ -57,3 +57,32 @@ async def test_heater(hass):
# Only test for a subset of attributes in case # Only test for a subset of attributes in case
# HA changes the implementation and a new one appears # HA changes the implementation and a new one appears
assert all(item in state.attributes.items() for item in expected_attributes.items()) assert all(item in state.attributes.items() for item in expected_attributes.items())
async def test_smartac_with_swing(hass):
"""Test creation of smart ac with swing climate."""
await async_init_integration(hass)
state = hass.states.get("climate.air_conditioning_with_swing")
assert state.state == "auto"
expected_attributes = {
"current_humidity": 42.3,
"current_temperature": 20.9,
"fan_mode": "auto",
"fan_modes": ["auto", "high", "medium", "low"],
"friendly_name": "Air Conditioning with swing",
"hvac_action": "heating",
"hvac_modes": ["off", "auto", "heat", "cool", "heat_cool", "dry", "fan_only"],
"max_temp": 30.0,
"min_temp": 16.0,
"preset_mode": "home",
"preset_modes": ["away", "home"],
"supported_features": 57,
"target_temp_step": 1.0,
"temperature": 20.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())

View File

@ -19,6 +19,11 @@ async def async_init_integration(
devices_fixture = "tado/devices.json" devices_fixture = "tado/devices.json"
me_fixture = "tado/me.json" me_fixture = "tado/me.json"
zones_fixture = "tado/zones.json" zones_fixture = "tado/zones.json"
# Smart AC with Swing
zone_5_state_fixture = "tado/smartac3.with_swing.json"
zone_5_capabilities_fixture = "tado/zone_with_swing_capabilities.json"
# Water Heater 2 # Water Heater 2
zone_4_state_fixture = "tado/tadov2.water_heater.heating.json" zone_4_state_fixture = "tado/tadov2.water_heater.heating.json"
zone_4_capabilities_fixture = "tado/water_heater_zone_capabilities.json" zone_4_capabilities_fixture = "tado/water_heater_zone_capabilities.json"
@ -31,6 +36,7 @@ async def async_init_integration(
zone_2_state_fixture = "tado/tadov2.water_heater.auto_mode.json" zone_2_state_fixture = "tado/tadov2.water_heater.auto_mode.json"
zone_2_capabilities_fixture = "tado/water_heater_zone_capabilities.json" zone_2_capabilities_fixture = "tado/water_heater_zone_capabilities.json"
# Tado V2 with manual heating
zone_1_state_fixture = "tado/tadov2.heating.manual_mode.json" zone_1_state_fixture = "tado/tadov2.heating.manual_mode.json"
zone_1_capabilities_fixture = "tado/tadov2.zone_capabilities.json" zone_1_capabilities_fixture = "tado/tadov2.zone_capabilities.json"
@ -47,6 +53,10 @@ async def async_init_integration(
"https://my.tado.com/api/v2/homes/1/zones", "https://my.tado.com/api/v2/homes/1/zones",
text=load_fixture(zones_fixture), text=load_fixture(zones_fixture),
) )
m.get(
"https://my.tado.com/api/v2/homes/1/zones/5/capabilities",
text=load_fixture(zone_5_capabilities_fixture),
)
m.get( m.get(
"https://my.tado.com/api/v2/homes/1/zones/4/capabilities", "https://my.tado.com/api/v2/homes/1/zones/4/capabilities",
text=load_fixture(zone_4_capabilities_fixture), text=load_fixture(zone_4_capabilities_fixture),
@ -63,6 +73,10 @@ async def async_init_integration(
"https://my.tado.com/api/v2/homes/1/zones/1/capabilities", "https://my.tado.com/api/v2/homes/1/zones/1/capabilities",
text=load_fixture(zone_1_capabilities_fixture), text=load_fixture(zone_1_capabilities_fixture),
) )
m.get(
"https://my.tado.com/api/v2/homes/1/zones/5/state",
text=load_fixture(zone_5_state_fixture),
)
m.get( m.get(
"https://my.tado.com/api/v2/homes/1/zones/4/state", "https://my.tado.com/api/v2/homes/1/zones/4/state",
text=load_fixture(zone_4_state_fixture), text=load_fixture(zone_4_state_fixture),

View File

@ -0,0 +1,64 @@
{
"tadoMode": "HOME",
"geolocationOverride": false,
"geolocationOverrideDisableTime": null,
"preparation": null,
"setting": {
"type": "AIR_CONDITIONING",
"power": "ON",
"mode": "HEAT",
"temperature": {
"celsius": 20.00,
"fahrenheit": 68.00
},
"fanSpeed": "AUTO",
"swing": "ON"
},
"overlayType": null,
"overlay": null,
"openWindow": null,
"nextScheduleChange": {
"start": "2020-03-28T04:30:00Z",
"setting": {
"type": "AIR_CONDITIONING",
"power": "ON",
"mode": "HEAT",
"temperature": {
"celsius": 23.00,
"fahrenheit": 73.40
},
"fanSpeed": "AUTO",
"swing": "ON"
}
},
"nextTimeBlock": {
"start": "2020-03-28T04:30:00.000Z"
},
"link": {
"state": "ONLINE"
},
"activityDataPoints": {
"acPower": {
"timestamp": "2020-03-27T23:02:22.260Z",
"type": "POWER",
"value": "ON"
}
},
"sensorDataPoints": {
"insideTemperature": {
"celsius": 20.88,
"fahrenheit": 69.58,
"timestamp": "2020-03-28T02:09:27.830Z",
"type": "TEMPERATURE",
"precision": {
"celsius": 0.1,
"fahrenheit": 0.1
}
},
"humidity": {
"type": "PERCENTAGE",
"percentage": 42.30,
"timestamp": "2020-03-28T02:09:27.830Z"
}
}
}

View File

@ -0,0 +1,46 @@
{
"type": "AIR_CONDITIONING",
"AUTO": {
"fanSpeeds": ["AUTO", "HIGH", "MIDDLE", "LOW"],
"swings": ["OFF", "ON"]
},
"COOL": {
"temperatures": {
"celsius": {
"min": 18,
"max": 30,
"step": 1.0
},
"fahrenheit": {
"min": 64,
"max": 86,
"step": 1.0
}
},
"fanSpeeds": ["AUTO", "HIGH", "MIDDLE", "LOW"],
"swings": ["OFF", "ON"]
},
"DRY": {
"swings": ["OFF", "ON"]
},
"FAN": {
"fanSpeeds": ["AUTO", "HIGH", "MIDDLE", "LOW"],
"swings": ["OFF", "ON"]
},
"HEAT": {
"temperatures": {
"celsius": {
"min": 16,
"max": 30,
"step": 1.0
},
"fahrenheit": {
"min": 61,
"max": 86,
"step": 1.0
}
},
"fanSpeeds": ["AUTO", "HIGH", "MIDDLE", "LOW"],
"swings": ["OFF", "ON"]
}
}

View File

@ -175,5 +175,53 @@
}, },
"id" : 4, "id" : 4,
"supportsDazzle" : true "supportsDazzle" : true
},
{
"dazzleMode" : {
"supported" : true,
"enabled" : true
},
"name" : "Air Conditioning with swing",
"id" : 5,
"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"
} }
] ]