diff --git a/custom_components/niu/api.py b/custom_components/niu/api.py index 05d4697..7b3d660 100644 --- a/custom_components/niu/api.py +++ b/custom_components/niu/api.py @@ -1,4 +1,5 @@ from .const import * +import hashlib import requests import json from datetime import datetime, timedelta @@ -6,10 +7,9 @@ from time import gmtime, strftime class NiuApi: - def __init__(self, username, password, country, scooter_id) -> None: + def __init__(self, username, password, scooter_id) -> None: self.username = username self.password = password - self.country = country self.scooter_id = int(scooter_id) self.dataBat = None @@ -20,8 +20,8 @@ def __init__(self, username, password, country, scooter_id) -> None: def initApi(self): self.token = self.get_token() api_uri = MOTOINFO_LIST_API_URI - self.sn = self.get_vehicles_info(api_uri)["data"][self.scooter_id]["sn"] - self.sensor_prefix = self.get_vehicles_info(api_uri)["data"][self.scooter_id]["name"] + self.sn = self.get_vehicles_info(api_uri)["data"]["items"][self.scooter_id]["sn_id"] + self.sensor_prefix = self.get_vehicles_info(api_uri)["data"]["items"][self.scooter_id]["scooter_name"] self.updateBat() self.updateMoto() self.updateMotoInfo() @@ -31,17 +31,23 @@ def initApi(self): def get_token(self): username = self.username password = self.password - cc = self.country url = ACCOUNT_BASE_URL + LOGIN_URI - data = {"account": username, "countryCode": cc, "password": password} + md5 = hashlib.md5(password.encode("utf-8")).hexdigest() + data = { + "account": username, + "password": md5, + "grant_type": "password", + "scope": "base", + "app_id": "niu_ktdrr960", + } try: r = requests.post(url, data=data) except BaseException as e: print(e) return False data = json.loads(r.content.decode()) - return data["data"]["token"] + return data["data"]["token"]["access_token"] def get_vehicles_info(self, path): @@ -49,9 +55,9 @@ def get_vehicles_info(self, path): token = self.token url = API_BASE_URL + path - headers = {"token": token, "Accept-Language": "en-US"} + headers = {"token": token} try: - r = requests.post(url, headers=headers, data=[]) + r = requests.get(url, headers=headers, data=[]) except ConnectionError: return False if r.status_code != 200: @@ -66,7 +72,10 @@ def get_info(self,path, ): url = API_BASE_URL + path params = {"sn": sn} - headers = {"token": token, "Accept-Language": "en-US"} + headers = { + "token": token, + "user-agent": "manager/4.10.4 (android; IN2020 11);lang=zh-CN;clientIdentifier=Domestic;timezone=Asia/Shanghai;model=IN2020;deviceName=IN2020;ostype=android", + } try: r = requests.get(url, headers=headers, params=params) diff --git a/custom_components/niu/camera.py b/custom_components/niu/camera.py index 69c9105..592bac1 100644 --- a/custom_components/niu/camera.py +++ b/custom_components/niu/camera.py @@ -24,10 +24,9 @@ async def async_setup_entry(hass, entry, async_add_entities) -> None: username = niu_auth[CONF_USERNAME] password = niu_auth[CONF_PASSWORD] - country = niu_auth[CONF_COUNTRY] scooter_id = niu_auth[CONF_SCOOTER_ID] - api = NiuApi(username, password, country, scooter_id) + api = NiuApi(username, password, scooter_id) await hass.async_add_executor_job(api.initApi) camera_name = api.sensor_prefix + ' Last Track Camera' diff --git a/custom_components/niu/config_flow.py b/custom_components/niu/config_flow.py index d031029..4630b27 100644 --- a/custom_components/niu/config_flow.py +++ b/custom_components/niu/config_flow.py @@ -24,7 +24,6 @@ { vol.Required(CONF_USERNAME): str, vol.Required(CONF_PASSWORD): str, - vol.Required(CONF_COUNTRY, default=ITALY_COUNTRY_ID): str, vol.Required(CONF_SCOOTER_ID, default=DEFAULT_SCOOTER_ID): int, vol.Required(CONF_SENSORS, default=AVAILABLE_SENSORS): selector.SelectSelector( selector.SelectSelectorConfig(options=AVAILABLE_SENSORS, @@ -37,15 +36,14 @@ class NiuAuthenticator: - def __init__(self, username, password, country, scooter_id, sensors_selected) -> None: + def __init__(self, username, password, scooter_id, sensors_selected) -> None: self.username = username self.password = password - self.country = country self.scooter_id = scooter_id self.sensors_selected = sensors_selected async def authenticate(self, hass): - api = NiuApi(self.username, self.password, self.country, self.scooter_id) + api = NiuApi(self.username, self.password, self.scooter_id) try: token = await hass.async_add_executor_job(api.get_token) if isinstance(token, bool): @@ -71,10 +69,9 @@ async def async_step_user(self, user_input: dict[str, Any] | None = None) -> Flo if user_input != None: username = user_input[CONF_USERNAME] password = user_input[CONF_PASSWORD] - country = user_input[CONF_COUNTRY] scooter_id = user_input[CONF_SCOOTER_ID] sensors_selected = user_input[CONF_SENSORS] - niu_auth = NiuAuthenticator(username, password, country, scooter_id, sensors_selected) + niu_auth = NiuAuthenticator(username, password, scooter_id, sensors_selected) auth_result = await niu_auth.authenticate(self.hass) if auth_result: return self.async_create_entry(title=integration_title, data={CONF_AUTH:niu_auth.__dict__}) diff --git a/custom_components/niu/const.py b/custom_components/niu/const.py index e41ec5e..42b58af 100644 --- a/custom_components/niu/const.py +++ b/custom_components/niu/const.py @@ -1,9 +1,9 @@ ACCOUNT_BASE_URL = "https://account-fk.niu.com" -LOGIN_URI = "/appv2/login" +LOGIN_URI = "/v3/api/oauth2/token" API_BASE_URL = "https://app-api-fk.niu.com" MOTOR_BATTERY_API_URI = "/v3/motor_data/battery_info" -MOTOR_INDEX_API_URI = "/v3/motor_data/index_info" -MOTOINFO_LIST_API_URI = "/motoinfo/list" +MOTOR_INDEX_API_URI = "/v5/scooter/motor_data/index_info" +MOTOINFO_LIST_API_URI = "/v5/scooter/list" MOTOINFO_ALL_API_URI = "/motoinfo/overallTally" TRACK_LIST_API_URI = "/v5/track/list/v2" # FIRMWARE_BAS_URL = '/motorota/getfirmwareversion' @@ -11,13 +11,11 @@ DOMAIN = "niu" CONF_USERNAME = "username" CONF_PASSWORD = "password" -CONF_COUNTRY = "country" CONF_SCOOTER_ID = "scooter_id" CONF_AUTH = 'conf_auth' CONF_SENSORS = "sensors_selected" DEFAULT_SCOOTER_ID = 0 -ITALY_COUNTRY_ID = "39" SENSOR_TYPE_BAT = "BAT" SENSOR_TYPE_MOTO = "MOTO" @@ -67,7 +65,6 @@ { vol.Required(CONF_USERNAME): cv.string, vol.Required(CONF_PASSWORD): cv.string, - vol.Required(CONF_COUNTRY): cv.positive_int, vol.Optional(CONF_SCOOTER_ID, default=DEFAULT_SCOOTER_ID): cv.positive_int, vol.Optional(CONF_MONITORED_VARIABLES, default=["BatteryCharge"]): vol.All( cv.ensure_list, diff --git a/custom_components/niu/sensor.py b/custom_components/niu/sensor.py index 2b4544f..785fe9e 100644 --- a/custom_components/niu/sensor.py +++ b/custom_components/niu/sensor.py @@ -25,11 +25,10 @@ async def async_setup_entry(hass, entry, async_add_entities) -> None: username = niu_auth[CONF_USERNAME] password = niu_auth[CONF_PASSWORD] - country = niu_auth[CONF_COUNTRY] scooter_id = niu_auth[CONF_SCOOTER_ID] sensors_selected = niu_auth[CONF_SENSORS] - api = NiuApi(username, password, country, scooter_id) + api = NiuApi(username, password, scooter_id) await hass.async_add_executor_job(api.initApi) # add sensors diff --git a/custom_components/niu/string.json b/custom_components/niu/string.json index 70ca016..a5ccbd7 100644 --- a/custom_components/niu/string.json +++ b/custom_components/niu/string.json @@ -6,7 +6,6 @@ "data": { "CONF_USERNAME": "[%key:common::config_flow::data::conf_username%]", "CONF_PASSWORD": "[%key:common::config_flow::data::conf_password%]", - "CONF_COUNTRY": "[%key:common::config_flow::data::conf_country%]", "CONF_SCOOTER_ID": "[%key:common::config_flow::data::conf_scooter_id%]" } } diff --git a/custom_components/niu/translations/en.json b/custom_components/niu/translations/en.json index 85513f3..0044707 100644 --- a/custom_components/niu/translations/en.json +++ b/custom_components/niu/translations/en.json @@ -14,7 +14,6 @@ "data": { "username": "Username", "password": "Password", - "country": "Country id", "scooter_id": "Scooter id", "sensors_selected": "Select which sensor to integrate" }