Since this thing is on the innerwebs I suppose it should have a
[python_utils.git] / smart_home / chromecasts.py
index 7480cecc36826932ba90d69ecc83f70cf1a43a97..408ccf0e12ff3b1702ef7cd4b63d42c357fac7db 100644 (file)
@@ -1,45 +1,55 @@
 #!/usr/bin/env python3
 
+# © Copyright 2021-2022, Scott Gasch
+
 """Utilities for dealing with the webcams."""
 
 import atexit
 import datetime
 import logging
+import threading
+from typing import Any, List
 
 import pychromecast
 
-from decorator_utils import memoized
 import smart_home.device as dev
+from decorator_utils import memoized
 
 logger = logging.getLogger(__name__)
 
 
 class BaseChromecast(dev.Device):
-    ccasts = []
+    """A base class to represent a Google Chromecase device."""
+
+    ccasts: List[Any] = []
     refresh_ts = None
     browser = None
+    lock = threading.Lock()
 
     def __init__(self, name: str, mac: str, keywords: str = "") -> None:
         super().__init__(name.strip(), mac.strip(), keywords)
         ip = self.get_ip()
         now = datetime.datetime.now()
-        if (
+        with BaseChromecast.lock:
+            if (
                 BaseChromecast.refresh_ts is None
                 or (now - BaseChromecast.refresh_ts).total_seconds() > 60
-        ):
-            logger.debug('Refreshing the shared chromecast info list')
-            if BaseChromecast.browser is not None:
-                BaseChromecast.browser.stop_discovery()
-            BaseChromecast.ccasts, BaseChromecast.browser = pychromecast.get_chromecasts(
-                timeout=10.0
-            )
-            atexit.register(BaseChromecast.browser.stop_discovery)
-            BaseChromecast.refresh_ts = now
+            ):
+                logger.debug('Refreshing the shared chromecast info list')
+                if BaseChromecast.browser is not None:
+                    BaseChromecast.browser.stop_discovery()
+                (
+                    BaseChromecast.ccasts,
+                    BaseChromecast.browser,
+                ) = pychromecast.get_chromecasts(timeout=15.0)
+                assert BaseChromecast.browser is not None
+                atexit.register(BaseChromecast.browser.stop_discovery)
+                BaseChromecast.refresh_ts = now
 
         self.cast = None
         for cc in BaseChromecast.ccasts:
-            if cc.cast_info.host == ip:
-                logger.debug(f'Found chromecast at {ip}: {cc}')
+            if cc.cast_info.host == ip and cc.cast_info.cast_type != 'group':
+                logger.debug('Found chromecast at %s: %s', ip, cc)
                 self.cast = cc
                 self.cast.wait(timeout=1.0)
         if self.cast is None:
@@ -110,4 +120,3 @@ class BaseChromecast(dev.Device):
             f"Chromecast({self.cast.socket_client.host!r}, port={self.cast.socket_client.port!r}, "
             f"device={self.cast.cast_info.friendly_name!r})"
         )
-