Fix Tado fan mode (#120809)

This commit is contained in:
Etienne Soufflet 2024-06-30 20:38:35 +02:00 committed by GitHub
parent 2f5ec41fa6
commit 1a63bb89cb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 401 additions and 9 deletions

View file

@ -73,7 +73,7 @@ from .const import (
TYPE_HEATING,
)
from .entity import TadoZoneEntity
from .helper import decide_duration, decide_overlay_mode
from .helper import decide_duration, decide_overlay_mode, generate_supported_fanmodes
_LOGGER = logging.getLogger(__name__)
@ -200,15 +200,14 @@ def create_climate_entity(
continue
if capabilities[mode].get("fanSpeeds"):
supported_fan_modes = [
TADO_TO_HA_FAN_MODE_MAP_LEGACY[speed]
for speed in capabilities[mode]["fanSpeeds"]
]
supported_fan_modes = generate_supported_fanmodes(
TADO_TO_HA_FAN_MODE_MAP_LEGACY, capabilities[mode]["fanSpeeds"]
)
else:
supported_fan_modes = [
TADO_TO_HA_FAN_MODE_MAP[level]
for level in capabilities[mode]["fanLevel"]
]
supported_fan_modes = generate_supported_fanmodes(
TADO_TO_HA_FAN_MODE_MAP, capabilities[mode]["fanLevel"]
)
cool_temperatures = capabilities[CONST_MODE_COOL]["temperatures"]
else:

View file

@ -49,3 +49,15 @@ def decide_duration(
)
return duration
def generate_supported_fanmodes(tado_to_ha_mapping: dict[str, str], options: list[str]):
"""Return correct list of fan modes or None."""
supported_fanmodes = [
tado_to_ha_mapping.get(option)
for option in options
if tado_to_ha_mapping.get(option) is not None
]
if not supported_fanmodes:
return None
return supported_fanmodes

View file

@ -0,0 +1,88 @@
{
"tadoMode": "HOME",
"geolocationOverride": false,
"geolocationOverrideDisableTime": null,
"preparation": null,
"setting": {
"type": "AIR_CONDITIONING",
"power": "ON",
"mode": "HEAT",
"temperature": {
"celsius": 25.0,
"fahrenheit": 77.0
},
"fanLevel": "LEVEL3",
"verticalSwing": "ON",
"horizontalSwing": "ON"
},
"overlayType": "MANUAL",
"overlay": {
"type": "MANUAL",
"setting": {
"type": "AIR_CONDITIONING",
"power": "ON",
"mode": "HEAT",
"temperature": {
"celsius": 25.0,
"fahrenheit": 77.0
},
"fanLevel": "LEVEL3",
"verticalSwing": "ON"
},
"termination": {
"type": "MANUAL",
"typeSkillBasedApp": "MANUAL",
"projectedExpiry": null
}
},
"openWindow": null,
"nextScheduleChange": {
"start": "2024-07-01T05: 45: 00Z",
"setting": {
"type": "AIR_CONDITIONING",
"power": "ON",
"mode": "HEAT",
"temperature": {
"celsius": 24.0,
"fahrenheit": 75.2
},
"fanLevel": "LEVEL3",
"verticalSwing": "ON",
"horizontalSwing": "ON"
}
},
"nextTimeBlock": {
"start": "2024-07-01T05: 45: 00.000Z"
},
"link": {
"state": "ONLINE"
},
"runningOfflineSchedule": false,
"activityDataPoints": {
"acPower": {
"timestamp": "2022-07-13T18: 06: 58.183Z",
"type": "POWER",
"value": "ON"
}
},
"sensorDataPoints": {
"insideTemperature": {
"celsius": 24.3,
"fahrenheit": 75.74,
"timestamp": "2024-06-28T22: 23: 15.679Z",
"type": "TEMPERATURE",
"precision": {
"celsius": 0.1,
"fahrenheit": 0.1
}
},
"humidity": {
"type": "PERCENTAGE",
"percentage": 70.9,
"timestamp": "2024-06-28T22: 23: 15.679Z"
}
},
"terminationCondition": {
"type": "MANUAL"
}
}

View file

@ -287,6 +287,79 @@
"timestamp": "2020-03-28T02:09:27.830Z"
}
}
},
"6": {
"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": {
"start": "2024-07-01T05: 45: 00Z",
"setting": {
"type": "AIR_CONDITIONING",
"power": "ON",
"mode": "HEAT",
"temperature": {
"celsius": 24.0,
"fahrenheit": 75.2
},
"fanLevel": "LEVEL3",
"verticalSwing": "ON",
"horizontalSwing": "ON"
}
},
"nextTimeBlock": {
"start": "2024-07-01T05: 45: 00.000Z"
},
"link": {
"state": "ONLINE"
},
"runningOfflineSchedule": false,
"activityDataPoints": {
"acPower": {
"timestamp": "2022-07-13T18: 06: 58.183Z",
"type": "POWER",
"value": "OFF"
}
},
"sensorDataPoints": {
"insideTemperature": {
"celsius": 24.21,
"fahrenheit": 75.58,
"timestamp": "2024-06-28T21: 43: 51.067Z",
"type": "TEMPERATURE",
"precision": {
"celsius": 0.1,
"fahrenheit": 0.1
}
},
"humidity": {
"type": "PERCENTAGE",
"percentage": 71.4,
"timestamp": "2024-06-28T21: 43: 51.067Z"
}
},
"terminationCondition": {
"type": "MANUAL"
}
}
}
}

View file

@ -0,0 +1,130 @@
{
"type": "AIR_CONDITIONING",
"COOL": {
"temperatures": {
"celsius": {
"min": 16,
"max": 31,
"step": 1.0
},
"fahrenheit": {
"min": 61,
"max": 88,
"step": 1.0
}
},
"fanLevel": ["LEVEL3", "LEVEL2", "AUTO", "LEVEL1", "LEVEL4", "LEVEL5"],
"verticalSwing": ["MID_UP", "MID_DOWN", "ON", "OFF", "UP", "MID", "DOWN"],
"horizontalSwing": ["OFF", "ON"],
"light": ["ON", "OFF"]
},
"FAN": {
"temperatures": {
"celsius": {
"min": 16,
"max": 31,
"step": 1.0
},
"fahrenheit": {
"min": 61,
"max": 88,
"step": 1.0
}
},
"fanLevel": ["LEVEL3", "LEVEL2", "AUTO", "LEVEL1", "LEVEL4", "LEVEL5"],
"verticalSwing": ["MID_UP", "MID_DOWN", "ON", "OFF", "UP", "MID", "DOWN"],
"horizontalSwing": ["OFF", "ON"],
"light": ["ON", "OFF"]
},
"AUTO": {
"fanLevel": ["LEVEL3", "LEVEL2", "AUTO", "LEVEL1", "LEVEL4", "LEVEL5"],
"verticalSwing": ["MID_UP", "MID_DOWN", "ON", "OFF", "UP", "MID", "DOWN"],
"horizontalSwing": ["OFF", "ON"],
"light": ["ON", "OFF"]
},
"HEAT": {
"temperatures": {
"celsius": {
"min": 16,
"max": 31,
"step": 1.0
},
"fahrenheit": {
"min": 61,
"max": 88,
"step": 1.0
}
},
"fanLevel": ["LEVEL3", "LEVEL2", "AUTO", "LEVEL1", "LEVEL4", "LEVEL5"],
"verticalSwing": ["MID_UP", "MID_DOWN", "ON", "OFF", "UP", "MID", "DOWN"],
"horizontalSwing": ["OFF", "ON"],
"light": ["ON", "OFF"]
},
"DRY": {
"temperatures": {
"celsius": {
"min": 16,
"max": 31,
"step": 1.0
},
"fahrenheit": {
"min": 61,
"max": 88,
"step": 1.0
}
},
"verticalSwing": ["MID_UP", "MID_DOWN", "ON", "OFF", "UP", "MID", "DOWN"],
"horizontalSwing": ["OFF", "ON"],
"light": ["ON", "OFF"]
},
"initialStates": {
"mode": "COOL",
"modes": {
"COOL": {
"temperature": {
"celsius": 24,
"fahrenheit": 75
},
"fanLevel": "LEVEL3",
"verticalSwing": "OFF",
"horizontalSwing": "OFF",
"light": "ON"
},
"HEAT": {
"temperature": {
"celsius": 24,
"fahrenheit": 75
},
"fanLevel": "LEVEL3",
"verticalSwing": "OFF",
"horizontalSwing": "OFF",
"light": "ON"
},
"DRY": {
"temperature": {
"celsius": 24,
"fahrenheit": 75
},
"verticalSwing": "OFF",
"horizontalSwing": "OFF",
"light": "ON"
},
"FAN": {
"temperature": {
"celsius": 24,
"fahrenheit": 75
},
"fanLevel": "LEVEL3",
"verticalSwing": "OFF",
"horizontalSwing": "OFF",
"light": "ON"
},
"AUTO": {
"fanLevel": "LEVEL3",
"verticalSwing": "OFF",
"horizontalSwing": "OFF",
"light": "ON"
}
}
}
}

View file

@ -178,5 +178,45 @@
"deviceTypes": ["WR02"],
"reportAvailable": false,
"type": "AIR_CONDITIONING"
},
{
"id": 6,
"name": "Air Conditioning with fanlevel",
"type": "AIR_CONDITIONING",
"dateCreated": "2022-07-13T18: 06: 58.183Z",
"deviceTypes": ["WR02"],
"devices": [
{
"deviceType": "WR02",
"serialNo": "WR5",
"shortSerialNo": "WR5",
"currentFwVersion": "118.7",
"connectionState": {
"value": true,
"timestamp": "2024-06-28T21: 04: 23.463Z"
},
"characteristics": {
"capabilities": ["INSIDE_TEMPERATURE_MEASUREMENT", "IDENTIFY"]
},
"accessPointWiFi": {
"ssid": "tado8480"
},
"commandTableUploadState": "FINISHED",
"duties": ["ZONE_UI", "ZONE_DRIVER", "ZONE_LEADER"]
}
],
"reportAvailable": false,
"showScheduleSetup": false,
"supportsDazzle": true,
"dazzleEnabled": true,
"dazzleMode": {
"supported": true,
"enabled": true
},
"openWindowDetection": {
"supported": true,
"enabled": true,
"timeoutInSeconds": 900
}
}
]

View file

@ -89,3 +89,35 @@ async def test_smartac_with_swing(hass: HomeAssistant) -> None:
# 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_smartac_with_fanlevel_vertical_and_horizontal_swing(
hass: HomeAssistant,
) -> None:
"""Test creation of smart ac with swing climate."""
await async_init_integration(hass)
state = hass.states.get("climate.air_conditioning_with_fanlevel")
assert state.state == "heat"
expected_attributes = {
"current_humidity": 70.9,
"current_temperature": 24.3,
"fan_mode": "high",
"fan_modes": ["high", "medium", "auto", "low"],
"friendly_name": "Air Conditioning with fanlevel",
"hvac_action": "heating",
"hvac_modes": ["off", "auto", "heat", "cool", "heat_cool", "dry", "fan_only"],
"max_temp": 31.0,
"min_temp": 16.0,
"preset_mode": "auto",
"preset_modes": ["away", "home", "auto"],
"swing_modes": ["vertical", "horizontal", "both", "off"],
"supported_features": 441,
"target_temp_step": 1.0,
"temperature": 25.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

@ -27,6 +27,12 @@ async def async_init_integration(
# WR1 Device
device_wr1_fixture = "tado/device_wr1.json"
# Smart AC with fanLevel, Vertical and Horizontal swings
zone_6_state_fixture = "tado/smartac4.with_fanlevel.json"
zone_6_capabilities_fixture = (
"tado/zone_with_fanlevel_horizontal_vertical_swing.json"
)
# Smart AC with Swing
zone_5_state_fixture = "tado/smartac3.with_swing.json"
zone_5_capabilities_fixture = "tado/zone_with_swing_capabilities.json"
@ -95,6 +101,10 @@ async def async_init_integration(
"https://my.tado.com/api/v2/homes/1/zoneStates",
text=load_fixture(zone_states_fixture),
)
m.get(
"https://my.tado.com/api/v2/homes/1/zones/6/capabilities",
text=load_fixture(zone_6_capabilities_fixture),
)
m.get(
"https://my.tado.com/api/v2/homes/1/zones/5/capabilities",
text=load_fixture(zone_5_capabilities_fixture),
@ -135,6 +145,14 @@ async def async_init_integration(
"https://my.tado.com/api/v2/homes/1/zones/5/defaultOverlay",
text=load_fixture(zone_def_overlay),
)
m.get(
"https://my.tado.com/api/v2/homes/1/zones/6/defaultOverlay",
text=load_fixture(zone_def_overlay),
)
m.get(
"https://my.tado.com/api/v2/homes/1/zones/6/state",
text=load_fixture(zone_6_state_fixture),
)
m.get(
"https://my.tado.com/api/v2/homes/1/zones/5/state",
text=load_fixture(zone_5_state_fixture),