From 10e115cba3b6fb4c6b8988a5952ba21443d3c07d Mon Sep 17 00:00:00 2001 From: 0x3d Date: Wed, 7 Feb 2024 00:19:55 +0100 Subject: [PATCH 01/11] Accomodate for Stellantis' Jan 23 OAuth changes (still one manual step involved during setup but at least the error 500 is gone) --- psa_car_controller/psa/constants.py | 2 +- psa_car_controller/psa/oauth.py | 26 +++++++++++++++++-- psa_car_controller/psa/setup/app_decoder.py | 2 +- .../psacc/application/psa_client.py | 4 +-- 4 files changed, 28 insertions(+), 6 deletions(-) diff --git a/psa_car_controller/psa/constants.py b/psa_car_controller/psa/constants.py index e10fbd4..9c7e848 100644 --- a/psa_car_controller/psa/constants.py +++ b/psa_car_controller/psa/constants.py @@ -28,7 +28,7 @@ DEFAULT_PRECONDITIONING_PROGRAM = { "program3": {"day": [0, 0, 0, 0, 0, 0, 0], "hour": 34, "minute": 7, "on": 0}, "program4": {"day": [0, 0, 0, 0, 0, 0, 0], "hour": 34, "minute": 7, "on": 0} } -AUTHORIZE_SERVICE = "https://api.mpsa.com/api/connectedcar/v2/oauth/authorize" +AUTHORIZE_SERVICE = "https://idpcvs.opel.com/am/oauth2/authorize" REMOTE_URL = "https://api.groupe-psa.com/connectedcar/v4/virtualkey/remoteaccess/token?client_id=" BRAND = {"com.psa.mym.myopel": {"realm": "clientsB2COpel", "brand_code": "OP", "app_name": "MyOpel"}, "com.psa.mym.mypeugeot": {"realm": "clientsB2CPeugeot", "brand_code": "AP", "app_name": "MyPeugeot"}, diff --git a/psa_car_controller/psa/oauth.py b/psa_car_controller/psa/oauth.py index 26a4590..e4aad02 100644 --- a/psa_car_controller/psa/oauth.py +++ b/psa_car_controller/psa/oauth.py @@ -1,4 +1,9 @@ import logging +import hashlib +import secrets +import base64 +from typing import Tuple + from http import HTTPStatus from typing import Optional @@ -22,8 +27,25 @@ class OpenIdCredentialManager(CredentialManager): return {"grant_type": 'password', "username": login, "scope": ' '.join(self.service_information.scopes), "password": password, "realm": realm} - def init_with_user_credentials_realm(self, login: str, password: str, realm: str): - self._token_request(self._grant_password_request_realm(login, password, realm), True) + def generate_sha256_pkce(self, length: int) -> Tuple[str, str]: + if not (43 <= length <= 128): + raise Exception("Invalid length: " % str(length)) + verifier = secrets.token_urlsafe(length) + encoded = base64.urlsafe_b64encode(hashlib.sha256(verifier.encode('ascii')).digest()) + challenge = encoded.decode('ascii')[:-1] + return verifier, challenge + + def init_with_user_credentials_realm(self, country_code: str, realm: str): + redir_uri = "mymop://oauth2redirect/" + country_code.lower() + code_verifier, code_challenge = self.generate_sha256_pkce(64) + url = self.generate_authorize_url(redir_uri, secrets.token_urlsafe(16), code_challenge=code_challenge, code_challenge_method="S256") + + ret = "" + while len(ret) != 36: + logger.info("Now login to this URL in a browser: " + url) + ret = input("\nCopy+paste the resulting mymop-code (in F12 > Network when you hit the final OK button, 36 chars, UUID format): ") + + self._token_request(dict(grant_type='authorization_code', code=ret, redirect_uri=redir_uri, code_verifier=code_verifier), False) @staticmethod def _is_token_expired(response: Response) -> bool: diff --git a/psa_car_controller/psa/setup/app_decoder.py b/psa_car_controller/psa/setup/app_decoder.py index c6f4128..3694fd9 100755 --- a/psa_car_controller/psa/setup/app_decoder.py +++ b/psa_car_controller/psa/setup/app_decoder.py @@ -92,7 +92,7 @@ def firstLaunchConfig(package_name, client_email, client_password, country_code, psacc = PSAClient(None, apk_parser.client_id, apk_parser.client_secret, None, customer_id, BRAND[package_name]["realm"], country_code) - psacc.connect(client_email, client_password) + psacc.connect(country_code) psacc.save_config(name=config_prefix + "config.json") res = psacc.get_vehicles() diff --git a/psa_car_controller/psacc/application/psa_client.py b/psa_car_controller/psacc/application/psa_client.py index 8df313f..dbd47b1 100644 --- a/psa_car_controller/psacc/application/psa_client.py +++ b/psa_car_controller/psacc/application/psa_client.py @@ -31,8 +31,8 @@ logger = CustomLogger.getLogger(__name__) class PSAClient: - def connect(self, user, password): - self.manager.init_with_user_credentials_realm(user, password, self.realm) + def connect(self, country_code): + self.manager.init_with_user_credentials_realm(country_code, self.realm) # pylint: disable=too-many-arguments def __init__(self, refresh_token, client_id, client_secret, remote_refresh_token, customer_id, realm, country_code, From cdf7f85bf997257ad4307028f1e41c5698b70ec8 Mon Sep 17 00:00:00 2001 From: 0x3d Date: Wed, 7 Feb 2024 00:19:55 +0100 Subject: [PATCH 02/11] Accomodate for Stellantis' Jan 23 OAuth changes (still one manual step involved during setup but at least the error 500 is gone) --- psa_car_controller/psa/constants.py | 2 +- psa_car_controller/psa/oauth.py | 28 +++++++++++++++++-- psa_car_controller/psa/setup/app_decoder.py | 2 +- .../psacc/application/psa_client.py | 4 +-- 4 files changed, 30 insertions(+), 6 deletions(-) diff --git a/psa_car_controller/psa/constants.py b/psa_car_controller/psa/constants.py index e10fbd4..9c7e848 100644 --- a/psa_car_controller/psa/constants.py +++ b/psa_car_controller/psa/constants.py @@ -28,7 +28,7 @@ DEFAULT_PRECONDITIONING_PROGRAM = { "program3": {"day": [0, 0, 0, 0, 0, 0, 0], "hour": 34, "minute": 7, "on": 0}, "program4": {"day": [0, 0, 0, 0, 0, 0, 0], "hour": 34, "minute": 7, "on": 0} } -AUTHORIZE_SERVICE = "https://api.mpsa.com/api/connectedcar/v2/oauth/authorize" +AUTHORIZE_SERVICE = "https://idpcvs.opel.com/am/oauth2/authorize" REMOTE_URL = "https://api.groupe-psa.com/connectedcar/v4/virtualkey/remoteaccess/token?client_id=" BRAND = {"com.psa.mym.myopel": {"realm": "clientsB2COpel", "brand_code": "OP", "app_name": "MyOpel"}, "com.psa.mym.mypeugeot": {"realm": "clientsB2CPeugeot", "brand_code": "AP", "app_name": "MyPeugeot"}, diff --git a/psa_car_controller/psa/oauth.py b/psa_car_controller/psa/oauth.py index 26a4590..4ad5098 100644 --- a/psa_car_controller/psa/oauth.py +++ b/psa_car_controller/psa/oauth.py @@ -1,4 +1,9 @@ import logging +import hashlib +import secrets +import base64 +from typing import Tuple + from http import HTTPStatus from typing import Optional @@ -22,8 +27,27 @@ class OpenIdCredentialManager(CredentialManager): return {"grant_type": 'password', "username": login, "scope": ' '.join(self.service_information.scopes), "password": password, "realm": realm} - def init_with_user_credentials_realm(self, login: str, password: str, realm: str): - self._token_request(self._grant_password_request_realm(login, password, realm), True) + def generate_sha256_pkce(self, length: int) -> Tuple[str, str]: + if not (43 <= length <= 128): + raise ValueError("Invalid length: " % str(length)) + verifier = secrets.token_urlsafe(length) + encoded = base64.urlsafe_b64encode(hashlib.sha256(verifier.encode('ascii')).digest()) + challenge = encoded.decode('ascii')[:-1] + return verifier, challenge + + def init_with_user_credentials_realm(self, country_code: str): + redir_uri = "mymop://oauth2redirect/" + country_code.lower() + code_verifier, code_challenge = self.generate_sha256_pkce(64) + url = self.generate_authorize_url(redir_uri, secrets.token_urlsafe(16), + code_challenge=code_challenge, code_challenge_method="S256") + + ret = "" + while len(ret) != 36: + logger.info("Now login to this URL in a browser: " + url) + ret = input("\nCopy+paste the resulting mymop-code (in F12 > Network when you hit the final OK button, 36 chars, UUID format): ") + + self._token_request({ "grant_type": 'authorization_code', "code": ret, + "redirect_uri": redir_uri, "code_verifier": code_verifier), False) @staticmethod def _is_token_expired(response: Response) -> bool: diff --git a/psa_car_controller/psa/setup/app_decoder.py b/psa_car_controller/psa/setup/app_decoder.py index c6f4128..3694fd9 100755 --- a/psa_car_controller/psa/setup/app_decoder.py +++ b/psa_car_controller/psa/setup/app_decoder.py @@ -92,7 +92,7 @@ def firstLaunchConfig(package_name, client_email, client_password, country_code, psacc = PSAClient(None, apk_parser.client_id, apk_parser.client_secret, None, customer_id, BRAND[package_name]["realm"], country_code) - psacc.connect(client_email, client_password) + psacc.connect(country_code) psacc.save_config(name=config_prefix + "config.json") res = psacc.get_vehicles() diff --git a/psa_car_controller/psacc/application/psa_client.py b/psa_car_controller/psacc/application/psa_client.py index 8df313f..dbd47b1 100644 --- a/psa_car_controller/psacc/application/psa_client.py +++ b/psa_car_controller/psacc/application/psa_client.py @@ -31,8 +31,8 @@ logger = CustomLogger.getLogger(__name__) class PSAClient: - def connect(self, user, password): - self.manager.init_with_user_credentials_realm(user, password, self.realm) + def connect(self, country_code): + self.manager.init_with_user_credentials_realm(country_code, self.realm) # pylint: disable=too-many-arguments def __init__(self, refresh_token, client_id, client_secret, remote_refresh_token, customer_id, realm, country_code, From be3238f85bd9031fd894b6cb747b0c125084e753 Mon Sep 17 00:00:00 2001 From: 0x3d Date: Wed, 7 Feb 2024 00:38:16 +0100 Subject: [PATCH 03/11] Happy linter --- psa_car_controller/psa/oauth.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/psa_car_controller/psa/oauth.py b/psa_car_controller/psa/oauth.py index 4ad5098..ae56125 100644 --- a/psa_car_controller/psa/oauth.py +++ b/psa_car_controller/psa/oauth.py @@ -44,10 +44,11 @@ class OpenIdCredentialManager(CredentialManager): ret = "" while len(ret) != 36: logger.info("Now login to this URL in a browser: " + url) - ret = input("\nCopy+paste the resulting mymop-code (in F12 > Network when you hit the final OK button, 36 chars, UUID format): ") + ret = input("\nCopy+paste the resulting mymop-code (in F12 > Network" \ + "when you hit the final OK button, 36 chars, UUID format): ") self._token_request({ "grant_type": 'authorization_code', "code": ret, - "redirect_uri": redir_uri, "code_verifier": code_verifier), False) + "redirect_uri": redir_uri, "code_verifier": code_verifier}, False) @staticmethod def _is_token_expired(response: Response) -> bool: From 034ce5d3cc847549ea1158d050deee88664d43cd Mon Sep 17 00:00:00 2001 From: 0x3d Date: Wed, 7 Feb 2024 00:42:36 +0100 Subject: [PATCH 04/11] more linitng issues --- psa_car_controller/psa/oauth.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/psa_car_controller/psa/oauth.py b/psa_car_controller/psa/oauth.py index ae56125..d0e9b43 100644 --- a/psa_car_controller/psa/oauth.py +++ b/psa_car_controller/psa/oauth.py @@ -29,7 +29,7 @@ class OpenIdCredentialManager(CredentialManager): def generate_sha256_pkce(self, length: int) -> Tuple[str, str]: if not (43 <= length <= 128): - raise ValueError("Invalid length: " % str(length)) + raise ValueError("Invalid length: %s", str(length)) verifier = secrets.token_urlsafe(length) encoded = base64.urlsafe_b64encode(hashlib.sha256(verifier.encode('ascii')).digest()) challenge = encoded.decode('ascii')[:-1] @@ -43,7 +43,7 @@ class OpenIdCredentialManager(CredentialManager): ret = "" while len(ret) != 36: - logger.info("Now login to this URL in a browser: " + url) + logger.info("Now login to this URL in a browser: %s", url) ret = input("\nCopy+paste the resulting mymop-code (in F12 > Network" \ "when you hit the final OK button, 36 chars, UUID format): ") From 82a3df1febd4403d2d4059d91e1ac3e778be2c93 Mon Sep 17 00:00:00 2001 From: 0x3d Date: Wed, 7 Feb 2024 00:47:09 +0100 Subject: [PATCH 05/11] Derp. Starting to think 2 days of OAuth deep-diving was the easy part :-D --- psa_car_controller/psa/oauth.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/psa_car_controller/psa/oauth.py b/psa_car_controller/psa/oauth.py index d0e9b43..07eee23 100644 --- a/psa_car_controller/psa/oauth.py +++ b/psa_car_controller/psa/oauth.py @@ -29,7 +29,7 @@ class OpenIdCredentialManager(CredentialManager): def generate_sha256_pkce(self, length: int) -> Tuple[str, str]: if not (43 <= length <= 128): - raise ValueError("Invalid length: %s", str(length)) + raise ValueError("Invalid length: %d" % length) verifier = secrets.token_urlsafe(length) encoded = base64.urlsafe_b64encode(hashlib.sha256(verifier.encode('ascii')).digest()) challenge = encoded.decode('ascii')[:-1] From 9bcf2aeaf582dc8ea16edc009e570e4c31dd5eae Mon Sep 17 00:00:00 2001 From: 0x3d Date: Wed, 7 Feb 2024 01:17:44 +0100 Subject: [PATCH 06/11] Linters don't code --- psa_car_controller/psa/oauth.py | 5 +++-- psa_car_controller/psacc/application/psa_client.py | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/psa_car_controller/psa/oauth.py b/psa_car_controller/psa/oauth.py index 07eee23..900636d 100644 --- a/psa_car_controller/psa/oauth.py +++ b/psa_car_controller/psa/oauth.py @@ -41,10 +41,11 @@ class OpenIdCredentialManager(CredentialManager): url = self.generate_authorize_url(redir_uri, secrets.token_urlsafe(16), code_challenge=code_challenge, code_challenge_method="S256") + logger.info("Now login to this URL in a browser: %s", url) + ret = "" while len(ret) != 36: - logger.info("Now login to this URL in a browser: %s", url) - ret = input("\nCopy+paste the resulting mymop-code (in F12 > Network" \ + ret = input("\nCopy+paste the resulting mymop-code (in F12 > Network, " \ "when you hit the final OK button, 36 chars, UUID format): ") self._token_request({ "grant_type": 'authorization_code', "code": ret, diff --git a/psa_car_controller/psacc/application/psa_client.py b/psa_car_controller/psacc/application/psa_client.py index dbd47b1..e9a9ef2 100644 --- a/psa_car_controller/psacc/application/psa_client.py +++ b/psa_car_controller/psacc/application/psa_client.py @@ -32,7 +32,7 @@ logger = CustomLogger.getLogger(__name__) class PSAClient: def connect(self, country_code): - self.manager.init_with_user_credentials_realm(country_code, self.realm) + self.manager.init_with_user_credentials_realm(country_code) # pylint: disable=too-many-arguments def __init__(self, refresh_token, client_id, client_secret, remote_refresh_token, customer_id, realm, country_code, From 2721ac6a85f33691f3f022df8a964ec33475113e Mon Sep 17 00:00:00 2001 From: 0x3d Date: Wed, 7 Feb 2024 11:00:42 +0100 Subject: [PATCH 07/11] Use a different AUTHORIZE_SERVICE per brand/realm --- psa_car_controller/psa/connected_car_api/configuration.py | 2 +- psa_car_controller/psa/constants.py | 7 ++++++- psa_car_controller/psacc/application/psa_client.py | 2 +- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/psa_car_controller/psa/connected_car_api/configuration.py b/psa_car_controller/psa/connected_car_api/configuration.py index 8f1a4a4..4b2fe62 100644 --- a/psa_car_controller/psa/connected_car_api/configuration.py +++ b/psa_car_controller/psa/connected_car_api/configuration.py @@ -72,7 +72,7 @@ class Configuration(object): # Debug file location self.logger_file = None # Debug switch - self.debug = False + self.debug = True # SSL/TLS verification # Set this to false to skip verifying SSL certificate when calling API diff --git a/psa_car_controller/psa/constants.py b/psa_car_controller/psa/constants.py index 9c7e848..a41a858 100644 --- a/psa_car_controller/psa/constants.py +++ b/psa_car_controller/psa/constants.py @@ -28,7 +28,12 @@ DEFAULT_PRECONDITIONING_PROGRAM = { "program3": {"day": [0, 0, 0, 0, 0, 0, 0], "hour": 34, "minute": 7, "on": 0}, "program4": {"day": [0, 0, 0, 0, 0, 0, 0], "hour": 34, "minute": 7, "on": 0} } -AUTHORIZE_SERVICE = "https://idpcvs.opel.com/am/oauth2/authorize" +AUTHORIZE_SERVICE = {"clientsB2COpel": "https://idpcvs.opel.com/am/oauth2/authorize", + "clientsB2CPeugeot": "https://idpcvs.peugeot.com/am/oauth2/authorize", + "clientsB2CCitroen": "https://idpcvs.citroen.com/am/oauth2/authorize", + "clientsB2CDS": "https://idpcvs.driveds.com/am/oauth2/authorize", + "clientsB2CVauxhall": "https://idpcvs.vauxhall.co.uk/am/oauth2/authorize" + } REMOTE_URL = "https://api.groupe-psa.com/connectedcar/v4/virtualkey/remoteaccess/token?client_id=" BRAND = {"com.psa.mym.myopel": {"realm": "clientsB2COpel", "brand_code": "OP", "app_name": "MyOpel"}, "com.psa.mym.mypeugeot": {"realm": "clientsB2CPeugeot", "brand_code": "AP", "app_name": "MyPeugeot"}, diff --git a/psa_car_controller/psacc/application/psa_client.py b/psa_car_controller/psacc/application/psa_client.py index e9a9ef2..b510fec 100644 --- a/psa_car_controller/psacc/application/psa_client.py +++ b/psa_car_controller/psacc/application/psa_client.py @@ -38,7 +38,7 @@ class PSAClient: def __init__(self, refresh_token, client_id, client_secret, remote_refresh_token, customer_id, realm, country_code, proxies=None, weather_api=None, abrp=None, co2_signal_api=None): self.realm = realm - self.service_information = ServiceInformation(AUTHORIZE_SERVICE, + self.service_information = ServiceInformation(AUTHORIZE_SERVICE[self.realm], realm_info[self.realm]['oauth_url'], client_id, client_secret, From 66c188f18cee5270da90c0dfbf42bc6567128a48 Mon Sep 17 00:00:00 2001 From: 0x3d Date: Wed, 7 Feb 2024 11:05:01 +0100 Subject: [PATCH 08/11] Proper labelling --- psa_car_controller/psa/oauth.py | 2 +- psa_car_controller/psacc/application/psa_client.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/psa_car_controller/psa/oauth.py b/psa_car_controller/psa/oauth.py index 900636d..bd15f96 100644 --- a/psa_car_controller/psa/oauth.py +++ b/psa_car_controller/psa/oauth.py @@ -35,7 +35,7 @@ class OpenIdCredentialManager(CredentialManager): challenge = encoded.decode('ascii')[:-1] return verifier, challenge - def init_with_user_credentials_realm(self, country_code: str): + def init_with_country_code(self, country_code: str): redir_uri = "mymop://oauth2redirect/" + country_code.lower() code_verifier, code_challenge = self.generate_sha256_pkce(64) url = self.generate_authorize_url(redir_uri, secrets.token_urlsafe(16), diff --git a/psa_car_controller/psacc/application/psa_client.py b/psa_car_controller/psacc/application/psa_client.py index b510fec..4fefd3f 100644 --- a/psa_car_controller/psacc/application/psa_client.py +++ b/psa_car_controller/psacc/application/psa_client.py @@ -32,7 +32,7 @@ logger = CustomLogger.getLogger(__name__) class PSAClient: def connect(self, country_code): - self.manager.init_with_user_credentials_realm(country_code) + self.manager.init_with_country_code(country_code) # pylint: disable=too-many-arguments def __init__(self, refresh_token, client_id, client_secret, remote_refresh_token, customer_id, realm, country_code, From bd46b52f3b90d579cae217df3bc005a9b6c54d78 Mon Sep 17 00:00:00 2001 From: 0x3d Date: Wed, 7 Feb 2024 12:36:22 +0100 Subject: [PATCH 09/11] =?UTF-8?q?The=20"op"=20in=20"mym**op**"=20stands=20?= =?UTF-8?q?for=20Opel=20=F0=9F=98=85=20=F0=9F=A4=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- psa_car_controller/psa/oauth.py | 4 ++-- psa_car_controller/psa/setup/app_decoder.py | 4 ++-- psa_car_controller/psacc/application/psa_client.py | 7 ++++--- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/psa_car_controller/psa/oauth.py b/psa_car_controller/psa/oauth.py index bd15f96..6577f0a 100644 --- a/psa_car_controller/psa/oauth.py +++ b/psa_car_controller/psa/oauth.py @@ -35,8 +35,8 @@ class OpenIdCredentialManager(CredentialManager): challenge = encoded.decode('ascii')[:-1] return verifier, challenge - def init_with_country_code(self, country_code: str): - redir_uri = "mymop://oauth2redirect/" + country_code.lower() + def init_with_brand_country_code(self, brand: str, country_code: str): + redir_uri = "mym" + brand.lower() + "://oauth2redirect/" + country_code.lower() code_verifier, code_challenge = self.generate_sha256_pkce(64) url = self.generate_authorize_url(redir_uri, secrets.token_urlsafe(16), code_challenge=code_challenge, code_challenge_method="S256") diff --git a/psa_car_controller/psa/setup/app_decoder.py b/psa_car_controller/psa/setup/app_decoder.py index 3694fd9..cd475ec 100755 --- a/psa_car_controller/psa/setup/app_decoder.py +++ b/psa_car_controller/psa/setup/app_decoder.py @@ -91,8 +91,8 @@ def firstLaunchConfig(package_name, client_email, client_password, country_code, # Psacc psacc = PSAClient(None, apk_parser.client_id, apk_parser.client_secret, None, customer_id, BRAND[package_name]["realm"], - country_code) - psacc.connect(country_code) + country_code, BRAND[package_name]["brand_code"]) + psacc.connect() psacc.save_config(name=config_prefix + "config.json") res = psacc.get_vehicles() diff --git a/psa_car_controller/psacc/application/psa_client.py b/psa_car_controller/psacc/application/psa_client.py index 4fefd3f..67c3c62 100644 --- a/psa_car_controller/psacc/application/psa_client.py +++ b/psa_car_controller/psacc/application/psa_client.py @@ -31,12 +31,12 @@ logger = CustomLogger.getLogger(__name__) class PSAClient: - def connect(self, country_code): - self.manager.init_with_country_code(country_code) + def connect(self): + self.manager.init_with_brand_country_code(self.brand, self.country_code) # pylint: disable=too-many-arguments def __init__(self, refresh_token, client_id, client_secret, remote_refresh_token, customer_id, realm, country_code, - proxies=None, weather_api=None, abrp=None, co2_signal_api=None): + brand=None, proxies=None, weather_api=None, abrp=None, co2_signal_api=None): self.realm = realm self.service_information = ServiceInformation(AUTHORIZE_SERVICE[self.realm], realm_info[self.realm]['oauth_url'], @@ -60,6 +60,7 @@ class PSAClient: self._record_enabled = False self.weather_api = weather_api self.country_code = country_code + self.brand = brand self.info_callback = [] self.info_refresh_rate = 120 if abrp is None: From 073fb1828ed01b81c5bb6e54494471c79057cf37 Mon Sep 17 00:00:00 2001 From: 0x3d Date: Wed, 7 Feb 2024 12:46:20 +0100 Subject: [PATCH 10/11] mymop -> mymXX --- psa_car_controller/psa/oauth.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/psa_car_controller/psa/oauth.py b/psa_car_controller/psa/oauth.py index 6577f0a..607c0d2 100644 --- a/psa_car_controller/psa/oauth.py +++ b/psa_car_controller/psa/oauth.py @@ -45,7 +45,7 @@ class OpenIdCredentialManager(CredentialManager): ret = "" while len(ret) != 36: - ret = input("\nCopy+paste the resulting mymop-code (in F12 > Network, " \ + ret = input("\nCopy+paste the resulting mymXX-code (in F12 > Network, " \ "when you hit the final OK button, 36 chars, UUID format): ") self._token_request({ "grant_type": 'authorization_code', "code": ret, From 0fc116fbb524effbd954713087f1fdbb7b7d4a96 Mon Sep 17 00:00:00 2001 From: Gernot Hillier Date: Thu, 15 Feb 2024 21:48:47 +0100 Subject: [PATCH 11/11] fix: stay with paho-mqtt 1.x due to breaking change in 2.0 This fixes psacc crashing with: TypeError: Client.__init__() missing 1 required positional argument: 'callback_api_version' paho-mqtt 2.0, released on Feb, 10th, requires additional arguments to mqtt.Client(), see https://github.com/eclipse/paho.mqtt.python/blob/v2.0.0/docs/migrations.rst. So stay with 1.x for now. --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 19d4c5f..831291d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -12,7 +12,7 @@ include = [ [tool.poetry.dependencies] python = ">=3.7.2, <4.0.0" -paho-mqtt = ">=1.5.0" +paho-mqtt = ">=1.5.0, <2.0.0" dash = ">=2.9.0, <3.0.0" dash-daq = "^0.5.0" plotly = ">=5"