Skip to content

Improve retry logic for discovery, messaging (was: Handle empty responses) #38

@acmay

Description

@acmay

I have a device outside with an RSSI of -78 that sometimes returns data and sometimes doesn't. There is also multiple wireless video feeds that are going on at the same time as well that probably don't help.

I did this to get past the first exception on the unpack of empty data but it still fails later on. Not sure the best spot to put some extra retry logic.

diff --git a/kasa/protocol.py b/kasa/protocol.py
index f29b4be..60368f0 100755
--- a/kasa/protocol.py
+++ b/kasa/protocol.py
@@ -57,6 +57,10 @@ class TPLinkSmartHomeProtocol:
             while True:
                 chunk = await reader.read(4096)
                 if length == -1:
+                    if len(chunk) < 4:
+                        _LOGGER.error("Request %s:%s Failed to get response",
+                                      host, request)
+                        break
                     length = struct.unpack(">I", chunk[0:4])[0]
                 buffer += chunk
                 if (length > 0 and len(buffer) >= length + 4) or not chunk:
@@ -66,7 +70,10 @@ class TPLinkSmartHomeProtocol:
                 writer.close()
                 await writer.wait_closed()
 
-        response = TPLinkSmartHomeProtocol.decrypt(buffer[4:])
+        if len(buffer) > 4:
+            response = TPLinkSmartHomeProtocol.decrypt(buffer[4:])
+        else:
+            response = ""
         _LOGGER.debug("< (%i) %s", len(response), response)
 
         return json.loads(response)

Here are the logs of a good and failed run.

acmay@mud:~/src/hass/python-kasa$ PYTHONPATH=`pwd` python3 kasa/cli.py --host 192.168.1.28 sysinfo
No --strip nor --bulb nor --plug given, discovering..
== System info ==
{'alias': 'TP-LINK_Smart Plug_2ECE',
 'child_num': 2,
 'children': [{'alias': 'Rope',
               'id': 'XXXX',
               'next_action': {'action': 1, 'schd_sec': 69240, 'type': 1},
               'on_time': 0,
               'state': 0},
              {'alias': 'Plug 2',
               'id': 'XXXX',
               'next_action': {'type': -1},
               'on_time': 0,
               'state': 0}],
 'deviceId': 'XXX',
 'feature': 'TIM',
 'hwId': 'XXXX',
 'hw_ver': '1.0',
 'latitude_i': XXXX,
 'led_off': 0,
 'longitude_i': XXXXX,
 'mac': 'XXXX',
 'mic_type': 'IOT.SMARTPLUGSWITCH',
 'model': 'KP400(US)',
 'ntc_state': 0,
 'oemId': 'XXXX',
 'rssi': -78,
 'status': 'new',
 'sw_ver': '1.0.10 Build 190716 Rel.095026',
 'updating': 0}
acmay@mud:~/src/hass/python-kasa$ PYTHONPATH=`pwd` python3 kasa/cli.py --host 192.168.1.28 sysinfo
No --strip nor --bulb nor --plug given, discovering..
ERROR:kasa.protocol:Request 192.168.1.28:{"system": {"get_sysinfo": null}, "emeter": {"get_realtime": null}, "smartlife.iot.dimmer": {"get_dimmer_parameters": null}, "smartlife.iot.common.emeter": {"get_realtime": null}, "smartlife.iot.smartbulb.lightingservice": {"get_light_state": null}} Failed to get response
Traceback (most recent call last):
  File "kasa/cli.py", line 391, in <module>
    cli()
  File "/home/acmay/.local/lib/python3.7/site-packages/click/core.py", line 829, in __call__
    return self.main(*args, **kwargs)
  File "/home/acmay/.local/lib/python3.7/site-packages/click/core.py", line 782, in main
    rv = self.invoke(ctx)
  File "/home/acmay/.local/lib/python3.7/site-packages/click/core.py", line 1256, in invoke
    Command.invoke(self, ctx)
  File "/home/acmay/.local/lib/python3.7/site-packages/click/core.py", line 1066, in invoke
    return ctx.invoke(self.callback, **ctx.params)
  File "/home/acmay/.local/lib/python3.7/site-packages/click/core.py", line 610, in invoke
    return callback(*args, **kwargs)
  File "/home/acmay/.local/lib/python3.7/site-packages/click/decorators.py", line 21, in new_func
    return f(get_current_context(), *args, **kwargs)
  File "kasa/cli.py", line 68, in cli
    dev = asyncio.run(Discover.discover_single(host))
  File "/usr/lib/python3.7/asyncio/runners.py", line 43, in run
    return loop.run_until_complete(main)
  File "/usr/lib/python3.7/asyncio/base_events.py", line 584, in run_until_complete
    return future.result()
  File "/home/acmay/src/hass/python-kasa/kasa/discover.py", line 176, in discover_single
    info = await protocol.query(host, Discover.DISCOVERY_QUERY)
  File "/home/acmay/src/hass/python-kasa/kasa/protocol.py", line 79, in query
    return json.loads(response)
  File "/usr/lib/python3.7/json/__init__.py", line 348, in loads
    return _default_decoder.decode(s)
  File "/usr/lib/python3.7/json/decoder.py", line 337, in decode
    obj, end = self.raw_decode(s, idx=_w(s, 0).end())
  File "/usr/lib/python3.7/json/decoder.py", line 355, in raw_decode
    raise JSONDecodeError("Expecting value", s, err.value) from None
json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions