Переглянути джерело

fix (device): slow down excessive heartbeats

Observed in some logs that data is coming very fast from the device, with multiple
received messages within a second window in the debug log, including some very large
diagnostic messages with one particular device.
This appears to be because we wait only 0.1s each time around the loop which things
are going smoothly, only waiting 5s when there has been an error, to give the device
some time to recover. Although the gap between full polls is set at 30s, we were sending
a heartbeat every time around the loop when it was not due for a full poll, which forces
the device to reply straight away. Actually we only want to send heartbeats often enough
to stop the connection dropping (<30s, so every 10s is often enough), and just listen for
unsolicited data from the device the rest of the time.

Default timeout for receive is 5s, so we should still get a heartbeat in after a maximum
15.1s after this change.
Jason Rumney 1 тиждень тому
батько
коміт
50308ed4d2
1 змінених файлів з 10 додано та 4 видалено
  1. 10 4
      custom_components/tuya_local/device.py

+ 10 - 4
custom_components/tuya_local/device.py

@@ -149,6 +149,7 @@ class TuyaLocalDevice(object):
         # its switches.
         # its switches.
         self._FAKE_IT_TIMEOUT = 5
         self._FAKE_IT_TIMEOUT = 5
         self._CACHE_TIMEOUT = 30
         self._CACHE_TIMEOUT = 30
+        self._HEARTBEAT_INTERVAL = 10
         # More attempts are needed in auto mode so we can cycle through all
         # More attempts are needed in auto mode so we can cycle through all
         # the possibilities a couple of times
         # the possibilities a couple of times
         self._AUTO_CONNECTION_ATTEMPTS = len(API_PROTOCOL_VERSIONS) * 2 + 1
         self._AUTO_CONNECTION_ATTEMPTS = len(API_PROTOCOL_VERSIONS) * 2 + 1
@@ -315,6 +316,7 @@ class TuyaLocalDevice(object):
         while self._running:
         while self._running:
             error_count = self._api_working_protocol_failures
             error_count = self._api_working_protocol_failures
             force_backoff = False
             force_backoff = False
+            last_heartbeat = self._cached_state.get("updated_at", 0)
             try:
             try:
                 await self._api_lock.acquire()
                 await self._api_lock.acquire()
                 last_cache = self._cached_state.get("updated_at", 0)
                 last_cache = self._cached_state.get("updated_at", 0)
@@ -355,11 +357,15 @@ class TuyaLocalDevice(object):
                         dps_updated = False
                         dps_updated = False
                         full_poll = True
                         full_poll = True
                     self._last_full_poll = now
                     self._last_full_poll = now
+                    last_heartbeat = now  # reset heartbeat timer on full poll
                 elif persist:
                 elif persist:
-                    await self._hass.async_add_executor_job(
-                        self._api.heartbeat,
-                        True,
-                    )
+                    if now - last_heartbeat > self._HEARTBEAT_INTERVAL:
+                        await self._hass.async_add_executor_job(
+                            self._api.heartbeat,
+                            True,
+                        )
+                        last_heartbeat = now
+
                     poll = await self._hass.async_add_executor_job(
                     poll = await self._hass.async_add_executor_job(
                         self._api.receive,
                         self._api.receive,
                     )
                     )