mirror of
https://github.com/home-assistant/core.git
synced 2025-07-24 05:37:44 +00:00
Drop support for fan speeds and support reverse (#53105)
This commit is contained in:
parent
fe89603ee7
commit
8a7cb389ed
@ -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):
|
||||
|
@ -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() == {
|
||||
|
Loading…
x
Reference in New Issue
Block a user