diff --git a/homeassistant/components/demo/switch.py b/homeassistant/components/demo/switch.py index 04a55a591b7..e7a3b1741a2 100644 --- a/homeassistant/components/demo/switch.py +++ b/homeassistant/components/demo/switch.py @@ -14,12 +14,13 @@ def setup_platform(hass, config, add_entities_callback, discovery_info=None): class DemoSwitch(SwitchDevice): """Representation of a demo switch.""" - def __init__(self, name, state, icon, assumed): + def __init__(self, name, state, icon, assumed, device_class=None): """Initialize the Demo switch.""" self._name = name or DEVICE_DEFAULT_NAME self._state = state self._icon = icon self._assumed = assumed + self._device_class = device_class @property def should_poll(self): @@ -57,6 +58,11 @@ class DemoSwitch(SwitchDevice): """Return true if switch is on.""" return self._state + @property + def device_class(self): + """Return device of entity.""" + return self._device_class + def turn_on(self, **kwargs): """Turn the switch on.""" self._state = True diff --git a/homeassistant/components/google_assistant/const.py b/homeassistant/components/google_assistant/const.py index 585aa0027bb..477e67ab75a 100644 --- a/homeassistant/components/google_assistant/const.py +++ b/homeassistant/components/google_assistant/const.py @@ -31,6 +31,7 @@ TYPE_THERMOSTAT = PREFIX_TYPES + 'THERMOSTAT' TYPE_LOCK = PREFIX_TYPES + 'LOCK' TYPE_BLINDS = PREFIX_TYPES + 'BLINDS' TYPE_GARAGE = PREFIX_TYPES + 'GARAGE' +TYPE_OUTLET = PREFIX_TYPES + 'OUTLET' 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 59d8334cdac..ab2907cf661 100644 --- a/homeassistant/components/google_assistant/smart_home.py +++ b/homeassistant/components/google_assistant/smart_home.py @@ -32,6 +32,7 @@ from . import trait from .const import ( TYPE_LIGHT, TYPE_LOCK, TYPE_SCENE, TYPE_SWITCH, TYPE_VACUUM, TYPE_THERMOSTAT, TYPE_FAN, TYPE_CAMERA, TYPE_BLINDS, TYPE_GARAGE, + TYPE_OUTLET, CONF_ALIASES, CONF_ROOM_HINT, ERR_FUNCTION_NOT_SUPPORTED, ERR_PROTOCOL_ERROR, ERR_DEVICE_OFFLINE, ERR_UNKNOWN_ERROR, @@ -60,6 +61,8 @@ DOMAIN_TO_GOOGLE_TYPES = { DEVICE_CLASS_TO_GOOGLE_TYPES = { (cover.DOMAIN, cover.DEVICE_CLASS_GARAGE): TYPE_GARAGE, + (switch.DOMAIN, switch.DEVICE_CLASS_SWITCH): TYPE_SWITCH, + (switch.DOMAIN, switch.DEVICE_CLASS_OUTLET): TYPE_OUTLET, } diff --git a/homeassistant/components/switch/__init__.py b/homeassistant/components/switch/__init__.py index 65b2bb7b92a..e3f756abf53 100644 --- a/homeassistant/components/switch/__init__.py +++ b/homeassistant/components/switch/__init__.py @@ -33,6 +33,16 @@ PROP_TO_ATTR = { 'today_energy_kwh': ATTR_TODAY_ENERGY_KWH, } +DEVICE_CLASS_OUTLET = 'outlet' +DEVICE_CLASS_SWITCH = 'switch' + +DEVICE_CLASSES = [ + DEVICE_CLASS_OUTLET, + DEVICE_CLASS_SWITCH, +] + +DEVICE_CLASSES_SCHEMA = vol.All(vol.Lower, vol.In(DEVICE_CLASSES)) + SWITCH_SERVICE_SCHEMA = vol.Schema({ vol.Optional(ATTR_ENTITY_ID): cv.comp_entity_ids, }) @@ -113,3 +123,8 @@ class SwitchDevice(ToggleEntity): data[attr] = value return data + + @property + def device_class(self): + """Return the class of this device, from component DEVICE_CLASSES.""" + return None diff --git a/tests/components/google_assistant/test_smart_home.py b/tests/components/google_assistant/test_smart_home.py index be32d4cb5d9..24c7059d5c5 100644 --- a/tests/components/google_assistant/test_smart_home.py +++ b/tests/components/google_assistant/test_smart_home.py @@ -14,6 +14,7 @@ from homeassistant.components.google_assistant import ( const, trait, helpers, smart_home as sh, EVENT_COMMAND_RECEIVED, EVENT_QUERY_RECEIVED, EVENT_SYNC_RECEIVED) from homeassistant.components.demo.light import DemoLight +from homeassistant.components.demo.switch import DemoSwitch from homeassistant.helpers import device_registry from tests.common import (mock_device_registry, mock_registry, @@ -557,6 +558,49 @@ async def test_empty_name_doesnt_sync(hass): } +@pytest.mark.parametrize("device_class,google_type", [ + ('non_existing_class', 'action.devices.types.SWITCH'), + ('switch', 'action.devices.types.SWITCH'), + ('outlet', 'action.devices.types.OUTLET') +]) +async def test_device_class_switch(hass, device_class, google_type): + """Test that a cover entity syncs to the correct device type.""" + sensor = DemoSwitch( + 'Demo Sensor', + state=False, + icon='mdi:switch', + assumed=False, + device_class=device_class + ) + sensor.hass = hass + sensor.entity_id = 'switch.demo_sensor' + await sensor.async_update_ha_state() + + result = await sh.async_handle_message( + hass, BASIC_CONFIG, 'test-agent', + { + "requestId": REQ_ID, + "inputs": [{ + "intent": "action.devices.SYNC" + }] + }) + + assert result == { + 'requestId': REQ_ID, + 'payload': { + 'agentUserId': 'test-agent', + 'devices': [{ + 'attributes': {}, + 'id': 'switch.demo_sensor', + 'name': {'name': 'Demo Sensor'}, + 'traits': ['action.devices.traits.OnOff'], + 'type': google_type, + 'willReportState': False + }] + } + } + + async def test_query_disconnect(hass): """Test a disconnect message.""" result = await sh.async_handle_message(