diff --git a/.coveragerc b/.coveragerc
index f86ea86d2d10207f60655d4b694aa53c254d6f94..1f532727427296836a3e11d46cc601609d980bd9 100644
--- a/.coveragerc
+++ b/.coveragerc
@@ -967,6 +967,8 @@ omit =
     homeassistant/components/switchbot/switch.py
     homeassistant/components/switcher_kis/switch.py
     homeassistant/components/switchmate/switch.py
+    homeassistant/components/syncthing/__init__.py
+    homeassistant/components/syncthing/sensor.py
     homeassistant/components/syncthru/__init__.py
     homeassistant/components/syncthru/binary_sensor.py
     homeassistant/components/syncthru/sensor.py
diff --git a/CODEOWNERS b/CODEOWNERS
index eb46da1353da2668a12a82903e3124c20426a2ce..c2824fb33b63b14a38c040e7381633ad2b4ef8eb 100644
--- a/CODEOWNERS
+++ b/CODEOWNERS
@@ -478,6 +478,7 @@ homeassistant/components/swiss_public_transport/* @fabaff
 homeassistant/components/switchbot/* @danielhiversen
 homeassistant/components/switcher_kis/* @tomerfi
 homeassistant/components/switchmate/* @danielhiversen
+homeassistant/components/syncthing/* @zhulik
 homeassistant/components/syncthru/* @nielstron
 homeassistant/components/synology_dsm/* @hacf-fr @Quentame @mib1185
 homeassistant/components/synology_srm/* @aerialls
diff --git a/homeassistant/components/syncthing/__init__.py b/homeassistant/components/syncthing/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..d7cc671465a78721d02c45bd4975db502154690d
--- /dev/null
+++ b/homeassistant/components/syncthing/__init__.py
@@ -0,0 +1,172 @@
+"""The syncthing integration."""
+import asyncio
+import logging
+
+import aiosyncthing
+
+from homeassistant.config_entries import ConfigEntry
+from homeassistant.const import (
+    CONF_TOKEN,
+    CONF_URL,
+    CONF_VERIFY_SSL,
+    EVENT_HOMEASSISTANT_STOP,
+)
+from homeassistant.core import HomeAssistant
+from homeassistant.exceptions import ConfigEntryNotReady
+from homeassistant.helpers.dispatcher import async_dispatcher_send
+
+from .const import (
+    DOMAIN,
+    EVENTS,
+    RECONNECT_INTERVAL,
+    SERVER_AVAILABLE,
+    SERVER_UNAVAILABLE,
+)
+
+PLATFORMS = ["sensor"]
+
+_LOGGER = logging.getLogger(__name__)
+
+
+async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
+    """Set up syncthing from a config entry."""
+    data = entry.data
+
+    if DOMAIN not in hass.data:
+        hass.data[DOMAIN] = {}
+
+    client = aiosyncthing.Syncthing(
+        data[CONF_TOKEN],
+        url=data[CONF_URL],
+        verify_ssl=data[CONF_VERIFY_SSL],
+    )
+
+    try:
+        status = await client.system.status()
+    except aiosyncthing.exceptions.SyncthingError as exception:
+        await client.close()
+        raise ConfigEntryNotReady from exception
+
+    server_id = status["myID"]
+
+    syncthing = SyncthingClient(hass, client, server_id)
+    syncthing.subscribe()
+    hass.data[DOMAIN][entry.entry_id] = syncthing
+
+    hass.config_entries.async_setup_platforms(entry, PLATFORMS)
+
+    async def cancel_listen_task(_):
+        await syncthing.unsubscribe()
+
+    entry.async_on_unload(
+        hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, cancel_listen_task)
+    )
+
+    return True
+
+
+async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
+    """Unload a config entry."""
+    unload_ok = await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
+    if unload_ok:
+        syncthing = hass.data[DOMAIN].pop(entry.entry_id)
+        await syncthing.unsubscribe()
+
+    return unload_ok
+
+
+class SyncthingClient:
+    """A Syncthing client."""
+
+    def __init__(self, hass, client, server_id):
+        """Initialize the client."""
+        self._hass = hass
+        self._client = client
+        self._server_id = server_id
+        self._listen_task = None
+
+    @property
+    def server_id(self):
+        """Get server id."""
+        return self._server_id
+
+    @property
+    def url(self):
+        """Get server URL."""
+        return self._client.url
+
+    @property
+    def database(self):
+        """Get database namespace client."""
+        return self._client.database
+
+    @property
+    def system(self):
+        """Get system namespace client."""
+        return self._client.system
+
+    def subscribe(self):
+        """Start event listener coroutine."""
+        self._listen_task = asyncio.create_task(self._listen())
+
+    async def unsubscribe(self):
+        """Stop event listener coroutine."""
+        if self._listen_task:
+            self._listen_task.cancel()
+        await self._client.close()
+
+    async def _listen(self):
+        """Listen to Syncthing events."""
+        events = self._client.events
+        server_was_unavailable = False
+        while True:
+            if await self._server_available():
+                if server_was_unavailable:
+                    _LOGGER.info(
+                        "The syncthing server '%s' is back online", self._client.url
+                    )
+                    async_dispatcher_send(
+                        self._hass, f"{SERVER_AVAILABLE}-{self._server_id}"
+                    )
+                    server_was_unavailable = False
+            else:
+                await asyncio.sleep(RECONNECT_INTERVAL.total_seconds())
+                continue
+            try:
+                async for event in events.listen():
+                    if events.last_seen_id == 0:
+                        continue  # skipping historical events from the first batch
+                    if event["type"] not in EVENTS:
+                        continue
+
+                    signal_name = EVENTS[event["type"]]
+                    folder = None
+                    if "folder" in event["data"]:
+                        folder = event["data"]["folder"]
+                    else:  # A workaround, some events store folder id under `id` key
+                        folder = event["data"]["id"]
+                    async_dispatcher_send(
+                        self._hass,
+                        f"{signal_name}-{self._server_id}-{folder}",
+                        event,
+                    )
+            except aiosyncthing.exceptions.SyncthingError:
+                _LOGGER.info(
+                    "The syncthing server '%s' is not available. Sleeping %i seconds and retrying",
+                    self._client.url,
+                    RECONNECT_INTERVAL.total_seconds(),
+                )
+                async_dispatcher_send(
+                    self._hass, f"{SERVER_UNAVAILABLE}-{self._server_id}"
+                )
+                await asyncio.sleep(RECONNECT_INTERVAL.total_seconds())
+                server_was_unavailable = True
+                continue
+
+    async def _server_available(self):
+        try:
+            await self._client.system.ping()
+        except aiosyncthing.exceptions.SyncthingError:
+            return False
+        else:
+            return True
diff --git a/homeassistant/components/syncthing/config_flow.py b/homeassistant/components/syncthing/config_flow.py
new file mode 100644
index 0000000000000000000000000000000000000000..e6a5c994834817433f4a051b31a2f245361fa6e7
--- /dev/null
+++ b/homeassistant/components/syncthing/config_flow.py
@@ -0,0 +1,72 @@
+"""Config flow for syncthing integration."""
+import logging
+
+import aiosyncthing
+import voluptuous as vol
+
+from homeassistant import config_entries, core, exceptions
+from homeassistant.const import CONF_TOKEN, CONF_URL, CONF_VERIFY_SSL
+
+from .const import DEFAULT_URL, DEFAULT_VERIFY_SSL, DOMAIN
+
+_LOGGER = logging.getLogger(__name__)
+
+DATA_SCHEMA = vol.Schema(
+    {
+        vol.Required(CONF_URL, default=DEFAULT_URL): str,
+        vol.Required(CONF_TOKEN): str,
+        vol.Required(CONF_VERIFY_SSL, default=DEFAULT_VERIFY_SSL): bool,
+    }
+)
+
+
+async def validate_input(hass: core.HomeAssistant, data):
+    """Validate the user input allows us to connect."""
+
+    try:
+        async with aiosyncthing.Syncthing(
+            data[CONF_TOKEN],
+            url=data[CONF_URL],
+            verify_ssl=data[CONF_VERIFY_SSL],
+            loop=hass.loop,
+        ) as client:
+            server_id = (await client.system.status())["myID"]
+            return {"title": f"{data[CONF_URL]}", "server_id": server_id}
+    except aiosyncthing.exceptions.UnauthorizedError as error:
+        raise InvalidAuth from error
+    except Exception as error:
+        raise CannotConnect from error
+
+
+class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
+    """Handle a config flow for syncthing."""
+
+    VERSION = 1
+
+    async def async_step_user(self, user_input=None):
+        """Handle the initial step."""
+        errors = {}
+
+        if user_input is not None:
+            try:
+                info = await validate_input(self.hass, user_input)
+            except CannotConnect:
+                errors["base"] = "cannot_connect"
+            except InvalidAuth:
+                errors[CONF_TOKEN] = "invalid_auth"
+            else:
+                await self.async_set_unique_id(info["server_id"])
+                self._abort_if_unique_id_configured()
+                return self.async_create_entry(title=info["title"], data=user_input)
+
+        return self.async_show_form(
+            step_id="user", data_schema=DATA_SCHEMA, errors=errors
+        )
+
+
+class CannotConnect(exceptions.HomeAssistantError):
+    """Error to indicate we cannot connect."""
+
+
+class InvalidAuth(exceptions.HomeAssistantError):
+    """Error to indicate there is invalid auth."""
diff --git a/homeassistant/components/syncthing/const.py b/homeassistant/components/syncthing/const.py
new file mode 100644
index 0000000000000000000000000000000000000000..a9ec0ad03759e8744ddc7d6b68350e8335506974
--- /dev/null
+++ b/homeassistant/components/syncthing/const.py
@@ -0,0 +1,33 @@
+"""Constants for the syncthing integration."""
+from datetime import timedelta
+
+DOMAIN = "syncthing"
+
+DEFAULT_VERIFY_SSL = True
+DEFAULT_URL = "http://127.0.0.1:8384"
+
+RECONNECT_INTERVAL = timedelta(seconds=10)
+SCAN_INTERVAL = timedelta(seconds=120)
+
+FOLDER_SUMMARY_RECEIVED = "syncthing_folder_summary_received"
+FOLDER_PAUSED_RECEIVED = "syncthing_folder_paused_received"
+SERVER_UNAVAILABLE = "syncthing_server_unavailable"
+SERVER_AVAILABLE = "syncthing_server_available"
+STATE_CHANGED_RECEIVED = "syncthing_state_changed_received"
+
+EVENTS = {
+    "FolderSummary": FOLDER_SUMMARY_RECEIVED,
+    "StateChanged": STATE_CHANGED_RECEIVED,
+    "FolderPaused": FOLDER_PAUSED_RECEIVED,
+}
+
+
+FOLDER_SENSOR_ICONS = {
+    "paused": "mdi:folder-clock",
+    "scanning": "mdi:folder-search",
+    "syncing": "mdi:folder-sync",
+    "idle": "mdi:folder",
+}
+
+FOLDER_SENSOR_ALERT_ICON = "mdi:folder-alert"
+FOLDER_SENSOR_DEFAULT_ICON = "mdi:folder"
diff --git a/homeassistant/components/syncthing/manifest.json b/homeassistant/components/syncthing/manifest.json
new file mode 100644
index 0000000000000000000000000000000000000000..cd779e1657b78955759d90221384e1350655e410
--- /dev/null
+++ b/homeassistant/components/syncthing/manifest.json
@@ -0,0 +1,12 @@
+{
+  "domain": "syncthing",
+  "name": "Syncthing",
+  "config_flow": true,
+  "documentation": "https://www.home-assistant.io/integrations/syncthing",
+  "requirements": ["aiosyncthing==0.5.1"],
+  "codeowners": [
+    "@zhulik"
+  ],
+  "quality_scale": "silver",
+  "iot_class": "local_polling"
+}
diff --git a/homeassistant/components/syncthing/sensor.py b/homeassistant/components/syncthing/sensor.py
new file mode 100644
index 0000000000000000000000000000000000000000..5e8ea2f88c24271eca2a4a1ffad33148898b567e
--- /dev/null
+++ b/homeassistant/components/syncthing/sensor.py
@@ -0,0 +1,268 @@
+"""Support for monitoring the Syncthing instance."""
+
+import logging
+
+import aiosyncthing
+
+from homeassistant.components.sensor import SensorEntity
+from homeassistant.core import callback
+from homeassistant.exceptions import PlatformNotReady
+from homeassistant.helpers.dispatcher import async_dispatcher_connect
+from homeassistant.helpers.event import async_track_time_interval
+
+from .const import (
+    DOMAIN,
+    FOLDER_PAUSED_RECEIVED,
+    FOLDER_SENSOR_ALERT_ICON,
+    FOLDER_SENSOR_DEFAULT_ICON,
+    FOLDER_SENSOR_ICONS,
+    FOLDER_SUMMARY_RECEIVED,
+    SCAN_INTERVAL,
+    SERVER_AVAILABLE,
+    SERVER_UNAVAILABLE,
+    STATE_CHANGED_RECEIVED,
+)
+
+_LOGGER = logging.getLogger(__name__)
+
+
+async def async_setup_entry(hass, config_entry, async_add_entities):
+    """Set up the Syncthing sensors."""
+    syncthing = hass.data[DOMAIN][config_entry.entry_id]
+
+    try:
+        config = await syncthing.system.config()
+        version = await syncthing.system.version()
+    except aiosyncthing.exceptions.SyncthingError as exception:
+        raise PlatformNotReady from exception
+
+    server_id = syncthing.server_id
+    entities = [
+        FolderSensor(
+            syncthing,
+            server_id,
+            folder["id"],
+            folder["label"],
+            version["version"],
+        )
+        for folder in config["folders"]
+    ]
+
+    async_add_entities(entities)
+
+
+class FolderSensor(SensorEntity):
+    """A Syncthing folder sensor."""
+
+    STATE_ATTRIBUTES = {
+        "errors": "errors",
+        "globalBytes": "global_bytes",
+        "globalDeleted": "global_deleted",
+        "globalDirectories": "global_directories",
+        "globalFiles": "global_files",
+        "globalSymlinks": "global_symlinks",
+        "globalTotalItems": "global_total_items",
+        "ignorePatterns": "ignore_patterns",
+        "inSyncBytes": "in_sync_bytes",
+        "inSyncFiles": "in_sync_files",
+        "invalid": "invalid",
+        "localBytes": "local_bytes",
+        "localDeleted": "local_deleted",
+        "localDirectories": "local_directories",
+        "localFiles": "local_files",
+        "localSymlinks": "local_symlinks",
+        "localTotalItems": "local_total_items",
+        "needBytes": "need_bytes",
+        "needDeletes": "need_deletes",
+        "needDirectories": "need_directories",
+        "needFiles": "need_files",
+        "needSymlinks": "need_symlinks",
+        "needTotalItems": "need_total_items",
+        "pullErrors": "pull_errors",
+        "state": "state",
+    }
+
+    def __init__(self, syncthing, server_id, folder_id, folder_label, version):
+        """Initialize the sensor."""
+        self._syncthing = syncthing
+        self._server_id = server_id
+        self._folder_id = folder_id
+        self._folder_label = folder_label
+        self._state = None
+        self._unsub_timer = None
+        self._version = version
+
+        self._short_server_id = server_id.split("-")[0]
+
+    @property
+    def name(self):
+        """Return the name of the sensor."""
+        return f"{self._short_server_id} {self._folder_id} {self._folder_label}"
+
+    @property
+    def unique_id(self):
+        """Return the unique id of the entity."""
+        return f"{self._short_server_id}-{self._folder_id}"
+
+    @property
+    def state(self):
+        """Return the state of the sensor."""
+        return self._state["state"]
+
+    @property
+    def available(self):
+        """Could the device be accessed during the last update call."""
+        return self._state is not None
+
+    @property
+    def icon(self):
+        """Return the icon for this sensor."""
+        if self._state is None:
+            return FOLDER_SENSOR_DEFAULT_ICON
+        if self.state in FOLDER_SENSOR_ICONS:
+            return FOLDER_SENSOR_ICONS[self.state]
+        return FOLDER_SENSOR_ALERT_ICON
+
+    @property
+    def extra_state_attributes(self):
+        """Return the state attributes."""
+        return self._state
+
+    @property
+    def should_poll(self):
+        """Return the polling requirement for this sensor."""
+        return False
+
+    @property
+    def device_info(self):
+        """Return device information."""
+        return {
+            "identifiers": {(DOMAIN, self._server_id)},
+            "name": f"Syncthing ({self._syncthing.url})",
+            "manufacturer": "Syncthing Team",
+            "sw_version": self._version,
+            "entry_type": "service",
+        }
+
+    async def async_update_status(self):
+        """Request folder status and update state."""
+        try:
+            state = await self._syncthing.database.status(self._folder_id)
+        except aiosyncthing.exceptions.SyncthingError:
+            self._state = None
+        else:
+            self._state = self._filter_state(state)
+        self.async_write_ha_state()
+
+    def subscribe(self):
+        """Start polling syncthing folder status."""
+        if self._unsub_timer is None:
+
+            async def refresh(event_time):
+                """Get the latest data from Syncthing."""
+                await self.async_update_status()
+
+            self._unsub_timer = async_track_time_interval(
+                self.hass, refresh, SCAN_INTERVAL
+            )
+
+    @callback
+    def unsubscribe(self):
+        """Stop polling syncthing folder status."""
+        if self._unsub_timer is not None:
+            self._unsub_timer()
+            self._unsub_timer = None
+
+    async def async_added_to_hass(self):
+        """Handle entity which will be added."""
+
+        @callback
+        def handle_folder_summary(event):
+            if self._state is not None:
+                self._state = self._filter_state(event["data"]["summary"])
+                self.async_write_ha_state()
+
+        self.async_on_remove(
+            async_dispatcher_connect(
+                self.hass,
+                f"{FOLDER_SUMMARY_RECEIVED}-{self._server_id}-{self._folder_id}",
+                handle_folder_summary,
+            )
+        )
+
+        @callback
+        def handle_state_changed(event):
+            if self._state is not None:
+                self._state["state"] = event["data"]["to"]
+                self.async_write_ha_state()
+
+        self.async_on_remove(
+            async_dispatcher_connect(
+                self.hass,
+                f"{STATE_CHANGED_RECEIVED}-{self._server_id}-{self._folder_id}",
+                handle_state_changed,
+            )
+        )
+
+        @callback
+        def handle_folder_paused(event):
+            if self._state is not None:
+                self._state["state"] = "paused"
+                self.async_write_ha_state()
+
+        self.async_on_remove(
+            async_dispatcher_connect(
+                self.hass,
+                f"{FOLDER_PAUSED_RECEIVED}-{self._server_id}-{self._folder_id}",
+                handle_folder_paused,
+            )
+        )
+
+        @callback
+        def handle_server_unavailable():
+            self._state = None
+            self.unsubscribe()
+            self.async_write_ha_state()
+
+        self.async_on_remove(
+            async_dispatcher_connect(
+                self.hass,
+                f"{SERVER_UNAVAILABLE}-{self._server_id}",
+                handle_server_unavailable,
+            )
+        )
+
+        async def handle_server_available():
+            self.subscribe()
+            await self.async_update_status()
+
+        self.async_on_remove(
+            async_dispatcher_connect(
+                self.hass,
+                f"{SERVER_AVAILABLE}-{self._server_id}",
+                handle_server_available,
+            )
+        )
+
+        self.subscribe()
+        self.async_on_remove(self.unsubscribe)
+
+        await self.async_update_status()
+
+    def _filter_state(self, state):
+        # Select only needed state attributes and map their names
+        state = {
+            self.STATE_ATTRIBUTES[key]: value
+            for key, value in state.items()
+            if key in self.STATE_ATTRIBUTES
+        }
+
+        # A workaround, for some reason, state of paused folders is an empty string
+        if state["state"] == "":
+            state["state"] = "paused"
+
+        # Add some useful attributes
+        state["id"] = self._folder_id
+        state["label"] = self._folder_label
+
+        return state
diff --git a/homeassistant/components/syncthing/strings.json b/homeassistant/components/syncthing/strings.json
new file mode 100644
index 0000000000000000000000000000000000000000..1781df56f1e778eaae7fab8df1684a632315ee6b
--- /dev/null
+++ b/homeassistant/components/syncthing/strings.json
@@ -0,0 +1,22 @@
+{
+  "title": "Syncthing",
+  "config": {
+    "step": {
+      "user": {
+        "data": {
+          "title": "Setup Syncthing integration",
+          "url": "[%key:common::config_flow::data::url%]",
+          "verify_ssl": "[%key:common::config_flow::data::verify_ssl%]",
+          "token": "Token"
+        }
+      }
+    },
+    "error": {
+      "cannot_connect": "[%key:common::config_flow::error::cannot_connect%]",
+      "invalid_auth": "[%key:common::config_flow::error::invalid_auth%]"
+    },
+    "abort": {
+      "already_configured": "[%key:common::config_flow::abort::already_configured_service%]"
+    }
+  }
+}
diff --git a/homeassistant/components/syncthing/translations/en.json b/homeassistant/components/syncthing/translations/en.json
new file mode 100644
index 0000000000000000000000000000000000000000..00c73bedb9e62ab4e5a2a7b6c689cf7415334517
--- /dev/null
+++ b/homeassistant/components/syncthing/translations/en.json
@@ -0,0 +1,22 @@
+{
+    "config": {
+        "error": {
+            "cannot_connect": "Unable to connect to the Syncthing server.",
+            "invalid_auth": "Invalid authentication"
+        },
+        "abort": {
+            "already_configured": "Service is already configured"
+        },
+        "step": {
+            "user": {
+                "title": "Setup Syncthing integration",
+                "data": {
+                    "url": "URL",
+                    "token": "Token",
+                    "verify_ssl": "Verify SSL"
+                }
+            }
+        }
+    },
+    "title": "Syncthing"
+}
\ No newline at end of file
diff --git a/homeassistant/generated/config_flows.py b/homeassistant/generated/config_flows.py
index 6adcb16cc15a0c9bc9cbaf0debb337a2aba3bd1a..bb346ff5b0f9b78df899dfc5380b76a43e59092b 100644
--- a/homeassistant/generated/config_flows.py
+++ b/homeassistant/generated/config_flows.py
@@ -239,6 +239,7 @@ FLOWS = [
     "srp_energy",
     "starline",
     "subaru",
+    "syncthing",
     "syncthru",
     "synology_dsm",
     "system_bridge",
diff --git a/requirements_all.txt b/requirements_all.txt
index 39305ff7ccb7d4055c16b9e4ca9d248c45939cb8..481763adcc75b938141b4c735e92599d32dcc863 100644
--- a/requirements_all.txt
+++ b/requirements_all.txt
@@ -232,6 +232,9 @@ aioshelly==0.6.2
 # homeassistant.components.switcher_kis
 aioswitcher==1.2.1
 
+# homeassistant.components.syncthing
+aiosyncthing==0.5.1
+
 # homeassistant.components.unifi
 aiounifi==26
 
diff --git a/requirements_test_all.txt b/requirements_test_all.txt
index 97ee8a487e1ee9352bacbbc48facec120a0c528d..883ece77c4e1a695519c19fed9bde505c778b5b4 100644
--- a/requirements_test_all.txt
+++ b/requirements_test_all.txt
@@ -154,6 +154,9 @@ aioshelly==0.6.2
 # homeassistant.components.switcher_kis
 aioswitcher==1.2.1
 
+# homeassistant.components.syncthing
+aiosyncthing==0.5.1
+
 # homeassistant.components.unifi
 aiounifi==26
 
diff --git a/tests/components/syncthing/__init__.py b/tests/components/syncthing/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..8a4f28832ea37001368a4b3467df2a431fcccd3c
--- /dev/null
+++ b/tests/components/syncthing/__init__.py
@@ -0,0 +1 @@
+"""Tests for the syncthing integration."""
diff --git a/tests/components/syncthing/test_config_flow.py b/tests/components/syncthing/test_config_flow.py
new file mode 100644
index 0000000000000000000000000000000000000000..30f8bc0386b032aabbf644cedfaf1bf3832475c9
--- /dev/null
+++ b/tests/components/syncthing/test_config_flow.py
@@ -0,0 +1,106 @@
+"""Tests for syncthing config flow."""
+
+from unittest.mock import patch
+
+from aiosyncthing.exceptions import UnauthorizedError
+
+from homeassistant import config_entries, data_entry_flow, setup
+from homeassistant.components.syncthing.const import DOMAIN
+from homeassistant.const import CONF_NAME, CONF_TOKEN, CONF_URL, CONF_VERIFY_SSL
+
+from tests.common import MockConfigEntry
+
+NAME = "Syncthing"
+URL = "http://127.0.0.1:8384"
+TOKEN = "token"
+VERIFY_SSL = True
+
+MOCK_ENTRY = {
+    CONF_NAME: NAME,
+    CONF_URL: URL,
+    CONF_TOKEN: TOKEN,
+    CONF_VERIFY_SSL: VERIFY_SSL,
+}
+
+
+async def test_show_setup_form(hass):
+    """Test that the setup form is served."""
+    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"] == data_entry_flow.RESULT_TYPE_FORM
+    assert result["errors"] == {}
+    assert result["step_id"] == "user"
+
+
+async def test_flow_successfull(hass):
+    """Test with required fields only."""
+    with patch(
+        "aiosyncthing.system.System.status", return_value={"myID": "server-id"}
+    ), patch(
+        "homeassistant.components.syncthing.async_setup_entry",
+        return_value=True,
+    ) as mock_setup_entry:
+        result = await hass.config_entries.flow.async_init(
+            DOMAIN,
+            context={"source": "user"},
+            data={
+                CONF_NAME: NAME,
+                CONF_URL: URL,
+                CONF_TOKEN: TOKEN,
+                CONF_VERIFY_SSL: VERIFY_SSL,
+            },
+        )
+        assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
+        assert result["title"] == "http://127.0.0.1:8384"
+        assert result["data"][CONF_NAME] == NAME
+        assert result["data"][CONF_URL] == URL
+        assert result["data"][CONF_TOKEN] == TOKEN
+        assert result["data"][CONF_VERIFY_SSL] == VERIFY_SSL
+        assert len(mock_setup_entry.mock_calls) == 1
+
+
+async def test_flow_already_configured(hass):
+    """Test name is already configured."""
+
+    entry = MockConfigEntry(domain=DOMAIN, data=MOCK_ENTRY, unique_id="server-id")
+    entry.add_to_hass(hass)
+
+    with patch("aiosyncthing.system.System.status", return_value={"myID": "server-id"}):
+        result = await hass.config_entries.flow.async_init(
+            DOMAIN,
+            context={"source": "user"},
+            data=MOCK_ENTRY,
+        )
+
+    assert result["type"] == data_entry_flow.RESULT_TYPE_ABORT
+    assert result["reason"] == "already_configured"
+
+
+async def test_flow_invalid_auth(hass):
+    """Test invalid auth."""
+
+    with patch("aiosyncthing.system.System.status", side_effect=UnauthorizedError):
+        result = await hass.config_entries.flow.async_init(
+            DOMAIN,
+            context={"source": "user"},
+            data=MOCK_ENTRY,
+        )
+
+        assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
+        assert result["errors"]["token"] == "invalid_auth"
+
+
+async def test_flow_cannot_connect(hass):
+    """Test cannot connect."""
+
+    with patch("aiosyncthing.system.System.status", side_effect=Exception):
+        result = await hass.config_entries.flow.async_init(
+            DOMAIN,
+            context={"source": "user"},
+            data=MOCK_ENTRY,
+        )
+
+        assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
+        assert result["errors"]["base"] == "cannot_connect"