Add SmartThings button support via events (#20707)
* Add event support for buttons * binary_sensor test clean-up
This commit is contained in:
parent
3553d26f6b
commit
38ea43b678
5 changed files with 82 additions and 19 deletions
|
@ -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))
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Reference in a new issue