Skip to content

tiny

Takeover matrix — tiny replaces LoraFit·

Every LoraFit feature for the JY rings versus tiny — gateway, worker, agent — with status and proof.

  • anyone comparing tiny with LoraFit
  • 2 min read
  • 251 words

In 10 seconds

25 rows. Of the 20 LoraFit features: 13 ✅ done end to end, 2 🟡 (live mic stream, two-ring background restoration), 4 📄 documented on purpose (OTA, factory reset, HID paste, alarms — hardware says no), 1 ❌ skipped (multi-sport). The 5 ⭐ tiny-only rows are all ✅: memo → agent, agent → ring, fleet endpoint, staleness watchdog, health in the agent's context. Rings: silver SR116-088D (daily), black JY-Y3-011A (dev); both on the owner's iPhone, tiny iOS OTA 106.

At a glance·

status rows
✅ done, proven link · battery · live HR · auto-HR pref · SpO₂ · skin temp · records · steps · sleep + cradle rule · find · device name · voice memos · tap → hotkey · ⭐ memo → agent · ⭐ agent → ring (9 verbs) · ⭐ fleet endpoint · ⭐ staleness watchdog · ⭐ health brief
🟡 partial / proof pending on metal record live stream off the charger · two-ring background restoration · SpO₂ value on a finger · real tap codes · first real night of sleep · Android gateway on the Pixel
📄 documented only firmware OTA (SUOTA, never flash) · unbind / reboot / factory reset (never sent) · HID paste (41) · alarms (cmd 55 says unsupported on both rings)
❌ skipped multi-sport (38 / 10 / 27) — low priority, stream is decodable

Status marks: ✅ done · 🟡 partial · ❌ missing · 📄 documented only. Surfaces: G gateway (iOS/Android BLE), W worker + web, A agent. Every cmd id is decimal unless 0x. Protocol: Commands.

Full matrix — 25 rows
# Feature cmds LoraFit tiny G tiny W tiny A Gap / owner

| 1 | Link + time sync + app identity | 1, 26, 37, 55, 62 | ✓ | ✅ iOS/Android | ✅ device row fw/mac | ✅ health_devices | heartbeat 62 every 2 s only needed for audio | | 2 | Battery + charging | 6 (BAS lies) | ✓ | ✅ | ✅ charging/charging_ts | ✅ | debounce 5 min (H) | | 3 | Live HR | 7, 11, 17(end), 8 | ✓ | ✅ | ✅ series | ✅ | wear rule: 0 ticks in 30 s = off finger — 🟡 not surfaced | | 4 | Auto-HR schedule | 30 (0x1E) | ✓ 00:00–23:59 / 5 min | ✅ owner pref applied on link + on change (iOS, next OTA) | ✅ health_prefs.auto_hr_min (0045) rides on every claim reply | ✅ health_alert_rules {auto_hr_min: 0|5..60|null} | done 2026-09-19 18:30Z | | 5 | SpO₂ | 23 (0x17), 24 | ✓ | ✅ measure_spo2 (iOS ≥103, Android) | ✅ series | ✅ ring_command measure_spo2 | on-metal value pending (ring 0x19 = ended w/o value when off finger) | | 6 | Skin temperature | records 36 only | ✓ | ✅ via 36 | ✅ | ✅ | cradle 31 °C artefact tagged | | 7 | Health records (HR/SpO₂/temp history) | 36 → 45 | ✓ | ✅ | ✅ | ✅ | | | 8 | Steps / kcal / distance snapshot + history | 29, 33 → 42 | ✓ | ✅ | ✅ | ✅ | | | 9 | Sleep buckets + stages · wear rule | 34 → 43 · cmd 6 charging | ✓ (shows cradle readings as if worn) | ✅ cradle rule: day-0 sleep dropped while charging (iOS + Android) | ✅ summary excludes HR/SpO2/temp/HRV/stress/BP taken while THAT ring was on its charger (cradle_excluded, worker 5a418ca; live: 9 readings dropped 2026-09-19) | ✅ agent told cradle readings are excluded | first real night pending | | 10 | Alarms | 69, 65 | ✓ if supported | ❌ | ❌ | ❌ | cmd 55 reply is 2 B on both rings → alarm_supported absent ⇒ not supported by hardware; 📄 | | 11 | Find ring (vibrate) | 4 | ✗ (dead code) | ✅ button (local) + queue find (iOS ≥103, Android) | ✅ queue + web /health Find | ✅ ring_command find | on-metal proof pending (phone not yet on 103: rc_7e5f2ff8 stayed pending 17:56Z) | | 12 | Device name | 68 | shows | 🟡 decoded | ✅ | ✅ | labels silver/black (owner) | | 13 | Firmware + OTA (SUOTA 0xFEF5) | DIS/PnP, FEF5 | ✓ OTA | 📄 | 📄 | 📄 | never flash; document Dialog SUOTA only | | 14 | Unbind / reboot / factory reset | 67, 39 (0/2) | ✓ | ❌ | – | – | 39 never sent by tiny; 67 = 📄 | | 15 | Offline voice memo (4-tap) | 0x2F/0x28, 0x3D, 0x40, 0x34, 0x36 | ✓ list+upload | ✅ iOS build 104 memo_pull (RingAudio.swift, decode-identical to the Mac driver) · ✅ Android (RingAudio.kt, tinyai-id 29d7aa32, not yet installed on the Pixel) · Mac ✅ | ✅ /health/media + inbox | ✅ health_memos list/transcribe/delete | port memo pull to gateways, auto after 0x2F idle | | 16 | ⭐ Memo → transcript → agent action | – | ✗ | – | ✅ transcribed at ingest + one-shot agent job ring-memo-<sha> (health_prefs.memo_agent, default ON) | ✅ health_memos · health_alert_rules {memo_agent} | PROVEN prod 2026-09-19 17:45Z: spoken "what is the battery of my silver ring?" → push "Your silver ring is at 99% battery" in 28 s | | 17 | Realtime mic stream ("translation"/ChatAI) | 0x30 mode 1/2, 0x31, 0x32/0x33 | ✓ (phone does AI) | ✅ record {seconds} iOS OTA 106 recordLive + Android (same packet layout as memos: u32 ring-s · u16 0 · 12×40 B Opus; proven fallback: no stream on the charger → on-ring file → memo pull) | ✅ record in RING_COMMANDS, "record a 30 second voice note" routing, transcript sentence | ✅ ring_command record · web Record button | 🟡 stream path (0x32/0x33 off-charger) not yet seen on metal — owner: "record 10 seconds through my black ring" on 106 | | 18 | Multi-sport | 38, 10, 27, 0x1B | ✓ | ❌ | ❌ | ❌ | low priority; cmd 27 stream decodable | | 19 | Button events | 0x28 | (internal) | ✅ ingested as metric button (iOS/Android) | ✅ ring_button event + optional agent turn: health_prefs.button_prompt → one-shot job ring-button-<sha> (0044) | ✅ health_alert_rules {button_prompt} | PROVEN prod 2026-09-19 18:00Z: synthetic tap → "Your Black ring is at 100% battery, and you've taken 0 steps today." in ~30 s; real-tap code mapping (1|2) still to observe | | 20 | HID paste (translation flow) | 41 | ✓ | ❌ | – | – | 📄 skip (macOS bond side-effect) | | 21 | Background sync / reconnect / restoration | – | ✓ | 🟡 single ring; restoration array | – | – | multi-ring build 102 (lane H) | | 22 | ⭐ Agent reaches the ring | – | ✗ | ✅ iOS ≥103 claim loop (find/battery/status/hr/spo2/auto_hr/sync/memo_pull) · ✅ Android (same 8 verbs, 29d7aa32; on-metal proof pending — Pixel off USB) | ✅ ring_commands queue (0042, live) | ✅ ring_command tool | gateways must implement tiny/agent.md | | 23 | ⭐ Ring as fleet endpoint | – | ✗ | – | ✅ health-endpoint.ts: endpoint-kind device per ring, presence = last sync (15 min), worker hosts /ring/<hd>/api/{telemetry,chat} | ✅ use_device invoke "Silver ring" "battery" → ring command queue → sentence (prod-proven 18:50Z) | done | | 25 | ⭐ Staleness watchdog ("disconnected") | – | badge in app | – | ✅ health-watch.ts cron: ring silent > 3 h → one push + health_stale per outage, cleared by ingest | – | done 2026-09-19 18:36Z | | 24 | ⭐ Health hunk in agent context | – | ✗ | – | ✅ healthBrief | ✅ | done (lane H) |

What LoraFit actually does with a JY ring — the 28 builders it calls

Source of truth = the device class JiangYunRingDevice (apk/jadx/sources/defpackage/hr7.java). It calls exactly these 28 builders of BLEProtocolManager (hy7) — everything else in hy7 (vibrateLED, setUserInfo, setSportTarget, setTimeFormat, openCloseTemperature, setAuxFunction, BP/HRV, setAppRunningInfo, getMTU, getSportStatus) is dead code for this ring family:

setTime setAppInfo getDeviceInfo queryDeviceFeature sendAppHeartbeat getStepInfo getStepCountInfo getSleepData getHealthRecord openHeartRate closeHeartRate setAutoHeartRateSetting openCloseSpo queryAlarmList setAlarmList queryAudioState controlAudioMode pauseOrResumeAudio queryOfflineAudioFileCount getOfflineAudioData stopOfflineRecord stopOfflineRecordTransfer clearOfflineAudioData controlMultiSport pauseOrResumeSport sendPaste requestDeviceUnbind deviceOperation (+ BAS read, getVidPid via DIS 0x2A50).

LoraFit screens that touch the ring: Home (steps/kcal/distance, HR, SpO₂, sleep, temperature from records), Device card (battery, firmware, find = not offered for JY, unbind, factory reset/reboot), Auto-HR setting, Alarms (only when cmd 55 says alarm_supported), AI Recording (offline memos list + upload/transcribe), Real-time Translation / ChatAI (online mic stream, cmd 0x32/0x33, phone does the AI), Sport (multi-sport start/pause, cmd 38/10/27). No DND, no units, no wear-hand, no goals, no notifications-to-ring, no raise-to-wake exist on the JY path.

How the lane worked — priority order and bookkeeping (2026-09-19)
  1. Daily vitals & sleep gaps: SpO₂ on connect (5), wear rule surfaced (3), auto-HR setting write-through (4), cradle-aware sleep (9).
  2. Memos on the phone: gateway memo pull after the ring goes idle (15) → auto-transcribe + push text (16).
  3. Agent reach: ring_commands queue + ring_* tools (22, 11, 4/5 measure-now).
  4. Realtime mic → tiny voice (17). 5. Button → agent (19). 6. Fleet endpoint (23). 7. Docs-only rows (13, 14, 20, 10).

3. Lane bookkeeping

Lane dir ~/.tiny/ring-takeover-20260919/ (STATUS.md, JOURNAL.md, INBOX.md). Sibling lane H (~/tinyai-id-health, INBOX-H.md) owns iOS RingGateway.swift multi-ring build 102 — takeover lane works worker/web/agent + the memo/realtime port spec until H posts "BUILD 102 BOTH RINGS", then takes the gateway.

Design note, row 23 — superseded: shipped as health-endpoint.ts the same day

The fleet registry (devices, migration 0013) is token-bearing and kind ∈ daemon|browser|cli|endpoint; use_device invoke on an endpoint POSTs a prompt to the device's own URL. A ring has neither a token nor a URL — it is reachable only through the phone that holds the BLE link, and that phone already IS a fleet device. Proposal, deferred until the owner asks: - keep rings in health_devices (source of truth) and project them into /api/devices as kind:"ring" rows (id: hd_…, name: label, capabilities: ["find","battery","status","measure_hr","measure_spo2","set_auto_hr","sync","memo_pull"], last_seen: health_devices.last_seen, via: fleet_device_id) — read-only, no token, never revocable/rotatable; - use_device invoke on a ring row = ring_command (cmd + args parsed from the prompt by the caller's agent), result returned as the command's result; presence dot = last_seen < 15 min. Cost: worker devices.ts projection + web /devices + iOS/Android device lists render a fourth kind → touches the devices UI lanes, so it needs a charter of its own. Everything an agent needs today is already there via ring_command + health_devices.

Outcome: the projection design above is exactly what shipped — see Ring as endpoint.