@@ -92,22 +92,21 @@ async def request(
9292
9393class RoborockClient :
9494
95- def __init__ (self , endpoint : str , device_localkey : dict [str , str ], prefixed = False ) -> None :
95+ def __init__ (self , endpoint : str , device_localkey : dict [str , str ]) -> None :
9696 self .device_localkey = device_localkey
9797 self ._seq = 1
9898 self ._random = 4711
9999 self ._id_counter = 10000
100100 self ._salt = "TXdfu$jyZ#TZHsg4"
101- self ._endpoint = base64 . b64encode ( md5bin ( endpoint )[ 8 : 14 ]). decode ()
101+ self ._endpoint = endpoint
102102 self ._nonce = secrets .token_bytes (16 )
103- self ._prefixed = prefixed
104103 self ._waiting_queue : dict [int , RoborockQueue ] = {}
105104 self ._status_listeners : list [Callable [[str , str ], None ]] = []
106105
107106 def _decode_msg (self , msg : bytes , local_key : str ) -> dict [str , Any ]:
108- if self . _prefixed :
107+ if msg [ 4 : 7 ] == "1.0" . encode () :
109108 msg = msg [4 :]
110- if msg [0 :3 ] != "1.0" .encode ():
109+ elif msg [0 :3 ] != "1.0" .encode ():
111110 raise RoborockException (f"Unknown protocol version { msg [0 :3 ]} " )
112111 if len (msg ) == 17 :
113112 [version , _seq , _random , timestamp , protocol ] = struct .unpack (
@@ -118,31 +117,27 @@ def _decode_msg(self, msg: bytes, local_key: str) -> dict[str, Any]:
118117 "timestamp" : timestamp ,
119118 "protocol" : protocol ,
120119 }
121- # crc32 = binascii.crc32(msg[0: len(msg) - 4])
122120 [version , _seq , _random , timestamp , protocol , payload_len ] = struct .unpack (
123121 "!3sIIIHH" , msg [0 :19 ]
124122 )
125- if not payload_len :
126- return {
127- "version" : version ,
128- "timestamp" : timestamp ,
129- "protocol" : protocol ,
130- }
131- [payload , expected_crc32 ] = struct .unpack_from (f"!{ payload_len } sI" , msg , 19 )
132- # if crc32 != expected_crc32:
133- # raise RoborockException(f"Wrong CRC32 {crc32}, expected {expected_crc32}")
123+ extra_len = len (msg ) - 23 - payload_len
124+ [payload , expected_crc32 , extra ] = struct .unpack_from (f"!{ payload_len } sI{ extra_len } s" , msg , 19 )
125+ if not extra_len :
126+ crc32 = binascii .crc32 (msg [0 : 19 + payload_len ])
127+ if crc32 != expected_crc32 :
128+ raise RoborockException (f"Wrong CRC32 { crc32 } , expected { expected_crc32 } " )
134129
135130 aes_key = md5bin (encode_timestamp (timestamp ) + local_key + self ._salt )
136131 decipher = AES .new (aes_key , AES .MODE_ECB )
137- decrypted_payload = unpad (decipher .decrypt (payload ), AES .block_size )
132+ decrypted_payload = unpad (decipher .decrypt (payload ), AES .block_size ) if payload else extra
138133 return {
139134 "version" : version ,
140135 "timestamp" : timestamp ,
141136 "protocol" : protocol ,
142- "payload" : decrypted_payload ,
137+ "payload" : decrypted_payload
143138 }
144139
145- def _encode_msg (self , device_id , protocol , timestamp , payload , prefix = '' ) -> bytes :
140+ def _encode_msg (self , device_id , protocol , timestamp , payload , prefix = None ) -> bytes :
146141 local_key = self .device_localkey [device_id ]
147142 aes_key = md5bin (encode_timestamp (timestamp ) + local_key + self ._salt )
148143 cipher = AES .new (aes_key , AES .MODE_ECB )
@@ -157,13 +152,13 @@ def _encode_msg(self, device_id, protocol, timestamp, payload, prefix='') -> byt
157152 encrypted_len ,
158153 encrypted
159154 ]
160- if self . _prefixed :
155+ if prefix :
161156 values = [prefix ] + values
162157 msg = struct .pack (
163- f"!{ 'I' if self . _prefixed else '' } 3sIIIHH{ encrypted_len } s" ,
158+ f"!{ 'I' if prefix else '' } 3sIIIHH{ encrypted_len } s" ,
164159 * values
165160 )
166- crc32 = binascii .crc32 (msg [4 :] if self . _prefixed else msg )
161+ crc32 = binascii .crc32 (msg [4 :] if prefix else msg )
167162 msg += struct .pack ("!I" , crc32 )
168163 return msg
169164
@@ -258,7 +253,7 @@ def _get_payload(
258253 if secured :
259254 inner ["security" ] = {
260255 "endpoint" : self ._endpoint ,
261- "nonce" : "39344139463753454b4851444f4a4442" ,
256+ "nonce" : self . _nonce . hex (). upper () ,
262257 }
263258 payload = bytes (
264259 json .dumps (
0 commit comments