From a31501d99eb90430a6de9ea366fbea59fc944dad Mon Sep 17 00:00:00 2001 From: Tom Harris Date: Wed, 22 Aug 2018 03:09:04 -0400 Subject: [PATCH] Merge insteon_plm and insteon_local to insteon component (#16102) * Implement X10 * Add X10 after add_device_callback * Ref device by id not hex and add x10OnOffSwitch name * X10 services and add sensor device * Correctly reference X10_HOUSECODE_SCHEMA * Log adding of X10 devices * Add X10 All Units Off, All Lights On and All Lights Off devices * Correct ref to X10 states vs devices * Add X10 All Units Off, All Lights On and All Lights Off devices * Correct X10 config * Debug x10 device additions * Config x10 from bool to housecode char * Pass PLM to X10 device create * Remove PLM to call to add_x10_device * Unconfuse x10 config and method names * Correct spelling of x10_all_lights_off_housecode * Bump insteonplm to 0.10.0 to support X10 * Add host to config options * Add username and password to config for hub connectivity * Add username and password to config for hub * Convert port to int if host is defined * Add KeypadLinc * Update config schema to require either port or host * Solidify Hub and PLM configuration to ensure proper settings * Update hub schema * Bump insteonplm version * Fix pylint and flake issues * Bump insteonplm to 0.12.1 * Merge insteon_plm and insteon_local to insteon * Rename insteon_plm to insteon * Bump insteonplm to 0.12.2 * Flake8 cleanup * Update .coveragerc for insteon_plm, insteon_local and insteon changes * Add persistent notification * Fix reference to insteon_plm * Fix indentation * Shorten message and fix grammer * Add comment to remove in release 0.90 * Hound fix --- .coveragerc | 9 +- .../{insteon_plm.py => insteon.py} | 18 +- .../fan/{insteon_plm.py => insteon.py} | 16 +- homeassistant/components/fan/insteon_local.py | 107 ----------- .../{insteon_plm => insteon}/__init__.py | 169 +++++++++++------- .../{insteon_plm => insteon}/services.yaml | 0 homeassistant/components/insteon_local.py | 84 ++------- homeassistant/components/insteon_plm.py | 30 ++++ .../light/{insteon_plm.py => insteon.py} | 16 +- .../components/light/insteon_local.py | 98 ---------- .../sensor/{insteon_plm.py => insteon.py} | 16 +- .../switch/{insteon_plm.py => insteon.py} | 25 ++- .../components/switch/insteon_local.py | 83 --------- requirements_all.txt | 7 +- 14 files changed, 204 insertions(+), 474 deletions(-) rename homeassistant/components/binary_sensor/{insteon_plm.py => insteon.py} (76%) rename homeassistant/components/fan/{insteon_plm.py => insteon.py} (86%) delete mode 100644 homeassistant/components/fan/insteon_local.py rename homeassistant/components/{insteon_plm => insteon}/__init__.py (73%) rename homeassistant/components/{insteon_plm => insteon}/services.yaml (100%) create mode 100644 homeassistant/components/insteon_plm.py rename homeassistant/components/light/{insteon_plm.py => insteon.py} (80%) delete mode 100644 homeassistant/components/light/insteon_local.py rename homeassistant/components/sensor/{insteon_plm.py => insteon.py} (61%) rename homeassistant/components/switch/{insteon_plm.py => insteon.py} (69%) delete mode 100644 homeassistant/components/switch/insteon_local.py diff --git a/.coveragerc b/.coveragerc index 989830e5c9d..62f710f3680 100644 --- a/.coveragerc +++ b/.coveragerc @@ -136,12 +136,13 @@ omit = homeassistant/components/ihc/* homeassistant/components/*/ihc.py + + homeassistant/components/insteon/* + homeassistant/components/*/insteon.py homeassistant/components/insteon_local.py - homeassistant/components/*/insteon_local.py - - homeassistant/components/insteon_plm/* - homeassistant/components/*/insteon_plm.py + + homeassistant/components/insteon_plm.py homeassistant/components/ios.py homeassistant/components/*/ios.py diff --git a/homeassistant/components/binary_sensor/insteon_plm.py b/homeassistant/components/binary_sensor/insteon.py similarity index 76% rename from homeassistant/components/binary_sensor/insteon_plm.py rename to homeassistant/components/binary_sensor/insteon.py index 25fc3fb5d73..789ad894a41 100644 --- a/homeassistant/components/binary_sensor/insteon_plm.py +++ b/homeassistant/components/binary_sensor/insteon.py @@ -2,15 +2,15 @@ Support for INSTEON dimmers via PowerLinc Modem. For more details about this component, please refer to the documentation at -https://home-assistant.io/components/binary_sensor.insteon_plm/ +https://home-assistant.io/components/binary_sensor.insteon/ """ import asyncio import logging from homeassistant.components.binary_sensor import BinarySensorDevice -from homeassistant.components.insteon_plm import InsteonPLMEntity +from homeassistant.components.insteon import InsteonEntity -DEPENDENCIES = ['insteon_plm'] +DEPENDENCIES = ['insteon'] _LOGGER = logging.getLogger(__name__) @@ -24,27 +24,27 @@ SENSOR_TYPES = {'openClosedSensor': 'opening', @asyncio.coroutine def async_setup_platform(hass, config, async_add_devices, discovery_info=None): - """Set up the INSTEON PLM device class for the hass platform.""" - plm = hass.data['insteon_plm'].get('plm') + """Set up the INSTEON device class for the hass platform.""" + insteon_modem = hass.data['insteon'].get('modem') address = discovery_info['address'] - device = plm.devices[address] + device = insteon_modem.devices[address] state_key = discovery_info['state_key'] name = device.states[state_key].name if name != 'dryLeakSensor': _LOGGER.debug('Adding device %s entity %s to Binary Sensor platform', device.address.hex, device.states[state_key].name) - new_entity = InsteonPLMBinarySensor(device, state_key) + new_entity = InsteonBinarySensor(device, state_key) async_add_devices([new_entity]) -class InsteonPLMBinarySensor(InsteonPLMEntity, BinarySensorDevice): +class InsteonBinarySensor(InsteonEntity, BinarySensorDevice): """A Class for an Insteon device entity.""" def __init__(self, device, state_key): - """Initialize the INSTEON PLM binary sensor.""" + """Initialize the INSTEON binary sensor.""" super().__init__(device, state_key) self._sensor_type = SENSOR_TYPES.get(self._insteon_device_state.name) diff --git a/homeassistant/components/fan/insteon_plm.py b/homeassistant/components/fan/insteon.py similarity index 86% rename from homeassistant/components/fan/insteon_plm.py rename to homeassistant/components/fan/insteon.py index 0911295d090..62fa48935ec 100644 --- a/homeassistant/components/fan/insteon_plm.py +++ b/homeassistant/components/fan/insteon.py @@ -2,7 +2,7 @@ Support for INSTEON fans via PowerLinc Modem. For more details about this component, please refer to the documentation at -https://home-assistant.io/components/fan.insteon_plm/ +https://home-assistant.io/components/fan.insteon/ """ import asyncio import logging @@ -14,9 +14,9 @@ from homeassistant.components.fan import (SPEED_OFF, FanEntity, SUPPORT_SET_SPEED) from homeassistant.const import STATE_OFF -from homeassistant.components.insteon_plm import InsteonPLMEntity +from homeassistant.components.insteon import InsteonEntity -DEPENDENCIES = ['insteon_plm'] +DEPENDENCIES = ['insteon'] SPEED_TO_HEX = {SPEED_OFF: 0x00, SPEED_LOW: 0x3f, @@ -30,22 +30,22 @@ _LOGGER = logging.getLogger(__name__) @asyncio.coroutine def async_setup_platform(hass, config, async_add_devices, discovery_info=None): - """Set up the INSTEON PLM device class for the hass platform.""" - plm = hass.data['insteon_plm'].get('plm') + """Set up the INSTEON device class for the hass platform.""" + insteon_modem = hass.data['insteon'].get('modem') address = discovery_info['address'] - device = plm.devices[address] + device = insteon_modem.devices[address] state_key = discovery_info['state_key'] _LOGGER.debug('Adding device %s entity %s to Fan platform', device.address.hex, device.states[state_key].name) - new_entity = InsteonPLMFan(device, state_key) + new_entity = InsteonFan(device, state_key) async_add_devices([new_entity]) -class InsteonPLMFan(InsteonPLMEntity, FanEntity): +class InsteonFan(InsteonEntity, FanEntity): """An INSTEON fan component.""" @property diff --git a/homeassistant/components/fan/insteon_local.py b/homeassistant/components/fan/insteon_local.py deleted file mode 100644 index 28b93c86ed7..00000000000 --- a/homeassistant/components/fan/insteon_local.py +++ /dev/null @@ -1,107 +0,0 @@ -""" -Support for Insteon fans via local hub control. - -For more details about this component, please refer to the documentation at -https://home-assistant.io/components/fan.insteon_local/ -""" -import logging -from datetime import timedelta - -from homeassistant import util -from homeassistant.components.fan import ( - ATTR_SPEED, SPEED_OFF, SPEED_LOW, SPEED_MEDIUM, SPEED_HIGH, - SUPPORT_SET_SPEED, FanEntity) - -_CONFIGURING = {} -_LOGGER = logging.getLogger(__name__) - -DEPENDENCIES = ['insteon_local'] -DOMAIN = 'fan' - -MIN_TIME_BETWEEN_FORCED_SCANS = timedelta(milliseconds=100) -MIN_TIME_BETWEEN_SCANS = timedelta(seconds=5) - -SUPPORT_INSTEON_LOCAL = SUPPORT_SET_SPEED - - -def setup_platform(hass, config, add_devices, discovery_info=None): - """Set up the Insteon local fan platform.""" - insteonhub = hass.data['insteon_local'] - if discovery_info is None: - return - - linked = discovery_info['linked'] - device_list = [] - for device_id in linked: - if (linked[device_id]['cat_type'] == 'dimmer' and - linked[device_id]['sku'] == '2475F'): - device = insteonhub.fan(device_id) - device_list.append( - InsteonLocalFanDevice(device) - ) - - add_devices(device_list) - - -class InsteonLocalFanDevice(FanEntity): - """An abstract Class for an Insteon node.""" - - def __init__(self, node): - """Initialize the device.""" - self.node = node - self._speed = SPEED_OFF - - @property - def name(self): - """Return the name of the node.""" - return self.node.device_id - - @property - def unique_id(self): - """Return the ID of this Insteon node.""" - return self.node.device_id - - @property - def speed(self) -> str: - """Return the current speed.""" - return self._speed - - @property - def speed_list(self) -> list: - """Get the list of available speeds.""" - return [SPEED_OFF, SPEED_LOW, SPEED_MEDIUM, SPEED_HIGH] - - @util.Throttle(MIN_TIME_BETWEEN_SCANS, MIN_TIME_BETWEEN_FORCED_SCANS) - def update(self): - """Update state of the fan.""" - resp = self.node.status() - if 'cmd2' in resp: - if resp['cmd2'] == '00': - self._speed = SPEED_OFF - elif resp['cmd2'] == '55': - self._speed = SPEED_LOW - elif resp['cmd2'] == 'AA': - self._speed = SPEED_MEDIUM - elif resp['cmd2'] == 'FF': - self._speed = SPEED_HIGH - - @property - def supported_features(self): - """Flag supported features.""" - return SUPPORT_INSTEON_LOCAL - - def turn_on(self, speed: str = None, **kwargs) -> None: - """Turn device on.""" - if speed is None: - speed = kwargs.get(ATTR_SPEED, SPEED_MEDIUM) - - self.set_speed(speed) - - def turn_off(self, **kwargs) -> None: - """Turn device off.""" - self.node.off() - - def set_speed(self, speed: str) -> None: - """Set the speed of the fan.""" - if self.node.on(speed): - self._speed = speed diff --git a/homeassistant/components/insteon_plm/__init__.py b/homeassistant/components/insteon/__init__.py similarity index 73% rename from homeassistant/components/insteon_plm/__init__.py rename to homeassistant/components/insteon/__init__.py index 055015b74f5..212cdbac3b8 100644 --- a/homeassistant/components/insteon_plm/__init__.py +++ b/homeassistant/components/insteon/__init__.py @@ -1,8 +1,8 @@ """ -Support for INSTEON PowerLinc Modem. +Support for INSTEON Modems (PLM and Hub). For more details about this component, please refer to the documentation at -https://home-assistant.io/components/insteon_plm/ +https://home-assistant.io/components/insteon/ """ import asyncio import collections @@ -12,18 +12,24 @@ import voluptuous as vol from homeassistant.core import callback from homeassistant.const import (CONF_PORT, EVENT_HOMEASSISTANT_STOP, CONF_PLATFORM, - CONF_ENTITY_ID) + CONF_ENTITY_ID, + CONF_HOST) import homeassistant.helpers.config_validation as cv from homeassistant.helpers import discovery from homeassistant.helpers.entity import Entity -REQUIREMENTS = ['insteonplm==0.11.7'] +REQUIREMENTS = ['insteonplm==0.12.3'] _LOGGER = logging.getLogger(__name__) -DOMAIN = 'insteon_plm' +DOMAIN = 'insteon' +CONF_IP_PORT = 'ip_port' +CONF_HUB_USERNAME = 'username' +CONF_HUB_PASSWORD = 'password' CONF_OVERRIDE = 'device_override' +CONF_PLM_HUB_MSG = ('Must configure either a PLM port or a Hub host, username ' + 'and password') CONF_ADDRESS = 'address' CONF_CAT = 'cat' CONF_SUBCAT = 'subcat' @@ -56,8 +62,8 @@ HOUSECODES = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p'] BUTTON_PRESSED_STATE_NAME = 'onLevelButton' -EVENT_BUTTON_ON = 'insteon_plm.button_on' -EVENT_BUTTON_OFF = 'insteon_plm.button_off' +EVENT_BUTTON_ON = 'insteon.button_on' +EVENT_BUTTON_OFF = 'insteon.button_off' EVENT_CONF_BUTTON = 'button' CONF_DEVICE_OVERRIDE_SCHEMA = vol.All( @@ -79,17 +85,34 @@ CONF_X10_SCHEMA = vol.All( })) CONFIG_SCHEMA = vol.Schema({ - DOMAIN: vol.Schema({ - vol.Required(CONF_PORT): cv.string, - vol.Optional(CONF_OVERRIDE): vol.All( - cv.ensure_list_csv, [CONF_DEVICE_OVERRIDE_SCHEMA]), - vol.Optional(CONF_X10_ALL_UNITS_OFF): vol.In(HOUSECODES), - vol.Optional(CONF_X10_ALL_LIGHTS_ON): vol.In(HOUSECODES), - vol.Optional(CONF_X10_ALL_LIGHTS_OFF): vol.In(HOUSECODES), - vol.Optional(CONF_X10): vol.All( - cv.ensure_list_csv, [CONF_X10_SCHEMA]) - }) -}, extra=vol.ALLOW_EXTRA) + DOMAIN: vol.All( + vol.Schema( + {vol.Exclusive(CONF_PORT, 'plm_or_hub', + msg=CONF_PLM_HUB_MSG): cv.isdevice, + vol.Exclusive(CONF_HOST, 'plm_or_hub', + msg=CONF_PLM_HUB_MSG): cv.string, + vol.Optional(CONF_IP_PORT, default=25105): int, + vol.Optional(CONF_HUB_USERNAME): cv.string, + vol.Optional(CONF_HUB_PASSWORD): cv.string, + vol.Optional(CONF_OVERRIDE): vol.All( + cv.ensure_list_csv, [CONF_DEVICE_OVERRIDE_SCHEMA]), + vol.Optional(CONF_X10_ALL_UNITS_OFF): vol.In(HOUSECODES), + vol.Optional(CONF_X10_ALL_LIGHTS_ON): vol.In(HOUSECODES), + vol.Optional(CONF_X10_ALL_LIGHTS_OFF): vol.In(HOUSECODES), + vol.Optional(CONF_X10): vol.All(cv.ensure_list_csv, + [CONF_X10_SCHEMA]) + }, extra=vol.ALLOW_EXTRA, required=True), + cv.has_at_least_one_key(CONF_PORT, CONF_HOST), + vol.Schema( + {vol.Inclusive(CONF_HOST, 'hub', + msg=CONF_PLM_HUB_MSG): cv.string, + vol.Inclusive(CONF_HUB_USERNAME, 'hub', + msg=CONF_PLM_HUB_MSG): cv.string, + vol.Inclusive(CONF_HUB_PASSWORD, 'hub', + msg=CONF_PLM_HUB_MSG): cv.string, + }, extra=vol.ALLOW_EXTRA, required=True)) + }, extra=vol.ALLOW_EXTRA) + ADD_ALL_LINK_SCHEMA = vol.Schema({ vol.Required(SRV_ALL_LINK_GROUP): vol.Range(min=0, max=255), @@ -116,14 +139,18 @@ X10_HOUSECODE_SCHEMA = vol.Schema({ @asyncio.coroutine def async_setup(hass, config): - """Set up the connection to the PLM.""" + """Set up the connection to the modem.""" import insteonplm ipdb = IPDB() - plm = None + insteon_modem = None conf = config[DOMAIN] port = conf.get(CONF_PORT) + host = conf.get(CONF_HOST) + ip_port = conf.get(CONF_IP_PORT) + username = conf.get(CONF_HUB_USERNAME) + password = conf.get(CONF_HUB_PASSWORD) overrides = conf.get(CONF_OVERRIDE, []) x10_devices = conf.get(CONF_X10, []) x10_all_units_off_housecode = conf.get(CONF_X10_ALL_UNITS_OFF) @@ -131,7 +158,7 @@ def async_setup(hass, config): x10_all_lights_off_housecode = conf.get(CONF_X10_ALL_LIGHTS_OFF) @callback - def async_plm_new_device(device): + def async_new_insteon_device(device): """Detect device from transport to be delegated to platform.""" for state_key in device.states: platform_info = ipdb[device.states[state_key]] @@ -143,7 +170,7 @@ def async_setup(hass, config): _fire_button_on_off_event) else: - _LOGGER.info("New INSTEON PLM device: %s (%s) %s", + _LOGGER.info("New INSTEON device: %s (%s) %s", device.address, device.states[state_key].name, platform) @@ -160,12 +187,12 @@ def async_setup(hass, config): group = service.data.get(SRV_ALL_LINK_GROUP) mode = service.data.get(SRV_ALL_LINK_MODE) link_mode = 1 if mode.lower() == SRV_CONTROLLER else 0 - plm.start_all_linking(link_mode, group) + insteon_modem.start_all_linking(link_mode, group) def del_all_link(service): """Delete an INSTEON All-Link between two devices.""" group = service.data.get(SRV_ALL_LINK_GROUP) - plm.start_all_linking(255, group) + insteon_modem.start_all_linking(255, group) def load_aldb(service): """Load the device All-Link database.""" @@ -194,22 +221,22 @@ def async_setup(hass, config): """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. - print_aldb_to_log(plm.aldb) + print_aldb_to_log(insteon_modem.aldb) def x10_all_units_off(service): """Send the X10 All Units Off command.""" housecode = service.data.get(SRV_HOUSECODE) - plm.x10_all_units_off(housecode) + insteon_modem.x10_all_units_off(housecode) def x10_all_lights_off(service): """Send the X10 All Lights Off command.""" housecode = service.data.get(SRV_HOUSECODE) - plm.x10_all_lights_off(housecode) + insteon_modem.x10_all_lights_off(housecode) def x10_all_lights_on(service): """Send the X10 All Lights On command.""" housecode = service.data.get(SRV_HOUSECODE) - plm.x10_all_lights_on(housecode) + insteon_modem.x10_all_lights_on(housecode) def _register_services(): hass.services.register(DOMAIN, SRV_ADD_ALL_LINK, add_all_link, @@ -231,11 +258,11 @@ def async_setup(hass, config): hass.services.register(DOMAIN, SRV_X10_ALL_LIGHTS_ON, x10_all_lights_on, schema=X10_HOUSECODE_SCHEMA) - _LOGGER.debug("Insteon_plm Services registered") + _LOGGER.debug("Insteon Services registered") def _fire_button_on_off_event(address, group, val): # Firing an event when a button is pressed. - device = plm.devices[address.hex] + device = insteon_modem.devices[address.hex] state_name = device.states[group].name button = ("" if state_name == BUTTON_PRESSED_STATE_NAME else state_name[-1].lower()) @@ -250,13 +277,23 @@ def async_setup(hass, config): event, address.hex, button) hass.bus.fire(event, schema) - _LOGGER.info("Looking for PLM on %s", port) - conn = yield from insteonplm.Connection.create( - device=port, - loop=hass.loop, - workdir=hass.config.config_dir) + if host: + _LOGGER.info('Connecting to Insteon Hub on %s', host) + conn = yield from insteonplm.Connection.create( + host=host, + port=ip_port, + username=username, + password=password, + loop=hass.loop, + workdir=hass.config.config_dir) + else: + _LOGGER.info("Looking for Insteon PLM on %s", port) + conn = yield from insteonplm.Connection.create( + device=port, + loop=hass.loop, + workdir=hass.config.config_dir) - plm = conn.protocol + insteon_modem = conn.protocol for device_override in overrides: # @@ -265,32 +302,32 @@ def async_setup(hass, config): address = device_override.get('address') for prop in device_override: if prop in [CONF_CAT, CONF_SUBCAT]: - plm.devices.add_override(address, prop, - device_override[prop]) + insteon_modem.devices.add_override(address, prop, + device_override[prop]) elif prop in [CONF_FIRMWARE, CONF_PRODUCT_KEY]: - plm.devices.add_override(address, CONF_PRODUCT_KEY, - device_override[prop]) + insteon_modem.devices.add_override(address, CONF_PRODUCT_KEY, + device_override[prop]) hass.data[DOMAIN] = {} - hass.data[DOMAIN]['plm'] = plm + hass.data[DOMAIN]['modem'] = insteon_modem hass.data[DOMAIN]['entities'] = {} hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, conn.close) - plm.devices.add_device_callback(async_plm_new_device) + insteon_modem.devices.add_device_callback(async_new_insteon_device) if x10_all_units_off_housecode: - device = plm.add_x10_device(x10_all_units_off_housecode, - 20, - 'allunitsoff') + device = insteon_modem.add_x10_device(x10_all_units_off_housecode, + 20, + 'allunitsoff') if x10_all_lights_on_housecode: - device = plm.add_x10_device(x10_all_lights_on_housecode, - 21, - 'alllightson') + device = insteon_modem.add_x10_device(x10_all_lights_on_housecode, + 21, + 'alllightson') if x10_all_lights_off_housecode: - device = plm.add_x10_device(x10_all_lights_off_housecode, - 22, - 'alllightsoff') + device = insteon_modem.add_x10_device(x10_all_lights_off_housecode, + 22, + 'alllightsoff') for device in x10_devices: housecode = device.get(CONF_HOUSECODE) unitcode = device.get(CONF_UNITCODE) @@ -300,11 +337,11 @@ def async_setup(hass, config): x10_type = 'dimmable' elif device.get(CONF_PLATFORM) == 'binary_sensor': x10_type = 'sensor' - _LOGGER.debug("Adding X10 device to insteonplm: %s %d %s", + _LOGGER.debug("Adding X10 device to Insteon: %s %d %s", housecode, unitcode, x10_type) - device = plm.add_x10_device(housecode, - unitcode, - x10_type) + device = insteon_modem.add_x10_device(housecode, + unitcode, + x10_type) if device and hasattr(device.states[0x01], 'steps'): device.states[0x01].steps = steps @@ -324,11 +361,14 @@ class IPDB: from insteonplm.states.onOff import (OnOffSwitch, OnOffSwitch_OutletTop, OnOffSwitch_OutletBottom, - OpenClosedRelay) + OpenClosedRelay, + OnOffKeypadA, + OnOffKeypad) from insteonplm.states.dimmable import (DimmableSwitch, DimmableSwitch_Fan, - DimmableRemote) + DimmableRemote, + DimmableKeypadA) from insteonplm.states.sensor import (VariableSensor, OnOffSensor, @@ -347,6 +387,8 @@ class IPDB: State(OnOffSwitch_OutletBottom, 'switch'), State(OpenClosedRelay, 'switch'), State(OnOffSwitch, 'switch'), + State(OnOffKeypadA, 'switch'), + State(OnOffKeypad, 'switch'), State(LeakSensorDryWet, 'binary_sensor'), State(IoLincSensor, 'binary_sensor'), @@ -357,6 +399,7 @@ class IPDB: State(DimmableSwitch_Fan, 'fan'), State(DimmableSwitch, 'light'), State(DimmableRemote, 'on_off_events'), + State(DimmableKeypadA, 'light'), State(X10DimmableSwitch, 'light'), State(X10OnOffSwitch, 'switch'), @@ -382,11 +425,11 @@ class IPDB: return None -class InsteonPLMEntity(Entity): +class InsteonEntity(Entity): """INSTEON abstract base entity.""" def __init__(self, device, state_key): - """Initialize the INSTEON PLM binary sensor.""" + """Initialize the INSTEON binary sensor.""" self._insteon_device_state = device.states[state_key] self._insteon_device = device self._insteon_device.aldb.add_loaded_callback(self._aldb_loaded) @@ -429,11 +472,17 @@ class InsteonPLMEntity(Entity): @callback def async_entity_update(self, deviceid, statename, val): """Receive notification from transport that new data exists.""" + _LOGGER.debug('Received update for device %s group %d statename %s', + self.address, self.group, + self._insteon_device_state.name) self.async_schedule_update_ha_state() @asyncio.coroutine def async_added_to_hass(self): """Register INSTEON update events.""" + _LOGGER.debug('Tracking updates for device %s group %d statename %s', + self.address, self.group, + self._insteon_device_state.name) self._insteon_device_state.register_updates( self.async_entity_update) self.hass.data[DOMAIN]['entities'][self.entity_id] = self @@ -460,7 +509,7 @@ def print_aldb_to_log(aldb): _LOGGER.info('ALDB load status is %s', aldb.status.name) if aldb.status not in [ALDBStatus.LOADED, ALDBStatus.PARTIAL]: _LOGGER.warning('Device All-Link database not loaded') - _LOGGER.warning('Use service insteon_plm.load_aldb first') + _LOGGER.warning('Use service insteon.load_aldb first') return _LOGGER.info('RecID In Use Mode HWM Group Address Data 1 Data 2 Data 3') diff --git a/homeassistant/components/insteon_plm/services.yaml b/homeassistant/components/insteon/services.yaml similarity index 100% rename from homeassistant/components/insteon_plm/services.yaml rename to homeassistant/components/insteon/services.yaml diff --git a/homeassistant/components/insteon_local.py b/homeassistant/components/insteon_local.py index a18d4e0aa14..1dfb0c6e4cb 100644 --- a/homeassistant/components/insteon_local.py +++ b/homeassistant/components/insteon_local.py @@ -5,82 +5,24 @@ For more details about this component, please refer to the documentation at https://home-assistant.io/components/insteon_local/ """ import logging -import os - -import requests -import voluptuous as vol - -from homeassistant.const import ( - CONF_HOST, CONF_PASSWORD, CONF_PORT, CONF_TIMEOUT, CONF_USERNAME) -import homeassistant.helpers.config_validation as cv -from homeassistant.helpers.discovery import load_platform - -REQUIREMENTS = ['insteonlocal==0.53'] _LOGGER = logging.getLogger(__name__) -DEFAULT_PORT = 25105 -DEFAULT_TIMEOUT = 10 -DOMAIN = 'insteon_local' - -INSTEON_CACHE = '.insteon_local_cache' - -INSTEON_PLATFORMS = [ - 'light', - 'switch', - 'fan', -] - -CONFIG_SCHEMA = vol.Schema({ - DOMAIN: vol.Schema({ - vol.Required(CONF_HOST): cv.string, - vol.Required(CONF_PASSWORD): cv.string, - vol.Required(CONF_USERNAME): cv.string, - vol.Optional(CONF_PORT, default=DEFAULT_PORT): cv.port, - vol.Optional(CONF_TIMEOUT, default=DEFAULT_TIMEOUT): cv.positive_int, - }) -}, extra=vol.ALLOW_EXTRA) - def setup(hass, config): - """Set up the local Insteon hub.""" - from insteonlocal.Hub import Hub + """Setup the insteon_local component. - conf = config[DOMAIN] - username = conf.get(CONF_USERNAME) - password = conf.get(CONF_PASSWORD) - host = conf.get(CONF_HOST) - port = conf.get(CONF_PORT) - timeout = conf.get(CONF_TIMEOUT) + This component is depreciated as of release 0.77 and should be removed in + release 0.90. + """ + _LOGGER.warning('The insteon_local comonent has been replaced by ' + 'the insteon component') + _LOGGER.warning('Please see https://home-assistant.io/components/insteon') - try: - if not os.path.exists(hass.config.path(INSTEON_CACHE)): - os.makedirs(hass.config.path(INSTEON_CACHE)) + hass.components.persistent_notification.create( + 'insteon_local has been replaced by the insteon component.
' + 'Please see https://home-assistant.io/components/insteon', + title='insteon_local Component Deactivated', + notification_id='insteon_local') - insteonhub = Hub(host, username, password, port, timeout, _LOGGER, - hass.config.path(INSTEON_CACHE)) - - # Check for successful connection - insteonhub.get_buffer_status() - except requests.exceptions.ConnectTimeout: - _LOGGER.error("Could not connect", exc_info=True) - return False - except requests.exceptions.ConnectionError: - _LOGGER.error("Could not connect", exc_info=True) - return False - except requests.exceptions.RequestException: - if insteonhub.http_code == 401: - _LOGGER.error("Bad username or password for Insteon_local hub") - else: - _LOGGER.error("Error on Insteon_local hub check", exc_info=True) - return False - - linked = insteonhub.get_linked() - - hass.data['insteon_local'] = insteonhub - - for insteon_platform in INSTEON_PLATFORMS: - load_platform(hass, insteon_platform, DOMAIN, {'linked': linked}, - config) - - return True + return False diff --git a/homeassistant/components/insteon_plm.py b/homeassistant/components/insteon_plm.py new file mode 100644 index 00000000000..bd41819a0fa --- /dev/null +++ b/homeassistant/components/insteon_plm.py @@ -0,0 +1,30 @@ +""" +Support for INSTEON PowerLinc Modem. + +For more details about this component, please refer to the documentation at +https://home-assistant.io/components/insteon_plm/ +""" +import asyncio +import logging + +_LOGGER = logging.getLogger(__name__) + + +@asyncio.coroutine +def async_setup(hass, config): + """Setup the insteon_plm component. + + This component is depreciated as of release 0.77 and should be removed in + release 0.90. + """ + _LOGGER.warning('The insteon_plm comonent has been replaced by ' + 'the insteon component') + _LOGGER.warning('Please see https://home-assistant.io/components/insteon') + + hass.components.persistent_notification.create( + 'insteon_plm has been replaced by the insteon component.
' + 'Please see https://home-assistant.io/components/insteon', + title='insteon_plm Component Deactivated', + notification_id='insteon_plm') + + return False diff --git a/homeassistant/components/light/insteon_plm.py b/homeassistant/components/light/insteon.py similarity index 80% rename from homeassistant/components/light/insteon_plm.py rename to homeassistant/components/light/insteon.py index 8a3b463c2bd..88a9ab01de5 100644 --- a/homeassistant/components/light/insteon_plm.py +++ b/homeassistant/components/light/insteon.py @@ -2,40 +2,40 @@ Support for Insteon lights via PowerLinc Modem. For more details about this component, please refer to the documentation at -https://home-assistant.io/components/light.insteon_plm/ +https://home-assistant.io/components/light.insteon/ """ import asyncio import logging -from homeassistant.components.insteon_plm import InsteonPLMEntity +from homeassistant.components.insteon import InsteonEntity from homeassistant.components.light import ( ATTR_BRIGHTNESS, SUPPORT_BRIGHTNESS, Light) _LOGGER = logging.getLogger(__name__) -DEPENDENCIES = ['insteon_plm'] +DEPENDENCIES = ['insteon'] MAX_BRIGHTNESS = 255 @asyncio.coroutine def async_setup_platform(hass, config, async_add_devices, discovery_info=None): - """Set up the Insteon PLM device.""" - plm = hass.data['insteon_plm'].get('plm') + """Set up the Insteon component.""" + insteon_modem = hass.data['insteon'].get('modem') address = discovery_info['address'] - device = plm.devices[address] + device = insteon_modem.devices[address] state_key = discovery_info['state_key'] _LOGGER.debug('Adding device %s entity %s to Light platform', device.address.hex, device.states[state_key].name) - new_entity = InsteonPLMDimmerDevice(device, state_key) + new_entity = InsteonDimmerDevice(device, state_key) async_add_devices([new_entity]) -class InsteonPLMDimmerDevice(InsteonPLMEntity, Light): +class InsteonDimmerDevice(InsteonEntity, Light): """A Class for an Insteon device.""" @property diff --git a/homeassistant/components/light/insteon_local.py b/homeassistant/components/light/insteon_local.py deleted file mode 100644 index e2bc54de517..00000000000 --- a/homeassistant/components/light/insteon_local.py +++ /dev/null @@ -1,98 +0,0 @@ -""" -Support for Insteon dimmers via local hub control. - -For more details about this component, please refer to the documentation at -https://home-assistant.io/components/light.insteon_local/ -""" -import logging -from datetime import timedelta - -from homeassistant.components.light import ( - ATTR_BRIGHTNESS, SUPPORT_BRIGHTNESS, Light) -from homeassistant import util - -_CONFIGURING = {} -_LOGGER = logging.getLogger(__name__) - -DEPENDENCIES = ['insteon_local'] -DOMAIN = 'light' - -MIN_TIME_BETWEEN_FORCED_SCANS = timedelta(milliseconds=100) -MIN_TIME_BETWEEN_SCANS = timedelta(seconds=5) - -SUPPORT_INSTEON_LOCAL = SUPPORT_BRIGHTNESS - - -def setup_platform(hass, config, add_devices, discovery_info=None): - """Set up the Insteon local light platform.""" - insteonhub = hass.data['insteon_local'] - if discovery_info is None: - return - - linked = discovery_info['linked'] - device_list = [] - for device_id in linked: - if linked[device_id]['cat_type'] == 'dimmer': - device = insteonhub.dimmer(device_id) - device_list.append( - InsteonLocalDimmerDevice(device) - ) - - add_devices(device_list) - - -class InsteonLocalDimmerDevice(Light): - """An abstract Class for an Insteon node.""" - - def __init__(self, node): - """Initialize the device.""" - self.node = node - self._value = 0 - - @property - def name(self): - """Return the name of the node.""" - return self.node.device_id - - @property - def unique_id(self): - """Return the ID of this Insteon node.""" - return self.node.device_id - - @property - def brightness(self): - """Return the brightness of this light between 0..255.""" - return self._value - - @util.Throttle(MIN_TIME_BETWEEN_SCANS, MIN_TIME_BETWEEN_FORCED_SCANS) - def update(self): - """Update state of the light.""" - resp = self.node.status(0) - - while 'error' in resp and resp['error'] is True: - resp = self.node.status(0) - - if 'cmd2' in resp: - self._value = int(resp['cmd2'], 16) - - @property - def is_on(self): - """Return the boolean response if the node is on.""" - return self._value != 0 - - @property - def supported_features(self): - """Flag supported features.""" - return SUPPORT_INSTEON_LOCAL - - def turn_on(self, **kwargs): - """Turn device on.""" - brightness = 100 - if ATTR_BRIGHTNESS in kwargs: - brightness = int(kwargs[ATTR_BRIGHTNESS]) / 255 * 100 - - self.node.change_level(brightness) - - def turn_off(self, **kwargs): - """Turn device off.""" - self.node.off() diff --git a/homeassistant/components/sensor/insteon_plm.py b/homeassistant/components/sensor/insteon.py similarity index 61% rename from homeassistant/components/sensor/insteon_plm.py rename to homeassistant/components/sensor/insteon.py index 61f5877ed78..59c0fee7617 100644 --- a/homeassistant/components/sensor/insteon_plm.py +++ b/homeassistant/components/sensor/insteon.py @@ -2,35 +2,35 @@ Support for INSTEON dimmers via PowerLinc Modem. For more details about this component, please refer to the documentation at -https://home-assistant.io/components/sensor.insteon_plm/ +https://home-assistant.io/components/sensor.insteon/ """ import asyncio import logging -from homeassistant.components.insteon_plm import InsteonPLMEntity +from homeassistant.components.insteon import InsteonEntity from homeassistant.helpers.entity import Entity -DEPENDENCIES = ['insteon_plm'] +DEPENDENCIES = ['insteon'] _LOGGER = logging.getLogger(__name__) @asyncio.coroutine def async_setup_platform(hass, config, async_add_devices, discovery_info=None): - """Set up the INSTEON PLM device class for the hass platform.""" - plm = hass.data['insteon_plm'].get('plm') + """Set up the INSTEON device class for the hass platform.""" + insteon_modem = hass.data['insteon'].get('modem') address = discovery_info['address'] - device = plm.devices[address] + device = insteon_modem.devices[address] state_key = discovery_info['state_key'] _LOGGER.debug('Adding device %s entity %s to Sensor platform', device.address.hex, device.states[state_key].name) - new_entity = InsteonPLMSensorDevice(device, state_key) + new_entity = InsteonSensorDevice(device, state_key) async_add_devices([new_entity]) -class InsteonPLMSensorDevice(InsteonPLMEntity, Entity): +class InsteonSensorDevice(InsteonEntity, Entity): """A Class for an Insteon device.""" diff --git a/homeassistant/components/switch/insteon_plm.py b/homeassistant/components/switch/insteon.py similarity index 69% rename from homeassistant/components/switch/insteon_plm.py rename to homeassistant/components/switch/insteon.py index c357d1ccc04..8575b16c69b 100644 --- a/homeassistant/components/switch/insteon_plm.py +++ b/homeassistant/components/switch/insteon.py @@ -2,26 +2,26 @@ Support for INSTEON dimmers via PowerLinc Modem. For more details about this component, please refer to the documentation at -https://home-assistant.io/components/switch.insteon_plm/ +https://home-assistant.io/components/switch.insteon/ """ import asyncio import logging -from homeassistant.components.insteon_plm import InsteonPLMEntity +from homeassistant.components.insteon import InsteonEntity from homeassistant.components.switch import SwitchDevice -DEPENDENCIES = ['insteon_plm'] +DEPENDENCIES = ['insteon'] _LOGGER = logging.getLogger(__name__) @asyncio.coroutine def async_setup_platform(hass, config, async_add_devices, discovery_info=None): - """Set up the INSTEON PLM device class for the hass platform.""" - plm = hass.data['insteon_plm'].get('plm') + """Set up the INSTEON device class for the hass platform.""" + insteon_modem = hass.data['insteon'].get('modem') address = discovery_info['address'] - device = plm.devices[address] + device = insteon_modem.devices[address] state_key = discovery_info['state_key'] state_name = device.states[state_key].name @@ -30,17 +30,16 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None): device.address.hex, device.states[state_key].name) new_entity = None - if state_name in ['lightOnOff', 'outletTopOnOff', 'outletBottomOnOff', - 'x10OnOffSwitch']: - new_entity = InsteonPLMSwitchDevice(device, state_key) - elif state_name == 'openClosedRelay': - new_entity = InsteonPLMOpenClosedDevice(device, state_key) + if state_name == 'openClosedRelay': + new_entity = InsteonOpenClosedDevice(device, state_key) + else: + new_entity = InsteonSwitchDevice(device, state_key) if new_entity is not None: async_add_devices([new_entity]) -class InsteonPLMSwitchDevice(InsteonPLMEntity, SwitchDevice): +class InsteonSwitchDevice(InsteonEntity, SwitchDevice): """A Class for an Insteon device.""" @property @@ -59,7 +58,7 @@ class InsteonPLMSwitchDevice(InsteonPLMEntity, SwitchDevice): self._insteon_device_state.off() -class InsteonPLMOpenClosedDevice(InsteonPLMEntity, SwitchDevice): +class InsteonOpenClosedDevice(InsteonEntity, SwitchDevice): """A Class for an Insteon device.""" @property diff --git a/homeassistant/components/switch/insteon_local.py b/homeassistant/components/switch/insteon_local.py deleted file mode 100644 index c4c8a854670..00000000000 --- a/homeassistant/components/switch/insteon_local.py +++ /dev/null @@ -1,83 +0,0 @@ -""" -Support for Insteon switch devices via local hub support. - -For more details about this component, please refer to the documentation at -https://home-assistant.io/components/switch.insteon_local/ -""" -import logging -from datetime import timedelta - -from homeassistant.components.switch import SwitchDevice -from homeassistant import util - -_CONFIGURING = {} -_LOGGER = logging.getLogger(__name__) - -DEPENDENCIES = ['insteon_local'] -DOMAIN = 'switch' - -MIN_TIME_BETWEEN_FORCED_SCANS = timedelta(milliseconds=100) -MIN_TIME_BETWEEN_SCANS = timedelta(seconds=10) - - -def setup_platform(hass, config, add_devices, discovery_info=None): - """Set up the Insteon local switch platform.""" - insteonhub = hass.data['insteon_local'] - if discovery_info is None: - return - - linked = discovery_info['linked'] - device_list = [] - for device_id in linked: - if linked[device_id]['cat_type'] == 'switch': - device = insteonhub.switch(device_id) - device_list.append( - InsteonLocalSwitchDevice(device) - ) - - add_devices(device_list) - - -class InsteonLocalSwitchDevice(SwitchDevice): - """An abstract Class for an Insteon node.""" - - def __init__(self, node): - """Initialize the device.""" - self.node = node - self._state = False - - @property - def name(self): - """Return the name of the node.""" - return self.node.device_id - - @property - def unique_id(self): - """Return the ID of this Insteon node.""" - return self.node.device_id - - @util.Throttle(MIN_TIME_BETWEEN_SCANS, MIN_TIME_BETWEEN_FORCED_SCANS) - def update(self): - """Get the updated status of the switch.""" - resp = self.node.status(0) - - while 'error' in resp and resp['error'] is True: - resp = self.node.status(0) - - if 'cmd2' in resp: - self._state = int(resp['cmd2'], 16) > 0 - - @property - def is_on(self): - """Return the boolean response if the node is on.""" - return self._state - - def turn_on(self, **kwargs): - """Turn device on.""" - self.node.on() - self._state = True - - def turn_off(self, **kwargs): - """Turn device off.""" - self.node.off() - self._state = False diff --git a/requirements_all.txt b/requirements_all.txt index ada216de5d8..8bd39162d98 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -468,11 +468,8 @@ ihcsdk==2.2.0 # homeassistant.components.sensor.influxdb influxdb==5.0.0 -# homeassistant.components.insteon_local -insteonlocal==0.53 - -# homeassistant.components.insteon_plm -insteonplm==0.11.7 +# homeassistant.components.insteon +insteonplm==0.12.3 # homeassistant.components.sensor.iperf3 iperf3==0.1.10