{"slug": "th0rgal-open-oura-a-rust-toolkit-for-the-oura-ring-gen-3-4-5", "title": "Th0rgal/open_oura: a Rust toolkit for the Oura Ring (Gen 3/4/5)", "summary": "A Rust toolkit for reverse-engineering the Oura Ring's BLE protocol enables cloud-free data access from Gen 3/4/5 rings, including live heart rate, SpO2, sleep stages, and activity MET levels, bypassing Oura's cloud dependency. The project reproduces on-device PyTorch models for scores like Readiness and Sleep, but excludes proprietary model files.", "body_md": "Reverse-engineering the Oura ring BLE protocol, plus an independent, **cloud-free**\nclient that reads your data straight from the ring.\n\nTested live against a Ring 3 Horizon and a Ring 5 (pairing, auth, and event sync confirmed on both). Designed for Ring 3/4/5, which share the same GATT layout, packet framing, and authentication flow.\n\nStraight from the ring, with no Oura account: device info, battery, live heart rate\n(IBI to BPM), latest HR / SpO2, and the full history-event stream. That stream\ncarries raw PPG/IBI/temperature/motion/SpO2 samples plus the ring's **on-device**\nsleep stages, activity MET levels, and HRV.\n\nThe ring itself does **not** emit the 0-100 Readiness / Sleep / Activity / Stress\nscores. But those are **not** computed in\nOura's cloud either: they're computed **on the phone** by the native `ecore`\n\nengine and a set of on-device PyTorch models (the same `.pt`\n\nwe run here), then\nuploaded; the cloud only stores and syncs them back. So they're reproducible\noffline. The one genuine cloud-only step is **workout auto-classification**\n(`POST /api/activity-tagging/v2`\n\n). See\n[ docs/data-recovery-map.md](/Th0rgal/open_oura/blob/main/docs/data-recovery-map.md),\n\n[, and](/Th0rgal/open_oura/blob/main/docs/algorithms/README.md)\n\n`docs/algorithms/README.md`\n\n[for what runs.](/Th0rgal/open_oura/blob/main/docs/model-runners.md)\n\n`docs/model-runners.md`\n\nThose PyTorch models are Oura's proprietary IP and are NOT included in this repo(gitignored under`notes/models/`\n\n). The runners reference them by path; you decrypt and supply your own locally. Nothing model-related is committed or pushed.\n\n: the Rust client, split by concern (`crates/`\n\n`oura-protocol`\n\ndecode,`oura-link`\n\nfetch,`oura-analysis`\n\nmetrics,`oura-store`\n\nSQLite,`oura-cli`\n\n). Start here:and`crates/README.md`\n\n.`docs/architecture.md`\n\n: Python research bench for protocol exploration.`tools/`\n\n`oura_protocol.py`\n\n(full command matrix, auth, danger-gated ops, JSONL capture) and`oura_realtime_listener.py`\n\n.: protocol and reverse-engineering reference (index below).`docs/`\n\n: local-only, gitignored. The decompiled app and raw captures (which may contain serials, MACs, and auth keys).`reverse/`\n\n,`captures/`\n\n```\ncargo build --release\n./target/release/oura scan\n./target/release/oura --key-file key.hex info\n```\n\nSee [ crates/README.md](/Th0rgal/open_oura/blob/main/crates/README.md) for all commands (\n\n`scan`\n\n, `pair`\n\n,\n`info`\n\n, `sync`\n\n, `latest`\n\n, `live-hr`\n\n, `accel`\n\n, `viz`\n\n, `game`\n\n, `features`\n\n, `rdata`\n\n,\n`events`\n\n, `redecode`\n\n, `sleep-analyze`\n\n, `sessions`\n\n) and the auth-key details. `oura viz`\n\nopens a\nreal-time 3D motion visualizer in the browser; `oura game`\n\nis a tilt-controlled\nasteroid game driven by the ring.\n\n```\npython3 -m venv .venv && .venv/bin/pip install -r requirements.txt\n.venv/bin/python tools/oura_protocol.py --list\n```\n\nState-changing and destructive commands are hidden behind `--include-state`\n\nand\n`--include-danger`\n\n. On macOS, grant Bluetooth permission to the terminal.\n\n: the protocol command reference (requests, responses, auth, features), Ring 3.`docs/horizon-ring3-protocol-cheatsheet.md`\n\n: app internals, BLE constants, the auth operations, key generation, and nonce encryption.`docs/android-app-reversing.md`\n\n: what the ring emits vs what only the cloud computes.`docs/data-recovery-map.md`\n\n: when and how the app pulls each data channel, and the minimal client sync recipe.`docs/sync-orchestration.md`\n\n: Ring 5 BLE surface and first-contact findings.`docs/ring-5-observations.md`\n\n: the feature capabilities, runtime modes, what's on by default, and which event each enabled feature produces (incl. what`docs/ring-features.md`\n\n`experimental`\n\ndoes — and doesn't).: running Oura's decrypted on-device models on your synced data — what runs (activity, sleep, CVA, SpO2) vs what's blocked.`docs/model-runners.md`\n\n: decoding the raw PPG (`docs/cva-cardiovascular-age.md`\n\n`cva_raw_ppg_data`\n\n0x81) and running the cardiovascular-age model.: turning the SpO2 R-ratio into a percentage with Oura's own calibration.`docs/spo2-calibration.md`\n\n: the DFU/OTA opcodes, the working cloud download pipeline + codename map, per-device encryption status, and why the firmware key is unreachable (device-resident; not brute-forceable).`docs/firmware-update.md`\n\n: findings-only notes on the model/firmware encryption (the \"what\", not the \"how\" — no keys, endpoints, or procedures).`docs/security-observations.md`\n\n: the fetch/interpret/apply crate layering and where to add things.`docs/architecture.md`\n\n: the on-device ecore metric algorithms (scores, sleep, baselines) and their porting status.`docs/algorithms/README.md`\n\n: porting event-body decoders from the native`docs/native-decoder.md`\n\n`libringeventparser.so`\n\n(how the byte layouts were recovered with Ghidra).\n\n- Prefer passive, read-only requests. reset / DFU / factory-reset / flight-mode are gated behind explicit flags; do not send them during normal use.\n- App-gated operations need the ring's 16-byte auth key (re-sent each connection). Captures and keys are gitignored. Never commit a key.\n\nringverse Oura Ring 4 BLE notes:\n[https://github.com/ringverse/protocol/blob/main/oura/BLE.md](https://github.com/ringverse/protocol/blob/main/oura/BLE.md)", "url": "https://wpnews.pro/news/th0rgal-open-oura-a-rust-toolkit-for-the-oura-ring-gen-3-4-5", "canonical_source": "https://github.com/Th0rgal/open_oura", "published_at": "2026-06-28 10:02:01+00:00", "updated_at": "2026-06-28 10:35:33.510441+00:00", "lang": "en", "topics": ["developer-tools", "machine-learning", "ai-research"], "entities": ["Oura", "Th0rgal", "PyTorch", "BLE", "SQLite", "Rust", "Python"], "alternates": {"html": "https://wpnews.pro/news/th0rgal-open-oura-a-rust-toolkit-for-the-oura-ring-gen-3-4-5", "markdown": "https://wpnews.pro/news/th0rgal-open-oura-a-rust-toolkit-for-the-oura-ring-gen-3-4-5.md", "text": "https://wpnews.pro/news/th0rgal-open-oura-a-rust-toolkit-for-the-oura-ring-gen-3-4-5.txt", "jsonld": "https://wpnews.pro/news/th0rgal-open-oura-a-rust-toolkit-for-the-oura-ring-gen-3-4-5.jsonld"}}