mirror of
https://codeberg.org/vanous/huafetcher.git
synced 2025-01-10 07:02:03 +01:00
initial commit
This commit is contained in:
parent
fb57ce94fe
commit
7b449719f4
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,3 +1,4 @@
|
|||||||
|
.buildozer
|
||||||
# ---> Python
|
# ---> Python
|
||||||
# Byte-compiled / optimized / DLL files
|
# Byte-compiled / optimized / DLL files
|
||||||
__pycache__/
|
__pycache__/
|
||||||
|
23
README.md
23
README.md
@ -1,2 +1,25 @@
|
|||||||
# huafetcher
|
# huafetcher
|
||||||
|
|
||||||
|
Kivy GUI for huami-token. Works on desktop and as Android apk. Downloads key and aGPS data, unzips it into `/storage/emulated/0`
|
||||||
|
|
||||||
|
[huami-token](https://github.com/argrento/huami-token): all credits to the original author
|
||||||
|
|
||||||
|
## Install
|
||||||
|
|
||||||
|
Install [Buildozer](https://github.com/kivy/buildozer/) and [Kivy](https://github.com/kivy/kivy)
|
||||||
|
|
||||||
|
pip install buildozer
|
||||||
|
pip install kivy
|
||||||
|
|
||||||
|
or
|
||||||
|
|
||||||
|
pip install -r requirements.txt
|
||||||
|
|
||||||
|
## Run
|
||||||
|
|
||||||
|
python main.py
|
||||||
|
|
||||||
|
## make Android apk
|
||||||
|
|
||||||
|
buildozer -v android debug deploy run
|
||||||
|
|
||||||
|
BIN
data/icon.png
Normal file
BIN
data/icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 28 KiB |
80
data/icon.svg
Normal file
80
data/icon.svg
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
fill="white"
|
||||||
|
width="18px"
|
||||||
|
height="18px"
|
||||||
|
version="1.1"
|
||||||
|
id="svg6"
|
||||||
|
sodipodi:docname="icon.svg"
|
||||||
|
inkscape:export-filename="/tmp/icon.png"
|
||||||
|
inkscape:export-xdpi="2730.6699"
|
||||||
|
inkscape:export-ydpi="2730.6699"
|
||||||
|
inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)">
|
||||||
|
<metadata
|
||||||
|
id="metadata12">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title></dc:title>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<defs
|
||||||
|
id="defs10" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1"
|
||||||
|
objecttolerance="10"
|
||||||
|
gridtolerance="10"
|
||||||
|
guidetolerance="10"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:window-width="1920"
|
||||||
|
inkscape:window-height="1042"
|
||||||
|
id="namedview8"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:zoom="40.833333"
|
||||||
|
inkscape:cx="9"
|
||||||
|
inkscape:cy="9"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="38"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:current-layer="svg6" />
|
||||||
|
<path
|
||||||
|
d="M0 0h24v24H0V0z"
|
||||||
|
fill="none"
|
||||||
|
id="path2"
|
||||||
|
inkscape:export-filename="/tmp/icon.png"
|
||||||
|
inkscape:export-xdpi="2730.6699"
|
||||||
|
inkscape:export-ydpi="2730.6699" />
|
||||||
|
<path
|
||||||
|
d="M14.31 2l.41 2.48C13.87 4.17 12.96 4 12 4c-.95 0-1.87.17-2.71.47L9.7 2h4.61m.41 17.52L14.31 22H9.7l-.41-2.47c.84.3 1.76.47 2.71.47.96 0 1.87-.17 2.72-.48M16 0H8l-.95 5.73C5.19 7.19 4 9.45 4 12s1.19 4.81 3.05 6.27L8 24h8l.96-5.73C18.81 16.81 20 14.54 20 12s-1.19-4.81-3.04-6.27L16 0zm-4 18c-3.31 0-6-2.69-6-6s2.69-6 6-6 6 2.69 6 6-2.69 6-6 6z"
|
||||||
|
id="path4"
|
||||||
|
inkscape:export-filename="/tmp/icon.png"
|
||||||
|
inkscape:export-xdpi="2730.6699"
|
||||||
|
inkscape:export-ydpi="2730.6699"
|
||||||
|
style="stroke:#000000;stroke-opacity:1;stroke-width:0.2;stroke-miterlimit:4;stroke-dasharray:none" />
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8.88889px;line-height:124%;font-family:Sans;-inkscape-font-specification:Sans;letter-spacing:0px;word-spacing:0px;fill:#fffffc;fill-opacity:1;stroke:#000000;stroke-width:0.26666667;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
|
||||||
|
x="7.1302075"
|
||||||
|
y="15.376737"
|
||||||
|
id="text839"><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan837"
|
||||||
|
x="7.1302075"
|
||||||
|
y="15.376737"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8.88889px;font-family:Sans;-inkscape-font-specification:Sans;fill:#fffffc;fill-opacity:1;stroke-width:0.26666667;stroke:#000000;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none">hf</tspan></text>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 3.2 KiB |
193
huami_token.py
Normal file
193
huami_token.py
Normal file
@ -0,0 +1,193 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import json
|
||||||
|
import uuid
|
||||||
|
import random
|
||||||
|
import shutil
|
||||||
|
import urllib
|
||||||
|
import requests
|
||||||
|
|
||||||
|
import urls
|
||||||
|
|
||||||
|
|
||||||
|
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.result = 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 __str__(self):
|
||||||
|
return f"{self.email} {self.password} {self.method} {self.access_token}"
|
||||||
|
|
||||||
|
def parse_token(self, token_url):
|
||||||
|
|
||||||
|
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:
|
||||||
|
return
|
||||||
|
|
||||||
|
self.access_token = token_url_parameters['code']
|
||||||
|
self.country_code = 'US'
|
||||||
|
|
||||||
|
def get_access_token(self):
|
||||||
|
print(f"Getting access token with {self.method} login method...")
|
||||||
|
|
||||||
|
if self.method == 'xiaomi':
|
||||||
|
login_url = urls.URLS["login_xiaomi"]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
elif self.method == 'amazfit':
|
||||||
|
|
||||||
|
auth_url = urls.URLS['tokens_amazfit'].format(user_email=urllib.parse.quote(self.email))
|
||||||
|
|
||||||
|
data = urls.PAYLOADS['tokens_amazfit']
|
||||||
|
data['password'] = self.password
|
||||||
|
|
||||||
|
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(f"Wrong E-mail or Password. Error: {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']
|
||||||
|
|
||||||
|
|
||||||
|
def login(self, external_token=None):
|
||||||
|
print("Logging in...")
|
||||||
|
if external_token:
|
||||||
|
self.access_token = external_token
|
||||||
|
|
||||||
|
login_url = urls.URLS['login_amazfit']
|
||||||
|
|
||||||
|
data = urls.PAYLOADS['login_amazfit']
|
||||||
|
data['country_code'] = self.country_code
|
||||||
|
data['device_id'] = self.device_id
|
||||||
|
data['third_name'] = 'huami' if self.method == 'amazfit' else 'mi-watch'
|
||||||
|
data['code'] = self.access_token
|
||||||
|
data['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(f"Login error. Error: {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))
|
||||||
|
return True
|
||||||
|
|
||||||
|
def get_wearable_auth_keys(self):
|
||||||
|
print("Getting linked wearables...")
|
||||||
|
print(self.user_id)
|
||||||
|
|
||||||
|
devices_url = urls.URLS['devices'].format(user_id=urllib.parse.quote(self.user_id))
|
||||||
|
|
||||||
|
headers = urls.PAYLOADS['devices']
|
||||||
|
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']
|
||||||
|
|
||||||
|
devices_dict = {}
|
||||||
|
|
||||||
|
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 '00')
|
||||||
|
|
||||||
|
devices_dict[f'{mac_address}'] = auth_key
|
||||||
|
|
||||||
|
return devices_dict
|
||||||
|
|
||||||
|
def get_gps_data(self):
|
||||||
|
agps_packs = ["AGPS_ALM", "AGPSZIP"]
|
||||||
|
agps_file_names = ["cep_alm_pak.zip", "cep_7days.zip"]
|
||||||
|
agps_link = urls.URLS['agps']
|
||||||
|
|
||||||
|
headers = urls.PAYLOADS['agps']
|
||||||
|
headers['apptoken'] = self.app_token
|
||||||
|
|
||||||
|
for idx, agps_pack_name in enumerate(agps_packs):
|
||||||
|
print("Downloading {}...".format(agps_pack_name))
|
||||||
|
response = requests.get(agps_link.format(pack_name=agps_pack_name), headers=headers)
|
||||||
|
response.raise_for_status()
|
||||||
|
agps_result = response.json()[0]
|
||||||
|
if 'fileUrl' not in agps_result:
|
||||||
|
raise ValueError("No 'fileUrl' parameter in files request.")
|
||||||
|
with requests.get(agps_result['fileUrl'], stream=True) as r:
|
||||||
|
with open(agps_file_names[idx], 'wb') as f:
|
||||||
|
shutil.copyfileobj(r.raw, f)
|
||||||
|
|
||||||
|
def logout(self):
|
||||||
|
logout_url = urls.URLS['logout']
|
||||||
|
|
||||||
|
data = urls.PAYLOADS['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.")
|
||||||
|
|
||||||
|
|
394
main.py
Normal file
394
main.py
Normal file
@ -0,0 +1,394 @@
|
|||||||
|
from kivy.app import App
|
||||||
|
from kivy.uix.button import Button
|
||||||
|
from kivy.uix.label import Label
|
||||||
|
from kivy.lang import Builder
|
||||||
|
from kivy.utils import platform
|
||||||
|
from kivy.uix.textinput import TextInput
|
||||||
|
from kivy.uix.boxlayout import BoxLayout
|
||||||
|
from functools import partial
|
||||||
|
from kivy.clock import Clock
|
||||||
|
from kivy.logger import Logger
|
||||||
|
from kivy.uix.dropdown import DropDown
|
||||||
|
from huami_token import HuamiAmazfit
|
||||||
|
import urls as urls
|
||||||
|
from kivy.core.clipboard import Clipboard
|
||||||
|
from kivy.storage.jsonstore import JsonStore
|
||||||
|
|
||||||
|
DEBUG=False
|
||||||
|
DEBUG=True
|
||||||
|
|
||||||
|
def debug_print(*xargs):
|
||||||
|
if DEBUG:
|
||||||
|
print(*xargs)
|
||||||
|
|
||||||
|
SPACING=2
|
||||||
|
Builder.load_string('''
|
||||||
|
<MyInputy>:
|
||||||
|
font_size: 30
|
||||||
|
halign: 'left'
|
||||||
|
color: 1,1,1,1
|
||||||
|
bcolor: .1, 0, .6, 0
|
||||||
|
canvas.before:
|
||||||
|
Color:
|
||||||
|
rgba: root.bcolor
|
||||||
|
Rectangle:
|
||||||
|
size: (self.width -2, self.height -2)
|
||||||
|
pos: (self.x+1,self.y +1)
|
||||||
|
|
||||||
|
|
||||||
|
<MyLabel>:
|
||||||
|
font_size: 30
|
||||||
|
halign: 'center'
|
||||||
|
bcolor: .7, .7, .7, 1
|
||||||
|
canvas.before:
|
||||||
|
Color:
|
||||||
|
rgba: root.bcolor
|
||||||
|
Rectangle:
|
||||||
|
size: self.size
|
||||||
|
pos: self.pos
|
||||||
|
|
||||||
|
<MyLeftLabel>:
|
||||||
|
font_size: 30
|
||||||
|
halign: 'left'
|
||||||
|
bcolor: .7, .7, .7, 1
|
||||||
|
canvas.before:
|
||||||
|
Color:
|
||||||
|
rgba: root.bcolor
|
||||||
|
Rectangle:
|
||||||
|
size: self.size
|
||||||
|
pos: self.pos
|
||||||
|
<MyButton>:
|
||||||
|
font_size: 30
|
||||||
|
bcolor: .7, .7, .7, 1
|
||||||
|
background_color: .1, 0, .5, 0
|
||||||
|
canvas.before:
|
||||||
|
Color:
|
||||||
|
rgba: root.bcolor
|
||||||
|
Rectangle:
|
||||||
|
size: self.size
|
||||||
|
pos: self.pos
|
||||||
|
|
||||||
|
''')
|
||||||
|
class MyLabel(Label):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class MyLeftLabel(Label):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class MyButton(Button):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class MyInput(TextInput):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class Main(App):
|
||||||
|
def build(self):
|
||||||
|
self.huamidevice=HuamiAmazfit()
|
||||||
|
self.store = JsonStore('credentials.json')
|
||||||
|
|
||||||
|
screen_layout = BoxLayout(orientation="vertical", spacing=SPACING)
|
||||||
|
buttons_layout = BoxLayout(orientation="horizontal", spacing=SPACING)
|
||||||
|
rows_layout = BoxLayout(orientation="vertical", spacing=SPACING)
|
||||||
|
|
||||||
|
self.instructions_label=MyLeftLabel(text='Huafetcher')
|
||||||
|
rows_layout.add_widget(self.instructions_label)
|
||||||
|
|
||||||
|
dropdown = DropDown()
|
||||||
|
|
||||||
|
xiaomi_button = MyButton(text='Xiaomi', size_hint_y=None, height=150)
|
||||||
|
xiaomi_button.bind(on_press=lambda a:self.set_login_method('xiaomi'))
|
||||||
|
xiaomi_button.bind(on_release=lambda btn: dropdown.select(btn.text))
|
||||||
|
amazfit_button = MyButton(text='Amazfit', size_hint_y=None, height=150)
|
||||||
|
amazfit_button.bind(on_press=lambda a:self.set_login_method('amazfit'))
|
||||||
|
amazfit_button.bind(on_release=lambda btn: dropdown.select(btn.text))
|
||||||
|
|
||||||
|
dropdown.add_widget(xiaomi_button)
|
||||||
|
dropdown.add_widget(amazfit_button)
|
||||||
|
|
||||||
|
dropdown_button = MyButton(text='Login method')
|
||||||
|
dropdown_button.bind(on_release=dropdown.open)
|
||||||
|
#dropdown_button.bind(on_press=lambda x: setattr(dropdown_button,'text','Select'))
|
||||||
|
dropdown.bind(on_select=lambda instance, x: setattr(dropdown_button, 'text', x))
|
||||||
|
|
||||||
|
get_token_button = MyButton(text='Get token')
|
||||||
|
get_token_button.bind(on_press=self.on_press_button_gettoken)
|
||||||
|
|
||||||
|
fetch_key_button = MyButton(text='Fetch key')
|
||||||
|
fetch_key_button.bind(on_press=self.on_press_button_fetch_key)
|
||||||
|
|
||||||
|
fetch_agps_button = MyButton(text='Fetch aGPS')
|
||||||
|
fetch_agps_button.bind(on_press=self.on_press_button_agps)
|
||||||
|
|
||||||
|
share_agps_button = MyButton(text='Share aGPS')
|
||||||
|
share_agps_button.bind(on_press=self.on_press_button_share_agps)
|
||||||
|
|
||||||
|
buttons_layout.add_widget(get_token_button)
|
||||||
|
#buttons_layout.add_widget(login_button)
|
||||||
|
buttons_layout.add_widget(fetch_key_button)
|
||||||
|
buttons_layout.add_widget(fetch_agps_button)
|
||||||
|
#sharing doesn't work
|
||||||
|
#buttons_layout.add_widget(share_agps_button)
|
||||||
|
|
||||||
|
paste_token_input_layout = BoxLayout(orientation="horizontal", spacing=SPACING)
|
||||||
|
paste_token_input_label=MyLabel(text='URL result')
|
||||||
|
|
||||||
|
self.paste_token_input = MyInput(text='',
|
||||||
|
multiline=False,
|
||||||
|
)
|
||||||
|
self.paste_token_input.bind(text=self.set_token)
|
||||||
|
|
||||||
|
|
||||||
|
paste_button1=MyButton(text='Paste', size_hint=(.3, 1))
|
||||||
|
paste_button1.bind(on_press=lambda instance: self.on_press_paste(self.paste_token_input) )
|
||||||
|
|
||||||
|
paste_token_input_layout.add_widget(paste_token_input_label)
|
||||||
|
paste_token_input_layout.add_widget(paste_button1)
|
||||||
|
paste_token_input_layout.add_widget(self.paste_token_input)
|
||||||
|
credentials_email_label=MyButton(text='Email' , size_hint=(.7, 1))
|
||||||
|
|
||||||
|
self.credentials_email_input = MyInput(text='',
|
||||||
|
multiline=False,
|
||||||
|
)
|
||||||
|
self.credentials_email_input.bind(text=lambda instance,x: setattr(self.huamidevice,'email',x))
|
||||||
|
credentials_email_label.bind(on_press=self.on_press_paste_email)
|
||||||
|
|
||||||
|
paste_button2=MyButton(text='Paste', size_hint=(.3, 1))
|
||||||
|
paste_button2.bind(on_press=lambda instance: self.on_press_paste(self.credentials_email_input) )
|
||||||
|
|
||||||
|
save_button1=MyButton(text='Save', size_hint=(.3, 1))
|
||||||
|
#load_button1.bind(on_press=lambda instance: )
|
||||||
|
save_button1.bind(on_press=lambda instance: self.on_press_save(self.credentials_email_input, 'email') )
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
self.credentials_email_layout = BoxLayout(orientation="horizontal", spacing=SPACING)
|
||||||
|
self.credentials_email_layout.add_widget(credentials_email_label)
|
||||||
|
#credentials_email_layout.add_widget(load_button1)
|
||||||
|
self.credentials_email_layout.add_widget(save_button1)
|
||||||
|
self.credentials_email_layout.add_widget(paste_button2)
|
||||||
|
self.credentials_email_layout.add_widget(self.credentials_email_input)
|
||||||
|
|
||||||
|
|
||||||
|
credentials_password_label=MyLabel(text='Password', size_hint=(.7, 1))
|
||||||
|
|
||||||
|
self.credentials_password_input = MyInput(text='',
|
||||||
|
multiline=False,
|
||||||
|
)
|
||||||
|
self.credentials_password_input.bind(text=lambda instance,x: setattr(self.huamidevice,'password',x))
|
||||||
|
credentials_password_label.bind(on_press=self.on_press_paste_password)
|
||||||
|
|
||||||
|
paste_button3=MyButton(text='Paste', size_hint=(.3, 1))
|
||||||
|
paste_button3.bind(on_press=lambda instance: self.on_press_paste(self.credentials_password_input) )
|
||||||
|
|
||||||
|
save_button2=MyButton(text='Save', size_hint=(.3, 1))
|
||||||
|
save_button2.bind(on_press=lambda instance: self.on_press_save(self.credentials_password_input, 'password') )
|
||||||
|
|
||||||
|
self.credentials_password_layout = BoxLayout(orientation="horizontal", spacing=SPACING)
|
||||||
|
self.credentials_password_layout.add_widget(credentials_password_label)
|
||||||
|
self.credentials_password_layout.add_widget(save_button2)
|
||||||
|
self.credentials_password_layout.add_widget(paste_button3)
|
||||||
|
self.credentials_password_layout.add_widget(self.credentials_password_input)
|
||||||
|
|
||||||
|
rows_layout.add_widget(dropdown_button)
|
||||||
|
rows_layout.add_widget(self.credentials_email_layout)
|
||||||
|
rows_layout.add_widget(self.credentials_password_layout)
|
||||||
|
rows_layout.add_widget(paste_token_input_layout)
|
||||||
|
|
||||||
|
result_value_label=MyButton(text='Found key')
|
||||||
|
self.result_value_value=TextInput()
|
||||||
|
|
||||||
|
|
||||||
|
copy_button4=MyButton(text='Copy', size_hint=(.3, 1))
|
||||||
|
copy_button4.bind(on_press=lambda instance: self.on_press_copy(self.result_value_value) )
|
||||||
|
|
||||||
|
|
||||||
|
result_value_layout = BoxLayout(orientation="horizontal", spacing=SPACING)
|
||||||
|
result_value_layout.add_widget(result_value_label)
|
||||||
|
result_value_layout.add_widget(copy_button4)
|
||||||
|
result_value_layout.add_widget(self.result_value_value)
|
||||||
|
result_value_label.bind(on_press=self.on_press_copy_result)
|
||||||
|
|
||||||
|
|
||||||
|
rows_layout.add_widget(result_value_layout)
|
||||||
|
|
||||||
|
|
||||||
|
rows_layout.add_widget(buttons_layout)
|
||||||
|
|
||||||
|
|
||||||
|
screen_layout.add_widget(rows_layout)
|
||||||
|
|
||||||
|
self.on_press_load(self.credentials_email_input, 'email')
|
||||||
|
self.on_press_load(self.credentials_password_input, 'password')
|
||||||
|
self.set_login_method('xiaomi')
|
||||||
|
dropdown_button.text='Xiaomi'
|
||||||
|
|
||||||
|
return screen_layout
|
||||||
|
|
||||||
|
def hide_widget(self, wid, dohide=True):
|
||||||
|
debug_print(dohide)
|
||||||
|
if hasattr(wid, 'saved_attrs'):
|
||||||
|
debug_print(wid.saved_attrs)
|
||||||
|
if not dohide:
|
||||||
|
wid.height, wid.size_hint_y, wid.opacity, wid.disabled = wid.saved_attrs
|
||||||
|
del wid.saved_attrs
|
||||||
|
elif dohide:
|
||||||
|
wid.saved_attrs = wid.height, wid.size_hint_y, wid.opacity, wid.disabled
|
||||||
|
wid.height, wid.size_hint_y, wid.opacity, wid.disabled = 0, None, 0, True
|
||||||
|
|
||||||
|
|
||||||
|
def set_login_method(self,method):
|
||||||
|
debug_print(method)
|
||||||
|
self.huamidevice.method=method
|
||||||
|
if method == 'xiaomi':
|
||||||
|
self.hide_widget(self.credentials_email_layout, dohide=True)
|
||||||
|
self.hide_widget(self.credentials_password_layout, dohide=True)
|
||||||
|
else:
|
||||||
|
self.hide_widget(self.credentials_email_layout, dohide=False)
|
||||||
|
self.hide_widget(self.credentials_password_layout, dohide=False)
|
||||||
|
|
||||||
|
def set_token(self, instance, text):
|
||||||
|
debug_print("got", text)
|
||||||
|
debug_print(self.huamidevice)
|
||||||
|
self.huamidevice.parse_token(text)
|
||||||
|
debug_print(self.huamidevice)
|
||||||
|
|
||||||
|
def on_press_button_gettoken(self, instance):
|
||||||
|
debug_print('You pressed the button login!')
|
||||||
|
debug_print(self.huamidevice)
|
||||||
|
self.instructions_label.text="log in and paste url here"
|
||||||
|
if self.huamidevice.method == 'xiaomi':
|
||||||
|
login_url = urls.URLS["login_xiaomi"]
|
||||||
|
if ( platform != 'android' ):
|
||||||
|
import webbrowser
|
||||||
|
webbrowser.open(login_url, new = 2)
|
||||||
|
else:
|
||||||
|
from jnius import autoclass
|
||||||
|
from jnius import cast
|
||||||
|
|
||||||
|
PythonActivity = autoclass('org.kivy.android.PythonActivity')
|
||||||
|
Intent = autoclass('android.content.Intent')
|
||||||
|
Uri = autoclass('android.net.Uri')
|
||||||
|
intent = Intent()
|
||||||
|
intent.setAction(Intent.ACTION_VIEW)
|
||||||
|
intent.setData(Uri.parse(login_url))
|
||||||
|
currentActivity = cast('android.app.Activity', PythonActivity.mActivity)
|
||||||
|
currentActivity.startActivity(intent)
|
||||||
|
|
||||||
|
self.huamidevice.get_access_token()
|
||||||
|
|
||||||
|
|
||||||
|
def on_press_button_fetch_key(self, instance):
|
||||||
|
debug_print('You pressed the button fetch!')
|
||||||
|
debug_print(self.huamidevice)
|
||||||
|
self.instructions_label.text="signing in"
|
||||||
|
if (self.huamidevice.login()):
|
||||||
|
self.instructions_label.text="Signed in as: {}, getting data".format(self.huamidevice.user_id)
|
||||||
|
|
||||||
|
|
||||||
|
device_keys = self.huamidevice.get_wearable_auth_keys()
|
||||||
|
self.instructions_label.text="Done"
|
||||||
|
self.result_value_value.text=""
|
||||||
|
for device_key in device_keys:
|
||||||
|
debug_print(f"{device_key} {device_keys[device_key]}")
|
||||||
|
|
||||||
|
self.result_value_value.text=f"{device_keys[device_key]}"
|
||||||
|
|
||||||
|
#Clock.schedule_once(partial(self.doit), 1)
|
||||||
|
|
||||||
|
def on_press_paste_token(self, instance):
|
||||||
|
self.paste_token_input.text=Clipboard.paste()
|
||||||
|
|
||||||
|
def on_press_paste_email(self, instance):
|
||||||
|
self.credentials_email_input.text=Clipboard.paste()
|
||||||
|
|
||||||
|
def on_press_paste_password(self, instance):
|
||||||
|
self.credentials_password_input.text=Clipboard.paste()
|
||||||
|
|
||||||
|
def on_press_copy_result(self, instance):
|
||||||
|
Clipboard.copy(self.result_value_value.text)
|
||||||
|
|
||||||
|
def on_press_paste(self, instance):
|
||||||
|
instance.text=Clipboard.paste()
|
||||||
|
|
||||||
|
def on_press_copy(self, instance):
|
||||||
|
Clipboard.copy(instance.text)
|
||||||
|
|
||||||
|
def on_press_load(self, instance, key):
|
||||||
|
if self.store.exists(key):
|
||||||
|
instance.text=self.store.get(key)["value"]
|
||||||
|
|
||||||
|
def on_press_save(self, instance, key):
|
||||||
|
self.store.put(key, value=instance.text)
|
||||||
|
|
||||||
|
def on_press_button_agps(self, instance):
|
||||||
|
import zipfile
|
||||||
|
debug_print('You pressed the button agps!')
|
||||||
|
debug_print(self.huamidevice)
|
||||||
|
self.instructions_label.text="signing in"
|
||||||
|
if (self.huamidevice.login()):
|
||||||
|
self.instructions_label.text="Signed in as: {}, getting data".format(self.huamidevice.user_id)
|
||||||
|
|
||||||
|
self.huamidevice.get_gps_data()
|
||||||
|
agps_file_names = ["cep_alm_pak.zip"]
|
||||||
|
if ( platform == 'android' ):
|
||||||
|
import shutil
|
||||||
|
import os
|
||||||
|
from jnius import autoclass
|
||||||
|
from jnius import cast
|
||||||
|
Environment = autoclass('android.os.Environment')
|
||||||
|
File = autoclass('java.io.File')
|
||||||
|
data_dir = Environment.getExternalStorageDirectory().getPath()
|
||||||
|
debug_print(data_dir)
|
||||||
|
for filename in agps_file_names:
|
||||||
|
sdpathfile = os.path.join(data_dir, filename)
|
||||||
|
shutil.copyfile(filename, sdpathfile)
|
||||||
|
with zipfile.ZipFile(filename, "r") as zip_f:
|
||||||
|
#zip_f.extractall()
|
||||||
|
zip_f.extractall(data_dir)
|
||||||
|
|
||||||
|
self.instructions_label.text="Done"
|
||||||
|
#Clock.schedule_once(partial(self.doit), 1)
|
||||||
|
|
||||||
|
def on_press_button_share_agps(self, instance):
|
||||||
|
#not working because android broke it
|
||||||
|
if ( platform == 'android' ):
|
||||||
|
import os
|
||||||
|
from jnius import autoclass
|
||||||
|
from jnius import cast
|
||||||
|
Environment = autoclass('android.os.Environment')
|
||||||
|
File = autoclass('java.io.File')
|
||||||
|
data_dir = Environment.getExternalStorageDirectory().getPath()
|
||||||
|
|
||||||
|
PythonActivity = autoclass('org.kivy.android.PythonActivity')
|
||||||
|
Intent = autoclass('android.content.Intent')
|
||||||
|
Uri = autoclass('android.net.Uri')
|
||||||
|
intent = Intent()
|
||||||
|
intent.setAction(Intent.ACTION_VIEW)
|
||||||
|
data_dir = getattr(self, 'user_data_dir')
|
||||||
|
file_target=File(os.path.join(data_dir, "cep_pak.bin"))
|
||||||
|
#target=Uri.parse(os.path.join("file:///", data_dir, "cep_pak.bin"))
|
||||||
|
target=Uri.fromFile(file_target)
|
||||||
|
#intent.setData(Uri.parse(os.path.join("file:///", data_dir, "cep_pak.bin")))
|
||||||
|
#intent.setType("application/octet-stream")
|
||||||
|
intent.setDataAndType(target, "application/octet-stream")
|
||||||
|
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||||
|
currentActivity = cast('android.app.Activity', PythonActivity.mActivity)
|
||||||
|
currentActivity.startActivity(intent)
|
||||||
|
|
||||||
|
#intent = Intent()
|
||||||
|
#intent.setAction(Intent.ACTION_VIEW)
|
||||||
|
#intent.setData(Uri.parse("gps_alm.bin"))
|
||||||
|
#currentActivity = cast('android.app.Activity', PythonActivity.mActivity)
|
||||||
|
#currentActivity.startActivity(intent)
|
||||||
|
|
||||||
|
|
||||||
|
#def doit(self, *kargs):
|
||||||
|
|
||||||
|
def openweb(url):
|
||||||
|
debug_print("open ", url)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
app = Main()
|
||||||
|
app.run()
|
||||||
|
|
221
requirements.txt
Normal file
221
requirements.txt
Normal file
@ -0,0 +1,221 @@
|
|||||||
|
aiofile==1.4.3
|
||||||
|
aiofiles==0.4.0
|
||||||
|
aiohttp==3.5.4
|
||||||
|
aiohttp-cors==0.7.0
|
||||||
|
aiosqlite==0.8.0
|
||||||
|
altgraph==0.16.1
|
||||||
|
appdirs==1.4.4
|
||||||
|
argon2-cffi==20.1.0
|
||||||
|
arrow==0.17.0
|
||||||
|
asciimatics==1.11.0
|
||||||
|
asn1crypto==0.24.0
|
||||||
|
astral==1.9.2
|
||||||
|
async-timeout==3.0.1
|
||||||
|
atomicwrites==1.3.0
|
||||||
|
attrs==18.2.0
|
||||||
|
backcall==0.2.0
|
||||||
|
bcrypt==3.1.5
|
||||||
|
beautifulsoup4==4.6.3
|
||||||
|
binaryornot==0.4.4
|
||||||
|
bleach==3.1.5
|
||||||
|
boltons==18.0.1
|
||||||
|
boto3==1.9.106
|
||||||
|
botocore==1.12.106
|
||||||
|
briefcase==0.3.3
|
||||||
|
brython==3.6.2
|
||||||
|
bs4==0.0.1
|
||||||
|
buildozer==1.2.0
|
||||||
|
cachetools==4.1.0
|
||||||
|
certifi==2018.11.29
|
||||||
|
cffi==1.12.2
|
||||||
|
chardet==3.0.4
|
||||||
|
cli-helpers==2.1.0
|
||||||
|
click==7.1.2
|
||||||
|
colorama==0.4.3
|
||||||
|
colosseum==0.2.0
|
||||||
|
commonmark==0.9.1
|
||||||
|
configobj==5.0.6
|
||||||
|
cookiecutter==1.7.2
|
||||||
|
cryptography==2.9
|
||||||
|
cycler==0.10.0
|
||||||
|
Cython==0.29.21
|
||||||
|
dateparser==0.7.0
|
||||||
|
decorator==4.4.2
|
||||||
|
defusedxml==0.6.0
|
||||||
|
distlib==0.3.1
|
||||||
|
distro==1.4.0
|
||||||
|
docutils==0.14
|
||||||
|
ecdsa==0.16.0
|
||||||
|
entrypoints==0.3
|
||||||
|
enum34==1.1.10
|
||||||
|
envs==1.3
|
||||||
|
et-xmlfile==1.0.1
|
||||||
|
face==0.1.0
|
||||||
|
feedparser==6.0.2
|
||||||
|
filelock==3.0.12
|
||||||
|
Flask==0.12.2
|
||||||
|
Flask-SQLAlchemy==2.3.2
|
||||||
|
future==0.18.2
|
||||||
|
gbulb==0.6.1
|
||||||
|
gitdb==4.0.5
|
||||||
|
GitPython==3.1.11
|
||||||
|
glom==18.4.0
|
||||||
|
gTTS-token==1.1.3
|
||||||
|
h11==0.9.0
|
||||||
|
h2==3.2.0
|
||||||
|
home-assistant-frontend==20190220.0
|
||||||
|
homeassistant==0.88.2
|
||||||
|
hpack==3.0.0
|
||||||
|
humanize==0.5.1
|
||||||
|
hyperframe==5.2.0
|
||||||
|
idna==2.7
|
||||||
|
ifaddr==0.1.6
|
||||||
|
importlib-metadata==1.6.0
|
||||||
|
ipykernel==5.3.4
|
||||||
|
ipython==7.18.1
|
||||||
|
ipython-genutils==0.2.0
|
||||||
|
ipywidgets==7.5.1
|
||||||
|
iso8601==0.1.12
|
||||||
|
itsdangerous==0.24
|
||||||
|
jdcal==1.4.1
|
||||||
|
jedi==0.17.2
|
||||||
|
Jinja2==2.10
|
||||||
|
jinja2-time==0.2.0
|
||||||
|
jmespath==0.9.4
|
||||||
|
joblib==0.16.0
|
||||||
|
jsonschema==3.2.0
|
||||||
|
jupyter==1.0.0
|
||||||
|
jupyter-client==6.1.7
|
||||||
|
jupyter-console==6.2.0
|
||||||
|
jupyter-core==4.6.3
|
||||||
|
Kivy==1.11.1
|
||||||
|
Kivy-Garden==0.1.4
|
||||||
|
kiwisolver==1.0.1
|
||||||
|
litecli==1.4.1
|
||||||
|
Logbook==1.5.3
|
||||||
|
lxml==4.2.5
|
||||||
|
macholib==1.11
|
||||||
|
MarkupSafe==1.0
|
||||||
|
matplotlib==3.0.0
|
||||||
|
matrix-nio==0.10.0
|
||||||
|
mistune==0.8.4
|
||||||
|
MouseInfo==0.1.2
|
||||||
|
multidict==4.4.2
|
||||||
|
mutagen==1.42.0
|
||||||
|
nbconvert==5.6.1
|
||||||
|
nbformat==5.0.7
|
||||||
|
netdisco==2.3.0
|
||||||
|
notebook==6.1.3
|
||||||
|
Nuitka==0.6.3.1
|
||||||
|
numpy==1.15.2
|
||||||
|
opencv-python==4.1.2.30
|
||||||
|
openpyxl==3.0.3
|
||||||
|
packaging==20.4
|
||||||
|
paho-mqtt==1.4.0
|
||||||
|
pandas==0.24.0
|
||||||
|
pandocfilters==1.4.2
|
||||||
|
parso==0.7.1
|
||||||
|
patsy==0.5.1
|
||||||
|
peewee==3.13.2
|
||||||
|
pefile==2018.8.8
|
||||||
|
pep517==0.6.0
|
||||||
|
pexpect==4.8.0
|
||||||
|
pickleshare==0.7.5
|
||||||
|
Pillow==6.2.1
|
||||||
|
ply==3.11
|
||||||
|
poyo==0.5.0
|
||||||
|
prometheus-client==0.8.0
|
||||||
|
prompt-toolkit==3.0.7
|
||||||
|
ptyprocess==0.6.0
|
||||||
|
PyAutoGUI==0.9.48
|
||||||
|
pycairo==1.20.0
|
||||||
|
pycparser==2.19
|
||||||
|
pycryptodome==3.3.1
|
||||||
|
pyfiglet==0.8.post1
|
||||||
|
pygal==2.4.0
|
||||||
|
PyGetWindow==0.0.8
|
||||||
|
Pygments==2.6.1
|
||||||
|
PyGObject==3.38.0
|
||||||
|
pyjsparser==2.7.1
|
||||||
|
PyJWT==1.6.4
|
||||||
|
PyMsgBox==1.0.6
|
||||||
|
pyodbc==4.0.24
|
||||||
|
pyOpenSSL==19.1.0
|
||||||
|
pyotp==2.2.6
|
||||||
|
pyparsing==2.2.2
|
||||||
|
pyperclip==1.7.0
|
||||||
|
PyQRCode==1.2.1
|
||||||
|
PyRect==0.1.4
|
||||||
|
pyrsistent==0.16.0
|
||||||
|
PyScreeze==0.1.25
|
||||||
|
pyserial==3.4
|
||||||
|
python-dateutil==2.7.3
|
||||||
|
python-jose-cryptodome==1.3.2
|
||||||
|
python-magic==0.4.15
|
||||||
|
python-olm==3.1.3
|
||||||
|
python-slugify==4.0.1
|
||||||
|
python-xlib==0.23
|
||||||
|
python3-xlib==0.15
|
||||||
|
pytoml==0.1.21
|
||||||
|
PyTweening==1.0.3
|
||||||
|
pytz==2018.9
|
||||||
|
PyYAML==3.13
|
||||||
|
pyzmq==19.0.2
|
||||||
|
qtconsole==4.7.6
|
||||||
|
QtPy==1.9.0
|
||||||
|
regex==2019.2.7
|
||||||
|
requests==2.25.0
|
||||||
|
rich==9.0.1
|
||||||
|
ruamel.yaml==0.15.88
|
||||||
|
s3transfer==0.2.0
|
||||||
|
scikit-learn==0.23.2
|
||||||
|
scipy==1.2.0
|
||||||
|
selenium==3.141.0
|
||||||
|
Send2Trash==1.5.0
|
||||||
|
serial==0.0.97
|
||||||
|
sgmllib3k==1.0.0
|
||||||
|
sh==1.14.1
|
||||||
|
simplegeneric==0.8.1
|
||||||
|
six==1.15.0
|
||||||
|
sklearn==0.0
|
||||||
|
slimit==0.8.1
|
||||||
|
smmap==3.0.4
|
||||||
|
SQLAlchemy==1.2.2
|
||||||
|
sqlparse==0.3.1
|
||||||
|
statsmodels==0.12.0
|
||||||
|
tabulate==0.8.7
|
||||||
|
terminado==0.8.3
|
||||||
|
terminaltables==3.1.0
|
||||||
|
testpath==0.4.4
|
||||||
|
text-unidecode==1.3
|
||||||
|
threadpoolctl==2.1.0
|
||||||
|
toga-core==0.3.0.dev25
|
||||||
|
toga-gtk==0.3.0.dev25
|
||||||
|
toml==0.10.2
|
||||||
|
tornado==6.0.4
|
||||||
|
traitlets==4.3.3
|
||||||
|
travertino==0.1.3
|
||||||
|
typing-extensions==3.7.4.3
|
||||||
|
tzlocal==1.5.1
|
||||||
|
ua-parser==0.8.0
|
||||||
|
Unidecode==1.0.23
|
||||||
|
unpaddedbase64==1.1.0
|
||||||
|
urllib3==1.23
|
||||||
|
urwid==2.1.0
|
||||||
|
user-agents==1.1.0
|
||||||
|
virtualenv==20.1.0
|
||||||
|
voluptuous==0.11.5
|
||||||
|
voluptuous-serialize==2.0.0
|
||||||
|
warrant==0.6.1
|
||||||
|
wcwidth==0.2.5
|
||||||
|
webcolors==1.11.1
|
||||||
|
webencodings==0.5.1
|
||||||
|
Werkzeug==0.16.0
|
||||||
|
widgetsnbextension==3.5.1
|
||||||
|
xlib==0.21
|
||||||
|
xlrd==1.2.0
|
||||||
|
xmltodict==0.11.0
|
||||||
|
yarl==1.2.6
|
||||||
|
yattag==1.10.0
|
||||||
|
zeroconf==0.21.3
|
||||||
|
zipp==3.1.0
|
53
urls.py
Normal file
53
urls.py
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
URLS = {
|
||||||
|
'login_xiaomi': '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',
|
||||||
|
'tokens_amazfit': 'https://api-user.huami.com/registrations/{user_email}/tokens',
|
||||||
|
'login_amazfit': 'https://account.huami.com/v2/client/login',
|
||||||
|
'devices': 'https://api-mifit-us2.huami.com/users/{user_id}/devices',
|
||||||
|
'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',
|
||||||
|
'logout': 'https://account-us2.huami.com/v1/client/logout'
|
||||||
|
}
|
||||||
|
|
||||||
|
PAYLOADS = {
|
||||||
|
'login_xiaomi': None,
|
||||||
|
'tokens_amazfit': {
|
||||||
|
'state': 'REDIRECTION',
|
||||||
|
'client_id': 'HuaMi',
|
||||||
|
'password': None,
|
||||||
|
'redirect_uri': 'https://s3-us-west-2.amazonws.com/hm-registration/successsignin.html',
|
||||||
|
'region': 'us-west-2',
|
||||||
|
'token': 'access',
|
||||||
|
'country_code': 'US'
|
||||||
|
},
|
||||||
|
'login_amazfit': {
|
||||||
|
'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',
|
||||||
|
'country_code': None,
|
||||||
|
'device_id': None,
|
||||||
|
'third_name': None,
|
||||||
|
'lang': 'en',
|
||||||
|
'device_model': 'android_phone',
|
||||||
|
'allow_registration': 'false',
|
||||||
|
'app_name': 'com.huami.midong',
|
||||||
|
'code': None,
|
||||||
|
'grant_type': None
|
||||||
|
},
|
||||||
|
'devices': {
|
||||||
|
'apptoken': None
|
||||||
|
},
|
||||||
|
'agps': {
|
||||||
|
'apptoken': None
|
||||||
|
},
|
||||||
|
'data_short': {
|
||||||
|
'apptoken': None,
|
||||||
|
'startDay': None,
|
||||||
|
'endDay': None
|
||||||
|
},
|
||||||
|
'logout': {
|
||||||
|
'login_token': None
|
||||||
|
},
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user