rov-autonomy/docs/ui_design.md

503 lines
29 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Argonaut 3 — UI Design Specification
**Version:** 2.0
**Date:** 9 July 2026
**Status:****SAFETY-CRITICAL FINDING — W1 does not see the vehicle.** With the flight controller
unreachable, W1 displayed GREEN / "Systems nominal". Every widget reflects the **RPi5 autonomy
stack**, not the vehicle. In AUV mode W1 is the pre-dive GO/NO-GO gate (`health_role: gate`) — as
built it would pass a dive with a dead FC. See §W1 and DIR-7 / DIR-12. **OPEN.**
**This session:** `rov_api` `/mode` endpoints (GET/POST) built, deployed, tested (`9109439`).
**W8 Mode Indicator built and validated live — render + data** (`87000e6`) — the first widget
beyond W0/W1 confirmed with real data. Chronic "widgets show no data" fault root-caused:
`cockpit_bridge` had no `respawn`, so a boot-time race left the data-lake feed permanently dead
(`c099c00`); fixed and verified across a cold stack restart.
**Prior status (v1.9):** FastAPI backend (`rov_api`) core deployed and verified on RPi5:8081. W3 backend
(`/abort`) now LIVE and confirmed end-to-end (button path → failsafe_monitor FSM). Mission
start/stop endpoints available. W3 widget label decision "RETURN TO SAFE" stands; widget code
update + `FASTAPI_HOST` config still pending. W6 committed as `w6_altitude.json`. Stage 2b
endpoints (return budget, backup, mission upload) deferred. Production data path confirmed as
cockpit_bridge WebSocket.
---
## Version History
| Version | Date | Changes |
|---|---|---|
| 2.0 | 9 Jul 2026 | **⚠ SAFETY-CRITICAL: W1 does not see the vehicle.** With the FC unreachable, W1 showed GREEN / "Systems nominal". `failsafe_monitor` does not gate on FC connectivity; absence of data is being read as good data. In AUV mode W1 is the pre-dive GO/NO-GO gate — as built it would pass a dive with a dead flight controller. W1 spec rewritten with required fixes; status line promoted from debug affordance to operational element carrying cause text. See DIR-7, DIR-12. **OPEN.** **W8 Mode Indicator added** — read-only active-profile display, colour-coded by base mode; validated live (render + data), the first widget beyond W0/W1 so confirmed (`87000e6`). Mode *switching* explicitly excluded from W8 (belongs to the setup wizard, `POST /mode`); ArduSub arm/vehicle mode excluded (Cockpit shows it natively). **Widget testing status corrected** — "renders" and "works" are now explicitly distinguished throughout: validated with live data = W0, W1, W8; render-only = W2W6; not built = W7. Prior wording conflated the two. **`rov_api` `/mode` endpoints** (GET/POST) built, deployed, tested incl. rejection path (`9109439`). **Chronic "widgets show no data" root-caused:** `cockpit_bridge` was launched but had no `respawn`; a boot-time race left it permanently dead, killing the whole data-lake feed. Fixed (`c099c00`), verified across a cold stack restart. This — not the widgets — was why W1 "sometimes" worked. |
| 1.9 | July 2026 | FastAPI backend (`rov_api`) core deployed on RPi5:8081 (commit 66a18ef). W3 backend `/abort` now LIVE — verified end-to-end (POST /abort → Bool /rov/mission/abort → failsafe_monitor flag_manual_abort → FSM NORMAL→HOLD_AND_RECOVER). Mission endpoints `/mission/start` and `/mission/stop` available and tested. `/health` returns live mission/recording/failsafe. W6 committed to Gitea as `w6_altitude.json` (underscore convention); probe widget removed. W3 widget code update (label + FASTAPI_HOST) still pending. Stage 2b deferred: `/return_budget` (W5), `/backup/*` (W7), `/mission/upload`. FastAPI runs as argonaut-api.service (manual-start). |
| 1.8 | July 2026 | W6 Altitude Widget built and deployed (`w6_altitude.json`). NO SONAR state confirmed — correct baseline with no Ping2. cockpit_bridge updated to 8 variables: `rov-recording` and `rov-altitude` added. W3 button label decided: "RETURN TO SAFE" (assessed vehicle return-to-safe per DIR-5, not emergency hard-stop; widget code update pending). Widget testing status clarified: W0 confirmed live, W1W5 visual confirmed only, W7 not built. Production data path: cockpit_bridge WebSocket is confirmed production path — NAMED_VALUE bridge node not required. |
| 1.7 | June 2026 | W7 (Backup Due Notice) added to widget scope — operator-facing reminder that a device backup is due, with delay options. Depends on RPi5:8081 FastAPI backend. See W7 spec and DIR-11. |
| 1.6 | June 2026 | Cockpit v1.18.2 DIY widget API confirmed via probe widget. Full `window.cockpit` surface (17 keys) enumerated. Confirmed: `getDataLakeVariableData(id)` returns live value. W1W5 can now be built. |
| 1.5 | June 2026 | Production data path confirmed as `cockpit_bridge` ROS2 node (port 9001, in rov_mission, commit 12b5161) — all 6 vars live in data lake as `external/rov-*`. W0 working with scroll fix. |
| 1.4 | May 2026 | Data injection architecture fully documented with confirmed working path (Generic WebSocket) and all failed approaches. Widget variable names corrected. |
| 1.3 | May 2026 | Cockpit native app confirmed required. JSON import format confirmed. CSS rules established. All 6 widgets complete and committed to Gitea. |
| 1.2 | May 2026 | Confirmed DIY widget approach, Data Lake Inspector as W0, build status added. |
| 1.1 | May 2026 | Added Mission Setup button widget. |
| 1.0 | May 2026 | Initial UI design specification. |
---
## 1. Approach — Cockpit DIY Widgets (Confirmed)
Widgets are Cockpit **DIY widgets** — JSON files containing `html`, `css`, `js`, and
`inheritCockpitStyles` fields, imported via the gear icon on a placed DIY widget panel.
> **Cockpit native desktop app v1.18.2 is required.**
> The BlueOS browser extension version is "Lite" and does not support DIY widgets.
> DIY widget support was added in v1.9.0.
> Generic WebSocket data injection was added in v1.18.0.
> Download: https://github.com/bluerobotics/cockpit/releases
### Import Format
Each widget is a `.json` file with this exact structure:
```json
{
"html": "...",
"css": "...",
"js": "...",
"inheritCockpitStyles": false
}
```
### CSS Rules — Hard Constraints (Do Not Break)
These were discovered through testing. Violating any of them crashes or corrupts
the Cockpit renderer:
| Rule | Reason |
|---|---|
| No `body {}` or `:root {}` blocks | Bleed into Cockpit's own styles — causes renderer crash |
| No `@keyframes` animations | Cause renderer instability |
| No unicode characters in JS strings | Use plain ASCII only (-- not —, ... not …) |
| No `position: fixed` elements | Use `display: block/none` toggling instead |
| No `async/await` | Use `.then()/.catch()` for all fetch calls |
| No global tag selectors (e.g. `div {}`) | Use ID and class selectors only, scoped to widget root |
### What DIY Widgets Can Do
| Capability | Mechanism |
|---|---|
| Read all variable metadata | `window.cockpit.getAllDataLakeVariablesInfo()` — returns array of {id, name, type, description} ONLY, not values |
| **Read a single live value** | **`window.cockpit.getDataLakeVariableData(variableId)` — CONFIRMED working in v1.18.2. Returns live numeric/string value. Use this in all widgets.** |
| Read single variable metadata | `window.cockpit.getDataLakeVariableInfo(variableId)` |
| Set a variable | `window.cockpit.setDataLakeVariableData(variableId, value)` — available (not tested) |
| Call external REST endpoints | `fetch()` with `.then()/.catch()` |
| Open a new browser tab | `window.open('URL', '_blank')` |
**NOT available in DIY widget scope (confirmed absent by probe):**
- `getDataLakeValue()` — undefined in v1.18.2
- `listenToDatalakeVariable()` — undefined (postMessage iframe External API only)
**Full window.cockpit surface (17 keys, confirmed v1.18.2):**
`dataLakeVariableData [object]`, `getDataLakeVariableData [function]`, `listenDataLakeVariable [function]`, `unlistenDataLakeVariable [function]`, `getAllDataLakeVariablesInfo [function]`, `getDataLakeVariableInfo [function]`, `setDataLakeVariableData [function]`, `createDataLakeVariable [function]`, `updateDataLakeVariableInfo [function]`, `deleteDataLakeVariable [function]`, `getDataLakeVariableLastUpdateTimestamp [function]`, `availableCockpitActions [object]`, `registerNewAction [function]`, `deleteAction [function]`, `registerActionCallback [function]`, `unregisterActionCallback [function]`, `executeActionCallback [function]`
---
## 2. Data Injection Architecture — CONFIRMED FACTS
### Production Path (Confirmed) — cockpit_bridge WebSocket
```
cockpit_bridge (ROS2 node on RPi5, rov_mission package, port 9001)
WebSocket server :9001
<-- Cockpit connects as client (Settings -> Generic WebSocket Connections)
--> Sends 'variable-name=value' text messages at 2Hz
--> Data lake key: external/{variable-name}
--> DIY widget reads: getDataLakeVariableData('external/{variable-name}')
```
**Message format:** Plain text, one variable per message:
```
variable-name=value
```
**Data lake key format:** `external/{variable-name}`
> CRITICAL: Cockpit normalises variable names when creating data lake IDs.
> Underscores become hyphens in the data lake ID.
> ALWAYS USE HYPHENS in WebSocket variable names.
**Cockpit one-time configuration:**
```
Cockpit -> Menu -> Settings -> Generic WebSocket Connections
Enter: ws://192.168.1.101:9001
Click: ADD CONNECTION
```
This configuration persists between Cockpit restarts.
### Failed Injection Approaches (Do Not Retry)
| Approach | Why it failed |
|---|---|
| HTTP POST to mavlink2rest /mavlink | Stored in REST only — not broadcast to Cockpit |
| UDP to MAVLink ports from external scripts | Does not route to mavlink2rest WebSocket |
| NAMED_VALUE with sysid=1, compid=1 | ArduSub detects heartbeat conflict — do not impersonate |
### Data Lake Variables (8 total, published by cockpit_bridge)
| Variable | Source topic | Notes |
|---|---|---|
| `external/rov-failsafe` | `/rov/failsafe` | 0=GREEN, 1=AMBER, 2=RED; -1=no data |
| `external/rov-depth` | `/rov/depth` | Metres (3 dp) |
| `external/rov-voltage` | `/mavros/battery` | Battery volts (2 dp) |
| `external/rov-heading` | `/mavros/mavros/compass_hdg` | Compass degrees (1 dp) |
| `external/rov-ms` | `/rov/mission/status` | 0=IDLE…4=ABORTED; -1=no data |
| `external/rov-mp` | `/rov/mission/status` | Progress 0-100% |
| `external/rov-recording` | `/rov/recording/active` | 1=recording, 0=not recording |
| `external/rov-altitude` | `/ping2/altitude` | Ping2 metres; -1.0=NO SONAR |
---
## 3. Widget Palette — Overview
Argonaut 3 uses Cockpit as the operator hub. **No more than 8 widgets are in scope.**
Cockpit is NOT a container for everything — only the specific operator-facing information
and controls needed for field operations.
| # | Widget | Purpose | Status |
|---|---|---|---|
| W0 | Data Lake Inspector | Dev diagnostic — shows all 706 data lake variables live | **Confirmed working** |
| W1 | System Health Indicator | DP-style GREEN/AMBER/RED traffic light showing mission capability | **Visual confirmed** |
| W2 | Mission Status | Mission state, progress, current task | **Visual confirmed** |
| W3 | Return To Safe Button | Operator-initiated vehicle return-to-safe (DIR-5) | **UI confirmed; backend LIVE; label update pending** |
| W4 | Mission Setup Button | Opens mission configuration page in new tab | **Visual confirmed** |
| W5 | Return Budget | Battery % and dynamic return budget with headroom | **Visual confirmed** |
| W6 | Altitude | Ping2 downward sonar altitude with colour-banded bar | **NO SONAR confirmed** |
| W7 | Backup Due Notice | Operator-aware backup reminder with delay control | **Not built** |
| W8 | Mode Indicator | Read-only active mode profile name, colour-coded by base mode | **Validated live (render + data)** |
> **Widget testing status (corrected 9 Jul 2026).** There is a hard distinction between a widget
> that **renders** and a widget that **works**. "Renders" means it draws in Cockpit. "Works" means
> it has been validated end-to-end with live data. Do not conflate them.
>
> - **Validated with live data:** W0, W1, **W8**.
> - **Render-confirmed only, never validated with data:** W2, W3, W4, W5, W6.
> - **Not built:** W7.
>
> W6 shows a correct NO SONAR state, which is its *no-data* state — that is not data validation.
> Full testing requires a live mission, FastAPI backend, and/or Ping2 hardware.
> **All widgets read the RPi5 autonomy stack, not the vehicle.** For vehicle state (FC present,
> armed/disarmed, board running) the operator currently must use BlueOS/Cockpit-native surfaces.
> This is a defect, not a design — see W1 below and DIR-12. In AUV mode there is no operator and
> no second tool, so the gate must become self-sufficient.
> **Widget consolidation:** Grant may consolidate W0W7 into a single unified widget
> as development progresses and the full operational picture is clearer. Not yet designed.
---
## 4. Widget Specs
---
### W0 — Data Lake Inspector
**File:** `w0_data_lake_inspector.json`
**Status:** **Confirmed working** — 706/706 vars live.
**Purpose:** Dev diagnostic tool. Renders a scrollable table of all Cockpit data lake
variables with live values. Used to confirm data is reaching the data lake from
cockpit_bridge, MAVROS, and other sources.
**Data source:** `window.cockpit.getAllDataLakeVariablesInfo()` for enumeration,
`getDataLakeVariableData(id)` for values.
**Notes:** Production use is optional — this is a dev/debug tool, not an operational widget.
---
### W1 — System Health Indicator
**File:** `w1_system_health_indicator.json`
**Status:** **Validated with live data** (GREEN/RED observed). ⚠ **But the assessment behind it is
incomplete and unsafe — see below.**
**Purpose:** Primary mission-capability indicator. DP-style traffic light showing
whether the vehicle is ready to conduct a mission (GREEN), degraded but proceeding
(AMBER), or in a critical state (RED).
**Data lake variable:** `external/rov-failsafe` (0=GREEN, 1=AMBER, 2=RED; -1=no data)
**Mode-dependent role (`external/rov-health-role`):**
- **ROV (`advisory`, 0)** — display only; the pilot decides.
- **AUV (`gate`, 1)** — **pre-dive GO/NO-GO gate.** RED blocks mission start. Last human-visible
decision point before the vehicle goes dark.
**Behaviour:**
- GREEN: "Systems nominal" — all parameters within limits
- AMBER: Named degraded parameter — mission continues with reduced confidence
- RED: Critical failure — return-to-safe active
- Initial / no data: grey / loading state
> ⚠ **OPEN, SAFETY-CRITICAL (9 Jul 2026).** On 9 July, with the Pixhawk unreachable and BlueOS
> reporting "No board running", **W1 displayed GREEN / "Systems nominal"**.
>
> **Cause:** `failsafe_monitor` does not gate on flight-controller connectivity. It assesses the
> autonomy stack's own view of health. With no FC data arriving it has no *bad* data, so it reports
> nominal. Absence of data is being treated as good data.
>
> **Consequence:** in AUV mode (`health_role: gate`) W1 would pass a pre-dive gate with a dead
> flight controller — on a vehicle that will have no operator once submerged.
>
> **Required (not built):**
> 1. `failsafe_monitor` MUST subscribe to `/mavros/state` and assess FC connection + heartbeat age,
> driving AMBER/RED on comms loss. (This was in the node's *original* design intent —
> `comms_timeout_sec`, `comms_lost` — but is not effective in the implemented node.)
> 2. A monitor with no input MUST NOT report GREEN. "No data" and "good data" must be distinct
> states, distinctly displayed.
> 3. W1's status line MUST carry cause text — `"Vehicle Disconnected"`, `"Heartbeat Lost"`,
> `"No Board Running"`, `"Systems nominal"` — not a bare colour. The status line was previously
> treated as a debug affordance; it is promoted to an operational element.
> 4. Consider a pre-dive FD-headroom check on BlueOS `ardupilot_manager` (handover §15a) as part of
> the same gate — same question, different failure mode.
>
> See **DIR-7** (health MUSTs) and **DIR-12** (vehicle health ≠ autonomy health).
**Test required:** Confirm GREEN/AMBER/RED transitions by triggering failsafe monitor
state changes with live data. **Additionally: confirm RED on FC disconnect** once (1) above is built.
---
### W2 — Mission Status
**File:** `w2_mission_status.json`
**Status:** **Visual confirmed** — IDLE state and progress bar display correctly. Untested with live mission.
**Purpose:** Show current mission state (IDLE/RUNNING/PAUSED/COMPLETE/ABORTED) and
progress as a percentage progress bar.
**Data lake variables:**
- `external/rov-ms` (0=IDLE, 1=RUNNING, 2=PAUSED, 3=COMPLETE, 4=ABORTED; -1=no data)
- `external/rov-mp` (0-100 percent)
**Test required:** Start a mission with waypoints, observe state transitions and progress bar advancing.
---
### W3 — Return To Safe Button
**File:** `w3_abort_button.json`
**Status:** **UI confirmed** — confirm dialog, 10s auto-cancel countdown, clean network-error
handling. Label in widget code still reads "ABORT MISSION" — **update to "RETURN TO SAFE" pending.**
**Purpose:** Operator-initiated vehicle return-to-safe action (DIR-5). This is a
**vehicle-layer action** — it moves the vehicle. It is NOT the mission start/stop button.
**Button label:** "RETURN TO SAFE" (decided July 2026 per DIR-5)
- Not "ABORT MISSION" — that implies emergency hard-stop
- Not "STOP MISSION" — that is a mission-layer action (DIR-4), not vehicle layer
- "RETURN TO SAFE" correctly states what the vehicle does: follow breadcrumb path
back to the closest designated safe place
**Mechanism:** Confirm dialog (10s auto-dismiss) → `fetch()` POST to FastAPI `/abort`
**Config:** `FASTAPI_HOST` constant in JS must be set to `http://192.168.1.101:8081`
**Dependency:** FastAPI backend at RPi5:8081 — **LIVE** (commit 66a18ef). `/abort` verified
end-to-end server-side: POST → Bool `/rov/mission/abort` → failsafe_monitor FSM
NORMAL→HOLD_AND_RECOVER.
**Remaining:** update widget code label ("ABORT MISSION" → "RETURN TO SAFE") and set
`FASTAPI_HOST`, then test the full button→backend path from Cockpit.
---
### W4 — Mission Setup Button
**File:** `w4_mission_setup_button.json`
**Status:** **Visual confirmed** — cyan button renders, "Configure before diving" status shown.
Opens 404 until setup page exists.
**Purpose:** Open mission setup page in a new browser tab without leaving Cockpit.
**Behaviour:**
- IDLE: Full brightness, "Configure before diving" label — button enabled
- RUNNING/PAUSED: Dimmed — button disabled (mission already in progress)
**Config:** `SETUP_URL` constant in JS must be set to the FastAPI setup page URL
**Dependency:** FastAPI backend serving the setup page — not yet built.
**Test required:** Open setup page successfully with live FastAPI backend.
---
### W5 — Return Budget
**File:** `w5_battery_return_budget.json`
**Status:** **Visual confirmed** — battery % shows pending. Return budget pending
until `external/rov-return-budget` is published.
**Purpose:** Show battery percentage alongside dynamic return budget and headroom warning.
**Data lake variables:**
- `external/rov-voltage` — battery voltage from cockpit_bridge
- `external/rov-return-budget` — return budget % (not yet published by cockpit_bridge)
**Headroom thresholds:**
- Headroom < 15%: AMBER warning
- Headroom < 5%: RED critical
**Dependency:** FastAPI backend for return budget calculation; cockpit_bridge must be
updated to publish `external/rov-return-budget`.
**Test required:** Full test with live voltage and return budget data.
---
### W6 — Altitude
**File:** `w6_altitude.json`
**Status:** **Built and deployed** (July 2026). **NO SONAR** state confirmed correct
baseline with no Ping2 connected. Full test hardware-gated on Ping2 sonar purchase.
**Purpose:** Display downward Ping2 sonar altitude above hull or seafloor with
colour-coded status and vertical bar gauge.
**Data lake variable:** `external/rov-altitude` (metres float; -1.0 = NO SONAR sentinel)
**Source topic:** `/ping2/altitude` (sensor_msgs/Range) published by Ping2 driver node
(hardware-gated; driver not yet built)
**Colour thresholds:**
- GREEN (GOOD): > 1.5m
- AMBER (CAUTION): 0.51.5m
- RED (CRITICAL): < 0.5m
- GREY (NO SONAR): sentinel value -1.0 (no Ping2 connected or no echo)
**Bar scale:** Linear, 0m (bottom) to 5m (top). Values above 5m fill bar to 100%.
**No hardware default:** Shows "NO SONAR" when altitude value is -1.0 (sentinel).
The sentinel is published by `cockpit_bridge` when no `/ping2/altitude` messages have
been received meaning no Ping2 driver is running.
**Notes:**
- `sensor_msgs/Range` field `range_max` (100m for Ping2) is treated as "no return"
and also maps to the -1.0 sentinel in cockpit_bridge.
- Widget layout uses a vertical bar to the left of the numeric readout. The bar background
shows faint colour zone tints at the threshold boundaries even when reading is live.
**Pending:** Ping2 ROS2 driver node (wraps ping-python library). Interface defined:
topic `/ping2/altitude`, type `sensor_msgs/Range`, field `range` in metres.
Write driver when Ping2 hardware arrives cockpit_bridge and widget are ready.
---
### W7 — Backup Due Notice (ops-facing)
**File:** `w7_backup_due_notice.json` **NOT YET BUILT**
**Status:** Scoped, not built. Depends on RPi5:8081 FastAPI backend (shared with W3/W4).
**Purpose:** Surface to the operator that a device backup is due, and let the operator
delay it, rather than allowing an unattended backup to start during operations.
See DIR-11 for intent.
**Why this exists:** The automated Pi backup system (built 30 Jun 2026) runs each Pi's
self-backup via root cron RPi4 at 00:00, RPi5 at 00:30 unattended, which is correct
for dev. In the field this is the wrong default: an SD image is a multi-GB `dd` stream
that must NOT begin mid-dive. The ops model inverts the dev model the operator is made
aware a backup is due and chooses when it runs, with the option to delay.
**Behaviour:**
- Hidden/dormant when no backup is due.
- When a backup is due, show a small unobtrusive notice: which device(s), how overdue.
- Offer delay options (e.g. delay 1h / 4h / until end of session). Delay is operator-chosen, never automatic.
- "Run now" option only enabled when vehicle is not in a mission (ties to `external/rov-ms`).
**Data sources (planned):**
- `FastAPI /backup/status` backup-due state and overdue age per device
- `external/rov-ms` mission state (to gate "run now")
**Delay mechanism (planned):** operator selection POSTs to `FastAPI /backup/delay`
**Dependency:** FastAPI backend on RPi5:8081 not yet built.
**Open / TBC with Grant:** exact delay options; whether "run now" is exposed in field;
whether notice appears for all operators or pilot-only.
---
### W8 — Mode Indicator
**File:** `w8_mode_indicator.json`
**Status:** **Validated live** render + data confirmed 9 Jul 2026 (commit `87000e6`).
**Purpose:** Read-only indicator of the **active operating-mode profile**. Answers one question:
"what mode am I in?" Nothing else.
**Data lake variables:**
- `external/rov-mode` (string) active profile name: `ROV`, `AUV`, or a saved hybrid name
- `external/rov-mode-base` (number) 0 = ROV, 1 = AUV; anything else treated as hybrid
**Behaviour:**
- Displays the profile name large and prominent, under a small `MODE` header
- Colour-coded by base mode: **cyan `#38bdf8`** = ROV, **green `#00e5a0`** = AUV,
**amber `#f59e0b`** = hybrid / unrecognised base
- No-data state: `--` in grey `#484f58` with a `NO DATA` / `NO API` status line
- 2 Hz poll, matching `cockpit_bridge` broadcast rate
**Explicitly NOT in scope:**
- **Read-only.** W8 never writes to the data lake and never calls `rov_api`. **Mode switching lives
in the setup wizard** (`POST /mode`), not here. An indicator indicates.
- **Does not show ArduSub arm state or vehicle mode.** Cockpit's native UI already surfaces
ARMED/DISARMED and flight mode; duplicating it here would add clutter, not information.
> **Note (DIR-12):** W8 reads a resolved profile that originates from `mode_profiles.yaml` on the
> RPi5. It reflects **configuration**, not vehicle state — it would display `AUV` with the Pixhawk
> disconnected. This is correct for what W8 is, but it is another reason W1 must carry the vehicle
> health picture.
---
## 5. Widget File Locations
**Gitea repo:** `rov-autonomy/widgets/`
**Laptop local:** `C:\Users\grant\Desktop\Autonomous ROV System\rov-autonomy\widgets\`
> **Widget JSON → Gitea:** W6 widget JSON (`w6_altitude.json`) and any updated W0W5
> files need to be re-imported from the laptop and pushed to Gitea. Do NOT overwrite
> from chat history — the laptop files are the source of truth.
---
## 6. Production Data Path — Confirmed
The production data path is **cockpit_bridge WebSocket** (confirmed working, commit 12b5161
onwards). The NAMED_VALUE bridge node previously considered is not required the WebSocket
path has no 10-char name limit, simpler implementation, and is already deployed.
**NAMED_VALUE is not needed for production.** Do not build a NAMED_VALUE bridge node.
The one case where native ArduSub NAMED_VALUE messages matter is data that ArduSub
itself publishes (e.g. attitude data) these flow automatically through mavlink2rest to
Cockpit's data lake without any bridge. Custom ROS2 data goes exclusively through
cockpit_bridge.
---
## 7. FastAPI Backend (`rov_api`)
Runs as `argonaut-api.service` on RPi5:8081 (manual-start in dev). **Core deployed and
verified end-to-end (commit 66a18ef).** Architecture: uvicorn/FastAPI in the main thread,
embedded rclpy node (`RovApiNode`) in a daemon background thread. CORS enabled for Cockpit.
### Endpoints
| Endpoint | Method | Action | Status |
|---|---|---|---|
| `/health` | GET | Returns mission state, recording active, failsafe state | DONE verified |
| `/abort` | POST | W3 RETURN TO SAFE publishes Bool to `/rov/mission/abort` (vehicle-layer, DIR-5) | DONE verified end-to-end |
| `/mission/start` | POST | MissionCommand START (recording no-go gate enforced by mission_executor) | DONE verified |
| `/mission/stop` | POST | MissionCommand ABORT | DONE verified |
| `/mission/upload` | POST | Accepts YAML file, saves to RPi5 | DEFERRED Stage 2b |
| `/return_budget` | GET | Returns current calculated return budget % (feeds W5) | DEFERRED Stage 2b |
| `/backup/status` | GET | Per-device backup-due state and overdue age (feeds W7) | DEFERRED Stage 2b (Option A) |
| `/backup/delay` | POST | Records operator-chosen backup delay window (feeds W7) | DEFERRED Stage 2b (Option A) |
**W3 abort path detail:** `/abort` publishes `Bool(true)` to `/rov/mission/abort`. The
failsafe_monitor latches this as `flag_manual_abort` FSM transitions NORMAL HOLD_AND_RECOVER.
This is the DIR-5 vehicle-layer return-to-safe, NOT the mission ABORT service. Verified live.
**W3 widget wiring (pending):** update `w3_abort_button.json` label to "RETURN TO SAFE" and
set the `FASTAPI_HOST` constant to `http://192.168.1.101:8081`.
**Stage 2b design notes:**
- `/return_budget`: return budget calculation approach under discussion ("shortest path to
safety" concept). Without a DVL, position is unreliable approach TBD with Grant.
- `/backup/*`: Option A chosen server exposes read-only JSON backup status, RPi5 FastAPI
polls outbound (most secure: no credentials on the field-exposed RPi5, read-only, outbound only).
---
## 8. Development Sequence
| Order | Task | Status |
|---|---|---|
| 1 | Confirm Cockpit native app required | DONE |
| 2 | Confirm JSON import format | DONE |
| 3 | Establish CSS rules for DIY widgets | DONE |
| 4 | W0 Data Lake Inspector | DONE confirmed working (706 vars live) |
| 5 | W1 System Health Indicator | DONE visual confirmed; full test pending |
| 6 | W2 Mission Status | DONE visual confirmed; full test pending |
| 7 | W3 Return To Safe Button | DONE (UI); backend LIVE; label + FASTAPI_HOST update pending |
| 8 | W4 Mission Setup Button | DONE visual confirmed; needs setup page (Stage 2b/Phase 6) |
| 9 | W5 Return Budget | DONE visual confirmed; needs /return_budget (Stage 2b) |
| 10 | Commit W0W5 to Gitea | DONE `rov-autonomy/widgets/` |
| 11 | cockpit_bridge node (WebSocket production path) | DONE 8 variables, commits 12b5161, 5d75a9d, 0640353 |
| 12 | Probe widget (API discovery tool) | DONE and DELETED dev tool only, not part of W0W7 |
| 13 | W6 Altitude Widget | DONE `w6_altitude.json`, committed (commit 785ec56) |
| 14 | FastAPI backend core (RPi5:8081) | DONE commit 66a18ef, verified end-to-end |
| 15 | W3 label update to "RETURN TO SAFE" + FASTAPI_HOST | PENDING widget code update required |
| 16 | W3 backend `/abort` POST confirmed end-to-end | DONE FSM NORMALHOLD_AND_RECOVER verified |
| 17 | W5 `/return_budget` + `rov-return-budget` publishing | DEFERRED Stage 2b (approach TBD) |
| 18 | W7 Backup Due Notice + FastAPI `/backup/*` | DEFERRED Stage 2b (Option A) |
| 19 | W6 full end-to-end test | HARDWARE-GATED requires Ping2 sonar (Phase 3 purchase) |
| 20 | W2 full test with live mission | READY backend available; needs loaded plan + `POST /mission/start` |
| 21 | Mission Setup View (full page, W4 target) | Phase 6 / Stage 2b |
| 22 | Viewer Page | Phase 6 |
---
*End of document — Argonaut 3 UI Design v1.9 — July 2026*
*Next revision triggered by: FastAPI backend built, W3 label updated, W7 built, Ping2 purchased.*