From 8bff8130149b9d758091325e717ac4a4f03480e1 Mon Sep 17 00:00:00 2001 From: Kane610 Date: Wed, 14 Feb 2018 01:23:04 +0100 Subject: [PATCH] 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 --- .../components/binary_sensor/deconz.py | 6 ++++-- homeassistant/components/deconz/__init__.py | 21 ++++++++++++++++--- homeassistant/components/deconz/services.yaml | 7 +++++-- homeassistant/components/light/deconz.py | 10 ++++----- homeassistant/components/scene/deconz.py | 10 +++++++-- homeassistant/components/sensor/deconz.py | 7 +++++-- requirements_all.txt | 2 +- 7 files changed, 46 insertions(+), 17 deletions(-) diff --git a/homeassistant/components/binary_sensor/deconz.py b/homeassistant/components/binary_sensor/deconz.py index 0d7c3e086bb..8fea7891c3d 100644 --- a/homeassistant/components/binary_sensor/deconz.py +++ b/homeassistant/components/binary_sensor/deconz.py @@ -7,7 +7,8 @@ https://home-assistant.io/components/binary_sensor.deconz/ import asyncio 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.core import callback @@ -21,7 +22,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None): return from pydeconz.sensor import DECONZ_BINARY_SENSOR - sensors = hass.data[DECONZ_DATA].sensors + sensors = hass.data[DATA_DECONZ].sensors entities = [] for key in sorted(sensors.keys(), key=int): @@ -42,6 +43,7 @@ class DeconzBinarySensor(BinarySensorDevice): def async_added_to_hass(self): """Subscribe sensors events.""" self._sensor.register_async_callback(self.async_update_callback) + self.hass.data[DATA_DECONZ_ID][self.entity_id] = self._sensor.deconz_id @callback def async_update_callback(self, reason): diff --git a/homeassistant/components/deconz/__init__.py b/homeassistant/components/deconz/__init__.py index 9d7d253c328..8435f6ef8a6 100644 --- a/homeassistant/components/deconz/__init__.py +++ b/homeassistant/components/deconz/__init__.py @@ -4,6 +4,7 @@ Support for deCONZ devices. For more details about this component, please refer to the documentation at https://home-assistant.io/components/deconz/ """ + import asyncio import logging @@ -17,11 +18,12 @@ from homeassistant.helpers import discovery from homeassistant.helpers.aiohttp_client import async_get_clientsession from homeassistant.util.json import load_json, save_json -REQUIREMENTS = ['pydeconz==27'] +REQUIREMENTS = ['pydeconz==28'] _LOGGER = logging.getLogger(__name__) DOMAIN = 'deconz' +DATA_DECONZ_ID = 'deconz_entities' CONFIG_FILE = 'deconz.conf' @@ -34,13 +36,16 @@ CONFIG_SCHEMA = vol.Schema({ }, extra=vol.ALLOW_EXTRA) SERVICE_FIELD = 'field' +SERVICE_ENTITY = 'entity' SERVICE_DATA = 'data' 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, }) + CONFIG_INSTRUCTIONS = """ Unlock your deCONZ gateway to register with Home Assistant. @@ -100,6 +105,7 @@ def async_setup_deconz(hass, config, deconz_config): return False hass.data[DOMAIN] = deconz + hass.data[DATA_DECONZ_ID] = {} for component in ['binary_sensor', 'light', 'scene', 'sensor']: 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 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 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: http://dresden-elektronik.github.io/deconz-rest-doc/rest/ """ - deconz = hass.data[DOMAIN] field = call.data.get(SERVICE_FIELD) + entity_id = call.data.get(SERVICE_ENTITY) 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) hass.services.async_register( DOMAIN, 'configure', async_configure, schema=SERVICE_SCHEMA) diff --git a/homeassistant/components/deconz/services.yaml b/homeassistant/components/deconz/services.yaml index 2e6593c6ea0..78bf7041a93 100644 --- a/homeassistant/components/deconz/services.yaml +++ b/homeassistant/components/deconz/services.yaml @@ -1,10 +1,13 @@ 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: 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' + entity: + description: Entity id representing a specific device in deCONZ. + example: 'light.rgb_light' data: description: Data is a json object with what data you want to alter. example: '{"on": true}' diff --git a/homeassistant/components/light/deconz.py b/homeassistant/components/light/deconz.py index 529917c36e2..0eef5a868b4 100644 --- a/homeassistant/components/light/deconz.py +++ b/homeassistant/components/light/deconz.py @@ -6,7 +6,8 @@ https://home-assistant.io/components/light.deconz/ """ 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 ( ATTR_BRIGHTNESS, ATTR_COLOR_TEMP, ATTR_EFFECT, ATTR_FLASH, ATTR_RGB_COLOR, 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'] -ATTR_LIGHT_GROUP = 'LightGroup' - @asyncio.coroutine 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: return - lights = hass.data[DECONZ_DATA].lights - groups = hass.data[DECONZ_DATA].groups + lights = hass.data[DATA_DECONZ].lights + groups = hass.data[DATA_DECONZ].groups entities = [] for light in lights.values(): @@ -64,6 +63,7 @@ class DeconzLight(Light): def async_added_to_hass(self): """Subscribe to lights events.""" self._light.register_async_callback(self.async_update_callback) + self.hass.data[DATA_DECONZ_ID][self.entity_id] = self._light.deconz_id @callback def async_update_callback(self, reason): diff --git a/homeassistant/components/scene/deconz.py b/homeassistant/components/scene/deconz.py index b3400c306af..db81d84c2b7 100644 --- a/homeassistant/components/scene/deconz.py +++ b/homeassistant/components/scene/deconz.py @@ -6,7 +6,8 @@ https://home-assistant.io/components/scene.deconz/ """ 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 DEPENDENCIES = ['deconz'] @@ -18,7 +19,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None): if discovery_info is None: return - scenes = hass.data[DECONZ_DATA].scenes + scenes = hass.data[DATA_DECONZ].scenes entities = [] for scene in scenes.values(): @@ -33,6 +34,11 @@ class DeconzScene(Scene): """Set up a 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 def async_activate(self): """Activate the scene.""" diff --git a/homeassistant/components/sensor/deconz.py b/homeassistant/components/sensor/deconz.py index b3adaa412ff..b60df1c6ac9 100644 --- a/homeassistant/components/sensor/deconz.py +++ b/homeassistant/components/sensor/deconz.py @@ -6,7 +6,8 @@ https://home-assistant.io/components/sensor.deconz/ """ 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.core import EventOrigin, callback from homeassistant.helpers.entity import Entity @@ -25,7 +26,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None): return from pydeconz.sensor import DECONZ_SENSOR, SWITCH as DECONZ_REMOTE - sensors = hass.data[DECONZ_DATA].sensors + sensors = hass.data[DATA_DECONZ].sensors entities = [] for key in sorted(sensors.keys(), key=int): @@ -51,6 +52,7 @@ class DeconzSensor(Entity): def async_added_to_hass(self): """Subscribe to sensors events.""" self._sensor.register_async_callback(self.async_update_callback) + self.hass.data[DATA_DECONZ_ID][self.entity_id] = self._sensor.deconz_id @callback def async_update_callback(self, reason): @@ -127,6 +129,7 @@ class DeconzBattery(Entity): def async_added_to_hass(self): """Subscribe to sensors events.""" self._device.register_async_callback(self.async_update_callback) + self.hass.data[DATA_DECONZ_ID][self.entity_id] = self._device.deconz_id @callback def async_update_callback(self, reason): diff --git a/requirements_all.txt b/requirements_all.txt index 223179374db..ab0c6be4693 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -688,7 +688,7 @@ pycsspeechtts==1.0.2 pydaikin==0.4 # homeassistant.components.deconz -pydeconz==27 +pydeconz==28 # homeassistant.components.zwave pydispatcher==2.0.5