PebbleKit transport layer and message codec #16

Open
opened 2026-08-31 17:14:39 +02:00 by robert · 0 comments
robert commented 2026-08-31 17:14:39 +02:00 (Migrated from git.butzei.de)

Goal

One place that owns talking to the watch.

Acceptance criteria

  • PebbleDataReceiver registered for the watchapp UUID
  • Outbound messages encoded from typed model objects using the generated key constants
  • PebbleKit.sendAckToPebble() sent for every inbound message
  • Send queue coalesces updates so a slow link cannot build an unbounded backlog
  • Connection state surfaced to the UI and to the ride service
  • Reconnect handled without losing ride state

Files

  • companion/.../pebble/PebbleTransport.kt
  • companion/.../pebble/Proto.kt

Notes

Priority under backpressure: navigation messages must never be dropped in favour of map frames.

  • Transport implements the update-rate and coalescing policy in docs/PROTOCOL.md section 4:
    changed keys only, full refresh every 10 s and on reconnect
  • Map frames dropped first under backpressure; navigation frames never dropped
  • Map frames suppressed entirely when the watch reports a PAGE_INDEX that is not the map
  • HR_SAMPLES batches decoded and handed to the recorder, backlog first (#66)
  • Steady-state throughput measured against the ~1.5 KB/s budget in PROTOCOL.md section 4

Which PebbleKit path this is built on depends on #4 — see D36, and do not assume the 2016 artifact
until that spike reports.

Update — 2026-09-02: PebbleKit 2, the handshake, and the command queue

  • Target PebbleKit Android 2 (bound services) as the primary, per #4's recommendation; the
    classic 4.0.1 intent path is the fallback (D37)
  • Whichever is used, the transport must not be reachable by other apps on the phone (NFR-S8, now
    general rather than fallback-only)
  • Send SCREEN_W / SCREEN_H / SCREEN_SHAPE in the handshake — the phone sizes map slices from
    them and cannot guess (D46, NFR-C12)
  • Drain the watch's command queue before pushing RIDE_STATE, and acknowledge with
    STATE_ACK (D43)
  • Emit a heartbeat per group at the intervals in PROTOCOL §4, even when no key in the group
    changed — the watch's staleness rule depends on it (D44)
## Goal One place that owns talking to the watch. ## Acceptance criteria - [ ] `PebbleDataReceiver` registered for the watchapp UUID - [ ] Outbound messages encoded from typed model objects using the generated key constants - [ ] `PebbleKit.sendAckToPebble()` sent for every inbound message - [ ] Send queue coalesces updates so a slow link cannot build an unbounded backlog - [ ] Connection state surfaced to the UI and to the ride service - [ ] Reconnect handled without losing ride state ## Files - `companion/.../pebble/PebbleTransport.kt` - `companion/.../pebble/Proto.kt` ## Notes Priority under backpressure: navigation messages must never be dropped in favour of map frames. ## Update — 2026-09-01: rates and the uplink are part of this - [ ] Transport implements the **update-rate and coalescing policy** in docs/PROTOCOL.md section 4: changed keys only, full refresh every 10 s and on reconnect - [ ] Map frames dropped first under backpressure; **navigation frames never dropped** - [ ] Map frames suppressed entirely when the watch reports a `PAGE_INDEX` that is not the map - [ ] `HR_SAMPLES` batches decoded and handed to the recorder, backlog first (#66) - [ ] Steady-state throughput measured against the ~1.5 KB/s budget in PROTOCOL.md section 4 Which PebbleKit path this is built on depends on #4 — see D36, and do not assume the 2016 artifact until that spike reports. ## Update — 2026-09-02: PebbleKit 2, the handshake, and the command queue - [ ] Target **PebbleKit Android 2** (bound services) as the primary, per #4's recommendation; the classic 4.0.1 intent path is the fallback (D37) - [ ] Whichever is used, the transport must not be reachable by other apps on the phone (NFR-S8, now general rather than fallback-only) - [ ] Send `SCREEN_W` / `SCREEN_H` / `SCREEN_SHAPE` in the handshake — the phone sizes map slices from them and cannot guess (D46, NFR-C12) - [ ] **Drain the watch's command queue before pushing `RIDE_STATE`**, and acknowledge with `STATE_ACK` (D43) - [ ] Emit a **heartbeat per group** at the intervals in PROTOCOL §4, even when no key in the group changed — the watch's staleness rule depends on it (D44)
Sign in to join this conversation.
No description provided.