From 1e88d595386f555eea1db6f00cd6831f533737f2 Mon Sep 17 00:00:00 2001 From: Arslaan Pathan Date: Sun, 29 Mar 2026 18:26:19 +1300 Subject: feat: sendMessageByZk --- FereFit_sendMessage_BLE.py | 44 +++++++++++++++++++++++++++++++++++++++ README.md | 51 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 95 insertions(+) create mode 100644 FereFit_sendMessage_BLE.py diff --git a/FereFit_sendMessage_BLE.py b/FereFit_sendMessage_BLE.py new file mode 100644 index 0000000..f180c07 --- /dev/null +++ b/FereFit_sendMessage_BLE.py @@ -0,0 +1,44 @@ +import asyncio +import sys +try: + from bleak import BleakScanner, BleakClient +except ModuleNotFoundError: + print("Error importing bleak, are you sure you installed it?") + print("Try running the following command: \"pip3 install bleak\"") + print("If that fails, try this: \"pip3 install bleak --break-system-packages\"") + sys.exit(1) + +WRITE_UUID = "6E40FC20-B5A3-F393-E0A9-E50E24DCCA9E" + +async def send_message(device_name: str, message: str, msg_type: int = 1): + print(f"Scanning for {device_name}...") + device = await BleakScanner.find_device_by_name(device_name, timeout=10) + if not device: + print("Watch not found!") + return + print(f"Found at {device.address}") + + encoded = message.encode('utf-8') + chunks = [encoded[i:i+17] for i in range(0, len(encoded), 17)] + + async with BleakClient(device) as client: + print("Enabling all message notification settings...") + settings = bytes([0x02, 0x02, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 3]) + await client.write_gatt_char(WRITE_UUID, settings) + await asyncio.sleep(1) + for i, chunk in enumerate(chunks): + packet = bytes([0x23, i, msg_type]) + chunk + if i == len(chunks) - 1: + packet = packet + bytes([0xFF]) + print(f"Sending chunk {i}: {packet.hex()}") + try: + await client.write_gatt_char(WRITE_UUID, packet) + print(f"Sent chunk {i}") + except Exception as e: + print(f"Failed to send chunk {i}: {e}") + await asyncio.sleep(5) + +if __name__ == "__main__": + watch_name = input("Enter watch name (default: Watch ULTRA): ") or "Watch ULTRA" + message = input("Enter message to send: ") + asyncio.run(send_message(watch_name, message)) diff --git a/README.md b/README.md index 931bc06..4a1a8f7 100644 --- a/README.md +++ b/README.md @@ -84,6 +84,57 @@ Heart rate possible responses: Other responses (blood oxygen, blood pressure, blood sugar) have not been tested yet. +### sendMessageByZk (push notification to watch) + +Must send `configDeviceSettings` first to enable notifications on the watch, otherwise messages will not display. + +Notification enable packet (write/6E40FC20) +``` +byte[0] = 0x02 (command) +byte[1] = 0x02 (subcommand) +byte[2] = skype enabled (0/1) +byte[3] = line enabled (0/1) +byte[4] = long time sit reminder interval +byte[5] = long time sit enabled (0/1) +byte[6] = call notice enabled (0/1) +byte[7] = SMS notice enabled (0/1) +byte[8] = WeChat enabled (0/1) +byte[9] = QQ enabled (0/1) +byte[10] = KakaoTalk enabled (0/1) +byte[11] = Facebook enabled (0/1) +byte[12] = Twitter enabled (0/1) +byte[13] = WhatsApp enabled (0/1) +byte[14] = LinkedIn enabled (0/1) +byte[15] = heart rate monitor (0/1) +byte[16] = hands up screen on (0/1) +byte[17] = heart rate loop monitor (0/1) +byte[18] = heart rate monitor interval time +byte[19] = Instagram enabled (0/1) +byte[20] = other push enabled (0/1) +byte[21] = Zalo (bit 0) + Messenger (bit 1) flags +``` + +Message packet structure (write/6E40FC20), one packet per 17 byte chunk: +``` +byte[0] = 0x23 (command) +byte[1] = chunk index (0, 1, 2...) +byte[2] = notification type + 0x01 = SMS + 0x02 = WeChat + 0x03 = QQ + 0x04 = DingTalk + 0x05 = WhatsApp + 0x06 = Facebook + 0x07 = Twitter + 0x08 = LinkedIn +byte[3-19] = up to 17 bytes of UTF-8 message text +byte[20] = 0xFF end marker (last chunk only, appended after text) +``` + +Message format: `"Title: Content"`, title truncated to 23 bytes, content to 240 bytes. + +Send chunks sequentially with ~100ms delay between each. + ### enterMakeDial (watch face) Watch face header packet (write/6E40FC20) -- cgit v1.2.3