From 0595fc3097fd6a8efa65f51fcb90aa9c125bd290 Mon Sep 17 00:00:00 2001 From: Tom Harris Date: Sun, 7 Jul 2019 14:31:04 -0400 Subject: [PATCH] Upgrade insteonplm to 0.16.0 and add INSTEON scene triggering (#24765) * Upgrade insteonplm to 0.16.0 and add INSTEON scene triggering * Fix spacing issue * Dummy commit to trigger CLA * Remove dummy change * Code review changes * Use ENTITY_MATCH_ALL keyword from const and lint cleanup * Make entity method print_aldb private --- homeassistant/components/insteon/__init__.py | 83 ++++++++++++++----- .../components/insteon/manifest.json | 2 +- .../components/insteon/services.yaml | 14 +++- requirements_all.txt | 2 +- 4 files changed, 76 insertions(+), 25 deletions(-) diff --git a/homeassistant/components/insteon/__init__.py b/homeassistant/components/insteon/__init__.py index a1eea2fb1df..834c9bf36f2 100644 --- a/homeassistant/components/insteon/__init__.py +++ b/homeassistant/components/insteon/__init__.py @@ -7,15 +7,18 @@ import voluptuous as vol from homeassistant.const import ( CONF_ADDRESS, CONF_ENTITY_ID, CONF_HOST, CONF_PLATFORM, CONF_PORT, - EVENT_HOMEASSISTANT_STOP) + ENTITY_MATCH_ALL, EVENT_HOMEASSISTANT_STOP) from homeassistant.core import callback from homeassistant.helpers import discovery +from homeassistant.helpers.dispatcher import ( + dispatcher_send, async_dispatcher_connect) import homeassistant.helpers.config_validation as cv from homeassistant.helpers.entity import Entity _LOGGER = logging.getLogger(__name__) DOMAIN = 'insteon' +INSTEON_ENTITIES = 'entities' CONF_IP_PORT = 'ip_port' CONF_HUB_USERNAME = 'username' @@ -49,6 +52,11 @@ SRV_LOAD_DB_RELOAD = 'reload' SRV_CONTROLLER = 'controller' SRV_RESPONDER = 'responder' SRV_HOUSECODE = 'housecode' +SRV_SCENE_ON = 'scene_on' +SRV_SCENE_OFF = 'scene_off' + +SIGNAL_LOAD_ALDB = 'load_aldb' +SIGNAL_PRINT_ALDB = 'print_aldb' HOUSECODES = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p'] @@ -84,6 +92,7 @@ CONF_DEVICE_OVERRIDE_SCHEMA = vol.All( vol.Optional(CONF_PLATFORM): cv.string, })) + CONF_X10_SCHEMA = vol.All( vol.Schema({ vol.Required(CONF_HOUSECODE): cv.string, @@ -92,6 +101,7 @@ CONF_X10_SCHEMA = vol.All( vol.Optional(CONF_DIM_STEPS): vol.Range(min=2, max=255) })) + CONFIG_SCHEMA = vol.Schema({ DOMAIN: vol.All( vol.Schema( @@ -121,23 +131,32 @@ ADD_ALL_LINK_SCHEMA = vol.Schema({ vol.Required(SRV_ALL_LINK_MODE): vol.In([SRV_CONTROLLER, SRV_RESPONDER]), }) + DEL_ALL_LINK_SCHEMA = vol.Schema({ vol.Required(SRV_ALL_LINK_GROUP): vol.Range(min=0, max=255), }) + LOAD_ALDB_SCHEMA = vol.Schema({ - vol.Required(CONF_ENTITY_ID): cv.entity_id, - vol.Optional(SRV_LOAD_DB_RELOAD, default='false'): cv.boolean, + vol.Required(CONF_ENTITY_ID): vol.Any(cv.entity_id, ENTITY_MATCH_ALL), + vol.Optional(SRV_LOAD_DB_RELOAD, default=False): cv.boolean, }) + PRINT_ALDB_SCHEMA = vol.Schema({ vol.Required(CONF_ENTITY_ID): cv.entity_id, }) + X10_HOUSECODE_SCHEMA = vol.Schema({ vol.Required(SRV_HOUSECODE): vol.In(HOUSECODES), }) + +TRIGGER_SCENE_SCHEMA = vol.Schema({ + vol.Required(SRV_ALL_LINK_GROUP): vol.Range(min=0, max=255)}) + + STATE_NAME_LABEL_MAP = { 'keypadButtonA': 'Button A', 'keypadButtonB': 'Button B', @@ -237,26 +256,26 @@ async def async_setup(hass, config): def load_aldb(service): """Load the device All-Link database.""" - entity_id = service.data.get(CONF_ENTITY_ID) - reload = service.data.get(SRV_LOAD_DB_RELOAD) - entities = hass.data[DOMAIN].get('entities') - entity = entities.get(entity_id) - if entity: - entity.load_aldb(reload) + entity_id = service.data[CONF_ENTITY_ID] + reload = service.data[SRV_LOAD_DB_RELOAD] + if entity_id.lower() == ENTITY_MATCH_ALL: + for entity_id in hass.data[DOMAIN].get(INSTEON_ENTITIES): + _send_load_aldb_signal(entity_id, reload) else: - _LOGGER.error('Entity %s is not an INSTEON device', entity_id) + _send_load_aldb_signal(entity_id, reload) + + def _send_load_aldb_signal(entity_id, reload): + """Send the load All-Link database signal to INSTEON entity.""" + signal = '{}_{}'.format(entity_id, SIGNAL_LOAD_ALDB) + dispatcher_send(hass, signal, reload) def print_aldb(service): """Print the All-Link Database for a device.""" # For now this sends logs to the log file. # Furture direction is to create an INSTEON control panel. - entity_id = service.data.get(CONF_ENTITY_ID) - entities = hass.data[DOMAIN].get('entities') - entity = entities.get(entity_id) - if entity: - entity.print_aldb() - else: - _LOGGER.error('Entity %s is not an INSTEON device', entity_id) + entity_id = service.data[CONF_ENTITY_ID] + signal = '{}_{}'.format(entity_id, SIGNAL_PRINT_ALDB) + dispatcher_send(hass, signal) def print_im_aldb(service): """Print the All-Link Database for a device.""" @@ -279,6 +298,16 @@ async def async_setup(hass, config): housecode = service.data.get(SRV_HOUSECODE) insteon_modem.x10_all_lights_on(housecode) + def scene_on(service): + """Trigger an INSTEON scene ON.""" + group = service.data.get(SRV_ALL_LINK_GROUP) + insteon_modem.trigger_group_on(group) + + def scene_off(service): + """Trigger an INSTEON scene ON.""" + group = service.data.get(SRV_ALL_LINK_GROUP) + insteon_modem.trigger_group_off(group) + def _register_services(): hass.services.register(DOMAIN, SRV_ADD_ALL_LINK, add_all_link, schema=ADD_ALL_LINK_SCHEMA) @@ -299,6 +328,12 @@ async def async_setup(hass, config): hass.services.register(DOMAIN, SRV_X10_ALL_LIGHTS_ON, x10_all_lights_on, schema=X10_HOUSECODE_SCHEMA) + hass.services.register(DOMAIN, SRV_SCENE_ON, + scene_on, + schema=TRIGGER_SCENE_SCHEMA) + hass.services.register(DOMAIN, SRV_SCENE_OFF, + scene_off, + schema=TRIGGER_SCENE_SCHEMA) _LOGGER.debug("Insteon Services registered") def _fire_button_on_off_event(address, group, val): @@ -352,7 +387,7 @@ async def async_setup(hass, config): hass.data[DOMAIN] = {} hass.data[DOMAIN]['modem'] = insteon_modem - hass.data[DOMAIN]['entities'] = {} + hass.data[DOMAIN][INSTEON_ENTITIES] = {} hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, conn.close) @@ -547,22 +582,26 @@ class InsteonEntity(Entity): self._insteon_device_state.name) self._insteon_device_state.register_updates( self.async_entity_update) - self.hass.data[DOMAIN]['entities'][self.entity_id] = self + self.hass.data[DOMAIN][INSTEON_ENTITIES][self.entity_id] = self + load_signal = '{}_{}'.format(self.entity_id, SIGNAL_LOAD_ALDB) + async_dispatcher_connect(self.hass, load_signal, self._load_aldb) + print_signal = '{}_{}'.format(self.entity_id, SIGNAL_PRINT_ALDB) + async_dispatcher_connect(self.hass, print_signal, self._print_aldb) - def load_aldb(self, reload=False): + def _load_aldb(self, reload=False): """Load the device All-Link Database.""" if reload: self._insteon_device.aldb.clear() self._insteon_device.read_aldb() - def print_aldb(self): + def _print_aldb(self): """Print the device ALDB to the log file.""" print_aldb_to_log(self._insteon_device.aldb) @callback def _aldb_loaded(self): """All-Link Database loaded for the device.""" - self.print_aldb() + self._print_aldb() def _get_label(self): """Get the device label for grouped devices.""" diff --git a/homeassistant/components/insteon/manifest.json b/homeassistant/components/insteon/manifest.json index a8c5b553943..3ac75c68313 100644 --- a/homeassistant/components/insteon/manifest.json +++ b/homeassistant/components/insteon/manifest.json @@ -3,7 +3,7 @@ "name": "Insteon", "documentation": "https://www.home-assistant.io/components/insteon", "requirements": [ - "insteonplm==0.15.4" + "insteonplm==0.16.0" ], "dependencies": [], "codeowners": [] diff --git a/homeassistant/components/insteon/services.yaml b/homeassistant/components/insteon/services.yaml index 4d87d7881bf..9c8d3237114 100644 --- a/homeassistant/components/insteon/services.yaml +++ b/homeassistant/components/insteon/services.yaml @@ -17,7 +17,7 @@ load_all_link_database: description: Load the All-Link Database for a device. WARNING - Loading a device All-LInk database is very time consuming and inconsistent. This may take a LONG time and may need to be repeated to obtain all records. fields: entity_id: - description: Name of the device to print + description: Name of the device to load. Use "all" to load the database of all devices. example: 'light.1a2b3c' reload: description: Reload all records. If true the current records are cleared from memory (does not effect the device) and the records are reloaded. If false the existing records are left in place and only missing records are added. Default is false. @@ -48,3 +48,15 @@ x10_all_lights_off: housecode: description: X10 house code example: c +scene_on: + description: Trigger an INSTEON scene to turn ON. + fields: + group: + description: INSTEON group or scene number + example: 26 +scene_off: + description: Trigger an INSTEON scene to turn OFF. + fields: + group: + description: INSTEON group or scene number + example: 26 \ No newline at end of file diff --git a/requirements_all.txt b/requirements_all.txt index c5d648cb8f6..502def0d0a4 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -650,7 +650,7 @@ incomfort-client==0.3.0 influxdb==5.2.0 # homeassistant.components.insteon -insteonplm==0.15.4 +insteonplm==0.16.0 # homeassistant.components.iperf3 iperf3==0.1.10