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

# WiFi Provisioning

> Put the M1 on a network for UDP streaming and uploads

The M1 uses WiFi for UDP streams, recording uploads, and firmware downloads.
Provision it over a USB or Bluetooth LE (BLE) control session.

## Provision a network

```cpp theme={null}
ERROR_CODE ec = dev.wifi_add("MyNetwork", "MyPassphrase", "US");
if (ec == ERROR_CODE::SUCCESS) {
    dev.wifi_select("MyNetwork");
}
```

The optional ISO country code sets the regulatory domain, and `US` is what
unlocks 5 GHz. Saved networks persist on the device.

```cpp theme={null}
dev.wifi_remove("MyNetwork");     // forget
dev.wifi_select("MyNetwork");     // prefer among saved networks
```

<Note>
  The M1 joins WPA2-PSK and WPA3-SAE (Personal) networks. Enterprise networks that
  authenticate with 802.1X/EAP are not supported, so a corporate SSID generally
  needs a guest or IoT network instead.
</Note>

## Read the connection state

WiFi status lives in the wireless block of the device information and
is cached when `open()` succeeds. WiFi add/remove/select calls refresh that
cached block after the command is accepted:

```cpp theme={null}
WirelessConfiguration w = dev.get_device_information().wireless;
// w.wifi_connected, w.wifi_ssid, w.wifi_ip_address
// w.wifi_rssi (dBm), w.internet_reachable
// w.wifi_state, w.wifi_link_speed, w.wifi_freq_mhz, w.wifi_security
// w.saved_networks, w.ble_connected
```

`get_device_information()` is cached and non-blocking. Because association is
asynchronous, the first snapshot after `wifi_add()` may still show
`connecting`.

The snapshot is captured at `open()` and updated by the WiFi calls, so a handle
held open across a network change continues to report the association captured
earlier. Call `refresh_device_information()` to update it, then read the struct
again:

```cpp theme={null}
dev.refresh_device_information();
WirelessConfiguration now = dev.get_device_information().wireless;
```

`wifi_state` is one of `connected`, `connecting`, `auth_failed`,
`disconnected`, or `unknown`. `connecting` appears only during a live attempt,
and `auth_failed` means the credentials were rejected. A dropped link reads
`disconnected` while the device reconnects on its own. `unknown` is set
host-side when a refresh could not complete, which is different from an empty
value: empty means this firmware did not report the field at all.

On firmware newer than v00.09.16, `connecting` and `auth_failed` describe a
specific connection attempt and expire approximately 90 seconds after it. An
expired result reverts to `disconnected` rather than persisting, so
`auth_failed` always refers to a recent attempt. On v00.09.16 and earlier, an
`auth_failed` result persists until the device reboots and may therefore name a
network whose credentials have since been corrected.

See [Core Types](/api/types#wirelessconfiguration) for the full block, including
`ble_connected`, which reports whether a Bluetooth central currently holds the
link on firmware newer than v00.09.16.

## From the CLI

```sh theme={null}
ef-cli --ble AA:BB:CC:DD:EE:FF wifi add MyNetwork MyPassphrase US
ef-cli --ble AA:BB:CC:DD:EE:FF wifi add "My iPhone"   # prompts for the password, hidden
ef-cli --ble AA:BB:CC:DD:EE:FF wifi select MyNetwork
ef-cli --ble AA:BB:CC:DD:EE:FF wifi status
ef-cli --ble AA:BB:CC:DD:EE:FF wifi list
ef-cli --ble AA:BB:CC:DD:EE:FF wifi scan
ef-cli --ble AA:BB:CC:DD:EE:FF wifi remove MyNetwork
```

Saved networks are held at equal priority, so the device connects automatically
to the strongest access point in range. `wifi select` overrides that choice for a
specific saved network. Re-adding the currently connected network has no effect
and does not drop the active link.

<Note>
  Operations that require connectivity (`upload_recording()`, update downloads)
  fail with `WIFI_NOT_CONNECTED` when the device is not associated. Check
  `wireless.wifi_connected` first for a better user experience.
</Note>

## Enable wireless streaming

Once the M1 is associated, open a new BLE session with the Linux receiver's
IP:

```cpp theme={null}
InitParameters init;
init.input_type = INPUT_TYPE::STREAM;
init.ble_address = "AA:BB:CC:DD:EE:FF";
init.udp_host = "192.168.1.50";  // receiving Linux host
init.udp_port = 5005;

Device dev;
dev.open(init);
```

The M1 and receiver must be mutually reachable. `udp_host` is the host
address, not the M1's address.
