SR116 · JY-Y3 · LoraFit rings — reverse engineered

A $30 AI ring, freed.

Heart rate, SpO₂, a microphone and a radio on your finger — and a vendor app in the way. The protocol byte for byte, a Python driver, tiny as the app.

Get started Protocol Read the frame ↓

The ring: a plain matte-black band with a small optical sensor window on the inside The ring in brushed silver: a plain band with a small optical sensor window on the inside
The ring seen edge-on: a plain band with a small plus-shaped touch pad on the outer face
  • HR3918 optical sensorinner face · HR, SpO₂, temperature
  • DA14xxx radio · mic · flashone GATT service
  • Touch padtap four times, talk

The inscription · ten bytes

Speak to it in ten bytes.

  1. FE FCmagic — 0xFCFE, little-endian
  2. 07 00cmd 7 — open heart rate
  3. 01 00total — 1
  4. 01 00index — 1
  5. 00 00len — no payload, no checksum

FE FC 0B 00 01 00 01 00 07 00 29 FA 65 69 00 00 5F 95 bpm — cmd 11, one tick per 5 s

Framing → All 52 command ids →

Every byte, decoded.

Fourteen captured frames; the needle reads them.

The loop · ring → phone → tiny

Tap four times. Talk.

1.95 s · 97 × 40 B Opus · synthetic voice

“what is the battery of my silver ring?”

tiny +28 s Your silver ring is at 99% battery Pulled over BLE, transcribed, answered by your agent — proven.

Audio protocol → Memos in tiny →

Live · Web Bluetooth

Have one? Talk to it.

56FFone GATT service · write 33F3 · notify 33F4
10 Bheader FE FC · cmd · total · index · len + payload
Opus16 kHz mono, 12 × 40 B frames per packet
0 keysno auth, no checksum — anyone in range

Three things it does.

$ pip install git+https://github.com/cagataycali/lord-the-ring
$ ring-cli scan --seconds 10
  E4:…:9A  SR116-088D  -61 dBm
$ export RING=E4:…:9A
$ ring-cli battery -a $RING
  {"battery_percent": 100, "charging": 0}
$ ring-cli hr --seconds 15 -a $RING
  [{"ts": 1758300000, "hr": 85}, {"ts": 1758300005, "hr": 86}]
$ ring-cli audio-state -a $RING
  {"state": 0, "files": 1}
$ ring-cli audio-pull -a $RING
  captures/memo.opus  captures/memo.wav  (6 min 05 s)

It works from a terminal.

Scan, battery, live heart rate, your memo as a WAV — no vendor app, no account. ring-cli bridge posts vitals every minute.

Getting started CLI reference

How the pieces fit.

flowchart LR
  R["`**💍 ring**
SR116 / JY-Y3
GATT 56FF`"] -- "BLE · notify 33F4" --> P["`**📱 phone gateway**
tiny iOS / Android
or ring-cli bridge`"]
  P -- "POST /api/health/ingest
vitals · memos (Opus)" --> W["`**☁️ worker**
health store · transcript
ring_commands queue`"]
  W -- "one-shot job" --> A["`**🤖 your agent**
health_* · ring_command`"]
  A -. "find · battery · measure_hr
record · memo_pull" .-> W
  W -. "claim loop" .-> P
  P -. "write 33F3" .-> R

BLE to the phone, HTTPS to your account, a job to your agent — commands return the same way. The tiny side →

→ 07                    open heart rate
← 0B  ts6 55            85 bpm
← 0B  ts6 56            86 bpm
← 11                    session ended

→ 3D  ← 3D 01 00        one memo waiting
→ 40 · 34               pull it
← 34 × 1522             6 min 05 s of Opus
← 36 01 00  → 36 01 00  delete it

Proven, not guessed.

Three sources had to agree — the decompiled app, an HCI capture, our own evidence/*.jsonl. When they disagreed, the bytes won.

How it was done tiny vs LoraFit, row by row