Repository navigation
Description
NOOP version
12.0.0
Platform
macOS
OS version
26.5
WHOOP strap / Oura ring model
WHOOP 4.0
Where the data is coming from
Live Bluetooth (WHOOP strap connected)
Test Centre profile
Not a test-mode bug
What happens
- Strap unused since 2023, deep-discharged, no WHOOP membership
Bonding, live HR/RR, haptics (buzz) and broadcast-HR all work. Commands that carry a payload do not seem to reach the strap intact: right after every SET_CLOCK and SET_ALARM_TIME, the strap logs BLE SPI: GENERIC CMD CRC FAILURE 4, and neither setting is applied.
1. Clock is never set by NOOP → strap refuses to write flash
After the deep discharge the strap RTC was near epoch (~1971). NOOP sends SET_CLOCK on every connect, but the clock stayed invalid, and the strap logged this 100+ times:
→ Set Clock payload=cb27e16a00000000
→ Set Clock payload=cb27e16a0000000000
strap: Flash: RTC timestamp 31553056 is invalid; not saving data to flash.
strap: BLE SPI: GENERIC CMD CRC FAILURE 4
strap: BLE SPI: GENERIC CMD CRC FAILURE 4
strap: BLE SPI: GENERIC CMD CRC FAILURE 4
GET_CLOCK never answered either (Clock: GET_CLOCK unresponsive — derived rough correlation from Data Range …). Every history offload completed with 0 sensor rows (console-only / nothing-banked), and sleep detection reported grav=0 … reason=no-motion.
Workaround that worked: I connected the strap once to the official WHOOP app, which set the clock (Boot RTC: … 10-27-2026 22:51:23), then re-paired with NOOP. After that, "not saving data to flash" was gone and the first offload persisted data:
Backfill: session persisted 555 rows (107 with motion, 107 skin-temp) across 1 night(s).
The first full night was then detected and staged correctly.
2. Firmware alarm is not stored
→ Set Alarm Time payload=010c89e16a00000000
Alarm: armed for Wed 06:33 GMT+1 …
→ Get Alarm Time payload=01
Alarm: strap reports NO alarm currently stored (epoch 0) — the arm did not persist on the strap
strap: BLE SPI: GENERIC CMD CRC FAILURE 4
The alarm did not fire. This looks like the same signature as #34, but here the alarm and the clock fail in the same way.
3. Possibly related: GET_DATA_RANGE decoding
Strap backlog pages behind: not decodable from this frame (#689 — offsets may have moved). The "newest banked record" jumps between 2025, 2027 and 2029 within minutes, e.g.:
Get Data Range raw frame: aa1800ff2802227be101f8323c0256039203000000000101a8823ccc
Full strap log attached.
What you expected instead
SET_CLOCK and SET_ALARM_TIME should be applied on this firmware, so that a strap whose RTC has reset doesn't need the official app to start storing data again.
Steps to reproduce
- Let a WHOOP 4.0 (fw 41.13.2.0) fully discharge so its RTC resets.
- Pair with NOOP 12.0.0 on macOS and keep it connected.
- Observe the strap log: SET_CLOCK is followed by "GENERIC CMD CRC FAILURE",
the RTC stays invalid, and the strap logs "not saving data to flash". - Arm the firmware alarm: GET_ALARM_TIME reads back epoch 0 and the alarm never fires.
Strap log
[06:43:56] Backfill: auto-continuing (#364/#451) — the trim advanced and the strap is still handing over real records (frontier 1807781942, strap-reported newest 1793166114); re-kicking offload 2/24 without waiting the 15-min floor.[06:43:56] → Send Historical Data payload=00[06:43:56] Backfill: session started — historical offload requestedCommand response: SEND_HISTORICAL_DATA(22) → PENDING(2)[06:43:57] Backfill: reached the end of available history (trim=0xFFFFFFFF) - caught up; the strap handed over its banked history earlier this sync. Nothing more to offload.[06:43:57] → Historical Data Result payload=01ffffffffffffffff[06:43:58] Backfill: session ended — reason=HISTORY_COMPLETEBackfill: refreshing dashboard cache from completed syncre-score: trigger=post-offload newData=yessleep SKIPPED 19 day(s) — need ≥200 hrSamples: hrSamples=0 on 19 day(s): 2026-10-08, 2026-10-09, 2026-10-10, 2026-10-11, 2026-10-12, 2026-10-13, 2026-10-14, 2026-10-15, 2026-10-16, 2026-10-17, 2026-10-18, 2026-10-19, 2026-10-20, 2026-10-21, 2026-10-22, 2026-10-23, 2026-10-24, 2026-10-25, 2026-10-26analyzeRecent dayCache reused=0/2 size=2 days=21 missBy=absent:19,hr:2analyzeRecent cost prep=111ms score=85msanalyzeRecent windows hr[read=33966 served=9733 truncated=0 ownerFlips=0 reuseOff=0] rr[read=21910 served=2435 truncated=0 ownerFlips=0 reuseOff=0]rhr day=2026-10-28 floor=45 nightMean=51 inBedSamples=23778 (floor = WHOOP-style lowest-sustained = NOOP RHR; mean = sleeping-HR-app number)resp day=2026-10-28 rpm=14.1resp day=2026-10-27 rpm=nilsleep day=2026-10-28 totalSleepMin=382 stages=71+121+190=382 eff=0.96 matched=1 source=computedhrv day=2026-10-28 window=whole avgHrv=59.3hrv diag day=2026-10-28 rmssd=60ms sdnn=111ms meanNN=1189ms rr=19199/18992 rejected=1% coverage=0.96 collapsedCov=0.95 dupBeats=4 beatAccurate=0.75 rrIntegrity=plausibleeffort score day=2026-10-28 hr=24234 enough=true hrMax=183.0(provided) rhr=45.0 reserve=138.0 method=edwards trimp=0.0 strain=0.0 z0=403.9 z1=0.0 z2=0.0 z3=0.0 z4=0.0 z5=0.0effort calib day=2026-10-28 hrmax=183 src=override tanaka=185 peak=90 rhr=45 sustained=90 span=4workout detect day=2026-10-28 hr=24234 motion=24234 restHR=45 floor=60 motionOK=373 hrMissing=0 hrTooLow=160 active=213 runs=10 bridged=10 longestRunS=97 meanRunS=21 short=10 noHR=0 lowIntensity=0 kept=0sleep day=2026-10-27 totalSleepMin=nil stages=nil eff=nil matched=0 source=computedhrv day=2026-10-27 window=whole avgHrv=nilsleep-detect day=2026-10-27 NO-NIGHT hr=9733 rr=2435 resp=521 grav=521 skin=521 steps=0 provided=0 window=54h reason=staged-noneeffort score day=2026-10-27 hr=9732 enough=true hrMax=183.0(provided) rhr=60.0 reserve=123.0 method=edwards trimp=0.0 strain=0.0 z0=171.8 z1=0.0 z2=0.0 z3=0.0 z4=0.0 z5=0.0effort calib day=2026-10-27 hrmax=183 src=override tanaka=185 peak=107 rhr=60 sustained=107 span=5workout detect day=2026-10-27 hr=9732 motion=520 restHR=61 floor=76 motionOK=65 hrMissing=0 hrTooLow=64 active=1 runs=1 bridged=1 longestRunS=0 meanRunS=0 short=1 noHR=0 lowIntensity=0 kept=0analyzeRecent stepsMotion reused=59/60 size=60analyzeRecent storeProbes total=6ms dayOwner=81/2ms ownerHr=0/0ms gravityFp=60/4msDedup(#899): swept 2 device id(s), removed 0 overlapping duplicate session(s).analyzeRecent postLoop total=146ms dayReplay=2ms baselines=1ms score2=17ms watchFold=0ms persist=1ms weekly=0ms steps=23ms sleepWrite=95ms sleepHeal=1ms workouts=6ms tail=0msre-score: done — scored 2 night(s) in 565 ms (#1005)
Before you submit
- I attached my exported NOOP .zip (not a screenshot of the Live screen). If my bug is a clearly reproducible UI issue I described exactly how to see it instead.
- I attached or pasted a strap log above — or my bug is a clearly reproducible UI issue that doesn't need one (e.g. a typo, a button that does nothing) and I've described exactly how to see it.
- I checked the Troubleshooting guide — especially "history syncs but no data" (most often the strap isn't banking history to flash; charge it to 100% and reconnect).
- I checked the FAQ and — if I'm on a WHOOP 5.0 / MG — the 5.0/MG status page, or — if I'm on an Oura ring — the Oura ring support table, and this isn't an already-known limit (e.g. SpO₂, recovery/sleep on the 5/MG, or no Recovery / HRV on a ring-only day).
- I've left out anything personal (strap serial, account email, raw export).
Activity
BSchneppe commentedon Nov 9, 2026
Same failure on Android, with a strap sold new in box and never paired with the official app. I captured the official app's first connect over HCI. After that connect the clock latched, and NOOP's next sync persisted data.
Setup
Before, with NOOP only
Offload: no history rows ever persistedandmotion NO. Every night loggedreason=no-motion-no-hypnogram grav=0.SET_CLOCK(8-byte and 9-byte forms) andGET_CLOCKon every connect. The export has noGET_CLOCK(11) replyline.GET_DATA_RANGEvaried between 2025-03, 2025-05 and 2030-01, withHeal #547purges andclock future-datedskips.banked nothing … newest stored record is about 543–613 day(s) old. My guess is that these records are factory test data.bandBpm, and a shorter run fell underminSleepMin=60.Strap console in the HCI capture (these lines don't appear in the NOOP export):
31688684 seconds puts the RTC in 1971, as in the original report.
The official app's first connect, decoded from writes to the command characteristic:
The official app's handshake differs from NOOP's in two places:
[secs u32 LE][0x00000439 u32 LE][00], so the second field is 1081. I don't know what that field encodes. NOOP sends[secs][00 00 00 00]and[secs][00 00 00 00 00].GET_HELLO_HARVARD, waits for the reply, and then sendsSET_CLOCK. NOOP sends hello, set-clock, get-clock, stop-raw and get-range in one burst, and the export showsERROR_GATT_WRITE_REQUEST_BUSYretries during it.One capture can't show which difference matters.
After re-pairing with NOOP, with no other changes
NOOP's
GET_CLOCKnow gets replies, and the offload persists rows.Suggestions
GET_CLOCKnever replies and the data range is far in the past or the future, the export could say that the strap clock never latched and flash recording is off. Today it only says the strap "stopped saving history to its flash".