Implement google_assistant ModesTrait for input_select (#36313)

This commit is contained in:
Brynley McDonald 2020-06-02 04:40:47 +12:00 committed by GitHub
parent a333417ddf
commit 47706dac1a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 121 additions and 14 deletions

View File

@ -8,6 +8,7 @@ from homeassistant.components import (
fan,
group,
input_boolean,
input_select,
light,
lock,
media_player,
@ -44,6 +45,7 @@ DEFAULT_EXPOSED_DOMAINS = [
"fan",
"group",
"input_boolean",
"input_select",
"light",
"media_player",
"scene",
@ -113,6 +115,7 @@ DOMAIN_TO_GOOGLE_TYPES = {
fan.DOMAIN: TYPE_FAN,
group.DOMAIN: TYPE_SWITCH,
input_boolean.DOMAIN: TYPE_SWITCH,
input_select.DOMAIN: TYPE_SENSOR,
light.DOMAIN: TYPE_LIGHT,
lock.DOMAIN: TYPE_LOCK,
media_player.DOMAIN: TYPE_SETTOP,

View File

@ -9,6 +9,7 @@ from homeassistant.components import (
fan,
group,
input_boolean,
input_select,
light,
lock,
media_player,
@ -1131,11 +1132,15 @@ class ModesTrait(_Trait):
SYNONYMS = {
"input source": ["input source", "input", "source"],
"sound mode": ["sound mode", "effects"],
"option": ["option", "setting", "mode", "value"],
}
@staticmethod
def supported(domain, features, device_class):
"""Test if state is supported."""
if domain == input_select.DOMAIN:
return True
if domain != media_player.DOMAIN:
return False
@ -1174,15 +1179,20 @@ class ModesTrait(_Trait):
attrs = self.state.attributes
modes = []
if media_player.ATTR_INPUT_SOURCE_LIST in attrs:
modes.append(
_generate("input source", attrs[media_player.ATTR_INPUT_SOURCE_LIST])
)
if self.state.domain == media_player.DOMAIN:
if media_player.ATTR_INPUT_SOURCE_LIST in attrs:
modes.append(
_generate(
"input source", attrs[media_player.ATTR_INPUT_SOURCE_LIST]
)
)
if media_player.ATTR_SOUND_MODE_LIST in attrs:
modes.append(
_generate("sound mode", attrs[media_player.ATTR_SOUND_MODE_LIST])
)
if media_player.ATTR_SOUND_MODE_LIST in attrs:
modes.append(
_generate("sound mode", attrs[media_player.ATTR_SOUND_MODE_LIST])
)
elif self.state.domain == input_select.DOMAIN:
modes.append(_generate("option", attrs[input_select.ATTR_OPTIONS]))
payload = {"availableModes": modes}
@ -1194,11 +1204,16 @@ class ModesTrait(_Trait):
response = {}
mode_settings = {}
if media_player.ATTR_INPUT_SOURCE_LIST in attrs:
mode_settings["input source"] = attrs.get(media_player.ATTR_INPUT_SOURCE)
if self.state.domain == media_player.DOMAIN:
if media_player.ATTR_INPUT_SOURCE_LIST in attrs:
mode_settings["input source"] = attrs.get(
media_player.ATTR_INPUT_SOURCE
)
if media_player.ATTR_SOUND_MODE_LIST in attrs:
mode_settings["sound mode"] = attrs.get(media_player.ATTR_SOUND_MODE)
if media_player.ATTR_SOUND_MODE_LIST in attrs:
mode_settings["sound mode"] = attrs.get(media_player.ATTR_SOUND_MODE)
elif self.state.domain == input_select.DOMAIN:
mode_settings["option"] = self.state.state
if mode_settings:
response["on"] = self.state.state != STATE_OFF
@ -1210,6 +1225,28 @@ class ModesTrait(_Trait):
async def execute(self, command, data, params, challenge):
"""Execute an SetModes command."""
settings = params.get("updateModeSettings")
if self.state.domain == input_select.DOMAIN:
option = params["updateModeSettings"]["option"]
await self.hass.services.async_call(
input_select.DOMAIN,
input_select.SERVICE_SELECT_OPTION,
{
ATTR_ENTITY_ID: self.state.entity_id,
input_select.ATTR_OPTION: option,
},
blocking=True,
context=data.context,
)
return
if self.state.domain != media_player.DOMAIN:
_LOGGER.info(
"Received an Options command for unrecognised domain %s",
self.state.domain,
)
return
requested_source = settings.get("input source")
sound_mode = settings.get("sound mode")

View File

@ -11,6 +11,7 @@ from homeassistant.components import (
fan,
group,
input_boolean,
input_select,
light,
lock,
media_player,
@ -1267,8 +1268,8 @@ async def test_fan_speed(hass):
assert calls[0].data == {"entity_id": "fan.living_room_fan", "speed": "medium"}
async def test_modes(hass):
"""Test Mode trait."""
async def test_modes_media_player(hass):
"""Test Media Player Mode trait."""
assert helpers.get_google_type(media_player.DOMAIN, None) is not None
assert trait.ModesTrait.supported(
media_player.DOMAIN, media_player.SUPPORT_SELECT_SOURCE, None
@ -1351,6 +1352,72 @@ async def test_modes(hass):
assert calls[0].data == {"entity_id": "media_player.living_room", "source": "media"}
async def test_modes_input_select(hass):
"""Test Input Select Mode trait."""
assert helpers.get_google_type(input_select.DOMAIN, None) is not None
assert trait.ModesTrait.supported(input_select.DOMAIN, None, None)
trt = trait.ModesTrait(
hass,
State(
"input_select.bla",
"abc",
attributes={input_select.ATTR_OPTIONS: ["abc", "123", "xyz"]},
),
BASIC_CONFIG,
)
attribs = trt.sync_attributes()
assert attribs == {
"availableModes": [
{
"name": "option",
"name_values": [
{
"name_synonym": ["option", "setting", "mode", "value"],
"lang": "en",
}
],
"settings": [
{
"setting_name": "abc",
"setting_values": [{"setting_synonym": ["abc"], "lang": "en"}],
},
{
"setting_name": "123",
"setting_values": [{"setting_synonym": ["123"], "lang": "en"}],
},
{
"setting_name": "xyz",
"setting_values": [{"setting_synonym": ["xyz"], "lang": "en"}],
},
],
"ordered": False,
}
]
}
assert trt.query_attributes() == {
"currentModeSettings": {"option": "abc"},
"on": True,
"online": True,
}
assert trt.can_execute(
trait.COMMAND_MODES, params={"updateModeSettings": {"option": "xyz"}},
)
calls = async_mock_service(
hass, input_select.DOMAIN, input_select.SERVICE_SELECT_OPTION
)
await trt.execute(
trait.COMMAND_MODES, BASIC_DATA, {"updateModeSettings": {"option": "xyz"}}, {},
)
assert len(calls) == 1
assert calls[0].data == {"entity_id": "input_select.bla", "option": "xyz"}
async def test_sound_modes(hass):
"""Test Mode trait."""
assert helpers.get_google_type(media_player.DOMAIN, None) is not None