From 95dc06cca673b44ba7175e65faa7d60c74a16ab2 Mon Sep 17 00:00:00 2001 From: Eduard van Valkenburg Date: Wed, 25 Jul 2018 12:17:12 +0200 Subject: [PATCH] Add Brunt Cover Device (#15653) * New Brunt Branch * Some small changes and updates based on review. --- .coveragerc | 1 + homeassistant/components/cover/brunt.py | 182 ++++++++++++++++++++++++ requirements_all.txt | 3 + 3 files changed, 186 insertions(+) create mode 100644 homeassistant/components/cover/brunt.py diff --git a/.coveragerc b/.coveragerc index 09d2f765d2a187..7e10830d87611b 100644 --- a/.coveragerc +++ b/.coveragerc @@ -401,6 +401,7 @@ omit = homeassistant/components/climate/touchline.py homeassistant/components/climate/venstar.py homeassistant/components/climate/zhong_hong.py + homeassistant/components/cover/brunt.py homeassistant/components/cover/garadget.py homeassistant/components/cover/gogogate2.py homeassistant/components/cover/homematic.py diff --git a/homeassistant/components/cover/brunt.py b/homeassistant/components/cover/brunt.py new file mode 100644 index 00000000000000..713f06db7359da --- /dev/null +++ b/homeassistant/components/cover/brunt.py @@ -0,0 +1,182 @@ +""" +Support for Brunt Blind Engine covers. + +For more details about this component, please refer to the documentation at +https://home-assistant.io/components/cover.brunt +""" + +import logging + +import voluptuous as vol + +from homeassistant.const import ( + ATTR_ATTRIBUTION, CONF_PASSWORD, CONF_USERNAME) +from homeassistant.components.cover import ( + ATTR_POSITION, CoverDevice, + PLATFORM_SCHEMA, SUPPORT_CLOSE, + SUPPORT_OPEN, SUPPORT_SET_POSITION +) +import homeassistant.helpers.config_validation as cv + +REQUIREMENTS = ['brunt==0.1.2'] + +_LOGGER = logging.getLogger(__name__) + +COVER_FEATURES = SUPPORT_OPEN | SUPPORT_CLOSE | SUPPORT_SET_POSITION +DEVICE_CLASS = 'window' + +ATTR_REQUEST_POSITION = 'request_position' +NOTIFICATION_ID = 'brunt_notification' +NOTIFICATION_TITLE = 'Brunt Cover Setup' +ATTRIBUTION = 'Based on an unofficial Brunt SDK.' + +CLOSED_POSITION = 0 +OPEN_POSITION = 100 + +PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ + vol.Required(CONF_USERNAME): cv.string, + vol.Required(CONF_PASSWORD): cv.string +}) + + +def setup_platform(hass, config, add_devices, discovery_info=None): + """Set up the brunt platform.""" + # pylint: disable=no-name-in-module + from brunt import BruntAPI + username = config[CONF_USERNAME] + password = config[CONF_PASSWORD] + + bapi = BruntAPI(username=username, password=password) + try: + things = bapi.getThings()['things'] + if not things: + _LOGGER.error("No things present in account.") + else: + add_devices([BruntDevice( + bapi, thing['NAME'], + thing['thingUri']) for thing in things], True) + except (TypeError, KeyError, NameError, ValueError) as ex: + _LOGGER.error("%s", ex) + hass.components.persistent_notification.create( + 'Error: {}
' + 'You will need to restart hass after fixing.' + ''.format(ex), + title=NOTIFICATION_TITLE, + notification_id=NOTIFICATION_ID) + + +class BruntDevice(CoverDevice): + """ + Representation of a Brunt cover device. + + Contains the common logic for all Brunt devices. + """ + + def __init__(self, bapi, name, thing_uri): + """Init the Brunt device.""" + self._bapi = bapi + self._name = name + self._thing_uri = thing_uri + + self._state = {} + self._available = None + + @property + def name(self): + """Return the name of the device as reported by tellcore.""" + return self._name + + @property + def available(self): + """Could the device be accessed during the last update call.""" + return self._available + + @property + def current_cover_position(self): + """ + Return current position of cover. + + None is unknown, 0 is closed, 100 is fully open. + """ + pos = self._state.get('currentPosition') + return int(pos) if pos else None + + @property + def request_cover_position(self): + """ + Return request position of cover. + + The request position is the position of the last request + to Brunt, at times there is a diff of 1 to current + None is unknown, 0 is closed, 100 is fully open. + """ + pos = self._state.get('requestPosition') + return int(pos) if pos else None + + @property + def move_state(self): + """ + Return current moving state of cover. + + None is unknown, 0 when stopped, 1 when opening, 2 when closing + """ + mov = self._state.get('moveState') + return int(mov) if mov else None + + @property + def is_opening(self): + """Return if the cover is opening or not.""" + return self.move_state == 1 + + @property + def is_closing(self): + """Return if the cover is closing or not.""" + return self.move_state == 2 + + @property + def device_state_attributes(self): + """Return the detailed device state attributes.""" + return { + ATTR_ATTRIBUTION: ATTRIBUTION, + ATTR_REQUEST_POSITION: self.request_cover_position + } + + @property + def device_class(self): + """Return the class of this device, from component DEVICE_CLASSES.""" + return DEVICE_CLASS + + @property + def supported_features(self): + """Flag supported features.""" + return COVER_FEATURES + + @property + def is_closed(self): + """Return true if cover is closed, else False.""" + return self.current_cover_position == CLOSED_POSITION + + def update(self): + """Poll the current state of the device.""" + try: + self._state = self._bapi.getState( + thingUri=self._thing_uri).get('thing') + self._available = True + except (TypeError, KeyError, NameError, ValueError) as ex: + _LOGGER.error("%s", ex) + self._available = False + + def open_cover(self, **kwargs): + """Set the cover to the open position.""" + self._bapi.changeRequestPosition( + OPEN_POSITION, thingUri=self._thing_uri) + + def close_cover(self, **kwargs): + """Set the cover to the closed position.""" + self._bapi.changeRequestPosition( + CLOSED_POSITION, thingUri=self._thing_uri) + + def set_cover_position(self, **kwargs): + """Set the cover to a specific position.""" + self._bapi.changeRequestPosition( + kwargs[ATTR_POSITION], thingUri=self._thing_uri) diff --git a/requirements_all.txt b/requirements_all.txt index 2cd4d8d4a4913f..3d4b48398f9c1a 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -196,6 +196,9 @@ braviarc-homeassistant==0.3.7.dev0 # homeassistant.components.switch.broadlink broadlink==0.9.0 +# homeassistant.components.cover.brunt +brunt==0.1.2 + # homeassistant.components.device_tracker.bluetooth_tracker bt_proximity==0.1.2