Add SmartThings button support via events (#20707)

* Add event support for buttons

* binary_sensor test clean-up
This commit is contained in:
Andrew Sayre 2019-02-03 00:08:37 -06:00 committed by Paulus Schoutsen
parent 3553d26f6b
commit 38ea43b678
5 changed files with 82 additions and 19 deletions

View file

@ -19,7 +19,7 @@ from homeassistant.helpers.typing import ConfigType, HomeAssistantType
from .config_flow import SmartThingsFlowHandler # noqa
from .const import (
CONF_APP_ID, CONF_INSTALLED_APP_ID, DATA_BROKERS, DATA_MANAGER, DOMAIN,
SIGNAL_SMARTTHINGS_UPDATE, SUPPORTED_PLATFORMS)
EVENT_BUTTON, SIGNAL_SMARTTHINGS_UPDATE, SUPPORTED_PLATFORMS)
from .smartapp import (
setup_smartapp, setup_smartapp_endpoint, validate_installed_app)
@ -154,6 +154,19 @@ class DeviceBroker:
continue
device.status.apply_attribute_update(
evt.component_id, evt.capability, evt.attribute, evt.value)
# Fire events for buttons
if evt.capability == 'button' and evt.attribute == 'button':
data = {
'component_id': evt.component_id,
'device_id': evt.device_id,
'location_id': evt.location_id,
'value': evt.value,
'name': device.label
}
self._hass.bus.async_fire(EVENT_BUTTON, data)
_LOGGER.debug("Fired button event: %s", data)
updated_devices.add(device.device_id)
_LOGGER.debug("Update received with %s events and updated %s devices",
len(req.events), len(updated_devices))

View file

@ -12,6 +12,7 @@ CONF_LOCATION_ID = 'location_id'
DATA_MANAGER = 'manager'
DATA_BROKERS = 'brokers'
DOMAIN = 'smartthings'
EVENT_BUTTON = "smartthings.button"
SIGNAL_SMARTTHINGS_UPDATE = 'smartthings_update'
SIGNAL_SMARTAPP_PREFIX = 'smartthings_smartap_'
SETTINGS_INSTANCE_ID = "hassInstanceId"
@ -25,6 +26,7 @@ SUPPORTED_PLATFORMS = [
]
SUPPORTED_CAPABILITIES = [
'accelerationSensor',
'button',
'colorControl',
'colorTemperature',
'contactSensor',

View file

@ -254,14 +254,16 @@ def device_factory_fixture():
@pytest.fixture(name="event_factory")
def event_factory_fixture():
"""Fixture for creating mock devices."""
def _factory(device_id, event_type="DEVICE_EVENT"):
def _factory(device_id, event_type="DEVICE_EVENT", capability='',
attribute='Updated', value='Value'):
event = Mock()
event.event_type = event_type
event.device_id = device_id
event.component_id = 'main'
event.capability = ''
event.attribute = 'Updated'
event.value = 'Value'
event.capability = capability
event.attribute = attribute
event.value = value
event.location_id = str(uuid4())
return event
return _factory
@ -269,11 +271,15 @@ def event_factory_fixture():
@pytest.fixture(name="event_request_factory")
def event_request_factory_fixture(event_factory):
"""Fixture for creating mock smartapp event requests."""
def _factory(device_ids):
def _factory(device_ids=None, events=None):
request = Mock()
request.installed_app_id = uuid4()
request.events = [event_factory(id) for id in device_ids]
request.events.append(event_factory(uuid4()))
request.events.append(event_factory(device_ids[0], event_type="OTHER"))
if events is None:
events = []
if device_ids:
events.extend([event_factory(id) for id in device_ids])
events.append(event_factory(uuid4()))
events.append(event_factory(device_ids[0], event_type="OTHER"))
request.events = events
return request
return _factory

View file

@ -6,9 +6,10 @@ real HTTP calls are not initiated during testing.
"""
from pysmartthings import Attribute, Capability
from homeassistant.components.binary_sensor import DEVICE_CLASSES
from homeassistant.components.smartthings import DeviceBroker, binary_sensor
from homeassistant.components.smartthings.const import (
DATA_BROKERS, DOMAIN, SIGNAL_SMARTTHINGS_UPDATE)
DATA_BROKERS, DOMAIN, SIGNAL_SMARTTHINGS_UPDATE, SUPPORTED_CAPABILITIES)
from homeassistant.config_entries import (
CONN_CLASS_CLOUD_PUSH, SOURCE_USER, ConfigEntry)
from homeassistant.const import ATTR_FRIENDLY_NAME
@ -32,6 +33,18 @@ async def _setup_platform(hass, *devices):
return config_entry
async def test_mapping_integrity():
"""Test ensures the map dicts have proper integrity."""
# Ensure every CAPABILITY_TO_ATTRIB key is in SUPPORTED_CAPABILITIES
# Ensure every CAPABILITY_TO_ATTRIB value is in ATTRIB_TO_CLASS keys
for capability, attrib in binary_sensor.CAPABILITY_TO_ATTRIB.items():
assert capability in SUPPORTED_CAPABILITIES, capability
assert attrib in binary_sensor.ATTRIB_TO_CLASS.keys(), attrib
# Ensure every ATTRIB_TO_CLASS value is in DEVICE_CLASSES
for device_class in binary_sensor.ATTRIB_TO_CLASS.values():
assert device_class in DEVICE_CLASSES
async def test_async_setup_platform():
"""Test setup platform does nothing (it uses config entries)."""
await binary_sensor.async_setup_platform(None, None, None)
@ -58,15 +71,15 @@ async def test_entity_and_device_attributes(hass, device_factory):
# Act
await _setup_platform(hass, device)
# Assert
entity = entity_registry.async_get('binary_sensor.motion_sensor_1_motion')
assert entity
assert entity.unique_id == device.device_id + '.' + Attribute.motion
device_entry = device_registry.async_get_device(
entry = entity_registry.async_get('binary_sensor.motion_sensor_1_motion')
assert entry
assert entry.unique_id == device.device_id + '.' + Attribute.motion
entry = device_registry.async_get_device(
{(DOMAIN, device.device_id)}, [])
assert device_entry
assert device_entry.name == device.label
assert device_entry.model == device.device_type_name
assert device_entry.manufacturer == 'Unavailable'
assert entry
assert entry.name == device.label
assert entry.model == device.device_type_name
assert entry.manufacturer == 'Unavailable'
async def test_update_from_signal(hass, device_factory):

View file

@ -8,7 +8,8 @@ import pytest
from homeassistant.components import smartthings
from homeassistant.components.smartthings.const import (
DATA_BROKERS, DOMAIN, SIGNAL_SMARTTHINGS_UPDATE, SUPPORTED_PLATFORMS)
DATA_BROKERS, DOMAIN, EVENT_BUTTON, SIGNAL_SMARTTHINGS_UPDATE,
SUPPORTED_PLATFORMS)
from homeassistant.exceptions import ConfigEntryNotReady
from homeassistant.helpers.dispatcher import async_dispatcher_connect
@ -181,3 +182,31 @@ async def test_event_handler_ignores_other_installed_app(
await hass.async_block_till_done()
assert not called
async def test_event_handler_fires_button_events(
hass, device_factory, event_factory, event_request_factory):
"""Test the event handler fires button events."""
device = device_factory('Button 1', ['button'])
event = event_factory(device.device_id, capability='button',
attribute='button', value='pushed')
request = event_request_factory(events=[event])
called = False
def handler(evt):
nonlocal called
called = True
assert evt.data == {
'component_id': 'main',
'device_id': device.device_id,
'location_id': event.location_id,
'value': 'pushed',
'name': device.label
}
hass.bus.async_listen(EVENT_BUTTON, handler)
broker = smartthings.DeviceBroker(
hass, [device], request.installed_app_id)
await broker.event_handler(request, None, None)
await hass.async_block_till_done()
assert called