core/homeassistant/components/isy994.py

219 lines
6.2 KiB
Python
Raw Normal View History

2015-04-04 08:33:03 +00:00
"""
2016-03-07 17:49:31 +00:00
Support the ISY-994 controllers.
2015-08-08 17:16:15 +00:00
For configuration details please visit the documentation for this component at
2015-11-09 12:12:18 +00:00
https://home-assistant.io/components/isy994/
2015-04-04 08:33:03 +00:00
"""
import logging
from urllib.parse import urlparse
2016-02-19 05:27:50 +00:00
from homeassistant.const import (
CONF_HOST, CONF_PASSWORD, CONF_USERNAME,
EVENT_HOMEASSISTANT_STOP)
from homeassistant.helpers import validate_config, discovery
2015-04-04 08:33:03 +00:00
from homeassistant.helpers.entity import ToggleEntity
DOMAIN = "isy994"
REQUIREMENTS = ['PyISY==1.0.6']
2015-04-04 08:33:03 +00:00
ISY = None
SENSOR_STRING = 'Sensor'
HIDDEN_STRING = '{HIDE ME}'
CONF_TLS_VER = 'tls'
2015-04-04 08:33:03 +00:00
_LOGGER = logging.getLogger(__name__)
2015-04-04 08:33:03 +00:00
def setup(hass, config):
2016-03-08 16:55:57 +00:00
"""Setup ISY994 component.
This will automatically import associated lights, switches, and sensors.
"""
2016-01-29 05:37:08 +00:00
import PyISY
# pylint: disable=global-statement
# check for required values in configuration file
if not validate_config(config,
{DOMAIN: [CONF_HOST, CONF_USERNAME, CONF_PASSWORD]},
_LOGGER):
2015-04-04 08:33:03 +00:00
return False
2016-03-07 17:49:31 +00:00
# Pull and parse standard configuration.
user = config[DOMAIN][CONF_USERNAME]
password = config[DOMAIN][CONF_PASSWORD]
host = urlparse(config[DOMAIN][CONF_HOST])
addr = host.geturl()
if host.scheme == 'http':
addr = addr.replace('http://', '')
https = False
elif host.scheme == 'https':
addr = addr.replace('https://', '')
https = True
2015-04-04 08:33:03 +00:00
else:
_LOGGER.error('isy994 host value in configuration file is invalid.')
return False
port = host.port
addr = addr.replace(':{}'.format(port), '')
2016-03-07 17:49:31 +00:00
# Pull and parse optional configuration.
global SENSOR_STRING
global HIDDEN_STRING
SENSOR_STRING = str(config[DOMAIN].get('sensor_string', SENSOR_STRING))
HIDDEN_STRING = str(config[DOMAIN].get('hidden_string', HIDDEN_STRING))
tls_version = config[DOMAIN].get(CONF_TLS_VER, None)
2015-04-04 08:33:03 +00:00
2016-03-07 17:49:31 +00:00
# Connect to ISY controller.
2015-04-04 08:33:03 +00:00
global ISY
ISY = PyISY.ISY(addr, port, user, password, use_https=https,
tls_ver=tls_version, log=_LOGGER)
2015-04-04 08:33:03 +00:00
if not ISY.connected:
return False
2016-03-07 17:49:31 +00:00
# Listen for HA stop to disconnect.
hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP, stop)
# Load platforms for the devices in the ISY controller that we support.
for component in ('sensor', 'light', 'switch'):
discovery.load_platform(hass, component, DOMAIN, None, config)
2015-04-04 08:33:03 +00:00
ISY.auto_update = True
return True
def stop(event):
2016-03-07 17:49:31 +00:00
"""Cleanup the ISY subscription."""
ISY.auto_update = False
class ISYDeviceABC(ToggleEntity):
2016-03-07 17:49:31 +00:00
"""An abstract Class for an ISY device."""
2016-03-08 16:55:57 +00:00
_attrs = {}
_onattrs = []
_states = []
_dtype = None
_domain = None
_name = None
def __init__(self, node):
2016-03-08 16:55:57 +00:00
"""Initialize the device."""
# setup properties
self.node = node
# track changes
self._change_handler = self.node.status. \
subscribe('changed', self.on_update)
def __del__(self):
2016-03-07 17:49:31 +00:00
"""Cleanup subscriptions because it is the right thing to do."""
self._change_handler.unsubscribe()
@property
def domain(self):
2016-03-07 17:49:31 +00:00
"""Return the domain of the entity."""
return self._domain
@property
def dtype(self):
2016-03-07 17:49:31 +00:00
"""Return the data type of the entity (binary or analog)."""
if self._dtype in ['analog', 'binary']:
return self._dtype
return 'binary' if self.unit_of_measurement is None else 'analog'
@property
def should_poll(self):
2016-03-07 17:49:31 +00:00
"""No polling needed."""
return False
@property
def value(self):
2016-03-07 17:49:31 +00:00
"""Return the unclean value from the controller."""
# pylint: disable=protected-access
return self.node.status._val
@property
def state_attributes(self):
2016-03-07 17:49:31 +00:00
"""Return the state attributes for the node."""
attr = {}
for name, prop in self._attrs.items():
attr[name] = getattr(self, prop)
attr = self._attr_filter(attr)
return attr
def _attr_filter(self, attr):
2016-03-07 17:49:31 +00:00
"""A Placeholder for attribute filters."""
2015-08-29 00:18:54 +00:00
# pylint: disable=no-self-use
return attr
@property
def unique_id(self):
2016-03-07 17:49:31 +00:00
"""Return the ID of this ISY sensor."""
# pylint: disable=protected-access
return self.node._id
@property
def raw_name(self):
2016-03-07 17:49:31 +00:00
"""Return the unclean node name."""
return str(self._name) \
if self._name is not None else str(self.node.name)
@property
def name(self):
2016-03-07 17:49:31 +00:00
"""Return the cleaned name of the node."""
return self.raw_name.replace(HIDDEN_STRING, '').strip() \
.replace('_', ' ')
2015-12-02 07:32:06 +00:00
@property
def hidden(self):
2016-03-07 17:49:31 +00:00
"""Suggestion if the entity should be hidden from UIs."""
2015-12-02 07:32:06 +00:00
return HIDDEN_STRING in self.raw_name
def update(self):
2016-03-07 17:49:31 +00:00
"""Update state of the sensor."""
# ISY objects are automatically updated by the ISY's event stream
pass
def on_update(self, event):
2016-03-08 16:55:57 +00:00
"""Handle the update received event."""
self.update_ha_state()
@property
def is_on(self):
2016-03-07 17:49:31 +00:00
"""Return a boolean response if the node is on."""
return bool(self.value)
@property
def is_open(self):
2016-03-07 17:49:31 +00:00
"""Return boolean response if the node is open. On = Open."""
return self.is_on
@property
def state(self):
2016-03-07 17:49:31 +00:00
"""Return the state of the node."""
if len(self._states) > 0:
return self._states[0] if self.is_on else self._states[1]
return self.value
def turn_on(self, **kwargs):
2016-03-08 16:55:57 +00:00
"""Turn the device on."""
if self.domain is not 'sensor':
attrs = [kwargs.get(name) for name in self._onattrs]
self.node.on(*attrs)
else:
_LOGGER.error('ISY cannot turn on sensors.')
def turn_off(self, **kwargs):
2016-03-08 16:55:57 +00:00
"""Turn the device off."""
if self.domain is not 'sensor':
self.node.off()
else:
_LOGGER.error('ISY cannot turn off sensors.')
@property
def unit_of_measurement(self):
2016-03-07 17:49:31 +00:00
"""Return the defined units of measurement or None."""
try:
return self.node.units
except AttributeError:
return None