Skip to content

Commit 03e1f05

Browse files
authored
Merge pull request #298 from uzlonewolf/zbgw
Updates for Zigbee Gateway sub-device usage
2 parents 8c32950 + 36f2bb0 commit 03e1f05

File tree

2 files changed

+30
-10
lines changed

2 files changed

+30
-10
lines changed

examples/zigbee_gateway.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,14 @@
55
# connected and then one or more children are added.
66

77
# configure the parent device
8+
# address=None will cause it to search the network for the device
89
gw = tinytuya.Device( 'eb...4', address=None, local_key='aabbccddeeffgghh', persist=True, version=3.3 )
910

1011
print( 'GW IP found:', gw.address )
1112

1213
# configure one or more children. Every dev_id must be unique!
14+
# cid is the "node_id" from devices.json
15+
# node_id can be used as an alias for cid
1316
zigbee1 = tinytuya.OutletDevice( 'eb14...w', cid='0011223344556601', parent=gw )
1417
zigbee2 = tinytuya.OutletDevice( 'eb04...l', cid='0011223344556689', parent=gw )
1518

tinytuya/core.py

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@
1010
1111
Classes
1212
* AESCipher - Cryptography Helpers
13-
* XenonDevice(dev_id, address=None, local_key="", dev_type="default", connection_timeout=5, version="3.1", persist=False) - Base Tuya Objects and Functions
13+
* XenonDevice(...) - Base Tuya Objects and Functions
14+
XenonDevice(dev_id, address=None, local_key="", dev_type="default", connection_timeout=5, version="3.1", persist=False, cid/node_id=None, parent=None)
1415
* Device(XenonDevice) - Tuya Class for Devices
1516
1617
Functions
@@ -675,23 +676,25 @@ def device_info( dev_id ):
675676

676677
class XenonDevice(object):
677678
def __init__(
678-
self, dev_id, address=None, local_key="", dev_type="default", connection_timeout=5, version=3.1, persist=False, cid=None, parent=None # pylint: disable=W0621
679+
self, dev_id, address=None, local_key="", dev_type="default", connection_timeout=5, version=3.1, persist=False, cid=None, node_id=None, parent=None # pylint: disable=W0621
679680
):
680681
"""
681682
Represents a Tuya device.
682683
683684
Args:
684685
dev_id (str): The device id.
685-
cid (str: Optional sub device id. Default to None.
686686
address (str): The network address.
687687
local_key (str, optional): The encryption key. Defaults to None.
688+
cid (str: Optional sub device id. Default to None.
689+
node_id (str: alias for cid)
690+
parent (object: gateway device this device is a child of)
688691
689692
Attributes:
690693
port (int): The port to connect to.
691694
"""
692695

693696
self.id = dev_id
694-
self.cid = cid
697+
self.cid = cid if cid else node_id
695698
self.address = address
696699
self.connection_timeout = connection_timeout
697700
self.retry = True
@@ -716,14 +719,25 @@ def __init__(
716719

717720
if not local_key:
718721
local_key = ""
719-
devinfo = device_info( dev_id )
720-
if devinfo and 'key' in devinfo and devinfo['key']:
721-
local_key = devinfo['key']
722+
# sub-devices do not need a local key, so only look it up if we are not a sub-device
723+
if not parent:
724+
devinfo = device_info( dev_id )
725+
if devinfo and 'key' in devinfo and devinfo['key']:
726+
local_key = devinfo['key']
722727
self.local_key = local_key.encode("latin1")
723728
self.real_local_key = self.local_key
724729
self.cipher = None
725730

726731
if self.parent:
732+
# if we are a child then we should have a cid/node_id but none were given - try and find it the same way we look up local keys
733+
if not self.cid:
734+
devinfo = device_info( dev_id )
735+
if devinfo and 'node_id' in devinfo and devinfo['node_id']:
736+
self.cid = devinfo['node_id']
737+
if not self.cid:
738+
# not fatal as the user could have set the device_id to the cid
739+
# in that case dev_type should be 'zigbee' to set the proper fields in requests
740+
log.debug( 'Child device but no cid/node_id given!' )
727741
XenonDevice.set_version(self, self.parent.version)
728742
self.parent._register_child(self)
729743
elif (not address) or address == "Auto" or address == "0.0.0.0":
@@ -742,8 +756,11 @@ def __init__(
742756
# them (such as BulbDevice) make connections when called
743757
XenonDevice.set_version(self, 3.1)
744758

745-
if cid and self.dev_type == 'default':
759+
if self.cid and self.dev_type == 'default':
746760
self.dev_type = 'zigbee'
761+
elif self.dev_type == 'zigbee' and not self.cid:
762+
# this probably won't work, but it might
763+
log.debug( 'Zigbee device but no cid/node_id given, using dev_id as the cid!' )
747764

748765
def __del__(self):
749766
# In case we have a lingering socket connection, close it
@@ -1101,8 +1118,8 @@ def _process_message( self, msg, dev_type=None, from_child=None, minresponse=28,
11011118
else:
11021119
result = self._process_response(result)
11031120
self.received_wrong_cid_queue.append( (found_child, result) )
1104-
# do not pass from_child this time to make sure we do not get stuck in a loop
1105-
return self._send_receive( None, minresponse, True, decode_response, from_child=True)
1121+
# events should not be coming in so fast that we will never timeout a read, so don't worry about loops
1122+
return self._send_receive( None, minresponse, True, decode_response, from_child=from_child)
11061123

11071124
# legacy/default mode avoids persisting socket across commands
11081125
self._check_socket_close()

0 commit comments

Comments
 (0)