Protocol
Command reference·
Every JY ring command id with its request payload, reply shape and proof status.
In 10 seconds
52 command ids: 28 ✅ proven live, 6 📡 seen on the air, 16 📖 APK-only, 2 ⛔ never sent. cmd is the u16 at
offset 2 of the frame; ts6 = 6-byte local seconds (Time). Ids are decimal here,
(0x..) alongside where the audio pages use hex — sleep is 34, the memo stream is 0x34 = 52. The twelve below are
the ones a gateway actually uses; the full ledger is collapsed by group underneath.
The twelve that matter·
| cmd | does | request → reply |
|---|---|---|
| 1 | set time | ts6 + 00 → echo Y u16 M D h m s |
| 6 | battery | 00 00 → percent u8, charging u8 (also pushed on the cradle) |
| 37 | device info | — → fw u16, mac[6], mfr u16, model u16 (pushed on connect) |
| 55 | features | 00 00 → remote_recording, storage |
| 7 / 8 / 11 / 17 | live HR | open / close / tick ts6, hr u8 every ~5 s / session ended |
| 30 | auto-HR schedule | start_h, start_m, end_h, end_m, enable, interval_min → echo |
| 29 | steps snapshot | — → ts6, steps u32, kcal u16, distance u16 |
| 33 → 42 | step history | day → 16 B items … terminator with day 00:00 |
| 34 → 43 | sleep | day → 8 B items ts6, quality, motion (300 s buckets) … terminator |
| 36 → 45 | health records | day → 14 B items ts6, hr, spo2, temp_tenths i16, u32 … terminator |
| 61 · 64 · 52 · 54 (0x3D · 0x40 · 0x34 · 0x36) | voice memo | count → stop-transfer → Opus stream → echo remaining deletes (Audio) |
| 4 | find (vibrate) | mode u8 → echo 01 |
Never sent by this driver or by tiny: 39 deviceOperation (reboot / factory reset), 67 unbind, anything on SUOTA FEF5.
Status in the ledger: ✅ [LIVE] · 📡 [CAPTURE] · 📖 [APK] only · ⛔ never send.
Ledger · link, identity, time — 11 rows
| cmd | name (APK) | request payload | reply | status |
|---|---|---|---|---|
| 1 | setTime | ts6 + 00 |
echo: year u16, month, day, hour, min, sec |
✅ |
| 3 | getMTU | 00 00 |
— (MTU is negotiated at ATT level; 512) | 📖 |
| 26 (0x1A) | setAppInfo | 00 + app_id[12] |
echo | ✅ |
| 28 (0x1C) | setAppRunningInfo | u32 |
ack | 📖 |
| 37 (0x25) | getDeviceInfo | — (also pushed on connect) | firmware u16, mac[6], manufacturer u16, model u16 |
✅ |
| 55 (0x37) | queryDeviceFeature | 00 00 |
remote_recording, storage u8 each (APK also lists classic_bt, alarm_supported; both rings answer 2 bytes) |
✅ |
| 62 (0x3E) | sendAppHeartbeat | — | — · every 2 s while connected | ✅ |
| 66 (0x42) | (connect request) | — | android/ios_connect_request, classic_bt_address |
📖 |
| 68 (0x44) | (push) device name | — | len u8, ASCII — not in the APK parser |
✅ |
| 67 (0x43) | requestDeviceUnbind | — | unbind_result |
⛔ |
| 39 (0x27) | deviceOperation | u8: 0 reboot · 2 factory reset |
— | ⛔ |
Ledger · battery, find, settings — 9 rows
| cmd | name | request | reply | status |
|---|---|---|---|---|
| 6 | getBattery | 00 00 (also pushed) |
percent u8, charging u8 |
✅ |
| 4 | vibrateLED | mode u8 |
echo 01 |
✅ (buzz felt) |
| 2 | setUserInfo | u8×5 (sex, age, height, weight, ?) + u64 |
ack | 📖 |
| 12 (0x0C) | setSportTarget | steps u32 |
ack | 📖 |
| 13 (0x0D) | setAuxFunction | 13 flag bytes | ack | 📖 |
| 14 (0x0E) | setTimeFormat | u8 (0 = 24 h) |
ack | 📖 |
| 30 (0x1E) | setAutoHeartRateSetting | start_h, start_m, end_h, end_m, enable, interval_min |
echo | ✅ |
| 65 (0x41) | setAlarmList | 5 × enabled, hour, minute, repeat&0x7F = 20 B |
alarm_set_result |
📖 |
| 69 (0x45) | queryAlarmList | — | alarms[] 4 B each (both rings: empty) |
✅ |
Ledger · vitals, live — 10 rows
| cmd | name | request | reply | status |
|---|---|---|---|---|
| 7 | openHeartRate | — | ack; ticks follow as cmd 11 | ✅ |
| 8 | closeHeartRate | — | echo | ✅ |
| 11 (0x0B) | (stream) live HR | — | ts6, hr u8 every ~5 s |
✅ |
| 17 (0x11) | (push) HR session ended | — | empty | ✅ |
| 23 (0x17) | openCloseSpo2 | u8 |
toggles; then 24 | 📡 |
| 24 (0x18) | (stream) SpO₂ | — | ts6, spo2 u8 |
📡 |
| 25 (0x19) | (push) SpO₂ ended without value | — | empty (setBloodStatus(false)) |
📡 |
| 20 (0x14) | openCloseTemperature | u8 |
then 21 | 📖 |
| 21 (0x15) | (stream) temperature | — | ts6, raw i16 (/100 °C) |
📖 |
| 15 / 19 | BP · HRV · BP calibration | no parser branch → not supported on this ring | 📖 |
Ledger · activity, sleep, history — 12 rows
| cmd | name | request | reply | status |
|---|---|---|---|---|
| 29 (0x1D) | getStepInfo | — (also pushed) | ts6, steps u32, kcal u16, distance u16 |
✅ |
| 33 (0x21) | getStepCountInfo | day u8 (0 = today) |
items 16 B: ts6, duration u16, steps u32, kcal u16, distance u16; FF-filled = end |
✅ |
| 34 (0x22) | getSleepData | day u8 |
items 8 B: ts6, quality u8, motion u8 — 300 s buckets |
✅ |
| 36 (0x24) | getHealthRecord | day u8 |
items 14 B: ts6, hr u8, spo2 u8, temp_tenths i16, u32 unused |
✅ |
| 42 (0x2A) | (terminator) steps done | — | ts6 = day 00:00 |
✅ |
| 43 (0x2B) | (terminator) sleep done | — | ts6 |
✅ |
| 45 (0x2D) | (terminator) records done | — | ts6 |
✅ |
| 38 (0x26) | controlMultiSport | u8 |
38 | 📡 |
| 10 (0x0A) | pauseOrResumeSport | u8, 00 |
sport_id u8, paused u8 |
📡 |
| 27 (0x1B) | (stream) sport realtime | — | 26 B: start ts6, type, now ts6, duration u16, steps u32, kcal u16, dist u16, hr u8, temp i16, spo2 u8 | 📡 |
| 9 | getSportStatus | 00 00 |
? | 📖 |
| 40 (0x28) | (event) button | — | u8: 1 press · 2 → 0 release |
✅ |
Ledger · audio — 11 rows
| cmd | name | request | reply | status |
|---|---|---|---|---|
| 47 (0x2F) | queryAudioState | 00 00 |
state u8, ext u8 — 0x00 idle · 0x10 recording · 0x40 recording to flash |
✅ |
| 48 (0x30) | controlAudioMode | mode u8, 00 — 0 stop · 1 online record · 2 AI dialog |
action, final_state |
✅ |
| 49 (0x31) | pauseOrResumeAudio | u8, 00 |
📖 | |
| 50 / 51 (0x32/0x33) | (stream) live audio packets | — | u32 seq, u16 0, 12 × 40 B Opus |
📖 |
| 52 (0x34) | getOfflineAudioData / (stream) memo packets | — | same layout, total/index = packets |
✅ |
| 54 (0x36) | clearOfflineAudioData | remaining u16 (echo what the ring pushed) |
ring pushes 0x36 <remaining> after the last packet |
✅ |
| 61 (0x3D) | queryOfflineAudioFileCount | — | count u16 |
✅ |
| 63 (0x3F) | stopOfflineRecord | — | — | 📖 |
| 64 (0x40) | stopOfflineRecordTransfer | — | — · sent 1 s before 0x34 | ✅ |
| 41 (0x29) | sendPaste | 01 |
HID paste trigger for the translation flow | 📖 |