AmazFit
A Python toolchain that installs custom watchfaces on an Amazfit Band 7 directly from macOS, by reimplementing the vendor's proprietary Bluetooth protocol from scratch.
What It Does
I bought an AmazFit watch and was researching whether or not I could make a custom watchface for it cause I saw some custom ones in the offical Zepp store. Then Claude talked me into reverse-engineering the protocol and here we are.
How it works
The official Zepp app is the only sanctioned way to load a watchface, and its store is a bland catalog of ad-supported skins. I wanted to see whether a small pile of Python could replace it (build a face from a source directory, push it over BLE, done) without an Android device in the loop.
Almost none of the Huami 2021 protocol is documented publicly. The only working reference implementation lives inside Gadgetbridge's Android codebase, spread across a few dozen Java files. The port covers three layers: a K-163 elliptic-curve ECDH handshake, an AES-128-ECB chunked-framing transport, and the endpoint-and-command state machine on top. First end-to-end install landed 675 ms wall-clock from "go" to a watchface running on the wrist.
Built with
- BLE: Bleak on macOS. iPhone Bluetooth has to be off during scan/connect. iOS Zepp holds the BLE connection even when force-quit.
- Crypto: Hand-rolled K-163 curve (the pre-standard curve Huami picked), AES-128-ECB with a per-message key XORed against the frame handle.
- Transport: Huami's "chunked-2021" framing over GATT characteristic
0x0016, with per-endpoint encryption flags negotiated at connect time. - Install path: Legacy firmware chars
0x1531/0x1532on service0x1530. Not the newer chunked transport, which was the day's biggest surprise. - Build: ZMake compiles a source directory (
app.json,app.js, assets) into the.binthe watch expects.