From 61ba7795e4c0067049e40c1e61faad75b132169c Mon Sep 17 00:00:00 2001 From: Aaron Bach Date: Mon, 22 Oct 2018 13:27:07 -0600 Subject: [PATCH 1/4] Make MyQ platform async --- homeassistant/components/cover/myq.py | 93 ++++++++++++--------------- 1 file changed, 42 insertions(+), 51 deletions(-) diff --git a/homeassistant/components/cover/myq.py b/homeassistant/components/cover/myq.py index 5ceb4260d0c3fb..da4d3f928ae8e3 100644 --- a/homeassistant/components/cover/myq.py +++ b/homeassistant/components/cover/myq.py @@ -13,10 +13,9 @@ 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' @@ -28,9 +27,6 @@ 'opening': STATE_OPENING } -NOTIFICATION_ID = 'myq_notification' -NOTIFICATION_TITLE = 'MyQ Cover Setup' - COVER_SCHEMA = vol.Schema({ vol.Required(CONF_TYPE): cv.string, vol.Required(CONF_USERNAME): cv.string, @@ -38,45 +34,40 @@ }) -def setup_platform(hass, config, add_entities, discovery_info=None): - """Set up the MyQ component.""" - from pymyq import MyQAPI as pymyq +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 - username = config.get(CONF_USERNAME) - password = config.get(CONF_PASSWORD) - brand = config.get(CONF_TYPE) - myq = pymyq(username, password, brand) + websession = aiohttp_client.async_get_clientsession(hass) + + username = config[CONF_USERNAME] + password = config[CONF_PASSWORD] + brand = config[CONF_TYPE] try: - if not myq.is_supported_brand(): - raise ValueError("Unsupported type. See documentation") + 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 - if not myq.is_login_valid(): - raise ValueError("Username or Password is incorrect") + devices = await myq.get_devices() + async_add_entities([MyQDevice(device) for device in devices], True) - add_entities(MyQDevice(myq, door) for door in myq.get_garage_doors()) - return 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) - return False + return 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 + self._state = None @property def device_class(self): @@ -91,32 +82,22 @@ def should_poll(self): @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 +107,18 @@ 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() - def update(self): + async def async_open_cover(self, **kwargs): + """Issue open command to cover.""" + await self._device.open() + + async def async_update(self): """Update status of cover.""" - self._status = self.myq.get_status(self.device_id) + await self._device.update() + + self._state = self._device.state From 7ef9704bc561157efc1263f2e81d92cfcdcf8936 Mon Sep 17 00:00:00 2001 From: Aaron Bach Date: Thu, 15 Nov 2018 10:37:14 -0700 Subject: [PATCH 2/4] Bumped requirements --- requirements_all.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements_all.txt b/requirements_all.txt index 1545440f8b7f3d..2b828273f26ec5 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 From 77d364939e0fb9bd0c48813ee2fa054e8fe56ec1 Mon Sep 17 00:00:00 2001 From: Aaron Bach Date: Sat, 17 Nov 2018 22:27:51 -0700 Subject: [PATCH 3/4] Member comments --- homeassistant/components/cover/myq.py | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/homeassistant/components/cover/myq.py b/homeassistant/components/cover/myq.py index da4d3f928ae8e3..ebb6e72ee34049 100644 --- a/homeassistant/components/cover/myq.py +++ b/homeassistant/components/cover/myq.py @@ -9,7 +9,7 @@ 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) @@ -27,7 +27,7 @@ 'opening': STATE_OPENING } -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 @@ -58,8 +58,6 @@ async def async_setup_platform( devices = await myq.get_devices() async_add_entities([MyQDevice(device) for device in devices], True) - return True - class MyQDevice(CoverDevice): """Representation of a MyQ cover.""" @@ -67,7 +65,6 @@ class MyQDevice(CoverDevice): def __init__(self, device): """Initialize with API object, device id.""" self._device = device - self._state = None @property def device_class(self): @@ -120,5 +117,3 @@ async def async_open_cover(self, **kwargs): async def async_update(self): """Update status of cover.""" await self._device.update() - - self._state = self._device.state From 7a87ef616f9d02fbcd9520a817ea91445924f553 Mon Sep 17 00:00:00 2001 From: Aaron Bach Date: Sun, 18 Nov 2018 10:10:50 -0700 Subject: [PATCH 4/4] Member updates --- homeassistant/components/cover/myq.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/homeassistant/components/cover/myq.py b/homeassistant/components/cover/myq.py index ebb6e72ee34049..bdff232fec9156 100644 --- a/homeassistant/components/cover/myq.py +++ b/homeassistant/components/cover/myq.py @@ -18,8 +18,6 @@ REQUIREMENTS = ['pymyq==1.0.0'] _LOGGER = logging.getLogger(__name__) -DEFAULT_NAME = 'myq' - MYQ_TO_HASS = { 'closed': STATE_CLOSED, 'closing': STATE_CLOSING, @@ -71,11 +69,6 @@ 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."""