diff --git a/homeassistant/components/google_assistant/const.py b/homeassistant/components/google_assistant/const.py index 3294ff54c2e..2e43e20f124 100644 --- a/homeassistant/components/google_assistant/const.py +++ b/homeassistant/components/google_assistant/const.py @@ -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 = { diff --git a/homeassistant/components/google_assistant/trait.py b/homeassistant/components/google_assistant/trait.py index d7cd55b7f80..0c547f18741 100644 --- a/homeassistant/components/google_assistant/trait.py +++ b/homeassistant/components/google_assistant/trait.py @@ -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( diff --git a/homeassistant/setup.py b/homeassistant/setup.py index f5a6f9b9721..9b0c5282108 100644 --- a/homeassistant/setup.py +++ b/homeassistant/setup.py @@ -41,6 +41,7 @@ BASE_PLATFORMS = { "notify", "remote", "scene", + "select", "sensor", "switch", "tts", diff --git a/tests/components/google_assistant/test_trait.py b/tests/components/google_assistant/test_trait.py index 46d81443a05..e2821d207d5 100644 --- a/tests/components/google_assistant/test_trait.py +++ b/tests/components/google_assistant/test_trait.py @@ -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