Skip to content

WiFiLinkTroubleshooting

Rob Dobson edited this page Oct 15, 2026 · 1 revision

WiFi Link Troubleshooting

How to diagnose a Raft device whose WiFi link is unreliable, for example one which reports that it is connected but can't be reached. The diagnostics, recovery and settings described here are in RaftCore versions after 1.58.1.

Symptoms

  • Connected but unreachable. The device reports that WiFi is connected (on the serial console, e.g. the SysMan status line: "wifiSTA":{"conn":1,...}), but it can't be reached from the network, and its own pings to the gateway fail. A restart fixes it.
  • Slow or stalled transfers. Uploads or downloads which usually take seconds sometimes take tens of seconds. TCP retransmits after packets are lost.
  • Repeated disconnects or failed connections, often with disconnect reasons 2 (authentication expired), 4 (association expired) or 15 (4-way handshake timeout).

Causes found so far

Cause Signs Fix
Board transmits a poor signal at full power The access point sees a low or falling signal and a low receive rate from the device (UniFi: "AP/Client Signal Balance: Poor"). Connections to an access point fail or stop passing data, while other devices on it are fine. The same access point works when the TX power is reduced Limit the TX power (wifiTxPowerDbm, see WiFi transmit power). Seen on a UM FeatherS3: no connection to a nearby access point at 20 dBm, reliable at 15 dBm or less
Internal RAM exhausted heap.intMin (from wifidiag) falls to a few KB under load, often with concurrent HTTP transfers. WiFi and lwIP can't allocate buffers, so the link stops passing data. Crashes in the web server can also occur Enable PSRAM on boards which have it (CONFIG_SPIRAM). Use RaftCore after 1.58.1, where the PSRAM-aware buffers use PSRAM under ESP-IDF 5+, and RaftWebServer after 1.16.1, which handles allocation failures and sends files in smaller chunks. On boards without PSRAM, reduce the web server's numConnSlots and sendMax (see WebServer memory use)
An access point holding stale state for the device Only one access point is affected and the device's TX power makes no difference Restart the access point

Diagnosing

  1. Read the link diagnostics: wifidiag over HTTP, or typed on the serial console if the device can't be reached. Check:
    • rssi, bssid and ch: which access point the device is on, and how well it hears it;
    • disc, discReason and bcnTO: disconnections and beacon timeouts;
    • ping: whether the device can reach its gateway;
    • heap: internal RAM.
  2. Turn on the link summary: "wifiDiag": {"logS": 60} in the NetMan settings (or wifidiag?logS=60) logs one line a minute.
  3. On a network with several access points (mesh), test each one by locking the device to it with wifidiag?bssid=<bssid> (wifiscan lists them). Clear the lock with bssid=any.
  4. Try a lower TX power with wifidiag?txPwr=15, then 11 and 8.
  5. Check the access point's view of the device if possible: signal, receive and transmit rates, retries, and its connection history.
  6. Measure timing with nothing reading the USB console as well, since console writes behave differently when a host is reading (see SerialConsole).

Link recovery (on by default) reconnects a device whose link has stopped passing data, preferring another access point with the same SSID. It is a safety net, not a fix: regular recoveries on one access point point to one of the causes above.

Test scripts

RaftCore unit_tests/wifi_link_hw contains host-side scripts for exercising a device's link while monitoring it. They need Python 3, and pyserial for the serial console.

Script Purpose
monitor.py Pings the device, a control device and the gateway every second, polls HTTP and captures the device's serial console with host timestamps. When the device becomes unreachable while the gateway responds, it investigates over the serial console: reads wifidiag, starts a ping from the device to the gateway, waits for self-recovery and then forces a reconnect. Writes events.jsonl, samples.csv and serial.log
stress.py Load generator: cycles through idle, bursts of small HTTP requests, downloads of a 100 KB file (the device transmits), uploads of it (the device receives) and optional restarts
uploads.sh Repeated curl uploads (a heavy receive load on the device)
txpower_matrix.py For each access point and TX power: locks the device to the access point and runs a short load test. Reports connection, gateway ping, ping loss, round-trip time and throughput

Example:

cd unit_tests/wifi_link_hw
python3 monitor.py --dut 192.168.86.52 --port /dev/ttyACM1 --control 192.168.86.43 --minutes 60 --out results &
python3 stress.py --dut 192.168.86.52 --minutes 60

Related

Clone this wiki locally