> ## Documentation Index
> Fetch the complete documentation index at: https://docs.altnautica.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Physical UI

> The OLED display and four-button menu system on the ground station.

# Physical UI (OLED + Buttons)

The ground station has a 128x64 pixel OLED and four tactile buttons. Together they give you status at a glance and a menu system for configuration, pairing, and network control. No laptop or phone required.

<Frame caption="The SSD1306 OLED showing the Link status screen with RSSI, bitrate, and FEC statistics">
  <img src="https://mintlify.s3.us-west-1.amazonaws.com/altnautica/images/placeholder-oled-ui.png" alt="Ground station OLED display showing WFB-ng link statistics" />
</Frame>

## Hardware

**OLED display.** SSD1306 or SH1106 driver IC, 128x64 pixels, I2C interface at address `0x3C`. Wired with four connections: SDA, SCL, VCC (3.3 V), and GND. The 1.3" size is easier to read in the field. The 0.96" size works on the bench.

**Buttons.** Four 6mm tactile momentary pushbuttons. Each wires between a GPIO pin and GND. The agent enables internal pull-ups in software, so you do not need external resistors for the bench build.

| Button | Pi 4B GPIO | Header pin | Short press    | Long press (2 sec)          |
| ------ | ---------- | ---------- | -------------- | --------------------------- |
| B1     | GPIO 5     | Pin 29     | Menu up        | Toggle recording            |
| B2     | GPIO 6     | Pin 31     | Menu down      | Toggle WiFi AP on/off       |
| B3     | GPIO 13    | Pin 33     | Select / enter | Start drone pairing         |
| B4     | GPIO 19    | Pin 35     | Back / exit    | Factory reset (hold 10 sec) |

Long-press events fire on release, not at the 2-second mark. If you hold B4 and change your mind, just let go before 2 seconds and nothing happens.

## Status screens

Five auto-cycling screens rotate every 5 seconds. Press B1 or B2 to advance manually.

### 1. Link

Shows the WFB-ng radio link to the drone.

```
Link
RSSI  -52 dBm
Rate  8.5 Mbps
FEC   1204 rec / 2 lost
Chan  149 (5 GHz)
```

### 2. Drone

Shows the connected drone status.

```
Drone
ID    ados-drone-5e9a4c
Mode  LOITER
Batt  82%   12 sats
Alt   45 m  Spd 3.2 m/s
```

### 3. GCS (connected clients)

Shows who is connected to the ground station.

```
GCS
HDMI         PIC
192.168.4.23  observer
192.168.7.2   observer
```

The `PIC` badge marks the pilot-in-command client.

### 4. Network

Shows current network state and uplinks.

```
Net
AP   ADOS-GS-5E9A  192.168.4.1
USB  192.168.7.1    connected
Up   wlan0-client   OK
4G   disabled
```

### 5. System

Shows SBC health and agent version.

```
System
CPU  22%   RAM 640/4096 MB
Temp 51 C  Up  2d 14h
Agent v0.89.2
```

All text renders at 8x16 pixel font size so you can read it with reading glasses at arm's length.

### Role badge

When the node is mesh-capable (`mesh_capable: true` in `/etc/ados/profile.conf`), the status screen header carries a small role tag at the top right:

| Tag      | Meaning                                                        |
| -------- | -------------------------------------------------------------- |
| `Dir`    | direct mode (single-node)                                      |
| `Rly`    | relay mode                                                     |
| `Rx<id>` | receiver mode (with the first three characters of the mesh id) |

On a fresh box where no role has been picked yet, the OLED replaces the status cycle entirely with a "Role: unset" prompt that points at the Mesh menu. Pressing any button enters the Mesh -> Set role flow directly.

## Menu system

Press B3 (Select) from any status screen to enter the menu. Navigation uses the same four buttons:

* **B1:** move up
* **B2:** move down
* **B3:** enter / confirm
* **B4:** back / exit

```
Main Menu
├── Pair with drone
├── Network
│   ├── WiFi AP on/off
│   ├── WiFi client scan and join
│   ├── 4G modem status
│   └── Uplink priority
├── Mesh                            (visible only when mesh_capable)
│   ├── Set role                    (cycle direct / relay / receiver)
│   ├── Accept relay                (receiver only)
│   ├── Join mesh                   (relay only, when not joined)
│   ├── Neighbors                   (relay or receiver)
│   └── Leave mesh                  (when on a mesh)
├── Radio
│   ├── Channel (1-165)
│   └── Bitrate / FEC profile
├── Display
│   ├── HDMI resolution
│   └── OLED brightness
├── System
│   ├── Version
│   ├── Reboot
│   └── Factory reset
└── Back to status
```

The Mesh submenu only appears when `mesh_capable: true` in `/etc/ados/profile.conf`. `profile_detect` sets this flag at boot when a second USB WiFi adapter is present on the node. Children inside the submenu are filtered by the current role: a receiver sees "Accept relay" but not "Join mesh"; a relay sees the inverse; "Leave mesh" only appears when a mesh is up.

## Mesh overlay screens

Mesh actions take over the OLED with dedicated screens that override the normal status cycle. Each overlay rebinds the four buttons to actions specific to that screen.

| Screen              | Triggered by                          | Buttons                                                                     |
| ------------------- | ------------------------------------- | --------------------------------------------------------------------------- |
| **Role picker**     | Mesh -> Set role                      | B1/B2 cycle direct/relay/receiver, B3 apply, B4 back                        |
| **Accept window**   | Mesh -> Accept relay (receiver)       | B1 approve highlighted pending, B2/B3 scroll, B4 close window               |
| **Join scan**       | Mesh -> Join mesh (relay)             | B1 send join request to discovered receiver, B4 cancel                      |
| **Joined status**   | After successful join                 | B4 back to status                                                           |
| **Hub unreachable** | Relay loses receiver via mDNS timeout | B1 wait longer, B4 transition to direct                                     |
| **Neighbors**       | Mesh -> Neighbors                     | B1/B2 scroll, B4 back                                                       |
| **Leave confirm**   | Mesh -> Leave mesh                    | B3 confirm leave (transitions to direct), B4 cancel                         |
| **Error states**    | Any pairing or role error             | B4 dismiss; the screen shows a short message keyed off the agent error code |

The first-boot unset screen (when a mesh-capable node has no role yet) is its own override that any button press dismisses by entering the Mesh submenu.

## Factory reset

Factory reset is a two-step process to prevent accidents:

<Steps>
  <Step title="Hold B4 for 10 seconds">
    The OLED shows a countdown: "Factory reset in 10... 9... 8..."
  </Step>

  <Step title="Confirm within 5 seconds">
    The OLED shows "Confirm? Hold B4 again for 3 seconds." Release B4, then hold it again within 5 seconds.
  </Step>

  <Step title="Reset begins">
    The agent erases pairing keys, resets config to defaults, and reboots. The ground station returns to the first-boot state.
  </Step>
</Steps>

If you release B4 during either hold, or if the 5-second confirm window passes, nothing happens.

On a mesh-capable node the factory reset additionally transitions the role to `direct`, stops the mesh services, and wipes `/etc/ados/mesh/*` (the mesh id, the shared PSK, the receiver hint, the revocation list, and the role sentinel). The node returns to a fresh state and can be paired into a different deployment.

## Power saving and burn-in protection

OLED screens can develop burn-in from static content over long periods. The agent includes three mitigations:

* **Auto-dim:** brightness drops to 20% after 60 seconds of no button activity
* **Pixel invert:** white-on-black swaps to black-on-white every 10 minutes
* **Screensaver:** a small bouncing "ADOS" logo appears after 5 minutes of idle

Any button press wakes the display immediately.

## Graceful degradation

The OLED and buttons are optional. The ground station works fine without them.

| Missing hardware       | Behavior                                                                                                                            |
| ---------------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
| No OLED                | Agent skips the OLED service. All menu functions are available via the setup webapp and the ground-station panel in Mission Control |
| No buttons             | OLED still renders status screens on a 5-second cycle. Configuration is done via setup webapp or GCS                                |
| No OLED and no buttons | Agent runs headless. Use WiFi AP + browser, USB tether, or HDMI kiosk for all interaction                                           |

<Tip>
  On boards other than the Pi 4B, GPIO pin numbers are defined in the HAL board profile YAML. The agent reads the board profile at boot and maps buttons accordingly. You do not need to edit any code.
</Tip>

## Remapping buttons

You can remap what each button does (short press and long press) from three places:

* **OLED menu:** not available (you would need buttons to remap buttons)
* **Setup webapp:** Advanced page
* **Mission Control:** ground-station panel > Physical UI tab

The button remap matrix supports any combination of actions: record toggle, WiFi toggle, pair, reboot, factory reset, cycle screen, and more.

## What is next

* [Display](/ground-agent/display) if your node has the SPI LCD attached for the touch surface and native dashboard
* [Setup and Pairing](/ground-agent/setup-and-pairing) for the first-time walkthrough
* [Hardware Tab](/ground-agent/hardware-tab) for the Mission Control management interface
* [HDMI Kiosk](/ground-agent/hdmi-kiosk) for standalone flight display
