Webhook names (#18206)
* Add new automation_info param to async_trigger * Add domain and name to webhook registration and add WS command
This commit is contained in:
parent
6e4ce35a69
commit
2e9132873a
20 changed files with 119 additions and 54 deletions
|
@ -400,6 +400,9 @@ async def _async_process_trigger(hass, config, trigger_configs, name, action):
|
||||||
This method is a coroutine.
|
This method is a coroutine.
|
||||||
"""
|
"""
|
||||||
removes = []
|
removes = []
|
||||||
|
info = {
|
||||||
|
'name': name
|
||||||
|
}
|
||||||
|
|
||||||
for conf in trigger_configs:
|
for conf in trigger_configs:
|
||||||
platform = await async_prepare_setup_platform(
|
platform = await async_prepare_setup_platform(
|
||||||
|
@ -408,7 +411,7 @@ async def _async_process_trigger(hass, config, trigger_configs, name, action):
|
||||||
if platform is None:
|
if platform is None:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
remove = await platform.async_trigger(hass, conf, action)
|
remove = await platform.async_trigger(hass, conf, action, info)
|
||||||
|
|
||||||
if not remove:
|
if not remove:
|
||||||
_LOGGER.error("Error setting up trigger %s", name)
|
_LOGGER.error("Error setting up trigger %s", name)
|
||||||
|
|
|
@ -24,7 +24,7 @@ TRIGGER_SCHEMA = vol.Schema({
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
async def async_trigger(hass, config, action):
|
async def async_trigger(hass, config, action, automation_info):
|
||||||
"""Listen for events based on configuration."""
|
"""Listen for events based on configuration."""
|
||||||
event_type = config.get(CONF_EVENT_TYPE)
|
event_type = config.get(CONF_EVENT_TYPE)
|
||||||
event_data_schema = vol.Schema(
|
event_data_schema = vol.Schema(
|
||||||
|
|
|
@ -33,7 +33,7 @@ def source_match(state, source):
|
||||||
return state and state.attributes.get('source') == source
|
return state and state.attributes.get('source') == source
|
||||||
|
|
||||||
|
|
||||||
async def async_trigger(hass, config, action):
|
async def async_trigger(hass, config, action, automation_info):
|
||||||
"""Listen for state changes based on configuration."""
|
"""Listen for state changes based on configuration."""
|
||||||
source = config.get(CONF_SOURCE).lower()
|
source = config.get(CONF_SOURCE).lower()
|
||||||
zone_entity_id = config.get(CONF_ZONE)
|
zone_entity_id = config.get(CONF_ZONE)
|
||||||
|
|
|
@ -22,7 +22,7 @@ TRIGGER_SCHEMA = vol.Schema({
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
async def async_trigger(hass, config, action):
|
async def async_trigger(hass, config, action, automation_info):
|
||||||
"""Listen for events based on configuration."""
|
"""Listen for events based on configuration."""
|
||||||
event = config.get(CONF_EVENT)
|
event = config.get(CONF_EVENT)
|
||||||
|
|
||||||
|
|
|
@ -32,7 +32,7 @@ TRIGGER_SCHEMA = vol.Schema({
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
async def async_trigger(hass, config, action):
|
async def async_trigger(hass, config, action, automation_info):
|
||||||
"""Listen for events based on configuration."""
|
"""Listen for events based on configuration."""
|
||||||
number = config.get(CONF_NUMBER)
|
number = config.get(CONF_NUMBER)
|
||||||
held_more_than = config.get(CONF_HELD_MORE_THAN)
|
held_more_than = config.get(CONF_HELD_MORE_THAN)
|
||||||
|
|
|
@ -24,7 +24,7 @@ TRIGGER_SCHEMA = vol.Schema({
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
async def async_trigger(hass, config, action):
|
async def async_trigger(hass, config, action, automation_info):
|
||||||
"""Listen for state changes based on configuration."""
|
"""Listen for state changes based on configuration."""
|
||||||
topic = config.get(CONF_TOPIC)
|
topic = config.get(CONF_TOPIC)
|
||||||
payload = config.get(CONF_PAYLOAD)
|
payload = config.get(CONF_PAYLOAD)
|
||||||
|
|
|
@ -28,7 +28,7 @@ TRIGGER_SCHEMA = vol.All(vol.Schema({
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
async def async_trigger(hass, config, action):
|
async def async_trigger(hass, config, action, automation_info):
|
||||||
"""Listen for state changes based on configuration."""
|
"""Listen for state changes based on configuration."""
|
||||||
entity_id = config.get(CONF_ENTITY_ID)
|
entity_id = config.get(CONF_ENTITY_ID)
|
||||||
below = config.get(CONF_BELOW)
|
below = config.get(CONF_BELOW)
|
||||||
|
|
|
@ -26,7 +26,7 @@ TRIGGER_SCHEMA = vol.All(vol.Schema({
|
||||||
}), cv.key_dependency(CONF_FOR, CONF_TO))
|
}), cv.key_dependency(CONF_FOR, CONF_TO))
|
||||||
|
|
||||||
|
|
||||||
async def async_trigger(hass, config, action):
|
async def async_trigger(hass, config, action, automation_info):
|
||||||
"""Listen for state changes based on configuration."""
|
"""Listen for state changes based on configuration."""
|
||||||
entity_id = config.get(CONF_ENTITY_ID)
|
entity_id = config.get(CONF_ENTITY_ID)
|
||||||
from_state = config.get(CONF_FROM, MATCH_ALL)
|
from_state = config.get(CONF_FROM, MATCH_ALL)
|
||||||
|
|
|
@ -24,7 +24,7 @@ TRIGGER_SCHEMA = vol.Schema({
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
async def async_trigger(hass, config, action):
|
async def async_trigger(hass, config, action, automation_info):
|
||||||
"""Listen for events based on configuration."""
|
"""Listen for events based on configuration."""
|
||||||
event = config.get(CONF_EVENT)
|
event = config.get(CONF_EVENT)
|
||||||
offset = config.get(CONF_OFFSET)
|
offset = config.get(CONF_OFFSET)
|
||||||
|
|
|
@ -22,7 +22,7 @@ TRIGGER_SCHEMA = IF_ACTION_SCHEMA = vol.Schema({
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
async def async_trigger(hass, config, action):
|
async def async_trigger(hass, config, action, automation_info):
|
||||||
"""Listen for state changes based on configuration."""
|
"""Listen for state changes based on configuration."""
|
||||||
value_template = config.get(CONF_VALUE_TEMPLATE)
|
value_template = config.get(CONF_VALUE_TEMPLATE)
|
||||||
value_template.hass = hass
|
value_template.hass = hass
|
||||||
|
|
|
@ -28,7 +28,7 @@ TRIGGER_SCHEMA = vol.All(vol.Schema({
|
||||||
}), cv.has_at_least_one_key(CONF_HOURS, CONF_MINUTES, CONF_SECONDS, CONF_AT))
|
}), cv.has_at_least_one_key(CONF_HOURS, CONF_MINUTES, CONF_SECONDS, CONF_AT))
|
||||||
|
|
||||||
|
|
||||||
async def async_trigger(hass, config, action):
|
async def async_trigger(hass, config, action, automation_info):
|
||||||
"""Listen for state changes based on configuration."""
|
"""Listen for state changes based on configuration."""
|
||||||
if CONF_AT in config:
|
if CONF_AT in config:
|
||||||
at_time = config.get(CONF_AT)
|
at_time = config.get(CONF_AT)
|
||||||
|
|
|
@ -14,6 +14,8 @@ from homeassistant.core import callback
|
||||||
from homeassistant.const import CONF_PLATFORM, CONF_WEBHOOK_ID
|
from homeassistant.const import CONF_PLATFORM, CONF_WEBHOOK_ID
|
||||||
import homeassistant.helpers.config_validation as cv
|
import homeassistant.helpers.config_validation as cv
|
||||||
|
|
||||||
|
from . import DOMAIN as AUTOMATION_DOMAIN
|
||||||
|
|
||||||
DEPENDENCIES = ('webhook',)
|
DEPENDENCIES = ('webhook',)
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
@ -39,10 +41,11 @@ async def _handle_webhook(action, hass, webhook_id, request):
|
||||||
hass.async_run_job(action, {'trigger': result})
|
hass.async_run_job(action, {'trigger': result})
|
||||||
|
|
||||||
|
|
||||||
async def async_trigger(hass, config, action):
|
async def async_trigger(hass, config, action, automation_info):
|
||||||
"""Trigger based on incoming webhooks."""
|
"""Trigger based on incoming webhooks."""
|
||||||
webhook_id = config.get(CONF_WEBHOOK_ID)
|
webhook_id = config.get(CONF_WEBHOOK_ID)
|
||||||
hass.components.webhook.async_register(
|
hass.components.webhook.async_register(
|
||||||
|
AUTOMATION_DOMAIN, automation_info['name'],
|
||||||
webhook_id, partial(_handle_webhook, action))
|
webhook_id, partial(_handle_webhook, action))
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
|
|
|
@ -26,7 +26,7 @@ TRIGGER_SCHEMA = vol.Schema({
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
async def async_trigger(hass, config, action):
|
async def async_trigger(hass, config, action, automation_info):
|
||||||
"""Listen for state changes based on configuration."""
|
"""Listen for state changes based on configuration."""
|
||||||
entity_id = config.get(CONF_ENTITY_ID)
|
entity_id = config.get(CONF_ENTITY_ID)
|
||||||
zone_entity_id = config.get(CONF_ZONE)
|
zone_entity_id = config.get(CONF_ZONE)
|
||||||
|
|
|
@ -76,7 +76,7 @@ async def handle_webhook(hass, webhook_id, request):
|
||||||
async def async_setup_entry(hass, entry):
|
async def async_setup_entry(hass, entry):
|
||||||
"""Configure based on config entry."""
|
"""Configure based on config entry."""
|
||||||
hass.components.webhook.async_register(
|
hass.components.webhook.async_register(
|
||||||
entry.data[CONF_WEBHOOK_ID], handle_webhook)
|
DOMAIN, 'DialogFlow', entry.data[CONF_WEBHOOK_ID], handle_webhook)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -88,7 +88,7 @@ async def handle_webhook(hass, webhook_id, request):
|
||||||
async def async_setup_entry(hass, entry):
|
async def async_setup_entry(hass, entry):
|
||||||
"""Configure based on config entry."""
|
"""Configure based on config entry."""
|
||||||
hass.components.webhook.async_register(
|
hass.components.webhook.async_register(
|
||||||
entry.data[CONF_WEBHOOK_ID], handle_webhook)
|
DOMAIN, 'IFTTT', entry.data[CONF_WEBHOOK_ID], handle_webhook)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -81,7 +81,7 @@ async def verify_webhook(hass, token=None, timestamp=None, signature=None):
|
||||||
async def async_setup_entry(hass, entry):
|
async def async_setup_entry(hass, entry):
|
||||||
"""Configure based on config entry."""
|
"""Configure based on config entry."""
|
||||||
hass.components.webhook.async_register(
|
hass.components.webhook.async_register(
|
||||||
entry.data[CONF_WEBHOOK_ID], handle_webhook)
|
DOMAIN, 'Mailgun', entry.data[CONF_WEBHOOK_ID], handle_webhook)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -56,7 +56,7 @@ async def handle_webhook(hass, webhook_id, request):
|
||||||
async def async_setup_entry(hass, entry):
|
async def async_setup_entry(hass, entry):
|
||||||
"""Configure based on config entry."""
|
"""Configure based on config entry."""
|
||||||
hass.components.webhook.async_register(
|
hass.components.webhook.async_register(
|
||||||
entry.data[CONF_WEBHOOK_ID], handle_webhook)
|
DOMAIN, 'Twilio', entry.data[CONF_WEBHOOK_ID], handle_webhook)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -6,10 +6,12 @@ https://home-assistant.io/components/webhook/
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from aiohttp.web import Response
|
from aiohttp.web import Response
|
||||||
|
import voluptuous as vol
|
||||||
|
|
||||||
from homeassistant.core import callback
|
from homeassistant.core import callback
|
||||||
from homeassistant.loader import bind_hass
|
from homeassistant.loader import bind_hass
|
||||||
from homeassistant.auth.util import generate_secret
|
from homeassistant.auth.util import generate_secret
|
||||||
|
from homeassistant.components import websocket_api
|
||||||
from homeassistant.components.http.view import HomeAssistantView
|
from homeassistant.components.http.view import HomeAssistantView
|
||||||
|
|
||||||
DOMAIN = 'webhook'
|
DOMAIN = 'webhook'
|
||||||
|
@ -17,16 +19,26 @@ DEPENDENCIES = ['http']
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
WS_TYPE_LIST = 'webhook/list'
|
||||||
|
SCHEMA_WS_LIST = websocket_api.BASE_COMMAND_MESSAGE_SCHEMA.extend({
|
||||||
|
vol.Required('type'): WS_TYPE_LIST,
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
@bind_hass
|
@bind_hass
|
||||||
def async_register(hass, webhook_id, handler):
|
def async_register(hass, domain, name, webhook_id, handler):
|
||||||
"""Register a webhook."""
|
"""Register a webhook."""
|
||||||
handlers = hass.data.setdefault(DOMAIN, {})
|
handlers = hass.data.setdefault(DOMAIN, {})
|
||||||
|
|
||||||
if webhook_id in handlers:
|
if webhook_id in handlers:
|
||||||
raise ValueError('Handler is already defined!')
|
raise ValueError('Handler is already defined!')
|
||||||
|
|
||||||
handlers[webhook_id] = handler
|
handlers[webhook_id] = {
|
||||||
|
'domain': domain,
|
||||||
|
'name': name,
|
||||||
|
'handler': handler
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
|
@ -53,6 +65,10 @@ def async_generate_url(hass, webhook_id):
|
||||||
async def async_setup(hass, config):
|
async def async_setup(hass, config):
|
||||||
"""Initialize the webhook component."""
|
"""Initialize the webhook component."""
|
||||||
hass.http.register_view(WebhookView)
|
hass.http.register_view(WebhookView)
|
||||||
|
hass.components.websocket_api.async_register_command(
|
||||||
|
WS_TYPE_LIST, websocket_list,
|
||||||
|
SCHEMA_WS_LIST
|
||||||
|
)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
@ -67,19 +83,33 @@ class WebhookView(HomeAssistantView):
|
||||||
"""Handle webhook call."""
|
"""Handle webhook call."""
|
||||||
hass = request.app['hass']
|
hass = request.app['hass']
|
||||||
handlers = hass.data.setdefault(DOMAIN, {})
|
handlers = hass.data.setdefault(DOMAIN, {})
|
||||||
handler = handlers.get(webhook_id)
|
webhook = handlers.get(webhook_id)
|
||||||
|
|
||||||
# Always respond successfully to not give away if a hook exists or not.
|
# Always respond successfully to not give away if a hook exists or not.
|
||||||
if handler is None:
|
if webhook is None:
|
||||||
_LOGGER.warning(
|
_LOGGER.warning(
|
||||||
'Received message for unregistered webhook %s', webhook_id)
|
'Received message for unregistered webhook %s', webhook_id)
|
||||||
return Response(status=200)
|
return Response(status=200)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
response = await handler(hass, webhook_id, request)
|
response = await webhook['handler'](hass, webhook_id, request)
|
||||||
if response is None:
|
if response is None:
|
||||||
response = Response(status=200)
|
response = Response(status=200)
|
||||||
return response
|
return response
|
||||||
except Exception: # pylint: disable=broad-except
|
except Exception: # pylint: disable=broad-except
|
||||||
_LOGGER.exception("Error processing webhook %s", webhook_id)
|
_LOGGER.exception("Error processing webhook %s", webhook_id)
|
||||||
return Response(status=200)
|
return Response(status=200)
|
||||||
|
|
||||||
|
|
||||||
|
@callback
|
||||||
|
def websocket_list(hass, connection, msg):
|
||||||
|
"""Return a list of webhooks."""
|
||||||
|
handlers = hass.data.setdefault(DOMAIN, {})
|
||||||
|
result = [{
|
||||||
|
'webhook_id': webhook_id,
|
||||||
|
'domain': info['domain'],
|
||||||
|
'name': info['name'],
|
||||||
|
} for webhook_id, info in handlers.items()]
|
||||||
|
|
||||||
|
connection.send_message(
|
||||||
|
websocket_api.result_message(msg['id'], result))
|
||||||
|
|
|
@ -22,7 +22,8 @@ async def test_unregistering_webhook(hass, mock_client):
|
||||||
"""Handle webhook."""
|
"""Handle webhook."""
|
||||||
hooks.append(args)
|
hooks.append(args)
|
||||||
|
|
||||||
hass.components.webhook.async_register(webhook_id, handle)
|
hass.components.webhook.async_register(
|
||||||
|
'test', "Test hook", webhook_id, handle)
|
||||||
|
|
||||||
resp = await mock_client.post('/api/webhook/{}'.format(webhook_id))
|
resp = await mock_client.post('/api/webhook/{}'.format(webhook_id))
|
||||||
assert resp.status == 200
|
assert resp.status == 200
|
||||||
|
@ -51,7 +52,7 @@ async def test_posting_webhook_nonexisting(hass, mock_client):
|
||||||
|
|
||||||
async def test_posting_webhook_invalid_json(hass, mock_client):
|
async def test_posting_webhook_invalid_json(hass, mock_client):
|
||||||
"""Test posting to a nonexisting webhook."""
|
"""Test posting to a nonexisting webhook."""
|
||||||
hass.components.webhook.async_register('hello', None)
|
hass.components.webhook.async_register('test', "Test hook", 'hello', None)
|
||||||
resp = await mock_client.post('/api/webhook/hello', data='not-json')
|
resp = await mock_client.post('/api/webhook/hello', data='not-json')
|
||||||
assert resp.status == 200
|
assert resp.status == 200
|
||||||
|
|
||||||
|
@ -65,7 +66,8 @@ async def test_posting_webhook_json(hass, mock_client):
|
||||||
"""Handle webhook."""
|
"""Handle webhook."""
|
||||||
hooks.append((args[0], args[1], await args[2].text()))
|
hooks.append((args[0], args[1], await args[2].text()))
|
||||||
|
|
||||||
hass.components.webhook.async_register(webhook_id, handle)
|
hass.components.webhook.async_register(
|
||||||
|
'test', "Test hook", webhook_id, handle)
|
||||||
|
|
||||||
resp = await mock_client.post('/api/webhook/{}'.format(webhook_id), json={
|
resp = await mock_client.post('/api/webhook/{}'.format(webhook_id), json={
|
||||||
'data': True
|
'data': True
|
||||||
|
@ -86,7 +88,8 @@ async def test_posting_webhook_no_data(hass, mock_client):
|
||||||
"""Handle webhook."""
|
"""Handle webhook."""
|
||||||
hooks.append(args)
|
hooks.append(args)
|
||||||
|
|
||||||
hass.components.webhook.async_register(webhook_id, handle)
|
hass.components.webhook.async_register(
|
||||||
|
'test', "Test hook", webhook_id, handle)
|
||||||
|
|
||||||
resp = await mock_client.post('/api/webhook/{}'.format(webhook_id))
|
resp = await mock_client.post('/api/webhook/{}'.format(webhook_id))
|
||||||
assert resp.status == 200
|
assert resp.status == 200
|
||||||
|
@ -94,3 +97,28 @@ async def test_posting_webhook_no_data(hass, mock_client):
|
||||||
assert hooks[0][0] is hass
|
assert hooks[0][0] is hass
|
||||||
assert hooks[0][1] == webhook_id
|
assert hooks[0][1] == webhook_id
|
||||||
assert await hooks[0][2].text() == ''
|
assert await hooks[0][2].text() == ''
|
||||||
|
|
||||||
|
|
||||||
|
async def test_listing_webhook(hass, hass_ws_client, hass_access_token):
|
||||||
|
"""Test unregistering a webhook."""
|
||||||
|
assert await async_setup_component(hass, 'webhook', {})
|
||||||
|
client = await hass_ws_client(hass, hass_access_token)
|
||||||
|
|
||||||
|
hass.components.webhook.async_register(
|
||||||
|
'test', "Test hook", "my-id", None)
|
||||||
|
|
||||||
|
await client.send_json({
|
||||||
|
'id': 5,
|
||||||
|
'type': 'webhook/list',
|
||||||
|
})
|
||||||
|
|
||||||
|
msg = await client.receive_json()
|
||||||
|
assert msg['id'] == 5
|
||||||
|
assert msg['success']
|
||||||
|
assert msg['result'] == [
|
||||||
|
{
|
||||||
|
'webhook_id': 'my-id',
|
||||||
|
'domain': 'test',
|
||||||
|
'name': 'Test hook'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
|
@ -7,35 +7,36 @@ from homeassistant.core import callback
|
||||||
from tests.common import MockDependency
|
from tests.common import MockDependency
|
||||||
|
|
||||||
|
|
||||||
@MockDependency('twilio', 'rest')
|
|
||||||
@MockDependency('twilio', 'twiml')
|
|
||||||
async def test_config_flow_registers_webhook(hass, aiohttp_client):
|
async def test_config_flow_registers_webhook(hass, aiohttp_client):
|
||||||
"""Test setting up Twilio and sending webhook."""
|
"""Test setting up Twilio and sending webhook."""
|
||||||
with patch('homeassistant.util.get_local_ip', return_value='example.com'):
|
with MockDependency('twilio', 'rest'), MockDependency('twilio', 'twiml'):
|
||||||
result = await hass.config_entries.flow.async_init('twilio', context={
|
with patch('homeassistant.util.get_local_ip',
|
||||||
'source': 'user'
|
return_value='example.com'):
|
||||||
|
result = await hass.config_entries.flow.async_init(
|
||||||
|
'twilio', context={
|
||||||
|
'source': 'user'
|
||||||
|
})
|
||||||
|
assert result['type'] == data_entry_flow.RESULT_TYPE_FORM, result
|
||||||
|
|
||||||
|
result = await hass.config_entries.flow.async_configure(
|
||||||
|
result['flow_id'], {})
|
||||||
|
assert result['type'] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
|
||||||
|
webhook_id = result['result'].data['webhook_id']
|
||||||
|
|
||||||
|
twilio_events = []
|
||||||
|
|
||||||
|
@callback
|
||||||
|
def handle_event(event):
|
||||||
|
"""Handle Twilio event."""
|
||||||
|
twilio_events.append(event)
|
||||||
|
|
||||||
|
hass.bus.async_listen(twilio.RECEIVED_DATA, handle_event)
|
||||||
|
|
||||||
|
client = await aiohttp_client(hass.http.app)
|
||||||
|
await client.post('/api/webhook/{}'.format(webhook_id), data={
|
||||||
|
'hello': 'twilio'
|
||||||
})
|
})
|
||||||
assert result['type'] == data_entry_flow.RESULT_TYPE_FORM, result
|
|
||||||
|
|
||||||
result = await hass.config_entries.flow.async_configure(
|
assert len(twilio_events) == 1
|
||||||
result['flow_id'], {})
|
assert twilio_events[0].data['webhook_id'] == webhook_id
|
||||||
assert result['type'] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
|
assert twilio_events[0].data['hello'] == 'twilio'
|
||||||
webhook_id = result['result'].data['webhook_id']
|
|
||||||
|
|
||||||
twilio_events = []
|
|
||||||
|
|
||||||
@callback
|
|
||||||
def handle_event(event):
|
|
||||||
"""Handle Twilio event."""
|
|
||||||
twilio_events.append(event)
|
|
||||||
|
|
||||||
hass.bus.async_listen(twilio.RECEIVED_DATA, handle_event)
|
|
||||||
|
|
||||||
client = await aiohttp_client(hass.http.app)
|
|
||||||
await client.post('/api/webhook/{}'.format(webhook_id), data={
|
|
||||||
'hello': 'twilio'
|
|
||||||
})
|
|
||||||
|
|
||||||
assert len(twilio_events) == 1
|
|
||||||
assert twilio_events[0].data['webhook_id'] == webhook_id
|
|
||||||
assert twilio_events[0].data['hello'] == 'twilio'
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue