Add support for automation config panel (#7509)
* Add support for automation config * Build fromtend * Lintpull/7294/merge
parent
d86dfb6336
commit
5d820ec188
|
@ -16,7 +16,7 @@ from homeassistant.core import CoreState
|
|||
from homeassistant import config as conf_util
|
||||
from homeassistant.const import (
|
||||
ATTR_ENTITY_ID, CONF_PLATFORM, STATE_ON, SERVICE_TURN_ON, SERVICE_TURN_OFF,
|
||||
SERVICE_TOGGLE, SERVICE_RELOAD, EVENT_HOMEASSISTANT_START)
|
||||
SERVICE_TOGGLE, SERVICE_RELOAD, EVENT_HOMEASSISTANT_START, CONF_ID)
|
||||
from homeassistant.components import logbook
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
from homeassistant.helpers import extract_domain_configs, script, condition
|
||||
|
@ -26,6 +26,7 @@ from homeassistant.helpers.restore_state import async_get_last_state
|
|||
from homeassistant.loader import get_platform
|
||||
from homeassistant.util.dt import utcnow
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
from homeassistant.components.frontend import register_built_in_panel
|
||||
|
||||
DOMAIN = 'automation'
|
||||
ENTITY_ID_FORMAT = DOMAIN + '.{}'
|
||||
|
@ -81,6 +82,7 @@ _TRIGGER_SCHEMA = vol.All(
|
|||
_CONDITION_SCHEMA = vol.All(cv.ensure_list, [cv.CONDITION_SCHEMA])
|
||||
|
||||
PLATFORM_SCHEMA = vol.Schema({
|
||||
CONF_ID: cv.string,
|
||||
CONF_ALIAS: cv.string,
|
||||
vol.Optional(CONF_INITIAL_STATE): cv.boolean,
|
||||
vol.Optional(CONF_HIDE_ENTITY, default=DEFAULT_HIDE_ENTITY): cv.boolean,
|
||||
|
@ -139,6 +141,14 @@ def reload(hass):
|
|||
hass.services.call(DOMAIN, SERVICE_RELOAD)
|
||||
|
||||
|
||||
def async_reload(hass):
|
||||
"""Reload the automation from config.
|
||||
|
||||
Returns a coroutine object.
|
||||
"""
|
||||
return hass.services.async_call(DOMAIN, SERVICE_RELOAD)
|
||||
|
||||
|
||||
@asyncio.coroutine
|
||||
def async_setup(hass, config):
|
||||
"""Set up the automation."""
|
||||
|
@ -215,15 +225,20 @@ def async_setup(hass, config):
|
|||
DOMAIN, service, turn_onoff_service_handler,
|
||||
descriptions.get(service), schema=SERVICE_SCHEMA)
|
||||
|
||||
if 'frontend' in hass.config.components:
|
||||
register_built_in_panel(hass, 'automation', 'Automations',
|
||||
'mdi:playlist-play')
|
||||
|
||||
return True
|
||||
|
||||
|
||||
class AutomationEntity(ToggleEntity):
|
||||
"""Entity to show status of entity."""
|
||||
|
||||
def __init__(self, name, async_attach_triggers, cond_func, async_action,
|
||||
hidden, initial_state):
|
||||
def __init__(self, automation_id, name, async_attach_triggers, cond_func,
|
||||
async_action, hidden, initial_state):
|
||||
"""Initialize an automation entity."""
|
||||
self._id = automation_id
|
||||
self._name = name
|
||||
self._async_attach_triggers = async_attach_triggers
|
||||
self._async_detach_triggers = None
|
||||
|
@ -346,6 +361,16 @@ class AutomationEntity(ToggleEntity):
|
|||
self.async_trigger)
|
||||
yield from self.async_update_ha_state()
|
||||
|
||||
@property
|
||||
def device_state_attributes(self):
|
||||
"""Return automation attributes."""
|
||||
if self._id is None:
|
||||
return None
|
||||
|
||||
return {
|
||||
CONF_ID: self._id
|
||||
}
|
||||
|
||||
|
||||
@asyncio.coroutine
|
||||
def _async_process_config(hass, config, component):
|
||||
|
@ -359,6 +384,7 @@ def _async_process_config(hass, config, component):
|
|||
conf = config[config_key]
|
||||
|
||||
for list_no, config_block in enumerate(conf):
|
||||
automation_id = config_block.get(CONF_ID)
|
||||
name = config_block.get(CONF_ALIAS) or "{} {}".format(config_key,
|
||||
list_no)
|
||||
|
||||
|
@ -383,8 +409,8 @@ def _async_process_config(hass, config, component):
|
|||
config_block.get(CONF_TRIGGER, []), name
|
||||
)
|
||||
entity = AutomationEntity(
|
||||
name, async_attach_triggers, cond_func, action, hidden,
|
||||
initial_state)
|
||||
automation_id, name, async_attach_triggers, cond_func, action,
|
||||
hidden, initial_state)
|
||||
|
||||
entities.append(entity)
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ import os
|
|||
import voluptuous as vol
|
||||
|
||||
from homeassistant.core import callback
|
||||
from homeassistant.const import EVENT_COMPONENT_LOADED
|
||||
from homeassistant.const import EVENT_COMPONENT_LOADED, CONF_ID
|
||||
from homeassistant.setup import (
|
||||
async_prepare_setup_platform, ATTR_COMPONENT)
|
||||
from homeassistant.components.frontend import register_built_in_panel
|
||||
|
@ -14,8 +14,8 @@ from homeassistant.util.yaml import load_yaml, dump
|
|||
|
||||
DOMAIN = 'config'
|
||||
DEPENDENCIES = ['http']
|
||||
SECTIONS = ('core', 'group', 'hassbian')
|
||||
ON_DEMAND = ('zwave', )
|
||||
SECTIONS = ('core', 'group', 'hassbian', 'automation')
|
||||
ON_DEMAND = ('zwave')
|
||||
|
||||
|
||||
@asyncio.coroutine
|
||||
|
@ -60,7 +60,7 @@ def async_setup(hass, config):
|
|||
return True
|
||||
|
||||
|
||||
class EditKeyBasedConfigView(HomeAssistantView):
|
||||
class BaseEditConfigView(HomeAssistantView):
|
||||
"""Configure a Group endpoint."""
|
||||
|
||||
def __init__(self, component, config_type, path, key_schema, data_schema,
|
||||
|
@ -73,13 +73,29 @@ class EditKeyBasedConfigView(HomeAssistantView):
|
|||
self.data_schema = data_schema
|
||||
self.post_write_hook = post_write_hook
|
||||
|
||||
def _empty_config(self):
|
||||
"""Empty config if file not found."""
|
||||
raise NotImplementedError
|
||||
|
||||
def _get_value(self, data, config_key):
|
||||
"""Get value."""
|
||||
raise NotImplementedError
|
||||
|
||||
def _write_value(self, data, config_key, new_value):
|
||||
"""Set value."""
|
||||
raise NotImplementedError
|
||||
|
||||
@asyncio.coroutine
|
||||
def get(self, request, config_key):
|
||||
"""Fetch device specific config."""
|
||||
hass = request.app['hass']
|
||||
current = yield from hass.loop.run_in_executor(
|
||||
None, _read, hass.config.path(self.path))
|
||||
return self.json(current.get(config_key, {}))
|
||||
current = yield from self.read_config(hass)
|
||||
value = self._get_value(current, config_key)
|
||||
|
||||
if value is None:
|
||||
return self.json_message('Resource not found', 404)
|
||||
|
||||
return self.json(value)
|
||||
|
||||
@asyncio.coroutine
|
||||
def post(self, request, config_key):
|
||||
|
@ -104,10 +120,10 @@ class EditKeyBasedConfigView(HomeAssistantView):
|
|||
hass = request.app['hass']
|
||||
path = hass.config.path(self.path)
|
||||
|
||||
current = yield from hass.loop.run_in_executor(None, _read, path)
|
||||
current.setdefault(config_key, {}).update(data)
|
||||
current = yield from self.read_config(hass)
|
||||
self._write_value(current, config_key, data)
|
||||
|
||||
yield from hass.loop.run_in_executor(None, _write, path, current)
|
||||
yield from hass.async_add_job(_write, path, current)
|
||||
|
||||
if self.post_write_hook is not None:
|
||||
hass.async_add_job(self.post_write_hook(hass))
|
||||
|
@ -116,13 +132,59 @@ class EditKeyBasedConfigView(HomeAssistantView):
|
|||
'result': 'ok',
|
||||
})
|
||||
|
||||
@asyncio.coroutine
|
||||
def read_config(self, hass):
|
||||
"""Read the config."""
|
||||
current = yield from hass.async_add_job(
|
||||
_read, hass.config.path(self.path))
|
||||
if not current:
|
||||
current = self._empty_config()
|
||||
return current
|
||||
|
||||
|
||||
class EditKeyBasedConfigView(BaseEditConfigView):
|
||||
"""Configure a list of entries."""
|
||||
|
||||
def _empty_config(self):
|
||||
"""Return an empty config."""
|
||||
return {}
|
||||
|
||||
def _get_value(self, data, config_key):
|
||||
"""Get value."""
|
||||
return data.get(config_key, {})
|
||||
|
||||
def _write_value(self, data, config_key, new_value):
|
||||
"""Set value."""
|
||||
data.setdefault(config_key, {}).update(new_value)
|
||||
|
||||
|
||||
class EditIdBasedConfigView(BaseEditConfigView):
|
||||
"""Configure key based config entries."""
|
||||
|
||||
def _empty_config(self):
|
||||
"""Return an empty config."""
|
||||
return []
|
||||
|
||||
def _get_value(self, data, config_key):
|
||||
"""Get value."""
|
||||
return next(
|
||||
(val for val in data if val.get(CONF_ID) == config_key), None)
|
||||
|
||||
def _write_value(self, data, config_key, new_value):
|
||||
"""Set value."""
|
||||
value = self._get_value(data, config_key)
|
||||
|
||||
if value is None:
|
||||
value = {CONF_ID: config_key}
|
||||
data.append(value)
|
||||
|
||||
value.update(new_value)
|
||||
|
||||
|
||||
def _read(path):
|
||||
"""Read YAML helper."""
|
||||
if not os.path.isfile(path):
|
||||
with open(path, 'w'):
|
||||
pass
|
||||
return {}
|
||||
return None
|
||||
|
||||
return load_yaml(path)
|
||||
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
"""Provide configuration end points for Z-Wave."""
|
||||
import asyncio
|
||||
|
||||
from homeassistant.components.config import EditIdBasedConfigView
|
||||
from homeassistant.components.automation import (
|
||||
PLATFORM_SCHEMA, DOMAIN, async_reload)
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
|
||||
|
||||
CONFIG_PATH = 'automations.yaml'
|
||||
|
||||
|
||||
@asyncio.coroutine
|
||||
def async_setup(hass):
|
||||
"""Set up the Automation config API."""
|
||||
hass.http.register_view(EditIdBasedConfigView(
|
||||
DOMAIN, 'config', CONFIG_PATH, cv.string,
|
||||
PLATFORM_SCHEMA, post_write_hook=async_reload
|
||||
))
|
||||
return True
|
|
@ -1,18 +1,19 @@
|
|||
"""DO NOT MODIFY. Auto-generated by script/fingerprint_frontend."""
|
||||
|
||||
FINGERPRINTS = {
|
||||
"compatibility.js": "83d9c77748dafa9db49ae77d7f3d8fb0",
|
||||
"core.js": "5d08475f03adb5969bd31855d5ca0cfd",
|
||||
"compatibility.js": "8e4c44b5f4288cc48ec1ba94a9bec812",
|
||||
"core.js": "8cc30e2ad9ee3df44fe7a17507099d88",
|
||||
"frontend.html": "5999c8fac69c503b846672cae75a12b0",
|
||||
"mdi.html": "f407a5a57addbe93817ee1b244d33fbe",
|
||||
"micromarkdown-js.html": "93b5ec4016f0bba585521cf4d18dec1a",
|
||||
"panels/ha-panel-automation.html": "cc6fe23a97c1974b9f4165a7692bb280",
|
||||
"panels/ha-panel-config.html": "59d9eb28758b497a4d9b2428f978b9b1",
|
||||
"panels/ha-panel-dev-event.html": "2db9c218065ef0f61d8d08db8093cad2",
|
||||
"panels/ha-panel-dev-info.html": "61610e015a411cfc84edd2c4d489e71d",
|
||||
"panels/ha-panel-dev-service.html": "415552027cb083badeff5f16080410ed",
|
||||
"panels/ha-panel-dev-state.html": "d70314913b8923d750932367b1099750",
|
||||
"panels/ha-panel-dev-template.html": "567fbf86735e1b891e40c2f4060fec9b",
|
||||
"panels/ha-panel-hassio.html": "23d175b6744c20e2fdf475b6efdaa1d3",
|
||||
"panels/ha-panel-hassio.html": "41fc94a5dc9247ed7efa112614491c71",
|
||||
"panels/ha-panel-history.html": "89062c48c76206cad1cec14ddbb1cbb1",
|
||||
"panels/ha-panel-iframe.html": "d920f0aa3c903680f2f8795e2255daab",
|
||||
"panels/ha-panel-logbook.html": "6dd6a16f52117318b202e60f98400163",
|
||||
|
|
|
@ -1 +1 @@
|
|||
!(function(){"use strict";function e(e,r){var t=arguments;if(void 0===e||null===e)throw new TypeError("Cannot convert first argument to object");for(var n=Object(e),o=1;o<arguments.length;o++){var i=t[o];if(void 0!==i&&null!==i)for(var l=Object.keys(Object(i)),a=0,c=l.length;a<c;a++){var b=l[a],f=Object.getOwnPropertyDescriptor(i,b);void 0!==f&&f.enumerable&&(n[b]=i[b])}}return n}function r(){Object.assign||Object.defineProperty(Object,"assign",{enumerable:!1,configurable:!0,writable:!0,value:e})}var t={assign:e,polyfill:r};t.polyfill()})();
|
||||
!function(){"use strict";function e(e,t){if(void 0===e||null===e)throw new TypeError("Cannot convert first argument to object");for(var r=Object(e),n=1;n<arguments.length;n++){var o=arguments[n];if(void 0!==o&&null!==o)for(var i=Object.keys(Object(o)),l=0,c=i.length;l<c;l++){var a=i[l],b=Object.getOwnPropertyDescriptor(o,a);void 0!==b&&b.enumerable&&(r[a]=o[a])}}return r}function t(){Object.assign||Object.defineProperty(Object,"assign",{enumerable:!1,configurable:!0,writable:!0,value:e})}({assign:e,polyfill:t}).polyfill()}();
|
||||
|
|
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
|
@ -1 +1 @@
|
|||
Subproject commit 9e7dc4a921f86e60cc1f14afe254e5310b63e854
|
||||
Subproject commit ca82a411aa1e875ef0fc26e34bdd2033f5b99276
|
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
|
@ -98,6 +98,7 @@ tts:
|
|||
platform: google
|
||||
|
||||
group: !include groups.yaml
|
||||
automation: !include automations.yaml
|
||||
"""
|
||||
|
||||
|
||||
|
@ -158,10 +159,13 @@ def create_default_config(config_dir, detect_location=True):
|
|||
"""
|
||||
from homeassistant.components.config.group import (
|
||||
CONFIG_PATH as GROUP_CONFIG_PATH)
|
||||
from homeassistant.components.config.automation import (
|
||||
CONFIG_PATH as AUTOMATION_CONFIG_PATH)
|
||||
|
||||
config_path = os.path.join(config_dir, YAML_CONFIG_FILE)
|
||||
version_path = os.path.join(config_dir, VERSION_FILE)
|
||||
group_yaml_path = os.path.join(config_dir, GROUP_CONFIG_PATH)
|
||||
automation_yaml_path = os.path.join(config_dir, AUTOMATION_CONFIG_PATH)
|
||||
|
||||
info = {attr: default for attr, default, _, _ in DEFAULT_CORE_CONFIG}
|
||||
|
||||
|
@ -203,6 +207,9 @@ def create_default_config(config_dir, detect_location=True):
|
|||
with open(group_yaml_path, 'w'):
|
||||
pass
|
||||
|
||||
with open(automation_yaml_path, 'wt') as fil:
|
||||
fil.write('[]')
|
||||
|
||||
return config_path
|
||||
|
||||
except IOError:
|
||||
|
|
Loading…
Reference in New Issue