DoorBird feature update (#11193)
* Allow disabling the DoorBird camera live view * Support for push notifications from DoorBird devices * use DoorBirdPy 0.1.1 instead of 0.1.0 * Fix lint errors in DoorBird binary sensor * Change DoorBird push notifications from binary sensor to event * Remove DoorBird camera options * use DoorBirdPy 0.1.2 to fix history image urls * clean up doorbird event code and remove unused doorbird camera imports * use async for doorbird doorbell events * Minor changes * Update file header * Fix my mess * Fix docstringpull/11362/head
parent
9a34e7174c
commit
6b586c268a
|
@ -1,60 +0,0 @@
|
||||||
"""Support for reading binary states from a DoorBird video doorbell."""
|
|
||||||
from datetime import timedelta
|
|
||||||
import logging
|
|
||||||
|
|
||||||
from homeassistant.components.binary_sensor import BinarySensorDevice
|
|
||||||
from homeassistant.components.doorbird import DOMAIN as DOORBIRD_DOMAIN
|
|
||||||
from homeassistant.util import Throttle
|
|
||||||
|
|
||||||
DEPENDENCIES = ['doorbird']
|
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
|
||||||
_MIN_UPDATE_INTERVAL = timedelta(milliseconds=250)
|
|
||||||
|
|
||||||
SENSOR_TYPES = {
|
|
||||||
"doorbell": {
|
|
||||||
"name": "Doorbell Ringing",
|
|
||||||
"icon": {
|
|
||||||
True: "bell-ring",
|
|
||||||
False: "bell",
|
|
||||||
None: "bell-outline"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def setup_platform(hass, config, add_devices, discovery_info=None):
|
|
||||||
"""Set up the DoorBird binary sensor component."""
|
|
||||||
device = hass.data.get(DOORBIRD_DOMAIN)
|
|
||||||
add_devices([DoorBirdBinarySensor(device, "doorbell")], True)
|
|
||||||
|
|
||||||
|
|
||||||
class DoorBirdBinarySensor(BinarySensorDevice):
|
|
||||||
"""A binary sensor of a DoorBird device."""
|
|
||||||
|
|
||||||
def __init__(self, device, sensor_type):
|
|
||||||
"""Initialize a binary sensor on a DoorBird device."""
|
|
||||||
self._device = device
|
|
||||||
self._sensor_type = sensor_type
|
|
||||||
self._state = None
|
|
||||||
|
|
||||||
@property
|
|
||||||
def name(self):
|
|
||||||
"""Get the name of the sensor."""
|
|
||||||
return SENSOR_TYPES[self._sensor_type]["name"]
|
|
||||||
|
|
||||||
@property
|
|
||||||
def icon(self):
|
|
||||||
"""Get an icon to display."""
|
|
||||||
state_icon = SENSOR_TYPES[self._sensor_type]["icon"][self._state]
|
|
||||||
return "mdi:{}".format(state_icon)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def is_on(self):
|
|
||||||
"""Get the state of the binary sensor."""
|
|
||||||
return self._state
|
|
||||||
|
|
||||||
@Throttle(_MIN_UPDATE_INTERVAL)
|
|
||||||
def update(self):
|
|
||||||
"""Pull the latest value from the device."""
|
|
||||||
self._state = self._device.doorbell_state()
|
|
|
@ -1,51 +1,40 @@
|
||||||
"""Support for viewing the camera feed from a DoorBird video doorbell."""
|
"""
|
||||||
|
Support for viewing the camera feed from a DoorBird video doorbell.
|
||||||
|
|
||||||
|
For more details about this platform, please refer to the documentation at
|
||||||
|
https://home-assistant.io/components/camera.doorbird/
|
||||||
|
"""
|
||||||
import asyncio
|
import asyncio
|
||||||
import datetime
|
import datetime
|
||||||
import logging
|
import logging
|
||||||
import voluptuous as vol
|
|
||||||
|
|
||||||
import aiohttp
|
import aiohttp
|
||||||
import async_timeout
|
import async_timeout
|
||||||
|
|
||||||
from homeassistant.components.camera import PLATFORM_SCHEMA, Camera
|
from homeassistant.components.camera import Camera
|
||||||
from homeassistant.components.doorbird import DOMAIN as DOORBIRD_DOMAIN
|
from homeassistant.components.doorbird import DOMAIN as DOORBIRD_DOMAIN
|
||||||
from homeassistant.helpers import config_validation as cv
|
|
||||||
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
||||||
|
|
||||||
DEPENDENCIES = ['doorbird']
|
DEPENDENCIES = ['doorbird']
|
||||||
|
|
||||||
_CAMERA_LIVE = "DoorBird Live"
|
|
||||||
_CAMERA_LAST_VISITOR = "DoorBird Last Ring"
|
_CAMERA_LAST_VISITOR = "DoorBird Last Ring"
|
||||||
_LIVE_INTERVAL = datetime.timedelta(seconds=1)
|
_CAMERA_LIVE = "DoorBird Live"
|
||||||
_LAST_VISITOR_INTERVAL = datetime.timedelta(minutes=1)
|
_LAST_VISITOR_INTERVAL = datetime.timedelta(minutes=1)
|
||||||
|
_LIVE_INTERVAL = datetime.timedelta(seconds=1)
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
_TIMEOUT = 10 # seconds
|
_TIMEOUT = 10 # seconds
|
||||||
|
|
||||||
CONF_SHOW_LAST_VISITOR = 'last_visitor'
|
|
||||||
|
|
||||||
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
|
|
||||||
vol.Optional(CONF_SHOW_LAST_VISITOR, default=False): cv.boolean
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
|
def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
|
||||||
"""Set up the DoorBird camera platform."""
|
"""Set up the DoorBird camera platform."""
|
||||||
device = hass.data.get(DOORBIRD_DOMAIN)
|
device = hass.data.get(DOORBIRD_DOMAIN)
|
||||||
|
async_add_devices([
|
||||||
_LOGGER.debug("Adding DoorBird camera %s", _CAMERA_LIVE)
|
DoorBirdCamera(device.live_image_url, _CAMERA_LIVE, _LIVE_INTERVAL),
|
||||||
entities = [DoorBirdCamera(device.live_image_url, _CAMERA_LIVE,
|
DoorBirdCamera(
|
||||||
_LIVE_INTERVAL)]
|
device.history_image_url(1, 'doorbell'), _CAMERA_LAST_VISITOR,
|
||||||
|
_LAST_VISITOR_INTERVAL),
|
||||||
if config.get(CONF_SHOW_LAST_VISITOR):
|
])
|
||||||
_LOGGER.debug("Adding DoorBird camera %s", _CAMERA_LAST_VISITOR)
|
|
||||||
entities.append(DoorBirdCamera(device.history_image_url(1),
|
|
||||||
_CAMERA_LAST_VISITOR,
|
|
||||||
_LAST_VISITOR_INTERVAL))
|
|
||||||
|
|
||||||
async_add_devices(entities)
|
|
||||||
_LOGGER.info("Added DoorBird camera(s)")
|
|
||||||
|
|
||||||
|
|
||||||
class DoorBirdCamera(Camera):
|
class DoorBirdCamera(Camera):
|
||||||
|
@ -75,7 +64,6 @@ class DoorBirdCamera(Camera):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
websession = async_get_clientsession(self.hass)
|
websession = async_get_clientsession(self.hass)
|
||||||
|
|
||||||
with async_timeout.timeout(_TIMEOUT, loop=self.hass.loop):
|
with async_timeout.timeout(_TIMEOUT, loop=self.hass.loop):
|
||||||
response = yield from websession.get(self._url)
|
response = yield from websession.get(self._url)
|
||||||
|
|
||||||
|
|
|
@ -1,40 +1,54 @@
|
||||||
"""Support for a DoorBird video doorbell."""
|
"""
|
||||||
|
Support for DoorBird device.
|
||||||
|
|
||||||
|
For more details about this component, please refer to the documentation at
|
||||||
|
https://home-assistant.io/components/doorbird/
|
||||||
|
"""
|
||||||
|
import asyncio
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
|
|
||||||
from homeassistant.const import CONF_HOST, CONF_USERNAME, CONF_PASSWORD
|
from homeassistant.const import CONF_HOST, CONF_USERNAME, CONF_PASSWORD
|
||||||
|
from homeassistant.components.http import HomeAssistantView
|
||||||
import homeassistant.helpers.config_validation as cv
|
import homeassistant.helpers.config_validation as cv
|
||||||
|
|
||||||
REQUIREMENTS = ['DoorBirdPy==0.1.0']
|
REQUIREMENTS = ['DoorBirdPy==0.1.2']
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
DOMAIN = 'doorbird'
|
DOMAIN = 'doorbird'
|
||||||
|
|
||||||
|
API_URL = '/api/{}'.format(DOMAIN)
|
||||||
|
|
||||||
|
CONF_DOORBELL_EVENTS = 'doorbell_events'
|
||||||
|
|
||||||
CONFIG_SCHEMA = vol.Schema({
|
CONFIG_SCHEMA = vol.Schema({
|
||||||
DOMAIN: vol.Schema({
|
DOMAIN: vol.Schema({
|
||||||
vol.Required(CONF_HOST): cv.string,
|
vol.Required(CONF_HOST): cv.string,
|
||||||
vol.Required(CONF_USERNAME): cv.string,
|
vol.Required(CONF_USERNAME): cv.string,
|
||||||
vol.Required(CONF_PASSWORD): cv.string
|
vol.Required(CONF_PASSWORD): cv.string,
|
||||||
|
vol.Optional(CONF_DOORBELL_EVENTS): cv.boolean,
|
||||||
})
|
})
|
||||||
}, extra=vol.ALLOW_EXTRA)
|
}, extra=vol.ALLOW_EXTRA)
|
||||||
|
|
||||||
|
SENSOR_DOORBELL = 'doorbell'
|
||||||
|
|
||||||
|
|
||||||
def setup(hass, config):
|
def setup(hass, config):
|
||||||
"""Set up the DoorBird component."""
|
"""Set up the DoorBird component."""
|
||||||
|
from doorbirdpy import DoorBird
|
||||||
|
|
||||||
device_ip = config[DOMAIN].get(CONF_HOST)
|
device_ip = config[DOMAIN].get(CONF_HOST)
|
||||||
username = config[DOMAIN].get(CONF_USERNAME)
|
username = config[DOMAIN].get(CONF_USERNAME)
|
||||||
password = config[DOMAIN].get(CONF_PASSWORD)
|
password = config[DOMAIN].get(CONF_PASSWORD)
|
||||||
|
|
||||||
from doorbirdpy import DoorBird
|
|
||||||
device = DoorBird(device_ip, username, password)
|
device = DoorBird(device_ip, username, password)
|
||||||
status = device.ready()
|
status = device.ready()
|
||||||
|
|
||||||
if status[0]:
|
if status[0]:
|
||||||
_LOGGER.info("Connected to DoorBird at %s as %s", device_ip, username)
|
_LOGGER.info("Connected to DoorBird at %s as %s", device_ip, username)
|
||||||
hass.data[DOMAIN] = device
|
hass.data[DOMAIN] = device
|
||||||
return True
|
|
||||||
elif status[1] == 401:
|
elif status[1] == 401:
|
||||||
_LOGGER.error("Authorization rejected by DoorBird at %s", device_ip)
|
_LOGGER.error("Authorization rejected by DoorBird at %s", device_ip)
|
||||||
return False
|
return False
|
||||||
|
@ -42,3 +56,31 @@ def setup(hass, config):
|
||||||
_LOGGER.error("Could not connect to DoorBird at %s: Error %s",
|
_LOGGER.error("Could not connect to DoorBird at %s: Error %s",
|
||||||
device_ip, str(status[1]))
|
device_ip, str(status[1]))
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
if config[DOMAIN].get(CONF_DOORBELL_EVENTS):
|
||||||
|
# Provide an endpoint for the device to call to trigger events
|
||||||
|
hass.http.register_view(DoorbirdRequestView())
|
||||||
|
|
||||||
|
# This will make HA the only service that gets doorbell events
|
||||||
|
url = '{}{}/{}'.format(
|
||||||
|
hass.config.api.base_url, API_URL, SENSOR_DOORBELL)
|
||||||
|
device.reset_notifications()
|
||||||
|
device.subscribe_notification(SENSOR_DOORBELL, url)
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
class DoorbirdRequestView(HomeAssistantView):
|
||||||
|
"""Provide a page for the device to call."""
|
||||||
|
|
||||||
|
url = API_URL
|
||||||
|
name = API_URL[1:].replace('/', ':')
|
||||||
|
extra_urls = [API_URL + '/{sensor}']
|
||||||
|
|
||||||
|
# pylint: disable=no-self-use
|
||||||
|
@asyncio.coroutine
|
||||||
|
def get(self, request, sensor):
|
||||||
|
"""Respond to requests from the device."""
|
||||||
|
hass = request.app['hass']
|
||||||
|
hass.bus.async_fire('{}_{}'.format(DOMAIN, sensor))
|
||||||
|
return 'OK'
|
||||||
|
|
|
@ -20,7 +20,7 @@ certifi>=2017.4.17
|
||||||
# Adafruit_BBIO==1.0.0
|
# Adafruit_BBIO==1.0.0
|
||||||
|
|
||||||
# homeassistant.components.doorbird
|
# homeassistant.components.doorbird
|
||||||
DoorBirdPy==0.1.0
|
DoorBirdPy==0.1.2
|
||||||
|
|
||||||
# homeassistant.components.isy994
|
# homeassistant.components.isy994
|
||||||
PyISY==1.1.0
|
PyISY==1.1.0
|
||||||
|
|
Loading…
Reference in New Issue