1) Performed many pylint and flake8 fixes to clean up isy994 integration and hidden entities addition. 2) Added necessary code to allow groups to also be hidden. 3) Made most of the weather data from the isy994 component be hidden by default.

This commit is contained in:
Ryan Kraus 2015-04-15 02:05:34 -04:00
parent caed69d5ea
commit b20424261c
6 changed files with 85 additions and 30 deletions

View File

@ -625,8 +625,8 @@ class StateMachine(object):
# components that don't use the Entity base class for their entities. # components that don't use the Entity base class for their entities.
# The sun component is an example of this. The Entity class cannot be # The sun component is an example of this. The Entity class cannot be
# imported cleanly, so assume the state is shown. This means that for # imported cleanly, so assume the state is shown. This means that for
# visibility to be supported, the state must originate from a class that # visibility to be supported, the state must originate from a class
# uses the base class Entity or it must manually put the hidden # that uses the base class Entity or it must manually put the hidden
# attribute in its attributes dictionary. # attribute in its attributes dictionary.
if ATTR_HIDDEN not in attributes: if ATTR_HIDDEN not in attributes:
attributes[ATTR_HIDDEN] = False attributes[ATTR_HIDDEN] = False

View File

@ -208,7 +208,7 @@ def process_ha_core_config(hass, config):
if key in config: if key in config:
setattr(hass.config, attr, config[key]) setattr(hass.config, attr, config[key])
Entity._visibility.update(config.get('visibility', [{}])[0]) Entity.visibility.update(config.get('visibility', [{}])[0])
if CONF_TEMPERATURE_UNIT in config: if CONF_TEMPERATURE_UNIT in config:
unit = config[CONF_TEMPERATURE_UNIT] unit = config[CONF_TEMPERATURE_UNIT]

View File

@ -7,10 +7,11 @@ Provides functionality to group devices that can be turned on or off.
import homeassistant as ha import homeassistant as ha
from homeassistant.helpers import generate_entity_id from homeassistant.helpers import generate_entity_id
from homeassistant.helpers.entity import Entity
import homeassistant.util as util import homeassistant.util as util
from homeassistant.const import ( from homeassistant.const import (
ATTR_ENTITY_ID, ATTR_FRIENDLY_NAME, STATE_ON, STATE_OFF, ATTR_ENTITY_ID, ATTR_FRIENDLY_NAME, STATE_ON, STATE_OFF,
STATE_HOME, STATE_NOT_HOME, STATE_UNKNOWN) STATE_HOME, STATE_NOT_HOME, STATE_UNKNOWN, ATTR_HIDDEN)
DOMAIN = "group" DOMAIN = "group"
DEPENDENCIES = [] DEPENDENCIES = []
@ -112,6 +113,10 @@ def setup(hass, config):
class Group(object): class Group(object):
""" Tracks a group of entity ids. """ """ Tracks a group of entity ids. """
visibility = Entity.visibility
_hidden = False
def __init__(self, hass, name, entity_ids=None, user_defined=True): def __init__(self, hass, name, entity_ids=None, user_defined=True):
self.hass = hass self.hass = hass
self.name = name self.name = name
@ -138,7 +143,8 @@ class Group(object):
return { return {
ATTR_ENTITY_ID: self.tracking, ATTR_ENTITY_ID: self.tracking,
ATTR_AUTO: not self.user_defined, ATTR_AUTO: not self.user_defined,
ATTR_FRIENDLY_NAME: self.name ATTR_FRIENDLY_NAME: self.name,
ATTR_HIDDEN: self.hidden
} }
def update_tracked_entity_ids(self, entity_ids): def update_tracked_entity_ids(self, entity_ids):
@ -213,6 +219,24 @@ class Group(object):
self.hass.states.set( self.hass.states.set(
self.entity_id, group_off, self.state_attr) self.entity_id, group_off, self.state_attr)
@property
def hidden(self):
"""
Returns the official decision of whether the entity should be hidden.
Any value set by the user in the configuration file will overwrite
whatever the component sets for visibility.
"""
if self.entity_id is not None and \
self.entity_id.lower() in self.visibility:
return self.visibility[self.entity_id.lower()] == 'hide'
else:
return self._hidden
@hidden.setter
def hidden(self, val):
""" Sets the suggestion for visibility. """
self._hidden = bool(val)
def setup_group(hass, name, entity_ids, user_defined=True): def setup_group(hass, name, entity_ids, user_defined=True):
""" Sets up a group state that is the combined state of """ Sets up a group state that is the combined state of

View File

@ -29,15 +29,19 @@ SENSOR_STRING = 'Sensor'
HIDDEN_STRING = '{HIDE ME}' HIDDEN_STRING = '{HIDE ME}'
# setup logger # setup logger
logger = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
def setup(hass, config): def setup(hass, config):
"""
Setup isy994 component.
This will automatically import associated lights, switches, and sensors.
"""
# pylint: disable=global-statement
# check for required values in configuration file # check for required values in configuration file
if not validate_config(config, if not validate_config(config,
{DOMAIN: [CONF_HOST, CONF_USERNAME, CONF_PASSWORD]}, {DOMAIN: [CONF_HOST, CONF_USERNAME, CONF_PASSWORD]},
logger): _LOGGER):
return False return False
# pull and parse standard configuration # pull and parse standard configuration
@ -52,7 +56,7 @@ def setup(hass, config):
addr = addr.replace('https://', '') addr = addr.replace('https://', '')
https = True https = True
else: else:
logger.error('isy994 host value in configuration file is invalid.') _LOGGER.error('isy994 host value in configuration file is invalid.')
return False return False
port = host.port port = host.port
addr = addr.replace(':{}'.format(port), '') addr = addr.replace(':{}'.format(port), '')
@ -65,7 +69,7 @@ def setup(hass, config):
# connect to ISY controller # connect to ISY controller
global ISY global ISY
ISY = PyISY.ISY(addr, port, user, password, use_https=https, log=logger) ISY = PyISY.ISY(addr, port, user, password, use_https=https, log=_LOGGER)
if not ISY.connected: if not ISY.connected:
return False return False
@ -91,6 +95,7 @@ class ISYDeviceABC(ToggleEntity):
_states = [] _states = []
_dtype = None _dtype = None
_domain = None _domain = None
_name = None
def __init__(self, node): def __init__(self, node):
# setup properties # setup properties
@ -98,34 +103,39 @@ class ISYDeviceABC(ToggleEntity):
self.hidden = HIDDEN_STRING in self.raw_name self.hidden = HIDDEN_STRING in self.raw_name
# track changes # track changes
self._changeHandler = self.node.status. \ self._change_handler = self.node.status. \
subscribe('changed', self.onUpdate) subscribe('changed', self.on_update)
def __del__(self): def __del__(self):
""" cleanup subscriptions because it is the right thing to do. """ """ cleanup subscriptions because it is the right thing to do. """
self._changeHandler.unsubscribe() self._change_handler.unsubscribe()
@property @property
def domain(self): def domain(self):
""" Returns the domain of the entity. """
return self._domain return self._domain
@property @property
def dtype(self): def dtype(self):
""" Returns the data type of the entity (binary or analog). """
if self._dtype in ['analog', 'binary']: if self._dtype in ['analog', 'binary']:
return self._dtype return self._dtype
return 'binary' if self._units is None else 'analog' return 'binary' if self.unit_of_measurement is None else 'analog'
@property @property
def should_poll(self): def should_poll(self):
""" Tells Home Assistant not to poll this entity. """
return False return False
@property @property
def value(self): def value(self):
""" returns the unclean value from the controller """ """ returns the unclean value from the controller """
# pylint: disable=protected-access
return self.node.status._val return self.node.status._val
@property @property
def state_attributes(self): def state_attributes(self):
""" Returns the state attributes for the node. """
attr = {ATTR_FRIENDLY_NAME: self.name} attr = {ATTR_FRIENDLY_NAME: self.name}
for name, prop in self._attrs.items(): for name, prop in self._attrs.items():
attr[name] = getattr(self, prop) attr[name] = getattr(self, prop)
@ -134,18 +144,18 @@ class ISYDeviceABC(ToggleEntity):
@property @property
def unique_id(self): def unique_id(self):
""" Returns the id of this isy sensor """ """ Returns the id of this isy sensor """
# pylint: disable=protected-access
return self.node._id return self.node._id
@property @property
def raw_name(self): def raw_name(self):
try: """ Returns the unclean node name. """
return str(self._name) return str(self._name) \
except AttributeError: if self._name is not None else str(self.node.name)
return str(self.node.name)
@property @property
def name(self): def name(self):
""" Returns the name of the node if any. """ """ Returns the cleaned name of the node. """
return self.raw_name.replace(HIDDEN_STRING, '').strip() return self.raw_name.replace(HIDDEN_STRING, '').strip()
def update(self): def update(self):
@ -153,16 +163,18 @@ class ISYDeviceABC(ToggleEntity):
# ISY objects are automatically updated by the ISY's event stream # ISY objects are automatically updated by the ISY's event stream
pass pass
def onUpdate(self, e): def on_update(self, event):
""" Handles the update received event. """ """ Handles the update received event. """
self.update_ha_state() self.update_ha_state()
@property @property
def is_on(self): def is_on(self):
""" Returns boolean response if the node is on. """
return bool(self.value) return bool(self.value)
@property @property
def is_open(self): def is_open(self):
""" Returns boolean respons if the node is open. On = Open. """
return self.is_on return self.is_on
@property @property
@ -178,17 +190,18 @@ class ISYDeviceABC(ToggleEntity):
attrs = [kwargs.get(name) for name in self._onattrs] attrs = [kwargs.get(name) for name in self._onattrs]
self.node.on(*attrs) self.node.on(*attrs)
else: else:
logger.error('ISY cannot turn on sensors.') _LOGGER.error('ISY cannot turn on sensors.')
def turn_off(self, **kwargs): def turn_off(self, **kwargs):
""" turns the device off """ """ turns the device off """
if self.domain is not 'sensor': if self.domain is not 'sensor':
self.node.off() self.node.off()
else: else:
logger.error('ISY cannot turn off sensors.') _LOGGER.error('ISY cannot turn off sensors.')
@property @property
def unit_of_measurement(self): def unit_of_measurement(self):
""" Returns the defined units of measurement or None. """
try: try:
return self.node.units return self.node.units
except AttributeError: except AttributeError:

View File

@ -3,13 +3,29 @@
import logging import logging
# homeassistant imports # homeassistant imports
from homeassistant.components.isy994 import ISY, ISYDeviceABC, SENSOR_STRING from homeassistant.components.isy994 import (ISY, ISYDeviceABC, SENSOR_STRING,
HIDDEN_STRING)
from homeassistant.const import (STATE_OPEN, STATE_CLOSED, STATE_HOME, from homeassistant.const import (STATE_OPEN, STATE_CLOSED, STATE_HOME,
STATE_NOT_HOME, STATE_ON, STATE_OFF) STATE_NOT_HOME, STATE_ON, STATE_OFF)
DEFAULT_HIDDEN_WEATHER = ['Temperature_High', 'Temperature_Low', 'Feels_Like',
'Temperature_Average', 'Pressure', 'Dew_Point',
'Gust_Speed', 'Evapotranspiration',
'Irrigation_Requirement', 'Water_Deficit_Yesterday',
'Elevation', 'Average_Temperature_Tomorrow',
'High_Temperature_Tomorrow',
'Low_Temperature_Tomorrow', 'Humidity_Tomorrow',
'Wind_Speed_Tomorrow', 'Gust_Speed_Tomorrow',
'Rain_Tomorrow', 'Snow_Tomorrow',
'Forecast_Average_Temperature',
'Forecast_High_Temperature',
'Forecast_Low_Temperature', 'Forecast_Humidity',
'Forecast_Rain', 'Forecast_Snow']
def setup_platform(hass, config, add_devices, discovery_info=None): def setup_platform(hass, config, add_devices, discovery_info=None):
""" Sets up the isy994 platform. """ """ Sets up the isy994 platform. """
# pylint: disable=protected-access
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
devs = [] devs = []
# verify connection # verify connection
@ -21,7 +37,8 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
if ISY.climate is not None: if ISY.climate is not None:
for prop in ISY.climate._id2name: for prop in ISY.climate._id2name:
if prop is not None: if prop is not None:
node = WeatherPseudoNode('ISY.weather.' + prop, prop, prefix = HIDDEN_STRING if prop in DEFAULT_HIDDEN_WEATHER else ''
node = WeatherPseudoNode('ISY.weather.' + prop, prefix + prop,
getattr(ISY.climate, prop), getattr(ISY.climate, prop),
getattr(ISY.climate, prop + '_units')) getattr(ISY.climate, prop + '_units'))
devs.append(ISYSensorDevice(node)) devs.append(ISYSensorDevice(node))
@ -42,7 +59,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
# folder does not exist # folder does not exist
pass pass
else: else:
for dtype, name, node_id in folder.children: for _, _, node_id in folder.children:
node = folder[node_id].leaf node = folder[node_id].leaf
devs.append(ISYSensorDevice(node, states)) devs.append(ISYSensorDevice(node, states))
@ -51,6 +68,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
class WeatherPseudoNode(object): class WeatherPseudoNode(object):
""" This class allows weather variable to act as regular nodes. """ """ This class allows weather variable to act as regular nodes. """
# pylint: disable=too-few-public-methods
def __init__(self, device_id, name, status, units=None): def __init__(self, device_id, name, status, units=None):
self._id = device_id self._id = device_id
@ -64,6 +82,6 @@ class ISYSensorDevice(ISYDeviceABC):
_domain = 'sensor' _domain = 'sensor'
def __init__(self, node, states=[]): def __init__(self, node, states=None):
super().__init__(node) super().__init__(node)
self._states = states self._states = states or []

View File

@ -83,7 +83,7 @@ class Entity(object):
hass = None hass = None
entity_id = None entity_id = None
_visibility = {} visibility = {}
def update_ha_state(self, force_refresh=False): def update_ha_state(self, force_refresh=False):
""" """
@ -138,8 +138,8 @@ class Entity(object):
whatever the component sets for visibility. whatever the component sets for visibility.
""" """
if self.entity_id is not None and \ if self.entity_id is not None and \
self.entity_id.lower() in self._visibility: self.entity_id.lower() in self.visibility:
return self._visibility[self.entity_id.lower()] == 'hide' return self.visibility[self.entity_id.lower()] == 'hide'
else: else:
return self._hidden return self._hidden