From dd3a80b053e20aa98484629a942b55b2619f3cd5 Mon Sep 17 00:00:00 2001 From: Anton Polikasov <61949281+polikasov@users.noreply.github.com> Date: Sun, 18 Sep 2022 19:12:15 +0300 Subject: [PATCH 1/3] add yeedi support --- deebot_t8/auth_client.py | 47 +++++++++++++++++++++++++-------------- deebot_t8/cli/__main__.py | 7 +++++- deebot_t8/cli/config.py | 3 +++ 3 files changed, 39 insertions(+), 18 deletions(-) diff --git a/deebot_t8/auth_client.py b/deebot_t8/auth_client.py index 627eb85..cc79e8b 100644 --- a/deebot_t8/auth_client.py +++ b/deebot_t8/auth_client.py @@ -15,26 +15,34 @@ LOGGER = logging.getLogger(__name__) -CLIENT_KEY = "1520391301804" -CLIENT_SECRET = "6c319b2a5cd3e66e39159c2e28f2fce9" -AUTH_CLIENT_KEY = "1520391491841" -AUTH_CLIENT_SECRET = "77ef58ce3afbe337da74aa8c5ab963a9" - class DeebotAuthClient: - def __init__(self, portal_client: PortalClient, device_id: str, country: str): + def __init__(self, portal_client: PortalClient, device_id: str, country: str, vendor: str): self._portal_client = portal_client self._device_id = device_id self._country = country + self._vendor = vendor self._meta = { "country": country, "lang": "EN", "deviceId": device_id, - "appCode": "global_e", - "appVersion": "1.6.3", "channel": "google_play", "deviceType": "1", } + if self._vendor == 'ecovacs': + self._CLIENT_KEY = "1520391301804" + self._CLIENT_SECRET = "6c319b2a5cd3e66e39159c2e28f2fce9" + self._AUTH_CLIENT_KEY = "1520391491841" + self._AUTH_CLIENT_SECRET = "77ef58ce3afbe337da74aa8c5ab963a9" + self._meta["appCode"] = "global_e" + self._meta["appVersion"] = "1.6.3" + elif self._vendor == 'yeedi': + self._CLIENT_KEY = "1581917520081" + self._CLIENT_SECRET = "ed5b3dd9a0253de7d90305d077eb5fee" + self._AUTH_CLIENT_KEY = "1581923437995" + self._AUTH_CLIENT_SECRET = "304a71592690995b2bb304e66b5ddee6" + self._meta["appCode"] = "yd_global_e" + self._meta["appVersion"] = "1.3.0" def _sign_params( self, @@ -53,15 +61,15 @@ def _get_login_url(self): tld = "cn" if self._country == "cn" else "com" login_path = "user/loginCheckMobile" if self._country == "cn" else "user/login" return ( - "https://gl-{country}-api.ecovacs.{tld}/v1/private/{country}/" + "https://gl-{country}-api.{vendor}.{tld}/v1/private/{country}/" "{lang}/{deviceId}/{appCode}/{appVersion}/{channel}/" "{deviceType}/{login_path}" - ).format(login_path=login_path, tld=tld, **self._meta) + ).format(login_path=login_path, tld=tld, vendor=self._vendor, **self._meta) def _get_authcode_url(self): tld = "cn" if self._country == "cn" else "com" return ( - f"https://gl-{self._country}-openapi.ecovacs.{tld}/" + f"https://gl-{self._country}-openapi.{self._vendor}.{tld}/" f"v1/global/auth/getAuthCode" ) @@ -78,10 +86,10 @@ def do_account_password_exchange( # Sign params params_sig = self._sign_params( - {**self._meta, **params}, CLIENT_KEY, CLIENT_SECRET + {**self._meta, **params}, self._CLIENT_KEY, self._CLIENT_SECRET ) params["authSign"] = params_sig - params["authAppkey"] = CLIENT_KEY + params["authAppkey"] = self._CLIENT_KEY url = self._get_login_url() @@ -120,11 +128,11 @@ def do_get_authcode(self, uid: str, access_token: str): "openId": "global", **params, }, - AUTH_CLIENT_KEY, - AUTH_CLIENT_SECRET, + self._AUTH_CLIENT_KEY, + self._AUTH_CLIENT_SECRET, ) params["authSign"] = params_sig - params["authAppkey"] = AUTH_CLIENT_KEY + params["authAppkey"] = self._AUTH_CLIENT_KEY # Do request resp = requests.get(self._get_authcode_url(), params=params) @@ -144,7 +152,10 @@ def do_get_authcode(self, uid: str, access_token: str): ) def do_login_by_iot_token(self, user_id: str, auth_code: str): - org = "ECOCN" if self._country == "cn" else "ECOWW" + if self._vendor == 'ecovacs': + org = "ECOCN" if self._country == "cn" else "ECOWW" + elif self._vendor == 'yeedi': + org = "ECOYDCN" if self._country == "cn" else "ECOYDWW" country = "Chinese" if self._country == "cn" else self._country.upper() resp = self._portal_client.do_post( @@ -186,6 +197,7 @@ def __init__( self, auth_client: DeebotAuthClient, country: str, + vendor: str, device_id: str, account_id: str, password_hash: str, @@ -194,6 +206,7 @@ def __init__( ): self._auth_client = auth_client self._country = country + self._vendor = vendor self._device_id = device_id self._account_id = account_id diff --git a/deebot_t8/cli/__main__.py b/deebot_t8/cli/__main__.py index 11096ad..4eae986 100644 --- a/deebot_t8/cli/__main__.py +++ b/deebot_t8/cli/__main__.py @@ -65,10 +65,12 @@ def on_credentials_changed(credentials: Credentials): portal_client=portal_client, device_id=config.device_id, country=config.country, + vendor=config.vendor, ) authenticator = Authenticator( auth_client=auth_client, country=config.country, + vendor=config.vendor, device_id=config.device_id, account_id=config.username, password_hash=config.password_hash, @@ -100,9 +102,10 @@ def renew_access_tokens_impl(auth: DeebotAuthClient, config: Config): @click.option("--username", type=str, required=True) @click.option("--password", type=str, required=True) @click.option("--country", type=str, required=True) +@click.option("--vendor", type=str, required=True) @click.option("--continent", type=str, required=True) @click.option("--regen-device", type=bool) -def login(obj: TypedObj, username, password, country, continent, regen_device): +def login(obj: TypedObj, username, password, country, vendor, continent, regen_device): # TODO(NW): Infer continent from country if not regen_device and obj.config is not None and obj.config.device_id is not None: @@ -116,6 +119,7 @@ def login(obj: TypedObj, username, password, country, continent, regen_device): password_hash=md5_hex(password), device_id=device_id, country=country, + vendor=vendor, continent=continent, ) # Recreate clients for this special use case to apply new configuration @@ -129,6 +133,7 @@ def login(obj: TypedObj, username, password, country, continent, regen_device): portal_client=portal_client, device_id=obj.config.device_id, country=obj.config.country, + vendor=obj.config.vendor ) write_config(obj.config_path, obj.config) diff --git a/deebot_t8/cli/config.py b/deebot_t8/cli/config.py index e5da723..1224ccb 100644 --- a/deebot_t8/cli/config.py +++ b/deebot_t8/cli/config.py @@ -16,6 +16,7 @@ class Config: username: str password_hash: str country: str + vendor: str continent: str device_id: str @@ -33,6 +34,7 @@ def serialize(self): "username": self.username, "passwordHash": self.password_hash, "country": self.country, + "vendor": self.vendor, "continent": self.continent, "deviceId": self.device_id, "credentials": creds, @@ -52,6 +54,7 @@ def deserialize(cls, o): username=o["username"], password_hash=o["passwordHash"], country=o["country"], + vendor=o["vendor"], continent=o["continent"], device_id=o["deviceId"], credentials=creds, From 21bee85450062ca2225fd84283287e484db40824 Mon Sep 17 00:00:00 2001 From: Anton Polikasov <61949281+polikasov@users.noreply.github.com> Date: Sun, 18 Sep 2022 19:41:26 +0300 Subject: [PATCH 2/3] remove vendor from authenticator --- deebot_t8/auth_client.py | 2 -- deebot_t8/cli/__main__.py | 1 - 2 files changed, 3 deletions(-) diff --git a/deebot_t8/auth_client.py b/deebot_t8/auth_client.py index cc79e8b..fcf4a9c 100644 --- a/deebot_t8/auth_client.py +++ b/deebot_t8/auth_client.py @@ -197,7 +197,6 @@ def __init__( self, auth_client: DeebotAuthClient, country: str, - vendor: str, device_id: str, account_id: str, password_hash: str, @@ -206,7 +205,6 @@ def __init__( ): self._auth_client = auth_client self._country = country - self._vendor = vendor self._device_id = device_id self._account_id = account_id diff --git a/deebot_t8/cli/__main__.py b/deebot_t8/cli/__main__.py index 4eae986..f57f7a6 100644 --- a/deebot_t8/cli/__main__.py +++ b/deebot_t8/cli/__main__.py @@ -70,7 +70,6 @@ def on_credentials_changed(credentials: Credentials): authenticator = Authenticator( auth_client=auth_client, country=config.country, - vendor=config.vendor, device_id=config.device_id, account_id=config.username, password_hash=config.password_hash, From ca930a4b5c43cab4d269f9296bd9355b705852f9 Mon Sep 17 00:00:00 2001 From: Anton Polikasov <61949281+polikasov@users.noreply.github.com> Date: Sun, 18 Sep 2022 23:55:06 +0300 Subject: [PATCH 3/3] add content to clean, charge cmd --- deebot_t8/entity.py | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/deebot_t8/entity.py b/deebot_t8/entity.py index a464245..a2c1e39 100644 --- a/deebot_t8/entity.py +++ b/deebot_t8/entity.py @@ -539,13 +539,31 @@ def stop(self): ) def pause(self): - self.exc_command("clean_V2", {"act": "pause"}) + self.exc_command( + "clean_V2", + { + "act": "pause", + "content": {"count": "", "donotClean": "", "type": "", "value": ""}, + } + ) def resume(self): - self.exc_command("clean_V2", {"act": "resume"}) + self.exc_command( + "clean_V2", + { + "act": "resume", + "content": {"count": "", "donotClean": "", "type": "", "value": ""}, + } + ) def return_to_charge(self): - self.exc_command("charge", {"act": "go"}) + self.exc_command( + "charge", + { + "act": "go", + "content": {"count": "", "donotClean": "", "type": "", "value": ""}, + } + ) def relocate(self): self.exc_command("setRelocationState", {"mode": "manu"})