From 8f59be2059adf59821ed0352b09044d285119c15 Mon Sep 17 00:00:00 2001 From: Aaron Bach Date: Sun, 18 Nov 2018 10:37:03 -0700 Subject: [PATCH] Make MyQ platform async (#18489) * Make MyQ platform async * Bumped requirements * Member comments * Member updates --- homeassistant/components/cover/myq.py | 101 ++++++++++---------------- requirements_all.txt | 2 +- 2 files changed, 41 insertions(+), 62 deletions(-) diff --git a/homeassistant/components/cover/myq.py b/homeassistant/components/cover/myq.py index 5ceb4260d0c3fb..bdff232fec9156 100644 --- a/homeassistant/components/cover/myq.py +++ b/homeassistant/components/cover/myq.py @@ -9,18 +9,15 @@ import voluptuous as vol from homeassistant.components.cover import ( - CoverDevice, SUPPORT_CLOSE, SUPPORT_OPEN) + PLATFORM_SCHEMA, SUPPORT_CLOSE, SUPPORT_OPEN, CoverDevice) from homeassistant.const import ( CONF_PASSWORD, CONF_TYPE, CONF_USERNAME, STATE_CLOSED, STATE_CLOSING, STATE_OPEN, STATE_OPENING) -import homeassistant.helpers.config_validation as cv - -REQUIREMENTS = ['pymyq==0.0.15'] +from homeassistant.helpers import aiohttp_client, config_validation as cv +REQUIREMENTS = ['pymyq==1.0.0'] _LOGGER = logging.getLogger(__name__) -DEFAULT_NAME = 'myq' - MYQ_TO_HASS = { 'closed': STATE_CLOSED, 'closing': STATE_CLOSING, @@ -28,95 +25,69 @@ 'opening': STATE_OPENING } -NOTIFICATION_ID = 'myq_notification' -NOTIFICATION_TITLE = 'MyQ Cover Setup' - -COVER_SCHEMA = vol.Schema({ +PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ vol.Required(CONF_TYPE): cv.string, vol.Required(CONF_USERNAME): cv.string, vol.Required(CONF_PASSWORD): cv.string }) -def setup_platform(hass, config, add_entities, discovery_info=None): - """Set up the MyQ component.""" - from pymyq import MyQAPI as pymyq - - username = config.get(CONF_USERNAME) - password = config.get(CONF_PASSWORD) - brand = config.get(CONF_TYPE) - myq = pymyq(username, password, brand) +async def async_setup_platform( + hass, config, async_add_entities, discovery_info=None): + """Set up the platform.""" + from pymyq import login + from pymyq.errors import MyQError, UnsupportedBrandError - try: - if not myq.is_supported_brand(): - raise ValueError("Unsupported type. See documentation") + websession = aiohttp_client.async_get_clientsession(hass) - if not myq.is_login_valid(): - raise ValueError("Username or Password is incorrect") + username = config[CONF_USERNAME] + password = config[CONF_PASSWORD] + brand = config[CONF_TYPE] - add_entities(MyQDevice(myq, door) for door in myq.get_garage_doors()) - return True + try: + myq = await login(username, password, brand, websession) + except UnsupportedBrandError: + _LOGGER.error('Unsupported brand: %s', brand) + return + except MyQError as err: + _LOGGER.error('There was an error while logging in: %s', err) + return - 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) - return False + devices = await myq.get_devices() + async_add_entities([MyQDevice(device) for device in devices], True) class MyQDevice(CoverDevice): """Representation of a MyQ cover.""" - def __init__(self, myq, device): + def __init__(self, device): """Initialize with API object, device id.""" - self.myq = myq - self.device_id = device['deviceid'] - self._name = device['name'] - self._status = None + self._device = device @property def device_class(self): """Define this cover as a garage door.""" return 'garage' - @property - def should_poll(self): - """Poll for state.""" - return True - @property def name(self): """Return the name of the garage door if any.""" - return self._name if self._name else DEFAULT_NAME + return self._device.name @property def is_closed(self): """Return true if cover is closed, else False.""" - if self._status in [None, False]: - return None - return MYQ_TO_HASS.get(self._status) == STATE_CLOSED + return MYQ_TO_HASS.get(self._device.state) == STATE_CLOSED @property def is_closing(self): """Return if the cover is closing or not.""" - return MYQ_TO_HASS.get(self._status) == STATE_CLOSING + return MYQ_TO_HASS.get(self._device.state) == STATE_CLOSING @property def is_opening(self): """Return if the cover is opening or not.""" - return MYQ_TO_HASS.get(self._status) == STATE_OPENING - - def close_cover(self, **kwargs): - """Issue close command to cover.""" - self.myq.close_device(self.device_id) - - def open_cover(self, **kwargs): - """Issue open command to cover.""" - self.myq.open_device(self.device_id) + return MYQ_TO_HASS.get(self._device.state) == STATE_OPENING @property def supported_features(self): @@ -126,8 +97,16 @@ def supported_features(self): @property def unique_id(self): """Return a unique, HASS-friendly identifier for this entity.""" - return self.device_id + return self._device.device_id + + async def async_close_cover(self, **kwargs): + """Issue close command to cover.""" + await self._device.close() + + async def async_open_cover(self, **kwargs): + """Issue open command to cover.""" + await self._device.open() - def update(self): + async def async_update(self): """Update status of cover.""" - self._status = self.myq.get_status(self.device_id) + await self._device.update() diff --git a/requirements_all.txt b/requirements_all.txt index 097b2c03a10f3d..5d70a1ac3f57f0 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1044,7 +1044,7 @@ pymonoprice==0.3 pymusiccast==0.1.6 # homeassistant.components.cover.myq -pymyq==0.0.15 +pymyq==1.0.0 # homeassistant.components.mysensors pymysensors==0.18.0