Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add websock command to query device for triggers #24044

Merged
merged 11 commits into from
Jun 10, 2019
2 changes: 2 additions & 0 deletions homeassistant/components/automation/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,8 @@ async def async_setup(hass, config):
"""Set up the automation."""
component = EntityComponent(_LOGGER, DOMAIN, hass,
group_name=GROUP_NAME_ALL_AUTOMATIONS)
device_automation = importlib.import_module('.device_automation', __name__)
emontnemery marked this conversation as resolved.
Show resolved Hide resolved
await device_automation.async_setup(hass)

await _async_process_config(hass, config, component)

Expand Down
73 changes: 73 additions & 0 deletions homeassistant/components/automation/device_automation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
"""Helpers for device automations."""
import importlib
import logging

import voluptuous as vol

from homeassistant.components import websocket_api
from homeassistant.core import split_entity_id
from homeassistant.helpers.entity_registry import async_entries_for_device

_LOGGER = logging.getLogger(__name__)


def _is_domain(entity, domain):
return split_entity_id(entity.entity_id)[0] == domain


async def async_setup(hass):
"""Set up device automation."""
hass.components.websocket_api.async_register_command(
websocket_device_automation_list_triggers)
return True


async def async_get_device_automation_triggers(hass, device_id):
"""List device triggers."""
device_registry = await hass.helpers.device_registry.async_get_registry()
entity_registry = await hass.helpers.entity_registry.async_get_registry()

domains = set()
triggers = []
device = device_registry.async_get(device_id)
for entry_id in device.config_entries:
config_entry = hass.config_entries.async_get_entry(entry_id)
domains.add(config_entry.domain)

entities = async_entries_for_device(entity_registry, device_id)
for entity in entities:
domains.add(split_entity_id(entity.entity_id)[0])

for domain in domains:
module = None
try:
module = importlib.import_module(
emontnemery marked this conversation as resolved.
Show resolved Hide resolved
'...{}.device_automation'.format(domain), __name__)
except ImportError:
_LOGGER.exception("Invalid domain %s", '...{}'.format(domain))
continue

if hasattr(module, 'DOMAIN_TRIGGERS'):
emontnemery marked this conversation as resolved.
Show resolved Hide resolved
pass
if hasattr(module, 'ENTITY_TRIGGERS'):
emontnemery marked this conversation as resolved.
Show resolved Hide resolved
# Generate trigger for each matching entity
domain_entities = [x for x in entities if _is_domain(x, domain)]
for entity in domain_entities:
for trigger in module.ENTITY_TRIGGERS:
emontnemery marked this conversation as resolved.
Show resolved Hide resolved
trigger = dict(trigger)
trigger.update(entity_id=entity.entity_id)
triggers.append(trigger)

return triggers


@websocket_api.async_response
@websocket_api.websocket_command({
vol.Required('type'): 'automation/device_automation/list_triggers',
vol.Required('device_id'): str,
})
async def websocket_device_automation_list_triggers(hass, connection, msg):
"""Handle request for device triggers."""
device_id = msg['device_id']
triggers = await async_get_device_automation_triggers(hass, device_id)
connection.send_result(msg['id'], {'triggers':triggers})
42 changes: 42 additions & 0 deletions homeassistant/components/light/device_automation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
"""Provides device automations for lights."""
import voluptuous as vol

import homeassistant.components.automation.state as state
from homeassistant.const import CONF_ENTITY_ID, CONF_PLATFORM, CONF_TYPE
import homeassistant.helpers.config_validation as cv
from . import DOMAIN

ENTITY_TRIGGERS = [
{
# Trigger when light is turned on
CONF_PLATFORM: '.{}.device_automation'.format(DOMAIN),
emontnemery marked this conversation as resolved.
Show resolved Hide resolved
CONF_TYPE: 'turn_on',
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's create constants for turn_on and turn_off

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

},
{
# Trigger when light is turned off
CONF_PLATFORM: '.{}.device_automation'.format(DOMAIN),
CONF_TYPE: 'turn_off',
},
]

TRIGGER_SCHEMA = vol.All(vol.Schema({
vol.Required(CONF_PLATFORM): '.{}.device_automation'.format(DOMAIN),
vol.Required(CONF_ENTITY_ID): cv.entity_ids,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be single?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

vol.Required(CONF_TYPE): str,
}))


async def async_trigger(hass, config, action, automation_info):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Name it async_attach_trigger. What is config vs automation_info ? Shouldn't we just have hass, trigger_config, action ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, but I leave it for now so the new trigger can be tested without any changes to the existing automation framework.

"""Listen for state changes based on configuration."""
trigger_type = config.get(CONF_TYPE)
if trigger_type == 'turn_on':
to_state = 'on'
else:
to_state = 'off'
state_config = {
state.CONF_ENTITY_ID: config[CONF_ENTITY_ID],
state.CONF_TO: to_state
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Include a FROM or else a color update will trigger it too.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed.


return await state.async_trigger(hass, state_config, action,
automation_info)