Protocol
Framing·
The 10-byte JY frame header, multi-packet replies, echo acknowledgements and pacing rules.
In 10 seconds
Every message is one frame: FE FC · cmd u16 · total u16 · index u16 · len u16 · payload, little-endian, no
checksum. Queries get a reply with the same cmd; settings are acked by an echo; there is no NAK — silence
means "can't". Only audio really uses total/index. [APK: hy7.buildPacket] [LIVE]
FE FC 07 00 01 00 01 00 00 00
offset size field notes
0 2 magic 0xFCFE → bytes FE FC on the wire
2 2 cmd command id (decimal in the tables, hex in captures)
4 2 total packets in this logical message — requests: 1
6 2 index 1-based packet index — requests: 1
8 2 len payload length N
10 N payload
total comes before index — the 1522-packet audio stream proved it (total=1522, index=1…1522). The receiver
rejects a frame whose length is not 10 + len.
Four kinds of frame·
| kind | examples | reply |
|---|---|---|
| query | 6 29 37 55 47 61 |
same cmd + data payload |
| setting | 1 8 26 30 |
the request echoed back (set-time echoes the decoded Y u16 M D h m s) |
| stream | 11 HR tick · 40 button · 6 battery on cradle ~30 s · 62 |
unsolicited, nobody asks per frame |
| failure | HR off the finger | no op, no NAK — no ticks; the client times out |
Multi-packet replies·
| field | value |
|---|---|
history 33 34 36 |
a run of total=1, index=1 frames, each holding several fixed-size items, closed by a terminator 42 / 43 / 45 carrying the day's 00:00. Empty day = terminator alone. Today's sleep may come with no 43 → idle-close after 3 s |
audio 0x32 0x33 0x34 |
the true multi-packet case: total/index count the packets of one recording; every packet keeps its header, so the driver passes them through (PASSTHROUGH_CMDS) instead of gluing |
Pacing and keep-alive — write spacing, heartbeat, MTU, silence after disconnect
| rule | value | source |
|---|---|---|
| gap between writes | ≥ 300 ms (150 ms during audio transfer) | [APK] hy7 write queue |
| retries | a write that fails 3× is dropped | [APK] |
| heartbeat | cmd 62 (0x3E) every 2 s once features say storage=1 |
[APK] [CAPTURE] |
| MTU | ring requests 512; write payloads chunk to MTU−3 | [LIVE] |
| silence after disconnect | 8–40 s before the ring advertises again | [LIVE] |
Two history requests 300–500 ms apart once lost a terminator — wait for the reply, not the clock.
Worked example — set-time echo and a live HR tick
Set-time request and echo [LIVE], 2026-09-19 11:27:51 local:
FE FC 01 00 01 00 01 00 07 00 b7 7e ae 6a 00 00 00
FE FC 01 00 01 00 01 00 07 00 ea 07 09 13 0b 1b 33
Live HR tick [APK self-test vector]:
FE FC 0B 00 01 00 01 00 07 00 29 FA 65 69 00 00 5F