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
This commit is contained in:
Tom Harris 2018-08-22 03:09:04 -04:00 committed by Paulus Schoutsen
parent 6864a44b5a
commit a31501d99e
14 changed files with 204 additions and 474 deletions

View File

@ -136,12 +136,13 @@ omit =
homeassistant/components/ihc/* homeassistant/components/ihc/*
homeassistant/components/*/ihc.py homeassistant/components/*/ihc.py
homeassistant/components/insteon/*
homeassistant/components/*/insteon.py
homeassistant/components/insteon_local.py homeassistant/components/insteon_local.py
homeassistant/components/*/insteon_local.py
homeassistant/components/insteon_plm.py
homeassistant/components/insteon_plm/*
homeassistant/components/*/insteon_plm.py
homeassistant/components/ios.py homeassistant/components/ios.py
homeassistant/components/*/ios.py homeassistant/components/*/ios.py

View File

@ -2,15 +2,15 @@
Support for INSTEON dimmers via PowerLinc Modem. Support for INSTEON dimmers via PowerLinc Modem.
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/binary_sensor.insteon_plm/ https://home-assistant.io/components/binary_sensor.insteon/
""" """
import asyncio import asyncio
import logging import logging
from homeassistant.components.binary_sensor import BinarySensorDevice 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__) _LOGGER = logging.getLogger(__name__)
@ -24,27 +24,27 @@ SENSOR_TYPES = {'openClosedSensor': 'opening',
@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):
"""Set up the INSTEON PLM device class for the hass platform.""" """Set up the INSTEON device class for the hass platform."""
plm = hass.data['insteon_plm'].get('plm') insteon_modem = hass.data['insteon'].get('modem')
address = discovery_info['address'] address = discovery_info['address']
device = plm.devices[address] device = insteon_modem.devices[address]
state_key = discovery_info['state_key'] state_key = discovery_info['state_key']
name = device.states[state_key].name name = device.states[state_key].name
if name != 'dryLeakSensor': if name != 'dryLeakSensor':
_LOGGER.debug('Adding device %s entity %s to Binary Sensor platform', _LOGGER.debug('Adding device %s entity %s to Binary Sensor platform',
device.address.hex, device.states[state_key].name) 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]) async_add_devices([new_entity])
class InsteonPLMBinarySensor(InsteonPLMEntity, BinarySensorDevice): class InsteonBinarySensor(InsteonEntity, BinarySensorDevice):
"""A Class for an Insteon device entity.""" """A Class for an Insteon device entity."""
def __init__(self, device, state_key): def __init__(self, device, state_key):
"""Initialize the INSTEON PLM binary sensor.""" """Initialize the INSTEON binary sensor."""
super().__init__(device, state_key) super().__init__(device, state_key)
self._sensor_type = SENSOR_TYPES.get(self._insteon_device_state.name) self._sensor_type = SENSOR_TYPES.get(self._insteon_device_state.name)

View File

@ -2,7 +2,7 @@
Support for INSTEON fans via PowerLinc Modem. Support for INSTEON fans via PowerLinc Modem.
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/fan.insteon_plm/ https://home-assistant.io/components/fan.insteon/
""" """
import asyncio import asyncio
import logging import logging
@ -14,9 +14,9 @@ from homeassistant.components.fan import (SPEED_OFF,
FanEntity, FanEntity,
SUPPORT_SET_SPEED) SUPPORT_SET_SPEED)
from homeassistant.const import STATE_OFF 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_TO_HEX = {SPEED_OFF: 0x00,
SPEED_LOW: 0x3f, SPEED_LOW: 0x3f,
@ -30,22 +30,22 @@ _LOGGER = logging.getLogger(__name__)
@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):
"""Set up the INSTEON PLM device class for the hass platform.""" """Set up the INSTEON device class for the hass platform."""
plm = hass.data['insteon_plm'].get('plm') insteon_modem = hass.data['insteon'].get('modem')
address = discovery_info['address'] address = discovery_info['address']
device = plm.devices[address] device = insteon_modem.devices[address]
state_key = discovery_info['state_key'] state_key = discovery_info['state_key']
_LOGGER.debug('Adding device %s entity %s to Fan platform', _LOGGER.debug('Adding device %s entity %s to Fan platform',
device.address.hex, device.states[state_key].name) 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]) async_add_devices([new_entity])
class InsteonPLMFan(InsteonPLMEntity, FanEntity): class InsteonFan(InsteonEntity, FanEntity):
"""An INSTEON fan component.""" """An INSTEON fan component."""
@property @property

View File

@ -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

View File

@ -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 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 asyncio
import collections import collections
@ -12,18 +12,24 @@ import voluptuous as vol
from homeassistant.core import callback from homeassistant.core import callback
from homeassistant.const import (CONF_PORT, EVENT_HOMEASSISTANT_STOP, from homeassistant.const import (CONF_PORT, EVENT_HOMEASSISTANT_STOP,
CONF_PLATFORM, CONF_PLATFORM,
CONF_ENTITY_ID) CONF_ENTITY_ID,
CONF_HOST)
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
from homeassistant.helpers import discovery from homeassistant.helpers import discovery
from homeassistant.helpers.entity import Entity from homeassistant.helpers.entity import Entity
REQUIREMENTS = ['insteonplm==0.11.7'] REQUIREMENTS = ['insteonplm==0.12.3']
_LOGGER = logging.getLogger(__name__) _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_OVERRIDE = 'device_override'
CONF_PLM_HUB_MSG = ('Must configure either a PLM port or a Hub host, username '
'and password')
CONF_ADDRESS = 'address' CONF_ADDRESS = 'address'
CONF_CAT = 'cat' CONF_CAT = 'cat'
CONF_SUBCAT = 'subcat' CONF_SUBCAT = 'subcat'
@ -56,8 +62,8 @@ HOUSECODES = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p'] 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p']
BUTTON_PRESSED_STATE_NAME = 'onLevelButton' BUTTON_PRESSED_STATE_NAME = 'onLevelButton'
EVENT_BUTTON_ON = 'insteon_plm.button_on' EVENT_BUTTON_ON = 'insteon.button_on'
EVENT_BUTTON_OFF = 'insteon_plm.button_off' EVENT_BUTTON_OFF = 'insteon.button_off'
EVENT_CONF_BUTTON = 'button' EVENT_CONF_BUTTON = 'button'
CONF_DEVICE_OVERRIDE_SCHEMA = vol.All( CONF_DEVICE_OVERRIDE_SCHEMA = vol.All(
@ -79,17 +85,34 @@ CONF_X10_SCHEMA = vol.All(
})) }))
CONFIG_SCHEMA = vol.Schema({ CONFIG_SCHEMA = vol.Schema({
DOMAIN: vol.Schema({ DOMAIN: vol.All(
vol.Required(CONF_PORT): cv.string, vol.Schema(
vol.Optional(CONF_OVERRIDE): vol.All( {vol.Exclusive(CONF_PORT, 'plm_or_hub',
cv.ensure_list_csv, [CONF_DEVICE_OVERRIDE_SCHEMA]), msg=CONF_PLM_HUB_MSG): cv.isdevice,
vol.Optional(CONF_X10_ALL_UNITS_OFF): vol.In(HOUSECODES), vol.Exclusive(CONF_HOST, 'plm_or_hub',
vol.Optional(CONF_X10_ALL_LIGHTS_ON): vol.In(HOUSECODES), msg=CONF_PLM_HUB_MSG): cv.string,
vol.Optional(CONF_X10_ALL_LIGHTS_OFF): vol.In(HOUSECODES), vol.Optional(CONF_IP_PORT, default=25105): int,
vol.Optional(CONF_X10): vol.All( vol.Optional(CONF_HUB_USERNAME): cv.string,
cv.ensure_list_csv, [CONF_X10_SCHEMA]) vol.Optional(CONF_HUB_PASSWORD): cv.string,
}) vol.Optional(CONF_OVERRIDE): vol.All(
}, extra=vol.ALLOW_EXTRA) 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({ ADD_ALL_LINK_SCHEMA = vol.Schema({
vol.Required(SRV_ALL_LINK_GROUP): vol.Range(min=0, max=255), vol.Required(SRV_ALL_LINK_GROUP): vol.Range(min=0, max=255),
@ -116,14 +139,18 @@ X10_HOUSECODE_SCHEMA = vol.Schema({
@asyncio.coroutine @asyncio.coroutine
def async_setup(hass, config): def async_setup(hass, config):
"""Set up the connection to the PLM.""" """Set up the connection to the modem."""
import insteonplm import insteonplm
ipdb = IPDB() ipdb = IPDB()
plm = None insteon_modem = None
conf = config[DOMAIN] conf = config[DOMAIN]
port = conf.get(CONF_PORT) 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, []) overrides = conf.get(CONF_OVERRIDE, [])
x10_devices = conf.get(CONF_X10, []) x10_devices = conf.get(CONF_X10, [])
x10_all_units_off_housecode = conf.get(CONF_X10_ALL_UNITS_OFF) 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) x10_all_lights_off_housecode = conf.get(CONF_X10_ALL_LIGHTS_OFF)
@callback @callback
def async_plm_new_device(device): def async_new_insteon_device(device):
"""Detect device from transport to be delegated to platform.""" """Detect device from transport to be delegated to platform."""
for state_key in device.states: for state_key in device.states:
platform_info = ipdb[device.states[state_key]] platform_info = ipdb[device.states[state_key]]
@ -143,7 +170,7 @@ def async_setup(hass, config):
_fire_button_on_off_event) _fire_button_on_off_event)
else: else:
_LOGGER.info("New INSTEON PLM device: %s (%s) %s", _LOGGER.info("New INSTEON device: %s (%s) %s",
device.address, device.address,
device.states[state_key].name, device.states[state_key].name,
platform) platform)
@ -160,12 +187,12 @@ def async_setup(hass, config):
group = service.data.get(SRV_ALL_LINK_GROUP) group = service.data.get(SRV_ALL_LINK_GROUP)
mode = service.data.get(SRV_ALL_LINK_MODE) mode = service.data.get(SRV_ALL_LINK_MODE)
link_mode = 1 if mode.lower() == SRV_CONTROLLER else 0 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): def del_all_link(service):
"""Delete an INSTEON All-Link between two devices.""" """Delete an INSTEON All-Link between two devices."""
group = service.data.get(SRV_ALL_LINK_GROUP) 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): def load_aldb(service):
"""Load the device All-Link database.""" """Load the device All-Link database."""
@ -194,22 +221,22 @@ def async_setup(hass, config):
"""Print the All-Link Database for a device.""" """Print the All-Link Database for a device."""
# For now this sends logs to the log file. # For now this sends logs to the log file.
# Furture direction is to create an INSTEON control panel. # 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): def x10_all_units_off(service):
"""Send the X10 All Units Off command.""" """Send the X10 All Units Off command."""
housecode = service.data.get(SRV_HOUSECODE) 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): def x10_all_lights_off(service):
"""Send the X10 All Lights Off command.""" """Send the X10 All Lights Off command."""
housecode = service.data.get(SRV_HOUSECODE) 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): def x10_all_lights_on(service):
"""Send the X10 All Lights On command.""" """Send the X10 All Lights On command."""
housecode = service.data.get(SRV_HOUSECODE) housecode = service.data.get(SRV_HOUSECODE)
plm.x10_all_lights_on(housecode) insteon_modem.x10_all_lights_on(housecode)
def _register_services(): def _register_services():
hass.services.register(DOMAIN, SRV_ADD_ALL_LINK, add_all_link, 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, hass.services.register(DOMAIN, SRV_X10_ALL_LIGHTS_ON,
x10_all_lights_on, x10_all_lights_on,
schema=X10_HOUSECODE_SCHEMA) schema=X10_HOUSECODE_SCHEMA)
_LOGGER.debug("Insteon_plm Services registered") _LOGGER.debug("Insteon Services registered")
def _fire_button_on_off_event(address, group, val): def _fire_button_on_off_event(address, group, val):
# Firing an event when a button is pressed. # 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 state_name = device.states[group].name
button = ("" if state_name == BUTTON_PRESSED_STATE_NAME button = ("" if state_name == BUTTON_PRESSED_STATE_NAME
else state_name[-1].lower()) else state_name[-1].lower())
@ -250,13 +277,23 @@ def async_setup(hass, config):
event, address.hex, button) event, address.hex, button)
hass.bus.fire(event, schema) hass.bus.fire(event, schema)
_LOGGER.info("Looking for PLM on %s", port) if host:
conn = yield from insteonplm.Connection.create( _LOGGER.info('Connecting to Insteon Hub on %s', host)
device=port, conn = yield from insteonplm.Connection.create(
loop=hass.loop, host=host,
workdir=hass.config.config_dir) 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: for device_override in overrides:
# #
@ -265,32 +302,32 @@ def async_setup(hass, config):
address = device_override.get('address') address = device_override.get('address')
for prop in device_override: for prop in device_override:
if prop in [CONF_CAT, CONF_SUBCAT]: if prop in [CONF_CAT, CONF_SUBCAT]:
plm.devices.add_override(address, prop, insteon_modem.devices.add_override(address, prop,
device_override[prop]) device_override[prop])
elif prop in [CONF_FIRMWARE, CONF_PRODUCT_KEY]: elif prop in [CONF_FIRMWARE, CONF_PRODUCT_KEY]:
plm.devices.add_override(address, CONF_PRODUCT_KEY, insteon_modem.devices.add_override(address, CONF_PRODUCT_KEY,
device_override[prop]) device_override[prop])
hass.data[DOMAIN] = {} hass.data[DOMAIN] = {}
hass.data[DOMAIN]['plm'] = plm hass.data[DOMAIN]['modem'] = insteon_modem
hass.data[DOMAIN]['entities'] = {} hass.data[DOMAIN]['entities'] = {}
hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, conn.close) 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: if x10_all_units_off_housecode:
device = plm.add_x10_device(x10_all_units_off_housecode, device = insteon_modem.add_x10_device(x10_all_units_off_housecode,
20, 20,
'allunitsoff') 'allunitsoff')
if x10_all_lights_on_housecode: if x10_all_lights_on_housecode:
device = plm.add_x10_device(x10_all_lights_on_housecode, device = insteon_modem.add_x10_device(x10_all_lights_on_housecode,
21, 21,
'alllightson') 'alllightson')
if x10_all_lights_off_housecode: if x10_all_lights_off_housecode:
device = plm.add_x10_device(x10_all_lights_off_housecode, device = insteon_modem.add_x10_device(x10_all_lights_off_housecode,
22, 22,
'alllightsoff') 'alllightsoff')
for device in x10_devices: for device in x10_devices:
housecode = device.get(CONF_HOUSECODE) housecode = device.get(CONF_HOUSECODE)
unitcode = device.get(CONF_UNITCODE) unitcode = device.get(CONF_UNITCODE)
@ -300,11 +337,11 @@ def async_setup(hass, config):
x10_type = 'dimmable' x10_type = 'dimmable'
elif device.get(CONF_PLATFORM) == 'binary_sensor': elif device.get(CONF_PLATFORM) == 'binary_sensor':
x10_type = '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) housecode, unitcode, x10_type)
device = plm.add_x10_device(housecode, device = insteon_modem.add_x10_device(housecode,
unitcode, unitcode,
x10_type) x10_type)
if device and hasattr(device.states[0x01], 'steps'): if device and hasattr(device.states[0x01], 'steps'):
device.states[0x01].steps = steps device.states[0x01].steps = steps
@ -324,11 +361,14 @@ class IPDB:
from insteonplm.states.onOff import (OnOffSwitch, from insteonplm.states.onOff import (OnOffSwitch,
OnOffSwitch_OutletTop, OnOffSwitch_OutletTop,
OnOffSwitch_OutletBottom, OnOffSwitch_OutletBottom,
OpenClosedRelay) OpenClosedRelay,
OnOffKeypadA,
OnOffKeypad)
from insteonplm.states.dimmable import (DimmableSwitch, from insteonplm.states.dimmable import (DimmableSwitch,
DimmableSwitch_Fan, DimmableSwitch_Fan,
DimmableRemote) DimmableRemote,
DimmableKeypadA)
from insteonplm.states.sensor import (VariableSensor, from insteonplm.states.sensor import (VariableSensor,
OnOffSensor, OnOffSensor,
@ -347,6 +387,8 @@ class IPDB:
State(OnOffSwitch_OutletBottom, 'switch'), State(OnOffSwitch_OutletBottom, 'switch'),
State(OpenClosedRelay, 'switch'), State(OpenClosedRelay, 'switch'),
State(OnOffSwitch, 'switch'), State(OnOffSwitch, 'switch'),
State(OnOffKeypadA, 'switch'),
State(OnOffKeypad, 'switch'),
State(LeakSensorDryWet, 'binary_sensor'), State(LeakSensorDryWet, 'binary_sensor'),
State(IoLincSensor, 'binary_sensor'), State(IoLincSensor, 'binary_sensor'),
@ -357,6 +399,7 @@ class IPDB:
State(DimmableSwitch_Fan, 'fan'), State(DimmableSwitch_Fan, 'fan'),
State(DimmableSwitch, 'light'), State(DimmableSwitch, 'light'),
State(DimmableRemote, 'on_off_events'), State(DimmableRemote, 'on_off_events'),
State(DimmableKeypadA, 'light'),
State(X10DimmableSwitch, 'light'), State(X10DimmableSwitch, 'light'),
State(X10OnOffSwitch, 'switch'), State(X10OnOffSwitch, 'switch'),
@ -382,11 +425,11 @@ class IPDB:
return None return None
class InsteonPLMEntity(Entity): class InsteonEntity(Entity):
"""INSTEON abstract base entity.""" """INSTEON abstract base entity."""
def __init__(self, device, state_key): 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_state = device.states[state_key]
self._insteon_device = device self._insteon_device = device
self._insteon_device.aldb.add_loaded_callback(self._aldb_loaded) self._insteon_device.aldb.add_loaded_callback(self._aldb_loaded)
@ -429,11 +472,17 @@ class InsteonPLMEntity(Entity):
@callback @callback
def async_entity_update(self, deviceid, statename, val): def async_entity_update(self, deviceid, statename, val):
"""Receive notification from transport that new data exists.""" """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() self.async_schedule_update_ha_state()
@asyncio.coroutine @asyncio.coroutine
def async_added_to_hass(self): def async_added_to_hass(self):
"""Register INSTEON update events.""" """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._insteon_device_state.register_updates(
self.async_entity_update) self.async_entity_update)
self.hass.data[DOMAIN]['entities'][self.entity_id] = self 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) _LOGGER.info('ALDB load status is %s', aldb.status.name)
if aldb.status not in [ALDBStatus.LOADED, ALDBStatus.PARTIAL]: if aldb.status not in [ALDBStatus.LOADED, ALDBStatus.PARTIAL]:
_LOGGER.warning('Device All-Link database not loaded') _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 return
_LOGGER.info('RecID In Use Mode HWM Group Address Data 1 Data 2 Data 3') _LOGGER.info('RecID In Use Mode HWM Group Address Data 1 Data 2 Data 3')

View File

@ -5,82 +5,24 @@ For more details about this component, please refer to the documentation at
https://home-assistant.io/components/insteon_local/ https://home-assistant.io/components/insteon_local/
""" """
import logging 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__) _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): def setup(hass, config):
"""Set up the local Insteon hub.""" """Setup the insteon_local component.
from insteonlocal.Hub import Hub
conf = config[DOMAIN] This component is depreciated as of release 0.77 and should be removed in
username = conf.get(CONF_USERNAME) release 0.90.
password = conf.get(CONF_PASSWORD) """
host = conf.get(CONF_HOST) _LOGGER.warning('The insteon_local comonent has been replaced by '
port = conf.get(CONF_PORT) 'the insteon component')
timeout = conf.get(CONF_TIMEOUT) _LOGGER.warning('Please see https://home-assistant.io/components/insteon')
try: hass.components.persistent_notification.create(
if not os.path.exists(hass.config.path(INSTEON_CACHE)): 'insteon_local has been replaced by the insteon component.<br />'
os.makedirs(hass.config.path(INSTEON_CACHE)) '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, return False
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

View File

@ -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.<br />'
'Please see https://home-assistant.io/components/insteon',
title='insteon_plm Component Deactivated',
notification_id='insteon_plm')
return False

View File

@ -2,40 +2,40 @@
Support for Insteon lights via PowerLinc Modem. Support for Insteon lights via PowerLinc Modem.
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/light.insteon_plm/ https://home-assistant.io/components/light.insteon/
""" """
import asyncio import asyncio
import logging import logging
from homeassistant.components.insteon_plm import InsteonPLMEntity from homeassistant.components.insteon import InsteonEntity
from homeassistant.components.light import ( from homeassistant.components.light import (
ATTR_BRIGHTNESS, SUPPORT_BRIGHTNESS, Light) ATTR_BRIGHTNESS, SUPPORT_BRIGHTNESS, Light)
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
DEPENDENCIES = ['insteon_plm'] DEPENDENCIES = ['insteon']
MAX_BRIGHTNESS = 255 MAX_BRIGHTNESS = 255
@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):
"""Set up the Insteon PLM device.""" """Set up the Insteon component."""
plm = hass.data['insteon_plm'].get('plm') insteon_modem = hass.data['insteon'].get('modem')
address = discovery_info['address'] address = discovery_info['address']
device = plm.devices[address] device = insteon_modem.devices[address]
state_key = discovery_info['state_key'] state_key = discovery_info['state_key']
_LOGGER.debug('Adding device %s entity %s to Light platform', _LOGGER.debug('Adding device %s entity %s to Light platform',
device.address.hex, device.states[state_key].name) 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]) async_add_devices([new_entity])
class InsteonPLMDimmerDevice(InsteonPLMEntity, Light): class InsteonDimmerDevice(InsteonEntity, Light):
"""A Class for an Insteon device.""" """A Class for an Insteon device."""
@property @property

View File

@ -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()

View File

@ -2,35 +2,35 @@
Support for INSTEON dimmers via PowerLinc Modem. Support for INSTEON dimmers via PowerLinc Modem.
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/sensor.insteon_plm/ https://home-assistant.io/components/sensor.insteon/
""" """
import asyncio import asyncio
import logging import logging
from homeassistant.components.insteon_plm import InsteonPLMEntity from homeassistant.components.insteon import InsteonEntity
from homeassistant.helpers.entity import Entity from homeassistant.helpers.entity import Entity
DEPENDENCIES = ['insteon_plm'] DEPENDENCIES = ['insteon']
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@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):
"""Set up the INSTEON PLM device class for the hass platform.""" """Set up the INSTEON device class for the hass platform."""
plm = hass.data['insteon_plm'].get('plm') insteon_modem = hass.data['insteon'].get('modem')
address = discovery_info['address'] address = discovery_info['address']
device = plm.devices[address] device = insteon_modem.devices[address]
state_key = discovery_info['state_key'] state_key = discovery_info['state_key']
_LOGGER.debug('Adding device %s entity %s to Sensor platform', _LOGGER.debug('Adding device %s entity %s to Sensor platform',
device.address.hex, device.states[state_key].name) 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]) async_add_devices([new_entity])
class InsteonPLMSensorDevice(InsteonPLMEntity, Entity): class InsteonSensorDevice(InsteonEntity, Entity):
"""A Class for an Insteon device.""" """A Class for an Insteon device."""

View File

@ -2,26 +2,26 @@
Support for INSTEON dimmers via PowerLinc Modem. Support for INSTEON dimmers via PowerLinc Modem.
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/switch.insteon_plm/ https://home-assistant.io/components/switch.insteon/
""" """
import asyncio import asyncio
import logging import logging
from homeassistant.components.insteon_plm import InsteonPLMEntity from homeassistant.components.insteon import InsteonEntity
from homeassistant.components.switch import SwitchDevice from homeassistant.components.switch import SwitchDevice
DEPENDENCIES = ['insteon_plm'] DEPENDENCIES = ['insteon']
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@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):
"""Set up the INSTEON PLM device class for the hass platform.""" """Set up the INSTEON device class for the hass platform."""
plm = hass.data['insteon_plm'].get('plm') insteon_modem = hass.data['insteon'].get('modem')
address = discovery_info['address'] address = discovery_info['address']
device = plm.devices[address] device = insteon_modem.devices[address]
state_key = discovery_info['state_key'] state_key = discovery_info['state_key']
state_name = device.states[state_key].name 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) device.address.hex, device.states[state_key].name)
new_entity = None new_entity = None
if state_name in ['lightOnOff', 'outletTopOnOff', 'outletBottomOnOff', if state_name == 'openClosedRelay':
'x10OnOffSwitch']: new_entity = InsteonOpenClosedDevice(device, state_key)
new_entity = InsteonPLMSwitchDevice(device, state_key) else:
elif state_name == 'openClosedRelay': new_entity = InsteonSwitchDevice(device, state_key)
new_entity = InsteonPLMOpenClosedDevice(device, state_key)
if new_entity is not None: if new_entity is not None:
async_add_devices([new_entity]) async_add_devices([new_entity])
class InsteonPLMSwitchDevice(InsteonPLMEntity, SwitchDevice): class InsteonSwitchDevice(InsteonEntity, SwitchDevice):
"""A Class for an Insteon device.""" """A Class for an Insteon device."""
@property @property
@ -59,7 +58,7 @@ class InsteonPLMSwitchDevice(InsteonPLMEntity, SwitchDevice):
self._insteon_device_state.off() self._insteon_device_state.off()
class InsteonPLMOpenClosedDevice(InsteonPLMEntity, SwitchDevice): class InsteonOpenClosedDevice(InsteonEntity, SwitchDevice):
"""A Class for an Insteon device.""" """A Class for an Insteon device."""
@property @property

View File

@ -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

View File

@ -468,11 +468,8 @@ ihcsdk==2.2.0
# homeassistant.components.sensor.influxdb # homeassistant.components.sensor.influxdb
influxdb==5.0.0 influxdb==5.0.0
# homeassistant.components.insteon_local # homeassistant.components.insteon
insteonlocal==0.53 insteonplm==0.12.3
# homeassistant.components.insteon_plm
insteonplm==0.11.7
# homeassistant.components.sensor.iperf3 # homeassistant.components.sensor.iperf3
iperf3==0.1.10 iperf3==0.1.10