Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .coveragerc
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,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
Expand Down
182 changes: 182 additions & 0 deletions homeassistant/components/cover/brunt.py
Original file line number Diff line number Diff line change
@@ -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: {}<br />'
'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)
3 changes: 3 additions & 0 deletions requirements_all.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down