From 39c6484d89337240918ffe60c35705b5b3405705 Mon Sep 17 00:00:00 2001 From: Andy Castille Date: Sun, 2 Jul 2017 00:16:47 -0500 Subject: [PATCH 01/17] use upstream RachioPy, fix manual run switches --- homeassistant/components/switch/rachio.py | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/homeassistant/components/switch/rachio.py b/homeassistant/components/switch/rachio.py index 63809fd4456ea7..6acbea8e95ceac 100644 --- a/homeassistant/components/switch/rachio.py +++ b/homeassistant/components/switch/rachio.py @@ -8,7 +8,7 @@ from homeassistant.components.switch import SwitchDevice, PLATFORM_SCHEMA from homeassistant.const import CONF_ACCESS_TOKEN -REQUIREMENTS = ['rachiopy==0.1.2'] +REQUIREMENTS = ['rachiopy==0.1.1'] _LOGGER = logging.getLogger(__name__) @@ -17,7 +17,7 @@ CONF_MANUAL_RUN_MINS = 'manual_run_mins' DEFAULT_MANUAL_RUN_MINS = 10 -MIN_UPDATE_INTERVAL = timedelta(minutes=5) +MIN_UPDATE_INTERVAL = timedelta(seconds=30) MIN_FORCED_UPDATE_INTERVAL = timedelta(seconds=1) PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ @@ -27,7 +27,6 @@ }) -# noinspection PyUnusedLocal def setup_platform(hass, config, add_devices, discovery_info=None): """Set up the component.""" # Get options @@ -215,14 +214,11 @@ def update(self): def turn_on(self): """Start the zone.""" - # Convert minutes to seconds - seconds = self._manual_run_secs * 60 - # Stop other zones first self.turn_off() - _LOGGER.info("Watering %s for %d sec", self.name, seconds) - self.rachio.zone.start(self.zone_id, seconds) + _LOGGER.info("Watering %s for %d s", self.name, self._manual_run_secs) + self.rachio.zone.start(self.zone_id, self._manual_run_secs) def turn_off(self): """Stop all zones.""" From 1d8575b6513bf74f7842bfc69aa252ed214536e5 Mon Sep 17 00:00:00 2001 From: Andy Castille Date: Sun, 2 Jul 2017 00:26:22 -0500 Subject: [PATCH 02/17] Update requirements for PyPi version of rachiopy --- requirements_all.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements_all.txt b/requirements_all.txt index c0ae35d7eed644..5ffc6b1ece9ae5 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -775,7 +775,7 @@ pyzabbix==0.7.4 qnapstats==0.2.4 # homeassistant.components.switch.rachio -rachiopy==0.1.2 +rachiopy==0.1.1 # homeassistant.components.climate.radiotherm radiotherm==1.3 From d7979effa7d22ab4895097178840bdabbda50fd0 Mon Sep 17 00:00:00 2001 From: Andy Castille Date: Fri, 7 Jul 2017 22:21:01 -0500 Subject: [PATCH 03/17] Use upstream RachioPy 0.1.2 (partial revert of https://github.com/Klikini/home-assistant/commit/39c6484d89337240918ffe60c35705b5b3405705) --- homeassistant/components/switch/rachio.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/switch/rachio.py b/homeassistant/components/switch/rachio.py index 6acbea8e95ceac..db6854633f6d4d 100644 --- a/homeassistant/components/switch/rachio.py +++ b/homeassistant/components/switch/rachio.py @@ -8,7 +8,7 @@ from homeassistant.components.switch import SwitchDevice, PLATFORM_SCHEMA from homeassistant.const import CONF_ACCESS_TOKEN -REQUIREMENTS = ['rachiopy==0.1.1'] +REQUIREMENTS = ['rachiopy==0.1.2'] _LOGGER = logging.getLogger(__name__) From 206904dc65008ec0d3a30cbd1c73985373b1a3f4 Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Sat, 8 Jul 2017 10:33:13 +0200 Subject: [PATCH 04/17] Revert rachiopy downgrade --- requirements_all.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements_all.txt b/requirements_all.txt index 5ffc6b1ece9ae5..c0ae35d7eed644 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -775,7 +775,7 @@ pyzabbix==0.7.4 qnapstats==0.2.4 # homeassistant.components.switch.rachio -rachiopy==0.1.1 +rachiopy==0.1.2 # homeassistant.components.climate.radiotherm radiotherm==1.3 From 96313d26e7e21f3811ab1b2fd58c8ccb819716fd Mon Sep 17 00:00:00 2001 From: Andy Castille Date: Sun, 6 Aug 2017 10:34:09 -0500 Subject: [PATCH 05/17] DoorBird base component --- homeassistant/components/doorbird.py | 49 ++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 homeassistant/components/doorbird.py diff --git a/homeassistant/components/doorbird.py b/homeassistant/components/doorbird.py new file mode 100644 index 00000000000000..80bd8e27c8bd28 --- /dev/null +++ b/homeassistant/components/doorbird.py @@ -0,0 +1,49 @@ +""" +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.""" + ip = config[DOMAIN].get(CONF_HOST) + username = config[DOMAIN].get(CONF_USERNAME) + password = config[DOMAIN].get(CONF_PASSWORD) + + from doorbirdpy import DoorBird + device = DoorBird(ip, username, password) + status = device.ready() + + if status[0]: + _LOGGER.info("Connected to DoorBird at {} as {}" + .format(ip, username)) + hass.data[DOMAIN] = device + _LOGGER.debug("DBDBG set device") + return True + elif status[1] == 401: + _LOGGER.error("Authorization rejected by DoorBird at {} for {}" + .format(ip, username)) + return False + else: + _LOGGER.error("Could not connect to DoorBird at {} as {}: DBP error {}" + .format(ip, username, status[1])) + return False From 44b19696fdc2352cd39030de8f79c1b33abc11ae Mon Sep 17 00:00:00 2001 From: Andy Castille Date: Sun, 6 Aug 2017 10:34:25 -0500 Subject: [PATCH 06/17] DoorBird cameras --- homeassistant/components/camera/doorbird.py | 97 +++++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 homeassistant/components/camera/doorbird.py diff --git a/homeassistant/components/camera/doorbird.py b/homeassistant/components/camera/doorbird.py new file mode 100644 index 00000000000000..bb0a0d3e977f5e --- /dev/null +++ b/homeassistant/components/camera/doorbird.py @@ -0,0 +1,97 @@ +""" +Support for viewing the camera feed from a DoorBird video doorbell. +""" + +import aiohttp +import asyncio +import async_timeout +import datetime +import logging +import voluptuous as vol + +from homeassistant.components.camera import PLATFORM_SCHEMA, Camera +from homeassistant.components.doorbird import DOMAIN +from homeassistant.helpers import config_validation as cv +from homeassistant.helpers.aiohttp_client import async_get_clientsession +from homeassistant.util.async import run_coroutine_threadsafe + +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.Required(CONF_SHOW_LAST_VISITOR, default=False): cv.boolean +}) + + +@asyncio.coroutine +def async_setup_platform(hass, config, async_add_devices, discovery_info=None): + device = hass.data.get(DOMAIN) + + _LOGGER.debug("Adding DoorBird camera " + _CAMERA_LIVE) + entities = [DoorBirdCamera(hass, device.live_image_url, _CAMERA_LIVE, + _LIVE_INTERVAL)] + + if config.get(CONF_SHOW_LAST_VISITOR): + _LOGGER.debug("Adding DoorBird camera " + _CAMERA_LAST_VISITOR) + entities.append(DoorBirdCamera(hass, device.history_image_url(1), + _CAMERA_LAST_VISITOR, + _LAST_VISITOR_INTERVAL)) + + async_add_devices(entities) + _LOGGER.info("Added DoorBird camera(s)") + return True + + +class DoorBirdCamera(Camera): + def __init__(self, hass, url, name, interval=None): + """Initialize the camera on a DoorBird device.""" + self._hass = hass + 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): + """:returns: The name of the camera.""" + return self._name + + def camera_image(self): + """:returns: The bytes of a camera image.""" + return run_coroutine_threadsafe( + self.async_camera_image(), self._hass.loop).result() + + @asyncio.coroutine + def async_camera_image(self): + """:returns: 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 From a7e70f1cb18f14461bb238d932ad2393183f93ac Mon Sep 17 00:00:00 2001 From: Andy Castille Date: Sun, 6 Aug 2017 10:34:37 -0500 Subject: [PATCH 07/17] DoorBird binary sensors --- .../components/binary_sensor/doorbird.py | 79 +++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 homeassistant/components/binary_sensor/doorbird.py diff --git a/homeassistant/components/binary_sensor/doorbird.py b/homeassistant/components/binary_sensor/doorbird.py new file mode 100644 index 00000000000000..a863e6afb098f6 --- /dev/null +++ b/homeassistant/components/binary_sensor/doorbird.py @@ -0,0 +1,79 @@ +""" +Support for reading binary states from a DoorBird video doorbell. +""" +from datetime import timedelta +import logging +import voluptuous as vol + +from homeassistant.components.binary_sensor import BinarySensorDevice,\ + PLATFORM_SCHEMA +from homeassistant.components.doorbird import DOMAIN +import homeassistant.helpers.config_validation as cv +from homeassistant.const import CONF_MONITORED_CONDITIONS, STATE_UNKNOWN +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", + STATE_UNKNOWN: "bell-outline" + } + } +} + +PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ + 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): + device = hass.data.get(DOMAIN) + + sensors = [] + for sensor_type in config.get(CONF_MONITORED_CONDITIONS): + if sensor_type == "doorbell": + _LOGGER.debug("Adding DoorBird binary sensor " + + str(SENSOR_TYPES[sensor_type]["name"])) + sensors.append(DoorBirdBinarySensor(device, sensor_type)) + + add_devices(sensors, True) + _LOGGER.info("Added DoorBird binary sensors") + return True + + +class DoorBirdBinarySensor(BinarySensorDevice): + def __init__(self, device, sensor_type): + """Initialize a binary sensor on a DoorBird device.""" + self._device = device + self._sensor_type = sensor_type + self._state = STATE_UNKNOWN + super(DoorBirdBinarySensor, self).__init__() + + @property + def name(self): + """:returns: The name of the sensor.""" + return SENSOR_TYPES[self._sensor_type]["name"] + + @property + def icon(self): + """:returns: An icon to display.""" + icon = SENSOR_TYPES[self._sensor_type]["icon"][self._state] + return "mdi:" + str(icon) + + @property + def is_on(self): + """:returns: The state of the binary sensor.""" + return self._state + + @Throttle(_MIN_UPDATE_INTERVAL) + def update(self): + """Pulls the latest value from the device.""" + self._state = self._device.doorbell_state() From 648927e02298abdade55a9a00db5fe9fc783f8ca Mon Sep 17 00:00:00 2001 From: Andy Castille Date: Sun, 6 Aug 2017 11:02:15 -0500 Subject: [PATCH 08/17] Sanity check --- homeassistant/components/binary_sensor/doorbird.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/homeassistant/components/binary_sensor/doorbird.py b/homeassistant/components/binary_sensor/doorbird.py index a863e6afb098f6..15fcac7e9b6824 100644 --- a/homeassistant/components/binary_sensor/doorbird.py +++ b/homeassistant/components/binary_sensor/doorbird.py @@ -52,6 +52,10 @@ def setup_platform(hass, config, add_devices, discovery_info=None): class DoorBirdBinarySensor(BinarySensorDevice): def __init__(self, device, sensor_type): """Initialize a binary sensor on a DoorBird device.""" + if sensor_type not in SENSOR_TYPES: + msg = sensor_type + " is not a valid DoorBird binary sensor" + raise NotImplementedError(msg) + self._device = device self._sensor_type = sensor_type self._state = STATE_UNKNOWN From 4c0baf708836d9c26b0d7125768d7177f2da460d Mon Sep 17 00:00:00 2001 From: Andy Castille Date: Sun, 6 Aug 2017 11:06:32 -0500 Subject: [PATCH 09/17] DoorBird switches --- homeassistant/components/switch/doorbird.py | 102 ++++++++++++++++++++ 1 file changed, 102 insertions(+) create mode 100644 homeassistant/components/switch/doorbird.py diff --git a/homeassistant/components/switch/doorbird.py b/homeassistant/components/switch/doorbird.py new file mode 100644 index 00000000000000..a39a3f11ac254e --- /dev/null +++ b/homeassistant/components/switch/doorbird.py @@ -0,0 +1,102 @@ +""" +Support for powering relays in a DoorBird video doorbell. +""" +import datetime +import logging +import voluptuous as vol + +from homeassistant.components.doorbird import 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): + device = hass.data.get(DOMAIN) + + switches = [] + for switch in SWITCHES: + if switch in config.get(CONF_SWITCHES): + _LOGGER.debug("Adding DoorBird switch " + + SWITCHES[switch]["name"]) + switches.append(DoorBirdSwitch(device, switch)) + + add_devices(switches) + _LOGGER.info("Added DoorBird switches") + return True + + +class DoorBirdSwitch(SwitchDevice): + def __init__(self, device, switch): + """Initialize a relay in a DoorBird device.""" + if switch not in SWITCHES: + msg = switch + " is not a valid DoorBird switch" + raise NotImplementedError(msg) + + self._device = device + self._switch = switch + self._state = False + self._assume_off = datetime.datetime.min + + @property + def name(self): + """:returns: The name of the switch.""" + return SWITCHES[self._switch]["name"] + + @property + def icon(self): + """:returns: An icon to display.""" + return "mdi:" + SWITCHES[self._switch]["icon"][self._state] + + @property + def is_on(self): + """:returns: 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"] + return True + + def turn_off(self, **kwargs): + """The relays are time-based and cannot be turned off.""" + return False + + def update(self): + if self._state and self._assume_off <= datetime.datetime.now(): + self._state = False + self._assume_off = datetime.datetime.min From b141ab194b9c964f3610cfa276f21b01bb10a75b Mon Sep 17 00:00:00 2001 From: Andy Castille Date: Sun, 6 Aug 2017 11:11:05 -0500 Subject: [PATCH 10/17] Add DoorBird to .coveragerc --- .coveragerc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.coveragerc b/.coveragerc index c74de0026b1134..1a2b3da4243157 100644 --- a/.coveragerc +++ b/.coveragerc @@ -41,6 +41,9 @@ omit = 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 From 14b7fa043fb17010bafd94dcecb669e63e71e89b Mon Sep 17 00:00:00 2001 From: Andy Castille Date: Sun, 6 Aug 2017 11:12:14 -0500 Subject: [PATCH 11/17] Add doorbirdpy to requirements_all.txt --- requirements_all.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/requirements_all.txt b/requirements_all.txt index c0ae35d7eed644..736908e4932485 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -17,6 +17,9 @@ astral==1.4 # homeassistant.components.bbb_gpio # Adafruit_BBIO==1.0.0 +# homeassistant.components.doorbird +DoorBirdPy==0.0.4 + # homeassistant.components.isy994 PyISY==1.0.7 From 54483fb8b3f38e72c480606c211644652f80e565 Mon Sep 17 00:00:00 2001 From: Andy Castille Date: Sun, 6 Aug 2017 15:03:52 -0500 Subject: [PATCH 12/17] Add more docstrings --- .../components/binary_sensor/doorbird.py | 8 +++---- homeassistant/components/camera/doorbird.py | 21 +++++++++++++------ homeassistant/components/doorbird.py | 16 ++++++-------- .../www_static/home-assistant-polymer | 2 +- homeassistant/components/switch/doorbird.py | 7 ++++--- 5 files changed, 30 insertions(+), 24 deletions(-) diff --git a/homeassistant/components/binary_sensor/doorbird.py b/homeassistant/components/binary_sensor/doorbird.py index 15fcac7e9b6824..0ec17af37e8567 100644 --- a/homeassistant/components/binary_sensor/doorbird.py +++ b/homeassistant/components/binary_sensor/doorbird.py @@ -1,6 +1,4 @@ -""" -Support for reading binary states from a DoorBird video doorbell. -""" +"""Support for reading binary states from a DoorBird video doorbell.""" from datetime import timedelta import logging import voluptuous as vol @@ -35,6 +33,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): + """Set up the DoorBird binary sensor component.""" device = hass.data.get(DOMAIN) sensors = [] @@ -50,6 +49,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): class DoorBirdBinarySensor(BinarySensorDevice): + """A binary sensor of a DoorBird device.""" def __init__(self, device, sensor_type): """Initialize a binary sensor on a DoorBird device.""" if sensor_type not in SENSOR_TYPES: @@ -79,5 +79,5 @@ def is_on(self): @Throttle(_MIN_UPDATE_INTERVAL) def update(self): - """Pulls the latest value from the device.""" + """Pull the latest value from the device.""" self._state = self._device.doorbell_state() diff --git a/homeassistant/components/camera/doorbird.py b/homeassistant/components/camera/doorbird.py index bb0a0d3e977f5e..138c28914c2fe1 100644 --- a/homeassistant/components/camera/doorbird.py +++ b/homeassistant/components/camera/doorbird.py @@ -1,14 +1,13 @@ -""" -Support for viewing the camera feed from a DoorBird video doorbell. -""" +"""Support for viewing the camera feed from a DoorBird video doorbell.""" -import aiohttp import asyncio -import async_timeout 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 from homeassistant.helpers import config_validation as cv @@ -33,6 +32,7 @@ @asyncio.coroutine def async_setup_platform(hass, config, async_add_devices, discovery_info=None): + """Set up the DoorBird camera platform.""" device = hass.data.get(DOMAIN) _LOGGER.debug("Adding DoorBird camera " + _CAMERA_LIVE) @@ -51,6 +51,8 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None): class DoorBirdCamera(Camera): + """The camera on a DoorBird device.""" + def __init__(self, hass, url, name, interval=None): """Initialize the camera on a DoorBird device.""" self._hass = hass @@ -74,7 +76,6 @@ def camera_image(self): @asyncio.coroutine def async_camera_image(self): """:returns: A still image from the camera.""" - now = datetime.datetime.now() if self._last_image and now - self._last_update < self._interval: @@ -95,3 +96,11 @@ def async_camera_image(self): except aiohttp.ClientError as error: _LOGGER.error("Error getting camera image: %s", error) return self._last_image + + def enable_motion_detection(self): + """Network callbacks are not supported by HA yet.""" + pass + + def disable_motion_detection(self): + """Network callbacks are not supported by HA yet.""" + pass diff --git a/homeassistant/components/doorbird.py b/homeassistant/components/doorbird.py index 80bd8e27c8bd28..2129c4eaafbd6c 100644 --- a/homeassistant/components/doorbird.py +++ b/homeassistant/components/doorbird.py @@ -1,6 +1,4 @@ -""" -Support for a DoorBird video doorbell. -""" +"""Support for a DoorBird video doorbell.""" import logging import voluptuous as vol @@ -34,16 +32,14 @@ def setup(hass, config): status = device.ready() if status[0]: - _LOGGER.info("Connected to DoorBird at {} as {}" - .format(ip, username)) + _LOGGER.info("Connected to DoorBird at %s as %s", ip, username) hass.data[DOMAIN] = device - _LOGGER.debug("DBDBG set device") return True elif status[1] == 401: - _LOGGER.error("Authorization rejected by DoorBird at {} for {}" - .format(ip, username)) + _LOGGER.error("Authorization rejected by DoorBird at %s for %s", + ip, username) return False else: - _LOGGER.error("Could not connect to DoorBird at {} as {}: DBP error {}" - .format(ip, username, status[1])) + _LOGGER.error("Could not connect to DoorBird at %s as %s: Error %s", + ip, username, str(status[1])) return False diff --git a/homeassistant/components/frontend/www_static/home-assistant-polymer b/homeassistant/components/frontend/www_static/home-assistant-polymer index 1ea7137c78b3df..1ad42592134c29 160000 --- a/homeassistant/components/frontend/www_static/home-assistant-polymer +++ b/homeassistant/components/frontend/www_static/home-assistant-polymer @@ -1 +1 @@ -Subproject commit 1ea7137c78b3df577f5df72a6c9bbe91bb5f7cd0 +Subproject commit 1ad42592134c290119879e8f8505ef5736a3071e diff --git a/homeassistant/components/switch/doorbird.py b/homeassistant/components/switch/doorbird.py index a39a3f11ac254e..7b7df40d4911cd 100644 --- a/homeassistant/components/switch/doorbird.py +++ b/homeassistant/components/switch/doorbird.py @@ -1,6 +1,4 @@ -""" -Support for powering relays in a DoorBird video doorbell. -""" +"""Support for powering relays in a DoorBird video doorbell.""" import datetime import logging import voluptuous as vol @@ -40,6 +38,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): + """Set up the DoorBird switch platform.""" device = hass.data.get(DOMAIN) switches = [] @@ -55,6 +54,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): class DoorBirdSwitch(SwitchDevice): + """A relay in a DoorBird device.""" def __init__(self, device, switch): """Initialize a relay in a DoorBird device.""" if switch not in SWITCHES: @@ -97,6 +97,7 @@ def turn_off(self, **kwargs): return False 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 From 3bafed39cf9f988eec5d956931f608b914d03da8 Mon Sep 17 00:00:00 2001 From: Andy Castille Date: Wed, 9 Aug 2017 09:21:32 -0500 Subject: [PATCH 13/17] Only the doorbell sensor works --- .../components/binary_sensor/doorbird.py | 35 ++++--------------- 1 file changed, 7 insertions(+), 28 deletions(-) diff --git a/homeassistant/components/binary_sensor/doorbird.py b/homeassistant/components/binary_sensor/doorbird.py index 0ec17af37e8567..2b53283aeb56f2 100644 --- a/homeassistant/components/binary_sensor/doorbird.py +++ b/homeassistant/components/binary_sensor/doorbird.py @@ -1,13 +1,10 @@ """Support for reading binary states from a DoorBird video doorbell.""" from datetime import timedelta import logging -import voluptuous as vol -from homeassistant.components.binary_sensor import BinarySensorDevice,\ - PLATFORM_SCHEMA +from homeassistant.components.binary_sensor import BinarySensorDevice from homeassistant.components.doorbird import DOMAIN -import homeassistant.helpers.config_validation as cv -from homeassistant.const import CONF_MONITORED_CONDITIONS, STATE_UNKNOWN +from homeassistant.const import STATE_UNKNOWN from homeassistant.util import Throttle DEPENDENCIES = ['doorbird'] @@ -26,25 +23,11 @@ } } -PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ - 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 DoorBird binary sensor component.""" device = hass.data.get(DOMAIN) - - sensors = [] - for sensor_type in config.get(CONF_MONITORED_CONDITIONS): - if sensor_type == "doorbell": - _LOGGER.debug("Adding DoorBird binary sensor " + - str(SENSOR_TYPES[sensor_type]["name"])) - sensors.append(DoorBirdBinarySensor(device, sensor_type)) - - add_devices(sensors, True) - _LOGGER.info("Added DoorBird binary sensors") + add_devices([DoorBirdBinarySensor(device, "doorbell")], True) return True @@ -52,10 +35,6 @@ class DoorBirdBinarySensor(BinarySensorDevice): """A binary sensor of a DoorBird device.""" def __init__(self, device, sensor_type): """Initialize a binary sensor on a DoorBird device.""" - if sensor_type not in SENSOR_TYPES: - msg = sensor_type + " is not a valid DoorBird binary sensor" - raise NotImplementedError(msg) - self._device = device self._sensor_type = sensor_type self._state = STATE_UNKNOWN @@ -63,18 +42,18 @@ def __init__(self, device, sensor_type): @property def name(self): - """:returns: The name of the sensor.""" + """Get the name of the sensor.""" return SENSOR_TYPES[self._sensor_type]["name"] @property def icon(self): - """:returns: An icon to display.""" + """Get an icon to display.""" icon = SENSOR_TYPES[self._sensor_type]["icon"][self._state] - return "mdi:" + str(icon) + return "mdi:{}".format(icon) @property def is_on(self): - """:returns: The state of the binary sensor.""" + """Get the state of the binary sensor.""" return self._state @Throttle(_MIN_UPDATE_INTERVAL) From a70ac131a9e3e2e3ddfc4fcd15bb099dbdf48c0d Mon Sep 17 00:00:00 2001 From: Andy Castille Date: Wed, 9 Aug 2017 09:21:59 -0500 Subject: [PATCH 14/17] Make last_visitor optional --- homeassistant/components/camera/doorbird.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/homeassistant/components/camera/doorbird.py b/homeassistant/components/camera/doorbird.py index 138c28914c2fe1..58054b69088c67 100644 --- a/homeassistant/components/camera/doorbird.py +++ b/homeassistant/components/camera/doorbird.py @@ -26,7 +26,7 @@ CONF_SHOW_LAST_VISITOR = 'last_visitor' PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ - vol.Required(CONF_SHOW_LAST_VISITOR, default=False): cv.boolean + vol.Optional(CONF_SHOW_LAST_VISITOR, default=False): cv.boolean }) @@ -65,17 +65,17 @@ def __init__(self, hass, url, name, interval=None): @property def name(self): - """:returns: The name of the camera.""" + """Get the name of the camera.""" return self._name def camera_image(self): - """:returns: The bytes of a camera image.""" + """Get the bytes of a camera image.""" return run_coroutine_threadsafe( self.async_camera_image(), self._hass.loop).result() @asyncio.coroutine def async_camera_image(self): - """:returns: A still image from the camera.""" + """Pull a still image from the camera.""" now = datetime.datetime.now() if self._last_image and now - self._last_update < self._interval: From 5d381a393039465e95e654ab30b0b4b30b876355 Mon Sep 17 00:00:00 2001 From: Andy Castille Date: Wed, 9 Aug 2017 09:22:30 -0500 Subject: [PATCH 15/17] Use PEP257 for docstrings --- homeassistant/components/switch/doorbird.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/switch/doorbird.py b/homeassistant/components/switch/doorbird.py index 7b7df40d4911cd..73091537e6c265 100644 --- a/homeassistant/components/switch/doorbird.py +++ b/homeassistant/components/switch/doorbird.py @@ -68,17 +68,17 @@ def __init__(self, device, switch): @property def name(self): - """:returns: The name of the switch.""" + """Get the name of the switch.""" return SWITCHES[self._switch]["name"] @property def icon(self): - """:returns: An icon to display.""" + """Get an icon to display.""" return "mdi:" + SWITCHES[self._switch]["icon"][self._state] @property def is_on(self): - """:returns: The assumed state of the relay.""" + """Get the assumed state of the relay.""" return self._state def turn_on(self, **kwargs): From e952b15d28ac933f4e6823bd7bcc023f1f56caa8 Mon Sep 17 00:00:00 2001 From: Andy Castille Date: Wed, 9 Aug 2017 09:22:43 -0500 Subject: [PATCH 16/17] Don't log the username --- homeassistant/components/doorbird.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/homeassistant/components/doorbird.py b/homeassistant/components/doorbird.py index 2129c4eaafbd6c..d7658f99ab28a7 100644 --- a/homeassistant/components/doorbird.py +++ b/homeassistant/components/doorbird.py @@ -36,10 +36,9 @@ def setup(hass, config): hass.data[DOMAIN] = device return True elif status[1] == 401: - _LOGGER.error("Authorization rejected by DoorBird at %s for %s", - ip, username) + _LOGGER.error("Authorization rejected by DoorBird at %s", ip) return False else: - _LOGGER.error("Could not connect to DoorBird at %s as %s: Error %s", - ip, username, str(status[1])) + _LOGGER.error("Could not connect to DoorBird at %s: Error %s", + ip, str(status[1])) return False From 98e1fdb8459d92bd7ee9ee18f5c54d92c84f31dd Mon Sep 17 00:00:00 2001 From: Andy Castille Date: Wed, 9 Aug 2017 09:24:04 -0500 Subject: [PATCH 17/17] remove extra space after import --- homeassistant/components/binary_sensor/doorbird.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/binary_sensor/doorbird.py b/homeassistant/components/binary_sensor/doorbird.py index 2b53283aeb56f2..a575cca1d23357 100644 --- a/homeassistant/components/binary_sensor/doorbird.py +++ b/homeassistant/components/binary_sensor/doorbird.py @@ -4,7 +4,7 @@ from homeassistant.components.binary_sensor import BinarySensorDevice from homeassistant.components.doorbird import DOMAIN -from homeassistant.const import STATE_UNKNOWN +from homeassistant.const import STATE_UNKNOWN from homeassistant.util import Throttle DEPENDENCIES = ['doorbird']