Bläddra i källkod

Avoid switching protocols once communication is working (#37)

* Be less eager about changing protocol.

Once the device is communicating, only switch protocols after the connection retry limit is reached.
This prevents compounding the problem, in particular when v3.3 protocol devices send back responses that pytuya does not handle, as switching to v3.1 seems to cause these devices to go offline for a few minutes sometimes.

Co-authored-by: Jason Rumney <jasonrumney@clarion.com.my>
Jason Rumney 6 år sedan
förälder
incheckning
d539e5887d
2 ändrade filer med 23 tillägg och 1 borttagningar
  1. 4 1
      custom_components/goldair_climate/device.py
  2. 19 0
      tests/test_device.py

+ 4 - 1
custom_components/goldair_climate/device.py

@@ -37,6 +37,7 @@ class GoldairTuyaDevice(object):
 
         self._name = name
         self._api_protocol_version_index = None
+        self._api_protocol_working = False
         self._api = pytuya.Device(dev_id, address, local_key, "device")
         self._refresh_task = None
         self._rotate_api_protocol_version()
@@ -198,13 +199,15 @@ class GoldairTuyaDevice(object):
         for i in range(self._CONNECTION_ATTEMPTS):
             try:
                 func()
+                self._api_protocol_working = True
                 break
             except Exception as e:
                 _LOGGER.debug(f"Retrying after exception {e}")
                 if i + 1 == self._CONNECTION_ATTEMPTS:
                     self._reset_cached_state()
+                    self._api_protocol_working = False
                     _LOGGER.error(error_message)
-                else:
+                elif self._api_protocol_working is False:
                     self._rotate_api_protocol_version()
 
     def _get_cached_state(self):

+ 19 - 0
tests/test_device.py

@@ -202,6 +202,25 @@ class TestDevice(IsolatedAsyncioTestCase):
             [call(3.1), call(3.3), call(3.1)]
         )
 
+    def test_api_protocol_version_is_stable_once_successful(self):
+        self.subject._api.set_version.assert_called_once_with(3.3)
+        self.subject._api.set_version.reset_mock()
+
+        self.subject._api.status.side_effect = [
+            {"dps": {"1": False}},
+            Exception("Error"),
+            Exception("Error"),
+            Exception("Error"),
+            Exception("Error"),
+            Exception("Error"),
+            Exception("Error"),
+        ]
+        self.subject.refresh()
+        self.subject.refresh()
+        self.subject.refresh()
+
+        self.subject._api.set_version.assert_has_calls([call(3.1), call(3.3)])
+
     def test_reset_cached_state_clears_cached_state_and_pending_updates(self):
         self.subject._cached_state = {"1": True, "updated_at": time()}
         self.subject._pending_updates = {"1": False}