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.
# 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
# visibility to be supported, the state must originate from a class that
# uses the base class Entity or it must manually put the hidden
# visibility to be supported, the state must originate from a class
# that uses the base class Entity or it must manually put the hidden
# attribute in its attributes dictionary.
if ATTR_HIDDEN not in attributes:
attributes[ATTR_HIDDEN] = False

View File

@ -208,7 +208,7 @@ def process_ha_core_config(hass, config):
if key in config:
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:
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
from homeassistant.helpers import generate_entity_id
from homeassistant.helpers.entity import Entity
import homeassistant.util as util
from homeassistant.const import (
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"
DEPENDENCIES = []
@ -112,6 +113,10 @@ def setup(hass, config):
class Group(object):
""" Tracks a group of entity ids. """
visibility = Entity.visibility
_hidden = False
def __init__(self, hass, name, entity_ids=None, user_defined=True):
self.hass = hass
self.name = name
@ -138,7 +143,8 @@ class Group(object):
return {
ATTR_ENTITY_ID: self.tracking,
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):
@ -213,6 +219,24 @@ class Group(object):
self.hass.states.set(
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):
""" Sets up a group state that is the combined state of

View File

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

View File

@ -3,13 +3,29 @@
import logging
# 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,
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):
""" Sets up the isy994 platform. """
# pylint: disable=protected-access
logger = logging.getLogger(__name__)
devs = []
# verify connection
@ -21,7 +37,8 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
if ISY.climate is not None:
for prop in ISY.climate._id2name:
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 + '_units'))
devs.append(ISYSensorDevice(node))
@ -42,7 +59,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
# folder does not exist
pass
else:
for dtype, name, node_id in folder.children:
for _, _, node_id in folder.children:
node = folder[node_id].leaf
devs.append(ISYSensorDevice(node, states))
@ -51,6 +68,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
class WeatherPseudoNode(object):
""" 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):
self._id = device_id
@ -64,6 +82,6 @@ class ISYSensorDevice(ISYDeviceABC):
_domain = 'sensor'
def __init__(self, node, states=[]):
def __init__(self, node, states=None):
super().__init__(node)
self._states = states
self._states = states or []

View File

@ -83,7 +83,7 @@ class Entity(object):
hass = None
entity_id = None
_visibility = {}
visibility = {}
def update_ha_state(self, force_refresh=False):
"""
@ -138,8 +138,8 @@ class Entity(object):
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'
self.entity_id.lower() in self.visibility:
return self.visibility[self.entity_id.lower()] == 'hide'
else:
return self._hidden