Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
123 changes: 5 additions & 118 deletions homeassistant/components/deconz/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@
)
from homeassistant.helpers import config_validation as cv

# Loading the config flow file will register the flow
from .config_flow import get_master_gateway
from .const import CONF_BRIDGEID, CONF_MASTER_GATEWAY, DEFAULT_PORT, DOMAIN, _LOGGER
from .const import CONF_BRIDGEID, CONF_MASTER_GATEWAY, DEFAULT_PORT, DOMAIN
from .gateway import DeconzGateway
from .services import async_setup_services, async_unload_services

CONFIG_SCHEMA = vol.Schema(
{
Expand All @@ -28,28 +28,6 @@
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,
vol.Optional(CONF_BRIDGEID): str,
}
),
cv.has_at_least_one_key(SERVICE_ENTITY, SERVICE_FIELD),
)

SERVICE_DEVICE_REFRESH = "device_refresh"

SERVICE_DEVICE_REFRESCH_SCHEMA = vol.All(vol.Schema({vol.Optional(CONF_BRIDGEID): str}))


async def async_setup(hass, config):
"""Load configuration for deCONZ component.
Expand Down Expand Up @@ -89,100 +67,10 @@ async def async_setup_entry(hass, config_entry):

await gateway.async_update_device_registry()

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[SERVICE_DATA]

gateway = get_master_gateway(hass)
if CONF_BRIDGEID in call.data:
gateway = hass.data[DOMAIN][call.data[CONF_BRIDGEID]]

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 = get_master_gateway(hass)
if CONF_BRIDGEID in call.data:
gateway = hass.data[DOMAIN][call.data[CONF_BRIDGEID]]

groups = set(gateway.api.groups.keys())
lights = set(gateway.api.lights.keys())
scenes = set(gateway.api.scenes.keys())
sensors = set(gateway.api.sensors.keys())

await gateway.api.async_load_parameters()

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,
schema=SERVICE_DEVICE_REFRESCH_SCHEMA,
)
await async_setup_services(hass)

hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, gateway.shutdown)

return True


Expand All @@ -191,8 +79,7 @@ async def async_unload_entry(hass, config_entry):
gateway = hass.data[DOMAIN].pop(config_entry.data[CONF_BRIDGEID])

if not hass.data[DOMAIN]:
hass.services.async_remove(DOMAIN, SERVICE_DECONZ)
hass.services.async_remove(DOMAIN, SERVICE_DEVICE_REFRESH)
await async_unload_services(hass)

elif gateway.master:
await async_update_master_gateway(hass, config_entry)
Expand Down
157 changes: 157 additions & 0 deletions homeassistant/components/deconz/services.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
"""deCONZ services."""
import voluptuous as vol

from homeassistant.helpers import config_validation as cv

from .config_flow import get_master_gateway
from .const import CONF_BRIDGEID, DOMAIN, _LOGGER

DECONZ_SERVICES = "deconz_services"

SERVICE_FIELD = "field"
SERVICE_ENTITY = "entity"
SERVICE_DATA = "data"

SERVICE_CONFIGURE_DEVICE = "configure"
SERVICE_CONFIGURE_DEVICE_SCHEMA = vol.All(
vol.Schema(
{
vol.Optional(SERVICE_ENTITY): cv.entity_id,
vol.Optional(SERVICE_FIELD): cv.matches_regex("/.*"),
vol.Required(SERVICE_DATA): dict,
vol.Optional(CONF_BRIDGEID): str,
}
),
cv.has_at_least_one_key(SERVICE_ENTITY, SERVICE_FIELD),
)

SERVICE_DEVICE_REFRESH = "device_refresh"
SERVICE_DEVICE_REFRESH_SCHEMA = vol.All(vol.Schema({vol.Optional(CONF_BRIDGEID): str}))


async def async_setup_services(hass):
"""Set up services for deCONZ integration."""
if hass.data.get(DECONZ_SERVICES, False):
return

hass.data[DECONZ_SERVICES] = True

async def async_call_deconz_service(service_call):
"""Call correct deCONZ service."""
service = service_call.service
service_data = service_call.data

if service == SERVICE_CONFIGURE_DEVICE:
await async_configure_service(hass, service_data)

elif service == SERVICE_DEVICE_REFRESH:
await async_refresh_devices_service(hass, service_data)

hass.services.async_register(
DOMAIN,
SERVICE_CONFIGURE_DEVICE,
async_call_deconz_service,
schema=SERVICE_CONFIGURE_DEVICE_SCHEMA,
)

hass.services.async_register(
DOMAIN,
SERVICE_DEVICE_REFRESH,
async_call_deconz_service,
schema=SERVICE_DEVICE_REFRESH_SCHEMA,
)


async def async_unload_services(hass):
"""Unload deCONZ services."""
if not hass.data.get(DECONZ_SERVICES):
return

hass.data[DECONZ_SERVICES] = False

hass.services.async_remove(DOMAIN, SERVICE_CONFIGURE_DEVICE)
hass.services.async_remove(DOMAIN, SERVICE_DEVICE_REFRESH)


async def async_configure_service(hass, data):
"""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 = data.get(SERVICE_FIELD, "")
entity_id = data.get(SERVICE_ENTITY)
data = data[SERVICE_DATA]

gateway = get_master_gateway(hass)
if CONF_BRIDGEID in data:
gateway = hass.data[DOMAIN][data[CONF_BRIDGEID]]

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)


async def async_refresh_devices_service(hass, data):
"""Refresh available devices from deCONZ."""
gateway = get_master_gateway(hass)
if CONF_BRIDGEID in data:
gateway = hass.data[DOMAIN][data[CONF_BRIDGEID]]

groups = set(gateway.api.groups.keys())
lights = set(gateway.api.lights.keys())
scenes = set(gateway.api.scenes.keys())
sensors = set(gateway.api.sensors.keys())

await gateway.api.async_load_parameters()

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
],
)