mirror of
https://github.com/home-assistant/core.git
synced 2025-07-25 06:07:17 +00:00
DoorBird Component (#9281)
* DoorBird Component * add newlines at end of files * fix lint * fix doorbird components conventions * fix doorbird domain import and log strings * don't redundantly add switches * Remove return statement from setup_platform
This commit is contained in:
parent
811f6b4092
commit
5f24cc229d
@ -52,6 +52,9 @@ omit =
|
|||||||
|
|
||||||
homeassistant/components/digital_ocean.py
|
homeassistant/components/digital_ocean.py
|
||||||
homeassistant/components/*/digital_ocean.py
|
homeassistant/components/*/digital_ocean.py
|
||||||
|
|
||||||
|
homeassistant/components/doorbird.py
|
||||||
|
homeassistant/components/*/doorbird.py
|
||||||
|
|
||||||
homeassistant/components/dweet.py
|
homeassistant/components/dweet.py
|
||||||
homeassistant/components/*/dweet.py
|
homeassistant/components/*/dweet.py
|
||||||
|
60
homeassistant/components/binary_sensor/doorbird.py
Normal file
60
homeassistant/components/binary_sensor/doorbird.py
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
"""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()
|
90
homeassistant/components/camera/doorbird.py
Normal file
90
homeassistant/components/camera/doorbird.py
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
"""Support for viewing the camera feed from a DoorBird video doorbell."""
|
||||||
|
|
||||||
|
import asyncio
|
||||||
|
import datetime
|
||||||
|
import logging
|
||||||
|
import voluptuous as vol
|
||||||
|
|
||||||
|
import aiohttp
|
||||||
|
import async_timeout
|
||||||
|
|
||||||
|
from homeassistant.components.camera import PLATFORM_SCHEMA, Camera
|
||||||
|
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
|
||||||
|
|
||||||
|
DEPENDENCIES = ['doorbird']
|
||||||
|
|
||||||
|
_CAMERA_LIVE = "DoorBird Live"
|
||||||
|
_CAMERA_LAST_VISITOR = "DoorBird Last Ring"
|
||||||
|
_LIVE_INTERVAL = datetime.timedelta(seconds=1)
|
||||||
|
_LAST_VISITOR_INTERVAL = datetime.timedelta(minutes=1)
|
||||||
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
_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
|
||||||
|
def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
|
||||||
|
"""Set up the DoorBird camera platform."""
|
||||||
|
device = hass.data.get(DOORBIRD_DOMAIN)
|
||||||
|
|
||||||
|
_LOGGER.debug("Adding DoorBird camera %s", _CAMERA_LIVE)
|
||||||
|
entities = [DoorBirdCamera(device.live_image_url, _CAMERA_LIVE,
|
||||||
|
_LIVE_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):
|
||||||
|
"""The camera on a DoorBird device."""
|
||||||
|
|
||||||
|
def __init__(self, url, name, interval=None):
|
||||||
|
"""Initialize the camera on a DoorBird device."""
|
||||||
|
self._url = url
|
||||||
|
self._name = name
|
||||||
|
self._last_image = None
|
||||||
|
self._interval = interval or datetime.timedelta
|
||||||
|
self._last_update = datetime.datetime.min
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def name(self):
|
||||||
|
"""Get the name of the camera."""
|
||||||
|
return self._name
|
||||||
|
|
||||||
|
@asyncio.coroutine
|
||||||
|
def async_camera_image(self):
|
||||||
|
"""Pull a still image from the camera."""
|
||||||
|
now = datetime.datetime.now()
|
||||||
|
|
||||||
|
if self._last_image and now - self._last_update < self._interval:
|
||||||
|
return self._last_image
|
||||||
|
|
||||||
|
try:
|
||||||
|
websession = async_get_clientsession(self.hass)
|
||||||
|
|
||||||
|
with async_timeout.timeout(_TIMEOUT, loop=self.hass.loop):
|
||||||
|
response = yield from websession.get(self._url)
|
||||||
|
|
||||||
|
self._last_image = yield from response.read()
|
||||||
|
self._last_update = now
|
||||||
|
return self._last_image
|
||||||
|
except asyncio.TimeoutError:
|
||||||
|
_LOGGER.error("Camera image timed out")
|
||||||
|
return self._last_image
|
||||||
|
except aiohttp.ClientError as error:
|
||||||
|
_LOGGER.error("Error getting camera image: %s", error)
|
||||||
|
return self._last_image
|
44
homeassistant/components/doorbird.py
Normal file
44
homeassistant/components/doorbird.py
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
"""Support for a DoorBird video doorbell."""
|
||||||
|
|
||||||
|
import logging
|
||||||
|
import voluptuous as vol
|
||||||
|
|
||||||
|
from homeassistant.const import CONF_HOST, CONF_USERNAME, CONF_PASSWORD
|
||||||
|
import homeassistant.helpers.config_validation as cv
|
||||||
|
|
||||||
|
REQUIREMENTS = ['DoorBirdPy==0.0.4']
|
||||||
|
|
||||||
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
DOMAIN = 'doorbird'
|
||||||
|
|
||||||
|
CONFIG_SCHEMA = vol.Schema({
|
||||||
|
DOMAIN: vol.Schema({
|
||||||
|
vol.Required(CONF_HOST): cv.string,
|
||||||
|
vol.Required(CONF_USERNAME): cv.string,
|
||||||
|
vol.Required(CONF_PASSWORD): cv.string
|
||||||
|
})
|
||||||
|
}, extra=vol.ALLOW_EXTRA)
|
||||||
|
|
||||||
|
|
||||||
|
def setup(hass, config):
|
||||||
|
"""Set up the DoorBird component."""
|
||||||
|
device_ip = config[DOMAIN].get(CONF_HOST)
|
||||||
|
username = config[DOMAIN].get(CONF_USERNAME)
|
||||||
|
password = config[DOMAIN].get(CONF_PASSWORD)
|
||||||
|
|
||||||
|
from doorbirdpy import DoorBird
|
||||||
|
device = DoorBird(device_ip, username, password)
|
||||||
|
status = device.ready()
|
||||||
|
|
||||||
|
if status[0]:
|
||||||
|
_LOGGER.info("Connected to DoorBird at %s as %s", device_ip, username)
|
||||||
|
hass.data[DOMAIN] = device
|
||||||
|
return True
|
||||||
|
elif status[1] == 401:
|
||||||
|
_LOGGER.error("Authorization rejected by DoorBird at %s", device_ip)
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
_LOGGER.error("Could not connect to DoorBird at %s: Error %s",
|
||||||
|
device_ip, str(status[1]))
|
||||||
|
return False
|
97
homeassistant/components/switch/doorbird.py
Normal file
97
homeassistant/components/switch/doorbird.py
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
"""Support for powering relays in a DoorBird video doorbell."""
|
||||||
|
import datetime
|
||||||
|
import logging
|
||||||
|
import voluptuous as vol
|
||||||
|
|
||||||
|
from homeassistant.components.doorbird import DOMAIN as DOORBIRD_DOMAIN
|
||||||
|
from homeassistant.components.switch import SwitchDevice, PLATFORM_SCHEMA
|
||||||
|
from homeassistant.const import CONF_SWITCHES
|
||||||
|
import homeassistant.helpers.config_validation as cv
|
||||||
|
|
||||||
|
DEPENDENCIES = ['doorbird']
|
||||||
|
|
||||||
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
SWITCHES = {
|
||||||
|
"open_door": {
|
||||||
|
"name": "Open Door",
|
||||||
|
"icon": {
|
||||||
|
True: "lock-open",
|
||||||
|
False: "lock"
|
||||||
|
},
|
||||||
|
"time": datetime.timedelta(seconds=3)
|
||||||
|
},
|
||||||
|
"light_on": {
|
||||||
|
"name": "Light On",
|
||||||
|
"icon": {
|
||||||
|
True: "lightbulb-on",
|
||||||
|
False: "lightbulb"
|
||||||
|
},
|
||||||
|
"time": datetime.timedelta(minutes=5)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
|
||||||
|
vol.Required(CONF_SWITCHES, default=[]):
|
||||||
|
vol.All(cv.ensure_list([vol.In(SWITCHES)]))
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
def setup_platform(hass, config, add_devices, discovery_info=None):
|
||||||
|
"""Set up the DoorBird switch platform."""
|
||||||
|
device = hass.data.get(DOORBIRD_DOMAIN)
|
||||||
|
|
||||||
|
switches = []
|
||||||
|
for switch in SWITCHES:
|
||||||
|
_LOGGER.debug("Adding DoorBird switch %s", SWITCHES[switch]["name"])
|
||||||
|
switches.append(DoorBirdSwitch(device, switch))
|
||||||
|
|
||||||
|
add_devices(switches)
|
||||||
|
_LOGGER.info("Added DoorBird switches")
|
||||||
|
|
||||||
|
|
||||||
|
class DoorBirdSwitch(SwitchDevice):
|
||||||
|
"""A relay in a DoorBird device."""
|
||||||
|
|
||||||
|
def __init__(self, device, switch):
|
||||||
|
"""Initialize a relay in a DoorBird device."""
|
||||||
|
self._device = device
|
||||||
|
self._switch = switch
|
||||||
|
self._state = False
|
||||||
|
self._assume_off = datetime.datetime.min
|
||||||
|
|
||||||
|
@property
|
||||||
|
def name(self):
|
||||||
|
"""Get the name of the switch."""
|
||||||
|
return SWITCHES[self._switch]["name"]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def icon(self):
|
||||||
|
"""Get an icon to display."""
|
||||||
|
return "mdi:{}".format(SWITCHES[self._switch]["icon"][self._state])
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_on(self):
|
||||||
|
"""Get the assumed state of the relay."""
|
||||||
|
return self._state
|
||||||
|
|
||||||
|
def turn_on(self, **kwargs):
|
||||||
|
"""Power the relay."""
|
||||||
|
if self._switch == "open_door":
|
||||||
|
self._state = self._device.open_door()
|
||||||
|
elif self._switch == "light_on":
|
||||||
|
self._state = self._device.turn_light_on()
|
||||||
|
|
||||||
|
now = datetime.datetime.now()
|
||||||
|
self._assume_off = now + SWITCHES[self._switch]["time"]
|
||||||
|
|
||||||
|
def turn_off(self, **kwargs):
|
||||||
|
"""The relays are time-based."""
|
||||||
|
raise NotImplementedError("DoorBird relays cannot be manually turned "
|
||||||
|
"off.")
|
||||||
|
|
||||||
|
def update(self):
|
||||||
|
"""Wait for the correct amount of assumed time to pass."""
|
||||||
|
if self._state and self._assume_off <= datetime.datetime.now():
|
||||||
|
self._state = False
|
||||||
|
self._assume_off = datetime.datetime.min
|
@ -17,6 +17,9 @@ astral==1.4
|
|||||||
# homeassistant.components.bbb_gpio
|
# homeassistant.components.bbb_gpio
|
||||||
# Adafruit_BBIO==1.0.0
|
# Adafruit_BBIO==1.0.0
|
||||||
|
|
||||||
|
# homeassistant.components.doorbird
|
||||||
|
DoorBirdPy==0.0.4
|
||||||
|
|
||||||
# homeassistant.components.isy994
|
# homeassistant.components.isy994
|
||||||
PyISY==1.0.8
|
PyISY==1.0.8
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user