core/homeassistant/components/deconz/__init__.py

175 lines
5.8 KiB
Python

"""
Support for deCONZ devices.
For more details about this component, please refer to the documentation at
https://home-assistant.io/components/deconz/
"""
import voluptuous as vol
from homeassistant import config_entries
from homeassistant.const import (
CONF_API_KEY, CONF_HOST, CONF_PORT, EVENT_HOMEASSISTANT_STOP)
from homeassistant.helpers import config_validation as cv
from homeassistant.helpers.device_registry import CONNECTION_NETWORK_MAC
# Loading the config flow file will register the flow
from .config_flow import configured_hosts
from .const import DEFAULT_PORT, DOMAIN, _LOGGER
from .gateway import DeconzGateway
REQUIREMENTS = ['pydeconz==47']
SUPPORTED_PLATFORMS = ['binary_sensor', 'cover',
'light', 'scene', 'sensor', 'switch']
CONFIG_SCHEMA = vol.Schema({
DOMAIN: vol.Schema({
vol.Optional(CONF_API_KEY): cv.string,
vol.Optional(CONF_HOST): cv.string,
vol.Optional(CONF_PORT, default=DEFAULT_PORT): cv.port,
})
}, extra=vol.ALLOW_EXTRA)
SERVICE_DECONZ = 'configure'
SERVICE_FIELD = 'field'
SERVICE_ENTITY = 'entity'
SERVICE_DATA = 'data'
SERVICE_SCHEMA = vol.All(vol.Schema({
vol.Optional(SERVICE_ENTITY): cv.entity_id,
vol.Optional(SERVICE_FIELD): cv.matches_regex('/.*'),
vol.Required(SERVICE_DATA): dict,
}), cv.has_at_least_one_key(SERVICE_ENTITY, SERVICE_FIELD))
SERVICE_DEVICE_REFRESH = 'device_refresh'
async def async_setup(hass, config):
"""Load configuration for deCONZ component.
Discovery has loaded the component if DOMAIN is not present in config.
"""
if DOMAIN in config:
deconz_config = None
if CONF_HOST in config[DOMAIN]:
deconz_config = config[DOMAIN]
if deconz_config and not configured_hosts(hass):
hass.async_add_job(hass.config_entries.flow.async_init(
DOMAIN,
context={'source': config_entries.SOURCE_IMPORT},
data=deconz_config
))
return True
async def async_setup_entry(hass, config_entry):
"""Set up a deCONZ bridge for a config entry.
Load config, group, light and sensor data for server information.
Start websocket for push notification of state changes from deCONZ.
"""
if DOMAIN in hass.data:
_LOGGER.error(
"Config entry failed since one deCONZ instance already exists")
return False
gateway = DeconzGateway(hass, config_entry)
hass.data[DOMAIN] = gateway
if not await gateway.async_setup():
return False
device_registry = await \
hass.helpers.device_registry.async_get_registry()
device_registry.async_get_or_create(
config_entry_id=config_entry.entry_id,
connections={(CONNECTION_NETWORK_MAC, gateway.api.config.mac)},
identifiers={(DOMAIN, gateway.api.config.bridgeid)},
manufacturer='Dresden Elektronik', model=gateway.api.config.modelid,
name=gateway.api.config.name, sw_version=gateway.api.config.swversion)
async def async_configure(call):
"""Set attribute of device in deCONZ.
Entity is used to resolve to a device path (e.g. '/lights/1').
Field is a string representing either a full path
(e.g. '/lights/1/state') when entity is not specified, or a
subpath (e.g. '/state') when used together with entity.
Data is a json object with what data you want to alter
e.g. data={'on': true}.
{
"field": "/lights/1/state",
"data": {"on": true}
}
See Dresden Elektroniks REST API documentation for details:
http://dresden-elektronik.github.io/deconz-rest-doc/rest/
"""
field = call.data.get(SERVICE_FIELD, '')
entity_id = call.data.get(SERVICE_ENTITY)
data = call.data.get(SERVICE_DATA)
gateway = hass.data[DOMAIN]
if entity_id:
try:
field = gateway.deconz_ids[entity_id] + field
except KeyError:
_LOGGER.error('Could not find the entity %s', entity_id)
return
await gateway.api.async_put_state(field, data)
hass.services.async_register(
DOMAIN, SERVICE_DECONZ, async_configure, schema=SERVICE_SCHEMA)
async def async_refresh_devices(call):
"""Refresh available devices from deCONZ."""
gateway = hass.data[DOMAIN]
groups = set(gateway.api.groups.keys())
lights = set(gateway.api.lights.keys())
scenes = set(gateway.api.scenes.keys())
sensors = set(gateway.api.sensors.keys())
if not await gateway.api.async_load_parameters():
return
gateway.async_add_device_callback(
'group', [group
for group_id, group in gateway.api.groups.items()
if group_id not in groups]
)
gateway.async_add_device_callback(
'light', [light
for light_id, light in gateway.api.lights.items()
if light_id not in lights]
)
gateway.async_add_device_callback(
'scene', [scene
for scene_id, scene in gateway.api.scenes.items()
if scene_id not in scenes]
)
gateway.async_add_device_callback(
'sensor', [sensor
for sensor_id, sensor in gateway.api.sensors.items()
if sensor_id not in sensors]
)
hass.services.async_register(
DOMAIN, SERVICE_DEVICE_REFRESH, async_refresh_devices)
hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, gateway.shutdown)
return True
async def async_unload_entry(hass, config_entry):
"""Unload deCONZ config entry."""
gateway = hass.data.pop(DOMAIN)
hass.services.async_remove(DOMAIN, SERVICE_DECONZ)
hass.services.async_remove(DOMAIN, SERVICE_DEVICE_REFRESH)
return await gateway.async_reset()