فهرست منبع

Use tinytuya set_multiple_values API function to send.

When this was originally developed, the only way to set arbitrary dps
was to work with low level functions, generating the payload then
sending it.

Over time, tinytuya has evolved with a more complete API, so there is
a higher level function to do what we want.

Currently it looks like it basically does the same as what we were
doing, but with new Tuya protocol versions coming all the time, and
workarounds for device issues being built in to tinytuya, it may pick
up extra functionality at some point, which we would miss by rolling
our own using lower level functions.

There is a minor performance hit in the case where we need resends,
but actually it looks like resends are handled at a lower level in
tinytuya anyway.

Unlikely based on review of the code, but may help with #338 and #372.
Jason Rumney 3 سال پیش
والد
کامیت
8b35f43e09
2فایلهای تغییر یافته به همراه10 افزوده شده و 12 حذف شده
  1. 4 8
      custom_components/tuya_local/device.py
  2. 6 4
      tests/test_device.py

+ 4 - 8
custom_components/tuya_local/device.py

@@ -370,29 +370,25 @@ class TuyaLocalDevice(object):
 
     async def _send_pending_updates(self):
         pending_properties = self._get_unsent_properties()
-        payload = self._api.generate_payload(
-            tinytuya.CONTROL,
-            pending_properties,
-        )
 
         _LOGGER.debug(
             f"{self.name} sending dps update: {json.dumps(pending_properties, default=non_json)}"
         )
 
         await self._retry_on_failed_connection(
-            lambda: self._send_payload(payload),
+            lambda: self._set_values(pending_properties),
             "Failed to update device state.",
         )
 
-    def _send_payload(self, payload):
+    def _set_values(self, properties):
         try:
             self._lock.acquire()
-            self._api.send(payload)
+            self._api.set_multiple_values(properties, nowait=True)
             self._cached_state["updated_at"] = 0
             now = time()
             self._last_connection = now
             pending_updates = self._get_pending_updates()
-            for key in list(pending_updates):
+            for key in properties.keys():
                 pending_updates[key]["updated_at"] = now
                 pending_updates[key]["sent"] = True
         finally:

+ 6 - 4
tests/test_device.py

@@ -277,7 +277,7 @@ class TestDevice(IsolatedAsyncioTestCase):
     async def test_async_set_property_sends_to_api(self):
         await self.subject.async_set_property("1", False)
 
-        self.mock_api().send.assert_called_once()
+        self.mock_api().set_multiple_values.assert_called_once()
 
     async def test_set_property_immediately_stores_pending_updates(self):
         self.subject._cached_state = {"1": True}
@@ -335,17 +335,19 @@ class TestDevice(IsolatedAsyncioTestCase):
             delta=2,
         )
 
-    def test_send_payload(self):
+    def test_set_values(self):
         # set up preconditions
         self.subject._pending_updates = {
             "1": {"value": "sample", "updated_at": time() - 2, "sent": False},
         }
 
         # call the function under test
-        self.subject._send_payload("PAYLOAD")
+        self.subject._set_values({"1": "sample"})
 
         # did it send what it was asked?
-        self.mock_api().send.assert_called_once_with("PAYLOAD")
+        self.mock_api().set_multiple_values.assert_called_once_with(
+            {"1": "sample"}, nowait=True
+        )
         # did it mark the pending updates as sent?
         self.assertTrue(self.subject._pending_updates["1"]["sent"])
         # did it update the time on the pending updates?