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

# WiFi

> Manage the box's own wireless interface

Scan for access points and join networks with the box's own wireless interface. This
is useful when the DUT hosts an access point. It is also useful when the box must move
between networks during a test.

## Handle

```rust theme={null}
use lager::LagerBox;

let lager = LagerBox::from_env()?;
let wifi = lager.wifi();
```

WiFi is a **box-level** capability, not a net. There is no net name and no `name()`.

<Note>
  This is the box's own interface. It is not the `NetType.Wifi` net available in the
  Python API, which gates one DUT's internet access through a router's parental
  controls. It is not a router net either.
</Note>

## Methods

| Method      | Description                                   |
| ----------- | --------------------------------------------- |
| `status()`  | Status of every wireless interface on the box |
| `scan()`    | Scan for access points on an interface        |
| `connect()` | Join a network                                |
| `delete()`  | Delete a saved connection profile             |

## Types

```rust theme={null}
pub struct WifiInterface {
    pub interface: String,   // e.g. "wlan0"
    pub ssid: String,        // or a placeholder like "Not Connected"
    pub state: String,       // "Connected" / "Disconnected"
}

pub struct WifiAccessPoint {
    pub ssid: Option<String>,      // "Hidden" for hidden networks
    pub address: Option<String>,   // BSSID
    pub strength: Option<i64>,     // approximate percent, 0-100
    pub security: Option<String>,  // "Open" / "Secured"
}

pub struct WifiConnection {
    pub ssid: String,
    pub connected: bool,
    pub interface: Option<String>,
    pub method: Option<String>,    // "nmcli" / "wpa_supplicant"
}
```

## Method Reference

### `status() -> Result<Vec<WifiInterface>>`

Status of every wireless interface on the box.

### `scan(interface: &str) -> Result<Vec<WifiAccessPoint>>`

Scan for access points, strongest first.

```rust theme={null}
for ap in wifi.scan("wlan0")? {
    println!("{:?} {:?}% {:?}", ap.ssid, ap.strength, ap.security);
}
```

### `connect(ssid: &str, password: &str) -> Result<WifiConnection>`

Join a network. Pass an empty password for an open network.

### `delete(ssid: &str) -> Result<()>`

Delete a saved connection profile by SSID.

## Examples

### Assert the DUT brought up its access point

```rust theme={null}
use lager::LagerBox;

let lager = LagerBox::from_env()?;
let wifi = lager.wifi();
let supply = lager.supply("supply1");

supply.set_voltage(3.3)?;
supply.enable()?;
std::thread::sleep(std::time::Duration::from_secs(15));

let aps = wifi.scan("wlan0")?;
let dut_ap = aps.iter()
    .find(|ap| ap.ssid.as_deref() == Some("DUT-SETUP"))
    .expect("DUT did not bring up its setup AP");
println!("AP up at {:?}% signal", dut_ap.strength);

supply.disable()?;
```

## Notes

* `capabilities.wifi_command` being `true` means the box **serves the route**, not
  that it can do the work. A box whose container has no `nmcli` installed answers
  `scan()` with `Error::Box` and HTTP 502 carrying
  `[Errno 2] No such file or directory: 'nmcli'`. On that same box, `status()` does not
  error at all: it returns an interface reporting `Interface detection failed`.
* Every action gets a flat 90-second budget. The nmcli and iwlist calls block for
  seconds, a connect can retry through wpa\_supplicant, and they queue on the box's
  wifi lock.
* `strength` is an approximate percentage, not dBm.
* Moving the box between networks can move the address you reach it at. Be careful
  connecting the box to a DUT-hosted AP if that is also the path that your test uses.
