Skip to content

Latest commit

 

History

History
58 lines (45 loc) · 3.26 KB

File metadata and controls

58 lines (45 loc) · 3.26 KB

WS contract — daemon ↔ glasses client (v1)

Source of truth: daemon/src/eventermidex/protocol.py. The glasses client mirrors these shapes but shares no code (CODEMAP invariant #1). One JSON object per ws text message.

Server → client

Type Shape Notes
hello {"type":"hello","v":1} Sent once on connect, before the first frame; the only message carrying the version
frame {"type":"frame","lines":["…"]} Full HUD frame replacement; client redraws the whole container
frame (list) {"type":"frame","lines":["…"],"list":{"items":["…"],"selected":0}} Additive (Phase 4 scroll fix): on menu/picker screens the daemon also sends the raw items + selected index. List-capable clients render a native OS list (the OS moves a selection border — no page-scroll animation) with lines[0] as the title; older clients ignore list and render lines
mic {"type":"mic","open":true|false} Client opens/closes the glasses mic (audioControl); on open failure it sends back a voice error
exit {"type":"exit"} Client shuts down its page container and closes the ws without reconnecting. Currently unsent — the "exit app" menu entry was dropped (Even's hold-to-exit covers it); the shape stays in the contract

On connect the daemon sends hello, then immediately the current frame.

Client → server

Type Shape Notes
gesture {"type":"gesture","name":"tap"|"double-tap"|"scroll-up"|"scroll-down"} The four gestures the G2 client emits
gesture (list) {"type":"gesture","name":"…","item":3} Additive: on a native-list screen the OS reports which index its selection border landed on; the daemon adopts it as the highlight truth (scroll = sync only; tap executes that item). Must be an int if present
voice {"type":"voice","chunk":"<base64 PCM>"} One mic PCM chunk (assumed 16 kHz 16-bit mono); daemon accumulates while recording, ignores otherwise
voice {"type":"voice","error":"mic-open-failed"} Mic could not be opened; daemon aborts the dictation
command {"type":"command","name":"…"} Reserved — parsed and logged only until Phase 4

Anything else raises ProtocolError on the daemon and is logged, never fatal.

Evolution

  • The version lives only in hello. Frames are the hot path over a bandwidth/MTU-bound BLE link and stay lean — no per-message v.
  • Receivers must silently ignore message types they don't recognize. This makes new message types additive: the deployed spike client (which ignores non-frame messages) keeps working unchanged.
  • Additive fields/types do not bump v; breaking changes to existing shapes do.

Example transcript

S: {"type":"hello","v":1}
S: {"type":"frame","lines":["evenTermidex","…"]}
C: {"type":"gesture","name":"tap"}
S: {"type":"frame","lines":["…updated…"]}

Dictation (menu → "dictate prompt"):

S: {"type":"mic","open":true}
C: {"type":"voice","chunk":"AAAA…"}      (repeated while speaking)
C: {"type":"gesture","name":"tap"}       (wearer taps: done)
S: {"type":"mic","open":false}
S: {"type":"frame","lines":["send this prompt?","…transcript…"]}
C: {"type":"gesture","name":"tap"}       (send)  — or double-tap (discard)