diff --git a/homeassistant/components/automation/webhook.py b/homeassistant/components/automation/webhook.py new file mode 100644 index 00000000000..2c9c331cdc5 --- /dev/null +++ b/homeassistant/components/automation/webhook.py @@ -0,0 +1,54 @@ +""" +Offer webhook triggered automation rules. + +For more details about this automation rule, please refer to the documentation +at https://home-assistant.io/docs/automation/trigger/#webhook-trigger +""" +from functools import partial +import logging + +from aiohttp import hdrs +import voluptuous as vol + +from homeassistant.core import callback +from homeassistant.const import CONF_PLATFORM +import homeassistant.helpers.config_validation as cv + +DEPENDENCIES = ('webhook',) + +_LOGGER = logging.getLogger(__name__) +CONF_WEBHOOK_ID = 'webhook_id' + +TRIGGER_SCHEMA = vol.Schema({ + vol.Required(CONF_PLATFORM): 'webhook', + vol.Required(CONF_WEBHOOK_ID): cv.string, +}) + + +async def _handle_webhook(action, hass, webhook_id, request): + """Handle incoming webhook.""" + result = { + 'platform': 'webhook', + 'webhook_id': webhook_id, + } + + if 'json' in request.headers.get(hdrs.CONTENT_TYPE, ''): + result['json'] = await request.json() + else: + result['data'] = await request.post() + + hass.async_run_job(action, {'trigger': result}) + + +async def async_trigger(hass, config, action): + """Trigger based on incoming webhooks.""" + webhook_id = config.get(CONF_WEBHOOK_ID) + hass.components.webhook.async_register( + webhook_id, partial(_handle_webhook, action)) + + @callback + def unregister(): + """Unregister webhook.""" + hass.components.webhook.async_unregister(webhook_id) + + return unregister diff --git a/tests/components/automation/test_webhook.py b/tests/components/automation/test_webhook.py new file mode 100644 index 00000000000..a6cde395583 --- /dev/null +++ b/tests/components/automation/test_webhook.py @@ -0,0 +1,75 @@ +"""The tests for the webhook automation trigger.""" +from homeassistant.core import callback +from homeassistant.setup import async_setup_component + + +async def test_webhook_json(hass, aiohttp_client): + """Test triggering with a JSON webhook.""" + events = [] + + @callback + def store_event(event): + """Helepr to store events.""" + events.append(event) + + hass.bus.async_listen('test_success', store_event) + + assert await async_setup_component(hass, 'automation', { + 'automation': { + 'trigger': { + 'platform': 'webhook', + 'webhook_id': 'json_webhook' + }, + 'action': { + 'event': 'test_success', + 'event_data_template': { + 'hello': 'yo {{ trigger.json.hello }}', + } + } + } + }) + + client = await aiohttp_client(hass.http.app) + + await client.post('/api/webhook/json_webhook', json={ + 'hello': 'world' + }) + + assert len(events) == 1 + assert events[0].data['hello'] == 'yo world' + + +async def test_webhook_post(hass, aiohttp_client): + """Test triggering with a POST webhook.""" + events = [] + + @callback + def store_event(event): + """Helepr to store events.""" + events.append(event) + + hass.bus.async_listen('test_success', store_event) + + assert await async_setup_component(hass, 'automation', { + 'automation': { + 'trigger': { + 'platform': 'webhook', + 'webhook_id': 'post_webhook' + }, + 'action': { + 'event': 'test_success', + 'event_data_template': { + 'hello': 'yo {{ trigger.data.hello }}', + } + } + } + }) + + client = await aiohttp_client(hass.http.app) + + await client.post('/api/webhook/post_webhook', data={ + 'hello': 'world' + }) + + assert len(events) == 1 + assert events[0].data['hello'] == 'yo world'