diff --git a/platypush/plugins/media/chromecast/__init__.py b/platypush/plugins/media/chromecast/__init__.py
index fcf1a446a..8c9727076 100644
--- a/platypush/plugins/media/chromecast/__init__.py
+++ b/platypush/plugins/media/chromecast/__init__.py
@@ -1,7 +1,12 @@
-import threading
-from typing import Callable, Optional
+from typing import Optional
 
-import pychromecast  # type: ignore
+from pychromecast import (
+    CastBrowser,
+    Chromecast,
+    ChromecastConnectionError,
+    SimpleCastListener,
+    get_chromecast_from_cast_info,
+)
 
 from platypush.backend.http.app.utils import get_remote_base_url
 from platypush.plugins import RunnablePlugin, action
@@ -35,24 +40,34 @@ class MediaChromecastPlugin(MediaPlugin, RunnablePlugin):
 
         self._is_local = False
         self.chromecast = chromecast
-        self.chromecasts = {}
+        self._chromecasts_by_uuid = {}
+        self._chromecasts_by_name = {}
         self._media_listeners = {}
-        self._refresh_lock = threading.RLock()
+        self._zc = None
+        self._browser = None
 
-    def _get_chromecasts(self, *args, **kwargs):
-        with self._refresh_lock:
-            ret = pychromecast.get_chromecasts(*args, **kwargs)
+    @property
+    def zc(self):
+        from zeroconf import Zeroconf
 
-            if isinstance(ret, tuple):
-                chromecasts, browser = ret
-                if browser:
-                    browser.stop_discovery()
-                    if browser.zc:
-                        browser.zc.close()
+        if not self._zc:
+            self._zc = Zeroconf()
 
-                return chromecasts
+        return self._zc
 
-        return ret
+    @property
+    def browser(self):
+        if not self._browser:
+            self._browser = CastBrowser(
+                SimpleCastListener(self._on_chromecast_discovered), self.zc
+            )
+
+            self._browser.start_discovery()
+
+        return self._browser
+
+    def _on_chromecast_discovered(self, _, service: str):
+        self.logger.info('Discovered Chromecast: %s', service)
 
     @staticmethod
     def _get_device_property(cc, prop: str):
@@ -60,7 +75,7 @@ class MediaChromecastPlugin(MediaPlugin, RunnablePlugin):
             return getattr(cc.device, prop)
         return getattr(cc.cast_info, prop)
 
-    def _serialize_device(self, cc: pychromecast.Chromecast) -> dict:
+    def _serialize_device(self, cc: Chromecast) -> dict:
         """
         Convert a Chromecast object and its status to a dictionary.
         """
@@ -102,101 +117,23 @@ class MediaChromecastPlugin(MediaPlugin, RunnablePlugin):
             ),
         }
 
-    def _refresh_chromecasts(
-        self,
-        tries: int = 2,
-        retry_wait: float = 10,
-        timeout: float = 60,
-        blocking: bool = True,
-        callback: Optional[Callable] = None,
-    ):
-        """
-        Get the list of Chromecast devices
+    def _event_callback(self, _, cast: Chromecast):
+        self._chromecasts_by_uuid[cast.uuid] = cast
+        self._chromecasts_by_name[
+            self._get_device_property(cast, 'friendly_name')
+        ] = cast
 
-        :param tries: Number of retries (default: 2)
-        :param retry_wait: Number of seconds between retries (default: 10 seconds)
-        :param timeout: Timeout before failing the call (default: 60 seconds)
-        :param blocking: If true, then the function will block until all the
-            Chromecast devices have been scanned. If false, then the provided
-            callback function will be invoked when a new device is discovered
-        :param callback: If blocking is false, then you can provide a callback
-            function that will be invoked when a new device is discovered
-        """
-        casts = {
-            self._get_device_property(cast, 'friendly_name'): cast
-            for cast in self._get_chromecasts(
-                tries=tries,
-                retry_wait=retry_wait,
-                timeout=timeout,
-                blocking=blocking,
-                callback=callback,
-            )
-        }
-
-        for name, cast in casts.copy().items():
-            if not self.chromecasts.get(name):
-                self.logger.info('Discovered new Chromecast: %s', name)
-                self.chromecasts[name] = cast
-                self._update_listeners(name, cast)
-                cast.wait()
-            else:
-                casts.pop(name)
-
-        for name, cast in casts.items():
-            cast.wait()
-            self.logger.info('Refreshed Chromecast state: %s', name)
-
-    def _event_callback(self, _, cast: pychromecast.Chromecast):
-        with self._refresh_lock:
-            self.chromecasts[self._get_device_property(cast, 'friendly_name')] = cast
-
-    def _update_listeners(self, name, cast):
-        if name not in self._media_listeners:
-            cast.start()
-            self._media_listeners[name] = MediaListener(
-                name=name, cast=cast, callback=self._event_callback
-            )
-            cast.media_controller.register_status_listener(self._media_listeners[name])
-            self.logger.debug('Started media listener for %s', name)
-
-    def get_chromecast(self, chromecast=None, n_tries=2):
-        if isinstance(chromecast, pychromecast.Chromecast):
-            assert chromecast, 'Invalid Chromecast object'
+    def get_chromecast(self, chromecast=None):
+        if isinstance(chromecast, Chromecast):
             return chromecast
 
-        if not chromecast:
-            if not self.chromecast:
-                raise RuntimeError(
-                    'No Chromecast specified nor default Chromecast configured'
-                )
-            chromecast = self.chromecast
+        if self._chromecasts_by_uuid.get(chromecast):
+            return self._chromecasts_by_uuid[chromecast]
 
-        if chromecast not in self.chromecasts:
-            casts = {}
-            while n_tries > 0:
-                n_tries -= 1
-                casts.update(
-                    {
-                        self._get_device_property(cast, 'friendly_name'): cast
-                        for cast in self._get_chromecasts()
-                    }
-                )
+        if self._chromecasts_by_name.get(chromecast):
+            return self._chromecasts_by_name[chromecast]
 
-                if chromecast in casts:
-                    self.chromecasts.update(casts)
-                    break
-
-            if chromecast not in self.chromecasts:
-                raise RuntimeError(f'Device {chromecast} not found')
-
-        cast = self.chromecasts[chromecast]
-
-        try:
-            cast.wait()
-        except Exception as e:
-            self.logger.warning('Failed to wait Chromecast sync: %s', e)
-
-        return cast
+        raise AssertionError(f'Chromecast {chromecast} not found')
 
     @action
     def play(
@@ -311,6 +248,17 @@ class MediaChromecastPlugin(MediaPlugin, RunnablePlugin):
 
     @action
     def stop(self, *_, chromecast: Optional[str] = None, **__):  # type: ignore
+        if self.should_stop():
+            if self._zc:
+                self._zc.close()
+                self._zc = None
+
+            if self._browser:
+                self._browser.stop_discovery()
+                self._browser = None
+
+            return
+
         chromecast = chromecast or self.chromecast
         if not chromecast:
             return None
@@ -513,13 +461,13 @@ class MediaChromecastPlugin(MediaPlugin, RunnablePlugin):
     def _status(self, chromecast: Optional[str] = None) -> dict:
         if chromecast:
             assert (
-                chromecast in self.chromecasts
+                chromecast in self._chromecasts_by_name
             ), f'No such Chromecast device: {chromecast}'
-            return self._serialize_device(self.chromecasts[chromecast])
+            return self._serialize_device(self._chromecasts_by_name[chromecast])
 
         return {
             name: self._serialize_device(cast)
-            for name, cast in self.chromecasts.items()
+            for name, cast in self._chromecasts_by_name.items()
         }
 
     @action
@@ -633,6 +581,54 @@ class MediaChromecastPlugin(MediaPlugin, RunnablePlugin):
     def remove_subtitles(self, *_, **__):
         raise NotImplementedError
 
+    def _refresh_chromecasts(self):
+        cast_info = {cast.friendly_name: cast for cast in self.browser.devices.values()}
+
+        for info in cast_info.values():
+            name = info.friendly_name
+            if self._chromecasts_by_uuid.get(
+                info.uuid
+            ) and self._chromecasts_by_name.get(name):
+                self.logger.debug('Chromecast %s already connected', name)
+                continue
+
+            self.logger.info('Started scan for Chromecast %s', name)
+
+            try:
+                cc = get_chromecast_from_cast_info(
+                    info,
+                    self.browser.zc,
+                    tries=2,
+                    retry_wait=5,
+                    timeout=30,
+                )
+
+                self._chromecasts_by_name[cc.name] = cc
+            except ChromecastConnectionError:
+                self.logger.warning('Failed to connect to Chromecast %s', info)
+                continue
+
+            if cc.uuid not in self._chromecasts_by_uuid:
+                self._chromecasts_by_uuid[cc.uuid] = cc
+                self.logger.debug('Connecting to Chromecast %s', name)
+
+                if name not in self._media_listeners:
+                    cc.start()
+                    self._media_listeners[name] = MediaListener(
+                        name=name or str(cc.uuid),
+                        cast=cc,
+                        callback=self._event_callback,
+                    )
+
+                    cc.media_controller.register_status_listener(
+                        self._media_listeners[name]
+                    )
+
+                    self.logger.info('Connected to Chromecast %s', name)
+
+            self._chromecasts_by_uuid[cc.uuid] = cc
+            self._chromecasts_by_name[name] = cc
+
     def main(self):
         while not self.should_stop():
             try: