-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathreadM365.py
executable file
·78 lines (67 loc) · 2.92 KB
/
readM365.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
#!/usr/bin/env python
# -*- mode: python; coding: utf-8 -*-
#
# Read data from Xiaomi M365 Scooter
from gattlib import GATTRequester, GATTResponse
from struct import *
from time import sleep
from binascii import hexlify
MASTER_TO_M365 = 0x20
M365_TO_MASTER = 0x23
BATTERY_TO_MASTER = 0x25
DISTANCE_INFO = 0x25
TRIP_INFO = 0xb0
BATTERY_INFO = 0x31
class Requester(GATTRequester):
def on_notification(self, handle, data):
payload = data[3:]
# print hexlify(payload)
if len(payload) > 8:
data_type, address = unpack('<xxxBxB', payload[:6])
if data_type == M365_TO_MASTER:
if address == DISTANCE_INFO:
distance_left = unpack('<H', payload[6:8])
print 'Distance left:', distance_left[0] / 100., 'km'
elif address == TRIP_INFO:
error, warning, flags, workmode, battery, speed, speed_average = unpack('<HHHHHHH', payload[6:20])
print 'Current speed:', speed / 100., 'km/h'
print 'Average speed:', speed_average / 100., 'km/h'
elif data_type == BATTERY_TO_MASTER:
if address == BATTERY_INFO:
capacity_left, battery_percent, current, voltage, battery_temperature1, battery_temperature2 \
= unpack('<HHhHBB', payload[6:16])
print 'Battery capacity:', capacity_left, 'mAh'
print 'Battery percentage:', battery_percent, '%'
print 'Battery current:', current / 100., 'A'
print 'Battery voltage:', voltage / 100., 'V'
print 'Battery temperature 1:', battery_temperature1 - 20, 'C'
print 'Battery temperature 2:', battery_temperature2 - 20, 'C'
else:
# this is a second packet from the 0xb0 request
total_m, temperature = unpack('<Ixxxxh', payload[:10])
print 'Total distance:', total_m / 1000., 'km'
print 'Frame temperature', temperature / 10., 'C'
address = "AA:BB:CC:DD:EE:FF"
requester = Requester(address, False)
try:
requester.connect(True, 'random')
except RuntimeError as e:
# gattlib.connect's `wait=True` requires elevated permission
# or modified capabilities.
# It still connects, but a RuntimeError is raised. Check if
# `self.gatt` is connected, and rethrow exception otherwise.
if not requester.is_connected():
raise e
# subscribe to the UART service
requester.write_by_handle(0x000c, str(bytearray([0x01, 0x00])))
sleep(0.1)
# speed, distance and lots of other stuff
requester.write_by_handle(0x000e, str(bytearray.fromhex("55aa 03 2001 b0 20 0bff")))
sleep(0.1)
# km left
requester.write_by_handle(0x000e, str(bytearray.fromhex("55aa 03 2001 25 02 b4ff")))
sleep(0.1)
# battery info
requester.write_by_handle(0x000e, str(bytearray.fromhex("55aa 03 2201 31 0a 9eff")))
sleep(0.1)
sleep(1)