diff --git a/CODEOWNERS b/CODEOWNERS
index 4d4c7d3d900736c7598d0cab999ee9d4e82a5737..5cbf0d411a0f23e82b2f76e260c67021da9039c1 100644
--- a/CODEOWNERS
+++ b/CODEOWNERS
@@ -409,6 +409,7 @@ homeassistant/components/usgs_earthquakes_feed/* @exxamalte
 homeassistant/components/utility_meter/* @dgomes
 homeassistant/components/velbus/* @Cereal2nd @brefra
 homeassistant/components/velux/* @Julius2342
+homeassistant/components/vera/* @vangorra
 homeassistant/components/versasense/* @flamm3blemuff1n
 homeassistant/components/version/* @fabaff
 homeassistant/components/vesync/* @markperdue @webdjoe
diff --git a/homeassistant/components/vera/__init__.py b/homeassistant/components/vera/__init__.py
index 1c9d412d974ddd033d8afab88be235f8c7d8e768..c98833a7daa014d15c36dcf42525a6eee6b5f3c2 100644
--- a/homeassistant/components/vera/__init__.py
+++ b/homeassistant/components/vera/__init__.py
@@ -1,4 +1,5 @@
 """Support for Vera devices."""
+import asyncio
 from collections import defaultdict
 import logging
 
@@ -6,6 +7,8 @@ import pyvera as veraApi
 from requests.exceptions import RequestException
 import voluptuous as vol
 
+from homeassistant import config_entries
+from homeassistant.config_entries import ConfigEntry
 from homeassistant.const import (
     ATTR_ARMED,
     ATTR_BATTERY_LEVEL,
@@ -15,26 +18,23 @@ from homeassistant.const import (
     CONF_LIGHTS,
     EVENT_HOMEASSISTANT_STOP,
 )
-from homeassistant.helpers import config_validation as cv, discovery
+from homeassistant.core import HomeAssistant
+from homeassistant.helpers import config_validation as cv
 from homeassistant.helpers.entity import Entity
 from homeassistant.util import convert, slugify
 from homeassistant.util.dt import utc_from_timestamp
 
-_LOGGER = logging.getLogger(__name__)
-
-DOMAIN = "vera"
-
-VERA_CONTROLLER = "vera_controller"
-
-CONF_CONTROLLER = "vera_controller_url"
-
-VERA_ID_FORMAT = "{}_{}"
-
-ATTR_CURRENT_POWER_W = "current_power_w"
-ATTR_CURRENT_ENERGY_KWH = "current_energy_kwh"
+from .common import ControllerData, get_configured_platforms
+from .config_flow import new_options
+from .const import (
+    ATTR_CURRENT_ENERGY_KWH,
+    ATTR_CURRENT_POWER_W,
+    CONF_CONTROLLER,
+    DOMAIN,
+    VERA_ID_FORMAT,
+)
 
-VERA_DEVICES = "vera_devices"
-VERA_SCENES = "vera_scenes"
+_LOGGER = logging.getLogger(__name__)
 
 VERA_ID_LIST_SCHEMA = vol.Schema([int])
 
@@ -51,42 +51,53 @@ CONFIG_SCHEMA = vol.Schema(
     extra=vol.ALLOW_EXTRA,
 )
 
-VERA_COMPONENTS = [
-    "binary_sensor",
-    "sensor",
-    "light",
-    "switch",
-    "lock",
-    "climate",
-    "cover",
-    "scene",
-]
 
+async def async_setup(hass: HomeAssistant, base_config: dict) -> bool:
+    """Set up for Vera controllers."""
+    config = base_config.get(DOMAIN)
 
-def setup(hass, base_config):
-    """Set up for Vera devices."""
+    if not config:
+        return True
 
-    def stop_subscription(event):
-        """Shutdown Vera subscriptions and subscription thread on exit."""
-        _LOGGER.info("Shutting down subscriptions")
-        hass.data[VERA_CONTROLLER].stop()
+    hass.async_create_task(
+        hass.config_entries.flow.async_init(
+            DOMAIN, context={"source": config_entries.SOURCE_IMPORT}, data=config,
+        )
+    )
 
-    config = base_config.get(DOMAIN)
+    return True
 
-    # Get Vera specific configuration.
-    base_url = config.get(CONF_CONTROLLER)
-    light_ids = config.get(CONF_LIGHTS)
-    exclude_ids = config.get(CONF_EXCLUDE)
+
+async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> bool:
+    """Do setup of vera."""
+    # Use options entered during initial config flow or provided from configuration.yml
+    if config_entry.data.get(CONF_LIGHTS) or config_entry.data.get(CONF_EXCLUDE):
+        hass.config_entries.async_update_entry(
+            entry=config_entry,
+            data=config_entry.data,
+            options=new_options(
+                config_entry.data.get(CONF_LIGHTS, []),
+                config_entry.data.get(CONF_EXCLUDE, []),
+            ),
+        )
+
+    base_url = config_entry.data[CONF_CONTROLLER]
+    light_ids = config_entry.options.get(CONF_LIGHTS, [])
+    exclude_ids = config_entry.options.get(CONF_EXCLUDE, [])
 
     # Initialize the Vera controller.
-    controller, _ = veraApi.init_controller(base_url)
-    hass.data[VERA_CONTROLLER] = controller
-    hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP, stop_subscription)
+    controller = veraApi.VeraController(base_url)
+    controller.start()
+
+    hass.bus.async_listen_once(
+        EVENT_HOMEASSISTANT_STOP,
+        lambda event: hass.async_add_executor_job(controller.stop),
+    )
 
     try:
-        all_devices = controller.get_devices()
+        all_devices = await hass.async_add_executor_job(controller.get_devices)
 
-        all_scenes = controller.get_scenes()
+        all_scenes = await hass.async_add_executor_job(controller.get_scenes)
     except RequestException:
         # There was a network related error connecting to the Vera controller.
         _LOGGER.exception("Error communicating with Vera API")
@@ -102,15 +113,35 @@ def setup(hass, base_config):
             continue
 
         vera_devices[device_type].append(device)
-    hass.data[VERA_DEVICES] = vera_devices
 
     vera_scenes = []
     for scene in all_scenes:
         vera_scenes.append(scene)
-    hass.data[VERA_SCENES] = vera_scenes
 
-    for component in VERA_COMPONENTS:
-        discovery.load_platform(hass, component, DOMAIN, {}, base_config)
+    controller_data = ControllerData(
+        controller=controller, devices=vera_devices, scenes=vera_scenes
+    )
+
+    hass.data[DOMAIN] = controller_data
+
+    # Forward the config data to the necessary platforms.
+    for platform in get_configured_platforms(controller_data):
+        hass.async_create_task(
+            hass.config_entries.async_forward_entry_setup(config_entry, platform)
+        )
+
+    return True
+
+
+async def async_unload_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> bool:
+    """Unload Withings config entry."""
+    controller_data = hass.data[DOMAIN]
+
+    tasks = [
+        hass.config_entries.async_forward_entry_unload(config_entry, platform)
+        for platform in get_configured_platforms(controller_data)
+    ]
+    await asyncio.gather(*tasks)
 
     return True
 
diff --git a/homeassistant/components/vera/binary_sensor.py b/homeassistant/components/vera/binary_sensor.py
index 061d2c5c99aef45df4c688159c97c7f4fead7bcb..621dc09930d99f439c71413b6f2aa2e9de54331a 100644
--- a/homeassistant/components/vera/binary_sensor.py
+++ b/homeassistant/components/vera/binary_sensor.py
@@ -1,21 +1,34 @@
 """Support for Vera binary sensors."""
 import logging
+from typing import Callable, List
 
-from homeassistant.components.binary_sensor import ENTITY_ID_FORMAT, BinarySensorDevice
+from homeassistant.components.binary_sensor import (
+    DOMAIN as PLATFORM_DOMAIN,
+    ENTITY_ID_FORMAT,
+    BinarySensorDevice,
+)
+from homeassistant.config_entries import ConfigEntry
+from homeassistant.core import HomeAssistant
+from homeassistant.helpers.entity import Entity
 
-from . import VERA_CONTROLLER, VERA_DEVICES, VeraDevice
+from . import VeraDevice
+from .const import DOMAIN
 
 _LOGGER = logging.getLogger(__name__)
 
 
-def setup_platform(hass, config, add_entities, discovery_info=None):
-    """Perform the setup for Vera controller devices."""
-    add_entities(
+async def async_setup_entry(
+    hass: HomeAssistant,
+    entry: ConfigEntry,
+    async_add_entities: Callable[[List[Entity], bool], None],
+) -> None:
+    """Set up the sensor config entry."""
+    controller_data = hass.data[DOMAIN]
+    async_add_entities(
         [
-            VeraBinarySensor(device, hass.data[VERA_CONTROLLER])
-            for device in hass.data[VERA_DEVICES]["binary_sensor"]
-        ],
-        True,
+            VeraBinarySensor(device, controller_data.controller)
+            for device in controller_data.devices.get(PLATFORM_DOMAIN)
+        ]
     )
 
 
diff --git a/homeassistant/components/vera/climate.py b/homeassistant/components/vera/climate.py
index 60e73d48978cdb1f6b9be24e0fcfe0516dc70df1..520c3b516df34f9d9960911420c82fc96df4cbf7 100644
--- a/homeassistant/components/vera/climate.py
+++ b/homeassistant/components/vera/climate.py
@@ -1,7 +1,12 @@
 """Support for Vera thermostats."""
 import logging
+from typing import Callable, List
 
-from homeassistant.components.climate import ENTITY_ID_FORMAT, ClimateDevice
+from homeassistant.components.climate import (
+    DOMAIN as PLATFORM_DOMAIN,
+    ENTITY_ID_FORMAT,
+    ClimateDevice,
+)
 from homeassistant.components.climate.const import (
     FAN_AUTO,
     FAN_ON,
@@ -12,10 +17,14 @@ from homeassistant.components.climate.const import (
     SUPPORT_FAN_MODE,
     SUPPORT_TARGET_TEMPERATURE,
 )
+from homeassistant.config_entries import ConfigEntry
 from homeassistant.const import ATTR_TEMPERATURE, TEMP_CELSIUS, TEMP_FAHRENHEIT
+from homeassistant.core import HomeAssistant
+from homeassistant.helpers.entity import Entity
 from homeassistant.util import convert
 
-from . import VERA_CONTROLLER, VERA_DEVICES, VeraDevice
+from . import VeraDevice
+from .const import DOMAIN
 
 _LOGGER = logging.getLogger(__name__)
 
@@ -25,14 +34,18 @@ SUPPORT_FLAGS = SUPPORT_TARGET_TEMPERATURE | SUPPORT_FAN_MODE
 SUPPORT_HVAC = [HVAC_MODE_COOL, HVAC_MODE_HEAT, HVAC_MODE_HEAT_COOL, HVAC_MODE_OFF]
 
 
-def setup_platform(hass, config, add_entities_callback, discovery_info=None):
-    """Set up of Vera thermostats."""
-    add_entities_callback(
+async def async_setup_entry(
+    hass: HomeAssistant,
+    entry: ConfigEntry,
+    async_add_entities: Callable[[List[Entity], bool], None],
+) -> None:
+    """Set up the sensor config entry."""
+    controller_data = hass.data[DOMAIN]
+    async_add_entities(
         [
-            VeraThermostat(device, hass.data[VERA_CONTROLLER])
-            for device in hass.data[VERA_DEVICES]["climate"]
-        ],
-        True,
+            VeraThermostat(device, controller_data.controller)
+            for device in controller_data.devices.get(PLATFORM_DOMAIN)
+        ]
     )
 
 
diff --git a/homeassistant/components/vera/common.py b/homeassistant/components/vera/common.py
new file mode 100644
index 0000000000000000000000000000000000000000..cdfdff404ec9117605bc1ba7577476647fedd006
--- /dev/null
+++ b/homeassistant/components/vera/common.py
@@ -0,0 +1,29 @@
+"""Common vera code."""
+import logging
+from typing import DefaultDict, List, NamedTuple, Set
+
+import pyvera as pv
+
+from homeassistant.components.scene import DOMAIN as SCENE_DOMAIN
+
+_LOGGER = logging.getLogger(__name__)
+
+
+class ControllerData(NamedTuple):
+    """Controller data."""
+
+    controller: pv.VeraController
+    devices: DefaultDict[str, List[pv.VeraDevice]]
+    scenes: List[pv.VeraScene]
+
+
+def get_configured_platforms(controller_data: ControllerData) -> Set[str]:
+    """Get configured platforms for a controller."""
+    platforms = []
+    for platform in controller_data.devices:
+        platforms.append(platform)
+
+    if controller_data.scenes:
+        platforms.append(SCENE_DOMAIN)
+
+    return set(platforms)
diff --git a/homeassistant/components/vera/config_flow.py b/homeassistant/components/vera/config_flow.py
new file mode 100644
index 0000000000000000000000000000000000000000..3d2b30f1079fc7a08bce509f599d1cc7c3df9c63
--- /dev/null
+++ b/homeassistant/components/vera/config_flow.py
@@ -0,0 +1,130 @@
+"""Config flow for Vera."""
+import logging
+import re
+from typing import List, cast
+
+import pyvera as pv
+from requests.exceptions import RequestException
+import voluptuous as vol
+
+from homeassistant import config_entries
+from homeassistant.const import CONF_EXCLUDE, CONF_LIGHTS, CONF_SOURCE
+from homeassistant.core import callback
+
+from .const import CONF_CONTROLLER, DOMAIN
+
+LIST_REGEX = re.compile("[^0-9]+")
+_LOGGER = logging.getLogger(__name__)
+
+
+def str_to_int_list(data: str) -> List[str]:
+    """Convert a string to an int list."""
+    if isinstance(str, list):
+        return cast(List[str], data)
+
+    return [s for s in LIST_REGEX.split(data) if len(s) > 0]
+
+
+def int_list_to_str(data: List[str]) -> str:
+    """Convert an int list to a string."""
+    return " ".join([str(i) for i in data])
+
+
+def new_options(lights: List[str], exclude: List[str]) -> dict:
+    """Create a standard options object."""
+    return {CONF_LIGHTS: lights, CONF_EXCLUDE: exclude}
+
+
+def options_schema(options: dict = None) -> dict:
+    """Return options schema."""
+    options = options or {}
+    return {
+        vol.Optional(
+            CONF_LIGHTS, default=int_list_to_str(options.get(CONF_LIGHTS, [])),
+        ): str,
+        vol.Optional(
+            CONF_EXCLUDE, default=int_list_to_str(options.get(CONF_EXCLUDE, [])),
+        ): str,
+    }
+
+
+def options_data(user_input: dict) -> dict:
+    """Return options dict."""
+    return new_options(
+        str_to_int_list(user_input.get(CONF_LIGHTS, "")),
+        str_to_int_list(user_input.get(CONF_EXCLUDE, "")),
+    )
+
+
+class OptionsFlowHandler(config_entries.OptionsFlow):
+    """Options for the component."""
+
+    def __init__(self, config_entry: config_entries.ConfigEntry):
+        """Init object."""
+        self.config_entry = config_entry
+
+    async def async_step_init(self, user_input=None):
+        """Manage the options."""
+        if user_input is not None:
+            return self.async_create_entry(title="", data=options_data(user_input),)
+
+        return self.async_show_form(
+            step_id="init",
+            data_schema=vol.Schema(options_schema(self.config_entry.options)),
+        )
+
+
+class VeraFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
+    """Vera config flow."""
+
+    @staticmethod
+    @callback
+    def async_get_options_flow(config_entry) -> OptionsFlowHandler:
+        """Get the options flow."""
+        return OptionsFlowHandler(config_entry)
+
+    async def async_step_user(self, user_input: dict = None):
+        """Handle user initiated flow."""
+        if self.hass.config_entries.async_entries(DOMAIN):
+            return self.async_abort(reason="already_configured")
+
+        if user_input is not None:
+            return await self.async_step_finish(
+                {
+                    **user_input,
+                    **options_data(user_input),
+                    **{CONF_SOURCE: config_entries.SOURCE_USER},
+                }
+            )
+
+        return self.async_show_form(
+            step_id="user",
+            data_schema=vol.Schema(
+                {**{vol.Required(CONF_CONTROLLER): str}, **options_schema()}
+            ),
+        )
+
+    async def async_step_import(self, config: dict):
+        """Handle a flow initialized by import."""
+        return await self.async_step_finish(
+            {**config, **{CONF_SOURCE: config_entries.SOURCE_IMPORT}}
+        )
+
+    async def async_step_finish(self, config: dict):
+        """Validate and create config entry."""
+        base_url = config[CONF_CONTROLLER] = config[CONF_CONTROLLER].rstrip("/")
+        controller = pv.VeraController(base_url)
+
+        # Verify the controller is online and get the serial number.
+        try:
+            await self.hass.async_add_executor_job(controller.refresh_data)
+        except RequestException:
+            _LOGGER.error("Failed to connect to vera controller %s", base_url)
+            return self.async_abort(
+                reason="cannot_connect", description_placeholders={"base_url": base_url}
+            )
+
+        await self.async_set_unique_id(controller.serial_number)
+        self._abort_if_unique_id_configured(config)
+
+        return self.async_create_entry(title=base_url, data=config)
diff --git a/homeassistant/components/vera/const.py b/homeassistant/components/vera/const.py
new file mode 100644
index 0000000000000000000000000000000000000000..c4f1d0efa3a0b2379a87b3defc71acc3fcebd348
--- /dev/null
+++ b/homeassistant/components/vera/const.py
@@ -0,0 +1,11 @@
+"""Vera constants."""
+DOMAIN = "vera"
+
+CONF_CONTROLLER = "vera_controller_url"
+
+VERA_ID_FORMAT = "{}_{}"
+
+ATTR_CURRENT_POWER_W = "current_power_w"
+ATTR_CURRENT_ENERGY_KWH = "current_energy_kwh"
+
+CONTROLLER_DATAS = "controller_datas"
diff --git a/homeassistant/components/vera/cover.py b/homeassistant/components/vera/cover.py
index b90dd8a053112daed699d4a47e691ebb38d1b191..0d0edb841c1ec041ab4c2fe05fca7aa7ed0c5d2d 100644
--- a/homeassistant/components/vera/cover.py
+++ b/homeassistant/components/vera/cover.py
@@ -1,21 +1,35 @@
 """Support for Vera cover - curtains, rollershutters etc."""
 import logging
+from typing import Callable, List
 
-from homeassistant.components.cover import ATTR_POSITION, ENTITY_ID_FORMAT, CoverDevice
+from homeassistant.components.cover import (
+    ATTR_POSITION,
+    DOMAIN as PLATFORM_DOMAIN,
+    ENTITY_ID_FORMAT,
+    CoverDevice,
+)
+from homeassistant.config_entries import ConfigEntry
+from homeassistant.core import HomeAssistant
+from homeassistant.helpers.entity import Entity
 
-from . import VERA_CONTROLLER, VERA_DEVICES, VeraDevice
+from . import VeraDevice
+from .const import DOMAIN
 
 _LOGGER = logging.getLogger(__name__)
 
 
-def setup_platform(hass, config, add_entities, discovery_info=None):
-    """Set up the Vera covers."""
-    add_entities(
+async def async_setup_entry(
+    hass: HomeAssistant,
+    entry: ConfigEntry,
+    async_add_entities: Callable[[List[Entity], bool], None],
+) -> None:
+    """Set up the sensor config entry."""
+    controller_data = hass.data[DOMAIN]
+    async_add_entities(
         [
-            VeraCover(device, hass.data[VERA_CONTROLLER])
-            for device in hass.data[VERA_DEVICES]["cover"]
-        ],
-        True,
+            VeraCover(device, controller_data.controller)
+            for device in controller_data.devices.get(PLATFORM_DOMAIN)
+        ]
     )
 
 
diff --git a/homeassistant/components/vera/light.py b/homeassistant/components/vera/light.py
index fee992356816e3c0d49cb2f9c4240efec6686fda..877fdf51f0a48d3493e9cd11638a3fe8d5e11978 100644
--- a/homeassistant/components/vera/light.py
+++ b/homeassistant/components/vera/light.py
@@ -1,29 +1,39 @@
 """Support for Vera lights."""
 import logging
+from typing import Callable, List
 
 from homeassistant.components.light import (
     ATTR_BRIGHTNESS,
     ATTR_HS_COLOR,
+    DOMAIN as PLATFORM_DOMAIN,
     ENTITY_ID_FORMAT,
     SUPPORT_BRIGHTNESS,
     SUPPORT_COLOR,
     Light,
 )
+from homeassistant.config_entries import ConfigEntry
+from homeassistant.core import HomeAssistant
+from homeassistant.helpers.entity import Entity
 import homeassistant.util.color as color_util
 
-from . import VERA_CONTROLLER, VERA_DEVICES, VeraDevice
+from . import VeraDevice
+from .const import DOMAIN
 
 _LOGGER = logging.getLogger(__name__)
 
 
-def setup_platform(hass, config, add_entities, discovery_info=None):
-    """Set up the Vera lights."""
-    add_entities(
+async def async_setup_entry(
+    hass: HomeAssistant,
+    entry: ConfigEntry,
+    async_add_entities: Callable[[List[Entity], bool], None],
+) -> None:
+    """Set up the sensor config entry."""
+    controller_data = hass.data[DOMAIN]
+    async_add_entities(
         [
-            VeraLight(device, hass.data[VERA_CONTROLLER])
-            for device in hass.data[VERA_DEVICES]["light"]
-        ],
-        True,
+            VeraLight(device, controller_data.controller)
+            for device in controller_data.devices.get(PLATFORM_DOMAIN)
+        ]
     )
 
 
diff --git a/homeassistant/components/vera/lock.py b/homeassistant/components/vera/lock.py
index 23b62bb03314667ccdd01cb1e5fe52adf53a4676..da3c432a6afa91ea2ca088f362e0e379134b6a44 100644
--- a/homeassistant/components/vera/lock.py
+++ b/homeassistant/components/vera/lock.py
@@ -1,10 +1,19 @@
 """Support for Vera locks."""
 import logging
-
-from homeassistant.components.lock import ENTITY_ID_FORMAT, LockDevice
+from typing import Callable, List
+
+from homeassistant.components.lock import (
+    DOMAIN as PLATFORM_DOMAIN,
+    ENTITY_ID_FORMAT,
+    LockDevice,
+)
+from homeassistant.config_entries import ConfigEntry
 from homeassistant.const import STATE_LOCKED, STATE_UNLOCKED
+from homeassistant.core import HomeAssistant
+from homeassistant.helpers.entity import Entity
 
-from . import VERA_CONTROLLER, VERA_DEVICES, VeraDevice
+from . import VeraDevice
+from .const import DOMAIN
 
 _LOGGER = logging.getLogger(__name__)
 
@@ -12,14 +21,18 @@ ATTR_LAST_USER_NAME = "changed_by_name"
 ATTR_LOW_BATTERY = "low_battery"
 
 
-def setup_platform(hass, config, add_entities, discovery_info=None):
-    """Find and return Vera locks."""
-    add_entities(
+async def async_setup_entry(
+    hass: HomeAssistant,
+    entry: ConfigEntry,
+    async_add_entities: Callable[[List[Entity], bool], None],
+) -> None:
+    """Set up the sensor config entry."""
+    controller_data = hass.data[DOMAIN]
+    async_add_entities(
         [
-            VeraLock(device, hass.data[VERA_CONTROLLER])
-            for device in hass.data[VERA_DEVICES]["lock"]
-        ],
-        True,
+            VeraLock(device, controller_data.controller)
+            for device in controller_data.devices.get(PLATFORM_DOMAIN)
+        ]
     )
 
 
diff --git a/homeassistant/components/vera/manifest.json b/homeassistant/components/vera/manifest.json
index 63102c2968786217d78418b60a3e0cb647aec125..4f585d964a86a77f041cb70b437635639d92c910 100644
--- a/homeassistant/components/vera/manifest.json
+++ b/homeassistant/components/vera/manifest.json
@@ -1,8 +1,11 @@
 {
   "domain": "vera",
   "name": "Vera",
+  "config_flow": true,
   "documentation": "https://www.home-assistant.io/integrations/vera",
   "requirements": ["pyvera==0.3.7"],
   "dependencies": [],
-  "codeowners": []
+  "codeowners": [
+    "@vangorra"
+  ]
 }
diff --git a/homeassistant/components/vera/scene.py b/homeassistant/components/vera/scene.py
index af5266ed4b3d7b40741687f7fcc96105e962f30d..7d09e2488938816b8b67b0dd7583ddd91bf421e2 100644
--- a/homeassistant/components/vera/scene.py
+++ b/homeassistant/components/vera/scene.py
@@ -1,22 +1,30 @@
 """Support for Vera scenes."""
 import logging
+from typing import Callable, List
 
 from homeassistant.components.scene import Scene
+from homeassistant.config_entries import ConfigEntry
+from homeassistant.core import HomeAssistant
+from homeassistant.helpers.entity import Entity
 from homeassistant.util import slugify
 
-from . import VERA_CONTROLLER, VERA_ID_FORMAT, VERA_SCENES
+from .const import DOMAIN, VERA_ID_FORMAT
 
 _LOGGER = logging.getLogger(__name__)
 
 
-def setup_platform(hass, config, add_entities, discovery_info=None):
-    """Set up the Vera scenes."""
-    add_entities(
+async def async_setup_entry(
+    hass: HomeAssistant,
+    entry: ConfigEntry,
+    async_add_entities: Callable[[List[Entity], bool], None],
+) -> None:
+    """Set up the sensor config entry."""
+    controller_data = hass.data[DOMAIN]
+    async_add_entities(
         [
-            VeraScene(scene, hass.data[VERA_CONTROLLER])
-            for scene in hass.data[VERA_SCENES]
-        ],
-        True,
+            VeraScene(device, controller_data.controller)
+            for device in controller_data.scenes
+        ]
     )
 
 
diff --git a/homeassistant/components/vera/sensor.py b/homeassistant/components/vera/sensor.py
index 9ac0a36ff9cd0007802a3dff4ab1c15de768789d..60ebeeb156655e2c5a760d2adfd08e67fe7d93a4 100644
--- a/homeassistant/components/vera/sensor.py
+++ b/homeassistant/components/vera/sensor.py
@@ -1,29 +1,37 @@
 """Support for Vera sensors."""
 from datetime import timedelta
 import logging
+from typing import Callable, List
 
 import pyvera as veraApi
 
-from homeassistant.components.sensor import ENTITY_ID_FORMAT
+from homeassistant.components.sensor import DOMAIN as PLATFORM_DOMAIN, ENTITY_ID_FORMAT
+from homeassistant.config_entries import ConfigEntry
 from homeassistant.const import TEMP_CELSIUS, TEMP_FAHRENHEIT, UNIT_PERCENTAGE
+from homeassistant.core import HomeAssistant
 from homeassistant.helpers.entity import Entity
 from homeassistant.util import convert
 
-from . import VERA_CONTROLLER, VERA_DEVICES, VeraDevice
+from . import VeraDevice
+from .const import DOMAIN
 
 _LOGGER = logging.getLogger(__name__)
 
 SCAN_INTERVAL = timedelta(seconds=5)
 
 
-def setup_platform(hass, config, add_entities, discovery_info=None):
-    """Set up the Vera controller devices."""
-    add_entities(
+async def async_setup_entry(
+    hass: HomeAssistant,
+    entry: ConfigEntry,
+    async_add_entities: Callable[[List[Entity], bool], None],
+) -> None:
+    """Set up the sensor config entry."""
+    controller_data = hass.data[DOMAIN]
+    async_add_entities(
         [
-            VeraSensor(device, hass.data[VERA_CONTROLLER])
-            for device in hass.data[VERA_DEVICES]["sensor"]
-        ],
-        True,
+            VeraSensor(device, controller_data.controller)
+            for device in controller_data.devices.get(PLATFORM_DOMAIN)
+        ]
     )
 
 
diff --git a/homeassistant/components/vera/strings.json b/homeassistant/components/vera/strings.json
new file mode 100644
index 0000000000000000000000000000000000000000..d8dec2c40cfa700aef48fbe56e44504f138332dc
--- /dev/null
+++ b/homeassistant/components/vera/strings.json
@@ -0,0 +1,32 @@
+{
+  "config": {
+    "title": "Vera",
+    "abort": {
+      "already_configured": "A controller is already configured.",
+      "cannot_connect": "Could not connect to controller with url {base_url}"
+    },
+    "step": {
+      "user": {
+        "title": "Setup Vera controller",
+        "description": "Provide a Vera controller url below. It should look like this: http://192.168.1.161:3480.",
+        "data": {
+          "vera_controller_url": "Controller URL",
+          "lights": "Vera switch device ids to treat as lights in Home Assistant.",
+          "exclude": "Vera device ids to exclude from Home Assistant."
+        }
+      }
+    }
+  },
+  "options": {
+    "step": {
+      "init": {
+        "title": "Vera controller options",
+        "description": "See the vera documentation for details on optional parameters: https://www.home-assistant.io/integrations/vera/. Note: Any changes here will need a restart to the home assistant server. To clear values, provide a space.",
+        "data": {
+          "lights": "Vera switch device ids to treat as lights in Home Assistant.",
+          "exclude": "Vera device ids to exclude from Home Assistant."
+        }
+      }
+    }
+  }
+}
diff --git a/homeassistant/components/vera/switch.py b/homeassistant/components/vera/switch.py
index ab3c3e6adb9555093513a3a72d0c0e44c5993703..a7ae6d45573e41177a8366792e128f898c06fba1 100644
--- a/homeassistant/components/vera/switch.py
+++ b/homeassistant/components/vera/switch.py
@@ -1,22 +1,35 @@
 """Support for Vera switches."""
 import logging
+from typing import Callable, List
 
-from homeassistant.components.switch import ENTITY_ID_FORMAT, SwitchDevice
+from homeassistant.components.switch import (
+    DOMAIN as PLATFORM_DOMAIN,
+    ENTITY_ID_FORMAT,
+    SwitchDevice,
+)
+from homeassistant.config_entries import ConfigEntry
+from homeassistant.core import HomeAssistant
+from homeassistant.helpers.entity import Entity
 from homeassistant.util import convert
 
-from . import VERA_CONTROLLER, VERA_DEVICES, VeraDevice
+from . import VeraDevice
+from .const import DOMAIN
 
 _LOGGER = logging.getLogger(__name__)
 
 
-def setup_platform(hass, config, add_entities, discovery_info=None):
-    """Set up the Vera switches."""
-    add_entities(
+async def async_setup_entry(
+    hass: HomeAssistant,
+    entry: ConfigEntry,
+    async_add_entities: Callable[[List[Entity], bool], None],
+) -> None:
+    """Set up the sensor config entry."""
+    controller_data = hass.data[DOMAIN]
+    async_add_entities(
         [
-            VeraSwitch(device, hass.data[VERA_CONTROLLER])
-            for device in hass.data[VERA_DEVICES]["switch"]
-        ],
-        True,
+            VeraSwitch(device, controller_data.controller)
+            for device in controller_data.devices.get(PLATFORM_DOMAIN)
+        ]
     )
 
 
diff --git a/homeassistant/generated/config_flows.py b/homeassistant/generated/config_flows.py
index 1584d342db4f59e5e2cec247c5abc97a60869df9..e00cd1b5936b34e833bdaa6a422f02d75da8f7db 100644
--- a/homeassistant/generated/config_flows.py
+++ b/homeassistant/generated/config_flows.py
@@ -122,6 +122,7 @@ FLOWS = [
     "unifi",
     "upnp",
     "velbus",
+    "vera",
     "vesync",
     "vilfo",
     "vizio",
diff --git a/tests/components/vera/common.py b/tests/components/vera/common.py
index 649cf9af6a54e852300b0473ee113f3f6c80f756..5574c93c515d0966ee7fd4353e6c40239fb80a37 100644
--- a/tests/components/vera/common.py
+++ b/tests/components/vera/common.py
@@ -1,47 +1,91 @@
 """Common code for tests."""
 
-from typing import Callable, NamedTuple, Tuple
+from typing import Callable, Dict, NamedTuple, Tuple
 
 from mock import MagicMock
-from pyvera import VeraController, VeraDevice, VeraScene
+import pyvera as pv
 
-from homeassistant.components.vera import CONF_CONTROLLER, DOMAIN
+from homeassistant.components.vera.const import CONF_CONTROLLER, DOMAIN
 from homeassistant.core import HomeAssistant
 from homeassistant.setup import async_setup_component
 
+from tests.common import MockConfigEntry
 
-class ComponentData(NamedTuple):
-    """Component data."""
+SetupCallback = Callable[[pv.VeraController, dict], None]
+
+
+class ControllerData(NamedTuple):
+    """Test data about a specific vera controller."""
+
+    controller: pv.VeraController
+    update_callback: Callable
 
-    controller: VeraController
+
+class ComponentData(NamedTuple):
+    """Test data about the vera component."""
+
+    controller_data: ControllerData
+
+
+class ControllerConfig(NamedTuple):
+    """Test config for mocking a vera controller."""
+
+    config: Dict
+    options: Dict
+    config_from_file: bool
+    serial_number: str
+    devices: Tuple[pv.VeraDevice, ...]
+    scenes: Tuple[pv.VeraScene, ...]
+    setup_callback: SetupCallback
+
+
+def new_simple_controller_config(
+    config: dict = None,
+    options: dict = None,
+    config_from_file=False,
+    serial_number="1111",
+    devices: Tuple[pv.VeraDevice, ...] = (),
+    scenes: Tuple[pv.VeraScene, ...] = (),
+    setup_callback: SetupCallback = None,
+) -> ControllerConfig:
+    """Create simple contorller config."""
+    return ControllerConfig(
+        config=config or {CONF_CONTROLLER: "http://127.0.0.1:123"},
+        options=options,
+        config_from_file=config_from_file,
+        serial_number=serial_number,
+        devices=devices,
+        scenes=scenes,
+        setup_callback=setup_callback,
+    )
 
 
 class ComponentFactory:
     """Factory class."""
 
-    def __init__(self, init_controller_mock):
-        """Initialize component factory."""
-        self.init_controller_mock = init_controller_mock
+    def __init__(self, vera_controller_class_mock):
+        """Initialize the factory."""
+        self.vera_controller_class_mock = vera_controller_class_mock
 
     async def configure_component(
-        self,
-        hass: HomeAssistant,
-        devices: Tuple[VeraDevice] = (),
-        scenes: Tuple[VeraScene] = (),
-        setup_callback: Callable[[VeraController], None] = None,
+        self, hass: HomeAssistant, controller_config: ControllerConfig
     ) -> ComponentData:
         """Configure the component with specific mock data."""
-        controller_url = "http://127.0.0.1:123"
-
-        hass_config = {
-            DOMAIN: {CONF_CONTROLLER: controller_url},
+        component_config = {
+            **(controller_config.config or {}),
+            **(controller_config.options or {}),
         }
 
-        controller = MagicMock(spec=VeraController)  # type: VeraController
-        controller.base_url = controller_url
+        controller = MagicMock(spec=pv.VeraController)  # type: pv.VeraController
+        controller.base_url = component_config.get(CONF_CONTROLLER)
         controller.register = MagicMock()
-        controller.get_devices = MagicMock(return_value=devices or ())
-        controller.get_scenes = MagicMock(return_value=scenes or ())
+        controller.start = MagicMock()
+        controller.stop = MagicMock()
+        controller.refresh_data = MagicMock()
+        controller.temperature_units = "C"
+        controller.serial_number = controller_config.serial_number
+        controller.get_devices = MagicMock(return_value=controller_config.devices)
+        controller.get_scenes = MagicMock(return_value=controller_config.scenes)
 
         for vera_obj in controller.get_devices() + controller.get_scenes():
             vera_obj.vera_controller = controller
@@ -49,17 +93,39 @@ class ComponentFactory:
         controller.get_devices.reset_mock()
         controller.get_scenes.reset_mock()
 
-        if setup_callback:
-            setup_callback(controller, hass_config)
+        if controller_config.setup_callback:
+            controller_config.setup_callback(controller)
+
+        self.vera_controller_class_mock.return_value = controller
 
-        def init_controller(base_url: str) -> list:
-            nonlocal controller
-            return [controller, True]
+        hass_config = {}
 
-        self.init_controller_mock.side_effect = init_controller
+        # Setup component through config file import.
+        if controller_config.config_from_file:
+            hass_config[DOMAIN] = component_config
 
         # Setup Home Assistant.
         assert await async_setup_component(hass, DOMAIN, hass_config)
         await hass.async_block_till_done()
 
-        return ComponentData(controller=controller)
+        # Setup component through config flow.
+        if not controller_config.config_from_file:
+            entry = MockConfigEntry(
+                domain=DOMAIN, data=component_config, options={}, unique_id="12345"
+            )
+            entry.add_to_hass(hass)
+
+            await hass.config_entries.async_setup(entry.entry_id)
+            await hass.async_block_till_done()
+
+        update_callback = (
+            controller.register.call_args_list[0][0][1]
+            if controller.register.call_args_list
+            else None
+        )
+
+        return ComponentData(
+            controller_data=ControllerData(
+                controller=controller, update_callback=update_callback
+            )
+        )
diff --git a/tests/components/vera/conftest.py b/tests/components/vera/conftest.py
index b94a40135d8b09c169568d0adba956810676502f..2c15d3e4182fbeed60de90a85e04e72d065c48b7 100644
--- a/tests/components/vera/conftest.py
+++ b/tests/components/vera/conftest.py
@@ -9,5 +9,5 @@ from .common import ComponentFactory
 @pytest.fixture()
 def vera_component_factory():
     """Return a factory for initializing the vera component."""
-    with patch("pyvera.init_controller") as init_controller_mock:
-        yield ComponentFactory(init_controller_mock)
+    with patch("pyvera.VeraController") as vera_controller_class_mock:
+        yield ComponentFactory(vera_controller_class_mock)
diff --git a/tests/components/vera/test_binary_sensor.py b/tests/components/vera/test_binary_sensor.py
index 2c2e2b8638818a838dfb739002b9272068b5761d..72651d6eda4f7490529e49f1cbfd0a27df23eb6b 100644
--- a/tests/components/vera/test_binary_sensor.py
+++ b/tests/components/vera/test_binary_sensor.py
@@ -1,38 +1,36 @@
 """Vera tests."""
 from unittest.mock import MagicMock
 
-from pyvera import VeraBinarySensor
+import pyvera as pv
 
 from homeassistant.core import HomeAssistant
 
-from .common import ComponentFactory
+from .common import ComponentFactory, new_simple_controller_config
 
 
 async def test_binary_sensor(
     hass: HomeAssistant, vera_component_factory: ComponentFactory
 ) -> None:
     """Test function."""
-    vera_device = MagicMock(spec=VeraBinarySensor)  # type: VeraBinarySensor
+    vera_device = MagicMock(spec=pv.VeraBinarySensor)  # type: pv.VeraBinarySensor
     vera_device.device_id = 1
+    vera_device.vera_device_id = 1
     vera_device.name = "dev1"
     vera_device.is_tripped = False
     entity_id = "binary_sensor.dev1_1"
 
     component_data = await vera_component_factory.configure_component(
-        hass=hass, devices=(vera_device,)
+        hass=hass,
+        controller_config=new_simple_controller_config(devices=(vera_device,)),
     )
-    controller = component_data.controller
-
-    update_callback = controller.register.call_args_list[0][0][1]
+    update_callback = component_data.controller_data.update_callback
 
     vera_device.is_tripped = False
     update_callback(vera_device)
     await hass.async_block_till_done()
     assert hass.states.get(entity_id).state == "off"
-    controller.register.reset_mock()
 
     vera_device.is_tripped = True
     update_callback(vera_device)
     await hass.async_block_till_done()
     assert hass.states.get(entity_id).state == "on"
-    controller.register.reset_mock()
diff --git a/tests/components/vera/test_climate.py b/tests/components/vera/test_climate.py
index c27a72865fd995f2a1a4728082444555c87035fc..9e5fa983ed053fc8405b39d4f100642bfa11f001 100644
--- a/tests/components/vera/test_climate.py
+++ b/tests/components/vera/test_climate.py
@@ -1,7 +1,7 @@
 """Vera tests."""
 from unittest.mock import MagicMock
 
-from pyvera import CATEGORY_THERMOSTAT, VeraController, VeraThermostat
+import pyvera as pv
 
 from homeassistant.components.climate.const import (
     FAN_AUTO,
@@ -13,17 +13,17 @@ from homeassistant.components.climate.const import (
 )
 from homeassistant.core import HomeAssistant
 
-from .common import ComponentFactory
+from .common import ComponentFactory, new_simple_controller_config
 
 
 async def test_climate(
     hass: HomeAssistant, vera_component_factory: ComponentFactory
 ) -> None:
     """Test function."""
-    vera_device = MagicMock(spec=VeraThermostat)  # type: VeraThermostat
+    vera_device = MagicMock(spec=pv.VeraThermostat)  # type: pv.VeraThermostat
     vera_device.device_id = 1
     vera_device.name = "dev1"
-    vera_device.category = CATEGORY_THERMOSTAT
+    vera_device.category = pv.CATEGORY_THERMOSTAT
     vera_device.power = 10
     vera_device.get_current_temperature.return_value = 71
     vera_device.get_hvac_mode.return_value = "Off"
@@ -31,10 +31,10 @@ async def test_climate(
     entity_id = "climate.dev1_1"
 
     component_data = await vera_component_factory.configure_component(
-        hass=hass, devices=(vera_device,),
+        hass=hass,
+        controller_config=new_simple_controller_config(devices=(vera_device,)),
     )
-    controller = component_data.controller
-    update_callback = controller.register.call_args_list[0][0][1]
+    update_callback = component_data.controller_data.update_callback
 
     assert hass.states.get(entity_id).state == HVAC_MODE_OFF
 
@@ -123,24 +123,26 @@ async def test_climate_f(
     hass: HomeAssistant, vera_component_factory: ComponentFactory
 ) -> None:
     """Test function."""
-    vera_device = MagicMock(spec=VeraThermostat)  # type: VeraThermostat
+    vera_device = MagicMock(spec=pv.VeraThermostat)  # type: pv.VeraThermostat
     vera_device.device_id = 1
     vera_device.name = "dev1"
-    vera_device.category = CATEGORY_THERMOSTAT
+    vera_device.category = pv.CATEGORY_THERMOSTAT
     vera_device.power = 10
     vera_device.get_current_temperature.return_value = 71
     vera_device.get_hvac_mode.return_value = "Off"
     vera_device.get_current_goal_temperature.return_value = 72
     entity_id = "climate.dev1_1"
 
-    def setup_callback(controller: VeraController, hass_config: dict) -> None:
+    def setup_callback(controller: pv.VeraController) -> None:
         controller.temperature_units = "F"
 
     component_data = await vera_component_factory.configure_component(
-        hass=hass, devices=(vera_device,), setup_callback=setup_callback
+        hass=hass,
+        controller_config=new_simple_controller_config(
+            devices=(vera_device,), setup_callback=setup_callback
+        ),
     )
-    controller = component_data.controller
-    update_callback = controller.register.call_args_list[0][0][1]
+    update_callback = component_data.controller_data.update_callback
 
     await hass.services.async_call(
         "climate", "set_temperature", {"entity_id": entity_id, "temperature": 30},
diff --git a/tests/components/vera/test_config_flow.py b/tests/components/vera/test_config_flow.py
new file mode 100644
index 0000000000000000000000000000000000000000..52ba55b509c8ac46585a613550194160b0adaa5f
--- /dev/null
+++ b/tests/components/vera/test_config_flow.py
@@ -0,0 +1,159 @@
+"""Vera tests."""
+from unittest.mock import MagicMock
+
+from mock import patch
+from requests.exceptions import RequestException
+
+from homeassistant import config_entries, data_entry_flow
+from homeassistant.components.vera import CONF_CONTROLLER, DOMAIN
+from homeassistant.const import CONF_EXCLUDE, CONF_LIGHTS, CONF_SOURCE
+from homeassistant.core import HomeAssistant
+from homeassistant.data_entry_flow import (
+    RESULT_TYPE_ABORT,
+    RESULT_TYPE_CREATE_ENTRY,
+    RESULT_TYPE_FORM,
+)
+
+from tests.common import MockConfigEntry
+
+
+async def test_async_step_user_success(hass: HomeAssistant) -> None:
+    """Test user step success."""
+    with patch("pyvera.VeraController") as vera_controller_class_mock:
+        controller = MagicMock()
+        controller.refresh_data = MagicMock()
+        controller.serial_number = "serial_number_0"
+        vera_controller_class_mock.return_value = controller
+
+        result = await hass.config_entries.flow.async_init(
+            DOMAIN, context={"source": config_entries.SOURCE_USER}
+        )
+        assert result["type"] == RESULT_TYPE_FORM
+        assert result["step_id"] == config_entries.SOURCE_USER
+
+        result = await hass.config_entries.flow.async_configure(
+            result["flow_id"],
+            user_input={
+                CONF_CONTROLLER: "http://127.0.0.1:123/",
+                CONF_LIGHTS: "12 13",
+                CONF_EXCLUDE: "14 15",
+            },
+        )
+        assert result["type"] == RESULT_TYPE_CREATE_ENTRY
+        assert result["title"] == "http://127.0.0.1:123"
+        assert result["data"] == {
+            CONF_CONTROLLER: "http://127.0.0.1:123",
+            CONF_SOURCE: config_entries.SOURCE_USER,
+            CONF_LIGHTS: ["12", "13"],
+            CONF_EXCLUDE: ["14", "15"],
+        }
+        assert result["result"].unique_id == controller.serial_number
+
+    entries = hass.config_entries.async_entries(DOMAIN)
+    assert entries
+
+
+async def test_async_step_user_already_configured(hass: HomeAssistant) -> None:
+    """Test user step with entry already configured."""
+    entry = MockConfigEntry(domain=DOMAIN, data={}, options={}, unique_id="12345")
+    entry.add_to_hass(hass)
+
+    result = await hass.config_entries.flow.async_init(
+        DOMAIN, context={"source": config_entries.SOURCE_USER}
+    )
+    assert result["type"] == RESULT_TYPE_ABORT
+    assert result["reason"] == "already_configured"
+
+
+async def test_async_step_import_success(hass: HomeAssistant) -> None:
+    """Test import step success."""
+    with patch("pyvera.VeraController") as vera_controller_class_mock:
+        controller = MagicMock()
+        controller.refresh_data = MagicMock()
+        controller.serial_number = "serial_number_1"
+        vera_controller_class_mock.return_value = controller
+
+        result = await hass.config_entries.flow.async_init(
+            DOMAIN,
+            context={"source": config_entries.SOURCE_IMPORT},
+            data={CONF_CONTROLLER: "http://127.0.0.1:123/"},
+        )
+
+        assert result["type"] == RESULT_TYPE_CREATE_ENTRY
+        assert result["title"] == "http://127.0.0.1:123"
+        assert result["data"] == {
+            CONF_CONTROLLER: "http://127.0.0.1:123",
+            CONF_SOURCE: config_entries.SOURCE_IMPORT,
+        }
+        assert result["result"].unique_id == controller.serial_number
+
+
+async def test_async_step_import_alredy_setup(hass: HomeAssistant) -> None:
+    """Test import step with entry already setup."""
+    entry = MockConfigEntry(domain=DOMAIN, data={}, options={}, unique_id="12345")
+    entry.add_to_hass(hass)
+
+    with patch("pyvera.VeraController") as vera_controller_class_mock:
+        controller = MagicMock()
+        controller.refresh_data = MagicMock()
+        controller.serial_number = "12345"
+        vera_controller_class_mock.return_value = controller
+
+        result = await hass.config_entries.flow.async_init(
+            DOMAIN,
+            context={"source": config_entries.SOURCE_IMPORT},
+            data={CONF_CONTROLLER: "http://localhost:445"},
+        )
+        assert result["type"] == RESULT_TYPE_ABORT
+        assert result["reason"] == "already_configured"
+
+
+async def test_async_step_finish_error(hass: HomeAssistant) -> None:
+    """Test finish step with error."""
+    with patch("pyvera.VeraController") as vera_controller_class_mock:
+        controller = MagicMock()
+        controller.refresh_data = MagicMock(side_effect=RequestException())
+        vera_controller_class_mock.return_value = controller
+
+        result = await hass.config_entries.flow.async_init(
+            DOMAIN,
+            context={"source": config_entries.SOURCE_IMPORT},
+            data={CONF_CONTROLLER: "http://127.0.0.1:123/"},
+        )
+
+        assert result["type"] == "abort"
+        assert result["reason"] == "cannot_connect"
+        assert result["description_placeholders"] == {
+            "base_url": "http://127.0.0.1:123"
+        }
+
+
+async def test_options(hass):
+    """Test updating options."""
+    base_url = "http://127.0.0.1/"
+    entry = MockConfigEntry(
+        domain=DOMAIN,
+        title=base_url,
+        data={CONF_CONTROLLER: "http://127.0.0.1/"},
+        options={CONF_LIGHTS: [1, 2, 3]},
+    )
+    entry.add_to_hass(hass)
+
+    result = await hass.config_entries.options.async_init(
+        entry.entry_id, context={"source": "test"}, data=None
+    )
+    assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
+    assert result["step_id"] == "init"
+
+    result = await hass.config_entries.options.async_configure(
+        result["flow_id"],
+        user_input={
+            CONF_LIGHTS: "1,2;3  4 5_6bb7",
+            CONF_EXCLUDE: "8,9;10  11 12_13bb14",
+        },
+    )
+    assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
+    assert result["data"] == {
+        CONF_LIGHTS: ["1", "2", "3", "4", "5", "6", "7"],
+        CONF_EXCLUDE: ["8", "9", "10", "11", "12", "13", "14"],
+    }
diff --git a/tests/components/vera/test_cover.py b/tests/components/vera/test_cover.py
index 79cb4adedfbc9272a19756f077b9795ee5e199c0..62cd47f831cdc3e09e09106c1ac02305a51df423 100644
--- a/tests/components/vera/test_cover.py
+++ b/tests/components/vera/test_cover.py
@@ -1,30 +1,30 @@
 """Vera tests."""
 from unittest.mock import MagicMock
 
-from pyvera import CATEGORY_CURTAIN, VeraCurtain
+import pyvera as pv
 
 from homeassistant.core import HomeAssistant
 
-from .common import ComponentFactory
+from .common import ComponentFactory, new_simple_controller_config
 
 
 async def test_cover(
     hass: HomeAssistant, vera_component_factory: ComponentFactory
 ) -> None:
     """Test function."""
-    vera_device = MagicMock(spec=VeraCurtain)  # type: VeraCurtain
+    vera_device = MagicMock(spec=pv.VeraCurtain)  # type: pv.VeraCurtain
     vera_device.device_id = 1
     vera_device.name = "dev1"
-    vera_device.category = CATEGORY_CURTAIN
+    vera_device.category = pv.CATEGORY_CURTAIN
     vera_device.is_closed = False
     vera_device.get_level.return_value = 0
     entity_id = "cover.dev1_1"
 
     component_data = await vera_component_factory.configure_component(
-        hass=hass, devices=(vera_device,),
+        hass=hass,
+        controller_config=new_simple_controller_config(devices=(vera_device,)),
     )
-    controller = component_data.controller
-    update_callback = controller.register.call_args_list[0][0][1]
+    update_callback = component_data.controller_data.update_callback
 
     assert hass.states.get(entity_id).state == "closed"
     assert hass.states.get(entity_id).attributes["current_position"] == 0
diff --git a/tests/components/vera/test_init.py b/tests/components/vera/test_init.py
index 9ff6cb4058b3c0d0d32accc6aeb381ff818dbe7b..a6208726451ba059022507f42e42404bbb2c27d5 100644
--- a/tests/components/vera/test_init.py
+++ b/tests/components/vera/test_init.py
@@ -1,78 +1,112 @@
 """Vera tests."""
-from unittest.mock import MagicMock
-
-from pyvera import (
-    VeraArmableDevice,
-    VeraBinarySensor,
-    VeraController,
-    VeraCurtain,
-    VeraDevice,
-    VeraDimmer,
-    VeraLock,
-    VeraScene,
-    VeraSceneController,
-    VeraSensor,
-    VeraSwitch,
-    VeraThermostat,
-)
-
-from homeassistant.components.vera import (
-    CONF_EXCLUDE,
-    CONF_LIGHTS,
-    DOMAIN,
-    VERA_DEVICES,
-)
+from asynctest import MagicMock
+import pyvera as pv
+from requests.exceptions import RequestException
+
+from homeassistant.components.vera import CONF_CONTROLLER, DOMAIN
+from homeassistant.config_entries import ENTRY_STATE_NOT_LOADED
 from homeassistant.core import HomeAssistant
 
-from .common import ComponentFactory
+from .common import ComponentFactory, new_simple_controller_config
+
+from tests.common import MockConfigEntry
 
 
-def new_vera_device(cls, device_id: int) -> VeraDevice:
-    """Create new mocked vera device.."""
-    vera_device = MagicMock(spec=cls)  # type: VeraDevice
-    vera_device.device_id = device_id
-    vera_device.name = f"dev${device_id}"
-    return vera_device
+async def test_init(
+    hass: HomeAssistant, vera_component_factory: ComponentFactory
+) -> None:
+    """Test function."""
+    vera_device1 = MagicMock(spec=pv.VeraBinarySensor)  # type: pv.VeraBinarySensor
+    vera_device1.device_id = 1
+    vera_device1.vera_device_id = 1
+    vera_device1.name = "first_dev"
+    vera_device1.is_tripped = False
+    entity1_id = "binary_sensor.first_dev_1"
+
+    await vera_component_factory.configure_component(
+        hass=hass,
+        controller_config=new_simple_controller_config(
+            config={CONF_CONTROLLER: "http://127.0.0.1:111"},
+            config_from_file=False,
+            serial_number="first_serial",
+            devices=(vera_device1,),
+        ),
+    )
 
+    entity_registry = await hass.helpers.entity_registry.async_get_registry()
+    entry1 = entity_registry.async_get(entity1_id)
 
-def assert_hass_vera_devices(hass: HomeAssistant, platform: str, arr_len: int) -> None:
-    """Assert vera devices are present.."""
-    assert hass.data[VERA_DEVICES][platform]
-    assert len(hass.data[VERA_DEVICES][platform]) == arr_len
+    assert entry1
 
 
-async def test_init(
+async def test_init_from_file(
     hass: HomeAssistant, vera_component_factory: ComponentFactory
 ) -> None:
     """Test function."""
-
-    def setup_callback(controller: VeraController, hass_config: dict) -> None:
-        hass_config[DOMAIN][CONF_EXCLUDE] = [11]
-        hass_config[DOMAIN][CONF_LIGHTS] = [10]
+    vera_device1 = MagicMock(spec=pv.VeraBinarySensor)  # type: pv.VeraBinarySensor
+    vera_device1.device_id = 1
+    vera_device1.vera_device_id = 1
+    vera_device1.name = "first_dev"
+    vera_device1.is_tripped = False
+    entity1_id = "binary_sensor.first_dev_1"
 
     await vera_component_factory.configure_component(
         hass=hass,
-        devices=(
-            new_vera_device(VeraDimmer, 1),
-            new_vera_device(VeraBinarySensor, 2),
-            new_vera_device(VeraSensor, 3),
-            new_vera_device(VeraArmableDevice, 4),
-            new_vera_device(VeraLock, 5),
-            new_vera_device(VeraThermostat, 6),
-            new_vera_device(VeraCurtain, 7),
-            new_vera_device(VeraSceneController, 8),
-            new_vera_device(VeraSwitch, 9),
-            new_vera_device(VeraSwitch, 10),
-            new_vera_device(VeraSwitch, 11),
+        controller_config=new_simple_controller_config(
+            config={CONF_CONTROLLER: "http://127.0.0.1:111"},
+            config_from_file=True,
+            serial_number="first_serial",
+            devices=(vera_device1,),
         ),
-        scenes=(MagicMock(spec=VeraScene),),
-        setup_callback=setup_callback,
     )
 
-    assert_hass_vera_devices(hass, "light", 2)
-    assert_hass_vera_devices(hass, "binary_sensor", 1)
-    assert_hass_vera_devices(hass, "sensor", 2)
-    assert_hass_vera_devices(hass, "switch", 2)
-    assert_hass_vera_devices(hass, "lock", 1)
-    assert_hass_vera_devices(hass, "climate", 1)
-    assert_hass_vera_devices(hass, "cover", 1)
+    entity_registry = await hass.helpers.entity_registry.async_get_registry()
+    entry1 = entity_registry.async_get(entity1_id)
+    assert entry1
+
+
+async def test_unload(
+    hass: HomeAssistant, vera_component_factory: ComponentFactory
+) -> None:
+    """Test function."""
+    vera_device1 = MagicMock(spec=pv.VeraBinarySensor)  # type: pv.VeraBinarySensor
+    vera_device1.device_id = 1
+    vera_device1.vera_device_id = 1
+    vera_device1.name = "first_dev"
+    vera_device1.is_tripped = False
+
+    await vera_component_factory.configure_component(
+        hass=hass, controller_config=new_simple_controller_config()
+    )
+
+    entries = hass.config_entries.async_entries(DOMAIN)
+    assert entries
+
+    for config_entry in entries:
+        assert await hass.config_entries.async_unload(config_entry.entry_id)
+        assert config_entry.state == ENTRY_STATE_NOT_LOADED
+
+
+async def test_async_setup_entry_error(
+    hass: HomeAssistant, vera_component_factory: ComponentFactory
+) -> None:
+    """Test function."""
+
+    def setup_callback(controller: pv.VeraController) -> None:
+        controller.get_devices.side_effect = RequestException()
+        controller.get_scenes.side_effect = RequestException()
+
+    await vera_component_factory.configure_component(
+        hass=hass,
+        controller_config=new_simple_controller_config(setup_callback=setup_callback),
+    )
+
+    entry = MockConfigEntry(
+        domain=DOMAIN,
+        data={CONF_CONTROLLER: "http://127.0.0.1"},
+        options={},
+        unique_id="12345",
+    )
+    entry.add_to_hass(hass)
+
+    assert not await hass.config_entries.async_setup(entry.entry_id)
diff --git a/tests/components/vera/test_light.py b/tests/components/vera/test_light.py
index fa63ce6345444411fcc3e248aec9d40d96d83b2e..fefa07ffa6ee40525ec8ba0475a23dcf2adf51ca 100644
--- a/tests/components/vera/test_light.py
+++ b/tests/components/vera/test_light.py
@@ -1,22 +1,22 @@
 """Vera tests."""
 from unittest.mock import MagicMock
 
-from pyvera import CATEGORY_DIMMER, VeraDimmer
+import pyvera as pv
 
 from homeassistant.components.light import ATTR_BRIGHTNESS, ATTR_HS_COLOR
 from homeassistant.core import HomeAssistant
 
-from .common import ComponentFactory
+from .common import ComponentFactory, new_simple_controller_config
 
 
 async def test_light(
     hass: HomeAssistant, vera_component_factory: ComponentFactory
 ) -> None:
     """Test function."""
-    vera_device = MagicMock(spec=VeraDimmer)  # type: VeraDimmer
+    vera_device = MagicMock(spec=pv.VeraDimmer)  # type: pv.VeraDimmer
     vera_device.device_id = 1
     vera_device.name = "dev1"
-    vera_device.category = CATEGORY_DIMMER
+    vera_device.category = pv.CATEGORY_DIMMER
     vera_device.is_switched_on = MagicMock(return_value=False)
     vera_device.get_brightness = MagicMock(return_value=0)
     vera_device.get_color = MagicMock(return_value=[0, 0, 0])
@@ -24,10 +24,10 @@ async def test_light(
     entity_id = "light.dev1_1"
 
     component_data = await vera_component_factory.configure_component(
-        hass=hass, devices=(vera_device,),
+        hass=hass,
+        controller_config=new_simple_controller_config(devices=(vera_device,)),
     )
-    controller = component_data.controller
-    update_callback = controller.register.call_args_list[0][0][1]
+    update_callback = component_data.controller_data.update_callback
 
     assert hass.states.get(entity_id).state == "off"
 
diff --git a/tests/components/vera/test_lock.py b/tests/components/vera/test_lock.py
index 362bdbeddc0fdef3d36434d7c1ac6950b52ce97a..d1b2209294a375ba84dbc2bbc2d2f9f03711e1fa 100644
--- a/tests/components/vera/test_lock.py
+++ b/tests/components/vera/test_lock.py
@@ -1,30 +1,30 @@
 """Vera tests."""
 from unittest.mock import MagicMock
 
-from pyvera import CATEGORY_LOCK, VeraLock
+import pyvera as pv
 
 from homeassistant.const import STATE_LOCKED, STATE_UNLOCKED
 from homeassistant.core import HomeAssistant
 
-from .common import ComponentFactory
+from .common import ComponentFactory, new_simple_controller_config
 
 
 async def test_lock(
     hass: HomeAssistant, vera_component_factory: ComponentFactory
 ) -> None:
     """Test function."""
-    vera_device = MagicMock(spec=VeraLock)  # type: VeraLock
+    vera_device = MagicMock(spec=pv.VeraLock)  # type: pv.VeraLock
     vera_device.device_id = 1
     vera_device.name = "dev1"
-    vera_device.category = CATEGORY_LOCK
+    vera_device.category = pv.CATEGORY_LOCK
     vera_device.is_locked = MagicMock(return_value=False)
     entity_id = "lock.dev1_1"
 
     component_data = await vera_component_factory.configure_component(
-        hass=hass, devices=(vera_device,),
+        hass=hass,
+        controller_config=new_simple_controller_config(devices=(vera_device,)),
     )
-    controller = component_data.controller
-    update_callback = controller.register.call_args_list[0][0][1]
+    update_callback = component_data.controller_data.update_callback
 
     assert hass.states.get(entity_id).state == STATE_UNLOCKED
 
diff --git a/tests/components/vera/test_scene.py b/tests/components/vera/test_scene.py
index 136227ffa7126e6c0d433ae77c3540d1a05d83cf..732a331681bdb234e3f297a57c836c65f15c38cd 100644
--- a/tests/components/vera/test_scene.py
+++ b/tests/components/vera/test_scene.py
@@ -1,24 +1,24 @@
 """Vera tests."""
 from unittest.mock import MagicMock
 
-from pyvera import VeraScene
+import pyvera as pv
 
 from homeassistant.core import HomeAssistant
 
-from .common import ComponentFactory
+from .common import ComponentFactory, new_simple_controller_config
 
 
 async def test_scene(
     hass: HomeAssistant, vera_component_factory: ComponentFactory
 ) -> None:
     """Test function."""
-    vera_scene = MagicMock(spec=VeraScene)  # type: VeraScene
+    vera_scene = MagicMock(spec=pv.VeraScene)  # type: pv.VeraScene
     vera_scene.scene_id = 1
     vera_scene.name = "dev1"
     entity_id = "scene.dev1_1"
 
     await vera_component_factory.configure_component(
-        hass=hass, scenes=(vera_scene,),
+        hass=hass, controller_config=new_simple_controller_config(scenes=(vera_scene,)),
     )
 
     await hass.services.async_call(
diff --git a/tests/components/vera/test_sensor.py b/tests/components/vera/test_sensor.py
index 9e84815d636230d669bda55afb7d5655c9f777ec..c915c5ead0fd173e0c1e08bb0c1fa0b63217545e 100644
--- a/tests/components/vera/test_sensor.py
+++ b/tests/components/vera/test_sensor.py
@@ -2,21 +2,12 @@
 from typing import Any, Callable, Tuple
 from unittest.mock import MagicMock
 
-from pyvera import (
-    CATEGORY_HUMIDITY_SENSOR,
-    CATEGORY_LIGHT_SENSOR,
-    CATEGORY_POWER_METER,
-    CATEGORY_SCENE_CONTROLLER,
-    CATEGORY_TEMPERATURE_SENSOR,
-    CATEGORY_UV_SENSOR,
-    VeraController,
-    VeraSensor,
-)
+import pyvera as pv
 
 from homeassistant.const import UNIT_PERCENTAGE
 from homeassistant.core import HomeAssistant
 
-from .common import ComponentFactory
+from .common import ComponentFactory, new_simple_controller_config
 
 
 async def run_sensor_test(
@@ -26,10 +17,10 @@ async def run_sensor_test(
     class_property: str,
     assert_states: Tuple[Tuple[Any, Any]],
     assert_unit_of_measurement: str = None,
-    setup_callback: Callable[[VeraController], None] = None,
+    setup_callback: Callable[[pv.VeraController], None] = None,
 ) -> None:
     """Test generic sensor."""
-    vera_device = MagicMock(spec=VeraSensor)  # type: VeraSensor
+    vera_device = MagicMock(spec=pv.VeraSensor)  # type: pv.VeraSensor
     vera_device.device_id = 1
     vera_device.name = "dev1"
     vera_device.category = category
@@ -37,10 +28,12 @@ async def run_sensor_test(
     entity_id = "sensor.dev1_1"
 
     component_data = await vera_component_factory.configure_component(
-        hass=hass, devices=(vera_device,), setup_callback=setup_callback
+        hass=hass,
+        controller_config=new_simple_controller_config(
+            devices=(vera_device,), setup_callback=setup_callback
+        ),
     )
-    controller = component_data.controller
-    update_callback = controller.register.call_args_list[0][0][1]
+    update_callback = component_data.controller_data.update_callback
 
     for (initial_value, state_value) in assert_states:
         setattr(vera_device, class_property, initial_value)
@@ -57,13 +50,13 @@ async def test_temperature_sensor_f(
 ) -> None:
     """Test function."""
 
-    def setup_callback(controller: VeraController, hass_config: dict) -> None:
+    def setup_callback(controller: pv.VeraController) -> None:
         controller.temperature_units = "F"
 
     await run_sensor_test(
         hass=hass,
         vera_component_factory=vera_component_factory,
-        category=CATEGORY_TEMPERATURE_SENSOR,
+        category=pv.CATEGORY_TEMPERATURE_SENSOR,
         class_property="temperature",
         assert_states=(("33", "1"), ("44", "7")),
         setup_callback=setup_callback,
@@ -77,7 +70,7 @@ async def test_temperature_sensor_c(
     await run_sensor_test(
         hass=hass,
         vera_component_factory=vera_component_factory,
-        category=CATEGORY_TEMPERATURE_SENSOR,
+        category=pv.CATEGORY_TEMPERATURE_SENSOR,
         class_property="temperature",
         assert_states=(("33", "33"), ("44", "44")),
     )
@@ -90,7 +83,7 @@ async def test_light_sensor(
     await run_sensor_test(
         hass=hass,
         vera_component_factory=vera_component_factory,
-        category=CATEGORY_LIGHT_SENSOR,
+        category=pv.CATEGORY_LIGHT_SENSOR,
         class_property="light",
         assert_states=(("12", "12"), ("13", "13")),
         assert_unit_of_measurement="lx",
@@ -104,7 +97,7 @@ async def test_uv_sensor(
     await run_sensor_test(
         hass=hass,
         vera_component_factory=vera_component_factory,
-        category=CATEGORY_UV_SENSOR,
+        category=pv.CATEGORY_UV_SENSOR,
         class_property="light",
         assert_states=(("12", "12"), ("13", "13")),
         assert_unit_of_measurement="level",
@@ -118,7 +111,7 @@ async def test_humidity_sensor(
     await run_sensor_test(
         hass=hass,
         vera_component_factory=vera_component_factory,
-        category=CATEGORY_HUMIDITY_SENSOR,
+        category=pv.CATEGORY_HUMIDITY_SENSOR,
         class_property="humidity",
         assert_states=(("12", "12"), ("13", "13")),
         assert_unit_of_measurement=UNIT_PERCENTAGE,
@@ -132,7 +125,7 @@ async def test_power_meter_sensor(
     await run_sensor_test(
         hass=hass,
         vera_component_factory=vera_component_factory,
-        category=CATEGORY_POWER_METER,
+        category=pv.CATEGORY_POWER_METER,
         class_property="power",
         assert_states=(("12", "12"), ("13", "13")),
         assert_unit_of_measurement="watts",
@@ -144,7 +137,7 @@ async def test_trippable_sensor(
 ) -> None:
     """Test function."""
 
-    def setup_callback(controller: VeraController, hass_config: dict) -> None:
+    def setup_callback(controller: pv.VeraController) -> None:
         controller.get_devices()[0].is_trippable = True
 
     await run_sensor_test(
@@ -162,7 +155,7 @@ async def test_unknown_sensor(
 ) -> None:
     """Test function."""
 
-    def setup_callback(controller: VeraController, hass_config: dict) -> None:
+    def setup_callback(controller: pv.VeraController) -> None:
         controller.get_devices()[0].is_trippable = False
 
     await run_sensor_test(
@@ -179,21 +172,21 @@ async def test_scene_controller_sensor(
     hass: HomeAssistant, vera_component_factory: ComponentFactory
 ) -> None:
     """Test function."""
-    vera_device = MagicMock(spec=VeraSensor)  # type: VeraSensor
+    vera_device = MagicMock(spec=pv.VeraSensor)  # type: pv.VeraSensor
     vera_device.device_id = 1
     vera_device.name = "dev1"
-    vera_device.category = CATEGORY_SCENE_CONTROLLER
+    vera_device.category = pv.CATEGORY_SCENE_CONTROLLER
     vera_device.get_last_scene_id = MagicMock(return_value="id0")
     vera_device.get_last_scene_time = MagicMock(return_value="0000")
     entity_id = "sensor.dev1_1"
 
     component_data = await vera_component_factory.configure_component(
-        hass=hass, devices=(vera_device,)
+        hass=hass,
+        controller_config=new_simple_controller_config(devices=(vera_device,)),
     )
-    controller = component_data.controller
-    update_callback = controller.register.call_args_list[0][0][1]
+    update_callback = component_data.controller_data.update_callback
 
-    vera_device.get_last_scene_time = "1111"
+    vera_device.get_last_scene_time.return_value = "1111"
     update_callback(vera_device)
     await hass.async_block_till_done()
     assert hass.states.get(entity_id).state == "id0"
diff --git a/tests/components/vera/test_switch.py b/tests/components/vera/test_switch.py
index ba09068e7e602fb14265351c8dbf1005bcc91f84..c41afad4759f8f3f909933ed4fbf483791245a54 100644
--- a/tests/components/vera/test_switch.py
+++ b/tests/components/vera/test_switch.py
@@ -1,29 +1,29 @@
 """Vera tests."""
 from unittest.mock import MagicMock
 
-from pyvera import CATEGORY_SWITCH, VeraSwitch
+import pyvera as pv
 
 from homeassistant.core import HomeAssistant
 
-from .common import ComponentFactory
+from .common import ComponentFactory, new_simple_controller_config
 
 
 async def test_switch(
     hass: HomeAssistant, vera_component_factory: ComponentFactory
 ) -> None:
     """Test function."""
-    vera_device = MagicMock(spec=VeraSwitch)  # type: VeraSwitch
+    vera_device = MagicMock(spec=pv.VeraSwitch)  # type: pv.VeraSwitch
     vera_device.device_id = 1
     vera_device.name = "dev1"
-    vera_device.category = CATEGORY_SWITCH
+    vera_device.category = pv.CATEGORY_SWITCH
     vera_device.is_switched_on = MagicMock(return_value=False)
     entity_id = "switch.dev1_1"
 
     component_data = await vera_component_factory.configure_component(
-        hass=hass, devices=(vera_device,),
+        hass=hass,
+        controller_config=new_simple_controller_config(devices=(vera_device,)),
     )
-    controller = component_data.controller
-    update_callback = controller.register.call_args_list[0][0][1]
+    update_callback = component_data.controller_data.update_callback
 
     assert hass.states.get(entity_id).state == "off"