Skip to content

Commit

Permalink
Minor fixes sub devices (#67)
Browse files Browse the repository at this point in the history
* ensure gateway is connedted if we use it.

* Handle fake_gateway if nodeID Not found. handle other errors

* core: don't switch to `type_0d` if version >= 3.4

* abort connect if unkown error happen

* Handle dc'd sub devices should resolve #66

* Handle dc'd sub devices should resolve #66
  • Loading branch information
xZetsubou committed Nov 13, 2023
1 parent fd4853f commit 6a8cdd4
Show file tree
Hide file tree
Showing 3 changed files with 26 additions and 20 deletions.
24 changes: 13 additions & 11 deletions custom_components/localtuya/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -249,18 +249,18 @@ async def async_connect(self, _now=None) -> None:
async def _make_connection(self):
"""Subscribe localtuya entity events."""
self._connect_task = True
host = self._device_config.get(CONF_HOST)
name = self._device_config.get(CONF_FRIENDLY_NAME)
host = name if self.is_subdevice else self._device_config.get(CONF_HOST)

try:
if self.is_subdevice:
# self.info(f"Connect Sub Device {name} through gateway {host}")
await self.get_gateway()
gateway = self._gwateway
if gateway and not gateway.connected or gateway.is_connecting:
self._connect_task = None
return
self._interface = gateway._interface
# self.info(f"Connect Sub Device {name} through gateway {host}")
else:
# self.info("Trying to connect to %s...", host)
self._interface = await pytuya.connect(
Expand Down Expand Up @@ -294,23 +294,25 @@ async def _make_connection(self):
status = await self._interface.status(cid=self._node_id)
if status is None:
raise Exception("Failed to retrieve status")
if not self.is_subdevice:
if not self._interface.heartbeater:
self._interface.start_heartbeat()
self.status_updated(status)

except UnicodeDecodeError as e: # pylint: disable=broad-except
self.exception(f"Connect to {host} failed: due to: {type(e)}")

await self.abort_connect()

except Exception as e: # pylint: disable=broad-except
self.warning(f"Connect to {host} failed: {e}")
if not (self._fake_gateway and "Not found" in str(e)):
e = "Sub device is not connected" if self.is_subdevice else e
self.warning(f"Connect to {host} failed: {e}")
await self.abort_connect()
if "json.decode" in str(type(e)):
self.warning(f"Initial state update failed {e}, trying key update")
self.info(f"Initial update state failed {e}, trying key update")
await self.update_local_key()
await self.abort_connect()
finally:
pass
except:
if self._fake_gateway:
self.warning(f"Failed to use {name} as gateway.")
await self.abort_connect()

if self._interface is not None:
# Attempt to restore status for all entities that need to first set
Expand Down Expand Up @@ -338,7 +340,7 @@ def _new_entity_handler(entity_id):
)

self._is_closing = False
self.info(f"Success: connected to {name if self.is_subdevice else host}")
self.info(f"Success: connected to {host}")
if self._sub_devices:
connect_sub_devices = [
device.async_connect() for device in self._sub_devices.values()
Expand Down
7 changes: 6 additions & 1 deletion custom_components/localtuya/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -343,7 +343,12 @@ async def validate_input(hass: core.HomeAssistant, entry_id, data):
conf_protocol = data[CONF_PROTOCOL_VERSION]
auto_protocol = conf_protocol == "auto"
# If sub device we will search if gateway is existed if not create new connection.
if cid and (existed_interface := localtuya_devices.get(data[CONF_HOST])):
if (
cid
and (existed_interface := localtuya_devices.get(data[CONF_HOST]))
and existed_interface.connected
and not existed_interface.is_connecting
):
interface = existed_interface._interface
close = False
else:
Expand Down
15 changes: 7 additions & 8 deletions custom_components/localtuya/core/pytuya/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -1155,11 +1155,12 @@ def _decode_payload(self, payload):
# return self.error_json(ERR_JSON, payload)

if "data unvalid" in payload:
self.dev_type = "type_0d"
self.debug(
"'data unvalid' error detected: switching to dev_type %r",
self.dev_type,
)
if self.version <= 3.3:
self.dev_type = "type_0d"
self.debug(
"'data unvalid' error detected: switching to dev_type %r",
self.dev_type,
)
return None
elif not payload.startswith(b"{"):
self.debug("Unexpected payload=%r", payload)
Expand All @@ -1171,13 +1172,11 @@ def _decode_payload(self, payload):
try:
json_payload = json.loads(payload)
except Exception as ex:
if len(payload) == 0: # No respones probably worng Local_Key
raise ValueError("Connected but no respones localkey is incorrect?")
if "devid not" in payload: # DeviceID Not found.
raise ValueError("DeviceID Not found")
else:
raise DecodeError(
"could not decrypt data: wrong local_key? (exception: %s)" % ex
f"could not decrypt data: wrong local_key? (exception: {ex}, payload: {payload})"
)
# json_payload = self.error_json(ERR_JSON, payload)

Expand Down

0 comments on commit 6a8cdd4

Please sign in to comment.