Abode push events and lock, cover, and switch components (#9095)

* Updated abodepy version to 0.7.1

* Refactored to use AbodeDevice. Added Abode Lock device.

* Added push updates to abode devices.

* Upgraded to 0.7.2 after finding issue with callbacks.

* Refactored to use AbodeDevice. Added Abode Lock device.

* Added push updates to abode devices.

* Upgraded to 0.7.2 after finding issue with callbacks.

* Bumped version to 0.8.2. Modified code to work with new constants and properties. Added cover and switch.

* Fixed hound violations.

* Updated to 0.8.3 to fix small bug with standby mode. Fixed comment in cover/abode.py.

* Fix lint issues

* Removed excessive logging. Moved device callback registration to async_added_to_hass. Moved abode controller from global into hass data.

* Removed explicit None from dict.get()

* Move device class into the constructor.

* Changed constant name to platforms.

* Changes as requested.

* Removing stray blank line.

* Added blank line of which I'm not sure how it was removed.

* Updated version to 0.9.0. Fixed motion sensor. Added power_switch_meter device type.

* Update abode.py

* fix lint
This commit is contained in:
Mister Wil 2017-08-29 08:34:19 -07:00 committed by Pascal Vizeli
parent 81a00bf3f1
commit 33c906c20a
7 changed files with 270 additions and 95 deletions

View file

@ -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 For more details about this component, please refer to the documentation at
https://home-assistant.io/components/abode/ https://home-assistant.io/components/abode/
""" """
import asyncio
import logging import logging
import voluptuous as vol import voluptuous as vol
from requests.exceptions import HTTPError, ConnectTimeout from requests.exceptions import HTTPError, ConnectTimeout
from homeassistant.helpers import discovery from homeassistant.helpers import discovery
from homeassistant.helpers import config_validation as cv 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__) _LOGGER = logging.getLogger(__name__)
@ -20,8 +25,7 @@ CONF_ATTRIBUTION = "Data provided by goabode.com"
DOMAIN = 'abode' DOMAIN = 'abode'
DEFAULT_NAME = 'Abode' DEFAULT_NAME = 'Abode'
DATA_ABODE = 'data_abode' DATA_ABODE = 'abode'
DEFAULT_ENTITY_NAMESPACE = 'abode'
NOTIFICATION_ID = 'abode_notification' NOTIFICATION_ID = 'abode_notification'
NOTIFICATION_TITLE = 'Abode Security Setup' NOTIFICATION_TITLE = 'Abode Security Setup'
@ -34,19 +38,21 @@ CONFIG_SCHEMA = vol.Schema({
}), }),
}, extra=vol.ALLOW_EXTRA) }, extra=vol.ALLOW_EXTRA)
ABODE_PLATFORMS = [
'alarm_control_panel', 'binary_sensor', 'lock', 'switch', 'cover'
]
def setup(hass, config): def setup(hass, config):
"""Set up Abode component.""" """Set up Abode component."""
import abodepy
conf = config[DOMAIN] conf = config[DOMAIN]
username = conf.get(CONF_USERNAME) username = conf.get(CONF_USERNAME)
password = conf.get(CONF_PASSWORD) password = conf.get(CONF_PASSWORD)
try: try:
data = AbodeData(username, password) hass.data[DATA_ABODE] = abode = abodepy.Abode(username, password)
hass.data[DATA_ABODE] = data
for component in ['binary_sensor', 'alarm_control_panel']:
discovery.load_platform(hass, component, DOMAIN, {}, config)
except (ConnectTimeout, HTTPError) as ex: except (ConnectTimeout, HTTPError) as ex:
_LOGGER.error("Unable to connect to Abode: %s", str(ex)) _LOGGER.error("Unable to connect to Abode: %s", str(ex))
@ -58,18 +64,62 @@ def setup(hass, config):
notification_id=NOTIFICATION_ID) notification_id=NOTIFICATION_ID)
return False 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 return True
class AbodeData: class AbodeDevice(Entity):
"""Shared Abode data.""" """Representation of an Abode device."""
def __init__(self, username, password): def __init__(self, controller, device):
"""Initialize Abode oject.""" """Initialize a sensor for Abode device."""
import abodepy self._controller = controller
self._device = device
self.abode = abodepy.Abode(username, password) @asyncio.coroutine
self.devices = self.abode.get_devices() 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", @property
len(self.devices)) 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()

View file

@ -6,10 +6,12 @@ https://home-assistant.io/components/alarm_control_panel.abode/
""" """
import logging import logging
from homeassistant.components.abode import (DATA_ABODE, DEFAULT_NAME) from homeassistant.components.abode import (
from homeassistant.const import (STATE_ALARM_ARMED_AWAY, 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) STATE_ALARM_ARMED_HOME, STATE_ALARM_DISARMED)
import homeassistant.components.alarm_control_panel as alarm
DEPENDENCIES = ['abode'] DEPENDENCIES = ['abode']
@ -20,30 +22,19 @@ ICON = 'mdi:security'
def setup_platform(hass, config, add_devices, discovery_info=None): def setup_platform(hass, config, add_devices, discovery_info=None):
"""Set up a sensor for an Abode device.""" """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.""" """An alarm_control_panel implementation for Abode."""
def __init__(self, hass, data, device): def __init__(self, controller, device):
"""Initialize the alarm control panel.""" """Initialize the alarm control panel."""
super(AbodeAlarm, self).__init__() AbodeDevice.__init__(self, controller, device)
self._device = device
self._name = "{0}".format(DEFAULT_NAME) 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 @property
def icon(self): def icon(self):
"""Return icon.""" """Return icon."""
@ -52,11 +43,11 @@ class AbodeAlarm(alarm.AlarmControlPanel):
@property @property
def state(self): def state(self):
"""Return the state of the device.""" """Return the state of the device."""
if self._device.mode == "standby": if self._device.is_standby:
state = STATE_ALARM_DISARMED state = STATE_ALARM_DISARMED
elif self._device.mode == "away": elif self._device.is_away:
state = STATE_ALARM_ARMED_AWAY state = STATE_ALARM_ARMED_AWAY
elif self._device.mode == "home": elif self._device.is_home:
state = STATE_ALARM_ARMED_HOME state = STATE_ALARM_ARMED_HOME
else: else:
state = None state = None
@ -65,18 +56,21 @@ class AbodeAlarm(alarm.AlarmControlPanel):
def alarm_disarm(self, code=None): def alarm_disarm(self, code=None):
"""Send disarm command.""" """Send disarm command."""
self._device.set_standby() self._device.set_standby()
self.schedule_update_ha_state()
def alarm_arm_home(self, code=None): def alarm_arm_home(self, code=None):
"""Send arm home command.""" """Send arm home command."""
self._device.set_home() self._device.set_home()
self.schedule_update_ha_state()
def alarm_arm_away(self, code=None): def alarm_arm_away(self, code=None):
"""Send arm away command.""" """Send arm away command."""
self._device.set_away() self._device.set_away()
self.schedule_update_ha_state()
def update(self): @property
"""Update the device state.""" def device_state_attributes(self):
self._device.refresh() """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
}

View file

@ -6,76 +6,56 @@ https://home-assistant.io/components/binary_sensor.abode/
""" """
import logging import logging
from homeassistant.components.abode import (CONF_ATTRIBUTION, DATA_ABODE) from homeassistant.components.abode import AbodeDevice, DATA_ABODE
from homeassistant.const import (ATTR_ATTRIBUTION) from homeassistant.components.binary_sensor import BinarySensorDevice
from homeassistant.components.binary_sensor import (BinarySensorDevice)
DEPENDENCIES = ['abode'] DEPENDENCIES = ['abode']
_LOGGER = logging.getLogger(__name__) _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): def setup_platform(hass, config, add_devices, discovery_info=None):
"""Set up a sensor for an Abode device.""" """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 = [] sensors = []
for sensor in data.devices: for sensor in abode.get_devices(type_filter=device_types):
_LOGGER.debug('Sensor type %s', sensor.type) sensors.append(AbodeBinarySensor(abode, sensor))
if sensor.type in ['Door Contact', 'Motion Camera']:
sensors.append(AbodeBinarySensor(hass, data, sensor))
_LOGGER.debug('Adding %d sensors', len(sensors))
add_devices(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.""" """A binary sensor implementation for Abode device."""
def __init__(self, hass, data, device): def __init__(self, controller, device):
"""Initialize a sensor for Abode device.""" """Initialize a sensor for Abode device."""
super(AbodeBinarySensor, self).__init__() AbodeDevice.__init__(self, controller, device)
self._device = device self._device_class = map_abode_device_class().get(self._device.type)
@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)
@property @property
def is_on(self): def is_on(self):
"""Return True if the binary sensor is on.""" """Return True if the binary sensor is on."""
if self._device.type == 'Door Contact': return self._device.is_on
return self._device.status != 'Closed'
elif self._device.type == 'Motion Camera':
return self._device.get_value('motion_event') == '1'
@property @property
def device_class(self): def device_class(self):
"""Return the class of the binary sensor.""" """Return the class of the binary sensor."""
return SENSOR_TYPES.get(self._device.type) return self._device_class
@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()

View file

@ -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()

View file

@ -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

View file

@ -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

View file

@ -39,7 +39,7 @@ SoCo==0.12
TwitterAPI==2.4.6 TwitterAPI==2.4.6
# homeassistant.components.abode # homeassistant.components.abode
abodepy==0.7.1 abodepy==0.9.0
# homeassistant.components.device_tracker.automatic # homeassistant.components.device_tracker.automatic
aioautomatic==0.6.2 aioautomatic==0.6.2