Abode services, events, lights, cameras, automations, quick actions. (#9310)
* Updated to latest AbodePy version. Added services and events. Added new device types. Added exclude, light, and polling config options. * Disable the event service if polling is enabled. * Addressed all CR's * Removed duplicated super call. * Name config option now used. Removed deprecated DEFAULT_NAME. * Modified partial to move event to first param.
This commit is contained in:
parent
5851944f80
commit
c44397e257
10 changed files with 588 additions and 96 deletions
|
@ -6,57 +6,138 @@ https://home-assistant.io/components/abode/
|
|||
"""
|
||||
import asyncio
|
||||
import logging
|
||||
from functools import partial
|
||||
from os import path
|
||||
|
||||
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.helpers.entity import Entity
|
||||
from homeassistant.const import (ATTR_ATTRIBUTION,
|
||||
CONF_USERNAME, CONF_PASSWORD,
|
||||
CONF_NAME, EVENT_HOMEASSISTANT_STOP,
|
||||
from homeassistant.config import load_yaml_config_file
|
||||
from homeassistant.const import (ATTR_ATTRIBUTION, ATTR_DATE, ATTR_TIME,
|
||||
ATTR_ENTITY_ID, CONF_USERNAME, CONF_PASSWORD,
|
||||
CONF_EXCLUDE, CONF_NAME,
|
||||
EVENT_HOMEASSISTANT_STOP,
|
||||
EVENT_HOMEASSISTANT_START)
|
||||
|
||||
REQUIREMENTS = ['abodepy==0.9.0']
|
||||
REQUIREMENTS = ['abodepy==0.11.5']
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
CONF_ATTRIBUTION = "Data provided by goabode.com"
|
||||
CONF_LIGHTS = "lights"
|
||||
CONF_POLLING = "polling"
|
||||
|
||||
DOMAIN = 'abode'
|
||||
DEFAULT_NAME = 'Abode'
|
||||
DATA_ABODE = 'abode'
|
||||
|
||||
NOTIFICATION_ID = 'abode_notification'
|
||||
NOTIFICATION_TITLE = 'Abode Security Setup'
|
||||
|
||||
EVENT_ABODE_ALARM = 'abode_alarm'
|
||||
EVENT_ABODE_ALARM_END = 'abode_alarm_end'
|
||||
EVENT_ABODE_AUTOMATION = 'abode_automation'
|
||||
EVENT_ABODE_FAULT = 'abode_panel_fault'
|
||||
EVENT_ABODE_RESTORE = 'abode_panel_restore'
|
||||
|
||||
SERVICE_SETTINGS = 'change_setting'
|
||||
SERVICE_CAPTURE_IMAGE = 'capture_image'
|
||||
SERVICE_TRIGGER = 'trigger_quick_action'
|
||||
|
||||
ATTR_DEVICE_ID = 'device_id'
|
||||
ATTR_DEVICE_NAME = 'device_name'
|
||||
ATTR_DEVICE_TYPE = 'device_type'
|
||||
ATTR_EVENT_CODE = 'event_code'
|
||||
ATTR_EVENT_NAME = 'event_name'
|
||||
ATTR_EVENT_TYPE = 'event_type'
|
||||
ATTR_EVENT_UTC = 'event_utc'
|
||||
ATTR_SETTING = 'setting'
|
||||
ATTR_USER_NAME = 'user_name'
|
||||
ATTR_VALUE = 'value'
|
||||
|
||||
ABODE_DEVICE_ID_LIST_SCHEMA = vol.Schema([str])
|
||||
|
||||
CONFIG_SCHEMA = vol.Schema({
|
||||
DOMAIN: vol.Schema({
|
||||
vol.Required(CONF_USERNAME): cv.string,
|
||||
vol.Required(CONF_PASSWORD): cv.string,
|
||||
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
|
||||
vol.Optional(CONF_NAME): cv.string,
|
||||
vol.Optional(CONF_POLLING, default=False): cv.boolean,
|
||||
vol.Optional(CONF_EXCLUDE, default=[]): ABODE_DEVICE_ID_LIST_SCHEMA,
|
||||
vol.Optional(CONF_LIGHTS, default=[]): ABODE_DEVICE_ID_LIST_SCHEMA
|
||||
}),
|
||||
}, extra=vol.ALLOW_EXTRA)
|
||||
|
||||
CHANGE_SETTING_SCHEMA = vol.Schema({
|
||||
vol.Required(ATTR_SETTING): cv.string,
|
||||
vol.Required(ATTR_VALUE): cv.string
|
||||
})
|
||||
|
||||
CAPTURE_IMAGE_SCHEMA = vol.Schema({
|
||||
ATTR_ENTITY_ID: cv.entity_ids,
|
||||
})
|
||||
|
||||
TRIGGER_SCHEMA = vol.Schema({
|
||||
ATTR_ENTITY_ID: cv.entity_ids,
|
||||
})
|
||||
|
||||
ABODE_PLATFORMS = [
|
||||
'alarm_control_panel', 'binary_sensor', 'lock', 'switch', 'cover'
|
||||
'alarm_control_panel', 'binary_sensor', 'lock', 'switch', 'cover',
|
||||
'camera', 'light'
|
||||
]
|
||||
|
||||
|
||||
class AbodeSystem(object):
|
||||
"""Abode System class."""
|
||||
|
||||
def __init__(self, username, password, name, polling, exclude, lights):
|
||||
"""Initialize the system."""
|
||||
import abodepy
|
||||
self.abode = abodepy.Abode(username, password,
|
||||
auto_login=True,
|
||||
get_devices=True,
|
||||
get_automations=True)
|
||||
self.name = name
|
||||
self.polling = polling
|
||||
self.exclude = exclude
|
||||
self.lights = lights
|
||||
self.devices = []
|
||||
|
||||
def is_excluded(self, device):
|
||||
"""Check if a device is configured to be excluded."""
|
||||
return device.device_id in self.exclude
|
||||
|
||||
def is_automation_excluded(self, automation):
|
||||
"""Check if an automation is configured to be excluded."""
|
||||
return automation.automation_id in self.exclude
|
||||
|
||||
def is_light(self, device):
|
||||
"""Check if a switch device is configured as a light."""
|
||||
import abodepy.helpers.constants as CONST
|
||||
|
||||
return (device.generic_type == CONST.TYPE_LIGHT or
|
||||
(device.generic_type == CONST.TYPE_SWITCH and
|
||||
device.device_id in self.lights))
|
||||
|
||||
|
||||
def setup(hass, config):
|
||||
"""Set up Abode component."""
|
||||
import abodepy
|
||||
from abodepy.exceptions import AbodeException
|
||||
|
||||
conf = config[DOMAIN]
|
||||
username = conf.get(CONF_USERNAME)
|
||||
password = conf.get(CONF_PASSWORD)
|
||||
name = conf.get(CONF_NAME)
|
||||
polling = conf.get(CONF_POLLING)
|
||||
exclude = conf.get(CONF_EXCLUDE)
|
||||
lights = conf.get(CONF_LIGHTS)
|
||||
|
||||
try:
|
||||
hass.data[DATA_ABODE] = abode = abodepy.Abode(
|
||||
username, password, auto_login=True, get_devices=True)
|
||||
|
||||
except (ConnectTimeout, HTTPError) as ex:
|
||||
hass.data[DOMAIN] = AbodeSystem(
|
||||
username, password, name, polling, exclude, lights)
|
||||
except (AbodeException, ConnectTimeout, HTTPError) as ex:
|
||||
_LOGGER.error("Unable to connect to Abode: %s", str(ex))
|
||||
|
||||
hass.components.persistent_notification.create(
|
||||
'Error: {}<br />'
|
||||
'You will need to restart hass after fixing.'
|
||||
|
@ -65,46 +146,144 @@ def setup(hass, config):
|
|||
notification_id=NOTIFICATION_ID)
|
||||
return False
|
||||
|
||||
setup_hass_services(hass)
|
||||
setup_hass_events(hass)
|
||||
setup_abode_events(hass)
|
||||
|
||||
for platform in ABODE_PLATFORMS:
|
||||
discovery.load_platform(hass, platform, DOMAIN, {}, config)
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def setup_hass_services(hass):
|
||||
"""Home assistant services."""
|
||||
from abodepy.exceptions import AbodeException
|
||||
|
||||
def change_setting(call):
|
||||
"""Change an Abode system setting."""
|
||||
setting = call.data.get(ATTR_SETTING)
|
||||
value = call.data.get(ATTR_VALUE)
|
||||
|
||||
try:
|
||||
hass.data[DOMAIN].abode.set_setting(setting, value)
|
||||
except AbodeException as ex:
|
||||
_LOGGER.warning(ex)
|
||||
|
||||
def capture_image(call):
|
||||
"""Capture a new image."""
|
||||
entity_ids = call.data.get(ATTR_ENTITY_ID)
|
||||
|
||||
target_devices = [device for device in hass.data[DOMAIN].devices
|
||||
if device.entity_id in entity_ids]
|
||||
|
||||
for device in target_devices:
|
||||
device.capture()
|
||||
|
||||
def trigger_quick_action(call):
|
||||
"""Trigger a quick action."""
|
||||
entity_ids = call.data.get(ATTR_ENTITY_ID, None)
|
||||
|
||||
target_devices = [device for device in hass.data[DOMAIN].devices
|
||||
if device.entity_id in entity_ids]
|
||||
|
||||
for device in target_devices:
|
||||
device.trigger()
|
||||
|
||||
descriptions = load_yaml_config_file(
|
||||
path.join(path.dirname(__file__), 'services.yaml'))[DOMAIN]
|
||||
|
||||
hass.services.register(
|
||||
DOMAIN, SERVICE_SETTINGS, change_setting,
|
||||
descriptions.get(SERVICE_SETTINGS),
|
||||
schema=CHANGE_SETTING_SCHEMA)
|
||||
|
||||
hass.services.register(
|
||||
DOMAIN, SERVICE_CAPTURE_IMAGE, capture_image,
|
||||
descriptions.get(SERVICE_CAPTURE_IMAGE),
|
||||
schema=CAPTURE_IMAGE_SCHEMA)
|
||||
|
||||
hass.services.register(
|
||||
DOMAIN, SERVICE_TRIGGER, trigger_quick_action,
|
||||
descriptions.get(SERVICE_TRIGGER),
|
||||
schema=TRIGGER_SCHEMA)
|
||||
|
||||
|
||||
def setup_hass_events(hass):
|
||||
"""Home assistant start and stop callbacks."""
|
||||
def startup(event):
|
||||
"""Listen for push events."""
|
||||
hass.data[DOMAIN].abode.events.start()
|
||||
|
||||
def logout(event):
|
||||
"""Logout of Abode."""
|
||||
abode.stop_listener()
|
||||
abode.logout()
|
||||
if not hass.data[DOMAIN].polling:
|
||||
hass.data[DOMAIN].abode.events.stop()
|
||||
|
||||
hass.data[DOMAIN].abode.logout()
|
||||
_LOGGER.info("Logged out of Abode")
|
||||
|
||||
if not hass.data[DOMAIN].polling:
|
||||
hass.bus.listen_once(EVENT_HOMEASSISTANT_START, startup)
|
||||
|
||||
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)
|
||||
def setup_abode_events(hass):
|
||||
"""Event callbacks."""
|
||||
import abodepy.helpers.timeline as TIMELINE
|
||||
|
||||
return True
|
||||
def event_callback(event, event_json):
|
||||
"""Handle an event callback from Abode."""
|
||||
data = {
|
||||
ATTR_DEVICE_ID: event_json.get(ATTR_DEVICE_ID, ''),
|
||||
ATTR_DEVICE_NAME: event_json.get(ATTR_DEVICE_NAME, ''),
|
||||
ATTR_DEVICE_TYPE: event_json.get(ATTR_DEVICE_TYPE, ''),
|
||||
ATTR_EVENT_CODE: event_json.get(ATTR_EVENT_CODE, ''),
|
||||
ATTR_EVENT_NAME: event_json.get(ATTR_EVENT_NAME, ''),
|
||||
ATTR_EVENT_TYPE: event_json.get(ATTR_EVENT_TYPE, ''),
|
||||
ATTR_EVENT_UTC: event_json.get(ATTR_EVENT_UTC, ''),
|
||||
ATTR_USER_NAME: event_json.get(ATTR_USER_NAME, ''),
|
||||
ATTR_DATE: event_json.get(ATTR_DATE, ''),
|
||||
ATTR_TIME: event_json.get(ATTR_TIME, ''),
|
||||
}
|
||||
|
||||
hass.bus.fire(event, data)
|
||||
|
||||
events = [TIMELINE.ALARM_GROUP, TIMELINE.ALARM_END_GROUP,
|
||||
TIMELINE.PANEL_FAULT_GROUP, TIMELINE.PANEL_RESTORE_GROUP,
|
||||
TIMELINE.AUTOMATION_GROUP]
|
||||
|
||||
for event in events:
|
||||
hass.data[DOMAIN].abode.events.add_event_callback(
|
||||
event,
|
||||
partial(event_callback, event))
|
||||
|
||||
|
||||
class AbodeDevice(Entity):
|
||||
"""Representation of an Abode device."""
|
||||
|
||||
def __init__(self, controller, device):
|
||||
def __init__(self, data, device):
|
||||
"""Initialize a sensor for Abode device."""
|
||||
self._controller = controller
|
||||
self._data = data
|
||||
self._device = device
|
||||
|
||||
@asyncio.coroutine
|
||||
def async_added_to_hass(self):
|
||||
"""Subscribe Abode events."""
|
||||
self.hass.async_add_job(
|
||||
self._controller.register, self._device,
|
||||
self._update_callback
|
||||
self._data.abode.events.add_device_callback,
|
||||
self._device.device_id, self._update_callback
|
||||
)
|
||||
|
||||
@property
|
||||
def should_poll(self):
|
||||
"""Return the polling state."""
|
||||
return False
|
||||
return self._data.polling
|
||||
|
||||
def update(self):
|
||||
"""Update automation state."""
|
||||
self._device.refresh()
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
|
@ -124,3 +303,51 @@ class AbodeDevice(Entity):
|
|||
def _update_callback(self, device):
|
||||
"""Update the device state."""
|
||||
self.schedule_update_ha_state()
|
||||
|
||||
|
||||
class AbodeAutomation(Entity):
|
||||
"""Representation of an Abode automation."""
|
||||
|
||||
def __init__(self, data, automation, event=None):
|
||||
"""Initialize for Abode automation."""
|
||||
self._data = data
|
||||
self._automation = automation
|
||||
self._event = event
|
||||
|
||||
@asyncio.coroutine
|
||||
def async_added_to_hass(self):
|
||||
"""Subscribe Abode events."""
|
||||
if self._event:
|
||||
self.hass.async_add_job(
|
||||
self._data.abode.events.add_event_callback,
|
||||
self._event, self._update_callback
|
||||
)
|
||||
|
||||
@property
|
||||
def should_poll(self):
|
||||
"""Return the polling state."""
|
||||
return self._data.polling
|
||||
|
||||
def update(self):
|
||||
"""Update automation state."""
|
||||
self._automation.refresh()
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
"""Return the name of the sensor."""
|
||||
return self._automation.name
|
||||
|
||||
@property
|
||||
def device_state_attributes(self):
|
||||
"""Return the state attributes."""
|
||||
return {
|
||||
ATTR_ATTRIBUTION: CONF_ATTRIBUTION,
|
||||
'automation_id': self._automation.automation_id,
|
||||
'type': self._automation.type,
|
||||
'sub_type': self._automation.sub_type
|
||||
}
|
||||
|
||||
def _update_callback(self, device):
|
||||
"""Update the device state."""
|
||||
self._automation.refresh()
|
||||
self.schedule_update_ha_state()
|
||||
|
|
|
@ -7,7 +7,7 @@ https://home-assistant.io/components/alarm_control_panel.abode/
|
|||
import logging
|
||||
|
||||
from homeassistant.components.abode import (
|
||||
AbodeDevice, DATA_ABODE, DEFAULT_NAME, CONF_ATTRIBUTION)
|
||||
AbodeDevice, DOMAIN as ABODE_DOMAIN, 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)
|
||||
|
@ -22,18 +22,22 @@ ICON = 'mdi:security'
|
|||
|
||||
def setup_platform(hass, config, add_devices, discovery_info=None):
|
||||
"""Set up a sensor for an Abode device."""
|
||||
abode = hass.data[DATA_ABODE]
|
||||
data = hass.data[ABODE_DOMAIN]
|
||||
|
||||
add_devices([AbodeAlarm(abode, abode.get_alarm())])
|
||||
alarm_devices = [AbodeAlarm(data, data.abode.get_alarm(), data.name)]
|
||||
|
||||
data.devices.extend(alarm_devices)
|
||||
|
||||
add_devices(alarm_devices)
|
||||
|
||||
|
||||
class AbodeAlarm(AbodeDevice, AlarmControlPanel):
|
||||
"""An alarm_control_panel implementation for Abode."""
|
||||
|
||||
def __init__(self, controller, device):
|
||||
def __init__(self, data, device, name):
|
||||
"""Initialize the alarm control panel."""
|
||||
AbodeDevice.__init__(self, controller, device)
|
||||
self._name = "{0}".format(DEFAULT_NAME)
|
||||
super().__init__(data, device)
|
||||
self._name = name
|
||||
|
||||
@property
|
||||
def icon(self):
|
||||
|
@ -65,6 +69,11 @@ class AbodeAlarm(AbodeDevice, AlarmControlPanel):
|
|||
"""Send arm away command."""
|
||||
self._device.set_away()
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
"""Return the name of the alarm."""
|
||||
return self._name or super().name
|
||||
|
||||
@property
|
||||
def device_state_attributes(self):
|
||||
"""Return the state attributes."""
|
||||
|
|
|
@ -6,7 +6,8 @@ https://home-assistant.io/components/binary_sensor.abode/
|
|||
"""
|
||||
import logging
|
||||
|
||||
from homeassistant.components.abode import AbodeDevice, DATA_ABODE
|
||||
from homeassistant.components.abode import (AbodeDevice, AbodeAutomation,
|
||||
DOMAIN as ABODE_DOMAIN)
|
||||
from homeassistant.components.binary_sensor import BinarySensorDevice
|
||||
|
||||
|
||||
|
@ -17,39 +18,38 @@ _LOGGER = logging.getLogger(__name__)
|
|||
|
||||
def setup_platform(hass, config, add_devices, discovery_info=None):
|
||||
"""Set up a sensor for an Abode device."""
|
||||
abode = hass.data[DATA_ABODE]
|
||||
|
||||
device_types = map_abode_device_class().keys()
|
||||
|
||||
sensors = []
|
||||
for sensor in abode.get_devices(type_filter=device_types):
|
||||
sensors.append(AbodeBinarySensor(abode, sensor))
|
||||
|
||||
add_devices(sensors)
|
||||
|
||||
|
||||
def map_abode_device_class():
|
||||
"""Map Abode device types to Home Assistant binary sensor class."""
|
||||
import abodepy.helpers.constants as CONST
|
||||
import abodepy.helpers.timeline as TIMELINE
|
||||
|
||||
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'
|
||||
}
|
||||
data = hass.data[ABODE_DOMAIN]
|
||||
|
||||
device_types = [CONST.TYPE_CONNECTIVITY, CONST.TYPE_MOISTURE,
|
||||
CONST.TYPE_MOTION, CONST.TYPE_OCCUPANCY,
|
||||
CONST.TYPE_OPENING]
|
||||
|
||||
devices = []
|
||||
for device in data.abode.get_devices(generic_type=device_types):
|
||||
if data.is_excluded(device):
|
||||
continue
|
||||
|
||||
devices.append(AbodeBinarySensor(data, device))
|
||||
|
||||
for automation in data.abode.get_automations(
|
||||
generic_type=CONST.TYPE_QUICK_ACTION):
|
||||
if data.is_automation_excluded(automation):
|
||||
continue
|
||||
|
||||
devices.append(AbodeQuickActionBinarySensor(
|
||||
data, automation, TIMELINE.AUTOMATION_EDIT_GROUP))
|
||||
|
||||
data.devices.extend(devices)
|
||||
|
||||
add_devices(devices)
|
||||
|
||||
|
||||
class AbodeBinarySensor(AbodeDevice, BinarySensorDevice):
|
||||
"""A binary sensor implementation for Abode device."""
|
||||
|
||||
def __init__(self, controller, device):
|
||||
"""Initialize a sensor for Abode device."""
|
||||
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."""
|
||||
|
@ -58,4 +58,17 @@ class AbodeBinarySensor(AbodeDevice, BinarySensorDevice):
|
|||
@property
|
||||
def device_class(self):
|
||||
"""Return the class of the binary sensor."""
|
||||
return self._device_class
|
||||
return self._device.generic_type
|
||||
|
||||
|
||||
class AbodeQuickActionBinarySensor(AbodeAutomation, BinarySensorDevice):
|
||||
"""A binary sensor implementation for Abode quick action automations."""
|
||||
|
||||
def trigger(self):
|
||||
"""Trigger a quick automation."""
|
||||
self._automation.trigger()
|
||||
|
||||
@property
|
||||
def is_on(self):
|
||||
"""Return True if the binary sensor is on."""
|
||||
return self._automation.is_active
|
||||
|
|
101
homeassistant/components/camera/abode.py
Normal file
101
homeassistant/components/camera/abode.py
Normal file
|
@ -0,0 +1,101 @@
|
|||
"""
|
||||
This component provides HA camera support for Abode Security System.
|
||||
|
||||
For more details about this platform, please refer to the documentation at
|
||||
https://home-assistant.io/components/camera.abode/
|
||||
"""
|
||||
import asyncio
|
||||
import logging
|
||||
|
||||
from datetime import timedelta
|
||||
import requests
|
||||
|
||||
from homeassistant.components.abode import AbodeDevice, DOMAIN as ABODE_DOMAIN
|
||||
from homeassistant.components.camera import Camera
|
||||
from homeassistant.util import Throttle
|
||||
|
||||
|
||||
DEPENDENCIES = ['abode']
|
||||
|
||||
MIN_TIME_BETWEEN_UPDATES = timedelta(seconds=90)
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def setup_platform(hass, config, add_devices, discoveryy_info=None):
|
||||
"""Set up Abode camera devices."""
|
||||
import abodepy.helpers.constants as CONST
|
||||
import abodepy.helpers.timeline as TIMELINE
|
||||
|
||||
data = hass.data[ABODE_DOMAIN]
|
||||
|
||||
devices = []
|
||||
for device in data.abode.get_devices(generic_type=CONST.TYPE_CAMERA):
|
||||
if data.is_excluded(device):
|
||||
continue
|
||||
|
||||
devices.append(AbodeCamera(data, device, TIMELINE.CAPTURE_IMAGE))
|
||||
|
||||
data.devices.extend(devices)
|
||||
|
||||
add_devices(devices)
|
||||
|
||||
|
||||
class AbodeCamera(AbodeDevice, Camera):
|
||||
"""Representation of an Abode camera."""
|
||||
|
||||
def __init__(self, data, device, event):
|
||||
"""Initialize the Abode device."""
|
||||
AbodeDevice.__init__(self, data, device)
|
||||
Camera.__init__(self)
|
||||
self._event = event
|
||||
self._response = None
|
||||
|
||||
@asyncio.coroutine
|
||||
def async_added_to_hass(self):
|
||||
"""Subscribe Abode events."""
|
||||
yield from super().async_added_to_hass()
|
||||
|
||||
self.hass.async_add_job(
|
||||
self._data.abode.events.add_timeline_callback,
|
||||
self._event, self._capture_callback
|
||||
)
|
||||
|
||||
def capture(self):
|
||||
"""Request a new image capture."""
|
||||
return self._device.capture()
|
||||
|
||||
@Throttle(MIN_TIME_BETWEEN_UPDATES)
|
||||
def refresh_image(self):
|
||||
"""Find a new image on the timeline."""
|
||||
if self._device.refresh_image():
|
||||
self.get_image()
|
||||
|
||||
def get_image(self):
|
||||
"""Attempt to download the most recent capture."""
|
||||
if self._device.image_url:
|
||||
try:
|
||||
self._response = requests.get(
|
||||
self._device.image_url, stream=True)
|
||||
|
||||
self._response.raise_for_status()
|
||||
except requests.HTTPError as err:
|
||||
_LOGGER.warning("Failed to get camera image: %s", err)
|
||||
self._response = None
|
||||
else:
|
||||
self._response = None
|
||||
|
||||
def camera_image(self):
|
||||
"""Get a camera image."""
|
||||
self.refresh_image()
|
||||
|
||||
if self._response:
|
||||
return self._response.content
|
||||
|
||||
return None
|
||||
|
||||
def _capture_callback(self, capture):
|
||||
"""Update the image with the device then refresh device."""
|
||||
self._device.update_image_location(capture)
|
||||
self.get_image()
|
||||
self.schedule_update_ha_state()
|
|
@ -6,7 +6,7 @@ https://home-assistant.io/components/cover.abode/
|
|||
"""
|
||||
import logging
|
||||
|
||||
from homeassistant.components.abode import AbodeDevice, DATA_ABODE
|
||||
from homeassistant.components.abode import AbodeDevice, DOMAIN as ABODE_DOMAIN
|
||||
from homeassistant.components.cover import CoverDevice
|
||||
|
||||
|
||||
|
@ -19,31 +19,32 @@ 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]
|
||||
data = hass.data[ABODE_DOMAIN]
|
||||
|
||||
sensors = []
|
||||
for sensor in abode.get_devices(type_filter=(CONST.DEVICE_SECURE_BARRIER)):
|
||||
sensors.append(AbodeCover(abode, sensor))
|
||||
devices = []
|
||||
for device in data.abode.get_devices(generic_type=CONST.TYPE_COVER):
|
||||
if data.is_excluded(device):
|
||||
continue
|
||||
|
||||
add_devices(sensors)
|
||||
devices.append(AbodeCover(data, device))
|
||||
|
||||
data.devices.extend(devices)
|
||||
|
||||
add_devices(devices)
|
||||
|
||||
|
||||
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
|
||||
return not self._device.is_open
|
||||
|
||||
def close_cover(self):
|
||||
def close_cover(self, **kwargs):
|
||||
"""Issue close command to cover."""
|
||||
self._device.close_cover()
|
||||
|
||||
def open_cover(self):
|
||||
def open_cover(self, **kwargs):
|
||||
"""Issue open command to cover."""
|
||||
self._device.open_cover()
|
||||
|
|
84
homeassistant/components/light/abode.py
Normal file
84
homeassistant/components/light/abode.py
Normal file
|
@ -0,0 +1,84 @@
|
|||
"""
|
||||
This component provides HA light support for Abode Security System.
|
||||
|
||||
For more details about this platform, please refer to the documentation at
|
||||
https://home-assistant.io/components/light.abode/
|
||||
"""
|
||||
import logging
|
||||
|
||||
from homeassistant.components.abode import AbodeDevice, DOMAIN as ABODE_DOMAIN
|
||||
from homeassistant.components.light import (
|
||||
ATTR_BRIGHTNESS, ATTR_RGB_COLOR,
|
||||
SUPPORT_BRIGHTNESS, SUPPORT_RGB_COLOR, Light)
|
||||
|
||||
|
||||
DEPENDENCIES = ['abode']
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def setup_platform(hass, config, add_devices, discovery_info=None):
|
||||
"""Set up Abode light devices."""
|
||||
import abodepy.helpers.constants as CONST
|
||||
|
||||
data = hass.data[ABODE_DOMAIN]
|
||||
|
||||
device_types = [CONST.TYPE_LIGHT, CONST.TYPE_SWITCH]
|
||||
|
||||
devices = []
|
||||
|
||||
# Get all regular lights that are not excluded or switches marked as lights
|
||||
for device in data.abode.get_devices(generic_type=device_types):
|
||||
if data.is_excluded(device) or not data.is_light(device):
|
||||
continue
|
||||
|
||||
devices.append(AbodeLight(data, device))
|
||||
|
||||
data.devices.extend(devices)
|
||||
|
||||
add_devices(devices)
|
||||
|
||||
|
||||
class AbodeLight(AbodeDevice, Light):
|
||||
"""Representation of an Abode light."""
|
||||
|
||||
def turn_on(self, **kwargs):
|
||||
"""Turn on the light."""
|
||||
if (ATTR_RGB_COLOR in kwargs and
|
||||
self._device.is_dimmable and self._device.has_color):
|
||||
self._device.set_color(kwargs[ATTR_RGB_COLOR])
|
||||
elif ATTR_BRIGHTNESS in kwargs and self._device.is_dimmable:
|
||||
self._device.set_level(kwargs[ATTR_BRIGHTNESS])
|
||||
else:
|
||||
self._device.switch_on()
|
||||
|
||||
def turn_off(self, **kwargs):
|
||||
"""Turn off the light."""
|
||||
self._device.switch_off()
|
||||
|
||||
@property
|
||||
def is_on(self):
|
||||
"""Return true if device is on."""
|
||||
return self._device.is_on
|
||||
|
||||
@property
|
||||
def brightness(self):
|
||||
"""Return the brightness of the light."""
|
||||
if self._device.is_dimmable and self._device.has_brightness:
|
||||
return self._device.brightness
|
||||
|
||||
@property
|
||||
def rgb_color(self):
|
||||
"""Return the color of the light."""
|
||||
if self._device.is_dimmable and self._device.has_color:
|
||||
return self._device.color
|
||||
|
||||
@property
|
||||
def supported_features(self):
|
||||
"""Flag supported features."""
|
||||
if self._device.is_dimmable and self._device.has_color:
|
||||
return SUPPORT_BRIGHTNESS | SUPPORT_RGB_COLOR
|
||||
elif self._device.is_dimmable:
|
||||
return SUPPORT_BRIGHTNESS
|
||||
|
||||
return 0
|
|
@ -6,7 +6,7 @@ https://home-assistant.io/components/lock.abode/
|
|||
"""
|
||||
import logging
|
||||
|
||||
from homeassistant.components.abode import AbodeDevice, DATA_ABODE
|
||||
from homeassistant.components.abode import AbodeDevice, DOMAIN as ABODE_DOMAIN
|
||||
from homeassistant.components.lock import LockDevice
|
||||
|
||||
|
||||
|
@ -19,22 +19,23 @@ 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]
|
||||
data = hass.data[ABODE_DOMAIN]
|
||||
|
||||
sensors = []
|
||||
for sensor in abode.get_devices(type_filter=(CONST.DEVICE_DOOR_LOCK)):
|
||||
sensors.append(AbodeLock(abode, sensor))
|
||||
devices = []
|
||||
for device in data.abode.get_devices(generic_type=CONST.TYPE_LOCK):
|
||||
if data.is_excluded(device):
|
||||
continue
|
||||
|
||||
add_devices(sensors)
|
||||
devices.append(AbodeLock(data, device))
|
||||
|
||||
data.devices.extend(devices)
|
||||
|
||||
add_devices(devices)
|
||||
|
||||
|
||||
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()
|
||||
|
|
|
@ -571,3 +571,32 @@ counter:
|
|||
entity_id:
|
||||
description: Entity id of the counter to reset.
|
||||
example: 'counter.count0'
|
||||
|
||||
abode:
|
||||
change_setting:
|
||||
description: Change an Abode system setting.
|
||||
|
||||
fields:
|
||||
setting:
|
||||
description: Setting to change.
|
||||
example: 'beeper_mute'
|
||||
|
||||
value:
|
||||
description: Value of the setting.
|
||||
example: '1'
|
||||
|
||||
capture_image:
|
||||
description: Request a new image capture from a camera device.
|
||||
|
||||
fields:
|
||||
entity_id:
|
||||
description: Entity id of the camera to request an image.
|
||||
example: 'camera.downstairs_motion_camera'
|
||||
|
||||
trigger_quick_action:
|
||||
description: Trigger an Abode quick action.
|
||||
|
||||
fields:
|
||||
entity_id:
|
||||
description: Entity id of the quick action to trigger.
|
||||
example: 'binary_sensor.home_quick_action'
|
||||
|
|
|
@ -6,7 +6,8 @@ https://home-assistant.io/components/switch.abode/
|
|||
"""
|
||||
import logging
|
||||
|
||||
from homeassistant.components.abode import AbodeDevice, DATA_ABODE
|
||||
from homeassistant.components.abode import (AbodeDevice, AbodeAutomation,
|
||||
DOMAIN as ABODE_DOMAIN)
|
||||
from homeassistant.components.switch import SwitchDevice
|
||||
|
||||
|
||||
|
@ -18,27 +19,36 @@ _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
|
||||
import abodepy.helpers.timeline as TIMELINE
|
||||
|
||||
abode = hass.data[DATA_ABODE]
|
||||
data = hass.data[ABODE_DOMAIN]
|
||||
|
||||
device_types = [
|
||||
CONST.DEVICE_POWER_SWITCH_SENSOR,
|
||||
CONST.DEVICE_POWER_SWITCH_METER]
|
||||
devices = []
|
||||
|
||||
sensors = []
|
||||
for sensor in abode.get_devices(type_filter=device_types):
|
||||
sensors.append(AbodeSwitch(abode, sensor))
|
||||
# Get all regular switches that are not excluded or marked as lights
|
||||
for device in data.abode.get_devices(generic_type=CONST.TYPE_SWITCH):
|
||||
if data.is_excluded(device) or not data.is_light(device):
|
||||
continue
|
||||
|
||||
add_devices(sensors)
|
||||
devices.append(AbodeSwitch(data, device))
|
||||
|
||||
# Get all Abode automations that can be enabled/disabled
|
||||
for automation in data.abode.get_automations(
|
||||
generic_type=CONST.TYPE_AUTOMATION):
|
||||
if data.is_automation_excluded(automation):
|
||||
continue
|
||||
|
||||
devices.append(AbodeAutomationSwitch(
|
||||
data, automation, TIMELINE.AUTOMATION_EDIT_GROUP))
|
||||
|
||||
data.devices.extend(devices)
|
||||
|
||||
add_devices(devices)
|
||||
|
||||
|
||||
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()
|
||||
|
@ -51,3 +61,20 @@ class AbodeSwitch(AbodeDevice, SwitchDevice):
|
|||
def is_on(self):
|
||||
"""Return true if device is on."""
|
||||
return self._device.is_on
|
||||
|
||||
|
||||
class AbodeAutomationSwitch(AbodeAutomation, SwitchDevice):
|
||||
"""A switch implementation for Abode automations."""
|
||||
|
||||
def turn_on(self, **kwargs):
|
||||
"""Turn on the device."""
|
||||
self._automation.set_active(True)
|
||||
|
||||
def turn_off(self, **kwargs):
|
||||
"""Turn off the device."""
|
||||
self._automation.set_active(False)
|
||||
|
||||
@property
|
||||
def is_on(self):
|
||||
"""Return True if the binary sensor is on."""
|
||||
return self._automation.is_active
|
||||
|
|
|
@ -42,7 +42,7 @@ SoCo==0.12
|
|||
TwitterAPI==2.4.6
|
||||
|
||||
# homeassistant.components.abode
|
||||
abodepy==0.9.0
|
||||
abodepy==0.11.5
|
||||
|
||||
# homeassistant.components.device_tracker.automatic
|
||||
aioautomatic==0.6.3
|
||||
|
|
Loading…
Add table
Reference in a new issue