Skip to content

ConnectionState

ConnectionState = { cause: "never-connected" | "user" | "link-lost" | "bluetooth-off" | "timeout" | "failed"; error: ConsoleSdkError | null; status: "disconnected"; } | { startedAt: number; status: "connecting"; step: "link" | "negotiating" | "identifying" | "clock-sync"; via: ConnectVia; } | { link: "healthy" | "unresponsive"; since: number; status: "ready"; via: ConnectVia; } | { progress: number; since: number; status: "updating"; } | { attempt: number; lastError: ConsoleSdkError | null; nextAttemptAt: number; since: number; status: "reconnecting"; }

Defined in: console-sdk/src/device/deviceModel.ts:50

The per-device connection state machine (SDK_PLAN.md §3.4.1). Consumers never subscribe to connection events; they read device.connection and branch on status. Every transition — including the degraded link: 'unresponsive' and the updating OTA hold — is data on this union.

{ cause: "never-connected" | "user" | "link-lost" | "bluetooth-off" | "timeout" | "failed"; error: ConsoleSdkError | null; status: "disconnected"; }

No live link. The single cause-carrying terminal state: cause distinguishes a fresh device ('never-connected'), a deliberate disconnect() ('user', which also suppresses auto-reconnect for the session), a dropped link with exhausted reconnect attempts ('link-lost'), a radio-off drop ('bluetooth-off'), a setup 'timeout', or a setup 'failed'. error carries the typed failure when one applies.


{ startedAt: number; status: "connecting"; step: "link" | "negotiating" | "identifying" | "clock-sync"; via: ConnectVia; }

A connect() is in flight. step reports the setup phase (BLE link → MTU/priority negotiation → DIS/serial identification → console clock sync); startedAt is the establishment attempt’s start time and via its provenance. connect() resolves only once the device reaches ready.


{ link: "healthy" | "unresponsive"; since: number; status: "ready"; via: ConnectVia; }

Protocol session up, realtime stream available, 2 s health check running. since is when the connection was established and via its provenance. link: 'unresponsive' is a degraded health-check reading surfaced as data (not a separate phase): commands remain callable and may recover the link; UI can badge it.


{ progress: number; since: number; status: "updating"; }

An OTA firmware transfer holds the link (fleet-visible so every screen renders the device consistently). since is when the update began; progress is 01. Workout arming rejects with command/busy while a device is here.


{ attempt: number; lastError: ConsoleSdkError | null; nextAttemptAt: number; since: number; status: "reconnecting"; }

The link dropped while the device was still wanted (auto-reconnect policy, or a drop mid-workout). Treated as degraded, not gone: bounded attempts with visible attempt/nextAttemptAt, and lastError from the previous failed attempt. since is when reconnection began.