Skip to content

Commit

Permalink
Fix bugs in pytuya
Browse files Browse the repository at this point in the history
This handles responses without a return code and also fixes support for
unencrypted clients. Made a few tweaks to debug logs as well.
  • Loading branch information
postlund committed Oct 19, 2020
1 parent 1d83055 commit e98c4a6
Showing 1 changed file with 17 additions and 11 deletions.
28 changes: 17 additions & 11 deletions custom_components/localtuya/pytuya/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -228,19 +228,25 @@ def add_data(self, data):
break

# length includes payload length, retcode, crc and suffix
payload_length = length - 4 - struct.calcsize(MESSAGE_END_FMT)
payload = self.buffer[header_len : header_len + payload_length]
if (retcode & 0xFFFFFF00) != 0:
payload_start = header_len - 4
payload_length = length - struct.calcsize(MESSAGE_END_FMT)
else:
payload_start = header_len
payload_length = length - 4 - struct.calcsize(MESSAGE_END_FMT)
payload = self.buffer[payload_start : payload_start + payload_length]

crc, _ = struct.unpack_from(
MESSAGE_END_FMT,
self.buffer[header_len + payload_length : header_len + length],
self.buffer[payload_start + payload_length : payload_start + length],
)

self.buffer = self.buffer[header_len + length - 4 :]
self.buffer = self.buffer[header_len - 4 + length :]
self._dispatch(TuyaMessage(seqno, cmd, retcode, payload, crc))

def _dispatch(self, msg):
"""Dispatch a message to someone that is listening."""
_LOGGER.debug("Dispatching message %s", msg)
if msg.seqno in self.listeners:
self.log.debug("Dispatching sequence number %d", msg.seqno)
sem = self.listeners[msg.seqno]
Expand All @@ -258,7 +264,7 @@ def _dispatch(self, msg):
else:
self.log.debug(
"Got message type %d for unknown listener %d: %s",
msg.command,
msg.cmd,
msg.seqno,
msg,
)
Expand Down Expand Up @@ -459,14 +465,14 @@ async def detect_available_dps(self):
try:
data = await self.status()
except Exception as e:
self.log.warning("Failed to get status: %s", e)
self.log.exception("Failed to get status: %s", e)
raise
if "dps" in data:
self.dps_cache.update(data["dps"])

if self.dev_type == "type_0a":
return self.dps_cache
self.log.debug("detected dps: %s", self.dps_cache)
self.log.debug("Detected dps: %s", self.dps_cache)
return self.dps_cache

def add_dps_to_request(self, dp_indicies):
Expand All @@ -477,10 +483,10 @@ def add_dps_to_request(self, dp_indicies):
self.dps_to_request.update({str(index): None for index in dp_indicies})

def _decode_payload(self, payload):
self.log.debug("Decode payload: %s", payload)

if not payload:
payload = "{}"
elif payload.startswith(b"{"):
payload = payload
elif payload.startswith(PROTOCOL_VERSION_BYTES_31):
payload = payload[len(PROTOCOL_VERSION_BYTES_31) :] # remove version header
# remove (what I'm guessing, but not confirmed is) 16-bytes of MD5
Expand All @@ -500,7 +506,7 @@ def _decode_payload(self, payload):
self.dev_type,
)
return None
elif not payload.startswith(b"{"):
else:
raise Exception(f"Unexpected payload={payload} (id: {self.id})")

if not isinstance(payload, str):
Expand Down Expand Up @@ -537,7 +543,7 @@ def _generate_payload(self, command, data=None):
json_data["dps"] = self.dps_to_request

payload = json.dumps(json_data).replace(" ", "").encode("utf-8")
self.log.debug("Paylod: %s", payload)
self.log.debug("Send paylod: %s", payload)

if self.version == 3.3:
payload = self.cipher.encrypt(payload, False)
Expand Down

0 comments on commit e98c4a6

Please sign in to comment.