Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update StepSpeaker and Speaker interfaces in Alexa #31444

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions homeassistant/components/alexa/capabilities.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
"""Alexa capabilities."""
import logging
import math

from homeassistant.components import (
cover,
Expand Down Expand Up @@ -645,6 +646,43 @@ def name(self):
"""Return the Alexa API name of this interface."""
return "Alexa.Speaker"

def properties_supported(self):
"""Return what properties this entity supports."""
properties = [{"name": "volume"}]

supported = self.entity.attributes.get(ATTR_SUPPORTED_FEATURES, 0)
if supported & media_player.SUPPORT_VOLUME_MUTE:
properties.append({"name": "muted"})

return properties

def properties_proactively_reported(self):
"""Return True if properties asynchronously reported."""
return True

def properties_retrievable(self):
"""Return True if properties can be retrieved."""
return True

def get_property(self, name):
"""Read and return a property."""
if name == "volume":
current_level = self.entity.attributes.get(
media_player.ATTR_MEDIA_VOLUME_LEVEL
)
try:
current = math.floor(int(current_level * 100))
except ZeroDivisionError:
current = 0
return current

if name == "muted":
return bool(
self.entity.attributes.get(media_player.ATTR_MEDIA_VOLUME_MUTED)
)

return None


class AlexaStepSpeaker(AlexaCapability):
"""Implements Alexa.StepSpeaker.
Expand Down
7 changes: 1 addition & 6 deletions homeassistant/components/alexa/entities.py
Original file line number Diff line number Diff line change
Expand Up @@ -508,12 +508,7 @@ def interfaces(self):
supported = self.entity.attributes.get(ATTR_SUPPORTED_FEATURES, 0)
if supported & media_player.const.SUPPORT_VOLUME_SET:
yield AlexaSpeaker(self.entity)

step_volume_features = (
media_player.const.SUPPORT_VOLUME_MUTE
| media_player.const.SUPPORT_VOLUME_STEP
)
if supported & step_volume_features:
elif supported & media_player.const.SUPPORT_VOLUME_STEP:
yield AlexaStepSpeaker(self.entity)

playback_features = (
Expand Down
221 changes: 126 additions & 95 deletions tests/components/alexa/test_smart_home.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
SUPPORT_TURN_ON,
SUPPORT_VOLUME_MUTE,
SUPPORT_VOLUME_SET,
SUPPORT_VOLUME_STEP,
)
import homeassistant.components.vacuum as vacuum
from homeassistant.const import TEMP_CELSIUS, TEMP_FAHRENHEIT
Expand Down Expand Up @@ -904,7 +905,6 @@ async def test_media_player(hass):
"Alexa.PlaybackStateReporter",
"Alexa.PowerController",
"Alexa.Speaker",
"Alexa.StepSpeaker",
)

playback_capability = get_capability(capabilities, "Alexa.PlaybackController")
Expand Down Expand Up @@ -958,93 +958,6 @@ async def test_media_player(hass):
hass,
)

call, _ = await assert_request_calls_service(
"Alexa.Speaker",
"SetVolume",
"media_player#test",
"media_player.volume_set",
hass,
payload={"volume": 50},
)
assert call.data["volume_level"] == 0.5

call, _ = await assert_request_calls_service(
"Alexa.Speaker",
"SetMute",
"media_player#test",
"media_player.volume_mute",
hass,
payload={"mute": True},
)
assert call.data["is_volume_muted"]

call, _, = await assert_request_calls_service(
"Alexa.Speaker",
"SetMute",
"media_player#test",
"media_player.volume_mute",
hass,
payload={"mute": False},
)
assert not call.data["is_volume_muted"]

await assert_percentage_changes(
hass,
[(0.7, "-5"), (0.8, "5"), (0, "-80")],
"Alexa.Speaker",
"AdjustVolume",
"media_player#test",
"volume",
"media_player.volume_set",
"volume_level",
)

call, _ = await assert_request_calls_service(
"Alexa.StepSpeaker",
"SetMute",
"media_player#test",
"media_player.volume_mute",
hass,
payload={"mute": True},
)
assert call.data["is_volume_muted"]

call, _, = await assert_request_calls_service(
"Alexa.StepSpeaker",
"SetMute",
"media_player#test",
"media_player.volume_mute",
hass,
payload={"mute": False},
)
assert not call.data["is_volume_muted"]

call, _ = await assert_request_calls_service(
"Alexa.StepSpeaker",
"AdjustVolume",
"media_player#test",
"media_player.volume_up",
hass,
payload={"volumeSteps": 1, "volumeStepsDefault": False},
)

call, _ = await assert_request_calls_service(
"Alexa.StepSpeaker",
"AdjustVolume",
"media_player#test",
"media_player.volume_down",
hass,
payload={"volumeSteps": -1, "volumeStepsDefault": False},
)

call, _ = await assert_request_calls_service(
"Alexa.StepSpeaker",
"AdjustVolume",
"media_player#test",
"media_player.volume_up",
hass,
payload={"volumeSteps": 10, "volumeStepsDefault": True},
)
call, _ = await assert_request_calls_service(
"Alexa.ChannelController",
"ChangeChannel",
Expand Down Expand Up @@ -1140,7 +1053,6 @@ async def test_media_player_power(hass):
"Alexa.PowerController",
"Alexa.SeekController",
"Alexa.Speaker",
"Alexa.StepSpeaker",
)

await assert_request_calls_service(
Expand Down Expand Up @@ -1265,22 +1177,141 @@ async def test_media_player_inputs(hass):


async def test_media_player_speaker(hass):
"""Test media player discovery with device class speaker."""
"""Test media player with speaker interface."""
device = (
"media_player.test",
"media_player.test_speaker",
"off",
{
"friendly_name": "Test media player",
"supported_features": 51765,
"friendly_name": "Test media player speaker",
"supported_features": SUPPORT_VOLUME_MUTE | SUPPORT_VOLUME_SET,
"volume_level": 0.75,
"device_class": "speaker",
},
)
appliance = await discovery_test(device, hass)

assert appliance["endpointId"] == "media_player#test"
assert appliance["endpointId"] == "media_player#test_speaker"
assert appliance["displayCategories"][0] == "SPEAKER"
assert appliance["friendlyName"] == "Test media player"
assert appliance["friendlyName"] == "Test media player speaker"

capabilities = assert_endpoint_capabilities(
appliance,
"Alexa",
"Alexa.EndpointHealth",
"Alexa.PowerController",
"Alexa.Speaker",
)

speaker_capability = get_capability(capabilities, "Alexa.Speaker")
properties = speaker_capability["properties"]
assert {"name": "volume"} in properties["supported"]
assert {"name": "muted"} in properties["supported"]

call, _ = await assert_request_calls_service(
"Alexa.Speaker",
"SetVolume",
"media_player#test_speaker",
"media_player.volume_set",
hass,
payload={"volume": 50},
)
assert call.data["volume_level"] == 0.5

call, _ = await assert_request_calls_service(
"Alexa.Speaker",
"SetMute",
"media_player#test_speaker",
"media_player.volume_mute",
hass,
payload={"mute": True},
)
assert call.data["is_volume_muted"]

call, _, = await assert_request_calls_service(
"Alexa.Speaker",
"SetMute",
"media_player#test_speaker",
"media_player.volume_mute",
hass,
payload={"mute": False},
)
assert not call.data["is_volume_muted"]

await assert_percentage_changes(
hass,
[(0.7, "-5"), (0.8, "5"), (0, "-80")],
"Alexa.Speaker",
"AdjustVolume",
"media_player#test_speaker",
"volume",
"media_player.volume_set",
"volume_level",
)


async def test_media_player_step_speaker(hass):
"""Test media player with step speaker interface."""
device = (
"media_player.test_step_speaker",
"off",
{
"friendly_name": "Test media player step speaker",
"supported_features": SUPPORT_VOLUME_MUTE | SUPPORT_VOLUME_STEP,
"device_class": "speaker",
},
)
appliance = await discovery_test(device, hass)

assert appliance["endpointId"] == "media_player#test_step_speaker"
assert appliance["displayCategories"][0] == "SPEAKER"
assert appliance["friendlyName"] == "Test media player step speaker"

call, _ = await assert_request_calls_service(
"Alexa.StepSpeaker",
"SetMute",
"media_player#test_step_speaker",
"media_player.volume_mute",
hass,
payload={"mute": True},
)
assert call.data["is_volume_muted"]

call, _, = await assert_request_calls_service(
"Alexa.StepSpeaker",
"SetMute",
"media_player#test_step_speaker",
"media_player.volume_mute",
hass,
payload={"mute": False},
)
assert not call.data["is_volume_muted"]

call, _ = await assert_request_calls_service(
"Alexa.StepSpeaker",
"AdjustVolume",
"media_player#test_step_speaker",
"media_player.volume_up",
hass,
payload={"volumeSteps": 1, "volumeStepsDefault": False},
)

call, _ = await assert_request_calls_service(
"Alexa.StepSpeaker",
"AdjustVolume",
"media_player#test_step_speaker",
"media_player.volume_down",
hass,
payload={"volumeSteps": -1, "volumeStepsDefault": False},
)

call, _ = await assert_request_calls_service(
"Alexa.StepSpeaker",
"AdjustVolume",
"media_player#test_step_speaker",
"media_player.volume_up",
hass,
payload={"volumeSteps": 10, "volumeStepsDefault": True},
)


async def test_media_player_seek(hass):
Expand Down