Drop support for fan speeds and support reverse (#53105)

This commit is contained in:
Joakim Plate 2021-07-21 07:07:15 +02:00 committed by GitHub
parent fe89603ee7
commit 8a7cb389ed
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 103 additions and 104 deletions

View File

@ -142,6 +142,7 @@ COMMAND_MEDIA_SEEK_RELATIVE = f"{PREFIX_COMMANDS}mediaSeekRelative"
COMMAND_MEDIA_SEEK_TO_POSITION = f"{PREFIX_COMMANDS}mediaSeekToPosition"
COMMAND_MEDIA_SHUFFLE = f"{PREFIX_COMMANDS}mediaShuffle"
COMMAND_MEDIA_STOP = f"{PREFIX_COMMANDS}mediaStop"
COMMAND_REVERSE = f"{PREFIX_COMMANDS}Reverse"
COMMAND_SET_HUMIDITY = f"{PREFIX_COMMANDS}SetHumidity"
COMMAND_SELECT_CHANNEL = f"{PREFIX_COMMANDS}selectChannel"
@ -1258,14 +1259,7 @@ class FanSpeedTrait(_Trait):
"""
name = TRAIT_FANSPEED
commands = [COMMAND_FANSPEED]
speed_synonyms = {
fan.SPEED_OFF: ["stop", "off"],
fan.SPEED_LOW: ["slow", "low", "slowest", "lowest"],
fan.SPEED_MEDIUM: ["medium", "mid", "middle"],
fan.SPEED_HIGH: ["high", "max", "fast", "highest", "fastest", "maximum"],
}
commands = [COMMAND_FANSPEED, COMMAND_REVERSE]
@staticmethod
def supported(domain, features, device_class, _):
@ -1280,23 +1274,21 @@ class FanSpeedTrait(_Trait):
"""Return speed point and modes attributes for a sync request."""
domain = self.state.domain
speeds = []
reversible = False
result = {}
if domain == fan.DOMAIN:
# The use of legacy speeds is deprecated in the schema, support will be removed after a quarter (2021.7)
modes = self.state.attributes.get(fan.ATTR_SPEED_LIST, [])
for mode in modes:
speed = {
"speed_name": mode,
"speed_values": [
{"speed_synonym": self.speed_synonyms.get(mode), "lang": "en"}
],
}
speeds.append(speed)
reversible = bool(
self.state.attributes.get(ATTR_SUPPORTED_FEATURES, 0)
& fan.SUPPORT_DIRECTION
)
result.update(
{
"reversible": reversible,
"supportsFanSpeedPercent": True,
}
)
elif domain == climate.DOMAIN:
modes = self.state.attributes.get(climate.ATTR_FAN_MODES, [])
for mode in modes:
@ -1306,32 +1298,32 @@ class FanSpeedTrait(_Trait):
}
speeds.append(speed)
return {
"availableFanSpeeds": {"speeds": speeds, "ordered": True},
"reversible": reversible,
"supportsFanSpeedPercent": True,
}
result.update(
{
"reversible": False,
"availableFanSpeeds": {"speeds": speeds, "ordered": True},
}
)
return result
def query_attributes(self):
"""Return speed point and modes query attributes."""
attrs = self.state.attributes
domain = self.state.domain
response = {}
if domain == climate.DOMAIN:
speed = attrs.get(climate.ATTR_FAN_MODE)
if speed is not None:
response["currentFanSpeedSetting"] = speed
speed = attrs.get(climate.ATTR_FAN_MODE) or "off"
response["currentFanSpeedSetting"] = speed
if domain == fan.DOMAIN:
speed = attrs.get(fan.ATTR_SPEED)
percent = attrs.get(fan.ATTR_PERCENTAGE) or 0
if speed is not None:
response["on"] = speed != fan.SPEED_OFF
response["currentFanSpeedSetting"] = speed
if percent is not None:
response["currentFanSpeedPercent"] = percent
response["currentFanSpeedPercent"] = percent
return response
async def execute(self, command, data, params, challenge):
async def execute_fanspeed(self, data, params):
"""Execute an SetFanSpeed command."""
domain = self.state.domain
if domain == climate.DOMAIN:
@ -1345,25 +1337,43 @@ class FanSpeedTrait(_Trait):
blocking=True,
context=data.context,
)
if domain == fan.DOMAIN:
service_params = {
ATTR_ENTITY_ID: self.state.entity_id,
}
if "fanSpeedPercent" in params:
service = fan.SERVICE_SET_PERCENTAGE
service_params[fan.ATTR_PERCENTAGE] = params["fanSpeedPercent"]
else:
service = fan.SERVICE_SET_SPEED
service_params[fan.ATTR_SPEED] = params["fanSpeed"]
if domain == fan.DOMAIN:
await self.hass.services.async_call(
fan.DOMAIN,
service,
service_params,
fan.SERVICE_SET_PERCENTAGE,
{
ATTR_ENTITY_ID: self.state.entity_id,
fan.ATTR_PERCENTAGE: params["fanSpeedPercent"],
},
blocking=True,
context=data.context,
)
async def execute_reverse(self, data, params):
"""Execute a Reverse command."""
domain = self.state.domain
if domain == fan.DOMAIN:
if self.state.attributes.get(fan.ATTR_DIRECTION) == fan.DIRECTION_FORWARD:
direction = fan.DIRECTION_REVERSE
else:
direction = fan.DIRECTION_FORWARD
await self.hass.services.async_call(
fan.DOMAIN,
fan.SERVICE_SET_DIRECTION,
{ATTR_ENTITY_ID: self.state.entity_id, fan.ATTR_DIRECTION: direction},
blocking=True,
context=data.context,
)
async def execute(self, command, data, params, challenge):
"""Execute a smart home command."""
if command == COMMAND_FANSPEED:
await self.execute_fanspeed(data, params)
elif command == COMMAND_REVERSE:
await self.execute_reverse(data, params)
@register_trait
class ModesTrait(_Trait):

View File

@ -1461,13 +1461,6 @@ async def test_fan_speed(hass):
"fan.living_room_fan",
fan.SPEED_HIGH,
attributes={
"speed_list": [
fan.SPEED_OFF,
fan.SPEED_LOW,
fan.SPEED_MEDIUM,
fan.SPEED_HIGH,
],
"speed": "low",
"percentage": 33,
"percentage_step": 1.0,
},
@ -1476,64 +1469,14 @@ async def test_fan_speed(hass):
)
assert trt.sync_attributes() == {
"availableFanSpeeds": {
"ordered": True,
"speeds": [
{
"speed_name": "off",
"speed_values": [{"speed_synonym": ["stop", "off"], "lang": "en"}],
},
{
"speed_name": "low",
"speed_values": [
{
"speed_synonym": ["slow", "low", "slowest", "lowest"],
"lang": "en",
}
],
},
{
"speed_name": "medium",
"speed_values": [
{"speed_synonym": ["medium", "mid", "middle"], "lang": "en"}
],
},
{
"speed_name": "high",
"speed_values": [
{
"speed_synonym": [
"high",
"max",
"fast",
"highest",
"fastest",
"maximum",
],
"lang": "en",
}
],
},
],
},
"reversible": False,
"supportsFanSpeedPercent": True,
}
assert trt.query_attributes() == {
"currentFanSpeedSetting": "low",
"on": True,
"currentFanSpeedPercent": 33,
}
assert trt.can_execute(trait.COMMAND_FANSPEED, params={"fanSpeed": "medium"})
calls = async_mock_service(hass, fan.DOMAIN, fan.SERVICE_SET_SPEED)
await trt.execute(trait.COMMAND_FANSPEED, BASIC_DATA, {"fanSpeed": "medium"}, {})
assert len(calls) == 1
assert calls[0].data == {"entity_id": "fan.living_room_fan", "speed": "medium"}
assert trt.can_execute(trait.COMMAND_FANSPEED, params={"fanSpeedPercent": 10})
calls = async_mock_service(hass, fan.DOMAIN, fan.SERVICE_SET_PERCENTAGE)
@ -1543,6 +1486,53 @@ async def test_fan_speed(hass):
assert calls[0].data == {"entity_id": "fan.living_room_fan", "percentage": 10}
@pytest.mark.parametrize(
"direction_state,direction_call",
[
(fan.DIRECTION_FORWARD, fan.DIRECTION_REVERSE),
(fan.DIRECTION_REVERSE, fan.DIRECTION_FORWARD),
(None, fan.DIRECTION_FORWARD),
],
)
async def test_fan_reverse(hass, direction_state, direction_call):
"""Test FanSpeed trait speed control support for fan domain."""
calls = async_mock_service(hass, fan.DOMAIN, fan.SERVICE_SET_DIRECTION)
trt = trait.FanSpeedTrait(
hass,
State(
"fan.living_room_fan",
fan.SPEED_HIGH,
attributes={
"percentage": 33,
"percentage_step": 1.0,
"direction": direction_state,
"supported_features": fan.SUPPORT_DIRECTION,
},
),
BASIC_CONFIG,
)
assert trt.sync_attributes() == {
"reversible": True,
"supportsFanSpeedPercent": True,
}
assert trt.query_attributes() == {
"currentFanSpeedPercent": 33,
}
assert trt.can_execute(trait.COMMAND_REVERSE, params={})
await trt.execute(trait.COMMAND_REVERSE, BASIC_DATA, {}, {})
assert len(calls) == 1
assert calls[0].data == {
"entity_id": "fan.living_room_fan",
"direction": direction_call,
}
async def test_climate_fan_speed(hass):
"""Test FanSpeed trait speed control support for climate domain."""
assert helpers.get_google_type(climate.DOMAIN, None) is not None
@ -1586,7 +1576,6 @@ async def test_climate_fan_speed(hass):
],
},
"reversible": False,
"supportsFanSpeedPercent": True,
}
assert trt.query_attributes() == {