Read-only BLE research client for smart ring protocol analysis.
A clean-room tool for capturing and logging BLE traffic from a smart ring (currently targeting the R21M form factor) for security and privacy research. All data is stored locally in SQLite. Nothing leaves the laptop.
- No cloud sync, no telemetry, no crash reporting to any remote service
- No writes to the ring (no OTA, no DFU, no config, no time sync)
- No use of any code, assets, or proprietary protocol details from any vendor application
- No handling of credentials of any kind
This project is a clean-room implementation derived from public Bluetooth specifications (Bluetooth SIG GATT profiles) and observed device behaviour. It does not incorporate code, assets, or proprietary protocol details from any vendor application.
The R21M ring ships with different chipsets depending on hardware revision. ringclient detects the chipset on connect and dispatches to the appropriate listener:
| Chipset | Detection | Status |
|---|---|---|
| Nordic Semiconductor nRF52 | Nordic UART Service UUID 6e400001-... |
Implemented |
| Realtek RTL8762 | Realtek UART UUID 0000d0ff-3c17-... |
Implemented |
| Jieli (JieLi 杰理) | TBD from live capture | Stub only |
Requires Python 3.12+ and uv.
git clone https://github.com/johnohhh1/ringclient
cd ringclient
uv sync
ringclient db-initLinux requires BlueZ >= 5.43 and D-Bus access:
sudo apt install bluez
# If permission errors on scan:
sudo setcap 'cap_net_raw,cap_net_admin+eip' $(which python3)
# Or run with: sudo -E uv run ringclient scan# Scan for nearby rings (15 seconds, broad filter)
ringclient scan --name "R21M|Smart|Ring" --seconds 15
# Enumerate all GATT services for a device
ringclient enumerate AA:BB:CC:DD:EE:FF
# Connect and log all BLE traffic for 5 minutes
ringclient monitor AA:BB:CC:DD:EE:FF --minutes 5
# Export a session
ringclient dump-session 1 --format json
ringclient dump-session 1 --format csvPacket decoding (ringclient/decode/packets.py) is empirical and intentionally sparse. All raw bytes are logged regardless of decode status. Opcode handlers are added as packets are observed and understood from captured traffic.
Current decode table: empty -- contributing observed opcodes via the @register(opcode) pattern is the next step after initial capture.
- data/ringclient.db -- SQLite database (gitignored)
- logs/*.jsonl -- structured JSON log per session (gitignored; can contain health readings)
- logs/gatt__.json -- GATT enumeration dumps (gitignored)
Listen-only research client. Protocol decode is empirical and incomplete.
Pull requests are welcome, especially:
- Opcode decoders for observed packets, using the
@register(opcode)pattern inringclient/decode/packets.py, with a test intests/test_decode.py - Jieli chipset detection and listener
- Captures from other ring hardware revisions (strip MACs and health data first)
Run the checks before opening a PR:
uv run pytest
uv run ruff check .Please keep the tool listen-only: no writes to the ring.
MIT. See LICENSE.