diff --git a/homeassistant/components/abode.py b/homeassistant/components/abode.py index 677fcab4f5d..c8d4ee67d49 100644 --- a/homeassistant/components/abode.py +++ b/homeassistant/components/abode.py @@ -4,15 +4,20 @@ This component provides basic support for Abode Home Security system. For more details about this component, please refer to the documentation at https://home-assistant.io/components/abode/ """ +import asyncio import logging import voluptuous as vol from requests.exceptions import HTTPError, ConnectTimeout from homeassistant.helpers import discovery from homeassistant.helpers import config_validation as cv -from homeassistant.const import CONF_USERNAME, CONF_PASSWORD, CONF_NAME +from homeassistant.helpers.entity import Entity +from homeassistant.const import (ATTR_ATTRIBUTION, + CONF_USERNAME, CONF_PASSWORD, + CONF_NAME, EVENT_HOMEASSISTANT_STOP, + EVENT_HOMEASSISTANT_START) -REQUIREMENTS = ['abodepy==0.7.1'] +REQUIREMENTS = ['abodepy==0.9.0'] _LOGGER = logging.getLogger(__name__) @@ -20,8 +25,7 @@ CONF_ATTRIBUTION = "Data provided by goabode.com" DOMAIN = 'abode' DEFAULT_NAME = 'Abode' -DATA_ABODE = 'data_abode' -DEFAULT_ENTITY_NAMESPACE = 'abode' +DATA_ABODE = 'abode' NOTIFICATION_ID = 'abode_notification' NOTIFICATION_TITLE = 'Abode Security Setup' @@ -34,19 +38,21 @@ CONFIG_SCHEMA = vol.Schema({ }), }, extra=vol.ALLOW_EXTRA) +ABODE_PLATFORMS = [ + 'alarm_control_panel', 'binary_sensor', 'lock', 'switch', 'cover' +] + def setup(hass, config): """Set up Abode component.""" + import abodepy + conf = config[DOMAIN] username = conf.get(CONF_USERNAME) password = conf.get(CONF_PASSWORD) try: - data = AbodeData(username, password) - hass.data[DATA_ABODE] = data - - for component in ['binary_sensor', 'alarm_control_panel']: - discovery.load_platform(hass, component, DOMAIN, {}, config) + hass.data[DATA_ABODE] = abode = abodepy.Abode(username, password) except (ConnectTimeout, HTTPError) as ex: _LOGGER.error("Unable to connect to Abode: %s", str(ex)) @@ -58,18 +64,62 @@ def setup(hass, config): notification_id=NOTIFICATION_ID) return False + for platform in ABODE_PLATFORMS: + discovery.load_platform(hass, platform, DOMAIN, {}, config) + + def logout(event): + """Logout of Abode.""" + abode.stop_listener() + abode.logout() + _LOGGER.info("Logged out of Abode") + + hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP, logout) + + def startup(event): + """Listen for push events.""" + abode.start_listener() + + hass.bus.listen_once(EVENT_HOMEASSISTANT_START, startup) + return True -class AbodeData: - """Shared Abode data.""" +class AbodeDevice(Entity): + """Representation of an Abode device.""" - def __init__(self, username, password): - """Initialize Abode oject.""" - import abodepy + def __init__(self, controller, device): + """Initialize a sensor for Abode device.""" + self._controller = controller + self._device = device - self.abode = abodepy.Abode(username, password) - self.devices = self.abode.get_devices() + @asyncio.coroutine + def async_added_to_hass(self): + """Subscribe Abode events.""" + self.hass.async_add_job( + self._controller.register, self._device, + self._update_callback + ) - _LOGGER.debug("Abode Security set up with %s devices", - len(self.devices)) + @property + def should_poll(self): + """Return the polling state.""" + return False + + @property + def name(self): + """Return the name of the sensor.""" + return self._device.name + + @property + def device_state_attributes(self): + """Return the state attributes.""" + return { + ATTR_ATTRIBUTION: CONF_ATTRIBUTION, + 'device_id': self._device.device_id, + 'battery_low': self._device.battery_low, + 'no_response': self._device.no_response + } + + def _update_callback(self, device): + """Update the device state.""" + self.schedule_update_ha_state() diff --git a/homeassistant/components/alarm_control_panel/abode.py b/homeassistant/components/alarm_control_panel/abode.py index 7d7ce931c20..7a615ffc7bf 100644 --- a/homeassistant/components/alarm_control_panel/abode.py +++ b/homeassistant/components/alarm_control_panel/abode.py @@ -6,10 +6,12 @@ https://home-assistant.io/components/alarm_control_panel.abode/ """ import logging -from homeassistant.components.abode import (DATA_ABODE, DEFAULT_NAME) -from homeassistant.const import (STATE_ALARM_ARMED_AWAY, +from homeassistant.components.abode import ( + AbodeDevice, DATA_ABODE, DEFAULT_NAME, CONF_ATTRIBUTION) +from homeassistant.components.alarm_control_panel import (AlarmControlPanel) +from homeassistant.const import (ATTR_ATTRIBUTION, STATE_ALARM_ARMED_AWAY, STATE_ALARM_ARMED_HOME, STATE_ALARM_DISARMED) -import homeassistant.components.alarm_control_panel as alarm + DEPENDENCIES = ['abode'] @@ -20,30 +22,19 @@ ICON = 'mdi:security' def setup_platform(hass, config, add_devices, discovery_info=None): """Set up a sensor for an Abode device.""" - data = hass.data.get(DATA_ABODE) + abode = hass.data[DATA_ABODE] - add_devices([AbodeAlarm(hass, data, data.abode.get_alarm())]) + add_devices([AbodeAlarm(abode, abode.get_alarm())]) -class AbodeAlarm(alarm.AlarmControlPanel): +class AbodeAlarm(AbodeDevice, AlarmControlPanel): """An alarm_control_panel implementation for Abode.""" - def __init__(self, hass, data, device): + def __init__(self, controller, device): """Initialize the alarm control panel.""" - super(AbodeAlarm, self).__init__() - self._device = device + AbodeDevice.__init__(self, controller, device) self._name = "{0}".format(DEFAULT_NAME) - @property - def should_poll(self): - """Return the polling state.""" - return True - - @property - def name(self): - """Return the name of the sensor.""" - return self._name - @property def icon(self): """Return icon.""" @@ -52,11 +43,11 @@ class AbodeAlarm(alarm.AlarmControlPanel): @property def state(self): """Return the state of the device.""" - if self._device.mode == "standby": + if self._device.is_standby: state = STATE_ALARM_DISARMED - elif self._device.mode == "away": + elif self._device.is_away: state = STATE_ALARM_ARMED_AWAY - elif self._device.mode == "home": + elif self._device.is_home: state = STATE_ALARM_ARMED_HOME else: state = None @@ -65,18 +56,21 @@ class AbodeAlarm(alarm.AlarmControlPanel): def alarm_disarm(self, code=None): """Send disarm command.""" self._device.set_standby() - self.schedule_update_ha_state() def alarm_arm_home(self, code=None): """Send arm home command.""" self._device.set_home() - self.schedule_update_ha_state() def alarm_arm_away(self, code=None): """Send arm away command.""" self._device.set_away() - self.schedule_update_ha_state() - def update(self): - """Update the device state.""" - self._device.refresh() + @property + def device_state_attributes(self): + """Return the state attributes.""" + return { + ATTR_ATTRIBUTION: CONF_ATTRIBUTION, + 'device_id': self._device.device_id, + 'battery_backup': self._device.battery, + 'cellular_backup': self._device.is_cellular + } diff --git a/homeassistant/components/binary_sensor/abode.py b/homeassistant/components/binary_sensor/abode.py index 9abff53026d..d3b0d662a94 100644 --- a/homeassistant/components/binary_sensor/abode.py +++ b/homeassistant/components/binary_sensor/abode.py @@ -6,76 +6,56 @@ https://home-assistant.io/components/binary_sensor.abode/ """ import logging -from homeassistant.components.abode import (CONF_ATTRIBUTION, DATA_ABODE) -from homeassistant.const import (ATTR_ATTRIBUTION) -from homeassistant.components.binary_sensor import (BinarySensorDevice) +from homeassistant.components.abode import AbodeDevice, DATA_ABODE +from homeassistant.components.binary_sensor import BinarySensorDevice + DEPENDENCIES = ['abode'] _LOGGER = logging.getLogger(__name__) -# Sensor types: Name, device_class -SENSOR_TYPES = { - 'Door Contact': 'opening', - 'Motion Camera': 'motion', -} - def setup_platform(hass, config, add_devices, discovery_info=None): """Set up a sensor for an Abode device.""" - data = hass.data.get(DATA_ABODE) + abode = hass.data[DATA_ABODE] + + device_types = map_abode_device_class().keys() sensors = [] - for sensor in data.devices: - _LOGGER.debug('Sensor type %s', sensor.type) - if sensor.type in ['Door Contact', 'Motion Camera']: - sensors.append(AbodeBinarySensor(hass, data, sensor)) + for sensor in abode.get_devices(type_filter=device_types): + sensors.append(AbodeBinarySensor(abode, sensor)) - _LOGGER.debug('Adding %d sensors', len(sensors)) add_devices(sensors) -class AbodeBinarySensor(BinarySensorDevice): +def map_abode_device_class(): + """Map Abode device types to Home Assistant binary sensor class.""" + import abodepy.helpers.constants as CONST + + return { + CONST.DEVICE_GLASS_BREAK: 'connectivity', + CONST.DEVICE_KEYPAD: 'connectivity', + CONST.DEVICE_DOOR_CONTACT: 'opening', + CONST.DEVICE_STATUS_DISPLAY: 'connectivity', + CONST.DEVICE_MOTION_CAMERA: 'connectivity', + CONST.DEVICE_WATER_SENSOR: 'moisture' + } + + +class AbodeBinarySensor(AbodeDevice, BinarySensorDevice): """A binary sensor implementation for Abode device.""" - def __init__(self, hass, data, device): + def __init__(self, controller, device): """Initialize a sensor for Abode device.""" - super(AbodeBinarySensor, self).__init__() - self._device = device - - @property - def should_poll(self): - """Return the polling state.""" - return True - - @property - def name(self): - """Return the name of the sensor.""" - return "{0} {1}".format(self._device.type, self._device.name) + AbodeDevice.__init__(self, controller, device) + self._device_class = map_abode_device_class().get(self._device.type) @property def is_on(self): """Return True if the binary sensor is on.""" - if self._device.type == 'Door Contact': - return self._device.status != 'Closed' - elif self._device.type == 'Motion Camera': - return self._device.get_value('motion_event') == '1' + return self._device.is_on @property def device_class(self): """Return the class of the binary sensor.""" - return SENSOR_TYPES.get(self._device.type) - - @property - def device_state_attributes(self): - """Return the state attributes.""" - attrs = {} - attrs[ATTR_ATTRIBUTION] = CONF_ATTRIBUTION - attrs['device_id'] = self._device.device_id - attrs['battery_low'] = self._device.battery_low - - return attrs - - def update(self): - """Update the device state.""" - self._device.refresh() + return self._device_class diff --git a/homeassistant/components/cover/abode.py b/homeassistant/components/cover/abode.py new file mode 100644 index 00000000000..b09c9e5e007 --- /dev/null +++ b/homeassistant/components/cover/abode.py @@ -0,0 +1,49 @@ +""" +This component provides HA cover support for Abode Security System. + +For more details about this platform, please refer to the documentation at +https://home-assistant.io/components/cover.abode/ +""" +import logging + +from homeassistant.components.abode import AbodeDevice, DATA_ABODE +from homeassistant.components.cover import CoverDevice + + +DEPENDENCIES = ['abode'] + +_LOGGER = logging.getLogger(__name__) + + +def setup_platform(hass, config, add_devices, discovery_info=None): + """Set up Abode cover devices.""" + import abodepy.helpers.constants as CONST + + abode = hass.data[DATA_ABODE] + + sensors = [] + for sensor in abode.get_devices(type_filter=(CONST.DEVICE_SECURE_BARRIER)): + sensors.append(AbodeCover(abode, sensor)) + + add_devices(sensors) + + +class AbodeCover(AbodeDevice, CoverDevice): + """Representation of an Abode cover.""" + + def __init__(self, controller, device): + """Initialize the Abode device.""" + AbodeDevice.__init__(self, controller, device) + + @property + def is_closed(self): + """Return true if cover is closed, else False.""" + return self._device.is_open is False + + def close_cover(self): + """Issue close command to cover.""" + self._device.close_cover() + + def open_cover(self): + """Issue open command to cover.""" + self._device.open_cover() diff --git a/homeassistant/components/lock/abode.py b/homeassistant/components/lock/abode.py new file mode 100644 index 00000000000..aad720e0d7d --- /dev/null +++ b/homeassistant/components/lock/abode.py @@ -0,0 +1,49 @@ +""" +This component provides HA lock support for Abode Security System. + +For more details about this platform, please refer to the documentation at +https://home-assistant.io/components/lock.abode/ +""" +import logging + +from homeassistant.components.abode import AbodeDevice, DATA_ABODE +from homeassistant.components.lock import LockDevice + + +DEPENDENCIES = ['abode'] + +_LOGGER = logging.getLogger(__name__) + + +def setup_platform(hass, config, add_devices, discovery_info=None): + """Set up Abode lock devices.""" + import abodepy.helpers.constants as CONST + + abode = hass.data[DATA_ABODE] + + sensors = [] + for sensor in abode.get_devices(type_filter=(CONST.DEVICE_DOOR_LOCK)): + sensors.append(AbodeLock(abode, sensor)) + + add_devices(sensors) + + +class AbodeLock(AbodeDevice, LockDevice): + """Representation of an Abode lock.""" + + def __init__(self, controller, device): + """Initialize the Abode device.""" + AbodeDevice.__init__(self, controller, device) + + def lock(self, **kwargs): + """Lock the device.""" + self._device.lock() + + def unlock(self, **kwargs): + """Unlock the device.""" + self._device.unlock() + + @property + def is_locked(self): + """Return true if device is on.""" + return self._device.is_locked diff --git a/homeassistant/components/switch/abode.py b/homeassistant/components/switch/abode.py new file mode 100644 index 00000000000..bed0b9c0b60 --- /dev/null +++ b/homeassistant/components/switch/abode.py @@ -0,0 +1,53 @@ +""" +This component provides HA switch support for Abode Security System. + +For more details about this platform, please refer to the documentation at +https://home-assistant.io/components/switch.abode/ +""" +import logging + +from homeassistant.components.abode import AbodeDevice, DATA_ABODE +from homeassistant.components.switch import SwitchDevice + + +DEPENDENCIES = ['abode'] + +_LOGGER = logging.getLogger(__name__) + + +def setup_platform(hass, config, add_devices, discovery_info=None): + """Set up Abode switch devices.""" + import abodepy.helpers.constants as CONST + + abode = hass.data[DATA_ABODE] + + device_types = [ + CONST.DEVICE_POWER_SWITCH_SENSOR, + CONST.DEVICE_POWER_SWITCH_METER] + + sensors = [] + for sensor in abode.get_devices(type_filter=device_types): + sensors.append(AbodeSwitch(abode, sensor)) + + add_devices(sensors) + + +class AbodeSwitch(AbodeDevice, SwitchDevice): + """Representation of an Abode switch.""" + + def __init__(self, controller, device): + """Initialize the Abode device.""" + AbodeDevice.__init__(self, controller, device) + + def turn_on(self, **kwargs): + """Turn on the device.""" + self._device.switch_on() + + def turn_off(self, **kwargs): + """Turn off the device.""" + self._device.switch_off() + + @property + def is_on(self): + """Return true if device is on.""" + return self._device.is_on diff --git a/requirements_all.txt b/requirements_all.txt index 771b6475be6..b357f9ffc53 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -39,7 +39,7 @@ SoCo==0.12 TwitterAPI==2.4.6 # homeassistant.components.abode -abodepy==0.7.1 +abodepy==0.9.0 # homeassistant.components.device_tracker.automatic aioautomatic==0.6.2