# K1 live console and Foxglove bridge Status: alpha implementation for the verified firmware-3 MQTT streams. It uses real K1 data and does not generate a placeholder cloud, pose or latency value. ## Architecture ```text K1 lio_pcl / lio_pose | v read-only MQTT subscription on TCP 1883 | +--> raw .k1mqtt + JSONL + SHA-256 summary (first) | v bounded latest-wins preview queue (32 messages) | v raw-LZ4/protobuf decoder --> foxglove.PointCloud / Pose / SceneUpdate | v ws://127.0.0.1:8765 --> Foxglove 3D React console <-- REST + WebSocket state --> FastAPI on 127.0.0.1:8000 ``` The Paho MQTT callback never decodes the point cloud. It writes and flushes the raw frame and metadata, then enqueues a preview reference. If visualization cannot keep up, the oldest queued preview is discarded while the raw capture continues. ## Start the local application Prerequisites are the repository-local Python environment and Node.js 20 or newer. No global Python package or system component is installed. ```bash uv sync --group dev cd apps/k1-viewer npm install npm run build cd ../.. uv run k1link serve ``` Open `http://127.0.0.1:8000`. `k1link serve` intentionally exposes no LAN bind option because its provisioning endpoint temporarily receives a Wi-Fi password. The password is accepted only in the POST body, is never logged or persisted by the connector, and is cleared from the React form after success. ## Replay the captured proof 1. In **Session**, select **Replay capture**. 2. Enter the repository-relative path: ```text sessions/20260715T122850Z_live_power_cycle/captures/mqtt_scan_full_payloads_03.tsv ``` 3. Use speed `1` and enable loop for initial viewer setup. 4. Start replay, then select **Open Foxglove 3D**. 5. In a Foxglove 3D panel, enable `/k1/points`, `/k1/pose` and `/k1/trajectory`. 6. For the cloud, choose `intensity` as the color field and a Turbo/Rainbow colormap or custom two-color gradient. Foxglove can also color by `x`, `y`, `z` and its derived ``. The reviewed TSV reader accepts exactly four columns: receive timestamp, topic, declared payload length and hex payload. It verifies timestamp, UTF-8 topic, declared length, hex encoding and allocation bounds. Native `mqtt.raw.k1mqtt` captures are supported directly and use their sibling metadata timestamps when present. ## Connect and stream live 1. Power K1 to its normal steady-green standby state. 2. Confirm the manual power checklist in **Connect**. 3. Run the real six-second BLE scan and select the K1 candidate. 4. Enter the existing router SSID/password and press **Provision Wi-Fi & connect**. That button is the explicit authorization for one reviewed 99-byte provisioning write; the backend never retries automatically. 5. When K1 reports a non-AP private address, press **Start live stream**. 6. Open Foxglove before scanning if convenient. 7. Double-click the physical K1 button to start scanning. Double-click again to stop, wait for the LED to return to steady green, then stop the local session. Each live run creates an ignored `sessions/_viewer_live/` directory with a redacted manifest, operator notes, raw MQTT frames, per-message metadata and a hash summary. No application request topic is published. ## Published topics | Topic | Foxglove schema | Meaning | | --- | --- | --- | | `/k1/points` | `foxglove.PointCloud` | metric XYZ float32 + uint8 intensity, stride 16 | | `/k1/pose` | `foxglove.PoseInFrame` | current decoded K1 pose in the `map` frame | | `/k1/trajectory` | `foxglove.SceneUpdate` | bounded cyan line strip, throttled while growing | | `/k1/metrics` | JSON schema | latency, decode/publish time, FPS, points and drops | Point coordinates remain `(x/scaler, y/scaler, z/scaler)` exactly as verified. No axis swap, quaternion normalization or vehicle extrinsic is silently applied. Only the low byte of `rgbi` is labeled intensity; interpreting the upper bytes as RGB remains unverified. ## Latency semantics `pipeline_ms` / `mqtt_to_publish_ms` is measured with the host monotonic clock from MQTT callback receipt through raw disk write, bounded queue wait, decode, packing and Foxglove channel publish. Rolling p50/p95 values use the last 512 published decoded messages. This is the exact Mac pipeline latency, not yet sensor-photon-to-screen latency. The K1 header timestamp epoch has not been proven, Foxglove rendering time is outside the Python publisher, and display latency is not observable without a clock-correlated device timestamp or high-speed-camera experiment. Foxglove message time therefore uses host receive Unix time while durations use `monotonic_ns`. ## Current boundaries - Raw panoramic camera frames were not present on the observed MQTT report topics; this milestone intentionally ships point cloud plus trajectory only. - Physical double-click remains the start/stop control. A future MQTT modeling publisher needs a separately reviewed state-changing profile. - The React application opens the official Foxglove viewer over a local WebSocket. It does not embed or fork the proprietary modern viewer; Foxglove account/seat terms apply to that viewer independently of this connector. - Exact path axes and a scanner-to-vehicle transform must be calibrated before mounting on the unmanned platform. ## Verification checkpoint — 2026-07-15 The full captured 180-second scan was passed through the production Foxglove bridge without a viewer-side substitute: | Check | Result | | --- | ---: | | MQTT messages read | 2,836 | | `lio_pcl` frames published | 1,140 | | `lio_pose` frames published | 1,215 | | points packed and published | 4,165,862 | | decoder errors | 0 | | final trajectory poses | 1,215 | The same replay was then started through the FastAPI/React contract at `10x`. The API exposed the loopback Foxglove URL, live point/pose metrics and non-zero preview-drop accounting under deliberate acceleration, and released TCP 8765 after the stop request. This validates replay, overload behavior and lifecycle; the next checkpoint is the powered K1 ideal-LAN live run.