* New Skybell platform with components

* Added skybell components to omit.

* Preemptively fixing lint issues (hopefully).

* Removed unused variable.

* Requested changes.

* Additional CRs

* Hopefully the last of the CR's!
This commit is contained in:
Mister Wil 2017-10-08 11:14:39 -07:00 committed by Fabian Affolter
parent ca54bbfcc9
commit 8132989f91
8 changed files with 507 additions and 0 deletions

View file

@ -169,6 +169,9 @@ omit =
homeassistant/components/scsgate.py
homeassistant/components/*/scsgate.py
homeassistant/components/skybell.py
homeassistant/components/*/skybell.py
homeassistant/components/tado.py
homeassistant/components/*/tado.py

View file

@ -0,0 +1,97 @@
"""
Binary sensor support for the Skybell HD Doorbell.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/binary_sensor.skybell/
"""
from datetime import timedelta
import logging
import voluptuous as vol
from homeassistant.components.binary_sensor import (
BinarySensorDevice, PLATFORM_SCHEMA)
from homeassistant.components.skybell import (
DEFAULT_ENTITY_NAMESPACE, DOMAIN as SKYBELL_DOMAIN, SkybellDevice)
from homeassistant.const import (
CONF_ENTITY_NAMESPACE, CONF_MONITORED_CONDITIONS)
import homeassistant.helpers.config_validation as cv
DEPENDENCIES = ['skybell']
_LOGGER = logging.getLogger(__name__)
SCAN_INTERVAL = timedelta(seconds=5)
# Sensor types: Name, device_class, event
SENSOR_TYPES = {
'button': ['Button', 'occupancy', 'device:sensor:button'],
'motion': ['Motion', 'motion', 'device:sensor:motion'],
}
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Optional(CONF_ENTITY_NAMESPACE, default=DEFAULT_ENTITY_NAMESPACE):
cv.string,
vol.Required(CONF_MONITORED_CONDITIONS, default=[]):
vol.All(cv.ensure_list, [vol.In(SENSOR_TYPES)]),
})
def setup_platform(hass, config, add_devices, discovery_info=None):
"""Set up the platform for a Skybell device."""
skybell = hass.data.get(SKYBELL_DOMAIN)
sensors = []
for sensor_type in config.get(CONF_MONITORED_CONDITIONS):
for device in skybell.get_devices():
sensors.append(SkybellBinarySensor(device, sensor_type))
add_devices(sensors, True)
class SkybellBinarySensor(SkybellDevice, BinarySensorDevice):
"""A binary sensor implementation for Skybell devices."""
def __init__(self, device, sensor_type):
"""Initialize a binary sensor for a Skybell device."""
super().__init__(device)
self._sensor_type = sensor_type
self._name = "{0} {1}".format(self._device.name,
SENSOR_TYPES[self._sensor_type][0])
self._device_class = SENSOR_TYPES[self._sensor_type][1]
self._event = {}
self._state = None
@property
def name(self):
"""Return the name of the sensor."""
return self._name
@property
def is_on(self):
"""Return True if the binary sensor is on."""
return self._state
@property
def device_class(self):
"""Return the class of the binary sensor."""
return self._device_class
@property
def device_state_attributes(self):
"""Return the state attributes."""
attrs = super().device_state_attributes
attrs['event_date'] = self._event.get('createdAt')
return attrs
def update(self):
"""Get the latest data and updates the state."""
super().update()
event = self._device.latest(SENSOR_TYPES[self._sensor_type][2])
self._state = bool(event and event.get('id') != self._event.get('id'))
self._event = event

View file

@ -0,0 +1,67 @@
"""
Camera support for the Skybell HD Doorbell.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/camera.skybell/
"""
from datetime import timedelta
import logging
import requests
from homeassistant.components.camera import Camera
from homeassistant.components.skybell import (
DOMAIN as SKYBELL_DOMAIN, SkybellDevice)
DEPENDENCIES = ['skybell']
_LOGGER = logging.getLogger(__name__)
SCAN_INTERVAL = timedelta(seconds=90)
def setup_platform(hass, config, add_devices, discovery_info=None):
"""Set up the platform for a Skybell device."""
skybell = hass.data.get(SKYBELL_DOMAIN)
sensors = []
for device in skybell.get_devices():
sensors.append(SkybellCamera(device))
add_devices(sensors, True)
class SkybellCamera(SkybellDevice, Camera):
"""A camera implementation for Skybell devices."""
def __init__(self, device):
"""Initialize a camera for a Skybell device."""
SkybellDevice.__init__(self, device)
Camera.__init__(self)
self._name = self._device.name
self._url = None
self._response = None
@property
def name(self):
"""Return the name of the sensor."""
return self._name
def camera_image(self):
"""Get the latest camera image."""
super().update()
if self._url != self._device.image:
self._url = self._device.image
try:
self._response = requests.get(
self._url, stream=True, timeout=10)
except requests.HTTPError as err:
_LOGGER.warning("Failed to get camera image: %s", err)
self._response = None
if not self._response:
return None
return self._response.content

View file

@ -0,0 +1,87 @@
"""
Light/LED support for the Skybell HD Doorbell.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/light.skybell/
"""
import logging
from homeassistant.components.light import (
ATTR_BRIGHTNESS, ATTR_RGB_COLOR,
SUPPORT_BRIGHTNESS, SUPPORT_RGB_COLOR, Light)
from homeassistant.components.skybell import (
DOMAIN as SKYBELL_DOMAIN, SkybellDevice)
DEPENDENCIES = ['skybell']
_LOGGER = logging.getLogger(__name__)
def setup_platform(hass, config, add_devices, discovery_info=None):
"""Set up the platform for a Skybell device."""
skybell = hass.data.get(SKYBELL_DOMAIN)
sensors = []
for device in skybell.get_devices():
sensors.append(SkybellLight(device))
add_devices(sensors, True)
def _to_skybell_level(level):
"""Convert the given HASS light level (0-255) to Skybell (0-100)."""
return int((level * 100) / 255)
def _to_hass_level(level):
"""Convert the given Skybell (0-100) light level to HASS (0-255)."""
return int((level * 255) / 100)
class SkybellLight(SkybellDevice, Light):
"""A binary sensor implementation for Skybell devices."""
def __init__(self, device):
"""Initialize a light for a Skybell device."""
super().__init__(device)
self._name = self._device.name
@property
def name(self):
"""Return the name of the sensor."""
return self._name
def turn_on(self, **kwargs):
"""Turn on the light."""
if ATTR_RGB_COLOR in kwargs:
self._device.led_rgb = kwargs[ATTR_RGB_COLOR]
elif ATTR_BRIGHTNESS in kwargs:
self._device.led_intensity = _to_skybell_level(
kwargs[ATTR_BRIGHTNESS])
else:
self._device.led_intensity = _to_skybell_level(255)
def turn_off(self, **kwargs):
"""Turn off the light."""
self._device.led_intensity = 0
@property
def is_on(self):
"""Return true if device is on."""
return self._device.led_intensity > 0
@property
def brightness(self):
"""Return the brightness of the light."""
return _to_hass_level(self._device.led_intensity)
@property
def rgb_color(self):
"""Return the color of the light."""
return self._device.led_rgb
@property
def supported_features(self):
"""Flag supported features."""
return SUPPORT_BRIGHTNESS | SUPPORT_RGB_COLOR

View file

@ -0,0 +1,82 @@
"""
Sensor support for Skybell Doorbells.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/sensor.skybell/
"""
from datetime import timedelta
import logging
import voluptuous as vol
from homeassistant.components.sensor import PLATFORM_SCHEMA
from homeassistant.components.skybell import (
DEFAULT_ENTITY_NAMESPACE, DOMAIN as SKYBELL_DOMAIN, SkybellDevice)
from homeassistant.const import (
CONF_ENTITY_NAMESPACE, CONF_MONITORED_CONDITIONS)
import homeassistant.helpers.config_validation as cv
DEPENDENCIES = ['skybell']
_LOGGER = logging.getLogger(__name__)
SCAN_INTERVAL = timedelta(seconds=30)
# Sensor types: Name, icon
SENSOR_TYPES = {
'chime_level': ['Chime Level', 'bell-ring'],
}
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Optional(CONF_ENTITY_NAMESPACE, default=DEFAULT_ENTITY_NAMESPACE):
cv.string,
vol.Required(CONF_MONITORED_CONDITIONS, default=[]):
vol.All(cv.ensure_list, [vol.In(SENSOR_TYPES)]),
})
def setup_platform(hass, config, add_devices, discovery_info=None):
"""Set up the platform for a Skybell device."""
skybell = hass.data.get(SKYBELL_DOMAIN)
sensors = []
for sensor_type in config.get(CONF_MONITORED_CONDITIONS):
for device in skybell.get_devices():
sensors.append(SkybellSensor(device, sensor_type))
add_devices(sensors, True)
class SkybellSensor(SkybellDevice):
"""A sensor implementation for Skybell devices."""
def __init__(self, device, sensor_type):
"""Initialize a sensor for a Skybell device."""
super().__init__(device)
self._sensor_type = sensor_type
self._icon = 'mdi:{}'.format(SENSOR_TYPES[self._sensor_type][1])
self._name = "{0} {1}".format(self._device.name,
SENSOR_TYPES[self._sensor_type][0])
self._state = None
@property
def name(self):
"""Return the name of the sensor."""
return self._name
@property
def state(self):
"""Return the state of the sensor."""
return self._state
@property
def icon(self):
"""Icon to use in the frontend, if any."""
return self._icon
def update(self):
"""Get the latest data and updates the state."""
super().update()
if self._sensor_type == 'chime_level':
self._state = self._device.outdoor_chime_level

View file

@ -0,0 +1,93 @@
"""
Support for the Skybell HD Doorbell.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/skybell/
"""
import logging
from requests.exceptions import HTTPError, ConnectTimeout
import voluptuous as vol
from homeassistant.const import (
ATTR_ATTRIBUTION, CONF_USERNAME, CONF_PASSWORD)
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.entity import Entity
REQUIREMENTS = ['skybellpy==0.1.1']
_LOGGER = logging.getLogger(__name__)
CONF_ATTRIBUTION = "Data provided by Skybell.com"
NOTIFICATION_ID = 'skybell_notification'
NOTIFICATION_TITLE = 'Skybell Sensor Setup'
DOMAIN = 'skybell'
DEFAULT_CACHEDB = './skybell_cache.pickle'
DEFAULT_ENTITY_NAMESPACE = 'skybell'
CONFIG_SCHEMA = vol.Schema({
DOMAIN: vol.Schema({
vol.Required(CONF_USERNAME): cv.string,
vol.Required(CONF_PASSWORD): cv.string,
}),
}, extra=vol.ALLOW_EXTRA)
def setup(hass, config):
"""Set up the Skybell component."""
conf = config[DOMAIN]
username = conf.get(CONF_USERNAME)
password = conf.get(CONF_PASSWORD)
try:
from skybellpy import Skybell
cache = hass.config.path(DEFAULT_CACHEDB)
skybell = Skybell(username=username, password=password,
get_devices=True, cache_path=cache)
hass.data[DOMAIN] = skybell
except (ConnectTimeout, HTTPError) as ex:
_LOGGER.error("Unable to connect to Skybell service: %s", str(ex))
hass.components.persistent_notification.create(
'Error: {}<br />'
'You will need to restart hass after fixing.'
''.format(ex),
title=NOTIFICATION_TITLE,
notification_id=NOTIFICATION_ID)
return False
return True
class SkybellDevice(Entity):
"""A HA implementation for Skybell devices."""
def __init__(self, device):
"""Initialize a sensor for Skybell device."""
self._device = device
@property
def should_poll(self):
"""Return the polling state."""
return True
def update(self):
"""Update automation 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,
'status': self._device.status,
'location': self._device.location,
'wifi_ssid': self._device.wifi_ssid,
'wifi_status': self._device.wifi_status,
'last_check_in': self._device.last_check_in,
'motion_threshold': self._device.motion_threshold,
'video_profile': self._device.video_profile,
}

View file

@ -0,0 +1,75 @@
"""
Switch support for the Skybell HD Doorbell.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/switch.skybell/
"""
import logging
import voluptuous as vol
from homeassistant.components.skybell import (
DEFAULT_ENTITY_NAMESPACE, DOMAIN as SKYBELL_DOMAIN, SkybellDevice)
from homeassistant.components.switch import PLATFORM_SCHEMA, SwitchDevice
from homeassistant.const import (
CONF_ENTITY_NAMESPACE, CONF_MONITORED_CONDITIONS)
import homeassistant.helpers.config_validation as cv
DEPENDENCIES = ['skybell']
_LOGGER = logging.getLogger(__name__)
# Switch types: Name
SWITCH_TYPES = {
'do_not_disturb': ['Do Not Disturb'],
'motion_sensor': ['Motion Sensor'],
}
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Optional(CONF_ENTITY_NAMESPACE, default=DEFAULT_ENTITY_NAMESPACE):
cv.string,
vol.Required(CONF_MONITORED_CONDITIONS, default=[]):
vol.All(cv.ensure_list, [vol.In(SWITCH_TYPES)]),
})
def setup_platform(hass, config, add_devices, discovery_info=None):
"""Set up the platform for a Skybell device."""
skybell = hass.data.get(SKYBELL_DOMAIN)
sensors = []
for switch_type in config.get(CONF_MONITORED_CONDITIONS):
for device in skybell.get_devices():
sensors.append(SkybellSwitch(device, switch_type))
add_devices(sensors, True)
class SkybellSwitch(SkybellDevice, SwitchDevice):
"""A switch implementation for Skybell devices."""
def __init__(self, device, switch_type):
"""Initialize a light for a Skybell device."""
super().__init__(device)
self._switch_type = switch_type
self._name = "{0} {1}".format(self._device.name,
SWITCH_TYPES[self._switch_type][0])
@property
def name(self):
"""Return the name of the sensor."""
return self._name
def turn_on(self, **kwargs):
"""Turn on the switch."""
setattr(self._device, self._switch_type, True)
def turn_off(self, **kwargs):
"""Turn on the switch."""
setattr(self._device, self._switch_type, False)
@property
def is_on(self):
"""Return true if device is on."""
return getattr(self._device, self._switch_type)

View file

@ -931,6 +931,9 @@ simplepush==1.1.3
# homeassistant.components.alarm_control_panel.simplisafe
simplisafe-python==1.0.5
# homeassistant.components.skybell
skybellpy==0.1.1
# homeassistant.components.notify.slack
slacker==0.9.60