docs: add WHOOP 5.0 (Gen 5) BLE protocol reference - #1
Open
DropTabl wants to merge 2 commits into
Open
Conversation
WHOOP 5.0 is a different device family from the Gen 4 band this repo documents: different service UUID, CRC-16/Modbus instead of CRC-8, a different envelope, and a different record layout. A Gen 4 decoder pointed at a Gen 5 band produces CRC failures. Adds PROTOCOL-GEN5.md covering transport and framing, the command set and response-correlation rule, session bring-up, packet types and revisions, the 99-byte revision-18 1 Hz record, realtime type-40 HR, the historical sync contract and its count gate, and the persistent config/feature-flag exchange. Two findings worth calling out: - Gen 5 exposes beat-to-beat R-R intervals in milliseconds, which PROTOCOL.md lists as genuinely unknown for Gen 4. Documented with its motion gate and the decoder rules that gate implies -- a zero count is ambiguous and the series must never be bridged across records. - Revision-18 body 16 looks like a second heart rate and matches the published HR closely in small samples, but agreement ranges from 4% to 80% across ordinary captures of the same band. Documented as retain-raw, do-not-name, and explicitly not usable as a validity signal. Confidence is marked verified/empirical/unknown throughout, matching PROTOCOL.md. Validated against a single strap, which is stated in the document as a limitation. Also adds a Gen 4 scope note to PROTOCOL.md and README.md pointing at the new file, so nobody aims the wrong decoder at the wrong generation. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
Important
This repository does not receive automatic reviews because it has fewer than 10 stars. ⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Plus Run ID: Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Two fields in the revision-18 flag words look like data and are not. Both have been decoded the wrong way in a real Gen 5 decoder, so they are worth stating explicitly rather than leaving as "two signal-processing flag words". - Flags-B bit 0x80 is a diagnostic-format / special-state marker, not an HR-present, HR-valid, confidence, corroboration or walk-detected bit. Heart rate is routinely present and in range while it is clear. It has two producers and the record does not serialise which one fired. What drives it is marked unknown: neither documented producer condition reproduces cleanly against captured history. - Flags-B bits 16..31 are a frequency-derived pair in cycles per minute, not R-R intervals. Real R-R lives at body 2 and body 3..10 in milliseconds, so a reader meeting these without a warning has an obvious wrong guess available. Also documents flags-A's structure -- only the low half is flag-like, bits 29..30 are one 2-bit enum, and bits 16..27 plus bit 31 are a rotating telemetry stream -- so neither word gets flattened into 32 booleans. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
WHOOP 5.0 is a different device family from the Gen 4 band this repo documents — different service UUID, CRC-16/Modbus instead of CRC-8, a different frame envelope, and a different record layout. A Gen 4 decoder pointed at a Gen 5 band produces CRC failures, so the two need separate references.
Adds
PROTOCOL-GEN5.md, written to matchPROTOCOL.md's structure and its verified / empirical / unknown confidence markers.What it covers
BLE transport and framing, the command set and the response-correlation rule, session bring-up, packet types and revisions, the 99-byte revision-18 1 Hz record, realtime type-40 HR, revisions 20/21/26 in brief, the historical sync contract and its count gate, and the persistent device-config / feature-flag exchange.
Two findings worth calling out
Gen 5 exposes beat-to-beat R-R intervals in milliseconds. The README currently lists "anything resembling HRV or beat-to-beat timing" as genuinely unknown — that holds for Gen 4, but Gen 5 carries it in two places under one contract (type-40 offsets 9..17, and revision-18 body 2 and 3..10). §7 documents the production path and, more importantly, the motion gate: intervals are emitted only while a rolling 30-second filtered acceleration envelope stays below a threshold. That gate drives the decoder rules — a zero count is ambiguous (no new interval vs. suppressed by motion), and the series is sparse and must never be bridged across a zero-count record, a timestamp gap, or non-adjacent records.
Revision-18 body 16 is a trap. It looks like a second heart rate and tracks the published HR closely enough that small samples read as a duplicate. Over 1.29M records it only ever takes
0or values in30..210—1..29and211..255never occur — so it is definitely an HR-domain scalar and definitely not a bitfield. But how often it equals the published HR ranges from 4% to 80% across ordinary captures of the same band, depending on an internal branch the packet does not serialise. Documented as retain-raw, do-not-name, and explicitly not usable as a validity or trust signal.Footguns documented
"1"= enabled,"2"= disabled, and"0"= raw/unset. A band commonly sits at"2", so writing"0"to enable something turns it off. Raw zero is not restorable, which makes a blanket enable-then-restore sequence irreversible.Scope and limitations
50.40.1.0. Cross-device confirmation would be welcome.PROTOCOL.mdandREADME.mdpointing at the new file, so nobody aims the wrong decoder at the wrong generation. Happy to drop those two edits and keep the cross-reference here instead if you'd prefer the existing docs untouched.🤖 Generated with Claude Code