Skip to content

fix(ble): Apple one-shot buzz on WHOOP 5/MG no longer sends RUN_ALARM - #2797

Open
JohanStefanes wants to merge 1 commit into
ryanbr:mainfrom
JohanStefanes:johan/5mg-buzz-no-run-alarm
Open

JohanStefanes wants to merge 1 commit into
ryanbr:mainfrom
JohanStefanes:johan/5mg-buzz-no-run-alarm

Conversation

@JohanStefanes

Copy link
Copy Markdown

Summary

Refs #2796. On a WHOOP 5.0/MG, the Apple one-shot buzz (BLEManager.buzzStrapOnce, used by the Live "Buzz strap" button and the Buzz Strap App Intent) sent RUN_ALARM REVISION_2 [0x02, 0x01] after the maverick 0x13 buzz. Per docs/PROTOCOL_ALARMS.md, RUN [2, ID] runs the alarm stored in that slot and then clears it, so pressing the button could fire and remove an armed wake alarm in slot 1.

This PR drops that write on 5/MG. The one-shot is now the maverick buzz alone, which is hardware-confirmed on its own (#926) and is exactly what Android already sends (WhoopBleClient.buzzStrapOnce, pinned by FramingTest).

  • Removes one BLE write, adds none. No new command, no new payload.
  • WHOOP 4.0 unchanged: still 79 [2,3,0,0,0] + 68 [0x01].
  • testPuffinOneShotBuzzSequenceGoldens now pins only the buzz frame for 5/MG. The runAlarmRev2 encoder stays pinned in testPuffinAlarmFramesMatchKotlinParityGoldens.
  • Doc comments on BLEManager.buzzStrapOnce and AppModel.buzzStrapOnce updated.

Out of scope, possibly a separate decision: .runAlarm is still on the Apple 5/MG allowlist (Android excludes it). Nothing on Apple sends it on 5/MG after this change.

Verification

Hardware (iOS, iPhone 17 Pro, WHOOP 5/MG, Protocol probes on). Strap alarm armed two minutes ahead, then "Buzz strap" pressed while it was armed. Relevant strap-log lines, unedited:

[8:12:48 PM] Alarm: armed 5/MG rev4 for Do. 8:14 PM MESZ — your local wake time
[8:12:59 PM] → Run Haptics Pattern payload=012f98000000000000000002 (puffin cmd=0x13)
[8:12:59 PM] Buzz: one-shot fired (5/MG maverick buzz, acked)
Command response: RUN_HAPTIC_PATTERN_MAVERICK(19) → PENDING(2)
...
[8:14:01 PM] Alarm: strap-driven wake fired (event 57), re-arming the next day's instant
  • The buzz was felt as three short pulses (the normal notify buzz, not the long alarm waveform).
  • No cmd 68 frame was sent after the buzz.
  • The armed alarm still fired on the strap at its scheduled time (event 57), so slot 1 was not consumed.

Strap firmware version was not recorded. The before-fix behaviour (slot 1 consumed by the RUN) was not reproduced on hardware; the risk in #2796 comes from the documented RUN semantics.

Automated:

  • swift test in Packages/WhoopProtocol: 816 tests, 0 failures.
  • xcodebuild scheme Strand (macOS) and NOOPiOS (iOS Simulator): build succeeded.
  • Tools/doc_comment_lint.py: pass.

Android is unchanged (already sends only the buzz on 5/MG).

🤖 Generated with Claude Code

On a 5/MG, BLEManager.buzzStrapOnce sent RUN_ALARM REVISION_2 [0x02, 0x01]
after the maverick 0x13 buzz. Per docs/PROTOCOL_ALARMS.md, RUN [2, ID] runs
the alarm stored in that slot and then clears it, so pressing "Buzz strap"
(or running the Buzz Strap shortcut) could fire and remove an armed wake
alarm in slot 1. The maverick buzz is hardware-confirmed on its own (ryanbr#926),
and Android already stops there on a 5/MG.

This removes one write and adds none. The WHOOP 4.0 sequence (79 + 68 [0x01])
is unchanged. The golden test now pins only the buzz frame for 5/MG; the
runAlarmRev2 encoder stays pinned in the parity goldens.

Refs ryanbr#2796, Refs ryanbr#921, Refs ryanbr#926

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant