@@ -83,6 +83,7 @@ def __init__(self, apiRegion=None, apiKey=None, apiSecret=None, apiDeviceID=None
8383 self .error = None
8484 self .new_sign_algorithm = new_sign_algorithm
8585 self .server_time_offset = 0
86+ self .use_old_device_list = False
8687
8788 if (not apiKey ) or (not apiSecret ):
8889 try :
@@ -93,7 +94,8 @@ def __init__(self, apiRegion=None, apiKey=None, apiSecret=None, apiDeviceID=None
9394 self .apiRegion = config ['apiRegion' ]
9495 self .apiKey = config ['apiKey' ]
9596 self .apiSecret = config ['apiSecret' ]
96- self .apiDeviceID = config ['apiDeviceID' ]
97+ if 'apiDeviceID' in config :
98+ self .apiDeviceID = config ['apiDeviceID' ]
9799 except :
98100 self .error = error_json (
99101 ERR_CLOUDKEY ,
@@ -305,24 +307,63 @@ def cloudrequest(self, url, action=None, post=None, query=None):
305307 action = 'POST' if post else 'GET'
306308 return self ._tuyaplatform (url , action = action , post = post , ver = None , query = query )
307309
310+ def _get_all_devices (self ):
311+ fetches = 0
312+ our_result = { 'result' : [] }
313+ last_row_key = None
314+ has_more = True
315+ total = 0
316+ query = {'size' :'50' }
317+
318+ while has_more :
319+ # API docu: https://developer.tuya.com/en/docs/cloud/fc19523d18?id=Kakr4p8nq5xsc
320+ result = self .cloudrequest ( '/v1.0/iot-01/associated-users/devices' , query = query )
321+ fetches += 1
322+ has_more = False
323+
324+ if type (result ) == dict :
325+ log .debug ( 'Cloud response:' )
326+ log .debug ( json .dumps ( result , indent = 2 ) )
327+ else :
328+ log .debug ( 'Cloud response: %r' , result )
329+
330+ # format it the same as before, basically just moves result->devices into result
331+ for i in result :
332+ if i == 'result' :
333+ our_result [i ] += result [i ]['devices' ]
334+ if 'total' in result [i ]: total = result [i ]['total' ]
335+ if 'last_row_key' in result [i ]:
336+ has_more = result [i ]['has_more' ]
337+ query ['last_row_key' ] = result [i ]['last_row_key' ]
338+ else :
339+ our_result [i ] = result [i ]
340+
341+ our_result ['fetches' ] = fetches
342+ our_result ['total' ] = total
343+
344+ return our_result
345+
308346 def getdevices (self , verbose = False ):
309347 """
310348 Return dictionary of all devices.
311349 If verbose is true, return full Tuya device
312350 details.
313351 """
314- uid = self ._getuid (self .apiDeviceID )
315- if uid is None :
316- return error_json (
317- ERR_CLOUD ,
318- "Unable to get uid for device list"
319- )
320- elif isinstance ( uid , dict ):
321- return uid
352+ if self .apiDeviceID and self .use_old_device_list :
353+ uid = self ._getuid (self .apiDeviceID )
354+ if uid is None :
355+ return error_json (
356+ ERR_CLOUD ,
357+ "Unable to get uid for device list"
358+ )
359+ elif isinstance ( uid , dict ):
360+ return uid
322361
323- # Use UID to get list of all Devices for User
324- uri = 'users/%s/devices' % uid
325- json_data = self ._tuyaplatform (uri )
362+ # Use UID to get list of all Devices for User
363+ uri = 'users/%s/devices' % uid
364+ json_data = self ._tuyaplatform (uri )
365+ else :
366+ json_data = self ._get_all_devices ()
326367
327368 if verbose :
328369 return json_data
@@ -335,26 +376,41 @@ def getdevices(self, verbose=False):
335376 # Filter to only Name, ID and Key
336377 return self .filter_devices ( json_data ['result' ] )
337378
379+ def _get_hw_addresses ( self , maclist , devices ):
380+ while devices :
381+ # returns id, mac, uuid (and sn if available)
382+ uri = 'devices/factory-infos?device_ids=%s' % ("," .join (devices [:50 ]))
383+ result = self ._tuyaplatform (uri )
384+ log .debug ( json .dumps ( result , indent = 2 ) )
385+ if 'result' in result :
386+ for dev in result ['result' ]:
387+ if 'id' in dev :
388+ dev_id = dev ['id' ]
389+ del dev ['id' ]
390+ maclist [dev_id ] = dev
391+ devices = devices [50 :]
392+
338393 def filter_devices ( self , devs , ip_list = None ):
339- # Use Device ID to get MAC addresses
340- uri = 'devices/factory-infos?device_ids=%s' % ( "," . join ( i [ 'id' ] for i in devs ))
341- json_mac_data = self ._tuyaplatform ( uri )
394+ json_mac_data = {}
395+ # mutable json_mac_data will be modified
396+ self ._get_hw_addresses ( json_mac_data , [ i [ 'id' ] for i in devs ] )
342397
343398 tuyadevices = []
344399 icon_host = 'https://images.' + self .urlhost .split ( '.' , 1 )[1 ] + '/'
345400
346401 for i in devs :
347- item = {}
348- item ['name' ] = i ['name' ].strip ()
349- item ['id' ] = i ['id' ]
350- item ['key' ] = i ['local_key' ]
351- if 'mac' in i :
352- item ['mac' ] = i ['mac' ]
353- else :
354- try :
355- item ['mac' ] = next ((m ['mac' ] for m in json_mac_data ['result' ] if m ['id' ] == i ['id' ]), "" )
356- except :
357- pass
402+ dev_id = i ['id' ]
403+ item = {
404+ 'name' : '' if 'name' not in i else i ['name' ].strip (),
405+ 'id' : dev_id ,
406+ 'key' : '' if 'local_key' not in i else i ['local_key' ],
407+ 'mac' : '' if 'mac' not in i else i ['mac' ]
408+ }
409+
410+ if dev_id in json_mac_data :
411+ for k in ('mac' ,'uuid' ,'sn' ):
412+ if k in json_mac_data [dev_id ]:
413+ item [k ] = json_mac_data [dev_id ][k ]
358414
359415 if ip_list and 'mac' in item and item ['mac' ] in ip_list :
360416 item ['ip' ] = ip_list [item ['mac' ]]
0 commit comments