[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-82131":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":9,"htmlUrl":10,"language":11,"languages":9,"totalLinesOfCode":9,"stars":12,"forks":13,"watchers":14,"openIssues":15,"contributorsCount":9,"subscribersCount":16,"size":16,"stars1d":17,"stars7d":18,"stars30d":19,"stars90d":16,"forks30d":16,"starsTrendScore":20,"compositeScore":21,"rankGlobal":9,"rankLanguage":9,"license":9,"archived":22,"fork":22,"defaultBranch":23,"hasWiki":22,"hasPages":22,"topics":9,"createdAt":9,"pushedAt":9,"updatedAt":24,"readmeContent":25,"aiSummary":26,"trendingCount":16,"starSnapshotCount":16,"syncStatus":27,"lastSyncTime":28,"discoverSource":29},82131,"openwhoop","bWanShiTong\u002Fopenwhoop","bWanShiTong","CLI allowing you to use your Whoop4.0 without subscription and without data leaving your device",null,"https:\u002F\u002Fgithub.com\u002FbWanShiTong\u002Fopenwhoop","Rust",274,36,22,7,0,11,39,60,33,87.2,false,"main","2026-06-12 04:01:37","# OpenWhoop\n\nOpenWhoop is a project that allows you to download and analyze health data directly from your Whoop 4.0 device without a Whoop subscription or Whoop's servers, making the data your own.\n\nFeatures include sleep detection, exercise detection, stress calculation, HRV analysis, SpO2, skin temperature, and strain scoring - all computed locally from raw sensor data.\n\n## Getting Started\n\nFor local development, copy `.env.example` into `.env` and then scan for your Whoop device:\n```sh\ncp .env.example .env\ncargo run -r -- scan\n```\n\nAfter you find your device:\n\n- On Linux, copy its address to `.env` under `WHOOP`\n- On macOS, copy its name to `.env` under `WHOOP`\n\nThen download data from your Whoop:\n```sh\ncargo run -r -- download-history\n```\n\nUse `set-whoop \u003Cwhoop>` and `set-remote \u003Cremote>` to save defaults into `~\u002F.openwhoop\u002F.env`. Release builds and installed binaries read `.env` from `~\u002F.openwhoop\u002F.env`. If `DATABASE_URL` is unset there, the CLI uses `sqlite:\u002F\u002F$HOME\u002F.openwhoop\u002Fdb.sqlite?mode=rwc`.\n\n## Commands\n\n| Command | Description |\n|---------|-------------|\n| `scan` | Scan for available Whoop devices |\n| `set-whoop \u003Cwhoop>` | Save the default Whoop device to `~\u002F.openwhoop\u002F.env` |\n| `set-remote \u003Cremote>` | Save the default remote database URL to `~\u002F.openwhoop\u002F.env` |\n| `download-history` | Download historical data from the device |\n| `detect-events` | Detect sleep and exercise events from raw data |\n| `sleep-stats` | Print sleep statistics (all-time and last 7 days) |\n| `exercise-stats` | Print exercise statistics (all-time and last 7 days) |\n| `calculate-stress` | Calculate stress scores (Baevsky stress index) |\n| `set-alarm \u003Ctime>` | Set device alarm (see [Alarm Formats](#alarm-formats)) |\n| `stream-hr` | Stream realtime heart rate |\n| `stream-stress` | Stream realtime stress from the live HR feed |\n| `sync` | Sync data between local and remote databases |\n| `merge \u003Cdatabase_url>` | Copy packets from another database into the current one |\n| `rerun` | Reprocess stored packets (useful after adding new packet handlers) |\n| `enable-imu` | Enable IMU (accelerometer\u002Fgyroscope) data collection |\n| `download-firmware` | Download firmware from WHOOP API |\n| `version` | Get device firmware version |\n| `restart` | Restart device |\n| `erase` | Erase all history data from device |\n| `completions \u003Cshell>` | Generate shell completions (bash, zsh, fish) |\n\n`stream-stress` uses the same realtime HR notifications as `stream-hr` and starts scoring after a small initial buffer, becoming more stable as more samples arrive.\n\n### Alarm Formats\n\nThe `set-alarm` command accepts several time formats:\n\n- **Datetime**: `2025-01-15 07:00:00` or `2025-01-15T07:00:00`\n- **Time of day**: `07:00:00`\n- **Relative offsets**: `1min`, `5min`, `10min`, `15min`, `30min`, `hour`\n\n## Configuration\n\nConfiguration is done through environment variables or a `.env` file. Debug runs use a repo-local `.env`; release builds read `~\u002F.openwhoop\u002F.env`.\n\n| Variable | Description | Required |\n|----------|-------------|----------|\n| `DATABASE_URL` | Database connection string (SQLite or PostgreSQL). Optional in release builds, which default to `~\u002F.openwhoop\u002Fdb.sqlite`. | No |\n| `WHOOP` | Device identifier (MAC address on Linux, name on macOS) | For device commands |\n| `REMOTE` | Remote database URL for `sync` command. Can be written with `set-remote`. | For sync |\n| `BLE_INTERFACE` | BLE adapter to use, e.g. `\"hci1 (usb:Something)\"` (Linux only) | No |\n| `DEBUG_PACKETS` | Set to `true` to store raw packets in database | No |\n| `RUST_LOG` | Logging level (default: `info`) | No |\n| `WHOOP_EMAIL` | WHOOP account email for `download-firmware` | For firmware |\n| `WHOOP_PASSWORD` | WHOOP account password for `download-firmware` | For firmware |\n\n### Database URLs\n\nIf `DATABASE_URL` is unset in a release build, the CLI automatically uses `sqlite:\u002F\u002F~\u002F.openwhoop\u002Fdb.sqlite?mode=rwc`.\n\nSQLite:\n```\nDATABASE_URL=sqlite:\u002F\u002Fdb.sqlite?mode=rwc\n```\n\nPostgreSQL:\n```\nDATABASE_URL=postgresql:\u002F\u002Fuser:password@localhost:5432\u002Fopenwhoop\n```\n\n## Importing Data to Python\n\n```py\nimport pandas as pd\nimport os\n\n# Heart rate data\nQUERY = \"SELECT time, bpm FROM heart_rate\"\n\n# Other available tables:\n# \"SELECT * FROM sleep_cycles\"\n# \"SELECT * FROM activities\"\n\nPREFIX = \"sqlite:\u002F\u002F\u002F\"  # Use \"sqlite:\u002F\u002F\u002F..\u002F\" if working from notebooks\u002F\nDATABASE_URL = os.getenv(\"DATABASE_URL\").replace(\"sqlite:\u002F\u002F\", PREFIX)\ndf = pd.read_sql(QUERY, DATABASE_URL)\n```\n\n## Tauri BLEC Backend\n\nThe Rust library can use `tauri-plugin-blec` instead of a direct `btleplug::Peripheral` when built with the optional `tauri-blec` feature:\n\n```toml\nopenwhoop = { path = \"..\u002Fopenwhoop-v2\u002Fsrc\u002Fopenwhoop\", features = [\"tauri-blec\"] }\ntauri-plugin-blec = \"0.8.1\"\n```\n\nRegister `tauri_plugin_blec::init()` in your Tauri builder, then create an OpenWhoop device from the plugin handler:\n\nOn Linux, compiling this feature also requires the normal Tauri\u002FWebKitGTK development packages installed on the build machine.\n\n```rust\nuse std::{\n    sync::{Arc, atomic::AtomicBool},\n    time::Duration,\n};\n\nuse openwhoop::{\n    HistorySyncConfig, WhoopDeviceWith,\n    ble::tauri_blec::{TauriBlecTransport, scan_tauri_blec_devices},\n    db::DatabaseHandler,\n};\n\nasync fn sync_from_tauri_blec(db: DatabaseHandler) -> anyhow::Result\u003C()> {\n    let handler = tauri_plugin_blec::get_handler()?;\n    let devices = scan_tauri_blec_devices(handler, Duration::from_secs(5), false).await?;\n    let device = devices\n        .into_iter()\n        .next()\n        .ok_or_else(|| anyhow::anyhow!(\"no WHOOP device found\"))?;\n\n    let transport = TauriBlecTransport::new(handler, device.address, false);\n    let mut whoop = WhoopDeviceWith::from_transport(transport, db, false, device.generation);\n    whoop.connect().await?;\n    whoop.initialize().await?;\n    whoop\n        .sync_history(\n            Arc::new(AtomicBool::new(false)),\n            HistorySyncConfig::default(),\n        )\n        .await\n}\n```\n\n## Protocol\n\nFor the full reverse engineering writeup, see [Reverse Engineering Whoop 4.0 for fun and FREEDOM](https:\u002F\u002Fgithub.com\u002FbWanShiTong\u002Freverse-engineering-whoop-post).\n\n### BLE Service\n\nThe device communicates over a custom BLE service (`61080001-8d6d-82b8-614a-1c8cb0f8dcc6`) with the following characteristics:\n\n| UUID       | Name              | Direction    | Description |\n|------------|-------------------|--------------|-------------|\n| 0x61080002 | CMD_TO_STRAP      | Write        | Send commands to the device |\n| 0x61080003 | CMD_FROM_STRAP    | Notify       | Device command responses |\n| 0x61080004 | EVENTS_FROM_STRAP | Notify       | Event notifications |\n| 0x61080005 | DATA_FROM_STRAP   | Notify       | Sensor and history data |\n| 0x61080007 | MEMFAULT          | Notify       | Memory fault logs |\n\n### Packet Structure\n\nAll packets follow the same general structure:\n\n| Field | Size | Description |\n|-------|------|-------------|\n| SOF | 1 byte | Start of frame (`0xAA`) |\n| Length | 2 bytes | Payload length (little-endian) |\n| Header | 2 bytes | Packet type identifier |\n| Payload | variable | Command or data payload |\n| CRC-32 | 4 bytes | Checksum |\n\n### CRC\n\nPackets use a CRC-32 with custom parameters:\n- Polynomial: `0x4C11DB7`\n- Reflect input\u002Foutput: `true`\n- Initial value: `0x0`\n- XOR output: `0xF43F44AC`\n\n### Command Categories\n\nCommands sent to `CMD_TO_STRAP` use a category byte:\n\n| Category | Purpose |\n|----------|---------|\n| `0x03` | Start\u002Fend activity and recording |\n| `0x0e` | Enable\u002Fdisable broadcast heart rate |\n| `0x16` | Trigger data retrieval |\n| `0x19` | Erase device |\n| `0x1d` | Reboot device |\n| `0x23` | Sync\u002Fhistory requests |\n| `0x42` | Set alarm time |\n| `0x4c` | Get device name |\n\n### History Data\n\nEach historical reading (96 bytes) contains:\n\n| Field | Description |\n|-------|-------------|\n| Heart rate | BPM (beats per minute) |\n| RR intervals | Beat-to-beat timing in milliseconds |\n| Activity | Classification (active, sleep, inactive, awake) |\n| PPG green\u002Fred\u002FIR | Photoplethysmography sensor values |\n| SpO2 red\u002FIR | Blood oxygen sensor values |\n| Skin temperature | Thermistor ADC reading |\n| Accelerometer | 3-axis gravity vector |\n| Respiratory rate | Derived respiratory rate |\n\nThe remaining sensor fields in each packet (which the original blog post marked as unknown) have since been fully decoded and are used to compute SpO2, skin temperature, and stress metrics.\n\n## TODO\n\n- [x] Sleep detection and activity detection\n- [ ] SpO2 readings\n- [ ] Temperature readings\n- [x] Stress calculation (Baevsky stress index)\n- [x] HRV analysis (RMSSD)\n- [x] Strain scoring (Edwards TRIMP)\n- [x] Database sync between SQLite and PostgreSQL\n- [ ] Mobile\u002FDesktop app\n- [ ] Testout Whoop 5.0\n","OpenWhoop 是一个命令行工具，允许用户在没有 Whoop 订阅的情况下直接从 Whoop 4.0 设备下载和分析健康数据，确保数据不会离开用户的设备。项目利用 Rust 语言开发，具备睡眠检测、运动检测、压力计算、HRV 分析、SpO2 测量、皮肤温度监测以及应变评分等功能，所有这些功能都基于原始传感器数据在本地完成计算。适用于希望完全控制个人健康数据且不依赖于云端服务的 Whoop 用户，特别是在对隐私保护有较高要求的场景下使用。",2,"2026-06-11 04:07:48","trending"]