Improve service by allowing to reference entity id instead of deconz id (#11862)

* Improve service by allowing to reference entity id instead of deconz id

* Change from having access to full entities to only store entity id together with deconz id

* Don't use eval, there is a dict type for voluptuous

* Use entity registry instead of keeping a local registry over entity ids

* Removed old code

* Add test for get_entry

* Bump dependency to v28
Fixed call to protected member

* Use chain to iterate over dict values

* Cleanup

* Fix hound comment

* Cleanup

* Follow refactoring of entity

* Revert to using a local registry

* Remove unused import

* self.hass is automatically available when entity is registered in hass
This commit is contained in:
Kane610 2018-02-14 01:23:04 +01:00 committed by Paulus Schoutsen
parent a4944da68f
commit 8bff813014
7 changed files with 46 additions and 17 deletions

View file

@ -7,7 +7,8 @@ https://home-assistant.io/components/binary_sensor.deconz/
import asyncio import asyncio
from homeassistant.components.binary_sensor import BinarySensorDevice from homeassistant.components.binary_sensor import BinarySensorDevice
from homeassistant.components.deconz import DOMAIN as DECONZ_DATA from homeassistant.components.deconz import (
DOMAIN as DATA_DECONZ, DATA_DECONZ_ID)
from homeassistant.const import ATTR_BATTERY_LEVEL from homeassistant.const import ATTR_BATTERY_LEVEL
from homeassistant.core import callback from homeassistant.core import callback
@ -21,7 +22,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
return return
from pydeconz.sensor import DECONZ_BINARY_SENSOR from pydeconz.sensor import DECONZ_BINARY_SENSOR
sensors = hass.data[DECONZ_DATA].sensors sensors = hass.data[DATA_DECONZ].sensors
entities = [] entities = []
for key in sorted(sensors.keys(), key=int): for key in sorted(sensors.keys(), key=int):
@ -42,6 +43,7 @@ class DeconzBinarySensor(BinarySensorDevice):
def async_added_to_hass(self): def async_added_to_hass(self):
"""Subscribe sensors events.""" """Subscribe sensors events."""
self._sensor.register_async_callback(self.async_update_callback) self._sensor.register_async_callback(self.async_update_callback)
self.hass.data[DATA_DECONZ_ID][self.entity_id] = self._sensor.deconz_id
@callback @callback
def async_update_callback(self, reason): def async_update_callback(self, reason):

View file

@ -4,6 +4,7 @@ Support for deCONZ devices.
For more details about this component, please refer to the documentation at For more details about this component, please refer to the documentation at
https://home-assistant.io/components/deconz/ https://home-assistant.io/components/deconz/
""" """
import asyncio import asyncio
import logging import logging
@ -17,11 +18,12 @@ from homeassistant.helpers import discovery
from homeassistant.helpers.aiohttp_client import async_get_clientsession from homeassistant.helpers.aiohttp_client import async_get_clientsession
from homeassistant.util.json import load_json, save_json from homeassistant.util.json import load_json, save_json
REQUIREMENTS = ['pydeconz==27'] REQUIREMENTS = ['pydeconz==28']
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
DOMAIN = 'deconz' DOMAIN = 'deconz'
DATA_DECONZ_ID = 'deconz_entities'
CONFIG_FILE = 'deconz.conf' CONFIG_FILE = 'deconz.conf'
@ -34,13 +36,16 @@ CONFIG_SCHEMA = vol.Schema({
}, extra=vol.ALLOW_EXTRA) }, extra=vol.ALLOW_EXTRA)
SERVICE_FIELD = 'field' SERVICE_FIELD = 'field'
SERVICE_ENTITY = 'entity'
SERVICE_DATA = 'data' SERVICE_DATA = 'data'
SERVICE_SCHEMA = vol.Schema({ SERVICE_SCHEMA = vol.Schema({
vol.Required(SERVICE_FIELD): cv.string, vol.Exclusive(SERVICE_FIELD, 'deconz_id'): cv.string,
vol.Exclusive(SERVICE_ENTITY, 'deconz_id'): cv.entity_id,
vol.Required(SERVICE_DATA): dict, vol.Required(SERVICE_DATA): dict,
}) })
CONFIG_INSTRUCTIONS = """ CONFIG_INSTRUCTIONS = """
Unlock your deCONZ gateway to register with Home Assistant. Unlock your deCONZ gateway to register with Home Assistant.
@ -100,6 +105,7 @@ def async_setup_deconz(hass, config, deconz_config):
return False return False
hass.data[DOMAIN] = deconz hass.data[DOMAIN] = deconz
hass.data[DATA_DECONZ_ID] = {}
for component in ['binary_sensor', 'light', 'scene', 'sensor']: for component in ['binary_sensor', 'light', 'scene', 'sensor']:
hass.async_add_job(discovery.async_load_platform( hass.async_add_job(discovery.async_load_platform(
@ -112,6 +118,7 @@ def async_setup_deconz(hass, config, deconz_config):
Field is a string representing a specific device in deCONZ Field is a string representing a specific device in deCONZ
e.g. field='/lights/1/state'. e.g. field='/lights/1/state'.
Entity_id can be used to retrieve the proper field.
Data is a json object with what data you want to alter Data is a json object with what data you want to alter
e.g. data={'on': true}. e.g. data={'on': true}.
{ {
@ -121,9 +128,17 @@ def async_setup_deconz(hass, config, deconz_config):
See Dresden Elektroniks REST API documentation for details: See Dresden Elektroniks REST API documentation for details:
http://dresden-elektronik.github.io/deconz-rest-doc/rest/ http://dresden-elektronik.github.io/deconz-rest-doc/rest/
""" """
deconz = hass.data[DOMAIN]
field = call.data.get(SERVICE_FIELD) field = call.data.get(SERVICE_FIELD)
entity_id = call.data.get(SERVICE_ENTITY)
data = call.data.get(SERVICE_DATA) data = call.data.get(SERVICE_DATA)
deconz = hass.data[DOMAIN]
if entity_id:
entities = hass.data.get(DATA_DECONZ_ID)
if entities:
field = entities.get(entity_id)
if field is None:
_LOGGER.error('Could not find the entity %s', entity_id)
return
yield from deconz.async_put_state(field, data) yield from deconz.async_put_state(field, data)
hass.services.async_register( hass.services.async_register(
DOMAIN, 'configure', async_configure, schema=SERVICE_SCHEMA) DOMAIN, 'configure', async_configure, schema=SERVICE_SCHEMA)

View file

@ -1,10 +1,13 @@
configure: configure:
description: Set attribute of device in Deconz. See Dresden Elektroniks REST API documentation for details http://dresden-elektronik.github.io/deconz-rest-doc/rest/ description: Set attribute of device in deCONZ. See https://home-assistant.io/components/deconz/#device-services for details.
fields: fields:
field: field:
description: Field is a string representing a specific device in Deconz. description: Field is a string representing a specific device in deCONZ.
example: '/lights/1/state' example: '/lights/1/state'
entity:
description: Entity id representing a specific device in deCONZ.
example: 'light.rgb_light'
data: data:
description: Data is a json object with what data you want to alter. description: Data is a json object with what data you want to alter.
example: '{"on": true}' example: '{"on": true}'

View file

@ -6,7 +6,8 @@ https://home-assistant.io/components/light.deconz/
""" """
import asyncio import asyncio
from homeassistant.components.deconz import DOMAIN as DECONZ_DATA from homeassistant.components.deconz import (
DOMAIN as DATA_DECONZ, DATA_DECONZ_ID)
from homeassistant.components.light import ( from homeassistant.components.light import (
ATTR_BRIGHTNESS, ATTR_COLOR_TEMP, ATTR_EFFECT, ATTR_FLASH, ATTR_RGB_COLOR, ATTR_BRIGHTNESS, ATTR_COLOR_TEMP, ATTR_EFFECT, ATTR_FLASH, ATTR_RGB_COLOR,
ATTR_TRANSITION, ATTR_XY_COLOR, EFFECT_COLORLOOP, FLASH_LONG, FLASH_SHORT, ATTR_TRANSITION, ATTR_XY_COLOR, EFFECT_COLORLOOP, FLASH_LONG, FLASH_SHORT,
@ -17,8 +18,6 @@ from homeassistant.util.color import color_RGB_to_xy
DEPENDENCIES = ['deconz'] DEPENDENCIES = ['deconz']
ATTR_LIGHT_GROUP = 'LightGroup'
@asyncio.coroutine @asyncio.coroutine
def async_setup_platform(hass, config, async_add_devices, discovery_info=None): def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
@ -26,8 +25,8 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
if discovery_info is None: if discovery_info is None:
return return
lights = hass.data[DECONZ_DATA].lights lights = hass.data[DATA_DECONZ].lights
groups = hass.data[DECONZ_DATA].groups groups = hass.data[DATA_DECONZ].groups
entities = [] entities = []
for light in lights.values(): for light in lights.values():
@ -64,6 +63,7 @@ class DeconzLight(Light):
def async_added_to_hass(self): def async_added_to_hass(self):
"""Subscribe to lights events.""" """Subscribe to lights events."""
self._light.register_async_callback(self.async_update_callback) self._light.register_async_callback(self.async_update_callback)
self.hass.data[DATA_DECONZ_ID][self.entity_id] = self._light.deconz_id
@callback @callback
def async_update_callback(self, reason): def async_update_callback(self, reason):

View file

@ -6,7 +6,8 @@ https://home-assistant.io/components/scene.deconz/
""" """
import asyncio import asyncio
from homeassistant.components.deconz import DOMAIN as DECONZ_DATA from homeassistant.components.deconz import (
DOMAIN as DATA_DECONZ, DATA_DECONZ_ID)
from homeassistant.components.scene import Scene from homeassistant.components.scene import Scene
DEPENDENCIES = ['deconz'] DEPENDENCIES = ['deconz']
@ -18,7 +19,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
if discovery_info is None: if discovery_info is None:
return return
scenes = hass.data[DECONZ_DATA].scenes scenes = hass.data[DATA_DECONZ].scenes
entities = [] entities = []
for scene in scenes.values(): for scene in scenes.values():
@ -33,6 +34,11 @@ class DeconzScene(Scene):
"""Set up a scene.""" """Set up a scene."""
self._scene = scene self._scene = scene
@asyncio.coroutine
def async_added_to_hass(self):
"""Subscribe to sensors events."""
self.hass.data[DATA_DECONZ_ID][self.entity_id] = self._scene.deconz_id
@asyncio.coroutine @asyncio.coroutine
def async_activate(self): def async_activate(self):
"""Activate the scene.""" """Activate the scene."""

View file

@ -6,7 +6,8 @@ https://home-assistant.io/components/sensor.deconz/
""" """
import asyncio import asyncio
from homeassistant.components.deconz import DOMAIN as DECONZ_DATA from homeassistant.components.deconz import (
DOMAIN as DATA_DECONZ, DATA_DECONZ_ID)
from homeassistant.const import ATTR_BATTERY_LEVEL, CONF_EVENT, CONF_ID from homeassistant.const import ATTR_BATTERY_LEVEL, CONF_EVENT, CONF_ID
from homeassistant.core import EventOrigin, callback from homeassistant.core import EventOrigin, callback
from homeassistant.helpers.entity import Entity from homeassistant.helpers.entity import Entity
@ -25,7 +26,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
return return
from pydeconz.sensor import DECONZ_SENSOR, SWITCH as DECONZ_REMOTE from pydeconz.sensor import DECONZ_SENSOR, SWITCH as DECONZ_REMOTE
sensors = hass.data[DECONZ_DATA].sensors sensors = hass.data[DATA_DECONZ].sensors
entities = [] entities = []
for key in sorted(sensors.keys(), key=int): for key in sorted(sensors.keys(), key=int):
@ -51,6 +52,7 @@ class DeconzSensor(Entity):
def async_added_to_hass(self): def async_added_to_hass(self):
"""Subscribe to sensors events.""" """Subscribe to sensors events."""
self._sensor.register_async_callback(self.async_update_callback) self._sensor.register_async_callback(self.async_update_callback)
self.hass.data[DATA_DECONZ_ID][self.entity_id] = self._sensor.deconz_id
@callback @callback
def async_update_callback(self, reason): def async_update_callback(self, reason):
@ -127,6 +129,7 @@ class DeconzBattery(Entity):
def async_added_to_hass(self): def async_added_to_hass(self):
"""Subscribe to sensors events.""" """Subscribe to sensors events."""
self._device.register_async_callback(self.async_update_callback) self._device.register_async_callback(self.async_update_callback)
self.hass.data[DATA_DECONZ_ID][self.entity_id] = self._device.deconz_id
@callback @callback
def async_update_callback(self, reason): def async_update_callback(self, reason):

View file

@ -688,7 +688,7 @@ pycsspeechtts==1.0.2
pydaikin==0.4 pydaikin==0.4
# homeassistant.components.deconz # homeassistant.components.deconz
pydeconz==27 pydeconz==28
# homeassistant.components.zwave # homeassistant.components.zwave
pydispatcher==2.0.5 pydispatcher==2.0.5