pull/11/head v0.2
Kirill Snezhko 2020-05-25 14:27:57 +03:00
commit 0ee549105d
4 zmienionych plików z 327 dodań i 0 usunięć

3
.gitignore vendored 100644
Wyświetl plik

@ -0,0 +1,3 @@
notebooks
.idea
.DS_Store

21
LICENSE 100644
Wyświetl plik

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2020 Kirill Snezhko
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

97
README.md 100644
Wyświetl plik

@ -0,0 +1,97 @@
# Huami-token
Script to obtain watch or band bluetooth acess token from Huami servers
## About
To use new versions of Amazfit and Xiaomi watches and bands with Gadgetbridge you need special unique key.
Read more here: https://codeberg.org/Freeyourgadget/Gadgetbridge/wiki/Huami-Server-Pairing.
## Preparation
1. Ensure that you login in Amazfit App with Amazfit or Xiaomi account --
because only this login methods are supported. If not, create new Amazfit account
with e-mail and password.
2. Pair, sync and update your watch with Amazfit App. Your pairing key will be stored on
Huami servers.
3. Clone this repo:
```git clone https://github.com/argrento/huami-token.git```
## Logging in with Amazfit account
Run script with your cridentials: `python huami_token.py --method amazfit --email youemail@example.com --password your_password`.
Sample output:
```bash
> python huami_token.py --method amazfit --email my_email --password password
Getting access token with amazfit login method...
Token: ['UaFHW53RJVYwqXaa7ncPQ']
Logging in...
Logged in! User id: 1234567890
Getting linked wearables...
Device 1. Mac = AB:CD:EF:12:34:56, auth_key = 0xa3c10e34e5c14637eea6b9efc061069
Logged out.
```
Here the `auth_key` is the unique pairing key for your watch.
### Logging in with Xiaomi account
This is a little bit harder to use, since you need to login manually on the Xiaomi web site.
1. Run script `python huami_token.py --method xiaomi`.
2. Script will ask you to open Xiaomi login web page. https://account.xiaomi.com/oauth2/authorize?skip_confirm=false&client_id=2882303761517383915&pt=0&scope=1+6000+16001+20000&redirect_uri=https%3A%2F%2Fhm.xiaomi.com%2Fwatch.do&_locale=en_US&response_type=code
3. Login with your credentials there.
4. If your login is successful, browser will show the error that connection is not secured.
On this stage address will look like this: `https://hm.xiaomi.com/watch.do?code=ALSG_CLOUDSRV_9B8D87D0EB77C71B45FF73B2266D922B`.
5. Copy this address.
6. Return to script, paste this address and press `enter`.
Sample output:
```bash
> python huami_token.py --method xiaomi
Getting access token with xiaomi login method...
Copy this URL to web-browser
https://account.xiaomi.com/oauth2/authorize?skip_confirm=false&client_id=2882303761517383915&pt=0&scope=1+6000+16001+20000&redirect_uri=https%3A%2F%2Fhm.xiaomi.com%2Fwatch.do&_locale=en_US&response_type=code
and login to your Mi account.
Paste URL after redirection here.
https://hm.xiaomi.com/watch.do?code=ALSG_CLOUDSRV_9B8D87D0EB77C71B45FF73B2266D922B
Token: ['ALSG_CLOUDSRV_9B8D87D0EB77C71B45FF73B2266D922B']
Logging in...
Logged in! User id: 3000654321
Getting linked wearables...
Device 1. Mac = 12:34:56:AB:CD:EF, auth_key = 0x3c10e34e5c1463527579996fa83e6d
Device 2. Mac = BA:DC:FE:21:43:65, auth_key = 0x0
Logged out.
```
Here the `auth_key` is the unique pairing key for your watch.
_In this example I have two devices: the first one is my Amazfit Bip S watch,
the second one is my Xiaomi Mi Smart Scale._
## Dependencies
* Python 3.7.7
* argparse
* requests
* urllib
* random
* uuid
* json
## Versioning
We use [SemVer](http://semver.org/) for versioning. For the versions available, see the [tags on this repository](https://github.com/your/project/tags).
## License
This project is licensed under the MIT License - see the [LICENSE.md](LICENSE.md) file for details

206
huami_token.py 100644
Wyświetl plik

@ -0,0 +1,206 @@
#!/usr/bin/env python3
import argparse
import requests
import urllib
import random
import uuid
import json
class HuamiAmazfit:
def __init__(self, method="amazfit", email=None, password=None):
if method == 'amazfit' and (not email or not password):
raise ValueError("For Amazfit method E-Mail and Password can not be null.")
self.method = method
self.email = email
self.password = password
self.access_token = None
self.country_code = None
self.app_token = None
self.login_token = None
self.user_id = None
self.r = str(uuid.uuid4())
# IMEI or something unique
self.device_id = "02:00:00:%02x:%02x:%02x" % (random.randint(0, 255),
random.randint(0, 255),
random.randint(0, 255))
def get_access_token(self):
print("Getting access token with {} login method...".format(self.method))
if self.method == 'xiaomi':
login_url = "https://account.xiaomi.com/oauth2/authorize?skip_confirm=false&" \
"client_id=2882303761517383915&pt=0&scope=1+6000+16001+20000&" \
"redirect_uri=https%3A%2F%2Fhm.xiaomi.com%2Fwatch.do&_locale=en_US&response_type=code"
print("Copy this URL to web-browser \n\n{}\n\nand login to your Mi account.".format(login_url))
token_url = input("\nPaste URL after redirection here.\n")
parsed_token_url = urllib.parse.urlparse(token_url)
token_url_parameters = urllib.parse.parse_qs(parsed_token_url.query)
if 'code' not in token_url_parameters:
raise ValueError("No 'code' parameter in login url.")
self.access_token = token_url_parameters['code']
self.country_code = 'US'
elif self.method == 'amazfit':
auth_url = 'https://api-user.huami.com/registrations/{}/tokens'.format(urllib.parse.quote(self.email))
data = {
'state': 'REDIRECTION',
'client_id': 'HuaMi',
'password': self.password,
'redirect_uri': 'https://s3-us-west-2.amazonws.com/hm-registration/successsignin.html',
'region': 'us-west-2',
'token': 'access',
'country_code': 'US'
}
response = requests.post(auth_url, data=data, allow_redirects=False)
response.raise_for_status()
# 'Location' parameter contains url with login status
redirect_url = urllib.parse.urlparse(response.headers.get('Location'))
redirect_url_parameters = urllib.parse.parse_qs(redirect_url.query)
if 'error' in redirect_url_parameters:
raise ValueError("Wrong E-mail or Password. Error: {}".format(redirect_url_parameters['error']))
if 'access' not in redirect_url_parameters:
raise ValueError("No 'access' parameter in login url.")
if 'country_code' not in redirect_url_parameters:
raise ValueError("No 'country_code' parameter in login url.")
self.access_token = redirect_url_parameters['access']
self.country_code = redirect_url_parameters['country_code']
print("Token: {}".format(self.access_token))
return self.access_token
def login(self, external_token=None):
print("Logging in...")
if external_token:
self.access_token = external_token
login_url = 'https://account.huami.com/v2/client/login'
data = {
'dn': 'account.huami.com,api-user.huami.com,app-analytics.huami.com,api-watch.huami.com,'
'api-analytics.huami.com,api-mifit.huami.com',
'app_version': '4.3.0-play',
'source': 'com.huami.watch.hmwatchmanager:4.3.0-play:100152',
'country_code': self.country_code,
'device_id': self.device_id,
'third_name': 'huami' if self.method == 'amazfit' else 'mi-watch',
'lang': 'en',
'device_model': 'android_phone',
'allow_registration': 'false',
'app_name': 'com.huami.midong',
'code': self.access_token,
'grant_type': 'access_token' if self.method == 'amazfit' else 'request_token'
}
response = requests.post(login_url, data=data, allow_redirects=False)
response.raise_for_status()
login_result = response.json()
if 'error_code' in login_result:
raise ValueError("Login error. Error: {}".format(login_result['error_code']))
if 'token_info' not in login_result:
raise ValueError("No 'token_info' parameter in login data.")
else:
token_info = login_result['token_info']
if 'app_token' not in token_info:
raise ValueError("No 'app_token' parameter in login data.")
self.app_token = token_info['app_token']
if 'login_token' not in token_info:
raise ValueError("No 'login_token' parameter in login data.")
self.login_token = token_info['login_token']
if 'user_id' not in token_info:
raise ValueError("No 'user_id' parameter in login data.")
self.user_id = token_info['user_id']
print("Logged in! User id: {}".format(self.user_id))
def get_wearable_auth_keys(self):
print("Getting linked wearables...\n")
devices_url = "https://api-mifit-us2.huami.com/users/{}/devices".format(urllib.parse.quote(self.user_id))
headers = {
'apptoken': self.app_token
}
response = requests.get(devices_url, headers=headers)
response.raise_for_status()
device_request = response.json()
if 'items' not in device_request:
raise ValueError("No 'items' parameter in devices data.")
devices = device_request['items']
for idx, wearable in enumerate(devices):
if 'macAddress' not in wearable:
raise ValueError("No 'macAddress' parameter in device data.")
mac_address = wearable['macAddress']
if 'additionalInfo' not in wearable:
raise ValueError("No 'additionalInfo' parameter in device data.")
device_info = json.loads(wearable['additionalInfo'])
if 'auth_key' not in device_info:
raise ValueError("No 'auth_key' parameter in device data.")
key_str = device_info['auth_key']
auth_key = '0x' + (key_str if key_str != '' else '0')
print("Device {}. Mac = {}, auth_key = {}".format(
idx+1,
mac_address,
auth_key))
def logout(self):
logout_url = "https://account-us2.huami.com/v1/client/logout"
data = {
'login_token': self.login_token
}
response = requests.post(logout_url, data=data)
logout_result = response.json()
if logout_result['result'] == 'ok':
print("\nLogged out.")
else:
print("\nError logging out.")
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Obtain Bluetooth Auth key from Amazfit servers")
parser.add_argument("-m",
"--method",
choices=["amazfit", "xiaomi"],
default="amazfit",
required=True,
help="Login method ")
parser.add_argument("-e",
"--email",
required=False,
help="Account e-mail address")
parser.add_argument("-p",
"--password",
required=False,
help="Account Password")
args = parser.parse_args()
device = HuamiAmazfit(method=args.method,
email=args.email,
password=args.password)
device.get_access_token()
device.login()
device.get_wearable_auth_keys()
device.logout()