diff --git a/.coveragerc b/.coveragerc
index 0609051f19635be562b6c0d44178dc965a5fec3d..3a7f33f6050b91e8b846be9f0acab7c331e409cf 100644
--- a/.coveragerc
+++ b/.coveragerc
@@ -702,7 +702,11 @@ omit =
     homeassistant/components/ping/device_tracker.py
     homeassistant/components/pioneer/media_player.py
     homeassistant/components/pjlink/media_player.py
-    homeassistant/components/plaato/*
+    homeassistant/components/plaato/__init__.py
+    homeassistant/components/plaato/binary_sensor.py
+    homeassistant/components/plaato/const.py
+    homeassistant/components/plaato/entity.py
+    homeassistant/components/plaato/sensor.py
     homeassistant/components/plex/media_player.py
     homeassistant/components/plum_lightpad/light.py
     homeassistant/components/pocketcasts/sensor.py
diff --git a/homeassistant/components/plaato/__init__.py b/homeassistant/components/plaato/__init__.py
index b365c7e0081bed8994b1d2fbe4a9469276471ba6..2cf97d5fd9a5a5b2122ffeded0a182dfcf79b063 100644
--- a/homeassistant/components/plaato/__init__.py
+++ b/homeassistant/components/plaato/__init__.py
@@ -1,11 +1,34 @@
-"""Support for Plaato Airlock."""
+"""Support for Plaato devices."""
+
+import asyncio
+from datetime import timedelta
 import logging
 
 from aiohttp import web
+from pyplaato.models.airlock import PlaatoAirlock
+from pyplaato.plaato import (
+    ATTR_ABV,
+    ATTR_BATCH_VOLUME,
+    ATTR_BPM,
+    ATTR_BUBBLES,
+    ATTR_CO2_VOLUME,
+    ATTR_DEVICE_ID,
+    ATTR_DEVICE_NAME,
+    ATTR_OG,
+    ATTR_SG,
+    ATTR_TEMP,
+    ATTR_TEMP_UNIT,
+    ATTR_VOLUME_UNIT,
+    Plaato,
+    PlaatoDeviceType,
+)
 import voluptuous as vol
 
 from homeassistant.components.sensor import DOMAIN as SENSOR
+from homeassistant.config_entries import ConfigEntry
 from homeassistant.const import (
+    CONF_SCAN_INTERVAL,
+    CONF_TOKEN,
     CONF_WEBHOOK_ID,
     HTTP_OK,
     TEMP_CELSIUS,
@@ -13,31 +36,33 @@ from homeassistant.const import (
     VOLUME_GALLONS,
     VOLUME_LITERS,
 )
+from homeassistant.core import HomeAssistant, callback
+from homeassistant.exceptions import ConfigEntryNotReady
+from homeassistant.helpers import aiohttp_client
 import homeassistant.helpers.config_validation as cv
 from homeassistant.helpers.dispatcher import async_dispatcher_send
+from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
 
-from .const import DOMAIN
+from .const import (
+    CONF_DEVICE_NAME,
+    CONF_DEVICE_TYPE,
+    CONF_USE_WEBHOOK,
+    COORDINATOR,
+    DEFAULT_SCAN_INTERVAL,
+    DEVICE,
+    DEVICE_ID,
+    DEVICE_NAME,
+    DEVICE_TYPE,
+    DOMAIN,
+    PLATFORMS,
+    SENSOR_DATA,
+    UNDO_UPDATE_LISTENER,
+)
 
 _LOGGER = logging.getLogger(__name__)
 
 DEPENDENCIES = ["webhook"]
 
-PLAATO_DEVICE_SENSORS = "sensors"
-PLAATO_DEVICE_ATTRS = "attrs"
-
-ATTR_DEVICE_ID = "device_id"
-ATTR_DEVICE_NAME = "device_name"
-ATTR_TEMP_UNIT = "temp_unit"
-ATTR_VOLUME_UNIT = "volume_unit"
-ATTR_BPM = "bpm"
-ATTR_TEMP = "temp"
-ATTR_SG = "sg"
-ATTR_OG = "og"
-ATTR_BUBBLES = "bubbles"
-ATTR_ABV = "abv"
-ATTR_CO2_VOLUME = "co2_volume"
-ATTR_BATCH_VOLUME = "batch_volume"
-
 SENSOR_UPDATE = f"{DOMAIN}_sensor_update"
 SENSOR_DATA_KEY = f"{DOMAIN}.{SENSOR}"
 
@@ -60,31 +85,124 @@ WEBHOOK_SCHEMA = vol.Schema(
 )
 
 
-async def async_setup(hass, hass_config):
+async def async_setup(hass: HomeAssistant, config: dict):
     """Set up the Plaato component."""
+    hass.data.setdefault(DOMAIN, {})
     return True
 
 
-async def async_setup_entry(hass, entry):
+async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry):
     """Configure based on config entry."""
-    if DOMAIN not in hass.data:
-        hass.data[DOMAIN] = {}
 
-    webhook_id = entry.data[CONF_WEBHOOK_ID]
-    hass.components.webhook.async_register(DOMAIN, "Plaato", webhook_id, handle_webhook)
+    use_webhook = entry.data[CONF_USE_WEBHOOK]
+
+    if use_webhook:
+        async_setup_webhook(hass, entry)
+    else:
+        await async_setup_coordinator(hass, entry)
 
-    hass.async_create_task(hass.config_entries.async_forward_entry_setup(entry, SENSOR))
+    for platform in PLATFORMS:
+        if entry.options.get(platform, True):
+            hass.async_create_task(
+                hass.config_entries.async_forward_entry_setup(entry, platform)
+            )
 
     return True
 
 
-async def async_unload_entry(hass, entry):
+@callback
+def async_setup_webhook(hass: HomeAssistant, entry: ConfigEntry):
+    """Init webhook based on config entry."""
+    webhook_id = entry.data[CONF_WEBHOOK_ID]
+    device_name = entry.data[CONF_DEVICE_NAME]
+
+    _set_entry_data(entry, hass)
+
+    hass.components.webhook.async_register(
+        DOMAIN, f"{DOMAIN}.{device_name}", webhook_id, handle_webhook
+    )
+
+
+async def async_setup_coordinator(hass: HomeAssistant, entry: ConfigEntry):
+    """Init auth token based on config entry."""
+    auth_token = entry.data[CONF_TOKEN]
+    device_type = entry.data[CONF_DEVICE_TYPE]
+
+    if entry.options.get(CONF_SCAN_INTERVAL):
+        update_interval = timedelta(minutes=entry.options[CONF_SCAN_INTERVAL])
+    else:
+        update_interval = timedelta(minutes=DEFAULT_SCAN_INTERVAL)
+
+    coordinator = PlaatoCoordinator(hass, auth_token, device_type, update_interval)
+    await coordinator.async_refresh()
+    if not coordinator.last_update_success:
+        raise ConfigEntryNotReady
+
+    _set_entry_data(entry, hass, coordinator, auth_token)
+
+    for platform in PLATFORMS:
+        if entry.options.get(platform, True):
+            coordinator.platforms.append(platform)
+
+
+def _set_entry_data(entry, hass, coordinator=None, device_id=None):
+    device = {
+        DEVICE_NAME: entry.data[CONF_DEVICE_NAME],
+        DEVICE_TYPE: entry.data[CONF_DEVICE_TYPE],
+        DEVICE_ID: device_id,
+    }
+
+    hass.data[DOMAIN][entry.entry_id] = {
+        COORDINATOR: coordinator,
+        DEVICE: device,
+        SENSOR_DATA: None,
+        UNDO_UPDATE_LISTENER: entry.add_update_listener(_async_update_listener),
+    }
+
+
+async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry):
     """Unload a config entry."""
-    hass.components.webhook.async_unregister(entry.data[CONF_WEBHOOK_ID])
-    hass.data[SENSOR_DATA_KEY]()
+    use_webhook = entry.data[CONF_USE_WEBHOOK]
+    hass.data[DOMAIN][entry.entry_id][UNDO_UPDATE_LISTENER]()
 
-    await hass.config_entries.async_forward_entry_unload(entry, SENSOR)
-    return True
+    if use_webhook:
+        return await async_unload_webhook(hass, entry)
+
+    return await async_unload_coordinator(hass, entry)
+
+
+async def async_unload_webhook(hass: HomeAssistant, entry: ConfigEntry):
+    """Unload webhook based entry."""
+    if entry.data[CONF_WEBHOOK_ID] is not None:
+        hass.components.webhook.async_unregister(entry.data[CONF_WEBHOOK_ID])
+    return await async_unload_platforms(hass, entry, PLATFORMS)
+
+
+async def async_unload_coordinator(hass: HomeAssistant, entry: ConfigEntry):
+    """Unload auth token based entry."""
+    coordinator = hass.data[DOMAIN][entry.entry_id][COORDINATOR]
+    return await async_unload_platforms(hass, entry, coordinator.platforms)
+
+
+async def async_unload_platforms(hass: HomeAssistant, entry: ConfigEntry, platforms):
+    """Unload platforms."""
+    unloaded = all(
+        await asyncio.gather(
+            *[
+                hass.config_entries.async_forward_entry_unload(entry, platform)
+                for platform in platforms
+            ]
+        )
+    )
+    if unloaded:
+        hass.data[DOMAIN].pop(entry.entry_id)
+
+    return unloaded
+
+
+async def _async_update_listener(hass: HomeAssistant, entry: ConfigEntry):
+    """Handle options update."""
+    await hass.config_entries.async_reload(entry.entry_id)
 
 
 async def handle_webhook(hass, webhook_id, request):
@@ -96,31 +214,9 @@ async def handle_webhook(hass, webhook_id, request):
         return
 
     device_id = _device_id(data)
+    sensor_data = PlaatoAirlock.from_web_hook(data)
 
-    attrs = {
-        ATTR_DEVICE_NAME: data.get(ATTR_DEVICE_NAME),
-        ATTR_DEVICE_ID: data.get(ATTR_DEVICE_ID),
-        ATTR_TEMP_UNIT: data.get(ATTR_TEMP_UNIT),
-        ATTR_VOLUME_UNIT: data.get(ATTR_VOLUME_UNIT),
-    }
-
-    sensors = {
-        ATTR_TEMP: data.get(ATTR_TEMP),
-        ATTR_BPM: data.get(ATTR_BPM),
-        ATTR_SG: data.get(ATTR_SG),
-        ATTR_OG: data.get(ATTR_OG),
-        ATTR_ABV: data.get(ATTR_ABV),
-        ATTR_CO2_VOLUME: data.get(ATTR_CO2_VOLUME),
-        ATTR_BATCH_VOLUME: data.get(ATTR_BATCH_VOLUME),
-        ATTR_BUBBLES: data.get(ATTR_BUBBLES),
-    }
-
-    hass.data[DOMAIN][device_id] = {
-        PLAATO_DEVICE_ATTRS: attrs,
-        PLAATO_DEVICE_SENSORS: sensors,
-    }
-
-    async_dispatcher_send(hass, SENSOR_UPDATE, device_id)
+    async_dispatcher_send(hass, SENSOR_UPDATE, *(device_id, sensor_data))
 
     return web.Response(text=f"Saving status for {device_id}", status=HTTP_OK)
 
@@ -128,3 +224,35 @@ async def handle_webhook(hass, webhook_id, request):
 def _device_id(data):
     """Return name of device sensor."""
     return f"{data.get(ATTR_DEVICE_NAME)}_{data.get(ATTR_DEVICE_ID)}"
+
+
+class PlaatoCoordinator(DataUpdateCoordinator):
+    """Class to manage fetching data from the API."""
+
+    def __init__(
+        self,
+        hass,
+        auth_token,
+        device_type: PlaatoDeviceType,
+        update_interval: timedelta,
+    ):
+        """Initialize."""
+        self.api = Plaato(auth_token=auth_token)
+        self.hass = hass
+        self.device_type = device_type
+        self.platforms = []
+
+        super().__init__(
+            hass,
+            _LOGGER,
+            name=DOMAIN,
+            update_interval=update_interval,
+        )
+
+    async def _async_update_data(self):
+        """Update data via library."""
+        data = await self.api.get_data(
+            session=aiohttp_client.async_get_clientsession(self.hass),
+            device_type=self.device_type,
+        )
+        return data
diff --git a/homeassistant/components/plaato/binary_sensor.py b/homeassistant/components/plaato/binary_sensor.py
new file mode 100644
index 0000000000000000000000000000000000000000..0ee61b7668bd0a0ebcd8bc042c1c6c637d7aefba
--- /dev/null
+++ b/homeassistant/components/plaato/binary_sensor.py
@@ -0,0 +1,56 @@
+"""Support for Plaato Airlock sensors."""
+
+import logging
+
+from pyplaato.plaato import PlaatoKeg
+
+from homeassistant.components.binary_sensor import (
+    DEVICE_CLASS_OPENING,
+    DEVICE_CLASS_PROBLEM,
+    BinarySensorEntity,
+)
+
+from .const import CONF_USE_WEBHOOK, COORDINATOR, DOMAIN
+from .entity import PlaatoEntity
+
+_LOGGER = logging.getLogger(__name__)
+
+
+async def async_setup_entry(hass, config_entry, async_add_entities):
+    """Set up Plaato from a config entry."""
+
+    if config_entry.data[CONF_USE_WEBHOOK]:
+        return False
+
+    coordinator = hass.data[DOMAIN][config_entry.entry_id][COORDINATOR]
+    async_add_entities(
+        PlaatoBinarySensor(
+            hass.data[DOMAIN][config_entry.entry_id],
+            sensor_type,
+            coordinator,
+        )
+        for sensor_type in coordinator.data.binary_sensors.keys()
+    )
+
+    return True
+
+
+class PlaatoBinarySensor(PlaatoEntity, BinarySensorEntity):
+    """Representation of a Binary Sensor."""
+
+    @property
+    def is_on(self):
+        """Return true if the binary sensor is on."""
+        if self._coordinator is not None:
+            return self._coordinator.data.binary_sensors.get(self._sensor_type)
+        return False
+
+    @property
+    def device_class(self):
+        """Return the class of this device, from component DEVICE_CLASSES."""
+        if self._coordinator is None:
+            return None
+        if self._sensor_type is PlaatoKeg.Pins.LEAK_DETECTION:
+            return DEVICE_CLASS_PROBLEM
+        if self._sensor_type is PlaatoKeg.Pins.POURING:
+            return DEVICE_CLASS_OPENING
diff --git a/homeassistant/components/plaato/config_flow.py b/homeassistant/components/plaato/config_flow.py
index 3c616c822fb984cfd4e79ed2f3347c6a6be1844d..290776f47c116438a7ddf8dd8262725d7a39e8fb 100644
--- a/homeassistant/components/plaato/config_flow.py
+++ b/homeassistant/components/plaato/config_flow.py
@@ -1,10 +1,223 @@
-"""Config flow for GPSLogger."""
-from homeassistant.helpers import config_entry_flow
+"""Config flow for Plaato."""
+import logging
 
-from .const import DOMAIN
+from pyplaato.plaato import PlaatoDeviceType
+import voluptuous as vol
 
-config_entry_flow.register_webhook_flow(
-    DOMAIN,
-    "Webhook",
-    {"docs_url": "https://www.home-assistant.io/integrations/plaato/"},
+from homeassistant import config_entries
+from homeassistant.config_entries import ConfigEntry
+from homeassistant.const import CONF_SCAN_INTERVAL, CONF_TOKEN, CONF_WEBHOOK_ID
+from homeassistant.core import callback
+import homeassistant.helpers.config_validation as cv
+
+from .const import (
+    CONF_CLOUDHOOK,
+    CONF_DEVICE_NAME,
+    CONF_DEVICE_TYPE,
+    CONF_USE_WEBHOOK,
+    DEFAULT_SCAN_INTERVAL,
+    DOCS_URL,
+    PLACEHOLDER_DEVICE_NAME,
+    PLACEHOLDER_DEVICE_TYPE,
+    PLACEHOLDER_DOCS_URL,
+    PLACEHOLDER_WEBHOOK_URL,
 )
+from .const import DOMAIN  # pylint:disable=unused-import
+
+_LOGGER = logging.getLogger(__package__)
+
+
+class PlaatoConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
+    """Handles a Plaato config flow."""
+
+    VERSION = 2
+    CONNECTION_CLASS = config_entries.CONN_CLASS_LOCAL_POLL
+
+    def __init__(self):
+        """Initialize."""
+        self._init_info = {}
+
+    async def async_step_user(self, user_input=None):
+        """Handle user step."""
+
+        if user_input is not None:
+            self._init_info[CONF_DEVICE_TYPE] = PlaatoDeviceType(
+                user_input[CONF_DEVICE_TYPE]
+            )
+            self._init_info[CONF_DEVICE_NAME] = user_input[CONF_DEVICE_NAME]
+
+            return await self.async_step_api_method()
+
+        return self.async_show_form(
+            step_id="user",
+            data_schema=vol.Schema(
+                {
+                    vol.Required(
+                        CONF_DEVICE_NAME,
+                        default=self._init_info.get(CONF_DEVICE_NAME, None),
+                    ): str,
+                    vol.Required(
+                        CONF_DEVICE_TYPE,
+                        default=self._init_info.get(CONF_DEVICE_TYPE, None),
+                    ): vol.In(list(PlaatoDeviceType)),
+                }
+            ),
+        )
+
+    async def async_step_api_method(self, user_input=None):
+        """Handle device type step."""
+
+        device_type = self._init_info[CONF_DEVICE_TYPE]
+
+        if user_input is not None:
+            token = user_input.get(CONF_TOKEN, None)
+            use_webhook = user_input.get(CONF_USE_WEBHOOK, False)
+
+            if not token and not use_webhook:
+                errors = {"base": PlaatoConfigFlow._get_error(device_type)}
+                return await self._show_api_method_form(device_type, errors)
+
+            self._init_info[CONF_USE_WEBHOOK] = use_webhook
+            self._init_info[CONF_TOKEN] = token
+            return await self.async_step_webhook()
+
+        return await self._show_api_method_form(device_type)
+
+    async def async_step_webhook(self, user_input=None):
+        """Validate config step."""
+
+        use_webhook = self._init_info[CONF_USE_WEBHOOK]
+
+        if use_webhook and user_input is None:
+            webhook_id, webhook_url, cloudhook = await self._get_webhook_id()
+            self._init_info[CONF_WEBHOOK_ID] = webhook_id
+            self._init_info[CONF_CLOUDHOOK] = cloudhook
+
+            return self.async_show_form(
+                step_id="webhook",
+                description_placeholders={
+                    PLACEHOLDER_WEBHOOK_URL: webhook_url,
+                    PLACEHOLDER_DOCS_URL: DOCS_URL,
+                },
+            )
+
+        return await self._async_create_entry()
+
+    async def _async_create_entry(self):
+        """Create the entry step."""
+
+        webhook_id = self._init_info.get(CONF_WEBHOOK_ID, None)
+        auth_token = self._init_info[CONF_TOKEN]
+        device_name = self._init_info[CONF_DEVICE_NAME]
+        device_type = self._init_info[CONF_DEVICE_TYPE]
+
+        unique_id = auth_token if auth_token else webhook_id
+
+        await self.async_set_unique_id(unique_id)
+        self._abort_if_unique_id_configured()
+
+        return self.async_create_entry(
+            title=device_type.name,
+            data=self._init_info,
+            description_placeholders={
+                PLACEHOLDER_DEVICE_TYPE: device_type.name,
+                PLACEHOLDER_DEVICE_NAME: device_name,
+            },
+        )
+
+    async def _show_api_method_form(
+        self, device_type: PlaatoDeviceType, errors: dict = None
+    ):
+        data_scheme = vol.Schema({vol.Optional(CONF_TOKEN, default=""): str})
+
+        if device_type == PlaatoDeviceType.Airlock:
+            data_scheme = data_scheme.extend(
+                {vol.Optional(CONF_USE_WEBHOOK, default=False): bool}
+            )
+
+        return self.async_show_form(
+            step_id="api_method",
+            data_schema=data_scheme,
+            errors=errors,
+            description_placeholders={PLACEHOLDER_DEVICE_TYPE: device_type.name},
+        )
+
+    async def _get_webhook_id(self):
+        """Generate webhook ID."""
+        webhook_id = self.hass.components.webhook.async_generate_id()
+        if self.hass.components.cloud.async_active_subscription():
+            webhook_url = await self.hass.components.cloud.async_create_cloudhook(
+                webhook_id
+            )
+            cloudhook = True
+        else:
+            webhook_url = self.hass.components.webhook.async_generate_url(webhook_id)
+            cloudhook = False
+
+        return webhook_id, webhook_url, cloudhook
+
+    @staticmethod
+    def _get_error(device_type: PlaatoDeviceType):
+        if device_type == PlaatoDeviceType.Airlock:
+            return "no_api_method"
+        return "no_auth_token"
+
+    @staticmethod
+    @callback
+    def async_get_options_flow(config_entry):
+        """Get the options flow for this handler."""
+        return PlaatoOptionsFlowHandler(config_entry)
+
+
+class PlaatoOptionsFlowHandler(config_entries.OptionsFlow):
+    """Handle Plaato options."""
+
+    def __init__(self, config_entry: ConfigEntry):
+        """Initialize domain options flow."""
+        super().__init__()
+
+        self._config_entry = config_entry
+
+    async def async_step_init(self, user_input=None):
+        """Manage the options."""
+        use_webhook = self._config_entry.data.get(CONF_USE_WEBHOOK, False)
+        if use_webhook:
+            return await self.async_step_webhook()
+
+        return await self.async_step_user()
+
+    async def async_step_user(self, user_input=None):
+        """Manage the options."""
+        if user_input is not None:
+            return self.async_create_entry(title="", data=user_input)
+
+        return self.async_show_form(
+            step_id="user",
+            data_schema=vol.Schema(
+                {
+                    vol.Optional(
+                        CONF_SCAN_INTERVAL,
+                        default=self._config_entry.options.get(
+                            CONF_SCAN_INTERVAL, DEFAULT_SCAN_INTERVAL
+                        ),
+                    ): cv.positive_int
+                }
+            ),
+        )
+
+    async def async_step_webhook(self, user_input=None):
+        """Manage the options for webhook device."""
+        if user_input is not None:
+            return self.async_create_entry(title="", data=user_input)
+
+        webhook_id = self._config_entry.data.get(CONF_WEBHOOK_ID, None)
+        webhook_url = (
+            ""
+            if webhook_id is None
+            else self.hass.components.webhook.async_generate_url(webhook_id)
+        )
+
+        return self.async_show_form(
+            step_id="webhook",
+            description_placeholders={PLACEHOLDER_WEBHOOK_URL: webhook_url},
+        )
diff --git a/homeassistant/components/plaato/const.py b/homeassistant/components/plaato/const.py
index cbe8fcd2b6dc43b6f63a9b8035ab292e24e91d01..f50eaaac0ed8863128dd29220eeb4277e430f2ca 100644
--- a/homeassistant/components/plaato/const.py
+++ b/homeassistant/components/plaato/const.py
@@ -1,3 +1,27 @@
-"""Const for GPSLogger."""
+"""Const for Plaato."""
+from datetime import timedelta
 
 DOMAIN = "plaato"
+PLAATO_DEVICE_SENSORS = "sensors"
+PLAATO_DEVICE_ATTRS = "attrs"
+SENSOR_SIGNAL = f"{DOMAIN}_%s_%s"
+
+CONF_USE_WEBHOOK = "use_webhook"
+CONF_DEVICE_TYPE = "device_type"
+CONF_DEVICE_NAME = "device_name"
+CONF_CLOUDHOOK = "cloudhook"
+PLACEHOLDER_WEBHOOK_URL = "webhook_url"
+PLACEHOLDER_DOCS_URL = "docs_url"
+PLACEHOLDER_DEVICE_TYPE = "device_type"
+PLACEHOLDER_DEVICE_NAME = "device_name"
+DOCS_URL = "https://www.home-assistant.io/integrations/plaato/"
+PLATFORMS = ["sensor", "binary_sensor"]
+SENSOR_DATA = "sensor_data"
+COORDINATOR = "coordinator"
+DEVICE = "device"
+DEVICE_NAME = "device_name"
+DEVICE_TYPE = "device_type"
+DEVICE_ID = "device_id"
+UNDO_UPDATE_LISTENER = "undo_update_listener"
+DEFAULT_SCAN_INTERVAL = 5
+MIN_UPDATE_INTERVAL = timedelta(minutes=1)
diff --git a/homeassistant/components/plaato/entity.py b/homeassistant/components/plaato/entity.py
new file mode 100644
index 0000000000000000000000000000000000000000..6f72c3419a4626d92a770c997c3953bcde8de8c4
--- /dev/null
+++ b/homeassistant/components/plaato/entity.py
@@ -0,0 +1,103 @@
+"""PlaatoEntity class."""
+from pyplaato.models.device import PlaatoDevice
+
+from homeassistant.helpers import entity
+
+from .const import (
+    DEVICE,
+    DEVICE_ID,
+    DEVICE_NAME,
+    DEVICE_TYPE,
+    DOMAIN,
+    SENSOR_DATA,
+    SENSOR_SIGNAL,
+)
+
+
+class PlaatoEntity(entity.Entity):
+    """Representation of a Plaato Entity."""
+
+    def __init__(self, data, sensor_type, coordinator=None):
+        """Initialize the sensor."""
+        self._coordinator = coordinator
+        self._entry_data = data
+        self._sensor_type = sensor_type
+        self._device_id = data[DEVICE][DEVICE_ID]
+        self._device_type = data[DEVICE][DEVICE_TYPE]
+        self._device_name = data[DEVICE][DEVICE_NAME]
+        self._state = 0
+
+    @property
+    def _attributes(self) -> dict:
+        return PlaatoEntity._to_snake_case(self._sensor_data.attributes)
+
+    @property
+    def _sensor_name(self) -> str:
+        return self._sensor_data.get_sensor_name(self._sensor_type)
+
+    @property
+    def _sensor_data(self) -> PlaatoDevice:
+        if self._coordinator:
+            return self._coordinator.data
+        return self._entry_data[SENSOR_DATA]
+
+    @property
+    def name(self):
+        """Return the name of the sensor."""
+        return f"{DOMAIN} {self._device_type} {self._device_name} {self._sensor_name}".title()
+
+    @property
+    def unique_id(self):
+        """Return the unique ID of this sensor."""
+        return f"{self._device_id}_{self._sensor_type}"
+
+    @property
+    def device_info(self):
+        """Get device info."""
+        device_info = {
+            "identifiers": {(DOMAIN, self._device_id)},
+            "name": self._device_name,
+            "manufacturer": "Plaato",
+            "model": self._device_type,
+        }
+
+        if self._sensor_data.firmware_version != "":
+            device_info["sw_version"] = self._sensor_data.firmware_version
+
+        return device_info
+
+    @property
+    def device_state_attributes(self):
+        """Return the state attributes of the monitored installation."""
+        if self._attributes is not None:
+            return self._attributes
+
+    @property
+    def available(self):
+        """Return if sensor is available."""
+        if self._coordinator is not None:
+            return self._coordinator.last_update_success
+        return True
+
+    @property
+    def should_poll(self):
+        """Return the polling state."""
+        return False
+
+    async def async_added_to_hass(self):
+        """When entity is added to hass."""
+        if self._coordinator is not None:
+            self.async_on_remove(
+                self._coordinator.async_add_listener(self.async_write_ha_state)
+            )
+        else:
+            self.async_on_remove(
+                self.hass.helpers.dispatcher.async_dispatcher_connect(
+                    SENSOR_SIGNAL % (self._device_id, self._sensor_type),
+                    self.async_write_ha_state,
+                )
+            )
+
+    @staticmethod
+    def _to_snake_case(dictionary: dict):
+        return {k.lower().replace(" ", "_"): v for k, v in dictionary.items()}
diff --git a/homeassistant/components/plaato/manifest.json b/homeassistant/components/plaato/manifest.json
index 29e104b13ed3942935a336cc6c72068a76f3356c..e3291e5a229d243613be51174a1151229ed697b1 100644
--- a/homeassistant/components/plaato/manifest.json
+++ b/homeassistant/components/plaato/manifest.json
@@ -1,8 +1,10 @@
 {
   "domain": "plaato",
-  "name": "Plaato Airlock",
+  "name": "Plaato",
   "config_flow": true,
   "documentation": "https://www.home-assistant.io/integrations/plaato",
   "dependencies": ["webhook"],
-  "codeowners": ["@JohNan"]
+  "after_dependencies": ["cloud"],
+  "codeowners": ["@JohNan"],
+  "requirements": ["pyplaato==0.0.15"]
 }
diff --git a/homeassistant/components/plaato/sensor.py b/homeassistant/components/plaato/sensor.py
index 3f8034698fd8439f9e4ab34b540d27b3fd780e70..3f5e467f504a2d52c6e70b89f5dd5d698fe8a3b0 100644
--- a/homeassistant/components/plaato/sensor.py
+++ b/homeassistant/components/plaato/sensor.py
@@ -1,28 +1,29 @@
 """Support for Plaato Airlock sensors."""
 
 import logging
+from typing import Optional
 
-from homeassistant.const import PERCENTAGE
+from pyplaato.models.device import PlaatoDevice
+from pyplaato.plaato import PlaatoKeg
+
+from homeassistant.components.sensor import DEVICE_CLASS_TEMPERATURE
 from homeassistant.helpers.dispatcher import (
     async_dispatcher_connect,
     async_dispatcher_send,
 )
-from homeassistant.helpers.entity import Entity
-
-from . import (
-    ATTR_ABV,
-    ATTR_BATCH_VOLUME,
-    ATTR_BPM,
-    ATTR_CO2_VOLUME,
-    ATTR_TEMP,
-    ATTR_TEMP_UNIT,
-    ATTR_VOLUME_UNIT,
-    DOMAIN as PLAATO_DOMAIN,
-    PLAATO_DEVICE_ATTRS,
-    PLAATO_DEVICE_SENSORS,
-    SENSOR_DATA_KEY,
-    SENSOR_UPDATE,
+
+from . import ATTR_TEMP, SENSOR_UPDATE
+from ...core import callback
+from .const import (
+    CONF_USE_WEBHOOK,
+    COORDINATOR,
+    DEVICE,
+    DEVICE_ID,
+    DOMAIN,
+    SENSOR_DATA,
+    SENSOR_SIGNAL,
 )
+from .entity import PlaatoEntity
 
 _LOGGER = logging.getLogger(__name__)
 
@@ -31,134 +32,58 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info=
     """Set up the Plaato sensor."""
 
 
-async def async_setup_entry(hass, config_entry, async_add_entities):
+async def async_setup_entry(hass, entry, async_add_entities):
     """Set up Plaato from a config entry."""
-    devices = {}
-
-    def get_device(device_id):
-        """Get a device."""
-        return hass.data[PLAATO_DOMAIN].get(device_id, False)
-
-    def get_device_sensors(device_id):
-        """Get device sensors."""
-        return hass.data[PLAATO_DOMAIN].get(device_id).get(PLAATO_DEVICE_SENSORS)
+    entry_data = hass.data[DOMAIN][entry.entry_id]
 
-    async def _update_sensor(device_id):
+    @callback
+    async def _async_update_from_webhook(device_id, sensor_data: PlaatoDevice):
         """Update/Create the sensors."""
-        if device_id not in devices and get_device(device_id):
-            entities = []
-            sensors = get_device_sensors(device_id)
-
-            for sensor_type in sensors:
-                entities.append(PlaatoSensor(device_id, sensor_type))
-
-            devices[device_id] = entities
-
-            async_add_entities(entities, True)
+        entry_data[SENSOR_DATA] = sensor_data
+
+        if device_id != entry_data[DEVICE][DEVICE_ID]:
+            entry_data[DEVICE][DEVICE_ID] = device_id
+            async_add_entities(
+                [
+                    PlaatoSensor(entry_data, sensor_type)
+                    for sensor_type in sensor_data.sensors
+                ]
+            )
         else:
-            for entity in devices[device_id]:
-                async_dispatcher_send(hass, f"{PLAATO_DOMAIN}_{entity.unique_id}")
-
-    hass.data[SENSOR_DATA_KEY] = async_dispatcher_connect(
-        hass, SENSOR_UPDATE, _update_sensor
-    )
+            for sensor_type in sensor_data.sensors:
+                async_dispatcher_send(hass, SENSOR_SIGNAL % (device_id, sensor_type))
+
+    if entry.data[CONF_USE_WEBHOOK]:
+        async_dispatcher_connect(hass, SENSOR_UPDATE, _async_update_from_webhook)
+    else:
+        coordinator = entry_data[COORDINATOR]
+        async_add_entities(
+            PlaatoSensor(entry_data, sensor_type, coordinator)
+            for sensor_type in coordinator.data.sensors.keys()
+        )
 
     return True
 
 
-class PlaatoSensor(Entity):
-    """Representation of a Sensor."""
-
-    def __init__(self, device_id, sensor_type):
-        """Initialize the sensor."""
-        self._device_id = device_id
-        self._type = sensor_type
-        self._state = 0
-        self._name = f"{device_id} {sensor_type}"
-        self._attributes = None
-
-    @property
-    def name(self):
-        """Return the name of the sensor."""
-        return f"{PLAATO_DOMAIN} {self._name}"
+class PlaatoSensor(PlaatoEntity):
+    """Representation of a Plaato Sensor."""
 
     @property
-    def unique_id(self):
-        """Return the unique ID of this sensor."""
-        return f"{self._device_id}_{self._type}"
-
-    @property
-    def device_info(self):
-        """Get device info."""
-        return {
-            "identifiers": {(PLAATO_DOMAIN, self._device_id)},
-            "name": self._device_id,
-            "manufacturer": "Plaato",
-            "model": "Airlock",
-        }
-
-    def get_sensors(self):
-        """Get device sensors."""
-        return (
-            self.hass.data[PLAATO_DOMAIN]
-            .get(self._device_id)
-            .get(PLAATO_DEVICE_SENSORS, False)
-        )
-
-    def get_sensors_unit_of_measurement(self, sensor_type):
-        """Get unit of measurement for sensor of type."""
-        return (
-            self.hass.data[PLAATO_DOMAIN]
-            .get(self._device_id)
-            .get(PLAATO_DEVICE_ATTRS, [])
-            .get(sensor_type, "")
-        )
+    def device_class(self) -> Optional[str]:
+        """Return the class of this device, from component DEVICE_CLASSES."""
+        if self._coordinator is not None:
+            if self._sensor_type == PlaatoKeg.Pins.TEMPERATURE:
+                return DEVICE_CLASS_TEMPERATURE
+        if self._sensor_type == ATTR_TEMP:
+            return DEVICE_CLASS_TEMPERATURE
+        return None
 
     @property
     def state(self):
         """Return the state of the sensor."""
-        sensors = self.get_sensors()
-        if sensors is False:
-            _LOGGER.debug("Device with name %s has no sensors", self.name)
-            return 0
-
-        if self._type == ATTR_ABV:
-            return round(sensors.get(self._type), 2)
-        if self._type == ATTR_TEMP:
-            return round(sensors.get(self._type), 1)
-        if self._type == ATTR_CO2_VOLUME:
-            return round(sensors.get(self._type), 2)
-        return sensors.get(self._type)
-
-    @property
-    def device_state_attributes(self):
-        """Return the state attributes of the monitored installation."""
-        if self._attributes is not None:
-            return self._attributes
+        return self._sensor_data.sensors.get(self._sensor_type)
 
     @property
     def unit_of_measurement(self):
         """Return the unit of measurement."""
-        if self._type == ATTR_TEMP:
-            return self.get_sensors_unit_of_measurement(ATTR_TEMP_UNIT)
-        if self._type == ATTR_BATCH_VOLUME or self._type == ATTR_CO2_VOLUME:
-            return self.get_sensors_unit_of_measurement(ATTR_VOLUME_UNIT)
-        if self._type == ATTR_BPM:
-            return "bpm"
-        if self._type == ATTR_ABV:
-            return PERCENTAGE
-
-        return ""
-
-    @property
-    def should_poll(self):
-        """Return the polling state."""
-        return False
-
-    async def async_added_to_hass(self):
-        """Register callbacks."""
-        self.async_on_remove(
-            self.hass.helpers.dispatcher.async_dispatcher_connect(
-                f"{PLAATO_DOMAIN}_{self.unique_id}", self.async_write_ha_state
-            )
-        )
+        return self._sensor_data.get_unit_of_measurement(self._sensor_type)
diff --git a/homeassistant/components/plaato/strings.json b/homeassistant/components/plaato/strings.json
index 087cee136833f2eeb3b1229fd9306797494559b1..852ecc88ddec8b16d67d7cc7a98d15c78ff2375a 100644
--- a/homeassistant/components/plaato/strings.json
+++ b/homeassistant/components/plaato/strings.json
@@ -2,16 +2,53 @@
   "config": {
     "step": {
       "user": {
-        "title": "Set up the Plaato Webhook",
-        "description": "[%key:common::config_flow::description::confirm_setup%]"
+        "title": "Set up the Plaato devices",
+        "description": "[%key:common::config_flow::description::confirm_setup%]",
+        "data": {
+          "device_name": "Name your device",
+          "device_type": "Type of Plaato device"
+        }
+      },
+      "api_method": {
+        "title": "Select API method",
+        "description": "To be able to query the API an `auth_token` is required which can be obtained by following [these](https://plaato.zendesk.com/hc/en-us/articles/360003234717-Auth-token) instructions\n\n Selected device: **{device_type}** \n\nIf you rather use the built in webhook method (Airlock only) please check the box below and leave Auth Token blank",
+        "data": {
+          "use_webhook": "Use webhook",
+          "token": "Paste Auth Token here"
+        }
+      },
+      "webhook": {
+        "title": "Webhook to use",
+        "description": "To send events to Home Assistant, you will need to setup the webhook feature in Plaato Airlock.\n\nFill in the following info:\n\n- URL: `{webhook_url}`\n- Method: POST\n\nSee [the documentation]({docs_url}) for further details."
       }
     },
+    "error": {
+      "invalid_webhook_device": "You have selected a device that doesn't not support sending data to a webhook. It is only available for the Airlock",
+      "no_auth_token": "You need to add an auth token",
+      "no_api_method": "You need to add an auth token or select webhook"
+    },
     "abort": {
       "single_instance_allowed": "[%key:common::config_flow::abort::single_instance_allowed%]",
-      "webhook_not_internet_accessible": "[%key:common::config_flow::abort::webhook_not_internet_accessible%]"
+      "webhook_not_internet_accessible": "[%key:common::config_flow::abort::webhook_not_internet_accessible%]",
+      "already_configured": "[%key:common::config_flow::abort::already_configured_account%]"
     },
     "create_entry": {
-      "default": "To send events to Home Assistant, you will need to setup the webhook feature in Plaato Airlock.\n\nFill in the following info:\n\n- URL: `{webhook_url}`\n- Method: POST\n\nSee [the documentation]({docs_url}) for further details."
+      "default": "Your Plaato {device_type} with name **{device_name}** was successfully setup!"
+    }
+  },
+  "options": {
+    "step": {
+      "webhook": {
+        "title": "Options for Plaato Airlock",
+        "description": "Webhook info:\n\n- URL: `{webhook_url}`\n- Method: POST\n\n"
+      },
+      "user": {
+        "title": "Options for Plaato",
+        "description": "Set the update interval (minutes)",
+        "data": {
+          "update_interval": "Update interval (minutes)"
+        }
+      }
     }
   }
 }
diff --git a/homeassistant/components/plaato/translations/en.json b/homeassistant/components/plaato/translations/en.json
index 6f25c15583c2b87186cbdae76260d7a1f719b577..64d41d0091ecd4adf4dc3a430165e960bd4f01a2 100644
--- a/homeassistant/components/plaato/translations/en.json
+++ b/homeassistant/components/plaato/translations/en.json
@@ -1,16 +1,53 @@
 {
     "config": {
         "abort": {
+            "already_configured": "Account is already configured",
             "single_instance_allowed": "Already configured. Only a single configuration possible.",
             "webhook_not_internet_accessible": "Your Home Assistant instance needs to be accessible from the internet to receive webhook messages."
         },
         "create_entry": {
-            "default": "To send events to Home Assistant, you will need to setup the webhook feature in Plaato Airlock.\n\nFill in the following info:\n\n- URL: `{webhook_url}`\n- Method: POST\n\nSee [the documentation]({docs_url}) for further details."
+            "default": "Your Plaato {device_type} with name **{device_name}** was successfully setup!"
+        },
+        "error": {
+            "invalid_webhook_device": "You have selected a device that doesn't not support sending data to a webhook. It is only available for the Airlock",
+            "no_api_method": "You need to add an auth token or select webhook",
+            "no_auth_token": "You need to add an auth token"
         },
         "step": {
+            "api_method": {
+                "data": {
+                    "token": "Paste Auth Token here",
+                    "use_webhook": "Use webhook"
+                },
+                "description": "To be able to query the API an `auth_token` is required which can be obtained by following [these](https://plaato.zendesk.com/hc/en-us/articles/360003234717-Auth-token) instructions\n\n Selected device: **{device_type}** \n\nIf you rather use the built in webhook method (Airlock only) please check the box below and leave Auth Token blank",
+                "title": "Select API method"
+            },
             "user": {
+                "data": {
+                    "device_name": "Name your device",
+                    "device_type": "Type of Plaato device"
+                },
                 "description": "Do you want to start set up?",
-                "title": "Set up the Plaato Webhook"
+                "title": "Set up the Plaato devices"
+            },
+            "webhook": {
+                "description": "To send events to Home Assistant, you will need to setup the webhook feature in Plaato Airlock.\n\nFill in the following info:\n\n- URL: `{webhook_url}`\n- Method: POST\n\nSee [the documentation]({docs_url}) for further details.",
+                "title": "Webhook to use"
+            }
+        }
+    },
+    "options": {
+        "step": {
+            "user": {
+                "data": {
+                    "update_interval": "Update interval (minutes)"
+                },
+                "description": "Set the update interval (minutes)",
+                "title": "Options for Plaato"
+            },
+            "webhook": {
+                "description": "Webhook info:\n\n- URL: `{webhook_url}`\n- Method: POST\n\n",
+                "title": "Options for Plaato Airlock"
             }
         }
     }
diff --git a/requirements_all.txt b/requirements_all.txt
index 804b04952978555532d63b1482867505023886d5..c192883c95fccaa62bfda6f9f1baac35d7de5ed6 100644
--- a/requirements_all.txt
+++ b/requirements_all.txt
@@ -1615,6 +1615,9 @@ pypck==0.7.9
 # homeassistant.components.pjlink
 pypjlink2==1.2.1
 
+# homeassistant.components.plaato
+pyplaato==0.0.15
+
 # homeassistant.components.point
 pypoint==2.0.0
 
diff --git a/requirements_test_all.txt b/requirements_test_all.txt
index f855ab4bacc4f9e3ad62e16968057ac9763e22e7..5a30ae13e8c9929c2faefb6ce5018786bbbaed5d 100644
--- a/requirements_test_all.txt
+++ b/requirements_test_all.txt
@@ -842,6 +842,9 @@ pyowm==3.1.1
 # homeassistant.components.onewire
 pyownet==0.10.0.post1
 
+# homeassistant.components.plaato
+pyplaato==0.0.15
+
 # homeassistant.components.point
 pypoint==2.0.0
 
diff --git a/tests/components/plaato/__init__.py b/tests/components/plaato/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..dac4d341790c626f1a1e2f90e73f6e1c7b41966b
--- /dev/null
+++ b/tests/components/plaato/__init__.py
@@ -0,0 +1 @@
+"""Tests for the Plaato integration."""
diff --git a/tests/components/plaato/test_config_flow.py b/tests/components/plaato/test_config_flow.py
new file mode 100644
index 0000000000000000000000000000000000000000..10562b6aa60b333109862ebed8ce5de6771621a3
--- /dev/null
+++ b/tests/components/plaato/test_config_flow.py
@@ -0,0 +1,286 @@
+"""Test the Plaato config flow."""
+from unittest.mock import patch
+
+from pyplaato.models.device import PlaatoDeviceType
+import pytest
+
+from homeassistant import config_entries, data_entry_flow, setup
+from homeassistant.components.plaato.const import (
+    CONF_DEVICE_NAME,
+    CONF_DEVICE_TYPE,
+    CONF_USE_WEBHOOK,
+    DOMAIN,
+)
+from homeassistant.const import CONF_SCAN_INTERVAL, CONF_TOKEN, CONF_WEBHOOK_ID
+from homeassistant.data_entry_flow import RESULT_TYPE_CREATE_ENTRY, RESULT_TYPE_FORM
+
+from tests.common import MockConfigEntry
+
+BASE_URL = "http://example.com"
+WEBHOOK_ID = "webhook_id"
+UNIQUE_ID = "plaato_unique_id"
+
+
+@pytest.fixture(name="webhook_id")
+def mock_webhook_id():
+    """Mock webhook_id."""
+    with patch(
+        "homeassistant.components.webhook.async_generate_id", return_value=WEBHOOK_ID
+    ), patch(
+        "homeassistant.components.webhook.async_generate_url", return_value="hook_id"
+    ):
+        yield
+
+
+async def test_show_config_form(hass):
+    """Test show configuration form."""
+    await setup.async_setup_component(hass, "persistent_notification", {})
+    result = await hass.config_entries.flow.async_init(
+        DOMAIN, context={"source": config_entries.SOURCE_USER}
+    )
+
+    assert result["type"] == "form"
+    assert result["step_id"] == "user"
+
+
+async def test_show_config_form_device_type_airlock(hass):
+    """Test show configuration form."""
+    result = await hass.config_entries.flow.async_init(
+        DOMAIN,
+        context={"source": config_entries.SOURCE_USER},
+        data={
+            CONF_DEVICE_TYPE: PlaatoDeviceType.Airlock,
+            CONF_DEVICE_NAME: "device_name",
+        },
+    )
+
+    assert result["type"] == RESULT_TYPE_FORM
+    assert result["step_id"] == "api_method"
+    assert result["data_schema"].schema.get(CONF_TOKEN) == str
+    assert result["data_schema"].schema.get(CONF_USE_WEBHOOK) == bool
+
+
+async def test_show_config_form_device_type_keg(hass):
+    """Test show configuration form."""
+    result = await hass.config_entries.flow.async_init(
+        DOMAIN,
+        context={"source": config_entries.SOURCE_USER},
+        data={CONF_DEVICE_TYPE: PlaatoDeviceType.Keg, CONF_DEVICE_NAME: "device_name"},
+    )
+
+    assert result["type"] == RESULT_TYPE_FORM
+    assert result["step_id"] == "api_method"
+    assert result["data_schema"].schema.get(CONF_TOKEN) == str
+    assert result["data_schema"].schema.get(CONF_USE_WEBHOOK) is None
+
+
+async def test_show_config_form_validate_webhook(hass, webhook_id):
+    """Test show configuration form."""
+
+    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"] == "user"
+
+    result = await hass.config_entries.flow.async_configure(
+        result["flow_id"],
+        user_input={
+            CONF_DEVICE_TYPE: PlaatoDeviceType.Airlock,
+            CONF_DEVICE_NAME: "device_name",
+        },
+    )
+
+    assert result["type"] == RESULT_TYPE_FORM
+    assert result["step_id"] == "api_method"
+
+    async def return_async_value(val):
+        return val
+
+    hass.config.components.add("cloud")
+    with patch(
+        "homeassistant.components.cloud.async_active_subscription", return_value=True
+    ), patch(
+        "homeassistant.components.cloud.async_create_cloudhook",
+        return_value=return_async_value("https://hooks.nabu.casa/ABCD"),
+    ):
+        result = await hass.config_entries.flow.async_configure(
+            result["flow_id"],
+            user_input={
+                CONF_TOKEN: "",
+                CONF_USE_WEBHOOK: True,
+            },
+        )
+
+    assert result["type"] == RESULT_TYPE_FORM
+    assert result["step_id"] == "webhook"
+
+
+async def test_show_config_form_validate_token(hass):
+    """Test show configuration form."""
+
+    result = await hass.config_entries.flow.async_init(
+        DOMAIN, context={"source": config_entries.SOURCE_USER}
+    )
+
+    result = await hass.config_entries.flow.async_configure(
+        result["flow_id"],
+        user_input={
+            CONF_DEVICE_TYPE: PlaatoDeviceType.Keg,
+            CONF_DEVICE_NAME: "device_name",
+        },
+    )
+
+    assert result["type"] == RESULT_TYPE_FORM
+    assert result["step_id"] == "api_method"
+
+    with patch("homeassistant.components.plaato.async_setup_entry", return_value=True):
+        result = await hass.config_entries.flow.async_configure(
+            result["flow_id"], user_input={CONF_TOKEN: "valid_token"}
+        )
+
+    assert result["type"] == RESULT_TYPE_CREATE_ENTRY
+    assert result["title"] == PlaatoDeviceType.Keg.name
+    assert result["data"] == {
+        CONF_USE_WEBHOOK: False,
+        CONF_TOKEN: "valid_token",
+        CONF_DEVICE_TYPE: PlaatoDeviceType.Keg,
+        CONF_DEVICE_NAME: "device_name",
+    }
+
+
+async def test_show_config_form_no_cloud_webhook(hass, webhook_id):
+    """Test show configuration form."""
+
+    result = await hass.config_entries.flow.async_init(
+        DOMAIN, context={"source": config_entries.SOURCE_USER}
+    )
+
+    result = await hass.config_entries.flow.async_configure(
+        result["flow_id"],
+        user_input={
+            CONF_DEVICE_TYPE: PlaatoDeviceType.Airlock,
+            CONF_DEVICE_NAME: "device_name",
+        },
+    )
+
+    assert result["type"] == RESULT_TYPE_FORM
+    assert result["step_id"] == "api_method"
+
+    result = await hass.config_entries.flow.async_configure(
+        result["flow_id"],
+        user_input={
+            CONF_USE_WEBHOOK: True,
+            CONF_TOKEN: "",
+        },
+    )
+
+    assert result["type"] == RESULT_TYPE_FORM
+    assert result["step_id"] == "webhook"
+    assert result["errors"] is None
+
+
+async def test_show_config_form_api_method_no_auth_token(hass, webhook_id):
+    """Test show configuration form."""
+
+    # Using Keg
+    result = await hass.config_entries.flow.async_init(
+        DOMAIN, context={"source": config_entries.SOURCE_USER}
+    )
+
+    result = await hass.config_entries.flow.async_configure(
+        result["flow_id"],
+        user_input={
+            CONF_DEVICE_TYPE: PlaatoDeviceType.Keg,
+            CONF_DEVICE_NAME: "device_name",
+        },
+    )
+
+    assert result["type"] == RESULT_TYPE_FORM
+    assert result["step_id"] == "api_method"
+
+    result = await hass.config_entries.flow.async_configure(
+        result["flow_id"], user_input={CONF_TOKEN: ""}
+    )
+
+    assert result["type"] == RESULT_TYPE_FORM
+    assert result["step_id"] == "api_method"
+    assert len(result["errors"]) == 1
+    assert result["errors"]["base"] == "no_auth_token"
+
+    # Using Airlock
+    result = await hass.config_entries.flow.async_init(
+        DOMAIN, context={"source": config_entries.SOURCE_USER}
+    )
+
+    result = await hass.config_entries.flow.async_configure(
+        result["flow_id"],
+        user_input={
+            CONF_DEVICE_TYPE: PlaatoDeviceType.Airlock,
+            CONF_DEVICE_NAME: "device_name",
+        },
+    )
+
+    assert result["type"] == RESULT_TYPE_FORM
+    assert result["step_id"] == "api_method"
+
+    result = await hass.config_entries.flow.async_configure(
+        result["flow_id"], user_input={CONF_TOKEN: ""}
+    )
+
+    assert result["type"] == RESULT_TYPE_FORM
+    assert result["step_id"] == "api_method"
+    assert len(result["errors"]) == 1
+    assert result["errors"]["base"] == "no_api_method"
+
+
+async def test_options(hass):
+    """Test updating options."""
+    config_entry = MockConfigEntry(
+        domain=DOMAIN,
+        title="NAME",
+        data={},
+        options={CONF_SCAN_INTERVAL: 5},
+    )
+
+    config_entry.add_to_hass(hass)
+    with patch("homeassistant.components.plaato.async_setup_entry", return_value=True):
+        result = await hass.config_entries.options.async_init(config_entry.entry_id)
+
+    assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
+    assert result["step_id"] == "user"
+
+    result = await hass.config_entries.options.async_configure(
+        result["flow_id"],
+        user_input={CONF_SCAN_INTERVAL: 10},
+    )
+
+    assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
+    assert result["data"][CONF_SCAN_INTERVAL] == 10
+
+
+async def test_options_webhook(hass, webhook_id):
+    """Test updating options."""
+    config_entry = MockConfigEntry(
+        domain=DOMAIN,
+        title="NAME",
+        data={CONF_USE_WEBHOOK: True, CONF_WEBHOOK_ID: None},
+        options={CONF_SCAN_INTERVAL: 5},
+    )
+
+    config_entry.add_to_hass(hass)
+    with patch("homeassistant.components.plaato.async_setup_entry", return_value=True):
+        result = await hass.config_entries.options.async_init(config_entry.entry_id)
+
+    assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
+    assert result["step_id"] == "webhook"
+    assert result["description_placeholders"] == {"webhook_url": ""}
+
+    result = await hass.config_entries.options.async_configure(
+        result["flow_id"],
+        user_input={CONF_WEBHOOK_ID: WEBHOOK_ID},
+    )
+
+    assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
+    assert result["data"][CONF_WEBHOOK_ID] == CONF_WEBHOOK_ID