diff --git a/homeassistant/components/myq/__init__.py b/homeassistant/components/myq/__init__.py
index 51ad9fb48f060914ec40a7cc38b0c9136b7943e6..fc1d374fe43cd3f917d83574b73728ccc8ed0f4d 100644
--- a/homeassistant/components/myq/__init__.py
+++ b/homeassistant/components/myq/__init__.py
@@ -1,5 +1,6 @@
 """The MyQ integration."""
 import asyncio
+from datetime import timedelta
 import logging
 
 import pymyq
@@ -10,8 +11,9 @@ from homeassistant.const import CONF_PASSWORD, CONF_USERNAME
 from homeassistant.core import HomeAssistant
 from homeassistant.exceptions import ConfigEntryNotReady
 from homeassistant.helpers import aiohttp_client
+from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
 
-from .const import DOMAIN, PLATFORMS
+from .const import DOMAIN, MYQ_COORDINATOR, MYQ_GATEWAY, PLATFORMS, UPDATE_INTERVAL
 
 _LOGGER = logging.getLogger(__name__)
 
@@ -38,7 +40,15 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry):
     except MyQError:
         raise ConfigEntryNotReady
 
-    hass.data[DOMAIN][entry.entry_id] = myq
+    coordinator = DataUpdateCoordinator(
+        hass,
+        _LOGGER,
+        name="myq devices",
+        update_method=myq.update_device_info,
+        update_interval=timedelta(seconds=UPDATE_INTERVAL),
+    )
+
+    hass.data[DOMAIN][entry.entry_id] = {MYQ_GATEWAY: myq, MYQ_COORDINATOR: coordinator}
 
     for component in PLATFORMS:
         hass.async_create_task(
diff --git a/homeassistant/components/myq/const.py b/homeassistant/components/myq/const.py
index 260811e54ce5099fbc9f1c866a96460e18002475..dcae53bd08023a1d8dfce2d74d8ace5ee39ca086 100644
--- a/homeassistant/components/myq/const.py
+++ b/homeassistant/components/myq/const.py
@@ -1,4 +1,11 @@
 """The MyQ integration."""
+from pymyq.device import (
+    STATE_CLOSED as MYQ_STATE_CLOSED,
+    STATE_CLOSING as MYQ_STATE_CLOSING,
+    STATE_OPEN as MYQ_STATE_OPEN,
+    STATE_OPENING as MYQ_STATE_OPENING,
+)
+
 from homeassistant.const import STATE_CLOSED, STATE_CLOSING, STATE_OPEN, STATE_OPENING
 
 DOMAIN = "myq"
@@ -10,9 +17,25 @@ MYQ_DEVICE_TYPE_GATE = "gate"
 MYQ_DEVICE_STATE = "state"
 MYQ_DEVICE_STATE_ONLINE = "online"
 
+
 MYQ_TO_HASS = {
-    "closed": STATE_CLOSED,
-    "closing": STATE_CLOSING,
-    "open": STATE_OPEN,
-    "opening": STATE_OPENING,
+    MYQ_STATE_CLOSED: STATE_CLOSED,
+    MYQ_STATE_CLOSING: STATE_CLOSING,
+    MYQ_STATE_OPEN: STATE_OPEN,
+    MYQ_STATE_OPENING: STATE_OPENING,
 }
+
+MYQ_GATEWAY = "myq_gateway"
+MYQ_COORDINATOR = "coordinator"
+
+# myq has some ratelimits in place
+# and 61 seemed to be work every time
+UPDATE_INTERVAL = 61
+
+# Estimated time it takes myq to start transition from one
+# state to the next.
+TRANSITION_START_DURATION = 7
+
+# Estimated time it takes myq to complete a transition
+# from one state to another
+TRANSITION_COMPLETE_DURATION = 37
diff --git a/homeassistant/components/myq/cover.py b/homeassistant/components/myq/cover.py
index 0df61b4d5dbe86bcfbe9a80f8a42ac870a155e9d..21eca6179dd4ba27c7557c31db7a76992dc8df0a 100644
--- a/homeassistant/components/myq/cover.py
+++ b/homeassistant/components/myq/cover.py
@@ -1,9 +1,12 @@
 """Support for MyQ-Enabled Garage Doors."""
 import logging
+import time
 
 import voluptuous as vol
 
 from homeassistant.components.cover import (
+    DEVICE_CLASS_GARAGE,
+    DEVICE_CLASS_GATE,
     PLATFORM_SCHEMA,
     SUPPORT_CLOSE,
     SUPPORT_OPEN,
@@ -18,9 +21,22 @@ from homeassistant.const import (
     STATE_CLOSING,
     STATE_OPENING,
 )
+from homeassistant.core import callback
 from homeassistant.helpers import config_validation as cv
-
-from .const import DOMAIN, MYQ_DEVICE_STATE, MYQ_DEVICE_STATE_ONLINE, MYQ_TO_HASS
+from homeassistant.helpers.event import async_call_later
+
+from .const import (
+    DOMAIN,
+    MYQ_COORDINATOR,
+    MYQ_DEVICE_STATE,
+    MYQ_DEVICE_STATE_ONLINE,
+    MYQ_DEVICE_TYPE,
+    MYQ_DEVICE_TYPE_GATE,
+    MYQ_GATEWAY,
+    MYQ_TO_HASS,
+    TRANSITION_COMPLETE_DURATION,
+    TRANSITION_START_DURATION,
+)
 
 _LOGGER = logging.getLogger(__name__)
 
@@ -53,21 +69,32 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info=
 
 async def async_setup_entry(hass, config_entry, async_add_entities):
     """Set up mysq covers."""
-    myq = hass.data[DOMAIN][config_entry.entry_id]
-    async_add_entities([MyQDevice(device) for device in myq.covers.values()], True)
+    data = hass.data[DOMAIN][config_entry.entry_id]
+    myq = data[MYQ_GATEWAY]
+    coordinator = data[MYQ_COORDINATOR]
+
+    async_add_entities(
+        [MyQDevice(coordinator, device) for device in myq.covers.values()], True
+    )
 
 
 class MyQDevice(CoverDevice):
     """Representation of a MyQ cover."""
 
-    def __init__(self, device):
+    def __init__(self, coordinator, device):
         """Initialize with API object, device id."""
+        self._coordinator = coordinator
         self._device = device
+        self._last_action_timestamp = 0
+        self._scheduled_transition_update = None
 
     @property
     def device_class(self):
         """Define this cover as a garage door."""
-        return "garage"
+        device_type = self._device.device_json.get(MYQ_DEVICE_TYPE)
+        if device_type is not None and device_type == MYQ_DEVICE_TYPE_GATE:
+            return DEVICE_CLASS_GATE
+        return DEVICE_CLASS_GARAGE
 
     @property
     def name(self):
@@ -77,6 +104,9 @@ class MyQDevice(CoverDevice):
     @property
     def available(self):
         """Return if the device is online."""
+        if not self._coordinator.last_update_success:
+            return False
+
         # Not all devices report online so assume True if its missing
         return self._device.device_json[MYQ_DEVICE_STATE].get(
             MYQ_DEVICE_STATE_ONLINE, True
@@ -109,19 +139,41 @@ class MyQDevice(CoverDevice):
 
     async def async_close_cover(self, **kwargs):
         """Issue close command to cover."""
+        self._last_action_timestamp = time.time()
         await self._device.close()
-        # Writes closing state
-        self.async_write_ha_state()
+        self._async_schedule_update_for_transition()
 
     async def async_open_cover(self, **kwargs):
         """Issue open command to cover."""
+        self._last_action_timestamp = time.time()
         await self._device.open()
-        # Writes opening state
+        self._async_schedule_update_for_transition()
+
+    @callback
+    def _async_schedule_update_for_transition(self):
         self.async_write_ha_state()
 
+        # Cancel any previous updates
+        if self._scheduled_transition_update:
+            self._scheduled_transition_update()
+
+        # Schedule an update for when we expect the transition
+        # to be completed so the garage door or gate does not
+        # seem like its closing or opening for a long time
+        self._scheduled_transition_update = async_call_later(
+            self.hass,
+            TRANSITION_COMPLETE_DURATION,
+            self._async_complete_schedule_update,
+        )
+
+    async def _async_complete_schedule_update(self, _):
+        """Update status of the cover via coordinator."""
+        self._scheduled_transition_update = None
+        await self._coordinator.async_request_refresh()
+
     async def async_update(self):
         """Update status of cover."""
-        await self._device.update()
+        await self._coordinator.async_request_refresh()
 
     @property
     def device_info(self):
@@ -135,3 +187,27 @@ class MyQDevice(CoverDevice):
         if self._device.parent_device_id:
             device_info["via_device"] = (DOMAIN, self._device.parent_device_id)
         return device_info
+
+    @callback
+    def _async_consume_update(self):
+        if time.time() - self._last_action_timestamp <= TRANSITION_START_DURATION:
+            # If we just started a transition we need
+            # to prevent a bouncy state
+            return
+
+        self.async_write_ha_state()
+
+    @property
+    def should_poll(self):
+        """Return False, updates are controlled via coordinator."""
+        return False
+
+    async def async_added_to_hass(self):
+        """Subscribe to updates."""
+        self._coordinator.async_add_listener(self._async_consume_update)
+
+    async def async_will_remove_from_hass(self):
+        """Undo subscription."""
+        self._coordinator.async_remove_listener(self._async_consume_update)
+        if self._scheduled_transition_update:
+            self._scheduled_transition_update()