Support for Blink Camera System (#6444)

* Passing pep8, no tests yet

* Fixed some issues with the request throttling

* Removed ability to set throttle time because it was causing more issues than it was worth

* Added blink to .coveragerc

* Changed blinkpy version

* Removed global var, fixed per PR requests

* Added services for camera, migrated switch to binary_sensor

* Added schema for service, fixed naming, removed unused function
This commit is contained in:
Kevin Fronczak 2017-03-07 17:26:53 -05:00 committed by Pascal Vizeli
parent 3508f74fb2
commit 629b2e81ba
6 changed files with 332 additions and 0 deletions

View file

@ -17,6 +17,9 @@ omit =
homeassistant/components/bbb_gpio.py
homeassistant/components/*/bbb_gpio.py
homeassistant/components/blink.py
homeassistant/components/*/blink.py
homeassistant/components/bloomsky.py
homeassistant/components/*/bloomsky.py

View file

@ -0,0 +1,74 @@
"""
Support for Blink system camera control.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/binary_sensor.blink/
"""
from homeassistant.components.blink import DOMAIN
from homeassistant.components.binary_sensor import BinarySensorDevice
DEPENDENCIES = ['blink']
def setup_platform(hass, config, add_devices, discovery_info=None):
"""Setup the blink binary sensors."""
if discovery_info is None:
return
data = hass.data[DOMAIN].blink
devs = list()
for name in data.cameras:
devs.append(BlinkCameraMotionSensor(name, data))
devs.append(BlinkSystemSensor(data))
add_devices(devs, True)
class BlinkCameraMotionSensor(BinarySensorDevice):
"""A representation of a Blink binary sensor."""
def __init__(self, name, data):
"""Initialize the sensor."""
self._name = 'blink_' + name + '_motion_enabled'
self._camera_name = name
self.data = data
self._state = self.data.cameras[self._camera_name].armed
@property
def name(self):
"""Return the name of the blink sensor."""
return self._name
@property
def is_on(self):
"""Return the status of the sensor."""
return self._state
def update(self):
"""Update sensor state."""
self.data.refresh()
self._state = self.data.cameras[self._camera_name].armed
class BlinkSystemSensor(BinarySensorDevice):
"""A representation of a Blink system sensor."""
def __init__(self, data):
"""Initialize the sensor."""
self._name = 'blink armed status'
self.data = data
self._state = self.data.arm
@property
def name(self):
"""Return the name of the blink sensor."""
return self._name.replace(" ", "_")
@property
def is_on(self):
"""Return the status of the sensor."""
return self._state
def update(self):
"""Update sensor state."""
self.data.refresh()
self._state = self.data.arm

View file

@ -0,0 +1,87 @@
"""
Support for Blink Home Camera System.
For more details about this component, please refer to the documentation at
https://home-assistant.io/components/blink/
"""
import logging
import voluptuous as vol
import homeassistant.helpers.config_validation as cv
from homeassistant.const import (CONF_USERNAME,
CONF_PASSWORD,
ATTR_FRIENDLY_NAME,
ATTR_ARMED)
from homeassistant.helpers import discovery
_LOGGER = logging.getLogger(__name__)
DOMAIN = 'blink'
REQUIREMENTS = ['blinkpy==0.4.4']
CONFIG_SCHEMA = vol.Schema({
DOMAIN: vol.Schema({
vol.Required(CONF_USERNAME): cv.string,
vol.Required(CONF_PASSWORD): cv.string
})
}, extra=vol.ALLOW_EXTRA)
ARM_SYSTEM_SCHEMA = vol.Schema({
vol.Optional(ATTR_ARMED): cv.boolean
})
ARM_CAMERA_SCHEMA = vol.Schema({
vol.Required(ATTR_FRIENDLY_NAME): cv.string,
vol.Optional(ATTR_ARMED): cv.boolean
})
SNAP_PICTURE_SCHEMA = vol.Schema({
vol.Required(ATTR_FRIENDLY_NAME): cv.string
})
class BlinkSystem(object):
"""Blink System class."""
def __init__(self, config_info):
"""Initialize the system."""
import blinkpy
self.blink = blinkpy.Blink(username=config_info[DOMAIN][CONF_USERNAME],
password=config_info[DOMAIN][CONF_PASSWORD])
self.blink.setup_system()
def setup(hass, config):
"""Setup Blink System."""
hass.data[DOMAIN] = BlinkSystem(config)
discovery.load_platform(hass, 'camera', DOMAIN, {}, config)
discovery.load_platform(hass, 'sensor', DOMAIN, {}, config)
discovery.load_platform(hass, 'binary_sensor', DOMAIN, {}, config)
def snap_picture(call):
"""Take a picture."""
cameras = hass.data[DOMAIN].blink.cameras
name = call.data.get(ATTR_FRIENDLY_NAME, '')
if name in cameras:
cameras[name].snap_picture()
def arm_camera(call):
"""Arm a camera."""
cameras = hass.data[DOMAIN].blink.cameras
name = call.data.get(ATTR_FRIENDLY_NAME, '')
value = call.data.get(ATTR_ARMED, True)
if name in cameras:
cameras[name].set_motion_detect(value)
def arm_system(call):
"""Arm the system."""
value = call.data.get(ATTR_ARMED, True)
hass.data[DOMAIN].blink.arm = value
hass.data[DOMAIN].blink.refresh()
hass.services.register(DOMAIN, 'snap_picture', snap_picture,
schema=SNAP_PICTURE_SCHEMA)
hass.services.register(DOMAIN, 'arm_camera', arm_camera,
schema=ARM_CAMERA_SCHEMA)
hass.services.register(DOMAIN, 'arm_system', arm_system,
schema=ARM_SYSTEM_SCHEMA)
return True

View file

@ -0,0 +1,81 @@
"""
Support for Blink system camera.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/camera.blink/
"""
import logging
from datetime import timedelta
import requests
from homeassistant.components.blink import DOMAIN
from homeassistant.components.camera import Camera
from homeassistant.util import Throttle
DEPENDENCIES = ['blink']
MIN_TIME_BETWEEN_UPDATES = timedelta(seconds=60)
_LOGGER = logging.getLogger(__name__)
def setup_platform(hass, config, add_devices, discovery_info=None):
"""Setup a Blink Camera."""
if discovery_info is None:
return
data = hass.data[DOMAIN].blink
devs = list()
for name in data.cameras:
devs.append(BlinkCamera(hass, config, data, name))
add_devices(devs)
class BlinkCamera(Camera):
"""An implementation of a Blink Camera."""
def __init__(self, hass, config, data, name):
"""Initialize a camera."""
super().__init__()
self.data = data
self.hass = hass
self._name = name
self.notifications = self.data.cameras[self._name].notifications
self.response = None
_LOGGER.info("Initialized blink camera %s", self._name)
@property
def name(self):
"""A camera name."""
return self._name
@Throttle(MIN_TIME_BETWEEN_UPDATES)
def request_image(self):
"""An image request from Blink servers."""
_LOGGER.info("Requesting new image from blink servers")
image_url = self.check_for_motion()
header = self.data.cameras[self._name].header
self.response = requests.get(image_url, headers=header, stream=True)
def check_for_motion(self):
"""A method to check if motion has been detected since last update."""
self.data.refresh()
notifs = self.data.cameras[self._name].notifications
if notifs > self.notifications:
# We detected motion at some point
self.data.last_motion()
self.notifications = notifs
# returning motion image currently not working
# return self.data.cameras[self._name].motion['image']
elif notifs < self.notifications:
self.notifications = notifs
return self.data.camera_thumbs[self._name]
def camera_image(self):
"""Return a still image reponse from the camera."""
self.request_image()
return self.response.content

View file

@ -0,0 +1,84 @@
"""
Support for Blink system camera sensors.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/sensor.blink/
"""
import logging
from homeassistant.components.blink import DOMAIN
from homeassistant.const import TEMP_FAHRENHEIT
from homeassistant.helpers.entity import Entity
DEPENDENCIES = ['blink']
SENSOR_TYPES = {
'temperature': ['Temperature', TEMP_FAHRENHEIT],
'battery': ['Battery', ''],
'notifications': ['Notifications', '']
}
_LOGGER = logging.getLogger(__name__)
def setup_platform(hass, config, add_devices, discovery_info=None):
"""Setup a Blink sensor."""
if discovery_info is None:
return
data = hass.data[DOMAIN].blink
devs = list()
index = 0
for name in data.cameras:
devs.append(BlinkSensor(name, 'temperature', index, data))
devs.append(BlinkSensor(name, 'battery', index, data))
devs.append(BlinkSensor(name, 'notifications', index, data))
index += 1
add_devices(devs, True)
class BlinkSensor(Entity):
"""A Blink camera sensor."""
def __init__(self, name, sensor_type, index, data):
"""A method to initialize sensors from Blink camera."""
self._name = 'blink_' + name + '_' + SENSOR_TYPES[sensor_type][0]
self._camera_name = name
self._type = sensor_type
self.data = data
self.index = index
self._state = None
self._unit_of_measurement = SENSOR_TYPES[sensor_type][1]
@property
def name(self):
"""A method to return the name of the camera."""
return self._name
@property
def state(self):
"""A camera's current state."""
return self._state
@property
def unique_id(self):
"""A unique camera sensor identifier."""
return "sensor_{}_{}".format(self._name, self.index)
@property
def unit_of_measurement(self):
"""A method to determine the unit of measurement for temperature."""
return self._unit_of_measurement
def update(self):
"""A method to retrieve sensor data from the camera."""
camera = self.data.cameras[self._camera_name]
if self._type == 'temperature':
self._state = camera.temperature
elif self._type == 'battery':
self._state = camera.battery
elif self._type == 'notifications':
self._state = camera.notifications
else:
self._state = None
_LOGGER.warning("Could not retrieve state from %s", self.name)

View file

@ -67,6 +67,9 @@ batinfo==0.4.2
# homeassistant.components.sensor.scrape
beautifulsoup4==4.5.3
# homeassistant.components.blink
blinkpy==0.4.4
# homeassistant.components.light.blinksticklight
blinkstick==1.1.8