zyv / huawei-lpv2

A pure Python implementation of Huawei BLE Link Protocol v2
MIT License
46 stars 13 forks source link

feat: support Honor Band 4 Running Edition #8

Closed nabilbendafi closed 2 years ago

nabilbendafi commented 2 years ago

Thanks to information provided by @psolyca (psolyca/honor_band_4_re.md)

$> python ./band_lpv2.py 
/home/nabil.bendafi/huawei-lpv2/band_lpv2.py:131: FutureWarning: is_connected has been changed to a property. Calling it as an async method will be removed in a future version
  if not await self.client.is_connected():
INFO:__main__:Connected to band, current state: BandState.Connected
INFO:huawei.services.device_config:Negotiated link parameters:
        Protocol version: 2
        Max frame size: 512
        Max link size: 182
        Connection interval: 64
        Auth version : 3        Server nonce: BD 4C EC BB 97 33 23 14 25 0D 4A E1 1C 14 99 EA
INFO:huawei.services.device_config:Process authentication: 
        Check
INFO:huawei.services.device_config:Negotiated bond params:
        Bond status: 1
        Bond status info: 1
        BT version: 2
        Max frame size: 20
        Encryption counter: 6547
INFO:__main__:Handshake completed, current state: BandState.Ready
INFO:__main__:Command(tlvs=[TLV(tag=127, value=bytes.fromhex('00 01 86 A7'))])
INFO:__main__:Battery level: 60
INFO:__main__:Today totals: TodayTotals(calories=3, heart_rate=0, activities=[ActivityTotals(type=<MotionType.Walking: 1>, calories=3, steps=241, distance=145, height=None, time=None), ActivityTotals(type=<MotionType.Running: 2>, calories=0, steps=0, distance=0, height=None, time=None), ActivityTotals(type=<MotionType.ShallowSleep: 6>, calories=None, steps=None, distance=None, height=None, time=datetime.timedelta(seconds=4980)), ActivityTotals(type=<MotionType.DeepSleep: 7>, calories=None, steps=None, distance=None, height=None, time=datetime.timedelta(seconds=540))])
INFO:__main__:Stopped notifications, current state: BandState.Disconnected
psolyca commented 2 years ago

Thanks for this ^^

We are actually integrating Honor/Huawei devices to GadgetBridge and creating a Java library. Python code is not actively maintained but all GB code will be integrated later if possible in this.

nabilbendafi commented 2 years ago

I've been following https://github.com/Freeyourgadget/Gadgetbridge/issues/1021 for years... 😅 (while project was still hosted on Github). Your effort an involvement to bring Honor/Huawei support is really appreciate.

Even tough I own an Android device, my use of synchronizing my band is really limited. What I simply want at the end of the day: being able to synchronise date/time (daylight saving time) without having to install the Huawei vendor application (for which one need to create an account, and provide personal data), and this python library is totally doing the job :-) (and is written in Python ❤️ )


I use to own a Lenovo HW1 (for which I've initiated some code https://github.com/nabilbendafi/HW01), but my device died, that is also why I was happy that a Python library was available with all the work done behind reversing the communication protocol.

zyv commented 2 years ago

Hi @nabilbendafi!

Thank you very much for the PR!

Unfortunately, as @psolyca says, I don't have resources to adequately maintain this library and the documentation - so eventually, after Huawei changed the authentication scheme, this package stopped working, and I didn't have time to reverse further functions either. My problem with accepting external contributions instead, however, was code quality. It's was a nice research project for me, and I wanted the code to be of the quality which could directly serve as documentation for a reference implementation.

In the mean time, @psolyca and his team did an excellent job at reversing new authentication schemes and more functions. Their primarily motivation (unlike mine) was to make it usable with GB, but I have still thrown in the idea of making a library out of their stuff, so that in the end, we get also a stand-alone well-maintained core, that other people can use for their projects like you describe.

I'm still a fan of Python, and can more easily imagine getting this on OpenWRT instead of some Java stuff, but better have one open source and well-maintained library than nothing at all :-)

Having that said, I didn't closely look at your code, but it seems that what you did is very clean from the cursory look. I have just updated the packages and the CI for this project, and rebased your branch on top of it. I'll try to see if I can fix everything I want to fix and just merge your PR.

This way we will have maybe a very stripped down and primitive, but a working Python library for latest devices as an alternative to the Java library, which is great.

Cheers!

zyv commented 2 years ago

Hi @nabilbendafi and @psolyca - I think I'm done rewriting stuff, could you please test whether my changes still result in working code? If you don't understand why it was necessary to rewrite it this way - just ask any questions, I can try to take some time to explain. Otherwise, I can merge this after you confirm that this actually works for you :-)

psolyca commented 2 years ago

I will be off for 1 week. So I will have a look for the end of April.

nabilbendafi commented 2 years ago

@zyv Still looks good.

ERROR:bleak.backends.corebluetooth.scanner:macOS 12 requires non-empty service_uuids kwarg, otherwise no advertisement data will be received
INFO:__main__:Connected to band, current state: 1
INFO:huawei.services.device_config:Negotiated link parameters:
        Protocol version: 2
        Max frame size: 512
        Max link size: 182
        Connection interval: 64
        Auth version : 3
        Server nonce: BD 4C EC BB 97 33 23 14 25 0D 4A E1 1C 14 99 EA
INFO:huawei.services.device_config:Process authentication:
        Done!
INFO:huawei.services.device_config:Negotiated bond params:
        Bond status: 1
        Bond status info: 1
        BT version: 2
        Max frame size: 20
        Encryption counter: 6547
INFO:__main__:Handshake completed, current state: 11
INFO:__main__:Command(tlvs=[TLV(tag=127, value=bytes.fromhex('00 01 86 A7'))])
INFO:__main__:Battery level: 50
INFO:__main__:Today totals: TodayTotals(calories=3, heart_rate=None, activities=[ActivityTotals(type=<MotionType.Walking: 1>, calories=3, steps=320, distance=214, height=None, time=None), ActivityTotals(type=<MotionType.Running: 2>, calories=0, steps=0, distance=0, height=None, time=None), ActivityTotals(type=<MotionType.ShallowSleep: 6>, calories=None, steps=None, distance=None, height=None, time=datetime.timedelta(0)), ActivityTotals(type=<MotionType.DeepSleep: 7>, calories=None, steps=None, distance=None, height=None, time=datetime.timedelta(0))])
INFO:__main__:Stopped notifications, current state: 12

Was also able to change locale back and forth to zh-CN and en-US

Tested on macOS Monterey 12.3.1


https://github.com/zyv/huawei-lpv2/issues/7

However, a few days a kind soul has backported the newly reversed auth sequences from GB and submitted a PR: https://github.com/zyv/huawei-lpv2/pull/8. Please check whether this works for you, I have made my changes to it and intend to merge it to master as soon as someone has tested it.

I didn't done much that injecting new authentication keys, you desserve the whole credit.

nabilbendafi commented 2 years ago

For record: Band firmware is 1.1.5.5 (Model: AW70)

zyv commented 2 years ago

Thank you all very much! I hope one day I will get time to make this library great again :) basically, we need clean sliced packet parsing, backporting newly reversed functions, tests... and publishing to pypi?

psolyca commented 2 years ago

AW70 bands has less features than others but use the same basis. Some features are present on AW70 like workmode (wrist - foot) which are not present for other bands.