Th0rgal/open_oura

A Rust toolkit for the Oura Ring (Gen 3/4/5): reverse-engineered BLE protocol, event decoders, and reimplemented data-processing algorithms. Sync, store, and analyze your data locally.

538

stars

160

commits

Rust

primary language

Sep 7, 2026

updated

README

open_oura

Reverse-engineering the Oura ring BLE protocol, plus reusable Rust libraries and a small independent, cloud-free client that reads your data straight from the ring.

Tested 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.

What you can recover

Straight from the ring, with no Oura account: device info, battery, live heart rate (IBI to BPM), latest HR / SpO2, and the full history-event stream. That stream carries raw PPG/IBI/temperature/motion/SpO2 samples plus the ring's on-device sleep stages, activity MET levels, and HRV.

The ring itself does not emit the 0-100 Readiness / Sleep / Activity / Stress scores. But those are not computed in Oura's cloud either: they're computed on the phone by the native ecore engine and a set of on-device PyTorch models (the same .pt we run here), then uploaded; the cloud only stores and syncs them back. So they're reproducible offline. The one genuine cloud-only step is workout auto-classification (POST /api/activity-tagging/v2). See docs/data-recovery-map.md, docs/algorithms/README.md, and docs/model-runners.md for what runs.

Those PyTorch models are Oura's proprietary IP and are NOT included in this repo (gitignored under notes/models/). The runners reference them by path; you decrypt and supply your own locally. Nothing model-related is committed or pushed.

Repository map

  • crates/: the Rust client, split by concern (oura-protocol decode, oura-link fetch, oura-analysis metrics, oura-store SQLite, oura-cli). Start here: crates/README.md and docs/architecture.md.
  • tools/: Python research bench for protocol exploration. oura_protocol.py (full command matrix, auth, danger-gated ops, JSONL capture) and oura_realtime_listener.py.
  • docs/: protocol and reverse-engineering reference (index below).
  • reverse/, captures/: local-only, gitignored. The decompiled app and raw captures (which may contain serials, MACs, and auth keys).

App layer

The web dashboard, iOS app, DNA explorer, blood PDF import, and model-running product surface now live in open_health. This repository is the Oura protocol/library base that open_health consumes.

Quick start (Rust client)

cargo build --release
./target/release/oura scan
./target/release/oura --key-file key.hex info

See crates/README.md for all commands (scan, pair, factory-reset, info, sync, latest, live-hr, accel, features, rdata, events, redecode, sleep-analyze, subscribe, feature-mode, and feature-status) and the auth-key details. Destructive commands (factory-reset) require --yes.

Research bench (Python)

python3 -m venv .venv && .venv/bin/pip install -r requirements.txt
.venv/bin/python tools/oura_protocol.py --list

State-changing and destructive commands are hidden behind --include-state and --include-danger. On macOS, grant Bluetooth permission to the terminal.

Documentation

  • docs/horizon-ring3-protocol-cheatsheet.md: the protocol command reference (requests, responses, auth, features), Ring 3.
  • docs/android-app-reversing.md: app internals, BLE constants, the auth operations, key generation, and nonce encryption.
  • docs/data-recovery-map.md: what the ring emits vs what only the cloud computes.
  • docs/sync-orchestration.md: when and how the app pulls each data channel, and the minimal client sync recipe.
  • docs/ring-5-observations.md: Ring 5 BLE surface and first-contact findings.
  • docs/ring-features.md: the feature capabilities, runtime modes, what's on by default, and which event each enabled feature produces (incl. what experimental does — and doesn't).
  • docs/cva-cardiovascular-age.md: decoding the raw PPG (cva_raw_ppg_data 0x81) and running the cardiovascular-age model.
  • docs/spo2-calibration.md: turning the SpO2 R-ratio into a percentage with Oura's own calibration.
  • docs/firmware-update.md: 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/security-observations.md: findings-only notes on the model/firmware encryption (the "what", not the "how" — no keys, endpoints, or procedures).
  • docs/architecture.md: the fetch/interpret/apply crate layering and where to add things.
  • docs/algorithms/README.md: the on-device ecore metric algorithms (scores, sleep, baselines) and their porting status.
  • docs/factory-reset.md: the two verified ways to reset a ring — the 1a00 command and a button-free hardware procedure on the Gen3/Ring 4 dock — plus what a reset erases and how to re-pair without handing the ring back to the Oura app.
  • docs/native-decoder.md: porting event-body decoders from the native libringeventparser.so (how the byte layouts were recovered with Ghidra).

Safety and secrets

  • Prefer passive, read-only requests. reset / DFU / factory-reset / flight-mode are gated behind explicit flags; do not send them during normal use.
  • App-gated operations need the ring's 16-byte auth key (re-sent each connection). Captures and keys are gitignored. Never commit a key.

Prior art

ringverse Oura Ring 4 BLE notes: https://github.com/ringverse/protocol/blob/main/oura/BLE.md

Contributors

Th0rgal

157 commits

nsandoval

2 commits

liamhowell4

1 commits

Th0rgal/open_oura

A Rust toolkit for the Oura Ring (Gen 3/4/5): reverse-engineered BLE protocol, event decoders, and reimplemented data-processing algorithms. Sync, store, and analyze your data locally.

538

stars

160

commits

Rust

primary language

Sep 7, 2026

updated

README

open_oura

Reverse-engineering the Oura ring BLE protocol, plus reusable Rust libraries and a small independent, cloud-free client that reads your data straight from the ring.

Tested 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.

What you can recover

Straight from the ring, with no Oura account: device info, battery, live heart rate (IBI to BPM), latest HR / SpO2, and the full history-event stream. That stream carries raw PPG/IBI/temperature/motion/SpO2 samples plus the ring's on-device sleep stages, activity MET levels, and HRV.

The ring itself does not emit the 0-100 Readiness / Sleep / Activity / Stress scores. But those are not computed in Oura's cloud either: they're computed on the phone by the native ecore engine and a set of on-device PyTorch models (the same .pt we run here), then uploaded; the cloud only stores and syncs them back. So they're reproducible offline. The one genuine cloud-only step is workout auto-classification (POST /api/activity-tagging/v2). See docs/data-recovery-map.md, docs/algorithms/README.md, and docs/model-runners.md for what runs.

Those PyTorch models are Oura's proprietary IP and are NOT included in this repo (gitignored under notes/models/). The runners reference them by path; you decrypt and supply your own locally. Nothing model-related is committed or pushed.

Repository map

  • crates/: the Rust client, split by concern (oura-protocol decode, oura-link fetch, oura-analysis metrics, oura-store SQLite, oura-cli). Start here: crates/README.md and docs/architecture.md.
  • tools/: Python research bench for protocol exploration. oura_protocol.py (full command matrix, auth, danger-gated ops, JSONL capture) and oura_realtime_listener.py.
  • docs/: protocol and reverse-engineering reference (index below).
  • reverse/, captures/: local-only, gitignored. The decompiled app and raw captures (which may contain serials, MACs, and auth keys).

App layer

The web dashboard, iOS app, DNA explorer, blood PDF import, and model-running product surface now live in open_health. This repository is the Oura protocol/library base that open_health consumes.

Quick start (Rust client)

cargo build --release
./target/release/oura scan
./target/release/oura --key-file key.hex info

See crates/README.md for all commands (scan, pair, factory-reset, info, sync, latest, live-hr, accel, features, rdata, events, redecode, sleep-analyze, subscribe, feature-mode, and feature-status) and the auth-key details. Destructive commands (factory-reset) require --yes.

Research bench (Python)

python3 -m venv .venv && .venv/bin/pip install -r requirements.txt
.venv/bin/python tools/oura_protocol.py --list

State-changing and destructive commands are hidden behind --include-state and --include-danger. On macOS, grant Bluetooth permission to the terminal.

Documentation

  • docs/horizon-ring3-protocol-cheatsheet.md: the protocol command reference (requests, responses, auth, features), Ring 3.
  • docs/android-app-reversing.md: app internals, BLE constants, the auth operations, key generation, and nonce encryption.
  • docs/data-recovery-map.md: what the ring emits vs what only the cloud computes.
  • docs/sync-orchestration.md: when and how the app pulls each data channel, and the minimal client sync recipe.
  • docs/ring-5-observations.md: Ring 5 BLE surface and first-contact findings.
  • docs/ring-features.md: the feature capabilities, runtime modes, what's on by default, and which event each enabled feature produces (incl. what experimental does — and doesn't).
  • docs/cva-cardiovascular-age.md: decoding the raw PPG (cva_raw_ppg_data 0x81) and running the cardiovascular-age model.
  • docs/spo2-calibration.md: turning the SpO2 R-ratio into a percentage with Oura's own calibration.
  • docs/firmware-update.md: 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/security-observations.md: findings-only notes on the model/firmware encryption (the "what", not the "how" — no keys, endpoints, or procedures).
  • docs/architecture.md: the fetch/interpret/apply crate layering and where to add things.
  • docs/algorithms/README.md: the on-device ecore metric algorithms (scores, sleep, baselines) and their porting status.
  • docs/factory-reset.md: the two verified ways to reset a ring — the 1a00 command and a button-free hardware procedure on the Gen3/Ring 4 dock — plus what a reset erases and how to re-pair without handing the ring back to the Oura app.
  • docs/native-decoder.md: porting event-body decoders from the native libringeventparser.so (how the byte layouts were recovered with Ghidra).

Safety and secrets

  • Prefer passive, read-only requests. reset / DFU / factory-reset / flight-mode are gated behind explicit flags; do not send them during normal use.
  • App-gated operations need the ring's 16-byte auth key (re-sent each connection). Captures and keys are gitignored. Never commit a key.

Prior art

ringverse Oura Ring 4 BLE notes: https://github.com/ringverse/protocol/blob/main/oura/BLE.md

See what people are saying

Contributors

Th0rgal

157 commits

nsandoval

2 commits

liamhowell4

1 commits

Languages

Rust

56.7%

Python

42.6%