Add Select entity support to Google Assistant (#51997)

This commit is contained in:
Franck Nijhof 2021-06-18 23:30:46 +02:00 committed by GitHub
parent 0ca199d8d0
commit 655f797f67
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 105 additions and 5 deletions

View file

@ -15,6 +15,7 @@ from homeassistant.components import (
media_player,
scene,
script,
select,
sensor,
switch,
vacuum,
@ -39,6 +40,8 @@ CONF_PRIVATE_KEY = "private_key"
DEFAULT_EXPOSE_BY_DEFAULT = True
DEFAULT_EXPOSED_DOMAINS = [
"alarm_control_panel",
"binary_sensor",
"climate",
"cover",
"fan",
@ -47,15 +50,14 @@ DEFAULT_EXPOSED_DOMAINS = [
"input_boolean",
"input_select",
"light",
"lock",
"media_player",
"scene",
"script",
"select",
"sensor",
"switch",
"vacuum",
"lock",
"binary_sensor",
"sensor",
"alarm_control_panel",
]
PREFIX_TYPES = "action.devices.types."
@ -117,6 +119,7 @@ EVENT_QUERY_RECEIVED = "google_assistant_query"
EVENT_SYNC_RECEIVED = "google_assistant_sync"
DOMAIN_TO_GOOGLE_TYPES = {
alarm_control_panel.DOMAIN: TYPE_ALARM,
camera.DOMAIN: TYPE_CAMERA,
climate.DOMAIN: TYPE_THERMOSTAT,
cover.DOMAIN: TYPE_BLINDS,
@ -130,9 +133,9 @@ DOMAIN_TO_GOOGLE_TYPES = {
media_player.DOMAIN: TYPE_SETTOP,
scene.DOMAIN: TYPE_SCENE,
script.DOMAIN: TYPE_SCENE,
select.DOMAIN: TYPE_SENSOR,
switch.DOMAIN: TYPE_SWITCH,
vacuum.DOMAIN: TYPE_VACUUM,
alarm_control_panel.DOMAIN: TYPE_ALARM,
}
DEVICE_CLASS_TO_GOOGLE_TYPES = {

View file

@ -17,6 +17,7 @@ from homeassistant.components import (
media_player,
scene,
script,
select,
sensor,
switch,
vacuum,
@ -1384,6 +1385,9 @@ class ModesTrait(_Trait):
if domain == input_select.DOMAIN:
return True
if domain == select.DOMAIN:
return True
if domain == humidifier.DOMAIN and features & humidifier.SUPPORT_MODES:
return True
@ -1427,6 +1431,7 @@ class ModesTrait(_Trait):
(fan.DOMAIN, fan.ATTR_PRESET_MODES, "preset mode"),
(media_player.DOMAIN, media_player.ATTR_SOUND_MODE_LIST, "sound mode"),
(input_select.DOMAIN, input_select.ATTR_OPTIONS, "option"),
(select.DOMAIN, select.ATTR_OPTIONS, "option"),
(humidifier.DOMAIN, humidifier.ATTR_AVAILABLE_MODES, "mode"),
(light.DOMAIN, light.ATTR_EFFECT_LIST, "effect"),
):
@ -1459,6 +1464,8 @@ class ModesTrait(_Trait):
mode_settings["sound mode"] = attrs.get(media_player.ATTR_SOUND_MODE)
elif self.state.domain == input_select.DOMAIN:
mode_settings["option"] = self.state.state
elif self.state.domain == select.DOMAIN:
mode_settings["option"] = self.state.state
elif self.state.domain == humidifier.DOMAIN:
if ATTR_MODE in attrs:
mode_settings["mode"] = attrs.get(ATTR_MODE)
@ -1503,6 +1510,20 @@ class ModesTrait(_Trait):
)
return
if self.state.domain == select.DOMAIN:
option = settings["option"]
await self.hass.services.async_call(
select.DOMAIN,
select.SERVICE_SELECT_OPTION,
{
ATTR_ENTITY_ID: self.state.entity_id,
select.ATTR_OPTION: option,
},
blocking=True,
context=data.context,
)
return
if self.state.domain == humidifier.DOMAIN:
requested_mode = settings["mode"]
await self.hass.services.async_call(

View file

@ -41,6 +41,7 @@ BASE_PLATFORMS = {
"notify",
"remote",
"scene",
"select",
"sensor",
"switch",
"tts",

View file

@ -18,6 +18,7 @@ from homeassistant.components import (
media_player,
scene,
script,
select,
sensor,
switch,
vacuum,
@ -1799,6 +1800,80 @@ async def test_modes_input_select(hass):
assert calls[0].data == {"entity_id": "input_select.bla", "option": "xyz"}
async def test_modes_select(hass):
"""Test Select Mode trait."""
assert helpers.get_google_type(select.DOMAIN, None) is not None
assert trait.ModesTrait.supported(select.DOMAIN, None, None, None)
trt = trait.ModesTrait(
hass,
State("select.bla", "unavailable"),
BASIC_CONFIG,
)
assert trt.sync_attributes() == {"availableModes": []}
trt = trait.ModesTrait(
hass,
State(
"select.bla",
"abc",
attributes={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,
}
assert trt.can_execute(
trait.COMMAND_MODES,
params={"updateModeSettings": {"option": "xyz"}},
)
calls = async_mock_service(hass, select.DOMAIN, 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": "select.bla", "option": "xyz"}
async def test_modes_humidifier(hass):
"""Test Humidifier Mode trait."""
assert helpers.get_google_type(humidifier.DOMAIN, None) is not None