Closed dnandha closed 2 years ago
Ah yes, what happens if you add the self.ble.stop_listen()
after this line (under the condition that state is COMM
state):
https://github.com/dnandha/miauth/blob/3aadfb4bd290bf37d14a9f1c198d56d9dcce4e87/lib/python/miauth/mi/miclient.py#L72
Also while writing this I notice that after login()
you'll have to set ble.listen
back to True
, otherwise you won't receive any message on comm()
. A start_listening()
function could be introduced.
That somewhat works, but is unreliable I think, because those empty frames can appear anywhere - e.g. here:
Retrieving serial number
<- Empty data
Timeout, no answer received
b'' # a print(resp) I added because in one case I got a UnicodeDecodeError
Serial number:
Here's another one:
Retrieving serial number
<- Empty data
<- 55 ab 10 01 00 8a 90 2e 2e e4 1f 93 9a 42 c7 c2 f1 34 dd 43
b'U\xab\x10\x01\x00\x8a\x90..\xe4\x1f\x93\x9aB\xc7\xc2\xf14\xddC'
Traceback (most recent call last):
File "/usr/lib/python3.10/runpy.py", line 196, in _run_module_as_main
return _run_code(code, main_globals, None,
File "/usr/lib/python3.10/runpy.py", line 86, in _run_code
exec(code, run_globals)
File "/home/florian/proj/xiaomi-garmin/py/miauth/lib/python/miauth/cli.py", line 159, in <module>
main()
File "/home/florian/proj/xiaomi-garmin/py/miauth/lib/python/miauth/cli.py", line 155, in main
mi_main(ble)
File "/home/florian/proj/xiaomi-garmin/py/miauth/lib/python/miauth/cli.py", line 134, in mi_main
print("Serial number:", resp.decode())
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xab in position 1: invalid start byte
Ok I see. The serial number is sent across two packets and the decode error happens when only one packet is received, meaning: the empty data packet barges between those two serial number packets.
So instead of stop_listen()
on the first empty data packet define a threshold, e.g. 5 empty packets. This should solve the issue.
I tried this on top of your PR:
diff --git i/lib/python/miauth/mi/miclient.py w/lib/python/miauth/mi/miclient.py
index 19feaf7..485e7c4 100644
--- i/lib/python/miauth/mi/miclient.py
+++ w/lib/python/miauth/mi/miclient.py
@@ -35,6 +35,8 @@ class State(Enum):
CONFIRM = 4
COMM = 5
+ EMPTY_THRESHOLD = 5
+
def __init__(self, ble: BLEBase, debug=False):
self.ble = ble
self.debug = debug
@@ -64,13 +66,18 @@ def __init__(self, ble: BLEBase, debug=False):
self.token = b''
self.keys = b''
- # counter for sent uart commands
+ # counter for sent uart commands and empty responses
self.uart_it = 0
+ self.empty_counter = 0
def main_handler(self, data):
if not data:
if self.debug:
print("<- Empty data")
+ self.empty_counter += 1
+ if self.empty_counter == self.EMPTY_THRESHOLD:
+ print(f"Got {self.EMPTY_THRESHOLD} empty packets")
+ self.ble.stop_listening()
return
frm = data[0] + 0x100 * data[1]
but I still get a wild mixture of bluepy.btle.BTLEInternalError: Unexpected response (wr)
, cryptography.exceptions.InvalidTag
, the UnicodeEncodeError
from above, and this:
File "/home/florian/proj/xiaomi-garmin/py/miauth/lib/python/miauth/mi/miclient.py", line 123, in get_state
return self.seq[self.seq_idx][0]
IndexError: tuple index out of range
I never really got things to work reliably so far, but right now, it looks like it doesn't seem to work at all. I still feel like I only understand a tiny fraction of it all so far, so I'll probably be of limited help...
@The-Compiler For the stop_listen()
you forgot a part: "under the condition that state is COMM state". Otherwise it will count the total empty packets and exit mid-way, but we're only interested in the empty packets of the final state.
Something like this
> def main_handler(self, data):
> if not data:
> if self.debug:
> print("<- Empty data")
> + if self.get_state() == MiClient.State.COMM:
> + self.empty_counter += 1
> + if self.empty_counter >= self.EMPTY_THRESHOLD:
> + self.empty_counter = 0
> + print(f"Got {self.EMPTY_THRESHOLD} empty packets")
> + self.ble.stop_listening()
> return
>
> frm = data[0] + 0x100 * data[1]
EDIT: only count up in COMM state...
Right, that makes more sense. I've also had to set the initial seq
to something which has a state in it, so that calling get_state
works immediately after __init__
(that was the source of the IndexError
: seq_idx
being initialized to 0
, but seq
being ()
).
diff --git i/lib/python/miauth/mi/miclient.py w/lib/python/miauth/mi/miclient.py
index 19feaf7..0372e5e 100644
--- i/lib/python/miauth/mi/miclient.py
+++ w/lib/python/miauth/mi/miclient.py
@@ -35,6 +35,8 @@ class State(Enum):
CONFIRM = 4
COMM = 5
+ EMPTY_THRESHOLD = 5
+
def __init__(self, ble: BLEBase, debug=False):
self.ble = ble
self.debug = debug
@@ -47,7 +49,7 @@ def __init__(self, ble: BLEBase, debug=False):
# state machine is supplied with a sequence of ...
# if seq = [<state>, <on_state_enter_func()>]
# TODO: create sequence controller class
- self.seq = ()
+ self.seq = ((MiClient.State.INIT, None),)
self.seq_idx = 0
# buffer for send handler
@@ -64,13 +66,19 @@ def __init__(self, ble: BLEBase, debug=False):
self.token = b''
self.keys = b''
- # counter for sent uart commands
+ # counter for sent uart commands and empty responses
self.uart_it = 0
+ self.empty_counter = 0
def main_handler(self, data):
if not data:
if self.debug:
print("<- Empty data")
+ if self.get_state() == MiClient.State.COMM:
+ self.empty_counter += 1
+ if self.empty_counter == self.EMPTY_THRESHOLD:
+ print(f"Got {self.EMPTY_THRESHOLD} empty packets")
+ self.ble.stop_listening()
return
frm = data[0] + 0x100 * data[1]
With that, I now seem to always get the partial serial number, however:
new state: State.CONFIRM
<- 21 00 00 00
Mi login successful!
new state: State.COMM
<- Empty data
<- Empty data
<- Empty data
<- Empty data
<- Empty data
Got 5 empty packets
Retrieving serial number
<- 55 ab 10 01 00 69 af 3c 81 59 13 56 dd 1b 17 0c 07 cb 0f 29
Traceback (most recent call last):
File "/usr/lib/python3.10/runpy.py", line 196, in _run_module_as_main
return _run_code(code, main_globals, None,
File "/usr/lib/python3.10/runpy.py", line 86, in _run_code
exec(code, run_globals)
File "/home/florian/proj/xiaomi-garmin/py/miauth/lib/python/miauth/cli.py", line 158, in <module>
main()
File "/home/florian/proj/xiaomi-garmin/py/miauth/lib/python/miauth/cli.py", line 154, in main
mi_main(ble)
File "/home/florian/proj/xiaomi-garmin/py/miauth/lib/python/miauth/cli.py", line 133, in mi_main
print("Serial number:", resp.decode())
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xab in position 1: invalid start byte
Also while writing this I notice that after
login()
you'll have to setble.listen
back toTrue
, otherwise you won't receive any message oncomm()
. Astart_listening()
function could be introduced.
I've tried that as well:
diff --git i/lib/python/miauth/ble/blue.py w/lib/python/miauth/ble/blue.py
index 3be5510..b8b4ce2 100644
--- i/lib/python/miauth/ble/blue.py
+++ w/lib/python/miauth/ble/blue.py
@@ -93,6 +93,9 @@ def disconnect(self):
def stop_listening(self):
self.listen = False
+ def start_listening(self):
+ self.listen = True
+
def wait_notify(self, secs=1.0):
while self.p.waitForNotifications(secs) and self.listen:
continue
diff --git i/lib/python/miauth/mi/miclient.py w/lib/python/miauth/mi/miclient.py
index 19feaf7..b2c52f7 100644
--- i/lib/python/miauth/mi/miclient.py
+++ w/lib/python/miauth/mi/miclient.py
@@ -311,6 +319,8 @@ def on_send_did_state():
while self.get_state() != MiClient.State.COMM:
self.ble.wait_notify(secs=3.0)
+ self.ble.start_listening()
+
def send_encrypted(self, cmd):
res = MiCrypto.encrypt_uart(self.keys['app_key'],
self.keys['app_iv'],
but no dice:
Mi login successful!
new state: State.COMM
<- Empty data
<- Empty data
<- Empty data
<- Empty data
<- Empty data
Got 5 empty packets
Retrieving serial number
<- Empty data
<- 55 ab 10 01 00 17 a8 16 4a b5 79 a7 4d 86 b7 b6 73 f2 70 44
<- 24 a3 ba a0 fe a4 46 69 99 5b 3b f3
<- 55 ab 22 02 00 bc cd d6 66 e3 d8 3a 5d b8 3e a9 0d 79 09 d6
Traceback (most recent call last):
File "/usr/lib/python3.10/runpy.py", line 196, in _run_module_as_main
return _run_code(code, main_globals, None,
File "/usr/lib/python3.10/runpy.py", line 86, in _run_code
exec(code, run_globals)
File "/home/florian/proj/xiaomi-garmin/py/miauth/lib/python/miauth/cli.py", line 158, in <module>
main()
File "/home/florian/proj/xiaomi-garmin/py/miauth/lib/python/miauth/cli.py", line 154, in main
mi_main(ble)
File "/home/florian/proj/xiaomi-garmin/py/miauth/lib/python/miauth/cli.py", line 132, in mi_main
resp = mc.comm("55aa032001100e")
File "/home/florian/proj/xiaomi-garmin/py/miauth/lib/python/miauth/mi/miclient.py", line 368, in comm
self.ble.wait_notify()
File "/home/florian/proj/xiaomi-garmin/py/miauth/lib/python/miauth/ble/blue.py", line 100, in wait_notify
while self.p.waitForNotifications(secs) and self.listen:
File "/home/florian/proj/xiaomi-garmin/py/.venv/lib/python3.10/site-packages/bluepy/btle.py", line 560, in waitForNotifications
resp = self._getResp(['ntfy','ind'], timeout)
File "/home/florian/proj/xiaomi-garmin/py/.venv/lib/python3.10/site-packages/bluepy/btle.py", line 416, in _getResp
self.delegate.handleNotification(hnd, data)
File "/home/florian/proj/xiaomi-garmin/py/miauth/lib/python/miauth/ble/blue.py", line 47, in handleNotification
self.handler(data)
File "/home/florian/proj/xiaomi-garmin/py/miauth/lib/python/miauth/mi/miclient.py", line 105, in main_handler
dst, cmd, dec = self.decrypt(self.received_data)
File "/home/florian/proj/xiaomi-garmin/py/miauth/lib/python/miauth/mi/miclient.py", line 334, in decrypt
dec = MiCrypto.decrypt_uart(
File "/home/florian/proj/xiaomi-garmin/py/miauth/lib/python/miauth/mi/micrypto.py", line 122, in decrypt_uart
raise Exception("Invalid header.")
Exception: Invalid header.
Ok I see, so it stops listening before the command to retrieve the serial number has been sent. So the entry condition for the counter should be expanded to:
self.get_state() == MiClient.State.COMM and self.received_data
Since I don't have a DisplayDash all I can do at this point is helping you resolve this issue on your end. Once it works, we'll merge.
Still no luck:
Mi login successful!
new state: State.COMM
<- Empty data
<- Empty data
<- Empty data
<- Empty data
<- Empty data
Got 5 empty packets
Retrieving serial number
<- 55 ab 10 01 00 34 6e 34 fe 1f d5 42 be 23 26 f5 00 85 cf 64
<- 62 65 9e 1b df 9c 01 8b 0b ea b4 f4
<- 55 ab 20 02 00 4a fa 24 44 b2 67 2c 9f e1 20 25 25 36 94 6d
Traceback (most recent call last):
File "/usr/lib/python3.10/runpy.py", line 196, in _run_module_as_main
return _run_code(code, main_globals, None,
File "/usr/lib/python3.10/runpy.py", line 86, in _run_code
exec(code, run_globals)
File "/home/florian/proj/xiaomi-garmin/py/miauth/lib/python/miauth/cli.py", line 158, in <module>
main()
File "/home/florian/proj/xiaomi-garmin/py/miauth/lib/python/miauth/cli.py", line 154, in main
mi_main(ble)
File "/home/florian/proj/xiaomi-garmin/py/miauth/lib/python/miauth/cli.py", line 132, in mi_main
resp = mc.comm("55aa032001100e")
File "/home/florian/proj/xiaomi-garmin/py/miauth/lib/python/miauth/mi/miclient.py", line 368, in comm
self.ble.wait_notify()
File "/home/florian/proj/xiaomi-garmin/py/miauth/lib/python/miauth/ble/blue.py", line 100, in wait_notify
while self.p.waitForNotifications(secs) and self.listen:
File "/home/florian/proj/xiaomi-garmin/py/.venv/lib/python3.10/site-packages/bluepy/btle.py", line 560, in waitForNotifications
resp = self._getResp(['ntfy','ind'], timeout)
File "/home/florian/proj/xiaomi-garmin/py/.venv/lib/python3.10/site-packages/bluepy/btle.py", line 416, in _getResp
self.delegate.handleNotification(hnd, data)
File "/home/florian/proj/xiaomi-garmin/py/miauth/lib/python/miauth/ble/blue.py", line 47, in handleNotification
self.handler(data)
File "/home/florian/proj/xiaomi-garmin/py/miauth/lib/python/miauth/mi/miclient.py", line 105, in main_handler
dst, cmd, dec = self.decrypt(self.received_data)
File "/home/florian/proj/xiaomi-garmin/py/miauth/lib/python/miauth/mi/miclient.py", line 334, in decrypt
dec = MiCrypto.decrypt_uart(
File "/home/florian/proj/xiaomi-garmin/py/miauth/lib/python/miauth/mi/micrypto.py", line 122, in decrypt_uart
raise Exception("Invalid header.")
Exception: Invalid header.
Thanks for taking the time to help me get things running! :+1:
Ah it's because self.received_data
is reset too late.
Can you copy this line to the newly introduced on_comm_state
function?
https://github.com/dnandha/miauth/blob/93898e3c98bdecdec8129ac73ca2b6b2f3688b46/lib/python/miauth/mi/miclient.py#L347
This way when entering COMM state, the field will be blanked and we only start counting empty packets once at least one correct message has been received.
Not sure I follow - we currently don't have an on_comm_state
anymore. But I assume you mean something like here? https://github.com/dnandha/miauth/issues/5#issuecomment-1186994668
This is what I ended up with, full diff on top of this PR now:
diff --git i/lib/python/miauth/ble/blue.py w/lib/python/miauth/ble/blue.py
index 3be5510..b8b4ce2 100644
--- i/lib/python/miauth/ble/blue.py
+++ w/lib/python/miauth/ble/blue.py
@@ -93,6 +93,9 @@ def disconnect(self):
def stop_listening(self):
self.listen = False
+ def start_listening(self):
+ self.listen = True
+
def wait_notify(self, secs=1.0):
while self.p.waitForNotifications(secs) and self.listen:
continue
diff --git i/lib/python/miauth/mi/miclient.py w/lib/python/miauth/mi/miclient.py
index 19feaf7..dcb439f 100644
--- i/lib/python/miauth/mi/miclient.py
+++ w/lib/python/miauth/mi/miclient.py
@@ -35,6 +35,8 @@ class State(Enum):
CONFIRM = 4
COMM = 5
+ EMPTY_THRESHOLD = 5
+
def __init__(self, ble: BLEBase, debug=False):
self.ble = ble
self.debug = debug
@@ -47,7 +49,7 @@ def __init__(self, ble: BLEBase, debug=False):
# state machine is supplied with a sequence of ...
# if seq = [<state>, <on_state_enter_func()>]
# TODO: create sequence controller class
- self.seq = ()
+ self.seq = ((MiClient.State.INIT, None),)
self.seq_idx = 0
# buffer for send handler
@@ -64,13 +66,19 @@ def __init__(self, ble: BLEBase, debug=False):
self.token = b''
self.keys = b''
- # counter for sent uart commands
+ # counter for sent uart commands and empty responses
self.uart_it = 0
+ self.empty_counter = 0
def main_handler(self, data):
if not data:
if self.debug:
print("<- Empty data")
+ if self.get_state() == MiClient.State.COMM and self.received_data:
+ self.empty_counter += 1
+ if self.empty_counter == self.EMPTY_THRESHOLD:
+ print(f"Got {self.EMPTY_THRESHOLD} empty packets")
+ self.ble.stop_listening()
return
frm = data[0] + 0x100 * data[1]
@@ -296,6 +304,9 @@ def on_send_did_state():
f"{self.remote_info.hex(' ')} != {expected_remote_info.hex(' ')}"
self.ble.write(UUID.AVDTP, MiCommand.CMD_SEND_INFO)
+ def on_comm_state():
+ self.received_data = b''
+
self.seq = (
(MiClient.State.INIT, None),
(MiClient.State.SEND_KEY, on_send_key_state),
@@ -303,7 +314,7 @@ def on_send_did_state():
(MiClient.State.RECV_INFO, on_recv_info_state),
(MiClient.State.SEND_DID, on_send_did_state),
(MiClient.State.CONFIRM, None),
- (MiClient.State.COMM, None),
+ (MiClient.State.COMM, on_comm_state),
)
self.seq_idx = 0
@@ -311,6 +322,8 @@ def on_send_did_state():
while self.get_state() != MiClient.State.COMM:
self.ble.wait_notify(secs=3.0)
+ self.ble.start_listening()
+
def send_encrypted(self, cmd):
res = MiCrypto.encrypt_uart(self.keys['app_key'],
self.keys['app_iv'],
but now, the stop_listening
never triggers, because self.recieved_data
doesn't fill up anymore:
Mi login successful!
new state: State.COMM
<- Empty data
<- Empty data
<- Empty data
<- Empty data
<- Empty data
<- Empty data
<- Empty data
<- Empty data
[...]
^CTraceback (most recent call last):
File "/usr/lib/python3.10/runpy.py", line 196, in _run_module_as_main
return _run_code(code, main_globals, None,
File "/usr/lib/python3.10/runpy.py", line 86, in _run_code
exec(code, run_globals)
File "/home/florian/proj/xiaomi-garmin/py/miauth/lib/python/miauth/cli.py", line 158, in <module>
main()
File "/home/florian/proj/xiaomi-garmin/py/miauth/lib/python/miauth/cli.py", line 154, in main
mi_main(ble)
File "/home/florian/proj/xiaomi-garmin/py/miauth/lib/python/miauth/cli.py", line 122, in mi_main
mc.login()
File "/home/florian/proj/xiaomi-garmin/py/miauth/lib/python/miauth/mi/miclient.py", line 323, in login
self.ble.wait_notify(secs=3.0)
File "/home/florian/proj/xiaomi-garmin/py/miauth/lib/python/miauth/ble/blue.py", line 100, in wait_notify
while self.p.waitForNotifications(secs) and self.listen:
File "/home/florian/proj/xiaomi-garmin/py/.venv/lib/python3.10/site-packages/bluepy/btle.py", line 560, in waitForNotifications
resp = self._getResp(['ntfy','ind'], timeout)
File "/home/florian/proj/xiaomi-garmin/py/.venv/lib/python3.10/site-packages/bluepy/btle.py", line 407, in _getResp
resp = self._waitResp(wantType + ['ntfy', 'ind'], timeout)
File "/home/florian/proj/xiaomi-garmin/py/.venv/lib/python3.10/site-packages/bluepy/btle.py", line 342, in _waitResp
fds = self._poller.poll(timeout*1000)
KeyboardInterrupt
Ok, forget the thing I said about adding self.received_data
to the entry condition. I too had to understand the situation and now it's more clear.
Coming back to this:
... but no dice:
Mi login successful! new state: State.COMM <- Empty data <- Empty data <- Empty data <- Empty data <- Empty data Got 5 empty packets Retrieving serial number <- Empty data <- 55 ab 10 01 00 17 a8 16 4a b5 79 a7 4d 86 b7 b6 73 f2 70 44 <- 24 a3 ba a0 fe a4 46 69 99 5b 3b f3 <- 55 ab 22 02 00 bc cd d6 66 e3 d8 3a 5d b8 3e a9 0d 79 09 d6 Traceback (most recent call last): File "/usr/lib/python3.10/runpy.py", line 196, in _run_module_as_main return _run_code(code, main_globals, None, File "/usr/lib/python3.10/runpy.py", line 86, in _run_code exec(code, run_globals) File "/home/florian/proj/xiaomi-garmin/py/miauth/lib/python/miauth/cli.py", line 158, in <module> main() File "/home/florian/proj/xiaomi-garmin/py/miauth/lib/python/miauth/cli.py", line 154, in main mi_main(ble) File "/home/florian/proj/xiaomi-garmin/py/miauth/lib/python/miauth/cli.py", line 132, in mi_main resp = mc.comm("55aa032001100e") File "/home/florian/proj/xiaomi-garmin/py/miauth/lib/python/miauth/mi/miclient.py", line 368, in comm self.ble.wait_notify() File "/home/florian/proj/xiaomi-garmin/py/miauth/lib/python/miauth/ble/blue.py", line 100, in wait_notify while self.p.waitForNotifications(secs) and self.listen: File "/home/florian/proj/xiaomi-garmin/py/.venv/lib/python3.10/site-packages/bluepy/btle.py", line 560, in waitForNotifications resp = self._getResp(['ntfy','ind'], timeout) File "/home/florian/proj/xiaomi-garmin/py/.venv/lib/python3.10/site-packages/bluepy/btle.py", line 416, in _getResp self.delegate.handleNotification(hnd, data) File "/home/florian/proj/xiaomi-garmin/py/miauth/lib/python/miauth/ble/blue.py", line 47, in handleNotification self.handler(data) File "/home/florian/proj/xiaomi-garmin/py/miauth/lib/python/miauth/mi/miclient.py", line 105, in main_handler dst, cmd, dec = self.decrypt(self.received_data) File "/home/florian/proj/xiaomi-garmin/py/miauth/lib/python/miauth/mi/miclient.py", line 334, in decrypt dec = MiCrypto.decrypt_uart( File "/home/florian/proj/xiaomi-garmin/py/miauth/lib/python/miauth/mi/micrypto.py", line 122, in decrypt_uart raise Exception("Invalid header.") Exception: Invalid header.
The problem here is not the empty data, but the extra received data in the end: "55 ab 22 02 00 bc cd d6 66 e3 d8 3a 5d b8 3e a9 0d 79 09 d6", something which must be coming from the DisplayDash. So there must also be an exit condition: When a new header is received ("55a?") -> done.
I'll update this PR given this and the information from your last post so that we're back on the same page.
Edit: Splitting COMM into RDY_TO_RCV and RDY_TO_SEND seems to be a good solution. Once a message has been successfully received and decoded we enter RDY_TO_SEND and stop receiving messages. Once a new command is sent we enter RDY_TO_RCV and start listening. This also gets rid of manually calling stop_listen()
and start_listen()
.
Just pushed, it still works with my scooter and I think the send / receive logic is now a bit more clear.
Yay! That does seem to work quite nicely now.
One thing I noticed (already before the latest changes I think, but I can't test without the displaydash right now as I need to leave soon): It only seems to work for the first connection attempt, but not for subsequent ones, unless the scooter is rebooted.
With the code from your PR, I get:
Using Mi
Connecting
enabling notifications for: 6e400003-b5a3-f393-e0a9-e50e24dcca9e
enabling notifications for: 00000010-0000-1000-8000-00805f9b34fb
<- 55 ab 22 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Traceback (most recent call last):
File "/usr/lib/python3.10/runpy.py", line 196, in _run_module_as_main
return _run_code(code, main_globals, None,
File "/usr/lib/python3.10/runpy.py", line 86, in _run_code
exec(code, run_globals)
File "/home/florian/proj/xiaomi-garmin/py/miauth/lib/python/miauth/cli.py", line 158, in <module>
main()
File "/home/florian/proj/xiaomi-garmin/py/miauth/lib/python/miauth/cli.py", line 154, in main
mi_main(ble)
File "/home/florian/proj/xiaomi-garmin/py/miauth/lib/python/miauth/cli.py", line 103, in mi_main
mc.connect()
File "/home/florian/proj/xiaomi-garmin/py/miauth/lib/python/miauth/mi/miclient.py", line 116, in connect
self.ble.connect()
File "/home/florian/proj/xiaomi-garmin/py/miauth/lib/python/miauth/ble/blue.py", line 87, in connect
self.enable_notify(ch)
File "/home/florian/proj/xiaomi-garmin/py/miauth/lib/python/miauth/ble/blue.py", line 54, in enable_notify
resp = self.p.writeCharacteristic(ch.valHandle + 1, val, True)
File "/home/florian/proj/xiaomi-garmin/py/.venv/lib/python3.10/site-packages/bluepy/btle.py", line 543, in writeCharacteristic
return self._getResp('wr')
File "/home/florian/proj/xiaomi-garmin/py/.venv/lib/python3.10/site-packages/bluepy/btle.py", line 416, in _getResp
self.delegate.handleNotification(hnd, data)
File "/home/florian/proj/xiaomi-garmin/py/miauth/lib/python/miauth/ble/blue.py", line 47, in handleNotification
self.handler(data)
File "/home/florian/proj/xiaomi-garmin/py/miauth/lib/python/miauth/mi/miclient.py", line 87, in main_handler
if self.get_state() in [MiClient.State.RECV_INFO,
File "/home/florian/proj/xiaomi-garmin/py/miauth/lib/python/miauth/mi/miclient.py", line 126, in get_state
return self.seq[self.seq_idx][0]
IndexError: tuple index out of range
and when adding a proper initial seq
again:
diff --git i/lib/python/miauth/mi/miclient.py w/lib/python/miauth/mi/miclient.py
index 6c76587..f53b0f2 100644
--- i/lib/python/miauth/mi/miclient.py
+++ w/lib/python/miauth/mi/miclient.py
@@ -47,7 +47,7 @@ def __init__(self, ble: BLEBase, debug=False):
# state machine is supplied with a sequence of ...
# if seq = [<state>, <on_state_enter_func()>]
# TODO: create sequence controller class
- self.seq = ()
+ self.seq = ((MiClient.State.INIT, None),)
self.seq_idx = 0
# authentication related stuff
I then get:
Using Mi
Connecting
enabling notifications for: 6e400003-b5a3-f393-e0a9-e50e24dcca9e
enabling notifications for: 00000010-0000-1000-8000-00805f9b34fb
enabling notifications for: 00000019-0000-1000-8000-00805f9b34fb
<- 55 ab 22 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
<- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
<- 00 00 00 00 00 00 00 00 dd ff
Loading token from: ./mi_token
Logging in...
New state: State.SEND_KEY
<- 00 00 01 01
Mi ready to receive key
<- 55 ab 06 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
<- f9 ff
<- 00 00 01 00
Mi confirmed key receive
New state: State.RECV_KEY
<- 00 00 00 0d 01 00
Expecting 1 frames
<- 01 00 10 ac c7 f4 0d 2d 61 68 eb 67 40 3e 6f 24 2d 0e
<<-- 10 ac c7 f4 0d 2d 61 68 eb 67 40 3e 6f 24 2d 0e
New state: State.RECV_INFO
<- 55 ab 20 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
<- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Expecting 0 frames
<<--
New state: State.SEND_DID
HKDF result: 5a c9 e7 bf 68 f2 42 f9 41 4e c4 d0 6a bc 29 4f 8a bc c1 63 cc 54 18 92 91 26 bf 8d fd 96 4e b1 43 b4 da 31 48 5e b9 19 b8 0b 69 6a 2d ec 6a 25 be 30 a2 46 8a ce bb 0b 0c bf 96 18 0b da 35 90
DEV_KEY: 5a c9 e7 bf 68 f2 42 f9 41 4e c4 d0 6a bc 29 4f
APP_KEY: 8a bc c1 63 cc 54 18 92 91 26 bf 8d fd 96 4e b1
DEV_IV: 43 b4 da 31
APP_IV: 48 5e b9 19
Traceback (most recent call last):
File "/usr/lib/python3.10/runpy.py", line 196, in _run_module_as_main
return _run_code(code, main_globals, None,
File "/usr/lib/python3.10/runpy.py", line 86, in _run_code
exec(code, run_globals)
File "/home/florian/proj/xiaomi-garmin/py/miauth/lib/python/miauth/cli.py", line 158, in <module>
main()
File "/home/florian/proj/xiaomi-garmin/py/miauth/lib/python/miauth/cli.py", line 154, in main
mi_main(ble)
File "/home/florian/proj/xiaomi-garmin/py/miauth/lib/python/miauth/cli.py", line 122, in mi_main
mc.login()
File "/home/florian/proj/xiaomi-garmin/py/miauth/lib/python/miauth/mi/miclient.py", line 348, in login
self.ble.wait_notify(secs=3.0)
File "/home/florian/proj/xiaomi-garmin/py/miauth/lib/python/miauth/ble/blue.py", line 100, in wait_notify
while self.p.waitForNotifications(secs) and self.listen:
File "/home/florian/proj/xiaomi-garmin/py/.venv/lib/python3.10/site-packages/bluepy/btle.py", line 560, in waitForNotifications
resp = self._getResp(['ntfy','ind'], timeout)
File "/home/florian/proj/xiaomi-garmin/py/.venv/lib/python3.10/site-packages/bluepy/btle.py", line 416, in _getResp
self.delegate.handleNotification(hnd, data)
File "/home/florian/proj/xiaomi-garmin/py/miauth/lib/python/miauth/ble/blue.py", line 47, in handleNotification
self.handler(data)
File "/home/florian/proj/xiaomi-garmin/py/miauth/lib/python/miauth/mi/miclient.py", line 89, in main_handler
self.receive_handler(frm, data)
File "/home/florian/proj/xiaomi-garmin/py/miauth/lib/python/miauth/mi/miclient.py", line 168, in receive_handler
self.next_state()
File "/home/florian/proj/xiaomi-garmin/py/miauth/lib/python/miauth/mi/miclient.py", line 151, in next_state
self.exec_state()
File "/home/florian/proj/xiaomi-garmin/py/miauth/lib/python/miauth/mi/miclient.py", line 139, in exec_state
f()
File "/home/florian/proj/xiaomi-garmin/py/miauth/lib/python/miauth/mi/miclient.py", line 319, in on_send_did_state
assert self.remote_info == expected_remote_info, \
AssertionError: != 82 cb fc 06 49 e2 f3 09 35 97 df b6 f5 87 c3 5a 65 22 a8 d4 5e 06 32 33 b3 bd 1c c5 59 80 04 5a
or sometimes:
Using Mi
Connecting
enabling notifications for: 6e400003-b5a3-f393-e0a9-e50e24dcca9e
enabling notifications for: 00000010-0000-1000-8000-00805f9b34fb
enabling notifications for: 00000019-0000-1000-8000-00805f9b34fb
<- 55 ab 20 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
<- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
<- 00 00 00 00 00 00 df ff
Loading token from: ./mi_token
Logging in...
New state: State.SEND_KEY
<- 55 ab 0c 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
<- 00 00 00 00 00 00 f3 ff
<- 00 00 01 01
Mi ready to receive key
<- 55 ab 22 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
<- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
<- 00 00 00 00 00 00 00 00 dd ff
<- 00 00 01 00
Mi confirmed key receive
New state: State.RECV_KEY
<- 00 00 00 0d 01 00
Expecting 1 frames
<- 01 00 25 c3 dd 63 57 47 b6 d3 84 76 31 08 48 9e 7e c6
<<-- 25 c3 dd 63 57 47 b6 d3 84 76 31 08 48 9e 7e c6
New state: State.RECV_INFO
<- 55 ab 06 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
<- f9 ff
<- 00 00 00 0c 02 00
Expecting 2 frames
<- 01 00 31 0b 25 13 83 f7 f1 1f 1d af 9f 8d 34 05 2e db fe 17
<- 02 00 1d 98 8c a4 51 0c 3d 56 86 28 09 f7 d7 38
<<-- 31 0b 25 13 83 f7 f1 1f 1d af 9f 8d 34 05 2e db fe 17 1d 98 8c a4 51 0c 3d 56 86 28 09 f7 d7 38
New state: State.SEND_DID
HKDF result: 45 49 1f c6 d3 59 ee da cb 34 f6 a3 10 fc bd a6 5a 1c b3 99 5e 8e fa a2 d7 f4 9d 25 db d7 9c b7 fb 4c f7 c5 ff 4d ec c0 b8 bf 3d 4f 82 fc 96 50 e3 11 1e b6 cf 49 b1 1c 5a e5 14 6e 0b 39 5f 80
DEV_KEY: 45 49 1f c6 d3 59 ee da cb 34 f6 a3 10 fc bd a6
APP_KEY: 5a 1c b3 99 5e 8e fa a2 d7 f4 9d 25 db d7 9c b7
DEV_IV: fb 4c f7 c5
APP_IV: ff 4d ec c0
<- 55 ab 20 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
<- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
<- 00 00 00 00 00 00 df ff
<- 55 ab 0c 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
<- 00 00 00 00 00 00 f3 ff
<- 00 00 01 01
Mi ready to receive key
<- 00 00 01 00
Mi confirmed key receive
New state: State.CONFIRM
<- 21 00 00 00
Mi login successful!
New state: State.COMM_SEND
(Pause listening)
Retrieving serial number
-> 55 aa 03 20 01 10 0e
(Resuming listening)
-->> 55 ab 03 00 00 bf 7a c0 2e 69 d8 58 57 7d 35 a7 0b 81 fa
<- 55 ab 06 01 00 8c b9 52 9b 24 31 37 96 c4 37 cc 00 c1 6d 1f
Traceback (most recent call last):
File "/usr/lib/python3.10/runpy.py", line 196, in _run_module_as_main
return _run_code(code, main_globals, None,
File "/usr/lib/python3.10/runpy.py", line 86, in _run_code
exec(code, run_globals)
File "/home/florian/proj/xiaomi-garmin/py/miauth/lib/python/miauth/cli.py", line 158, in <module>
main()
File "/home/florian/proj/xiaomi-garmin/py/miauth/lib/python/miauth/cli.py", line 154, in main
mi_main(ble)
File "/home/florian/proj/xiaomi-garmin/py/miauth/lib/python/miauth/cli.py", line 132, in mi_main
resp = mc.comm("55aa032001100e")
File "/home/florian/proj/xiaomi-garmin/py/miauth/lib/python/miauth/mi/miclient.py", line 394, in comm
self.ble.wait_notify()
File "/home/florian/proj/xiaomi-garmin/py/miauth/lib/python/miauth/ble/blue.py", line 100, in wait_notify
while self.p.waitForNotifications(secs) and self.listen:
File "/home/florian/proj/xiaomi-garmin/py/.venv/lib/python3.10/site-packages/bluepy/btle.py", line 560, in waitForNotifications
resp = self._getResp(['ntfy','ind'], timeout)
File "/home/florian/proj/xiaomi-garmin/py/.venv/lib/python3.10/site-packages/bluepy/btle.py", line 416, in _getResp
self.delegate.handleNotification(hnd, data)
File "/home/florian/proj/xiaomi-garmin/py/miauth/lib/python/miauth/ble/blue.py", line 47, in handleNotification
self.handler(data)
File "/home/florian/proj/xiaomi-garmin/py/miauth/lib/python/miauth/mi/miclient.py", line 106, in main_handler
dst, cmd, dec = self.decrypt(self.received_data)
File "/home/florian/proj/xiaomi-garmin/py/miauth/lib/python/miauth/mi/miclient.py", line 362, in decrypt
dec = MiCrypto.decrypt_uart(
File "/home/florian/proj/xiaomi-garmin/py/miauth/lib/python/miauth/mi/micrypto.py", line 130, in decrypt_uart
return aes_ccm.decrypt(nonce, ct, None)
File "/home/florian/proj/xiaomi-garmin/py/.venv/lib/python3.10/site-packages/cryptography/hazmat/primitives/ciphers/aead.py", line 141, in decrypt
return aead._decrypt(
File "/home/florian/proj/xiaomi-garmin/py/.venv/lib/python3.10/site-packages/cryptography/hazmat/backends/openssl/aead.py", line 161, in _decrypt
raise InvalidTag
cryptography.exceptions.InvalidTag
Any idea what that could be about?
(I left the keys in the output this time, as I guess they could be relevant - and I guess I can just register a new token anyways)
@The-Compiler Yeah... first error is because message is handled before registration is started, second message is because the message received "55ab06" is not the message we wanted and message length is shorter than expected. I pushed a few fixes for these two issues, please report.
First connection still works:
Using Mi
Connecting
enabling notifications for: 6e400003-b5a3-f393-e0a9-e50e24dcca9e
enabling notifications for: 00000010-0000-1000-8000-00805f9b34fb
BLE message received but no handler.
enabling notifications for: 00000019-0000-1000-8000-00805f9b34fb
Loading token from: ./mi_token
Logging in...
New state: State.INIT
New state: State.SEND_KEY
<- 00 00 01 01
Mi ready to receive key
<- Empty data
<- 00 00 01 00
Mi confirmed key receive
New state: State.RECV_KEY
<- 00 00 00 0d 01 00
Expecting 1 frames
<- 01 00 e7 74 49 f5 e6 22 a8 d6 d7 dd 08 94 39 40 1f 1d
<<-- e7 74 49 f5 e6 22 a8 d6 d7 dd 08 94 39 40 1f 1d
<- Empty data
New state: State.RECV_INFO
<- 00 00 00 0c 02 00
Expecting 2 frames
<- 01 00 73 4e f7 44 64 cc 3f 23 58 e8 e6 f0 16 b3 f5 36 fa d2
<- 02 00 11 83 f7 78 df f6 22 59 31 f1 cc 92 37 4e
<<-- 73 4e f7 44 64 cc 3f 23 58 e8 e6 f0 16 b3 f5 36 fa d2 11 83 f7 78 df f6 22 59 31 f1 cc 92 37 4e
New state: State.SEND_DID
HKDF result: ba d2 36 2b 77 16 cb 67 9f 01 26 f9 63 35 53 d7 fb 2c 82 57 0b 21 2c 65 a0 4b 86 09 10 b4 81 71 94 d5 69 5b 84 34 cf 89 5a f4 61 98 90 eb 0f ce 07 27 02 de 4d 13 db 38 1e 0b fb c1 8b 38 45 1d
DEV_KEY: ba d2 36 2b 77 16 cb 67 9f 01 26 f9 63 35 53 d7
APP_KEY: fb 2c 82 57 0b 21 2c 65 a0 4b 86 09 10 b4 81 71
DEV_IV: 94 d5 69 5b
APP_IV: 84 34 cf 89
<- Empty data
<- Empty data
<- 00 00 01 01
Mi ready to receive key
<- Empty data
<- 00 00 01 00
Mi confirmed key receive
New state: State.CONFIRM
<- 21 00 00 00
Mi login successful!
New state: State.COMM_SEND
(Pause listening)
Retrieving serial number
-> 55 aa 03 20 01 10 0e
(Resuming listening)
-->> 55 ab 03 00 00 c2 ef d1 6b 6b ed fb ef ea 8a 5a c4 3b f7
<- 55 ab 10 01 00 70 bb 96 2d 22 cf 9c d4 45 69 97 57 d9 65 bf
<- 80 35 e3 74 ad a7 22 bd c5 d6 2c f2
<<-- 23 01 10 32 35 37 30 31 2f 30 30 30 39 39 38 30 36
(Pause listening)
Serial number: 25701/00099806
Disconnecting
but the subsequent ones do not:
Using Mi
Connecting
enabling notifications for: 6e400003-b5a3-f393-e0a9-e50e24dcca9e
enabling notifications for: 00000010-0000-1000-8000-00805f9b34fb
enabling notifications for: 00000019-0000-1000-8000-00805f9b34fb
BLE message received but no handler.
BLE message received but no handler.
Loading token from: ./mi_token
Logging in...
New state: State.INIT
New state: State.SEND_KEY
<- 55 ab 22 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
<- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
<- 00 00 00 00 00 00 00 00 dd ff
<- 00 00 01 01
Mi ready to receive key
<- 55 ab 06 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
<- f9 ff
<- 00 00 01 00
Mi confirmed key receive
New state: State.RECV_KEY
<- 00 00 00 0d 01 00
Expecting 1 frames
<- 55 ab 22 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
<- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Expecting 0 frames
<- 00 00 00 00 00 00 00 00 dd ff
Expecting 0 frames
<<--
New state: State.RECV_INFO
<<--
New state: State.SEND_DID
HKDF result: 49 bc 4f ec 9d 3c 4c a7 67 bb 19 17 1c ac 44 6e 43 c4 e2 ab 7a ad 1a 2f c4 10 ae 19 12 68 d1 c5 e5 f0 08 20 5a 44 62 13 b0 12 7f af e6 7f d9 cf 00 8b 2f 96 83 41 08 bf 59 d0 a3 b9 5e a8 6d c0
DEV_KEY: 49 bc 4f ec 9d 3c 4c a7 67 bb 19 17 1c ac 44 6e
APP_KEY: 43 c4 e2 ab 7a ad 1a 2f c4 10 ae 19 12 68 d1 c5
DEV_IV: e5 f0 08 20
APP_IV: 5a 44 62 13
Traceback (most recent call last):
File "/usr/lib/python3.10/runpy.py", line 196, in _run_module_as_main
return _run_code(code, main_globals, None,
File "/usr/lib/python3.10/runpy.py", line 86, in _run_code
exec(code, run_globals)
File "/home/florian/proj/xiaomi-garmin/py/miauth/lib/python/miauth/cli.py", line 158, in <module>
main()
File "/home/florian/proj/xiaomi-garmin/py/miauth/lib/python/miauth/cli.py", line 154, in main
mi_main(ble)
File "/home/florian/proj/xiaomi-garmin/py/miauth/lib/python/miauth/cli.py", line 122, in mi_main
mc.login()
File "/home/florian/proj/xiaomi-garmin/py/miauth/lib/python/miauth/mi/miclient.py", line 355, in login
self.ble.wait_notify(secs=3.0)
File "/home/florian/proj/xiaomi-garmin/py/miauth/lib/python/miauth/ble/blue.py", line 101, in wait_notify
while self.p.waitForNotifications(secs) and self.listen:
File "/home/florian/proj/xiaomi-garmin/py/.venv/lib/python3.10/site-packages/bluepy/btle.py", line 560, in waitForNotifications
resp = self._getResp(['ntfy','ind'], timeout)
File "/home/florian/proj/xiaomi-garmin/py/.venv/lib/python3.10/site-packages/bluepy/btle.py", line 416, in _getResp
self.delegate.handleNotification(hnd, data)
File "/home/florian/proj/xiaomi-garmin/py/miauth/lib/python/miauth/ble/blue.py", line 46, in handleNotification
self.handler(data)
File "/home/florian/proj/xiaomi-garmin/py/miauth/lib/python/miauth/mi/miclient.py", line 87, in main_handler
self.receive_handler(frm, data)
File "/home/florian/proj/xiaomi-garmin/py/miauth/lib/python/miauth/mi/miclient.py", line 166, in receive_handler
self.next_state()
File "/home/florian/proj/xiaomi-garmin/py/miauth/lib/python/miauth/mi/miclient.py", line 149, in next_state
self.exec_state()
File "/home/florian/proj/xiaomi-garmin/py/miauth/lib/python/miauth/mi/miclient.py", line 137, in exec_state
f()
File "/home/florian/proj/xiaomi-garmin/py/miauth/lib/python/miauth/mi/miclient.py", line 326, in on_send_did_state
assert self.remote_info == expected_remote_info, \
AssertionError: != b9 91 2b 92 32 95 7b 01 63 77 8f ac 71 55 d6 e2 78 7c e1 c6 f5 50 bc 37 5f 91 51 b3 68 a0 b9 59
So what's interesting is that in the first try no rogue messages appear during registration/login but in the second try they do. Almost like the DisplayDash has some internal logic when to stop and resume sending coupled to the authentication process.
Anyway, I think I can come up with additional sanity checks for the packages received for all the authentication states. Except a commit soon.
@The-Compiler Alright, it's not your turn to test! Made the authentication process much more explicit.
Yay! :tada:
It seems to be much more reliable now, but still sometimes fails with:
Using Mi
Connecting
enabling notifications for: 6e400003-b5a3-f393-e0a9-e50e24dcca9e
enabling notifications for: 00000010-0000-1000-8000-00805f9b34fb
enabling notifications for: 00000019-0000-1000-8000-00805f9b34fb
BLE message received but no handler.
BLE message received but no handler.
Loading token from: ./mi_token
Logging in...
New state: State.INIT
New state: State.SEND_KEY
<- 00 00 01 01
Mi ready to receive key
<- 55 ab 20 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
<- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
<- 00 00 00 00 00 00 df ff
<- 55 ab 0c 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
<- 00 00 00 00 00 00 f3 ff
<- 00 00 01 00
Mi confirmed key receive
New state: State.RECV_KEY
<- 00 00 00 0d 01 00
Expecting 1 frames
<- 01 00 6e 1f 34 15 43 ba a4 d2 ed d7 9f 1a 23 48 86 18
<<-- 6e 1f 34 15 43 ba a4 d2 ed d7 9f 1a 23 48 86 18
New state: State.RECV_INFO
<- 55 ab 22 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
<- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
<- 00 00 00 00 00 00 00 00 dd ff
<- 00 00 00 0c 02 00
Expecting 2 frames
<- 01 00 00 f7 64 f4 dd ac 0e 5e 62 3b 57 8c 39 5f 7e 50 a5 13
<- 02 00 8e 3e d0 ab 34 4a 12 51 2d 54 51 36 35 4e
<<-- 00 f7 64 f4 dd ac 0e 5e 62 3b 57 8c 39 5f 7e 50 a5 13 8e 3e d0 ab 34 4a 12 51 2d 54 51 36 35 4e
<- 55 ab 06 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
New state: State.SEND_DID
HKDF result: b5 cd 70 99 b4 9e c6 18 90 a4 c5 54 ce 4b 2b 2c 60 35 73 5e 88 35 48 a8 85 2d d7 54 af bc 37 8d 9a e6 d2 54 38 67 32 99 42 1a 41 a4 2f e6 3e c9 f8 50 30 a5 4f 47 77 73 d2 c2 bf 1c 3d a1 64 11
DEV_KEY: b5 cd 70 99 b4 9e c6 18 90 a4 c5 54 ce 4b 2b 2c
APP_KEY: 60 35 73 5e 88 35 48 a8 85 2d d7 54 af bc 37 8d
DEV_IV: 9a e6 d2 54
APP_IV: 38 67 32 99
<- f9 ff
<- 00 00 01 01
Mi ready to receive key
<- 00 00 01 00
Mi confirmed key receive
New state: State.CONFIRM
<- 21 00 00 00
Mi unknown response...
New state: State.COMM_SEND
(Pause listening)
Retrieving serial number
-> 55 aa 03 20 01 10 0e
(Resuming listening)
-->> 55 ab 03 00 00 97 6f 82 38 c8 ed 9c d1 14 76 85 86 85 f9
<- 55 ab 20 01 00 7d e2 c9 ea 77 8f 1a 08 d7 11 05 91 47 ca 1e
Rouge message received, ignoring.
<- 52 7e 9d 4b f9 73 01 ef ed ad 11 d6 26 28 f4 a3 80 36 33 e2
<- b0 06 b4 6b 72 38 33 ec
<- 55 ab 0c 02 00 b6 c1 08 07 98 20 ae ff f2 ff 7a 57 79 15 fc
Rouge message received, ignoring.
<- c6 f0 90 be d5 99 48 f3
Traceback (most recent call last):
File "/usr/lib/python3.10/runpy.py", line 196, in _run_module_as_main
return _run_code(code, main_globals, None,
File "/usr/lib/python3.10/runpy.py", line 86, in _run_code
exec(code, run_globals)
File "/home/florian/proj/xiaomi-garmin/py/miauth/lib/python/miauth/cli.py", line 158, in <module>
main()
File "/home/florian/proj/xiaomi-garmin/py/miauth/lib/python/miauth/cli.py", line 154, in main
mi_main(ble)
File "/home/florian/proj/xiaomi-garmin/py/miauth/lib/python/miauth/cli.py", line 132, in mi_main
resp = mc.comm("55aa032001100e")
File "/home/florian/proj/xiaomi-garmin/py/miauth/lib/python/miauth/mi/miclient.py", line 404, in comm
self.ble.wait_notify()
File "/home/florian/proj/xiaomi-garmin/py/miauth/lib/python/miauth/ble/blue.py", line 101, in wait_notify
while self.p.waitForNotifications(secs) and self.listen:
File "/home/florian/proj/xiaomi-garmin/py/.venv/lib/python3.10/site-packages/bluepy/btle.py", line 560, in waitForNotifications
resp = self._getResp(['ntfy','ind'], timeout)
File "/home/florian/proj/xiaomi-garmin/py/.venv/lib/python3.10/site-packages/bluepy/btle.py", line 416, in _getResp
self.delegate.handleNotification(hnd, data)
File "/home/florian/proj/xiaomi-garmin/py/miauth/lib/python/miauth/ble/blue.py", line 46, in handleNotification
self.handler(data)
File "/home/florian/proj/xiaomi-garmin/py/miauth/lib/python/miauth/mi/miclient.py", line 91, in main_handler
dst, cmd, dec = self.decrypt(self.received_data)
File "/home/florian/proj/xiaomi-garmin/py/miauth/lib/python/miauth/mi/miclient.py", line 372, in decrypt
dec = MiCrypto.decrypt_uart(
File "/home/florian/proj/xiaomi-garmin/py/miauth/lib/python/miauth/mi/micrypto.py", line 122, in decrypt_uart
raise Exception("Invalid header.")
Exception: Invalid header.
@The-Compiler Ok, very nice. Added an additional filter for rogue UART messages. Hope with this it's all clear.
Looking great now, and working fine in 9 out of 10 cases.
In the remaining 1 out of 10, it seems to hang:
sing Mi
Connecting
enabling notifications for: 6e400003-b5a3-f393-e0a9-e50e24dcca9e
enabling notifications for: 00000010-0000-1000-8000-00805f9b34fb
BLE message received but no handler.
BLE message received but no handler.
BLE message received but no handler.
enabling notifications for: 00000019-0000-1000-8000-00805f9b34fb
Loading token from: ./mi_token
Logging in...
New state: State.INIT
New state: State.SEND_KEY
<- 55 ab 06 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
<- f9 ff
<- 00 00 01 01
Mi ready to receive key
<- 00 00 01 00
Mi confirmed key receive
New state: State.RECV_KEY
<- 00 00 00 0d 01 00
Expecting 1 frames
<- 55 ab 0c 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
<- 00 00 00 00 00 00 f3 ff
<- 01 00 9e f5 22 2c 1b d4 38 a3 0b 79 13 71 a5 6e 79 e9
<<-- 9e f5 22 2c 1b d4 38 a3 0b 79 13 71 a5 6e 79 e9
New state: State.RECV_INFO
<- 00 00 00 0c 02 00
Expecting 2 frames
<- 55 ab 22 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
<- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
<- 00 00 00 00 00 00 00 00 dd ff
<- 01 00 c6 25 64 17 ec 97 d2 e9 15 ad 7d 02 74 0a 9d 12 7d fb
<- 02 00 a5 ff 55 11 49 cb 34 3b 70 b8 71 04 28 ad
<<-- c6 25 64 17 ec 97 d2 e9 15 ad 7d 02 74 0a 9d 12 7d fb a5 ff 55 11 49 cb 34 3b 70 b8 71 04 28 ad
New state: State.SEND_DID
HKDF result: 19 2d c5 d4 d3 0d c1 b1 66 4e 21 c1 0b 65 cb c0 55 47 72 f5 71 c9 20 78 12 a9 1c f4 b1 16 52 0e 1d ac 0e 4e ac 7b 11 00 3e 8d 92 16 df 92 51 82 f3 ed 06 4f 38 f5 a4 84 3c 84 44 c1 cf fd 07 3c
DEV_KEY: 19 2d c5 d4 d3 0d c1 b1 66 4e 21 c1 0b 65 cb c0
APP_KEY: 55 47 72 f5 71 c9 20 78 12 a9 1c f4 b1 16 52 0e
DEV_IV: 1d ac 0e 4e
APP_IV: ac 7b 11 00
<- 00 00 01 01
Mi ready to receive key
<- 55 ab 06 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
<- f9 ff
<- 00 00 01 00
Mi confirmed key receive
New state: State.CONFIRM
<- 21 00 00 00
Mi login successful!
New state: State.COMM_SEND
(Pause listening)
Retrieving serial number
-> 55 aa 03 20 01 10 0e
(Resuming listening)
-->> 55 ab 03 00 00 3b bb 3c 5f 5b 26 93 01 22 7a 4f 42 29 fc
<- 55 ab 0c 01 00 2b c4 a4 58 31 da 6a 35 12 b3 d8 27 d3 1a 54
Rogue message received, start ignoring.
<- a3 dd 79 3d 92 15 7b f6
<- 55 ab 22 02 00 98 e2 a9 08 a5 90 12 d4 e6 8a 82 14 00 29 62
Rogue message received, start ignoring.
<- 9a 5e ca a5 56 f3 bb 8c 4c 20 c4 c1 dc 5b 7b d0 bc 1a 81 ba
<- 33 80 fe 78 64 73 c8 67 5a e9
<- 55 ab 06 03 00 5a dd 7a ab 69 a2 75 0a 62 98 b4 5a 95 ac d6
Rogue message received, start ignoring.
<- f1 f7
<- 55 ab 20 04 00 a2 4c 81 1e f6 1f 0b 33 3e 29 82 67 9e 38 a4
Rogue message received, start ignoring.
<- f2 52 8a 3f 26 78 5b 35 d5 ea f5 07 ae f6 6f cb 78 3f ab c2
<- e2 de 44 8f d5 20 b1 eb
<- 55 ab 22 05 00 3f 6c b5 e8 7b ea b2 93 d8 b4 7b 8c c8 a4 9c
Rogue message received, start ignoring.
<- e5 24 60 3a 1c da 9c 6b 47 ef 99 9d c7 29 33 2e d6 cc 81 ea
<- 7c 87 42 a8 56 fb fa 83 26 e7
<- 55 ab 0c 06 00 8f cf 9d f4 95 9b 9d ca fb c6 1a 07 da c5 9c
Rogue message received, start ignoring.
<- 3a c9 dc 46 d5 a9 a7 f2
<- 55 ab 06 07 00 de 0f 81 fc 51 ac 32 85 41 a7 a3 f3 fc 8a 51
Rogue message received, start ignoring.
<- 7f f7
<- 55 ab 20 08 00 7a ee 36 f3 61 8e cd 84 3d e2 6c bc a5 1c 5c
Rogue message received, start ignoring.
<- 24 0c a9 8f 3c c8 43 e6 fc d7 2b d9 c3 8c e3 bf 1f 78 f7 13
<- 59 8d f1 6a ba 07 a2 e9
<- 55 ab 22 09 00 52 c9 df 88 48 52 27 da d6 3e 37 4f 2e 2f 6f
Rogue message received, start ignoring.
<- 48 0d d5 2f cc ae 5b b0 1c 7e 0e 30 a2 64 1a df da 6a c5 70
<- 26 60 23 5d cd da 41 73 c2 ec
<- 55 ab 0c 0a 00 a7 8e b0 8d 18 98 d5 d9 0c 5d 53 70 fb da d2
Rogue message received, start ignoring.
<- e0 a2 0e fb 63 4b 0d f4
<- 55 ab 06 0b 00 74 63 8a f3 45 0f fe ed e0 63 3f 73 96 99 53
Rogue message received, start ignoring.
<- e4 f7
<- 55 ab 20 0c 00 64 86 dc d1 a1 a2 e9 4d 49 24 e6 5f e4 10 a5
Rogue message received, start ignoring.
[etc.]
but I can't actually spot the answer at all there, so there might be nothing we can do about that anyways?
@The-Compiler In that case the expected response never came. Maybe something colliding on the bus. I've pushed a small change that gets you out of this situation by giving up after three non-expected / rogue messages. The comm()
function should exit properly with an empty response. On your side: if you receive an empty response, simply resend the command.
Please test one last time, then I'm merging.
Some more from testing for a couple of mins:
[...]
Mi login successful!
New state: State.COMM_SEND
(Pause listening)
Retrieving serial number
-> 55 aa 03 20 01 10 0e
(Resuming listening)
-->> 55 ab 03 00 00 47 b7 ee cf 7e f3 57 25 3f 0c b0 0a 4f fa
<- 55 ab 20 01 00 62 57 5e 91 00 5b a4 36 15 02 a9 ba f5 bb 97
<- 49 12 f3 1b d2 ec 0d 32 6c 2d 6c 31 51 f7 30 18 a2 43 d2 a2
<- 2a 5e a3 fb ee 3a 6d ed
<<-- 25 01 40 00 0e 02 0e 03 0e 05 0e 03 0e 01 0e 07 0e 04 0e 07 0e 02 0e 00 00 00 00 00 00 00 00 00 00
Traceback (most recent call last):
File "/usr/lib/python3.10/runpy.py", line 196, in _run_module_as_main
return _run_code(code, main_globals, None,
File "/usr/lib/python3.10/runpy.py", line 86, in _run_code
exec(code, run_globals)
File "/home/florian/proj/xiaomi-garmin/py/miauth/lib/python/miauth/cli.py", line 158, in <module>
main()
File "/home/florian/proj/xiaomi-garmin/py/miauth/lib/python/miauth/cli.py", line 154, in main
mi_main(ble)
File "/home/florian/proj/xiaomi-garmin/py/miauth/lib/python/miauth/cli.py", line 132, in mi_main
resp = mc.comm("55aa032001100e")
File "/home/florian/proj/xiaomi-garmin/py/miauth/lib/python/miauth/mi/miclient.py", line 412, in comm
self.ble.wait_notify()
File "/home/florian/proj/xiaomi-garmin/py/miauth/lib/python/miauth/ble/blue.py", line 101, in wait_notify
while self.p.waitForNotifications(secs) and self.listen:
File "/home/florian/proj/xiaomi-garmin/py/.venv/lib/python3.10/site-packages/bluepy/btle.py", line 560, in waitForNotifications
resp = self._getResp(['ntfy','ind'], timeout)
File "/home/florian/proj/xiaomi-garmin/py/.venv/lib/python3.10/site-packages/bluepy/btle.py", line 416, in _getResp
self.delegate.handleNotification(hnd, data)
File "/home/florian/proj/xiaomi-garmin/py/miauth/lib/python/miauth/ble/blue.py", line 46, in handleNotification
self.handler(data)
File "/home/florian/proj/xiaomi-garmin/py/miauth/lib/python/miauth/mi/miclient.py", line 106, in main_handler
raise Exception("Invalid response received.")
Exception: Invalid response received.
and:
Mi login successful!
New state: State.COMM_SEND
(Pause listening)
Retrieving serial number
-> 55 aa 03 20 01 10 0e
(Resuming listening)
-->> 55 ab 03 00 00 b4 9f be 72 ef 3f ff bd 24 f8 ee 5b 2a f8
<- 55 ab 06 01 00 66 c1 06 cf 77 11 ba dd bb 08 82 77 42 ba 49
Traceback (most recent call last):
File "/usr/lib/python3.10/runpy.py", line 196, in _run_module_as_main
return _run_code(code, main_globals, None,
File "/usr/lib/python3.10/runpy.py", line 86, in _run_code
exec(code, run_globals)
File "/home/florian/proj/xiaomi-garmin/py/miauth/lib/python/miauth/cli.py", line 158, in <module>
main()
File "/home/florian/proj/xiaomi-garmin/py/miauth/lib/python/miauth/cli.py", line 154, in main
mi_main(ble)
File "/home/florian/proj/xiaomi-garmin/py/miauth/lib/python/miauth/cli.py", line 132, in mi_main
resp = mc.comm("55aa032001100e")
File "/home/florian/proj/xiaomi-garmin/py/miauth/lib/python/miauth/mi/miclient.py", line 411, in comm
self.send_encrypted(cmd)
File "/home/florian/proj/xiaomi-garmin/py/miauth/lib/python/miauth/mi/miclient.py", line 373, in send_encrypted
self.ble.write_chunked(UUID.TX, res)
File "/home/florian/proj/xiaomi-garmin/py/miauth/lib/python/miauth/ble/blue.py", line 71, in write_chunked
self.write(ch, chunk, resp=resp)
File "/home/florian/proj/xiaomi-garmin/py/miauth/lib/python/miauth/ble/blue.py", line 66, in write
self.channels[ch].write(data, resp)
File "/home/florian/proj/xiaomi-garmin/py/.venv/lib/python3.10/site-packages/bluepy/btle.py", line 200, in write
return self.peripheral.writeCharacteristic(self.valHandle, val, withResponse)
File "/home/florian/proj/xiaomi-garmin/py/.venv/lib/python3.10/site-packages/bluepy/btle.py", line 543, in writeCharacteristic
return self._getResp('wr')
File "/home/florian/proj/xiaomi-garmin/py/.venv/lib/python3.10/site-packages/bluepy/btle.py", line 416, in _getResp
self.delegate.handleNotification(hnd, data)
File "/home/florian/proj/xiaomi-garmin/py/miauth/lib/python/miauth/ble/blue.py", line 46, in handleNotification
self.handler(data)
File "/home/florian/proj/xiaomi-garmin/py/miauth/lib/python/miauth/mi/miclient.py", line 99, in main_handler
dst, cmd, dec = self.decrypt(self.received_data)
File "/home/florian/proj/xiaomi-garmin/py/miauth/lib/python/miauth/mi/miclient.py", line 380, in decrypt
dec = MiCrypto.decrypt_uart(
File "/home/florian/proj/xiaomi-garmin/py/miauth/lib/python/miauth/mi/micrypto.py", line 130, in decrypt_uart
return aes_ccm.decrypt(nonce, ct, None)
File "/home/florian/proj/xiaomi-garmin/py/.venv/lib/python3.10/site-packages/cryptography/hazmat/primitives/ciphers/aead.py", line 141, in decrypt
return aead._decrypt(
File "/home/florian/proj/xiaomi-garmin/py/.venv/lib/python3.10/site-packages/cryptography/hazmat/backends/openssl/aead.py", line 161, in _decrypt
raise InvalidTag
cryptography.exceptions.InvalidTag
The "endless comms loop" issue can be reproduced by running the CLI immediately again after the previous invocation exits, before getting the disconnected double-beep from the BLE.
Note I'm also fine with ignoring the issues above - they seem to happen seldom enough that it shouldn't be a problem dealing with them somehow, and I'm already really thankful for all the fixes! :heart:
Hmm, the "reconnecting before disconnect beep" issue actually seems like a separate one, as those are actually not rogue messages (or at least not shown as such). Here is the log from the second invocation (before the first fully disconnected):
Using Mi
Connecting
enabling notifications for: 6e400003-b5a3-f393-e0a9-e50e24dcca9e
enabling notifications for: 00000010-0000-1000-8000-00805f9b34fb
BLE message received but no handler.
BLE message received but no handler.
enabling notifications for: 00000019-0000-1000-8000-00805f9b34fb
Loading token from: ./mi_token
Logging in...
New state: State.INIT
New state: State.SEND_KEY
<- e2 00 00 00
<- 55 ab 20 20 00 5c 8b 63 c8 34 69 a3 3c 55 f9 f6 a7 62 85 c8
<- 1b 80 32 6a 52 05 d7 66 1d 87 e1 18 09 43 18 52 c3 d9 e8 e0
<- 6f c6 b6 42 9b c9 84 eb
<- 55 ab 0c 21 00 75 8a 07 74 26 53 1d c3 3f 21 e2 9d 6e 82 ff
<- 50 a0 ad 23 d9 fc 9c f5
<- 55 ab 22 22 00 e9 df e0 64 dc 9d 90 98 a0 25 aa fd 89 d3 9e
<- 2a 2c 54 7d 94 4a d0 10 73 ee 89 2e dd 9f 80 24 ac 97 26 f9
<- 9e 17 58 4f a2 a8 35 42 0c e9
<- 55 ab 06 23 00 1f 5e 1f e3 c1 c9 fc f7 0d f4 6b 90 0c 1a 2d
<- 8b f8
<- 55 ab 20 24 00 e6 45 d0 de 5c 37 76 23 3f 95 3b d6 78 b0 6c
<- f0 82 3c b5 05 84 5d 0d 3f 3d 2a a6 eb 63 7a 86 6b 36 35 44
<- a9 fd 40 2b 2f 6f 84 ed
<- 55 ab 0c 25 00 d2 28 0c 7e 75 55 c7 42 0b 43 c2 b0 c7 56 74
<- f7 b4 42 c0 aa e0 ef f4
<- 55 ab 22 26 00 15 23 bc e0 07 9a 1b 37 a1 d1 ff 68 71 90 3d
<- 08 e5 04 97 0b 87 be d9 bb f1 c5 c9 60 37 e1 01 96 3f d5 bf
<- fa 69 13 d5 a3 30 83 b4 b7 e9
<- 55 ab 22 27 00 ba 0e dd 4d a8 99 96 25 b1 9f 1d b4 b3 0e d5
<- 1a b4 e8 75 2d 23 d4 48 30 55 0a a1 03 7d 5f 1a 00 a5 d8 0f
<- b4 6d e5 5e d7 b3 ab 52 da eb
<- 55 ab 06 28 00 0c 7a 35 3d 6a f9 8a 70 59 7a a8 8e 43 f4 b5
<- 87 f8
<- 55 ab 20 29 00 a7 e5 e9 35 a1 30 f6 53 82 6d b0 75 32 99 2c
<- df 64 eb ff 4a 57 c2 36 94 5d 73 a7 cb 2a a9 12 f6 90 41 63
<- 80 8c 78 7e 0a c3 6d ea
<- 55 ab 0c 2a 00 15 2c 4f 94 a3 03 cf 40 fa da 94 b0 24 40 f1
<- 5c 76 be ff 90 a7 bd f4
<- 55 ab 22 2b 00 18 8d b0 fc 40 48 76 a4 31 36 b8 8b e5 b1 5e
<- ba 9b d3 6c ff 30 dd e2 3e cf a6 2c 42 cf f5 b5 29 09 3a 10
<- f3 34 cd 40 97 2d bf cb 07 e9
<- 55 ab 06 2c 00 25 ac 8a 3a d3 ab 0e 48 14 06 ab 85 e9 70 e7
<- da f8
<- 55 ab 20 2d 00 96 ce 95 a5 a5 0d ff ef 73 94 d2 48 4a 45 47
<- fc b4 7b 81 8f 85 a8 af d9 d9 0c 58 53 d5 b4 8a 8a 06 81 9f
<- 14 de 11 b8 5f 09 17 ea
<- 55 ab 0c 2e 00 15 3d 05 21 23 03 de 4f c6 45 1a 50 13 c1 00
<- ea d5 13 5b a3 25 bc f8
<- 55 ab 22 2f 00 91 72 a1 e3 99 e7 e5 5d 32 69 c1 00 59 07 9c
<- 6d d3 c6 3a 0e 04 0e 7b 1b 6f 7a 97 24 33 e0 c6 fe 30 8f ed
<- 2a cc 58 b9 90 97 3b 81 06 eb
<- 55 ab 06 30 00 16 42 a5 75 2e 48 0b 70 d2 01 d4 e3 f5 0f 4e
<- 8a f9
<- 55 ab 20 31 00 07 ea 2f 95 82 15 49 e3 07 c1 d5 3b 03 d0 3c
<- c2 2a 5a 5f 41 10 e3 3f d3 d1 17 58 1a 96 86 20 f5 ad 8d 2c
<- f8 22 7b 87 4d 3e cc ed
<- 55 ab 0c 32 00 68 40 cc 6f 92 b6 5b 65 99 b2 f4 98 21 02 7b
<- 3e d0 68 49 2c ee 88 f5
<- 55 ab 22 33 00 bc 47 e9 ac e9 3b eb 70 e1 8f dc c5 28 eb 32
<- 21 1d 9a 03 9e b3 75 04 52 f2 95 74 bd 8d 8c 5f ce fc 1c 70
<- ff 6c ba 60 70 8c ea 2f 26 e8
<- 55 ab 06 34 00 aa 9c 48 79 65 28 bd 72 d8 3d 14 c1 1b 88 10
<- 65 f9
<- 55 ab 20 35 00 3d 86 95 09 6e 80 50 4b 1a b7 f0 a5 67 5b 58
<- a4 7c d5 e4 bb cf 5c 8a ca e7 9a fb d3 3e ab 56 7a fc e4 d0
<- 97 e9 4f 20 84 9b 67 e8
<- 55 ab 0c 36 00 b5 cb 49 e6 e6 48 59 f0 55 b3 66 54 24 73 54
<- 7d 51 f3 9a 63 05 27 f5
<- 55 ab 22 37 00 67 a1 86 4e 99 61 44 af c2 72 69 4e f0 4f c1
<- f4 8f 0d 6f ce 9e 69 d4 fc b8 aa f5 ca bd 7d 9e 6d 8f da 10
<- bb a7 ff c9 3d 83 f2 5f 34 e6
<- 55 ab 06 38 00 0f 9c 0d cc 4e e0 f1 75 fa b4 48 07 85 bd 99
<- d1 f7
<- 55 ab 20 39 00 94 7d da 0b 84 0c 77 7f be 2f 5c 3d 6a f8 3d
<- 75 dc 37 94 06 16 91 3b dc 30 31 dc ef e5 51 71 a8 31 02 3d
<- 8d a3 09 52 99 de 38 ed
<- 55 ab 0c 3a 00 ee df 01 60 5e c2 d2 6f 9d a6 c7 d3 79 36 eb
<- 70 22 75 29 f4 bf d0 f3
<- 55 ab 22 3b 00 94 26 55 2e db b7 e7 3a 84 8e c0 62 aa 6f a8
<- 70 5f d3 b7 88 00 57 7c 88 15 a4 37 d8 2f 0e 52 22 03 fb e5
<- 24 0f 2d 96 bd 82 0e 10 d2 ec
<- 55 ab 06 3c 00 44 fe 5d 09 51 e4 f8 da 32 f3 9a 5d 30 16 c5
<- e7 f7
<- 55 ab 20 3d 00 22 17 05 9f c1 e0 09 d2 c9 fd 1c 7c 00 9f da
<- d9 0c 1a 46 5d 25 8e 7c 8e 0c 33 1e 62 91 fd 44 85 92 bd 00
<- 85 f4 4e 3e 19 26 6a ee
<- 55 ab 0c 3e 00 3b e2 a8 80 07 76 5e a9 69 82 8b 80 b5 bc 78
<- b4 62 f9 e2 c5 97 c0 f3
<- 55 ab 22 3f 00 cd 6d b8 83 c3 e1 25 8c 17 36 de 41 34 5a 41
<- d6 4e 4f 59 da 41 af 58 4f 18 38 aa 55 dd 48 44 88 34 93 e8
<- c6 8d 7f b6 ef 3c df 1c bf ea
<- 55 ab 06 40 00 df f9 50 63 f9 f4 bd e0 37 ee 04 7c cf 68 a6
<- 22 f6
<- 55 ab 20 41 00 77 47 78 6d 74 5b 4b 73 b6 0a e5 08 03 ef be
<- 29 02 e5 e8 d6 24 ec 66 9b 63 5e 4a 71 12 66 13 2d ed bb 87
<- 84 be dd 38 25 62 f1 ec
<- 55 ab 0c 42 00 71 93 80 54 7d e0 e3 ea 7c 92 35 bf 85 bb 92
<- 16 11 27 65 01 ff 28 f5
<- 55 ab 22 43 00 42 56 78 3d 2f 3a c9 66 af e5 8c 45 97 92 91
<- ae dc c4 17 55 c6 7f fc 37 e4 86 d2 9c 39 3f 54 81 16 a0 5f
<- 5e c7 35 7b 15 18 1f b9 50 eb
<- 55 ab 06 44 00 81 27 05 d4 e9 e9 77 0b ad 22 e3 03 02 fe 61
<- ca f8
<- 55 ab 20 45 00 5e f5 4a f9 b1 8e fa 15 f3 d0 d5 a9 72 05 ab
<- e9 13 32 d8 a1 00 0c a8 9f 06 29 c9 b0 1b dc bd 96 b9 32 a5
<- 9e 60 a8 6f 19 90 19 ea
<- 55 ab 0c 46 00 8e fa 75 80 55 5f 2e 10 a2 fc c2 a2 e3 0a c5
<- 8d de 1c 42 69 44 14 f5
<- 55 ab 22 47 00 65 42 86 97 f4 86 bc 79 0f 98 2c a2 4f 9a c0
<- 34 78 65 87 7a d1 8e 93 69 98 09 39 27 bb a8 18 4c 0e 19 1c
<- fe ba e8 1b 4b 70 5e 84 35 ec
<- 55 ab 06 48 00 4b 63 08 e1 06 33 a3 00 56 03 cf 67 4e 09 5a
<- fe fa
<- 55 ab 20 49 00 b7 fb 16 ec 10 1e 91 f7 33 4c df 46 7f 9b 30
<- a0 a9 cf 9a 3a 6a e0 ac ea 6d c6 d4 12 1e e6 7d 01 99 30 50
<- 11 bc a0 2c dc b1 98 ea
<- 55 ab 0c 4a 00 a8 58 3f 3e 46 35 1e e8 13 c5 c4 1d 50 99 8a
<- cd f0 3e 4e 3b 16 e5 f6
<- 55 ab 22 4b 00 04 d7 94 7a 01 82 d8 94 c4 f9 0c 52 37 ad 72
<- 67 0b d1 e2 75 4b 84 40 56 16 1e cc 10 bf 15 4d cd 91 a4 b1
<- af 17 7b 72 ac cd 11 e4 45 eb
<- 55 ab 06 4c 00 5d 01 da fb cd 78 03 64 f0 98 cd 35 e1 e3 a1
<- df f6
<- 55 ab 20 4d 00 b8 48 b3 37 51 3d 4a 14 53 02 9b e8 19 fe 49
<- 1d 5b 62 cc 60 d7 46 ab 36 fb ac c7 d2 0b 53 f2 a8 0b 96 d9
<- 25 87 05 f5 97 f0 a1 eb
<- 55 ab 0c 4e 00 dd 95 d3 07 8b dd a7 af 70 fc 20 b5 8f 01 8d
<- a0 2f 0b d2 77 b2 68 f4
<- 55 ab 22 4f 00 08 b7 fb 70 dc a6 b0 ca c6 af 95 59 7e 4b e4
<- fb 9b db c6 fa 7b 31 5f 3b 81 36 1d d0 4e 61 98 5e 2c bf 1d
<- 8b da 20 c6 ce c9 62 a7 a5 e7
<- 55 ab 06 50 00 d1 63 3f 96 48 70 f4 09 fe b7 16 99 09 e4 0d
<- 8d f8
[...]
but again, if the answer is "just don't do that", then I'm fine with that as well.
@The-Compiler Yes, the answer is don't do that, but the program should tell you that, not me. Since BLE is sending an error code "e2 00 00 00" and I know that also "e0 00 00 00" exists, I'm now handling these and then raising an Exception.
@The-Compiler If there's nothing to add from your side and the latest commit works I would merge this PR. Just give me a go.
I was away today so I could only test now - as mentioned above I still see some weirdness, but it's definitely much more stable than before - so I'd say let's merge this, and I might get back to the remaining issues after I have a better understanding how the protocol works.
Thanks again for your patience and all the fixes, much appreciated! If there's a place I can donate a couple of Euros for beer/coffee/..., please let me know! If there's not, I suppose I could donate to Rollerplausch instead :slightly_smiling_face:
@The-Compiler You're welcome Florian, as soon as you said you wanted to use this project get stuff running with your smart watch I was all into it. It's very refreshing to work with someone who knows how to run Python, communicate technical matters and use the GitHub arsenal. Good luck with your project(s) and hope to hear from you soon ;) I've added a donation button back into the Readme, feel free to chip in - thanks ❤️
Solve #5 Needs testing