Repository navigation
WiFiLinkTroubleshooting
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.
-
Connected but unreachable. The device reports that WiFi is connected (on the serial console, e.g. the
SysManstatus 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).
| 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 |
-
Read the link diagnostics:
wifidiagover HTTP, or typed on the serial console if the device can't be reached. Check:-
rssi,bssidandch: which access point the device is on, and how well it hears it; -
disc,discReasonandbcnTO: disconnections and beacon timeouts; -
ping: whether the device can reach its gateway; -
heap: internal RAM.
-
-
Turn on the link summary:
"wifiDiag": {"logS": 60}in theNetMansettings (orwifidiag?logS=60) logs one line a minute. -
On a network with several access points (mesh), test each one by locking the device to it with
wifidiag?bssid=<bssid>(wifiscanlists them). Clear the lock withbssid=any. -
Try a lower TX power with
wifidiag?txPwr=15, then 11 and 8. - Check the access point's view of the device if possible: signal, receive and transmit rates, retries, and its connection history.
- 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.
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-
NetworkManager -
wifidiag,wifiscanand link recovery -
Network Settings -
wifiTxPowerDbmandwifiDiag - WebServer - memory use
- SerialConsole - console output when nothing is reading
Getting Started
- Quick Start
- Architecture at a Glance
- Writing Your First SysMod
- Adding a Comms Channel
- Adding an I2C Device Type
- PlatformIO / Arduino
Scaffolding & Building
- Raft CLI
- SysTypes
- Top-Level SysType
- Build Process
- WebUI Build Pipeline
- File System
- Partitions & Flash
- Local Dev Libraries
- Library Developer Guide
Architecture
Built-in SysMods
- NetworkManager
- WiFi Troubleshooting
- BLEManager
- WebServer
- MQTTManager
- SerialConsole
- CommandSerial
- CommandSocket
- CommandFile
- FileManager
- LogManager
- ESPOTAUpdate
- StatePublisher
- Remote Logging
- Data Source Registration
Comms & Protocols
- Stack Overview
- Comms Channels
- ProtocolExchange
- RICREST Protocol
- Real-Time Streams
- Adding REST Endpoints
- Built-in REST Endpoints
- File Download (OKTO)
- OTA Update Flow
Devices & Buses
- DeviceManager
- Device Manager REST API
- Device Factory & Classes
- Device Type Records
- Adding an I2C Device Type
- Device Data Publishing
- Data Logger
- I2C Bus
- I2C Device Scanning
- I2C ID & Polling
- MotorControl Overview
- MotorControl Config
- MotorControl Commands
ROS 2
Helpers
Reference