@@ -67,22 +67,107 @@ def _get_header_client_id(self):
6767 md5 .update (self ._device_identifier .encode ())
6868 return base64 .b64encode (md5 .digest ()).decode ()
6969
70- def _get_hawk_authentication (self , rriot : RRiot , url : str ) -> str :
70+ def _process_extra_hawk_values (self , values : dict | None ) -> str :
71+ if values is None :
72+ return ""
73+ else :
74+ sorted_keys = sorted (values .keys ())
75+ result = []
76+ for key in sorted_keys :
77+ value = values .get (key )
78+ result .append (f"{ key } ={ value } " )
79+ return hashlib .md5 ("&" .join (result ).encode ()).hexdigest ()
80+
81+ def _get_hawk_authentication (
82+ self , rriot : RRiot , url : str , formdata : dict | None = None , params : dict | None = None
83+ ) -> str :
7184 timestamp = math .floor (time .time ())
7285 nonce = secrets .token_urlsafe (6 )
86+ formdata_str = self ._process_extra_hawk_values (formdata )
87+ params_str = self ._process_extra_hawk_values (params )
88+
7389 prestr = ":" .join (
7490 [
7591 rriot .u ,
7692 rriot .s ,
7793 nonce ,
7894 str (timestamp ),
7995 hashlib .md5 (url .encode ()).hexdigest (),
80- "" ,
81- "" ,
96+ params_str ,
97+ formdata_str ,
8298 ]
8399 )
84100 mac = base64 .b64encode (hmac .new (rriot .h .encode (), prestr .encode (), hashlib .sha256 ).digest ()).decode ()
85- return f'Hawk id="{ rriot .u } ", s="{ rriot .s } ", ts="{ timestamp } ", nonce="{ nonce } ", mac="{ mac } "'
101+ return f'Hawk id="{ rriot .u } ",s="{ rriot .s } ",ts="{ timestamp } ",nonce="{ nonce } ",mac="{ mac } "'
102+
103+ async def nc_prepare (self , user_data : UserData , timezone : str ) -> dict :
104+ """This gets a few critical parameters for adding a device to your account."""
105+ if (
106+ user_data .rriot is None
107+ or user_data .rriot .r is None
108+ or user_data .rriot .u is None
109+ or user_data .rriot .r .a is None
110+ ):
111+ raise RoborockException ("Your userdata is missing critical attributes." )
112+ base_url = user_data .rriot .r .a
113+ prepare_request = PreparedRequest (base_url )
114+ hid = await self ._get_home_id (user_data )
115+ from aiohttp import FormData
116+
117+ data = FormData ()
118+ data .add_field ("hid" , hid )
119+ data .add_field ("tzid" , timezone )
120+
121+ prepare_response = await prepare_request .request (
122+ "post" ,
123+ "/nc/prepare" ,
124+ headers = {
125+ "Authorization" : self ._get_hawk_authentication (
126+ user_data .rriot , "/nc/prepare" , {"hid" : hid , "tzid" : timezone }
127+ ),
128+ },
129+ data = data ,
130+ )
131+
132+ if prepare_response is None :
133+ raise RoborockException ("prepare_response is None" )
134+ if not prepare_response .get ("success" ):
135+ raise RoborockException (f"{ prepare_response .get ('msg' )} - response code: { prepare_response .get ('code' )} " )
136+
137+ return prepare_response ["result" ]
138+
139+ async def add_device (self , user_data : UserData , s : str , t : str ) -> dict :
140+ """This will add a new device to your account
141+ it is recommended to only use this if you know what you are doing."""
142+ if (
143+ user_data .rriot is None
144+ or user_data .rriot .r is None
145+ or user_data .rriot .u is None
146+ or user_data .rriot .r .a is None
147+ ):
148+ raise RoborockException ("Your userdata is missing critical attributes." )
149+ base_url = user_data .rriot .r .a
150+ add_device_request = PreparedRequest (base_url )
151+
152+ add_device_response = await add_device_request .request (
153+ "GET" ,
154+ "/user/devices/newadd" ,
155+ headers = {
156+ "Authorization" : self ._get_hawk_authentication (
157+ user_data .rriot , "/user/devices/newadd" , params = {"s" : s , "t" : t }
158+ ),
159+ },
160+ params = {"s" : s , "t" : t },
161+ )
162+
163+ if add_device_response is None :
164+ raise RoborockException ("add_device is None" )
165+ if not add_device_response .get ("success" ):
166+ raise RoborockException (
167+ f"{ add_device_response .get ('msg' )} - response code: { add_device_response .get ('code' )} "
168+ )
169+
170+ return add_device_response ["result" ]
86171
87172 async def request_code (self ) -> None :
88173 base_url = await self ._get_base_url ()
0 commit comments