Repository navigation
Description
What happened?
Ring: RWfit-family ring on JieLi 0xAB framing (SR16). Its feature list reports sleep supported (body byte 87 = 1).
App: PulseLoop 2.11.1 on Android, Samsung.
What happens: the ring records sleep and shows it on its screen, but PulseLoop shows no sleep after syncing. Heart rate and SpO2 history do sync.
What the app does: RWfitSyncEngine.requestJieliHistory() sends {05,05,10} once per connection (RWfitSyncEngine.kt:86-92). No second page and no {05,05,30} is ever sent; the driver marks the 0x30 variants "unported" (RWfitDriver.kt ~153-186). RWfitJLHistory.decodeSleep (RWfitJLHistory.kt:195-290) runs on each reply with no saved state, and only emits a session when a 0x22 end follows a 0x11 start in the same payload. So a night split across pages or connections, or a night not yet closed, is dropped silently.
What the vendor SDK does: sleep is the only stream synced with GET_DEL_GET_DEL (DHBleSdk.java ~969: read a page, delete it with {05,05,30}, repeat until the reply is a bare 3-byte body), and the parser walks 7-byte records across the joined data (h.java O()). The WeChat SDK uses the same getDeleteGetDelete strategy for sleep. PulseLoopiOS PR #138 implemented exactly this (RWfitHistorySync.swift:136-180): a sleep page journal, the delete after each page, and decoding once at the end. Android hasn't ported it. The vendor connect sequence also sends session-create and timezone before syncing, which Android skips.
Real-world impact (SR16, night of Oct 25–26, 2026): PulseLoop received the first sleep page (2:11 to 5:57 AM, start marker 0x11, no end) on 7 consecutive connections (7:54 to 8:26 AM EDT) and discarded it every time, because decodeSleep requires 0x11 and 0x22 in the same reply. The end of the night is on the next page, which it never requests: it sends {05,05,10} once per connection and never {05,05,30}, so each new connection got the same page 1 again. A separate tool that read {05,05,10} repeatedly on one connection (no delete) got page 2 (6:02 to 7:46 AM), then the 0x22 end at 7:49 AM, then an empty reply. Joined, the night is 2:11 to 7:49 AM, 5 h 38 min (deep 59, light 211, REM 58, awake 10 min); PulseLoop shows no sleep for it. Example page-1 reply as PulseLoop received it: ab1100a46d89050510 32717334110000 ... (truncated). The full capture (all 7 connections) is available.
Suggested fix: port the iOS RWfit history flow for at least sleep: page until empty, keep a per-device journal of sleep pages, decode the joined pages, and delete only after the data is saved. Keep the other streams as they are or move them to GET_GET_DEL.
Captured bytes: request ab0100039d12050510. A sync on the evening before the night, with no sleep recorded yet, returned an empty sleep body ab1100039d12050510. I can attach a diagnostics export from a failed morning sync.
Steps to reproduce
- Sync the ring in the morning after sleep
- Sleep will continue to show no record.
Which ring are you using?
Other / not sure
iOS version
Android
iPhone model
Samsung S24
PulseLoop version / commit
DL from APK distribution page
Which area is affected?
Data sync / decoding
Logs / screenshots
Console conversation + my own debugging tool output showing full sleep conversation with the ringBefore submitting
- I searched existing issues and this isn't a duplicate.
- I removed any personal health data / secrets from logs and screenshots.
Activity
brantpeery commentedon Oct 28, 2026
I attached this here so iOS could take advantage of the full log as well. I know this is an Android issue, but I suspect is should be fixed in iOS first and pushed to Android.