Add support for passive devices (#171)

* Add support for passive devices

* Fix a few issues

* Fix broken handling of closing a connection

This fixes the following error:

  AttributeError: 'NoneType' object has no attribute 'write'

* Always use discovery broadcasts to trigger connects

From now on there's no connect loop but all attempts are initiated by
received discovery messages.

* Fix cancelling of heartbeat task

* Verify entry has been loaded before connecting

* Don't reset seqno when switching to type_d device
This commit is contained in:
Pierre Ståhl
2020-12-15 09:08:46 +01:00
committed by GitHub
parent 1d58abd0f2
commit 10e55e67b4
3 changed files with 45 additions and 54 deletions

View File

@@ -362,7 +362,7 @@ class TuyaProtocol(asyncio.Protocol, ContextualLogger):
if "dps" in decoded_message:
self.dps_cache.update(decoded_message["dps"])
listener = self.listener()
listener = self.listener and self.listener()
if listener is not None:
listener.status_updated(self.dps_cache)
@@ -377,12 +377,17 @@ class TuyaProtocol(asyncio.Protocol, ContextualLogger):
while True:
try:
await self.heartbeat()
await asyncio.sleep(HEARTBEAT_INTERVAL)
except asyncio.CancelledError:
self.debug("Stopped heartbeat loop")
raise
except Exception as ex:
self.exception("Heartbeat failed (%s), disconnecting", ex)
break
await asyncio.sleep(HEARTBEAT_INTERVAL)
self.debug("Stopped heartbeat loop")
self.close()
transport = self.transport
self.transport = None
transport.close()
self.transport = transport
self.on_connected.set_result(True)
@@ -396,24 +401,25 @@ class TuyaProtocol(asyncio.Protocol, ContextualLogger):
"""Disconnected from device."""
self.debug("Connection lost: %s", exc)
try:
self.close()
listener = self.listener and self.listener()
if listener is not None:
listener.disconnected()
except Exception:
self.exception("Failed to close connection")
finally:
try:
listener = self.listener()
if listener is not None:
listener.disconnected(exc)
except Exception:
self.exception("Failed to call disconnected callback")
self.exception("Failed to call disconnected callback")
def close(self):
async def close(self):
"""Close connection and abort all outstanding listeners."""
self.debug("Closing connection")
if self.heartbeater is not None:
self.heartbeater.cancel()
try:
await self.heartbeater
except asyncio.CancelledError:
pass
self.heartbeater = None
if self.dispatcher is not None:
self.dispatcher.abort()
self.dispatcher = None
if self.transport is not None:
transport = self.transport
self.transport = None
@@ -572,7 +578,7 @@ class TuyaProtocol(asyncio.Protocol, ContextualLogger):
if data is not None:
json_data["dps"] = data
if command_hb == 0x0D:
elif command_hb == 0x0D:
json_data["dps"] = self.dps_to_request
payload = json.dumps(json_data).replace(" ", "").encode("utf-8")