2222 RoborockInvalidEmail ,
2323 RoborockInvalidUserAgreement ,
2424 RoborockMissingParameters ,
25+ RoborockNoResponseFromBaseURL ,
2526 RoborockNoUserAgreement ,
2627 RoborockRateLimit ,
2728 RoborockTooFrequentCodeRequests ,
28- RoborockTooManyRequest ,
29- RoborockUrlException ,
3029)
3130
3231_LOGGER = logging .getLogger (__name__ )
@@ -52,37 +51,49 @@ class RoborockApiClient:
5251 def __init__ (self , username : str , base_url = None , session : aiohttp .ClientSession | None = None ) -> None :
5352 """Sample API Client."""
5453 self ._username = username
55- self ._default_url = "https://euiot.roborock.com"
5654 self .base_url = base_url
5755 self ._device_identifier = secrets .token_urlsafe (16 )
5856 self .session = session
57+ self ._country = None
58+ self ._country_code = None
5959
6060 async def _get_base_url (self ) -> str :
6161 if not self .base_url :
62- url_request = PreparedRequest (self ._default_url , self .session )
63- response = await url_request .request (
64- "post" ,
65- "/api/v1/getUrlByEmail" ,
66- params = {"email" : self ._username , "needtwostepauth" : "false" },
62+ for iot_url in [
63+ "https://usiot.roborock.com" ,
64+ "https://euiot.roborock.com" ,
65+ "https://cniot.roborock.com" ,
66+ "https://ruiot.roborock.com" ,
67+ ]:
68+ url_request = PreparedRequest (iot_url , self .session )
69+ response = await url_request .request (
70+ "post" ,
71+ "/api/v1/getUrlByEmail" ,
72+ params = {"email" : self ._username , "needtwostepauth" : "false" },
73+ )
74+ if response is None :
75+ continue
76+ response_code = response .get ("code" )
77+ if response_code != 200 :
78+ if response_code == 2003 :
79+ raise RoborockInvalidEmail ("Your email was incorrectly formatted." )
80+ elif response_code == 1001 :
81+ raise RoborockMissingParameters (
82+ "You are missing parameters for this request, are you sure you entered your username?"
83+ )
84+ else :
85+ _LOGGER .warning (
86+ "Failed to get base url for %s with the following context: %s" , self ._username , response
87+ )
88+ if response ["data" ]["countrycode" ] is not None :
89+ self ._country_code = response ["data" ]["countrycode" ]
90+ self ._country = response ["data" ]["country" ]
91+ self .base_url = response ["data" ]["url" ]
92+ return self .base_url
93+ raise RoborockNoResponseFromBaseURL (
94+ "No account was found for any base url we tried. Either your email is incorrect or we do not have a"
95+ " record of the roborock server your device is on."
6796 )
68- if response is None :
69- raise RoborockUrlException ("get url by email returned None" )
70- response_code = response .get ("code" )
71- if response_code != 200 :
72- _LOGGER .info ("Get base url failed for %s with the following context: %s" , self ._username , response )
73- if response_code == 2003 :
74- raise RoborockInvalidEmail ("Your email was incorrectly formatted." )
75- elif response_code == 1001 :
76- raise RoborockMissingParameters (
77- "You are missing parameters for this request, are you sure you entered your username?"
78- )
79- elif response_code == 9002 :
80- raise RoborockTooManyRequest ("Please temporarily disable making requests and try again later." )
81- raise RoborockUrlException (f"error code: { response_code } msg: { response .get ('error' )} " )
82- response_data = response .get ("data" )
83- if response_data is None :
84- raise RoborockUrlException ("response does not have 'data'" )
85- self .base_url = response_data .get ("url" )
8697 return self .base_url
8798
8899 def _get_header_client_id (self ):
@@ -249,14 +260,20 @@ async def _sign_key_v3(self, s: str) -> str:
249260
250261 return code_response ["data" ]["k" ]
251262
252- async def code_login_v4 (self , code : int | str , country : str , country_code : int ) -> UserData :
263+ async def code_login_v4 (
264+ self , code : int | str , country : str | None = None , country_code : int | None = None
265+ ) -> UserData :
253266 """
254267 Login via code authentication.
255268 :param code: The code from the email.
256269 :param country: The two-character representation of the country, i.e. "US"
257270 :param country_code: the country phone number code i.e. 1 for US.
258271 """
259272 base_url = await self ._get_base_url ()
273+ if country is None :
274+ country = self ._country
275+ if country_code is None :
276+ country_code = self ._country_code
260277 header_clientid = self ._get_header_client_id ()
261278 x_mercy_ks = "" .join (secrets .choice (string .ascii_letters + string .digits ) for _ in range (16 ))
262279 x_mercy_k = await self ._sign_key_v3 (x_mercy_ks )
0 commit comments