
    jhO                       d Z ddlmZ ddlmZ ddlZddlZddlZddlZddl	Z	ddl
Z
ddlZddlZddlZddlZddlZ	 ddlmZ dZexs e
j(                  j+                  d       Z	 eZ	 ddlZdZ	 ddlZdZer e        ej<                  Zej>                  Zej@                  Z ejB                  Z!ejD                  Z"ejF                  Z#ejH                  Z$ejJ                  Z%ejL                  Z&ejN                  Z'ejP                  Z(d	Z)d
Z*dZ+dZ, edd      Z-dZ.dZ/dZ0dZ1dZ2dZ3d	Z4dZ5dZ6 ejn                  e8      Z9d Z:d Z;d Z<d Z=d Z>d Z?d4dZ@ G d deA      ZB G d deA      ZC G d  d!eC      ZD G d" d#eC      ZEd5d$ZFd% ZGd6d&ZHddddddddddddg dfd'ZId( ZJd) ZKd* ZLd+ ZMd, ZNd- ZOd4d.ZPd7d/ZQd8d0ZRd9d1ZSd2 ZTe8d3k(  r		  eF        yy# e$ r dZY w xY w# e$ r Y yw xY w# e$ r dZY w xY w# e$ r dZY w xY w# eU$ r Y yw xY w):aT  
TinyTuya Network Scanner for Tuya based WiFi smart devices

Author: Jason A. Cox
For more information see https://github.com/jasonacox/tinytuya

Description
    Scan will scan the local network for Tuya devices and if a local devices.json is
    present in the local directory, will use the Local KEYs to poll the devices for
    status.

    )print_function)
namedtupleN)initTFwin   i,     )ipmacnamekeygwIdactiveabilityencrypt
productKeyversiontokenwf_cfg
TermColorsz>bold, subbold, normal, dim, alert, alertdim, cyan, red, yellow               d   c                      t        j                   t         j                  t         j                        } | j                  d       t	        | j                         d         }| j                          |S )N)z8.8.8.8P   r   )socketAF_INET
SOCK_DGRAMconnectstrgetsocknameclose)srs     =/DATA/.local/lib/python3.12/site-packages/tinytuya/scanner.pygetmyIPaddrr(   k   sK    fnnf&7&78AIIoAMMOAAGGIH    c                  V    t               j                  d      } dt        | d d       z  S )N.z%s.%s.%s.0/24r   )r(   splittuple)r&   s    r'   getmyIPr.   s   s)    C AU1Ra5\))r)   c                 P    t         rt        | ||      S t        rt        | ||      S y N)	NETIFLIBSgetmyIPs_via_netifacesPSULIBSgetmyIPs_via_psutil)termverboseasks      r'   getmyIPsr8   x   s)    %tWc;;"D'388r)   c                    i }t        j                         }	 |j                  d       |D ]  }t        j                  |      }|j	                  t         j
                        }|s;|D ]  }t        t        j                  |d   dz   |d   z         j                        }	|	d d dk(  r@|ru|dk7  rpt        | j                  d|	d	t        |      d
| j                  d      }
|
dd j                         dk(  rd}n#|
j                         j                  d      dk\  r|rt        | j                   dz   |	d       d||	<     |j#                         S #  Y 1xY w)Nloaddr/netmaskr   127.r   Scan network  from interface ? ([Y]es/[n]o/[a]ll yes): r   r   anAdding Networkto the force-scan listT)	netifaces
interfacesremoveifaddressesgetr   r"   	ipaddressIPv4Interfacenetworkinputboldnormallowerfindprintdimkeys)r5   r6   r7   ipsrH   	interface	addressesfamily_addressesaddresskanswers              r'   r2   r2      sg   
C%%'J$  	)))4	$==):):;'GI++GFOC,?	@R,RS[[\A!u!8"imirirtuwz  |E  xF  HL  HS  HS  %T  VFa{((*c1,,S1Q6 dhh!1116NOCF (  , 88:1s   E Ec                 ~   i }t        j                         }|D ]  }||   }|D ]  }|j                  t        j                  k7  r"t        t        j                  |j                  dz   |j                  z         j                        }|d d dk(  rm|ru|dk7  rpt        | j                  d|dt        |      d| j                  d      }	|	d	d
 j                         dk(  rd}n#|	j                         j                  d      d	k\  r|rt!        | j"                  dz   |d       d||<     |j%                         S )Nr<   r   r>   r   r?   r@   rA   rB   r   r   rC   rD   rE   rF   T)psutilnet_if_addrsfamilyr   r   r"   rL   rM   r[   r=   rN   rO   rP   rQ   rR   rS   rT   rU   rV   )
r5   r6   r7   rW   rH   rX   rY   r;   r\   r]   s
             r'   r4   r4      s9   
C$$&J	y)	D{{fnn,I++DLL,<T\\,IJRRSA!u!8"imirirtuwz  |E  xF  HL  HS  HS  %T  VFa{((*c1,,S1Q6 dhh!1116NOCF!   & 88:r)   c                  v   i } t         r~t        j                         }|D ]a  }t        j                  |      }|j	                  t        j
                        }|s:|D ]#  }d|v sd|v s|d   |d   k7  s|d   | |d   <   % c | r| S t        rt        j                         }|j                         D ]t  }|D ]m  }|j                  t        j
                  k(  s!|j                  s.|j                  s;|j                  |j                  k7  sU|j                  | |j                  <   o v | r| S t               | d<   | S )N	broadcastr;   z255.255.255.255)r1   rG   rH   rJ   rK   r   r3   r_   r`   valuesra   r   rc   r[   r(   )ip_to_broadcastrH   rX   rY   ipv4r;   s         r'   get_ip_to_broadcastrg      s!   O))+
#I!--i8I==!2!23D D"d*v~${BSW[\bWcBc=A&\[(9: ! $ ""((*
#**,I!;;&..0T^^Y]YeYeimiwiwYw6:llODNN3 " -
 "")4O%&r)   c                 F   d}t         j                  j                  sy| s!d}i } t               }|D ]  }||   }d|i| |<    d}g }| D ]x  }| |   }d|vr~t	        j                  t        j
                  t        j                        |d<   |d   j                  t        j                  t        j                  d       	 |d   j                  |df       d	|vrt        j                  d
|d      j                         }t        j                   dt         j"                  d |ddt         j$                  d      }	t        j&                  |	t         j(                        |d	<   d|vrd|d<   t        j                  d||d   |d          	 |d   j+                  |d	   |d   |d   f       d}|sc|d   j1                          |d= { |sRt        j2                  t4        j6                  k7  r|D ]  }t        j-                  |        t        j-                  d       | S #  t        j                  d|d       Y xY w# t        j,                  $ rT}
t        j                  d| d|d    d|d    d|
        |j/                  d| d|d    d|d    d|
        Y d }
~
d }
~
ww xY w)NFTrc   r   r   r   zJFailed to bind to address %r for discovery broadcasts, skipping interface!)exc_infopayloadapp)fromr	   hmac_keyportiX  z4Sending discovery broadcast from %r to %r on port %rz(Failed to send discovery broadcast from z to :: zRSending broadcast discovery packet failed, certain v3.5 devices will not be found!)tinytuya	AESCipherCRYPTOLIB_HAS_GCMrg   r   r   r    
setsockopt
SOL_SOCKETSO_BROADCASTbindlogdebugjsondumpsencodeTuyaMessageREQ_DEVINFOPREFIX_6699_VALUEpack_messageudpkeysendtoerrorappendr$   levelloggingDEBUG)
iface_listclose_socketsclient_bcast_addrsbcastr;   at_least_one_succeededbcast_error_messagesr[   iface	bcast_msgelines               r'   send_discovery_requestr      s   M//
02'E%e,D!,e5Jt ( #7#5 $mmFNNF<M<MNE(O(O&&v'8'8&:M:MqQh$$wqk3
 E!JJ7 ;=DDFE ,,a1E1EtUTUW[]e]w]wy}I'44i(//[E) E&M		I7TYZeTfhmnthuw	M(O""E)$4u[7I5QW=6Y[%)"
 (O!!#h; > "99%,		4! -		gi=		gip{	  B || 	MIIA'$uU`OaNbbcdijpdqcrrtuvtwxz ''+ST[S\\`afgras`ttuv{  }C  wD  vE  EG  HI  GJ  *K  M  M	Ms%   <H"H9H69J A
JJ c                       e Zd Zd Zy)KeyObjc                 Z    || _         || _        |j                  d      | _        d| _        y )Nutf8F)r   r   r}   key_encodedused)selfr   r   s      r'   __init__zKeyObj.__init__  s(    	::f-	r)   N)__name__
__module____qualname__r    r)   r'   r   r     s    r)   r   c                   6    e Zd Zd Zd Zd Zd Zd Zd Zd Z	y)	DeviceDetectc                    || _         d | _        || _        || _        d | _        d| _        d| _        d| _        d| _        d| _	        d| _
        d| _        d| _        d | _        d| _        g | _        g | _        d | _        d| _        d| _        d| _        d| _        d| _        t.        | _        d| _        d | _        t7        j6                         dz   | _        |d   | _        |si }d|v rd|vr|d   |d<   |d= || _        t<        D ]  }||vsd| j                  |<    | j                  d   sd	| j                  d<   d
| j                  vs| j                  d
   sd| j                  d
<   || j                  d<   y )NFr      retriesabliltyr    r   @dev_typedefaultr	   )r	   
deviceinfooptionsrz   devicescannedbroadcastedfound	key_found
gwid_found	err_found	ver_found	displayedmessagepassivemsgs
send_queuesockreadwriterI   timeoresetsFSCAN_NOT_STARTEDsteptry_v35_with_v34cur_keytimehard_time_limitinitial_connect_retriesdevinfo_keys)r   r	   r   r   rz   r\   s         r'   r   zDeviceDetect.__init__  s   
 
			

%	 %#yy{R/'.y'9$J
"y
'B$.y$9Jy!9%$A
"%'"  y)*-DOOI&doo-tz7R*3DOOJ'
 !#r)   c           
         | j                   rt        d| j                         | j                  r| j                  j	                          t        j
                  t
        j                  t
        j                        | _        | j                  j                  d       | j                  j                  t        | j                        t        f       d| _        d| _        g | _        t        j                         | j                   d   z   | _        | j$                  r| j$                  j&                  n| j(                  d   }|dk(  rd}t+        j,                  | j(                  d   | j                  || j(                  d	   t/        | j(                  d
               | _        | j0                  j3                  d       | j                  | j0                  _        y )NzConnecting to debug ipFTconnect_timeoutr   r   ffffffffffffffffr   r   r   )r   r   )rz   rT   r	   r   r$   r   r   SOCK_STREAMsetblocking
connect_exr"   TCPPORTr   r   r   r   r   r   r   r   r   rr   OutletDevicefloatr   set_socketPersistent)r   r   s     r'   r!   zDeviceDetect.connectH  s^   ::*DGG499diioo'MM&..&2D2DE			e$		s477|W57	
YY[4<<0A#BB
"&,,dllDOOE4J"9C++T__V-Ddggs]a]l]lmw]x  CH  IM  IX  IX  Yb  Ic  Cd  e((.!YYr)   c                     | j                   rt        d| j                         | j                  r| j                  j	                          d | _        dx| _        | _        d| _        y )Nz
in close 0FT)rz   rT   r	   r   r$   r   r   rI   r   s    r'   r$   zDeviceDetect.close\  sG    ::,(99diioo'	!&&	DJr)   c                     | j                   rt        d| j                         | j                  r| j	                          y y )Nz	in stop 0)rz   rT   r	   r   r$   r   s    r'   stopzDeviceDetect.stopd  s,    ::+tww'99JJL r)   c                     	 | j                   j                         d   }|sA	 | j                   j                  d      }| j                  rt        d| j                  d|       y|S # t        $ r[}d }| j                  rCt	        j
                  ||d        t        d| j                  d       t        | j                          Y d }~d }~ww xY w# t        $ r}| j                  rZ|j                  t        j                  k(  r=| xj                  dz  c_
        | j                  rt        d| j                  d       Y d }~y|j                  t        j                  k(  r$| j                  rWt        d| j                  d	       n?| j                  r.t	        j
                  ||d        t        d| j                  d
       Y d }~y Y d }~yd }~w | j                  r+t        d| j                  d       t	        j                          | j                          Y y xY w)Nr   z
Debug sockzconnection failed!  z$closed but received data?? Received:r   z)connection made but then closed, retryingFzCconnection made but then closed and retry limit exceeded, giving upz connection refused, not retryingzunhandled connection exception!)r   getpeername	Exceptionrz   	tracebackprint_exceptionrT   r	   recvOSErrorr   errno
ECONNRESET	print_excr$   )r   r;   r   r&   s       r'   get_peerzDeviceDetect.get_peerj  s   		! 99((*1-D IINND*::,1WYZ[2 Q  	!Dzz))!Ad3lDGG-ABdii 	!"   //AGGu?O?O4O00A50zzlDGG5`a WW 0 00zzlDGG5z{zz!11!Ad;lDGG5WX ::,1RS'')

s8   A$ ?C $	C-ACC	HA!F?:A;F??AHc                 ~   | j                   r+t        d| j                  | j                  j                         | j                  j                         }| j                  j                  | j                  j                  |             | j                  r| j                  j                  dk(  rpd| j                  _
        | j                  j                         }| j                  j                  | j                  j                  |             d| j                  _
        | j                   rt        d| j                         y y )Nzv3.4/5 trying key333333@      @z&v3.4/5 session key neg start, debug ip)rz   rT   r	   r   real_local_key&_negotiate_session_key_generate_step_1r   sendall_encode_messager   r   )r   step1s     r'   v34_negotiate_sess_key_startz)DeviceDetect.v34_negotiate_sess_key_start  s    ::%tww0J0JKBBD		4;;66?A  T[[%8%8C%?"%DKKKKFFHEIIt{{::ECE"%DKK:::DGGD r)   c                    t         j                  }| j                  r#t         j                  t        j
                         | j                  j                  |      }|st         j                  |       y| j                  j                  | j                  j                  |             | j                  j                          t         j                  |       y)NFT)ry   r   rz   setLevelr   r   r   &_negotiate_session_key_generate_step_3r   r   r   (_negotiate_session_key_generate_finalize)r   rkeylastloglevelstep3s       r'   v34_negotiate_sess_key_step_2z*DeviceDetect.v34_negotiate_sess_key_step_2  s    yy::LL'BBDJLL&		4;;66?A<<>\"r)   N)
r   r   r   r   r!   r$   r   r   r   r   r   r)   r'   r   r     s(    1#f'(-^Er)   r   c                   Z     e Zd Z fdZd Z fdZddZd Zd Zd Z	d Z
d	 Zd
 Z xZS )ForceScannedDevicec                     t         t        |   ||||       d| _        d | _        g | _        d| _        d| _        | j                          y )Nr   TF)	superr   r   r   keygenbrute_force_datar   v34_connect_okr!   r   r	   r   r   rz   	__class__s        r'   r   zForceScannedDevice.__init__  sH     $0"j'5R " $#r)   c                 v    | j                   rt        d| j                         d| _        | j	                          y )Nzin abortF)rz   rT   r	   r   r$   r   s    r'   abortzForceScannedDevice.abort  s'    ::*dgg&


r)   c                    | j                   rt        d| j                         t        t        |           | j                  t        k(  r| j                          | j                  sd| j                  d<   | j                  d   r_| j                  rR| j                  sEt        | j                  d| j                  d   | j                  | j                  d          d| _        y y y y )Nzin stop        r   r6   z!Failed to Force-Scan, FORCED STOP
termcolorsT)rz   rT   r	   r   r   r   r   FSCAN_v33_BRUTE_FORCE_ACQUIREbrute_force_v3x_datar   r   r   r   r   _print_device_infor   r   r   s    r'   r   zForceScannedDevice.stop  s    ::)TWW% $,.9955%%'~~),DOOI&<<	"tzz$..1TVZVbVbcoVprvr~r~  AE  AM  AM  NW  AX  Z!DN ;Iz"r)   c                    | j                   r!t        d| j                  | j                         | j                  ry | j                  t
        k(  r4d| _        d| _        | j                   rWt        d| j                  d       n>| j                  t        k(  r| j                   r(t        d| j                  d|rdndd| j                         | j                  d	k  r'| xj                  d
z  c_        | j                          n| j                   rt        d| j                         | j                  d   dk(  rI| j                   rt        d       d
| _        d| j                  d<   t
        | _        | j                          y | j                   rt        d       d| j                  d   j                  z  | _        d| _        d| j                  d<   t        | _        d| j                  d<   d | j                  d   D        | _        t!        | j                  d       | _        | j                   r!t        d| j"                  | j                         | j"                  	d| _        nc| j                          d| _        nJ| j                  t        k(  r|s| j$                  s| j                  d	k  r&| xj                  d
z  c_        | j                          y d| _        d| j                  d<   | j                  d   j&                  d| j                  d| _        t)        | j                  d| j                  d   | j                  | j                  d          d| _        | j-                          y | j/                          d| _        nB| j                  t0        k(  r| j/                          n|rd| _        | j                  t        k(  rdnd }| j                  d   j&                  d| j                  d!|| _        t)        | j                  d| j                  d   | j                  | j                  d          d| _        d| _        n| j                  t2        k(  s| j                  t4        k(  r6| j7                         sIt9        j8                         d"z   | _        d| _        n$| j                  t>        k(  r| j                  s@| j@                  sdnd }| j                  d   j&                  d| j                  d#|| _        t)        | j                  d$| j                  d   | j                  | j                  d          d| _        d| _        ny| j                   r"t        d| j                  d%| j                         d| _        t)        | j                  d| j                  d   | j                  | j                  d          d| _        | j                  r| j-                          y y )&Nz
in timeoutTzForceScannedDevice: Debug sockzconnect timed out!zsocket send failed,zno data received,zreceive timed out,zcurrent retry:r   r   z-ForceScannedDevice: Debug sock closed thrice:r   r   z-ForceScannedDevice: Retrying as v3.3 Device22device22z(ForceScannedDevice: Retrying as v3.4/3.5zR%s    Unable to determine version, likely v3.4 or v3.5 - trying key negotiation...r   r   r   r   c              3   :   K   | ]  }|j                   r|  y wr0   r   .0is     r'   	<genexpr>z-ForceScannedDevice.timeout.<locals>.<genexpr>  s     P*AQq*A   keylistz ForceScannedDevice: Keygen gave:Fr       Polling zM Failed: Device stopped responding before key was found (likely v3.4 or v3.5)Failed to Force-Scanr6   z (likely v3.4 or v3.5)r   z5 Failed: Unexpected close during read/write operation      @$ Failed: No response to poll requestForce-Scannedztimeout on unhandled step)!rz   rT   r	   r   rI   r   r   FSCAN_INITIAL_CONNECTr   r!   r   r   rU   r   FSCAN_v34_BRUTE_FORCE_ACTIVEr   nextr   r   alertdimr  r   r$   v3x_brute_force_try_next_keyFSCAN_v31_BRUTE_FORCE_ACTIVEFSCAN_v31_PASSIVE_LISTENr   r   r   r   r   FSCAN_FINAL_POLLr   )r   forcedhints      r'   timeoutzForceScannedDevice.timeout  sV   ::<$))5;;99))DK!DNzz6AUVYY//zz6AVouXk  |P  Rb  dh  dp  dp  q||a!::I477S??:.);zzMN#$DL2<DOOJ/ 1DILLN::DEsw{  xD  xD  EQ  xR  xV  xV   W .7
+8	-0	*P$,,y*AP#T[[$8::<dllDGGT<<'"&DKLLN*/D'YY66d&9&9<<!#LLA%LLLN  &*DN14DOOI. GK  GS  GS  T`  Ga  Gj  Gj  lp  ls  ls  $tDL&9OQUQ]Q]^jQkmqmymy{  |H  |H  IR  |S  T%)DNJJL--/"'DYY66--/!DN/3yy<X/X+^`Dhlhtht  vB  iC  iL  iL  NR  NU  NU  W[  \DL1GVbIceieqeqswss  AJ  tK  L!DNDKYY22diiC`6`,,.!YY[3.
#YY**<<7;~~/2[_[g[ght[u[~[~  AE  AH  AH  JN   O$,,|B\^b^j^jlplxlx  zC  mD  E!DNDKzz6A\^b^g^ghDK1GVbIceieqeqswss  AJ  tK  L!DN;;JJL r)   c                    | j                         }| j                  rt        d| j                  d|       || j	                          y |du rY| j                  rt        d| j                         | j
                  r| j
                  j	                          | j                          y t        j                         dz   | _        d| _	        d| _
        t        | j                        dkD  r|| j
                  j                  | j                  j                  | j                  d                | j                  dd  | _        t        | j                        dk(  rd| _        d| _        y d| _        d| _        t$        j                  d	| j                         | j                  r'| j&                  dk(  rt        d
| j                         d }| j&                  t(        k(  rpd| _        t,        | _        | j.                  d   dk(  r&t1        j2                  t0        j4                  d      }nOt1        j2                  t0        j6                  d      }n)| j&                  t,        k(  rzt9        t:        j=                  d            }| j.                  d   dk(  r%t1        j2                  t0        j4                  |      }nt1        j2                  t0        j6                  |      }n| j&                  t>        k(  rCt9        t:        j=                  d            }t1        j2                  t0        j@                  |      }nF| j&                  tB        k(  r| jE                          n"t        d| j                  d| j&                         |r_| j                  rt        d| j                  d|       | j                  j                  |      }	 | j
                  j                  |       y y #  | j                  jG                  |       d| _        d| _        Y y xY w)NzForceScannedDevice: devicezaddr is:Fz$ForceScannedDevice: Retrying connectg      ?Tr   r   zForce-Scan Found Device %sz- ForceScannedDevice: Force-Scan Found Device r   r  r)   @deadbeef112233445566778899aabbccddeeffb00bface112233feedbabe74f0z1ForceScannedDevice: Unhandled step in write()?!?!r   z$ ForceScannedDevice: Sending Device z	 Message )$r   rz   rT   r	   r$   r   r!   r   r   r   r   lenr   r   r   r   r   r   ry   r   r   r   r  r   rr   MessagePayloadCONTROL_NEWDP_QUERYbytes	bytearrayfromhexr  CONTROLr  r   r   )r   r;   msgdummy_payloads       r'   
write_datazForceScannedDevice.write_data3  s   
 }}::.TJ<JJLU]zz<dggFyy		!LLN YY[3&

"t!#IIt{{::DOOA<NPR"ooab1DO4??#q("
 	
			.8::$))q.twwPQ99))DL-DI z*j8--h.B.BCH--h.?.?EYY//!)"3"34v"wxMz*j8--h.B.BMR--h.?.?OYY66!)"3"34v"wxM))(*:*:MJC YY66--/EtwwPVX\XaXabzzTWWUXYZ++--s4C"		!!3( "&&-!
!	s   7O +Pc                    	 | j                   j                  d      }| j                  r$t        d| j                  d| j
                  d|       t        |      dk(  r| j                  d       y t        |      ru	 | j                  d   d	k(  r*|j                  t        j                        }|dkD  r||d  }n| j                  r| j                  d   d
k(  rx|j                  t        j                        }|dk\  rT| j                  rt        d       ||d  }d| _        d	| j                  d<   | j                  j                  d	       d| _        | j                  d   d	k7  r0|j                  t        j                         }|dk\  r||d  }d| _        | j                  d   d
k\  r| j                  j"                  nd }t        j$                  ||      }|}|t        |j&                        dz   d  }|rt        |j&                        dk(  r|j(                  t        j*                  k(  r| j-                  |      st        d|       | j                          y d| _        d| _        t2        | _        | j4                  d   j6                  d| j                  d| _        d| _        | j:                  j<                  | j                  d<   | j?                          d| j:                  _         | jB                  jE                  | j                  jG                  t        jH                               y |j&                  jK                  t        jL                        r@d| j                  d<   |j&                  t        t        jL                        dz   d  }d| _        nr|j&                  jK                  t        jN                        r=d| j                  d<   |j&                  t        t        jP                        d  }d| _        n|j&                  }| j                  r(t        d| j                  d| j
                  d|       | j
                  tR        k(  r2tU        jT                         dz   | _+        d}	 d|jY                  d      v rd| _        | j                  j                  d       d| j                  d<   tZ        | _        d}| j                  rt        d       d | j4                  d   D        | _.        | j_                          |s| j                  rt        d | j                  z         | j                  j                  d       d| j                  d<   d| _        t`        | _        | jb                  jE                  |       nb| j
                  t`        k(  r| jb                  jE                  |       n2| j
                  tZ        k(  r&d|jY                  d      v r| je                          n| j
                  tf        k(  ro|j(                  t        jh                  k(  r|jj                  dk(  r	 | jb                  jE                  tm        jn                  |             | jq                          nw| j
                  t2        k(  rc| j                  js                  |j&                        }| j                  r-t        d!| j                  | j
                  |       t        |       d}	|snd"|v r:t        |d"         d#kD  rd}	| j4                  d   jt                  d$|d"   | _        nKd%|v r$| j4                  d   j6                  d&|| _        n#| j4                  d   jt                  d'|| _        | j4                  d(   r8|	r6tw        | j                  d)| j4                  d   | j8                         d| _<        |	r| j{                          y tU        jT                         d*z   | _+        y t        |      rty y #  d}Y xY w#  Y y xY w#  Y xY w#  Y ,xY w)+Nr   r)   zForceScannedDevice:zgot stepzdata:r   Tr   r   r   z#ForceScannedDevice: device is v3.5!Frm      odata:r   r  r  r   r      gffffff
@zGot message from z
 for step rq   r  r   r   zTrying brute force!c              3   :   K   | ]  }|j                   r|  y wr0   r  r  s     r'   r
  z/ForceScannedDevice.read_data.<locals>.<genexpr>  s     &X2IQQRQWQWq2Ir  r  zDevice %s is probably v3.3zForceScannedDevice: Final Polldpsr   z    Status: Errorz    Error: z    Unknown: r6   r         @)>r   r   rz   rT   r	   r   r  r  r   rS   rr   PREFIX_6699_BINr   r   set_versionr   
PREFIX_BIN	local_keyunpack_messagerj   cmdSESS_KEY_NEG_RESPr   r   r   r  r   r  r   r   r   	found_keyr   r   r   generate_payloadr"  
startswithPROTOCOL_VERSION_BYTES_31PROTOCOL_VERSION_BYTES_33PROTOCOL_33_HEADERr  r   r   decoder  r   r  r   r   brute_force_found_keyr  STATUSretcodebase64	b64decoder   _decode_payloadrU   r  r   r$   )
r   dataprefix_offsetrn   r'  odatarj   have_err_stringresultfinisheds
             r'   	read_datazForceScannedDevice.read_data  s}   	99>>4)D ::'*diiRVXt9>LL$ $i??9-4$(IIh.F.F$GM$q(#MN3 ,,1Ks1R(,		(2J2J(K(A-#zz %&K L#'#7D49D19<DOOI6 KK33C8-1DNy1S8(,		(2E2E(F(A-#'#7D49D148OOI4NRU4U4;;00[_--dXF E CKK(*+,D #ckk*a/ww(444993@(E*LLN!	!
,	Y]YeYefrYsY|Y|  C  F  F   G!%)-)9)9& $(!&&t{{'C'CHDUDU'VW{{%%h&H&HI-0	*++c(*L*L&Mb&P&RS!%''(J(JK-0	*++c(*E*E&F&HI!%++zzTWXZyy11 "YY[3.
"''.."88)-//458	2$@	*.::!#8:&X$,,y2I&X99; 'zz;dggEGKK++C014DOOI.%)DN =DI))00';;;%%,,g7;;gnnV44..06677hoo-#++2B--44f6F6F6QS113 ..44ckkC:::DGGTYYPWX&M f_6%=)A-#'9=l9S9W9WY_`eYf#gDL&8<\8R8[8[]c#dDL:>,,|:T:X:XZ`#aDL<<	*x&$,,WcJdfjfrfrt%)DNJJL  "&s!2DJi $ii	DFF,s1   _/ :E_9 +B`  )>` /_69_= ``c                    t        | j                        dk(  ryd | j                  d   D        D ]  }|| _        d}t	        j
                  |j                        }d }| j                  D ]]  }d }	 |j                  |dd      }t        |      dk(  r(| j                  rt        d| j                  d|       |j                  }|r[d} n |s|r| j                           y g | _        y#  Y -xY w)Nr   Fc              3   :   K   | ]  }|j                   r|  y wr0   r  r  s     r'   r
  z:ForceScannedDevice.brute_force_v3x_data.<locals>.<genexpr>.  s     E6!affA6r  r  TzForceScannedDevice: Brute forcez
decrypted:)r  r   r   r   rr   rs   r   decryptrz   rT   r	   r   r@  )r   r   badciphermatchedr'  texts          r'   r   z'ForceScannedDevice.brute_force_v3x_data*  s    %%'1,Et||I6ECDLC'':FG,,
!>>3t=D4yA~ zz?,X\]$jjG C! -$ s**,3 F6 !#s   /!C*0C**C.c                 j   t        | j                  d       | _        | j                  s`| j                  rT| j                  j                  r>t        | j                  d       | _        | j                  r| j                  j                  r>| j                  I| j                  s7d | j
                  d   D        | _        	 t        | j                  d       | _        d| _        | j                  | j                  rt        d| j                         d| _	        d| j                  d<   | j
                  d   j                  d| j                  d	| _        t        | j                  d
| j
                  d   | j                  | j
                  d          d| _        y | j                  r+t        d| j                  | j                  j                         | j!                          y | j                  r+t        d| j                  | j                  j                         | j!                          y #  d | _        Y ZxY w)Nc              3       K   | ]  }|  y wr0   r   r  s     r'   r
  zBForceScannedDevice.v3x_brute_force_try_next_key.<locals>.<genexpr>W  s     B*AQq*A   r  TzMForceScannedDevice: v3.x brute force ran out of keys without finding a match!r   r   r   r  z Failed: No matching key foundr  r6   zUForceScannedDevice: v3.x brute force ran out of keys, restarting without skipping anyz4ForceScannedDevice: v3.x brute force trying next key)r  r   r   r   r   r   rz   rT   r	   rI   r   r  r   r  r   r   r!   r   s    r'   r  z/ForceScannedDevice.v3x_brute_force_try_next_keyL  s   T[[$0||,,4<<#4#4#T[[$8 ,,4<<#4#4 <<<<B$,,y*AB(#'d#<DL  DL||#::ikokrkrs"-0	*SWS_S_`lSmSvSvx|xx   A"DOO5KT\\ZfMgimiuiuw{  xD  xD  EN  xO  Q!%::qswszsz  }A  }I  }I  }M  }M  NzzLdggW[WcWcWgWghLLN%(#'DLs   =H& &	H2c                     | j                   r,t        d| j                  j                  d| j                         g | _        d| _        d| _        d| _        | j                  j                  | j                  d<   | j                          | j                  j                  x| j                  _        | j                  _        | j                  j!                  | j                  j#                  | j                  j%                  t&        j(                                     t*        | _        | j.                  d   j0                  d| j                  d| _        t5        j4                         d	z   | _        d| j                  _        y )
Nz)ForceScannedDevice: v3.x brute forced keyforTFr   r   r  r  r1  )rz   rT   r   r   r	   r   r   r   r   r   r9  r   r   r5  r   r   r   r   r:  rr   r"  r  r   r   r  r   r   r   r   r   s    r'   r@  z(ForceScannedDevice.brute_force_found_keyn  s   ::=t||?O?OQVX\X_X_` "	
!%!1!1=A\\=U=UU :		4;;668T8TU]UfUf8gik$	QUQ]Q]^jQkQtQtvzv}v}~YY[3&
 r)   c                 f   | j                   d   D ]  }|d   | j                  d   k(  s|d   | j                  d<   |d   x| j                  d<   | j                  d<   d|v r4|d   r/d| j                  vs| j                  d   s|d   | j                  d<   |d   | j                  _        d| _         y  y )Ntuyadevicesr   r   idr   r
   T)r   r   r   r[  r   )r   devs     r'   r9  zForceScannedDevice.found_key~  s    <<.C5zT__U33*-f+'BEd)K%(?C<CJE4PX\XgXghmXn-0ZDOOE*!$T!% /r)   )F)r   r   r   r   r   r   r  r)  rL  r   r  r@  r9  __classcell__r   s   @r'   r   r     s=    "^@R"haF D D! 	r)   r   c                   :     e Zd Z fdZ fdZd Zd Zd Z xZS )
PollDevicec                 b    t         t        |   ||||       d| _        |d   | _        d| _        y )NTr   F)r   r`  r   r   r   rK  r   s        r'   r   zPollDevice.__init__  s3    j$("j'5Jy)r)   c                     t         t        |           | j                  d   r7t	        | j
                  d| j                  d   | j                         d| _        y y )Nr6   zValid Broadcastr   T)r   r`  r$   r   r  r   r   r   r  s    r'   r$   zPollDevice.close  sL    j$%'<<	"1BDLLQ]D^`d`l`ln!DN #r)   c                    | j                   dkD  r| j                  r"t        d| j                  d| j                          | xj                   dz  c_         | j                  r| j                  j                          | j                          t        j                         t        j                  z   | _
        | j                  rt        d| j                         y y | j                  rt        d| j                  d       d}d	| j                  v r| j                  d	   }| j                  d
   j                  d| j                  d|| _        | j                          y )Nr   z PollDevice: Timeout for debug ipz- reconnecting, retriesr   zPollDevice: New timeo:z&PollDevice: Final timeout for debug ipz
- abortingr   errr   r  z	 Failed: )r   rz   rT   r	   r   r$   r!   r   rr   TIMEOUTr   r   r   r  r   )r   rd  s     r'   r  zPollDevice.timeout  s    <<!zz8$''C\^b^j^jkLLALyy		!LLNx'7'77DJzz.

;  zz>VC'ooe,<@LL<V<_<_aeahahjmnDLJJLr)   c                    | j                         }|sd| j                  vs| j                  d   sd| j                  d<   | j                  r@t        d| j                  d|| j
                         t        t        j                                | j                          y t        j                         | j                  d   z   | _        | j                  rt        d| j                         t        | j                        dkD  r|| j
                  j                  | j                  j!                  | j                  d                | j                  dd  | _        t        | j                        dk(  rd	| _        d
| _        y d	| _        	 | j                  j&                  dk\  r| j)                          n[| j
                  j                  | j                  j!                  | j                  j+                  t,        j.                                     d
| _        d| j                  d<   y #  d| j                  d<   t        t        j                                | j                          Y y xY w)Nrd  zConnect FailedzPollDevice: Debug sockzfailed!data_timeoutzPollDevice: WD New timeo:r   r   FTr   zNo responsezSend Poll failed)r   r   rz   rT   r	   r   r   
format_excr  r   r   r   r  r   r   r   r   r   r   r   r   r:  rr   r"  )r   r;   s     r'   r)  zPollDevice.write_data  s   }}T__,dooe6L)9&zz.D$))Ti**,-LLN YY[4<<#??
::-tzz:t!#IIt{{::DOOA<NPR"ooab1DO4??#q("
 	
	{{""c)113		!!4;;#>#>@\@\]e]n]n@o#qsDI%2DOOE"	%7DOOE")&&()LLNs   BH >Ic                    	 | j                   j                  d      }t        |      r[	 |j                  t        j                        }|dkD  r||d  }| j                  j                  dk\  r| j                  j                   nd }t        j"                  ||	      }|}|t        |j$                        d
z   d  }|rt        |j$                        dk(  r|j&                  t        j(                  k(  r| j+                  |      st	        d|       | j                          y d| _        d| _        | j0                  j3                  | j                  j5                  t        j6                               y | j                  j8                  }	 t:        j=                  d|       | j                  j?                  |j$                        }|| j                  j8                  k7  rt:        j=                  d|| j                  j8                         | j                   jE                  | j                  jG                  | j                  j5                  t        j6                                     y d| _$        | j                  j8                  | jJ                  d<   |rd|vr|r>d|v r:| j                  d   j                  d| j
                  d|d   d|d   | _        n0| j                  d   j                  d| j
                  d|| _        d| jJ                  d<   | j                          nU|| jJ                  d<   d| jJ                  d<   | j                  d   jL                  d|d   z  z   | _        | j                          t        |      rZy y #  | j                  dkD  r7| j                  d   rt	        d| j
                         | j                          Y y | j                  d   j                  d| j
                  d| _        | j                          Y y xY w#  Y y xY w#  t:        j=                  d       t        j@                  t        jB                        }Y xY w)Nr   r   r6   zread_data() failed, retryingr   r  z Failed: Read errorr   rm   r+  r,  FTz%PollDevice: raw unpacked message = %rz9PollDevice: error unpacking or decoding tuya JSON payloadzSPollDevice: Device22 detected and updated (%s -> %s) - Update payload and try againtyper/  r0  z    Access rejected by z (check key): rq   Payloadz-    Check DEVICE KEY - Invalid response from zUnable to pollrd  r   z    Status: %s)'r   r   r   r   rT   r	   r  r  r   r$   r  rS   rr   r4  r   r   r5  r6  rj   r7  r8  r   r   r   r   r   r:  r"  r   ry   rz   rE  
error_jsonERR_PAYLOADr   r   rK  r   rU   )r   rF  rG  rn   r'  rH  r   rJ  s           r'   rL  zPollDevice.read_data  s   	99>>4)D $i $		(*=*= > 1$/D48KK4G4G34N4;;00TX--dXF
 ECKK(*+,D #ckk*a/ww(444993@(E*LLN!	!
&&t{{'C'CHDUDU'VW{{++HC		A3G44S[[A 4;;///		iKK((
 		!!4;;#>#>@\@\]e]n]n@o#qs DM&*kk&:&:DOOF#U&0g/X\XdXdeqXrX{X{  ~B  ~E  ~E  GM  NU  GV  X^  _h  Xi  $jDL^b^j^jkw^x  _B  _B  DH  DK  DK  MS  $TDL)9&

)/&)+&#||L9==@PSYZ_S`@``

{ $ii		||a<<	*8$''BDHLLQ]D^DgDgimipipqDLJJL2C		UV!,,X-A-ABs*   N A1P ;P AP>PP:Q)	r   r   r   r   r$   r  r)  rL  r]  r^  s   @r'   r`  r`    s    "*(VKr)   r`  c           	      (    t        d| |d|||       y)z9Scans your network for Tuya devices with output to stdoutT)r6   scantimecolorpoll	forcescandiscover
assume_yesN)devices)ro  rp  rr  rs  rt  s        r'   scanrv  '  s    D85tyck  yC  Dr)   c              #   F  K   | D ]  }t         j                  r#t        |      t        k(  r|j	                  d      }	 t        j                  |d      }t        j                  d|       |r't        |j                  d||j                  z          t        j                   |      D ]  }t        |         y #  t        j                  d|       |rEt        |j                  d|z  z   |j                  z          t        t        j                                Y xY ww)Nlatin1F)strictz$Starting brute force network scan %sz&Unable to get network for %r, ignoringz.ERROR: Unable to get network for %r, ignoring.z  Starting Scan for network )rr   IS_PY2rj  r"   r?  rL   
ip_networkry   rz   rT   alertrQ   r   rh  rP   rU   IPv4Network)networksr6   r5   netblockrN   r;   s         r'   _generate_ipr  +  s     ??tH~4x0H		**8EBGII<gF $))GTXXVVW))'2Dd)O 3# 	II>IdjjDxOPRVR]R]^ _i**,-s   9D!-B<)AD!<ADD!c                 (   |sy | d   }| d   }| d   r| d   nd}| d   r| d   dk7  r| d   nd}| d   }	| d	   }
| d
   }d| v r| d   nd}|j                   dz   |z   dz   }| d   s,|j                  d|d|j                  |j                   z   }	n|j                  | d   z   |j                   z   }	t        d|	|||j                  ||j
                  |t        |      |j                  |
|j                  ||j
                  ||fz         |rt        |       y y )Nr	   r   r   rA   r   z0.0z??r   r   r
   r   z, MAC = r   z	Unknown vz Devicez{%s   Product ID = %s  [%s]:
    %sAddress = %s   %sDevice ID = %s (len:%d)  %sLocal Key = %s  %sVersion = %s  %sType = %s%s)	rU   r|  rQ   rT   subboldcyanr  redyellow)rJ  noter5   extra_messager6   r	   r   r   r   
devicenamedkeyr
   
devicetypesuffixs                 r'   r  r  @  sD   	B&>D)/)=%3J#))#4	9Je9SfYY]GJ%=D
-C'1V';
#JXX
"S(2-F&>15WdkkRVRZRZFZ[
[[6&>1DHH<
	 	GLLIIIHHKKII
	
* } r)   c                 /  a |xr t         }t        j                  |      }t        | }fd}d}st        j                  t
              rd}|rQt              dk(  rC|r/t        |j                  dt
        z  z   |j                  z          d}nt        dt
        z        |r&t        j                  t        j                  t        j                  t        j                        }|j                  t        j                   t        j"                  d       	 |j                  t        j                   t        j$                  d       |j)                  dt*        f       t        j                  t        j                  t        j                  t        j                        }|j                  t        j                   t        j"                  d       	 |j                  t        j                   t        j$                  d       |j)                  dt,        f       t        j                  t        j                  t        j                  t        j                        }|j                  t        j                   t        j"                  d       	 |j                  t        j                   t        j$                  d       |j)                  dt.        f       nd	x}x}}d
}|t        j0                  }|| }| rt        d|j2                  d|j                  d|j4                  dt        j6                  d	       |r#t        d|j4                  t              fz         |r4t        d|j8                  t*        t,        t.        ||j                  fz         g }g }i }i }i }i }g }g }g }d}d}g } g }!t;        |      }"t;        |	      }#|"xs |#}$d}%d}&d}'d}(t=        j<                         |z   })d}*t>        jA                  dt*        t,        t.               t=        j<                         }+t=        j<                         dz   },d	}-d	}.d
}/d}0i }1d}2tB        tB        || dg d}3D ]&  }4|3d   jE                  tG        |4d   |4d                ( |sg n
tI        |      }|	sg n
tI        |	      }	|rZ| r(t        |j8                  dz   |j4                  z   dz          d}5tK        |tH              stK        |tL              rU|D ]P  }6tK        |6tH              stK        |6tL              r|6D ]  }7|jE                  |7       d}5 >|jE                  |6       d}5R tK        |tN              stK        |tP              r|jE                  |       d}5|5rtR        sHtT        sBt        |j                  dz   |j4                  z          	 tW               }6|jE                  |6       n6t[        || |       }|s&t        |j                  dz   |j                  z          y	|
r|
D ]  }6|jE                  |6        ng }
|ri| rt>        jA                  d |       t]        || |      }-dx}&}'|rt=        j<                         dz   }(| r%t        |j2                  d!z   |j4                  z          |s|'rdnt        j0                  }t_               }8|8D ]  }9|8|9   }:d"|9i|1|:<    |'s1|)t=        j<                         kD  s|*t=        j<                         kD  s|!	r|r|||g}ng }g }i };g }<|!} g }!d}*d}=|,|)k\  rd}>n0|,t=        j<                         k  }>|>rt=        j<                         d#z   },|D ]G  }?|?j`                  r|?jb                  |vr|?||?jb                  <   |>r1|?jd                  t=        j<                         k  r|?jg                          |?jh                  r|<jE                  |?       ~|>r1|?jj                  t=        j<                         k  r|?jm                          |?jn                  s!|?jj                  d#z   |*kD  r|?jj                  d#z   }*|?jp                  s|?jr                  r|jE                  |?jp                         |?jt                  r|jE                  |?jp                         |?|;|?jp                  <   J |<D ]  }?|ji                  |?        |r|)|*kD  r(tw        |)t=        j<                         z
        }@|@dk  rd}@nd$tO        t        |            z   }@|'rd%tO        |.      z   n
tO        @      }At        |j4                  d&||   d'|Ad(|=d)d*       |dz   d+z  }tx        jz                  j}                          	 |'rd,}/|(r|(t=        j<                         k  rd}(|(sjt        |      t~        k  rWd}(t~        t        |      z
  }B|Bd-kD  rd-}Bt        B      D ]-  }4t        |-d	      }.|.$d}'t=        j<                         tB        z   d#z   }*d
}/ n|.|v r;|.|
v rr|
|.   d.   rj|
|.   d/   rb|.}6t        |6|
|.   |3|6|v       ||6<   ||6   j                          |jE                  ||6          t=        j<                         tB        z   }C|C|*kD  rfC}*nc|.|
v rt        |.|
|.   |3|.|v       }?nt        |.d	|3|.|v       }?|jE                  |?       |jE                  |?jp                         |?|;|?jp                  <   t=        j                  d0       |/d0z  }/0 |/dkD  rt=        j                  |/       t        |      dkD  rt        j                  ||g d      \  }D}E}Fn1t        |      dkD  rt        j                  |g g d      \  }D}F}Fg }Eng }Dg }EED ]  }H|H|;v s|;H   j                           DD ]  }H|H|ur H|urH|urH|;v r|;H   j                          (H|u rt*        }InH|u rt,        }InH|u rt.        }Ind5}IHj                  d6      \  }J}:|:d   }6d7}K	 t        j                  J      }Kt        j                  |K      }Kt>        jA                  d8|K       |%rd?Kv rbKd?   d@k(  rZ|6|vrTK||6<   | rMt        |j                  dAz   tO        |6      z   |j4                  z   dBz   tO        K      z   |j                  z          d/KvrN| r2t        |j                  dC|6d:Id;|j                  d<Kd'Jd=z          t>        jA                  dD|6IJ       b|6|vsh |Kd/         \  }L}M}N|L|KdE<   |M|Kd<   |N|KdF<   d|KvrKd/   |Kd<   | rV|j                  |j4                  z   dGz   tO        |6      z   dHz   tO        N      z   d<z   tO        K      z   |j                  z   ||6<   Ns>t        Kd/         dIk(  r-	 t        j                  Kd/   dJd	       }NdKtM        |N      z  |KdF<   t        |6K|3|6|v       ||6<   d}O|r\Kd.   dLk7  r)Ms'|j                  dM|6dN|j4                  ||6   _R        n+|0r'|j                  dM|6dO|j4                  ||6   _R        nd}OOr|!jE                  |6       n||6   j                          |6|v r|ji                  |6       ||6   j                  d/   |	v r!|	ji                  ||6   j                  d/          |rb|dz  }|dk(  rX| rt        dP       d}"d}#d}%d})|D ]>  }?|?jh                  r|?jn                  r|?jj                  d#z   |*kD  s0|?jj                  d#z   }*@ |D ]3  }?|?jb                  |6k(  s| rt        dQ|6dR       |?j                             | D ]L  }6||6   j                          |jE                  ||6          t=        j<                         tB        z   }C|C|*kD  sKC}*N |'sO|rM|)t=        j<                         k  r6|*t=        j<                         k  r|0s| rt        dS|z         dT |D        }-d	}d}'|#r)t;        |      st;        |	      s| rt        dU       d}#d}%d})|"rlt;        |      sat;        |	      sV| rt        dV       d}"d}%d})|D ]>  }?|?jh                  r|?jn                  r|?jj                  d#z   |*kD  s0|?jj                  d#z   }*@ |rA|0s?|%s=t=        j<                         |2k\  r&t=        j<                         t        z   }2t        |1       |'r	|)t=        j<                         kD  r	|*t=        j<                         kD  r	|!r	|D ]  }H|Hj                           |D ]  }H|Hj                           |r0|j                          |j                          |j                          |1D ]"  }P|1|P   }QdW|Qv sQdW   j                          |QdW= $ | r,t        dXt        t=        j<                         |+z
  d+      dY       ddddddZ}Rd}Sd}T|D ]  }6|6|v r||6= tO        ||6   j                  d.         }U|URvrdRU<   nRUxx   dz  cc<   ||6   j                  dE   sSdz  }Sn||6   j                  d   sTdz  }T||6   j                  s{|6|v s||6=  |D ]  }6tO        ||6   j                  d.         }U|URvrdRU<   nRUxx   dz  cc<   ||6   j                  dE   sSdz  }Sn||6   j                  d   sTdz  }T||6   j                  r|6|v r||6= ||6   jp                  s||6   j                  r||6   jg                           t        |      t        |      z   }V| r&t        d[|j                  d\Vd]       t        d^t        |             |&rdx}Wx}Xx}Yx}Z}[|D ]i  }6||6   }?|?j                  rWdz  }W|?j                  rXdz  }X|?j                  s|?j                  s[dz  }[|?j                  rYdz  }Y|?j                  reZdz  }Zk t        d_t        |      d`XdaWdb[       YsZrt        dcYddZ       d}\t        Rj                               D ]  }4R|4   s	\de|4dfR|4   z  }\ t        dg\dd	        Sr&t        |j                  dhS|j                         Tr&t        |j                  diT|j                         |r>t        |j                  |j                  djt        |      dk||j                         |	r>t        |j                  |j                  djt        |	      dl|	|j                         |r9t        |j                  dm|j                         |D ]  }6t        ||6           |rd/andnai }]|D ]%  }6||6   j                  }?|6|?dn<   d"|?do<   |?a   }M|?]|M<   ' |D ]:  }6||6   j                  }?|6|?dn<   dp|?do<   |?a   }M||6   j                  s1M]vs6|?]M<   < | rr|$sptI        ]j                               }^D ]A  }_|_d   at        afdq^D              r_}`|_d   |`d/<   d|`dn<   dr|`do<   ^jE                  |`       C t        t        ^|       t>        jA                  dsV       ]S # t&        $ r Y w xY w# t&        $ r Y $w xY w# t&        $ r Y }w xY w#  |jE                  dtX        z          t>        jA                  dtX               | r,t        |j                  dtX        z  z   |j                  z          Y xY w# t        $ r}}Gt>        jA                  d1       | rt        d2       |0dz  }0|0dk(  rd}'d})nA|0dk(  rY d	}G~Gt>        jA                  d3       | rt        d4       ty        j                          Y d	}G~Gd	}G~Gww xY w#  | r2t        |j                  d9|6d:Id;|j                  d<Kd'Jd=z          t>        jA                  d>|6IJ       Y xY w#  Y 	xY w)ta  Scans your network for Tuya devices and returns dictionary of devices discovered
        devices = tinytuya.deviceScan(verbose)

    Parameters:
        verbose = True or False, print formatted output to stdout [Default: False]
        scantime = The time to wait to pick up UDP from all devices (ignored when discover=False))
        color = True or False, print output in color [Default: True]
        poll = True or False, poll dps status for devices if possible
        forcescan = True, False, or a list of networks to force scan for device IP addresses
        byID = True or False, return dictionary by ID, otherwise by IP (default)
        show_timer = True or False, if True then timer will be displayed even when verbose=False
        discover = True or False, when False, UDP broadcast packets will be ignored
        wantips = A list of IP addresses we want.  Scan will stop early if all are found
        wantids = A list of Device IDs we want.  Scan will stop early if all are found
        snapshot = A dict of devices with IP addresses as keys.  These devices will be force-scanned
        assume_yes = True or False, do not prompt to confirm auto-detected network ranges
        tuyadevices = contents of devices.json, to prevent re-loading it if we already have it
        maxdevices = Stop scanning after this many devices are found.  0 for no limit

    Response:
        devices = Dictionary of all devices found

    To unpack data, you can do something like this:

        devices = tinytuya.deviceScan()
        for ip in devices:
            id = devices[ip]['gwId']
            key = devices[ip]['productKey']
            vers = devices[ip]['version']
            dps = devices[ip]['dps']

    c                 `    D ](  }d|v s|d   | k(  s|d   |d   d|v r|d   fc S dfc S  y)Nr[  r   r   r
   r   )r   r   r   r   )deviceidr	  rZ  s     r'   
tuyaLookupzdevices.<locals>.tuyaLookup  sK    AqyQtW0&	1U8!QuXLLLL  r)   FTr   zVWarning: Force-scan requires keys in %s but no keys were found.  Disabling force-scan.z6Force-scan requires keys in %s but no keys were found.r   r   Ng?
	TinyTuya (Tuya device scanner) []
z%%s[Loaded devices.json - %d devices]
zI%sScanning on UDP ports %s and %s and %s for devices for %d seconds...%s
z|/-\|z5Listening for Tuya devices on UDP ports %d, %d and %dr   r   )r   rg  r   r6   r   rZ  r  r  r[  r   z    Option: z"Network force scanning requested.
z    NOTE: neither module netifaces nor module psutil are available, multi-interface machines will be limited.
           (Requires: `pip install netifaces` or `pip install psutil`)
z-Unable to get local network, using default %rzHERROR: Unable to get your IP address and network automatically, using %sz#No networks to force-scan, exiting.zForce-scanning networks: %rz
    Running Scan...rc   g      ?zDevs:zFS:zScanning... z (z) z!                                )endr   g?
   r   r   g{Gz?zKeyboard Interruptz
**User Break**zKeyboard Interrupt - Exitingz
**User Break** - Exitingz???i  r)   zReceived valid UDP packet: %rz*  Unexpected payload from z	 to port rp    z)
z'Invalid UDP Packet from %r port %r - %rrl   rk   zNew Broadcast from App at  - z**  Payload missing required 'gwId' - from zAUDP Packet payload missing required 'gwId' - from %r port %r - %rr   r
   zNew Broadcast from z /    iz%02x:%02x:%02x:%02x:%02x:%02x3.1z    No Stats for z(: DEVICE KEY required to poll for statusz: User interrupted scanz2Found all the devices we wanted, ending scan earlyzAborting force-scan for devicezdue to received broadcastzSNot all devices were found by broadcast, starting force-scan for missing devices %rc              3       K   | ]  }|  y wr0   r   r  s     r'   r
  zdevices.<locals>.<genexpr>o  s     +7a7rV  z5Found all the device IDs we wanted, ending scan earlyz5Found all the device IPs we wanted, ending scan earlyr   zScan completed inseconds)r  z3.2z3.3z3.4z3.5z                    
zScan Complete!  Found z	 devices.zBroadcasted:zForce-Scanned:z - Matched GWID:zMatched Key:z
Unmatched:z%Force-Scan Errors: Connection Errors:zVersion Detect Failed:z, rq   z	Versions:zUnknown Devices: zMissing Local Key: zDid not find z devices by IP Address: z devices by DevID: zUndisplayed Broadcasts:r	   originrr  c              3   .   K   | ]  }|d    k(    yw)r   Nr   )r  dr\   s     r'   r
  zdevices.<locals>.<genexpr>	  s     <|!qyA~|s   cloudz#Scan complete with %s devices found)f
HAVE_COLORrr   	termcolorr   load_devicefile
DEVICEFILEr  rT   r|  rQ   RuntimeErrorr   r   r    IPPROTO_UDPru   rv   rw   SO_REUSEPORTAttributeErrorrx   UDPPORTUDPPORTS
UDPPORTAPPSCANTIMErP   rU   __version__r  boolr   ry   rz   r   r   r   list
isinstancer-   r"   r#  r1   r3   r.   DEFAULT_NETWORKr8   r  rg   r   r	   r   r   rI   r   r  r   r   r   r   intsysstdoutflushmax_parallelranger  r`  r!   r   sleepselectKeyboardInterruptexitr)  rL  recvfromdecrypt_udpr{   loadsr  r$  r%  r   r$   r   r   BROADCASTTIMEr   roundr   r   r   r   r   sortedrV   r  r   rd   anysave_snapshotfileSNAPSHOTFILE)br6   ro  rp  rq  rr  byID
show_timerrs  wantipswantidssnapshotrt  rZ  
maxdevicesr   r5   r  havekeysclientclients	clientapp	debug_ipsr~  scanned_devicesbroadcasted_devicesbroadcast_messagesbroadcasted_apps
devicelist
read_sockswrite_socksspinnerxspinnerconnect_this_roundconnect_next_round
ip_wantips
ip_wantidscan_end_earlyip_force_wants_endip_scanip_scan_runningip_scan_delayscan_end_timedevice_end_time
start_timetimeout_timescan_ips
current_ip
need_sleepuser_break_countclient_ip_broadcast_listclient_ip_broadcast_timerr   r	  add_connectedr	   ip2r   r   r;   	all_socksrI   devices_with_timers
do_timeoutr\  end_timetimwantcheck_end_timerdwr_rd  r   tgt_portrF  rJ  dnamer  r
   do_pollr[   r   	ver_countunknown_dev_countno_key_countver_strfound_countr   r   r   invalid	unmatchedr   ru  devicesarrayitemtmpr\   sb               `                                                                                    @r'   ru  ru  k  s   H  jE##E*J
$D H..z:HS%*$**w  {E   E  E  HL  HS  HS  S  TIWZddeev~~v/@/@&BTBTU&++V-@-@!D	f//1D1DaH 	RM" --0A0A6CUCUV6,,f.A.A1E	v00&2E2EqI 	b(^$ MM&..&2C2CVEWEWX	V..0C0CQG	  !2!2F4G4GK 	J'('+++9 $$
yy$++txx1E1EG	
 :dhhKHX=YYZ\<<(J$++VW IHOJJKHGgJgJ,*MGOMIIK(*MOIIEwPXZdeJ99;?LHJJ! !*'"G 	!!61T7AeH#>@   bT']GbT']G$,,/$((:=bbc y$(J	5,Jr4)ZU-D! .(-  " OOR)$)M   y#':y%+IOOY(!Mdjjaacgckckl m
+ BOOR) $T7
ND$**'LLt{{Z[BOOR!  II3X>7D:$((/ IIK!OM $))55@A '1X->->,.#!%(+6)? & $ ]TYY[8Odiik<Y]o '95JJ	/ =(J%4J$))+*;<C{{svv_<*-'c11DIIK?
zzc" #))tyy{":KKM399s?o*M
 '*ii#oO88xx!!#((+yy""388,"%Ichh= @ Cc"  .}tyy{:;a<A"3s:#77+:%J'HCRVRZRZ\cdl\mor  uH  I  OQ  R 1)HJJF	 
 !$tyy{2(-%3{+;l+J$)M'#k*::Dby$"4[%)8T%;
%-.3O.2iikO.Kc.QO),J!)-@@ (!+x!7HZ<PQZ<[`his`tu{`|%/:Db(S]J^`gikoxix:z 3B 7 3B 7 ? ? A * 1 13Fr3J L151N#1O#CWe_#-#9*<j(S]J^`gis  xA  jA  +CC*<j$PWYcgpYp*rC * 1 1# 6 + 2 2388 <69	#(( 3 !JJt,&$.J; )> A~

J(;!#"MM:{BK	BZ1$!==*b"aAAq " Dy $**, 
 D6!d'&9d)>S9$dO--/ v~"#"% t,JD$aBF	!--t5F+		96B "F6Ne$;--+1$R(t}}/KKcRTgUX\X`X``chhknoukvvy}  zE  zE   E  GV#$--tv  yA  CG  CN  CN  PV  X\  +]  ]  ^		]_ackmqr ,,%/v%?"c!&v $u #uv%#)&>F4L-1]]TXX-EH]-]`cdf`g-gjo-oruvyrz-z  ~A  .A  DG  HN  DO  .O  RV  R]  R]  .]&r*  s6&>2b8'//1EG(G%PS*(Tu +5b&'2QZ?*\#B'i(E1$ @D  @M  @M  OQ  SW  S[  S[  ;\+B/7)nrn{n{}  BF  BJ  BJ  ;K+B/7 #'&--b1'+113=NN2&&r*55f=HNN$7$;$F$Fv$NP!OJ!Q"!"VW%*
%*
-1*()#-C$'JJCIIX[O_nKn25))c/ $. &Cvv|"!"BBHcd		 &o | %B#++-2268!YY[?:N/>	 %  W$))+1MRaeienenepRp  zJknuuv+7+HG"OtG}tG}MNJ!%MtG}tG}MNJ!%M!

S[[		CSb?b&)ii#oO " -8JPTPYPYP[_xPx(,		m(C%"$<>[	 ]TYY[8Odiik<Y]o^	 

 

  +(1u(O!!#h	 , "E499;+CQ$H)U 1QqDIL! #)"-88CD)#!"Igg!#"2&11&9"$R(33E:ALr",,7I1I"2& "" ob)44Y?@)#!"Igg!#r"--f5" $//6AL2((R3E-E"2&2##?2+>+H+HB$$&# & )*3+??K{{K)	
 	~s#679GHHIH
HYH9%%b)==)q.)>>:?:a==)q.)}}glg & #S%9;MzZhjs  vB  DM  OG>	Kceln		()A|1il;;	 * 	{IabM+

<Mt{{[]$**lDKKXZtzzSWS^S^`cdk`lnuw{  xC  xC  D  E$**dkk[^_f[giprvr}r}~4::t{{KL()"-/ ) G!!"%00D	#H1v " b!,,D	#H1v2$$W)<GDM  }GNN,-DT
A<|<<"4jFD	 'H##C(   	<t=II3[ANG  		  		  		T+OOS%8:IIM_djjhkzz{"kk* +~ ! 	II*+01!1$"' !!Q&		89E">?
	\$--egiqsws~s~  AG  IM  +N  N  O		CRSWXds   /AX /AX /AX% #AX5 HAZ A A\&(,A]:X	AXXAXX	AX"X!AX"X%	AX2X1AX2X5A"AZZ	A\#Z&6A\["6A\\A\#\&AA]7]:A]?c                 <    d| v r
| d   r| d   S d| v r
| d   r| d   S y)Nr   r[  r   r   )olds    r'   	_get_gwidr    s3    }V6{s{s4y4yr)   c                     i }t        |       x|d<   |d<   dx}}ddddd d}|D ]0  }|r||v r||   r	||   ||<   || v r| |   r	| |   ||<   )||   ||<   2 |S )Nr[  r   r   r   )r	   r   r   r   r
   )r  )r  newr  r	   veritemsitms          r'   _build_itemr    s    D )3 00DJfLB"BdDE3#:#c(CDICZCHCDIc
DI  Kr)   c                    | d   }|dk(  r| d   }| d   }|s7t        d|j                  d|dd|j                  d	|j                         y |s;t        d|j                  d|dd|j                  |d
d|j
                  d
       y d|v sd|v r|j                  dz   |j                  z   }d|v r$|d   du r|j                  dz   |j                  z   }n'd|v r#|d   du r|j                  dz   |j                  z   }t        d|j                  d|dd|j                  |d
d|d|       y t        d|j                  d|dd|j                  |d
d|	       y )Nr   r   r   r	       [25.25z] z(No IP found - Battery-powered or offline18r  No Response120z[Off]Tz[On] z - DPS: )rT   r  r  rQ   rU   r|  rP   )r  r/  r5   r   r	   states         r'   _display_statusr  )  s/   <DrzF|	dB||T4==$++? 	@||T488R= 	> #:MMG+dhh6Eczc#h$.		G+dhh6Td!2		G+dhh6<<txxUCA B <<txxS: ;r)   c                     t        |       x| d<   | d<   d| v r| d   rt        | d         | d<   | d= | S d| v r| d   rt        | d         | d<   | S d| d<   | S )Nr[  r   r
  r   r   )r  r   )r  s    r'   _snapshot_load_itemr  A  s    '..CIF|E
s5z*IJ
 J	 
c	c)ns9~.I J IJr)   c                     i }t        |       |d<   ddddddd}| D ]
  }| |   ||<    |D ]  }||vs||   r||   ||<    d| v r| d   r| d   |d<   |d= d|v r|d= t        |d         |d<   |S )Nr[  r   )r	   r
  r  r   r   r
   r   r
  r   )r  r"   )r  r  r  r  s       r'   _snapshot_save_itemr  M  s     DC!DJR"RrMEHS	  d?$s)c
DI  Cy>i.DKO~Ld5k"DKKr)   c                    | rt        | t              st        } t        |       5 }t	        j
                  |      }d d d        g }r(d|v r$|d   D ]  }|j                  t        |              |r||d<   |S # 1 sw Y   >xY w)Nru  )r  r"   r  openr{   loadr   r  )fname	json_filerF  ru  r\  s        r'   load_snapshotfiler!  g  sw    :eS1	e	yy# 
G	T!	?CNN/46 #!YK 
s   A77B c                    | rt        | t              st        } |r|j                  }|j                  }ndx}}g }t        |      t        k(  rt        |j                               }|D ]  }|j                  t        |              t        j                         |d}t        j                  |d      }t        |dz   |z   dz   | z   dz          t        | d      5 }	|	j!                  |       d d d        y # 1 sw Y   y xY w)	Nr   	timestampru  r   indentz
>> zSaving device snapshot data to r  w)r  r"   r  rQ   rP   rj  dictr  rd   r   r  r   r{   r|   rT   r  r   )
r  rF  r5   normrP   ru  r  currentoutputoutfiles
             r'   r  r  t  s    :eS1{{yytGDzTDKKM"+C02 !YY[g>GZZ*F	$.4
"C
Ce
Kd
RS	eS	Wf 
		s   C55C>c                    | xr t         } t        j                  |       }t        | }t	        d|j
                  d|j                  d|j                  dt        j                  d	       	 t        t              }t	        d|j                  t        t        |d         fz         g }t	        |j                  dddddddddddddd
       t	        |j                         i }t!        |d   d       }	|	D ]  }
t#        |
d
      }|d   r|d   j%                  d      n|j                  dz   |j                  z   }|d   }|dk(  r|d   }t	        |j                  |dd|j&                  |d   dd|j(                  |d|j*                  |d    dd|j,                  |d!   d       |d   s|||d   <    |rd"}n-|rd#}n(t/        |j(                  d$z   |j                  z   d%z         }|j1                         j3                  d"      d&k  rt	        d       t	        |j                  d't        |	      d(       t5        d)| d*d*d)|+      }|	D ]|  }t7        |      }|r||vrt#        |d
      }t9        |d
|       .t#        |||         }d,||   v r,d,||   d,   v r"||   d,   d,   rt9        |||   d,   d,   |       pt9        |d
|       ~ t	        d-|j                  z         y
# t        $ rO}t	        |j                  dt        d|j                  dt        |      j                  d	|d
       Y d
}~y
d
}~ww xY w).aP  Uses snapshot.json to scan devices

    Parameters:
        color = True or False, print output in color [Default: True]
        assume_yes = True or False, auto-answer 'yes' to "Poll local devices?" (ignored when skip_poll is set)
        skip_poll = True or False, auto-answer 'no' to "Poll local devices?" (overrides assume_yes)
    r  r  r  r  r  z ERROR: Missing z file:r  rq   Nz%sLoaded %s - %d devices:
ru  Name25ID24IP15Key17Version5c                     | d   S Nr   r   xs    r'   <lambda>zsnapshot.<locals>.<lambda>      QvYr)   r   r	      zE: No IP found r   r   r   r  r   r   rD   y
Poll local devices? (Y/n): r   zPolling z$ local devices from last snapshot...FT)r6   rp  rq  r  rs  r  r/  	%s
Done.
)r  rr   r  r   rT   rP   rQ   rU   r  r!  r  r   r|  rj  r   r  r  r  ljustr  r  r  r  rO   rR   rS   ru  r  r  )rp  rt  	skip_pollr   r5   rF  r   tableby_ipdevicesxidxr   rW   r  r]   rJ  r	  r   r  s                      r'   r  r    s     jE##E*J
$D	99dkk488X-A-A	C
 . 

'488\3tICW*X
XY E	dkk6$US\
]^	$((OEd9o+>?Hc4)(.tfTl  $4::HY;Y\`\g\g;gvB;6NEXXudiisDHHV\]bVceiepeprx  zC  sDE 	F$<"(E&,  	t||&>>LyXY||~3!#b	DKKQTU]Q^_`e$TTYdijAa>D4v-"At-tT3"Avd|5F4L(UfTl56I-IfUYl[`NabgNh#T6$<+>u+EtM#T47  
-$((
"#
g  \SWS^S^`def`g`p`prstus   -K0 0	M9AMMc                 F   | xr t         } t        j                  |       }t        | }t	        d|j
                  d|j                  d|j                  dt        j                  d	       t        j                  t              }|s t	        |j                  dt        d       yt	        d	|j                  t        t        |      fz         t	        d
|j
                  z   dz   |j                  z          t        j                  t        |d       d      }	t	        |	       |rd}
n-|rd}
n(t!        |j"                  dz   |j                  z   dz         }
|
j%                         j'                  d      dk  rt)        || |d||       t	        d|j                  z         y)z|Uses devices.json to scan devices

    Parameters:
        color = True or False, print output in color [Default: True]
    r  r  r  r  r  z ERROR: Missing or empty z file
Nz%sLoaded %s - %d devices:z

zDevice Listing
c                     | d   S r9  r   r:  s    r'   r<  zalldevices.<locals>.<lambda>  s    6r)   r>  r   r%  rD   r@  rA  rB  r   T)rp  ro  r  rr  rs  rC  )r  rr   r  r   rT   rP   rQ   rU   r  r  r  r|  r  r{   r|   r  rO   r  rR   rS   poll_and_display)rp  ro  rr  rs  rt  rE  r   r5   rZ  r+  r]   s              r'   
alldevicesrM    sO     jE##E*J
$D	99dkk488X-A-A	C
 **:6K

JOP	
%:s;?O(P
PQ 
&499
1
1DHH
<=ZZ{/BCANF	&M 	t||&>>LyXY||~3!#+UXPT`it|~	-$((
"#
r)   c                    |xr t         }t        j                  |      }t        | }| D cg c]  }|d   	 }	}t	        |j
                  dz          t        ddd||	d|| |	      }
t	        d|j                  t        |
      d|j
                         t	        d       g }t	        d	       t        | d
       D ]  }t        |      }|rI||
v rEt        ||
|         }d|
|   v r!d|
|   d   v rt        ||
|   d   d   |       n't        |d |       nt        |d       }t        |d |       |j                  |        |rt        t        |
|       |S c c}w )Nr[  z+
Scanning local network for Tuya devices...FT)	r6   rq  r  ro  r  r  rr  rZ  rs  r  z local devices discoveredr   zPolling local devices...c                     | d   S r9  r   r:  s    r'   r<  z"poll_and_display.<locals>.<lambda>  s    6r)   r>  r/  )r  rr   r  r   rT   rQ   ru  rU   r  r  r  r  r  r   r  r  )rZ  rp  ro  r  rr  rs  r   r5   r;  by_idrJ  pollingrI  r   r  s                  r'   rL  rL    sd    jE##E*J
$D)*kQtWkE*	$++F
FGUD8UZgk  xA  OZ  em  nF	488S[$++
VW	"IG	
$%k':;#DFNVD\3Dt$&,u2E)Evd|E':5'A4ItT3T+DT4/t < <7N9 +s   Ec                     g } 	 t        t              }t        |d   d       }i }|D ]!  }d	|v s|d	   st        |d      }|||d	   <   # t        d
dddd
|      }|D ]  }t        |      }	|	r|	|v rt        |||	         }
nt        |d      }
|
d	   sd|
d<   n4|	|vsd||	   vsd||	   d   vs||	   d   d   sd|
d<   n||	   d   d   |
d<   | j                  |
        t        j                         | d}t        j                  |d      }t        |       y#  t        j                         dt        z  d}t        j                  |d      }t        |       Y yxY w)z;Uses snapshot.json to scan devices - respond with json
    z%Could not load JSON snapshot file: %s)r$  r   r   r%  Nru  c                     | d   S r9  r   r:  s    r'   r<  zsnapshotjson.<locals>.<lambda>.  r=  r)   r>  r	   Fr   T)r6   ro  rq  r  rs  r  zNo IPr   r/  r  r#  )r!  r  r   r{   r|   rT   r  r  ru  r  r   )rQ  rF  r*  r+  rH  rG  rI  r   respr   r  s              r'   snapshotjsonrU  !  s    G . d9o+>?HE3;3t9 #t-F%E#d) 
 514dU]bcD#DDLT$Z1DT+DDz#DMd4j!8EdTYIZ<Zbfgkblmrbstybz)DMt*U+E2DKt  "YY[g>GZZ*F	&M
C!%8_bn8noGA.fs   D AE__main__r0   )NTFTF)NT)TFN)TNFTFN)TNFFT)V__doc__
__future__r   collectionsr   rL   r{   r   r   r  r  r   r   rC  r   rr   coloramar   HAVE_COLORAMAImportErrorplatformr;  r  	raw_inputrO   	NameErrorrG   r1   r_   r3   r  r  r  
TCPTIMEOUTr   MAXCOUNTr  r  r  re  r  r  r  r   r   r   r   r  FSCAN_v3x_PROVOKE_RESPONSEr  FSCAN_v33_BRUTE_FORCE_ACTIVEr  r   r  r  	getLoggerr   ry   r(   r.   r8   r2   r4   rg   r   objectr   r   r   r`  rv  r  r  ru  r  r  r  r  r  r!  r  r  rM  rL  rU  r  r   r)   r'   <module>rf     s   & "      
     M @#,,"9"9%"@@
	EIG
 F   
$$ **  






  



 A &fg
          !    g!*
@0<6pV ]6 ]~T TnX XzD*'V D45W\im4QVdfg
R;0
4(GV(T!H(V z WA  M  		  I  Gh@  sY   G
 %G (G$ /G2 H  
GGG! G!$G/.G/2G=<G= HH