Parcourir la source

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 il y a 1 an
Parent
commit
dd03747ee5
2 fichiers modifiés avec 22 ajouts et 5 suppressions
  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_version_index = None
         self._api_protocol_working = False
         self._api_protocol_working = False
         self._api_working_protocol_failures = 0
         self._api_working_protocol_failures = 0
+        self.dev_cid = dev_cid
         try:
         try:
             if dev_cid:
             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(
                 self._api = tinytuya.Device(
                     dev_id,
                     dev_id,
                     cid=dev_cid,
                     cid=dev_cid,
-                    parent=tinytuya.Device(dev_id, address, local_key),
+                    parent=parent,
                 )
                 )
             else:
             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:
         except Exception as e:
             _LOGGER.error(
             _LOGGER.error(
                 "%s: %s while initialising device %s",
                 "%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
         # we handle retries at a higher level so we can rotate protocol version
         self._api.set_socketRetryLimit(1)
         self._api.set_socketRetryLimit(1)
         if self._api.parent:
         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)
             self._api.parent.set_socketRetryLimit(1)
+            poll_only = True
 
 
         self._refresh_task = None
         self._refresh_task = None
         self._protocol_configured = protocol_version
         self._protocol_configured = protocol_version
@@ -651,7 +663,10 @@ def setup_device(hass: HomeAssistant, config: dict):
         hass,
         hass,
         config[CONF_POLL_ONLY],
         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
     return device
 
 

+ 3 - 1
tests/test_device.py

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