Jelajahi Sumber

Subdevices: ensure same parent is used and only polling

When there are multiple child devices connected to the same hub, they
need to share the device to prevent too many parallel connections.
Also, we don't currently support push updates for child devices, so
we need to force polling.

Issue #1054, #1323
Jason Rumney 1 tahun lalu
induk
melakukan
dd03747ee5
2 mengubah file dengan 22 tambahan dan 5 penghapusan
  1. 19 4
      custom_components/tuya_local/device.py
  2. 3 1
      tests/test_device.py

+ 19 - 4
custom_components/tuya_local/device.py

@@ -67,16 +67,25 @@ class TuyaLocalDevice(object):
         self._api_protocol_version_index = None
         self._api_protocol_working = False
         self._api_working_protocol_failures = 0
+        self.dev_cid = dev_cid
         try:
             if dev_cid:
+                if hass.data[DOMAIN].get(dev_id):
+                    parent = hass.data[DOMAIN][dev_id]["tuyadevice"]
+                else:
+                    parent = tinytuya.Device(dev_id, address, local_key)
+                    hass.data[DOMAIN][dev_id] = {"tuyadevice": parent}
                 self._api = tinytuya.Device(
                     dev_id,
                     cid=dev_cid,
-                    parent=tinytuya.Device(dev_id, address, local_key),
+                    parent=parent,
                 )
             else:
-                self._api = tinytuya.Device(dev_id, address, local_key)
-            self.dev_cid = dev_cid
+                if hass.data[DOMAIN].get(dev_id):
+                    self._api = hass.data[DOMAIN][dev_id]["tuyadevice"]
+                else:
+                    self._api = tinytuya.Device(dev_id, address, local_key)
+                    hass.data[DOMAIN][dev_id] = {"tuyadevice": self._api}
         except Exception as e:
             _LOGGER.error(
                 "%s: %s while initialising device %s",
@@ -89,7 +98,10 @@ class TuyaLocalDevice(object):
         # we handle retries at a higher level so we can rotate protocol version
         self._api.set_socketRetryLimit(1)
         if self._api.parent:
+            # Retries cause problems for other children of the parent device
+            # Currently, we only support polling for child devices
             self._api.parent.set_socketRetryLimit(1)
+            poll_only = True
 
         self._refresh_task = None
         self._protocol_configured = protocol_version
@@ -651,7 +663,10 @@ def setup_device(hass: HomeAssistant, config: dict):
         hass,
         config[CONF_POLL_ONLY],
     )
-    hass.data[DOMAIN][get_device_id(config)] = {"device": device}
+    hass.data[DOMAIN][get_device_id(config)] = {
+        "device": device,
+        "tuyadevice": device._api,
+    }
 
     return device
 

+ 3 - 1
tests/test_device.py

@@ -14,12 +14,14 @@ class TestDevice(IsolatedAsyncioTestCase):
         device_patcher = patch("tinytuya.Device")
         self.addCleanup(device_patcher.stop)
         self.mock_api = device_patcher.start()
+        self.mock_api().parent = None
 
         hass_patcher = patch("homeassistant.core.HomeAssistant")
         self.addCleanup(hass_patcher.stop)
         self.hass = hass_patcher.start()
         self.hass().is_running = True
         self.hass().is_stopping = False
+        self.hass().data = {"tuya_local": {}}
 
         def job(func, *args):
             return func(*args)
@@ -50,7 +52,7 @@ class TestDevice(IsolatedAsyncioTestCase):
         self.subject._protocol_configured = "auto"
 
     def test_configures_tinytuya_correctly(self):
-        self.mock_api.assert_called_once_with(
+        self.mock_api.assert_called_with(
             "some_dev_id", "some.ip.address", "some_local_key"
         )
         self.assertIs(self.subject._api, self.mock_api())