# zwzn-freefit-re Reverse-engineering a sketchy Chinese watch app Documentation/protocols derived from decompiled FereFit Android app (jadx) (com.czw.freefit, SHENZHEN ZHONGWEI INTELLIGENT TECHNOLOGY Co.,Ltd) ## Disclaimer I request that none of this code and/or documentation, in part or in full, be hosted on GitHub, SourceForge, or any other proprietary platform. This request is made out of respect for both me, the developer, and you, the user. ## What this is and why it exists This is a git repo containing protocol documentation of the `freefit` watch app, commonly known as "FereFit", "Lyne_Wearables", "HomieFit", "zwsvibe", and "WIRCASS". It allows us to make our own app implementations for some watches that use these apps. In particular, my testing occurs with the "Watch ULTRA", which I cannot find any more brand information on, though it's a sort of no-name Apple Watch ULTRA knockoff. Although, this protocol should work fine for most other watches that use these apps. This exists for many reasons, though here are the top few: - I'm 13 and have too much free time - I wanted to get into reverse-engineering - I had an old knockoff "Watch ULTRA" from the arcade, and the original app was spyware - The RTC on this watch drifts badly, so without an app to periodically synchronize it, it becomes almost unusable Anyway, talk is cheap, let's get into the documentation! ## BLE characteristics ### Main characteristics (presumably Nordic UART/Nordic semiconductor chips) - Service UUID: 6E40FC00-B5A3-F393-E0A9-E50E24DCCA9E - Write characteristic UUID: 6E40FC20-B5A3-F393-E0A9-E50E24DCCA9E - Notify characteristic UUID: 6E40FC21-B5A3-F393-E0A9-E50E24DCCA9E ### Jieli/JL chip characteristics (untested) - Service UUID: 0000ae00-0000-1000-8000-00805f9b34fb - Write characteristic UUID: 0000ae01-0000-1000-8000-00805f9b34fb - Notify characteristic UUID: 0000ae02-0000-1000-8000-00805f9b34fb ## Protocols/functions ### Battery status/notification (read/6E40FC21) Sent by watch if command is invalid. TODO find proper trigger for this ``` byte[0] = 0x94 (BATTERY command/response) byte[1] = battery percentage (0-100) ``` ### syncTime Time sync packet structure (write/6E40FC20) ``` byte[0] = 0x01 (command) byte[1-4] = Unix timestamp (big endian, seconds) byte[5-8] = timezone offset (big endian, seconds) byte[9] = i (unknown param, use 0x00) byte[10] = language code byte[11] = 0x01 if traditional Chinese, else 0x00 ``` Response: 0x81 0x00 (success, notify/6E40FC21) ### switchFindBand (vibrate/find watch) Find band packet structure (write/6E40FC20) ``` byte[0] = 0x51 (command) byte[1] = 0x01 to start vibrating, else 0x00 ``` Response: 0xD1 0x01 for vibrating, else 0xD1 0x00 (6E40FC21) ### enterMakeDial (watch face) Watch face header packet (write/6E40FC20) ``` byte[0] = 0xE4 (ZK_DIAL command) byte[1] = 0x51 (mode flag) byte[2] = 0x01 (start) byte[3] = 0x00 byte[4-5] = total packet count (big endian) byte[6-9] = total image bytes (big endian) byte[10] = 0x00 byte[11-12] = MTU size (big endian) byte[13] = rotation flag byte[14] = 0x01 byte[15] = time text direction byte[16] = 0x00 byte[17-18] = transparent color (RGB565) byte[19-20] = checksum (sum of all image bytes, big endian) byte[21] = show date (0x01 = yes, 0x00 = no) ``` Header packet is followed by chunked RGB565 data, 1 chunk = MTU-14 bytes