Download firmware and font pack (experimental, unstable, dangerous), add ID and ACT columns. Fix #12

remotes/piggz/master
Kirill Snezhko 2021-02-24 02:08:48 +03:00
rodzic 750b4eea06
commit 0f9d6f6aab
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: AEC979562B0EE20B
4 zmienionych plików z 121 dodań i 23 usunięć

2
.gitignore vendored
Wyświetl plik

@ -4,3 +4,5 @@ notebooks
*.zip *.zip
__pycache__ __pycache__
*.dump *.dump
*.fw
*.bin

Wyświetl plik

@ -42,6 +42,8 @@ optional arguments:
Account Password Account Password
-b, --bt_keys Get bluetooth tokens of paired devices -b, --bt_keys Get bluetooth tokens of paired devices
-g, --gps Download A-GPS files -g, --gps Download A-GPS files
-f, --firmware Request firmware updates. Works only with -b/--bt_keys
argument. Extremely dangerous
-a, --all Do everything: get bluetooth tokens, download A-GPS -a, --all Do everything: get bluetooth tokens, download A-GPS
files files
-n, --no_logout Do not logout, keep active session and display app -n, --no_logout Do not logout, keep active session and display app
@ -60,11 +62,11 @@ Token: ['UaFHW53RJVYwqXaa7ncPQ']
Logging in... Logging in...
Logged in! User id: 1234567890 Logged in! User id: 1234567890
Getting linked wearables... Getting linked wearables...
+----------------------------------------------------------------+ +----------------------------------------------------------------------+
| ACT | MAC | auth_key | | ID | ACT | MAC | auth_key |
|-----+-------------------+--------------------------------------| |-----+-----+-------------------+--------------------------------------|
| 1 | AB:CD:EF:12:34:56 | 0xa3c10e34e5c14637eea6b9efc06106 | | 0 | 1 | AB:CD:EF:12:34:56 | 0xa3c10e34e5c14637eea6b9efc06106 |
+----------------------------------------------------------------+ +----------------------------------------------------------------------+
Logged out. Logged out.
``` ```
@ -99,12 +101,12 @@ Token: ['ALSG_CLOUDSRV_9B8D87D0EB77C71B45FF73B2266D922B']
Logging in... Logging in...
Logged in! User id: 3000654321 Logged in! User id: 3000654321
Getting linked wearables... Getting linked wearables...
+----------------------------------------------------------------+ +----------------------------------------------------------------------+
| ACT | MAC | auth_key | | ID | ACT | MAC | auth_key |
|-----+-------------------+--------------------------------------| |-----+-----+-------------------+--------------------------------------|
| 1 | 12:34:56:AB:CD:EF | 0x3c10e34e5c1463527579996fa83e6d | | 0 | 1 | 12:34:56:AB:CD:EF | 0x3c10e34e5c1463527579996fa83e6d |
| 0 | BA:DC:FE:21:43:65 | 0x00 | | 1 | 0 | BA:DC:FE:21:43:65 | 0x00 |
+----------------------------------------------------------------+ +----------------------------------------------------------------------+
Logged out. Logged out.
``` ```
@ -115,6 +117,17 @@ active or not.
In this example I have two devices: the first one is my Amazfit Bip S 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. the second one is my Xiaomi Mi Smart Scale.
## Experimental: updates download
This is extremely dangerous: flashing the wrong version can brick your device!
I am not responsible for any of problems that might arise.
Can be enabled with `-f/--firmware` argument. Will work only with `-b/--bt_keys` argument.
You should input the ID of a device, or `-1` to check for all.
Script will try to find updates for the firmware and the font pack for the device from
the table above.
## Dependencies ## Dependencies

Wyświetl plik

@ -12,6 +12,7 @@ import urllib
import argparse import argparse
import getpass import getpass
import requests import requests
import hashlib
from rich.console import Console from rich.console import Console
from rich.table import Table from rich.table import Table
@ -171,21 +172,60 @@ class HuamiAmazfit:
key_str = device_info['auth_key'] key_str = device_info['auth_key']
auth_key = '0x' + (key_str if key_str != '' else '00') auth_key = '0x' + (key_str if key_str != '' else '00')
if 'activeStatus' in _wearable:
active_status = str(_wearable['activeStatus'])
else:
active_status = '-1'
_wearables.append( _wearables.append(
{ {
'active_status': active_status, 'active_status': str(_wearable.get('activeStatus', '-1')),
'mac_address': mac_address, 'mac_address': mac_address,
'auth_key': auth_key 'auth_key': auth_key,
'device_source': str(_wearable.get('deviceSource', 0)),
'firmware_version': _wearable.get('firmwareVersion', 'v-1'),
'hardware_version': device_info.get('hardwareVersion', 'v-1'),
'production_source': device_info.get('productVersion', '0')
} }
) )
return _wearables return _wearables
def get_firmware(self, _wearable: dict) -> None:
"""Check and download updates for the furmware and fonts"""
fw_url = urls.URLS["fw_updates"]
params = urls.PAYLOADS["fw_updates"]
params['deviceSource'] = _wearable['device_source']
params['firmwareVersion'] = _wearable['firmware_version']
params['hardwareVersion'] = _wearable['hardware_version']
params['productionSource'] = _wearable['production_source']
headers = {
'appplatform': 'android_phone',
'appname': 'com.huami.midong',
'lang': 'en_US'
}
response = requests.get(fw_url, params=params, headers=headers)
response.raise_for_status()
fw_response = response.json()
msgs = []
links = []
hashes = []
if 'firmwareUrl' in fw_response:
msgs.append('firmware')
links.append(fw_response['firmwareUrl'])
hashes.append(fw_response['firmwareMd5'])
if 'fontUrl' in fw_response:
msgs.append('font')
links.append(fw_response['fontUrl'])
hashes.append(fw_response['fontMd5'])
if not links:
print("No updates found!")
else:
for msg, link, hash_sum in zip(msgs, links, hashes):
file_name = link.split('/')[-1]
print(f"Downloading {file_name}...")
with requests.get(link, stream=True) as r:
with open(file_name, 'wb') as f:
shutil.copyfileobj(r.raw, f)
def get_gps_data(self) -> None: def get_gps_data(self) -> None:
"""Download GPS packs: almanac and AGPS""" """Download GPS packs: almanac and AGPS"""
agps_packs = ["AGPS_ALM", "AGPSZIP"] agps_packs = ["AGPS_ALM", "AGPSZIP"]
@ -196,7 +236,7 @@ class HuamiAmazfit:
headers['apptoken'] = self.app_token headers['apptoken'] = self.app_token
for idx, agps_pack_name in enumerate(agps_packs): for idx, agps_pack_name in enumerate(agps_packs):
print("Downloading {}...".format(agps_pack_name)) print(f"Downloading {agps_pack_name}...")
response = requests.get(agps_link.format(pack_name=agps_pack_name), headers=headers) response = requests.get(agps_link.format(pack_name=agps_pack_name), headers=headers)
response.raise_for_status() response.raise_for_status()
agps_result = response.json()[0] agps_result = response.json()[0]
@ -252,11 +292,20 @@ if __name__ == "__main__":
required=False, required=False,
action='store_true', action='store_true',
help="Download A-GPS files") help="Download A-GPS files")
parser.add_argument("-f",
"--firmware",
required=False,
action='store_true',
help='Request firmware updates. Works only with -b/--bt_keys argument. '
'Extremely dangerous!')
parser.add_argument("-a", parser.add_argument("-a",
"--all", "--all",
required=False, required=False,
action='store_true', action='store_true',
help="Do everything: get bluetooth tokens, download A-GPS files") help="Do everything: get bluetooth tokens, download A-GPS files. But "
"do NOT download firmware updates")
parser.add_argument("-n", parser.add_argument("-n",
"--no_logout", "--no_logout",
@ -269,9 +318,13 @@ if __name__ == "__main__":
console = Console() console = Console()
table = Table(show_header=True, header_style="bold", box=box.ASCII) table = Table(show_header=True, header_style="bold", box=box.ASCII)
table.add_column("ID", width=3, justify='center')
table.add_column("ACT", width=3, justify='center') table.add_column("ACT", width=3, justify='center')
table.add_column("MAC", style="dim", width=17, justify='center') table.add_column("MAC", style="dim", width=17, justify='center')
table.add_column("auth_key", width=50, justify='center') table.add_column("auth_key", width=45, justify='center')
if args.firmware and not args.bt_keys:
parser.error("Can not use -f/--firmware without -b/--bt_keys!")
if args.password is None and args.method == "amazfit": if args.password is None and args.method == "amazfit":
args.password = getpass.getpass() args.password = getpass.getpass()
@ -282,12 +335,31 @@ if __name__ == "__main__":
device.get_access_token() device.get_access_token()
device.login() device.login()
wearables = []
if args.bt_keys or args.all: if args.bt_keys or args.all:
wearables = device.get_wearables() wearables = device.get_wearables()
for wearable in wearables: for idx, wearable in enumerate(wearables):
table.add_row(wearable['active_status'], wearable['mac_address'], wearable['auth_key']) table.add_row(str(idx), wearable['active_status'],
wearable['mac_address'], wearable['auth_key'])
console.print(table) console.print(table)
if args.firmware:
print("Downloading the firmware is untested and can brick your device. "
"I am not responsible for any problems that might arise.")
answer = input("Do you want to proceed? [yes/no] ")
if answer.lower() in ['yes', 'y', 'ye']:
wearable_id = input("ID of the device to check for updates (-1 for all of them): ")
if wearable_id == "-1":
print("Be extremely careful with downloaded files!")
for idx, wearable in enumerate(wearables):
print(f"\nChecking for device {idx}...")
device.get_firmware(wearable)
elif int(wearable_id) in range(0, len(wearables)):
device.get_firmware(wearables[wearable_id])
else:
print("Wrong input!")
if args.gps or args.all: if args.gps or args.all:
device.get_gps_data() device.get_gps_data()

11
urls.py
Wyświetl plik

@ -11,6 +11,7 @@ URLS = {
'agps': 'https://api-mifit-us2.huami.com/apps/com.huami.midong/fileTypes/{pack_name}/files', 'agps': 'https://api-mifit-us2.huami.com/apps/com.huami.midong/fileTypes/{pack_name}/files',
'data_short': 'https://api-mifit-us2.huami.com/users/{user_id}/deviceTypes/4/data', 'data_short': 'https://api-mifit-us2.huami.com/users/{user_id}/deviceTypes/4/data',
'logout': 'https://account-us2.huami.com/v1/client/logout', 'logout': 'https://account-us2.huami.com/v1/client/logout',
'fw_updates': 'https://api-mifit-us2.huami.com/devices/ALL/hasNewVersion'
} }
PAYLOADS = { PAYLOADS = {
@ -55,4 +56,14 @@ PAYLOADS = {
'logout': { 'logout': {
'login_token': None 'login_token': None
}, },
'fw_updates': {
'productionSource': None,
'deviceSource': None,
'fontVersion': '0',
'fontFlag': '0',
'appVersion': '5.9.2-play_100355',
'firmwareVersion': None,
'hardwareVersion': None,
'support8Bytes': 'true'
}
} }