diff --git a/homeassistant/components/google_assistant/const.py b/homeassistant/components/google_assistant/const.py index 12888ea2cf690..7dafc112aa025 100644 --- a/homeassistant/components/google_assistant/const.py +++ b/homeassistant/components/google_assistant/const.py @@ -27,6 +27,7 @@ TYPE_SWITCH = PREFIX_TYPES + 'SWITCH' TYPE_SCENE = PREFIX_TYPES + 'SCENE' TYPE_THERMOSTAT = PREFIX_TYPES + 'THERMOSTAT' +TYPE_VACUUM = PREFIX_TYPES + 'VACUUM' SERVICE_REQUEST_SYNC = 'request_sync' HOMEGRAPH_URL = 'https://homegraph.googleapis.com/' diff --git a/homeassistant/components/google_assistant/smart_home.py b/homeassistant/components/google_assistant/smart_home.py index 927139a483e0a..c922acb91c46d 100644 --- a/homeassistant/components/google_assistant/smart_home.py +++ b/homeassistant/components/google_assistant/smart_home.py @@ -19,12 +19,13 @@ scene, script, switch, + vacuum, ) from . import trait from .const import ( TYPE_LIGHT, TYPE_SCENE, TYPE_SWITCH, TYPE_THERMOSTAT, - CONF_ALIASES, CONF_ROOM_HINT, + TYPE_VACUUM, CONF_ALIASES, CONF_ROOM_HINT, ERR_NOT_SUPPORTED, ERR_PROTOCOL_ERROR, ERR_DEVICE_OFFLINE, ERR_UNKNOWN_ERROR ) @@ -44,6 +45,7 @@ scene.DOMAIN: TYPE_SCENE, script.DOMAIN: TYPE_SCENE, switch.DOMAIN: TYPE_SWITCH, + vacuum.DOMAIN: TYPE_VACUUM, } diff --git a/homeassistant/components/google_assistant/trait.py b/homeassistant/components/google_assistant/trait.py index 2f60f226042bb..088a58c9df770 100644 --- a/homeassistant/components/google_assistant/trait.py +++ b/homeassistant/components/google_assistant/trait.py @@ -11,10 +11,12 @@ scene, script, switch, + vacuum, ) from homeassistant.const import ( ATTR_ENTITY_ID, ATTR_UNIT_OF_MEASUREMENT, + ATTR_SUPPORTED_FEATURES, SERVICE_TURN_OFF, SERVICE_TURN_ON, STATE_OFF, @@ -33,6 +35,8 @@ TRAIT_COLOR_TEMP = PREFIX_TRAITS + 'ColorTemperature' TRAIT_SCENE = PREFIX_TRAITS + 'Scene' TRAIT_TEMPERATURE_SETTING = PREFIX_TRAITS + 'TemperatureSetting' +TRAIT_STARTSTOP = PREFIX_TRAITS + 'StartStop' +TRAIT_DOCK = PREFIX_TRAITS + 'Dock' PREFIX_COMMANDS = 'action.devices.commands.' COMMAND_ONOFF = PREFIX_COMMANDS + 'OnOff' @@ -44,7 +48,9 @@ COMMAND_THERMOSTAT_TEMPERATURE_SET_RANGE = ( PREFIX_COMMANDS + 'ThermostatTemperatureSetRange') COMMAND_THERMOSTAT_SET_MODE = PREFIX_COMMANDS + 'ThermostatSetMode' - +COMMAND_STARTSTOP = PREFIX_COMMANDS + 'StartStop' +COMMAND_PAUSEUNPAUSE = PREFIX_COMMANDS + 'PauseUnpause' +COMMAND_DOCK = PREFIX_COMMANDS + 'Dock' TRAITS = [] @@ -520,3 +526,126 @@ async def execute(self, hass, command, params): climate.ATTR_OPERATION_MODE: self.google_to_hass[params['thermostatMode']], }, blocking=True) + + +@register_trait +class StartStopTrait(_Trait): + """Trait to offer start, stop, and pause functionality. + + https://developers.google.com/actions/smarthome/traits/startstop + """ + + name = TRAIT_STARTSTOP + commands = [ + COMMAND_STARTSTOP, + COMMAND_PAUSEUNPAUSE + ] + + @staticmethod + def supported(domain, features): + """Test if state is supported.""" + if domain == vacuum.DOMAIN: + return features & vacuum.SUPPORT_STATE + + return False + + def sync_attributes(self): + """Return if vacuum is pausable.""" + return {'pausable': (self.state.attributes.get(ATTR_SUPPORTED_FEATURES) + & vacuum.SUPPORT_PAUSE) != 0} + + def query_attributes(self): + """Return the running/paused state.""" + domain = self.state.domain + response = {} + + if domain == vacuum.DOMAIN: + + state = self.state.state + + if state == vacuum.STATE_PAUSED: + response['isPaused'] = True + response['isRunning'] = False + elif state == vacuum.STATE_CLEANING: + response['isPaused'] = False + response['isRunning'] = True + else: + response['isPaused'] = False + response['isRunning'] = False + + return response + + async def execute(self, hass, command, params): + """Execute a start, stop, pause, or unpause command.""" + domain = self.state.domain + param_start = 'start' + param_pause = 'pause' + + if domain == vacuum.DOMAIN: + service_domain = domain + state = self.state.state + + if command == COMMAND_STARTSTOP: + if params[param_start]: + service = vacuum.SERVICE_START + else: + service = vacuum.SERVICE_STOP + + if command == COMMAND_PAUSEUNPAUSE: + if params[param_pause]: + if state == vacuum.STATE_CLEANING: + service = vacuum.SERVICE_PAUSE + else: + if state == vacuum.STATE_PAUSED: + service = vacuum.SERVICE_START + + await hass.services.async_call(service_domain, service, { + ATTR_ENTITY_ID: self.state.entity_id + }, blocking=True) + + +@register_trait +class DockTrait(_Trait): + """Trait to offer docking. + + https://developers.google.com/actions/smarthome/traits/dock + """ + + name = TRAIT_DOCK + commands = {COMMAND_DOCK} + + @staticmethod + def supported(domain, features): + """Test if state is supported.""" + if domain == vacuum.DOMAIN: + return features & vacuum.SUPPORT_STATE + + return False + + def sync_attributes(self): + """No attributes required.""" + return {} + + def query_attributes(self): + """Return if docked.""" + domain = self.state.domain + response = {} + + if domain == vacuum.DOMAIN: + state = self.state.state + + response['isDocked'] = bool(state == vacuum.STATE_DOCKED) + + return response + + async def execute(self, hass, command, params): + """Execute a return to dock command.""" + domain = self.state.domain + + if domain == vacuum.DOMAIN: + service_domain = domain + service = vacuum.SERVICE_RETURN_TO_BASE + + await hass.services.async_call(service_domain, service, { + ATTR_ENTITY_ID: self.state.entity_id + }, blocking=True)