diff --git a/.coveragerc b/.coveragerc index 91dbea13b21..348f7486541 100644 --- a/.coveragerc +++ b/.coveragerc @@ -59,6 +59,9 @@ omit = homeassistant/components/lutron.py homeassistant/components/*/lutron.py + homeassistant/components/lutron_caseta.py + homeassistant/components/*/lutron_caseta.py + homeassistant/components/modbus.py homeassistant/components/*/modbus.py diff --git a/homeassistant/components/light/lutron_caseta.py b/homeassistant/components/light/lutron_caseta.py new file mode 100644 index 00000000000..aef3f8ae799 --- /dev/null +++ b/homeassistant/components/light/lutron_caseta.py @@ -0,0 +1,64 @@ +"""Support for Lutron Caseta lights.""" +import logging + +from homeassistant.components.light import ( + ATTR_BRIGHTNESS, SUPPORT_BRIGHTNESS, Light) +from homeassistant.components.light.lutron import ( + to_hass_level, to_lutron_level) +from homeassistant.components.lutron_caseta import ( + LUTRON_CASETA_SMARTBRIDGE, LutronCasetaDevice) + + +_LOGGER = logging.getLogger(__name__) + +DEPENDENCIES = ['lutron_caseta'] + + +# pylint: disable=unused-argument +def setup_platform(hass, config, add_devices, discovery_info=None): + """Setup Lutron Caseta lights.""" + devs = [] + bridge = hass.data[LUTRON_CASETA_SMARTBRIDGE] + light_devices = bridge.get_devices_by_type("WallDimmer") + for light_device in light_devices: + dev = LutronCasetaLight(light_device, bridge) + devs.append(dev) + + add_devices(devs, True) + + +class LutronCasetaLight(LutronCasetaDevice, Light): + """Representation of a Lutron Light, including dimmable.""" + + @property + def supported_features(self): + """Flag supported features.""" + return SUPPORT_BRIGHTNESS + + @property + def brightness(self): + """Return the brightness of the light.""" + return to_hass_level(self._state["current_state"]) + + def turn_on(self, **kwargs): + """Turn the light on.""" + if ATTR_BRIGHTNESS in kwargs and self._device_type == "WallDimmer": + brightness = kwargs[ATTR_BRIGHTNESS] + else: + brightness = 255 + self._smartbridge.set_value(self._device_id, + to_lutron_level(brightness)) + + def turn_off(self, **kwargs): + """Turn the light off.""" + self._smartbridge.set_value(self._device_id, 0) + + @property + def is_on(self): + """Return true if device is on.""" + return self._state["current_state"] > 0 + + def update(self): + """Called when forcing a refresh of the device.""" + self._state = self._smartbridge.get_device_by_id(self._device_id) + _LOGGER.debug(self._state) diff --git a/homeassistant/components/lutron_caseta.py b/homeassistant/components/lutron_caseta.py new file mode 100644 index 00000000000..6cb42618af2 --- /dev/null +++ b/homeassistant/components/lutron_caseta.py @@ -0,0 +1,100 @@ +""" +Component for interacting with a Lutron Caseta system. + +For more details about this component, please refer to the documentation at +https://home-assistant.io/components/lutron_caseta/ +""" +import asyncio +import logging + +import voluptuous as vol + +import homeassistant.helpers.config_validation as cv +from homeassistant.const import (CONF_HOST, + CONF_USERNAME, + CONF_PASSWORD) +from homeassistant.helpers import discovery +from homeassistant.helpers.entity import Entity + +REQUIREMENTS = ['https://github.com/gurumitts/' + 'pylutron-caseta/archive/v0.2.4.zip#' + 'pylutron-caseta==v0.2.4'] + +_LOGGER = logging.getLogger(__name__) + +LUTRON_CASETA_SMARTBRIDGE = 'lutron_smartbridge' + +DOMAIN = 'lutron_caseta' + +CONFIG_SCHEMA = vol.Schema({ + DOMAIN: vol.Schema({ + vol.Required(CONF_HOST): cv.string, + vol.Required(CONF_USERNAME): cv.string, + vol.Required(CONF_PASSWORD): cv.string + }) +}, extra=vol.ALLOW_EXTRA) + + +def setup(hass, base_config): + """Setup the Lutron component.""" + from pylutron_caseta.smartbridge import Smartbridge + + config = base_config.get(DOMAIN) + hass.data[LUTRON_CASETA_SMARTBRIDGE] = Smartbridge( + hostname=config[CONF_HOST], + username=config[CONF_USERNAME], + password=config[CONF_PASSWORD] + ) + if not hass.data[LUTRON_CASETA_SMARTBRIDGE].is_connected(): + _LOGGER.error("Unable to connect to Lutron smartbridge at %s", + config[CONF_HOST]) + return False + + _LOGGER.info("Connected to Lutron smartbridge at %s", + config[CONF_HOST]) + + for component in ('light', 'switch'): + discovery.load_platform(hass, component, DOMAIN, {}, config) + + return True + + +class LutronCasetaDevice(Entity): + """Common base class for all Lutron Caseta devices.""" + + def __init__(self, device, bridge): + """Set up the base class. + + [:param]device the device metadata + [:param]bridge the smartbridge object + """ + self._device_id = device["device_id"] + self._device_type = device["type"] + self._device_name = device["name"] + self._state = None + self._smartbridge = bridge + + @asyncio.coroutine + def async_added_to_hass(self): + """Register callbacks.""" + self._smartbridge.add_subscriber(self._device_id, + self._update_callback) + + def _update_callback(self): + self.schedule_update_ha_state() + + @property + def name(self): + """Return the name of the device.""" + return self._device_name + + @property + def device_state_attributes(self): + """Return the state attributes.""" + attr = {'Lutron Integration ID': self._device_id} + return attr + + @property + def should_poll(self): + """No polling needed.""" + return False diff --git a/homeassistant/components/switch/lutron_caseta.py b/homeassistant/components/switch/lutron_caseta.py new file mode 100644 index 00000000000..a8fca67e91a --- /dev/null +++ b/homeassistant/components/switch/lutron_caseta.py @@ -0,0 +1,48 @@ +"""Support for Lutron Caseta switches.""" +import logging + +from homeassistant.components.lutron_caseta import ( + LUTRON_CASETA_SMARTBRIDGE, LutronCasetaDevice) +from homeassistant.components.switch import SwitchDevice + + +_LOGGER = logging.getLogger(__name__) + +DEPENDENCIES = ['lutron_caseta'] + + +# pylint: disable=unused-argument +def setup_platform(hass, config, add_devices, discovery_info=None): + """Setup Lutron switch.""" + devs = [] + bridge = hass.data[LUTRON_CASETA_SMARTBRIDGE] + switch_devices = bridge.get_devices_by_type("WallSwitch") + + for switch_device in switch_devices: + dev = LutronCasetaLight(switch_device, bridge) + devs.append(dev) + + add_devices(devs, True) + return True + + +class LutronCasetaLight(LutronCasetaDevice, SwitchDevice): + """Representation of a Lutron Caseta switch.""" + + def turn_on(self, **kwargs): + """Turn the switch on.""" + self._smartbridge.turn_on(self._device_id) + + def turn_off(self, **kwargs): + """Turn the switch off.""" + self._smartbridge.turn_off(self._device_id) + + @property + def is_on(self): + """Return true if device is on.""" + return self._state["current_state"] > 0 + + def update(self): + """Called when forcing a refresh of the device.""" + self._state = self._smartbridge.get_device_by_id(self._device_id) + _LOGGER.debug(self._state) diff --git a/requirements_all.txt b/requirements_all.txt old mode 100755 new mode 100644 index 60352b4febb..8527b9000e2 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -251,6 +251,9 @@ https://github.com/bashwork/pymodbus/archive/d7fc4f1cc975631e0a9011390e8017f64b6 # homeassistant.components.media_player.onkyo https://github.com/danieljkemp/onkyo-eiscp/archive/python3.zip#onkyo-eiscp==0.9.2 +# homeassistant.components.lutron_caseta +https://github.com/gurumitts/pylutron-caseta/archive/v0.2.4.zip#pylutron-caseta==v0.2.4 + # homeassistant.components.netatmo https://github.com/jabesq/netatmo-api-python/archive/v0.9.1.zip#lnetatmo==0.9.1