text: """
  Support for Verisure components.
  
  For more details about this component, please refer to the documentation at
  https://home-assistant.io/components/verisure/
  """
  import logging
  import threading
  import time
  from datetime import timedelta
  
  from homeassistant import bootstrap
  from homeassistant.const import (
      ATTR_DISCOVERED, ATTR_SERVICE, CONF_PASSWORD, CONF_USERNAME,
      EVENT_PLATFORM_DISCOVERED)
  from homeassistant.helpers import validate_config
  from homeassistant.loader import get_component
  from homeassistant.util import Throttle
  
  DOMAIN = "verisure"
  DISCOVER_SENSORS = 'verisure.sensors'
  DISCOVER_SWITCHES = 'verisure.switches'
  DISCOVER_ALARMS = 'verisure.alarm_control_panel'
  DISCOVER_LOCKS = 'verisure.lock'
  
  REQUIREMENTS = ['vsure==0.7.1']
  
  _LOGGER = logging.getLogger(__name__)
  
  HUB = None
  
  
  def setup(hass, config):
      """Setup the Verisure component."""
      if not validate_config(config,
                             {DOMAIN: [CONF_USERNAME, CONF_PASSWORD]},
                             _LOGGER):
          return False
  
      import verisure
      global HUB
      HUB = VerisureHub(config[DOMAIN], verisure)
      if not HUB.login():
          return False
  
      for comp_name, discovery in ((('sensor', DISCOVER_SENSORS),
                                    ('switch', DISCOVER_SWITCHES),
                                    ('alarm_control_panel', DISCOVER_ALARMS),
                                    ('lock', DISCOVER_LOCKS))):
          component = get_component(comp_name)
          bootstrap.setup_component(hass, component.DOMAIN, config)
          hass.bus.fire(EVENT_PLATFORM_DISCOVERED,
                        {ATTR_SERVICE: discovery,
                         ATTR_DISCOVERED: {}})
  
      return True
  
  
  # pylint: disable=too-many-instance-attributes
  class VerisureHub(object):
      """A Verisure hub wrapper class."""
  
      def __init__(self, domain_config, verisure):
          """Initialize the Verisure hub."""
          self.alarm_status = {}
          self.lock_status = {}
          self.climate_status = {}
          self.mouse_status = {}
          self.smartplug_status = {}
  
          self.config = domain_config
          self._verisure = verisure
  
          self._lock = threading.Lock()
  
          # When MyPages is brought up from maintenance it sometimes give us a
          # "wrong password" message. We will continue to retry after maintenance
          # regardless of that error.
          self._disable_wrong_password_error = False
          self._wrong_password_given = False
          self._reconnect_timeout = time.time()
  
          self.my_pages = verisure.MyPages(
              domain_config[CONF_USERNAME],
              domain_config[CONF_PASSWORD])
  
      def login(self):
          """Login to Verisure MyPages."""
          try:
              self.my_pages.login()
          except self._verisure.Error as ex:
              _LOGGER.error('Could not log in to verisure mypages, %s', ex)
              return False
          return True
  
      @Throttle(timedelta(seconds=1))
      def update_alarms(self):
          """Update the status of the alarm."""
          self.update_component(
              self.my_pages.alarm.get,
              self.alarm_status)
  
      @Throttle(timedelta(seconds=1))
      def update_locks(self):
          """Update the status of the locks."""
          self.update_component(
              self.my_pages.lock.get,
              self.lock_status)
  
      @Throttle(timedelta(seconds=60))
      def update_climate(self):
          """Update the status of the climate units."""
          self.update_component(
              self.my_pages.climate.get,
              self.climate_status)
  
      @Throttle(timedelta(seconds=60))
      def update_mousedetection(self):
          """Update the status of the mouse detectors."""
          self.update_component(
              self.my_pages.mousedetection.get,
              self.mouse_status)
  
      @Throttle(timedelta(seconds=1))
      def update_smartplugs(self):
          """Update the status of the smartplugs."""
          self.update_component(
              self.my_pages.smartplug.get,
              self.smartplug_status)
  
      def update_component(self, get_function, status):
          """Update the status of Verisure components."""
          if self._wrong_password_given:
              _LOGGER.error('Wrong password for Verisure, update config')
              return
          try:
              for overview in get_function():
                  try:
                      status[overview.id] = overview
                  except AttributeError:
                      status[overview.deviceLabel] = overview
          except self._verisure.Error as ex:
              _LOGGER.error('Caught connection error %s, tries to reconnect', ex)
              self.reconnect()
  
      def reconnect(self):
          """Reconnect to Verisure MyPages."""
          if self._reconnect_timeout > time.time():
              return
          if not self._lock.acquire(blocking=False):
              return
          try:
              self.my_pages.login()
              self._disable_wrong_password_error = False
          except self._verisure.LoginError as ex:
              _LOGGER.error("Wrong user name or password for Verisure MyPages")
              if self._disable_wrong_password_error:
                  self._reconnect_timeout = time.time() + 60
              else:
                  self._wrong_password_given = True
          except self._verisure.MaintenanceError:
              self._disable_wrong_password_error = True
              self._reconnect_timeout = time.time() + 60
              _LOGGER.error("Verisure MyPages down for maintenance")
          except self._verisure.Error as ex:
              _LOGGER.error("Could not login to Verisure MyPages, %s", ex)
              self._reconnect_timeout = time.time() + 5
          finally:
              self._lock.release()
  