Troubleshooting
Work from symptoms. Two diagnostic tools appear throughout this page, learn them first: the boot report and the serial console.
The boot report
At every boot, the splash screen lists peripherals that failed to initialize, and the same list is returned at GET /api/system. Each entry names the component and the error:
| Entry | Likely cause | Check |
|---|---|---|
SD (ESP_ERR_TIMEOUT) | Card missing, bad wiring, or no CS pull-up | Card seated? 10 kΩ pull-up on GPIO5? MISO/MOSI swapped? |
NFC (ESP_ERR_TIMEOUT) | PN532 not answering on I2C | DIP switches set to I2C? SDA/SCL swapped? Pull-ups present? |
Audio (...) | I2S pins or amp power | BCLK/LRC/DIN order, amp VIN |
A failed peripheral disables that feature but nothing else: the device is designed to keep booting.
The serial console
Connect USB-C and open a serial terminal at 115200 baud (the device is /dev/ttyACM0 on Linux, a COM port on Windows; no drivers needed on modern systems). The firmware narrates everything: boot, WiFi attempts with failure reasons, network scans, playback, and errors. Nearly every mystery ends here.
# Linux example
screen /dev/ttyACM0 115200
WiFi
| Symptom | Cause | Fix |
|---|---|---|
Serial shows Target SSID '...' not visible on 2.4 GHz | The network is 5 GHz only | The ESP32-S3 has no 5 GHz radio. Enable 2.4 GHz on the router or hotspot ("maximize compatibility" on iPhone hotspots) |
Retries with reason=15 or reason=204 | Wrong password | Re-provision; see first boot and WiFi |
Retries with reason=201 | Network not found | SSID typo, or the network is out of range |
Retries with reason=2 on multiple networks | Auth frames not answered; often marginal power to the radio | Use a better USB cable or supply. The firmware also steps its transmit power down automatically to rescue this case |
| Connects, then the dashboard is unreachable | Client isolation on the router or guest network | Allow LAN traffic between clients, or use the main network |
Clock stays --:-- while WiFi is up | The network blocks NTP (UDP 123) | Allow outbound NTP on the firewall or set a reachable SNTP server in the firmware build |
Audio
| Symptom | Cause | Fix |
|---|---|---|
| No sound at all, but the dashboard shows it playing | Speaker miswired, LRC/SD unconnected, or amp unpowered | The amp output is bridge-tied: run the speaker across both + and - pads, never to ground. Then check LRC (GPIO39), that SD (GPIO41) is connected, and VIN. Full checklist in audio wiring |
| Distortion at high volume | Supply sag or speaker too small | Feed the amp 5 V, use a 3 W or larger speaker |
| Radio stutters, underrun counter climbs | Network cannot sustain the stream | Move closer to the router; prefer 64 to 128 kbps stations |
| A specific file will not play | Unsupported container (m4a) or corrupt file | Re-encode as MP3; test the file on a computer |
SD card
| Symptom | Cause | Fix |
|---|---|---|
| Boot report shows SD timeout | See boot report wiring row | |
| Card mounts but the library is empty | Layout does not match the scanner rules | See SD library; run tools/prepare_sd_card_data.sh --check |
| exFAT card | Not supported | Reformat FAT32 |
Dashboard
| Symptom | Cause | Fix |
|---|---|---|
| Browser warns about the certificate | Expected, self-signed | Accept it once; the connection is still encrypted |
| Every action returns "unauthorized" | Missing or wrong API token | Enter the token in the prompt the dashboard shows (or Settings, Access). How to read it off the serial console |
| The token prompt reappears with a red status dot | The device's token changed (factory reset, re-flash, re-provisioning) | Paste the current token in the prompt; read it over USB with the token recovery paths |
| Pages load but nothing updates live | WebSocket blocked | Some corporate networks block WebSocket upgrades; try another network |
| Dashboard slow while audio plays | Normal on first TLS handshake per session | Subsequent requests are fast; keep the tab open |
| The idle screen shows a dim "اضبط الموقع من الإعدادات" | Prayer times have no configured location | Set the location in the dashboard Settings prayer panel (or POST /api/prayer/config); the hint disappears once configured |
NFC
| Symptom | Cause | Fix |
|---|---|---|
| No reaction to any card | PN532 failed at boot | Check the boot report and the DIP switches |
| A specific card is ignored | Not registered | Register it from the dashboard NFC page |
| Short read range | Case too thick or metal nearby | Keep the reader zone free of battery and metal, see enclosure |
Battery
| Symptom | Cause | Fix |
|---|---|---|
| Battery percentage stuck at 0 with USB power only | No battery sense voltage; monitoring disables itself on implausible readings | Expected on a bench setup without the battery divider |
| Device shuts down and will not stay on | Genuinely empty battery latch | Charge it; press the encoder to wake after deep sleep |
| Never shows charging | CHRG pin unwired or missing pull-up | GPIO17 wiring |
Recovering the API token
A lost token never requires a reset; the device can print its current token on demand:
- Connect USB and open the serial console, type
tokenand press Enter. The device prints the current token. - Without a computer: while the WiFi status screen is up, press and hold the encoder button for about 1.5 seconds. The token appears for 5 seconds and hides again.
A factory reset (below) is the path when you want to retire the old token and mint a new one.
Factory reset
A factory reset wipes all state (not SD audio) and prints a fresh API token on serial at the next boot. The dashboard has no reset button: send POST /api/reset with the token, or erase the nvs partition over serial (parttool.py -p PORT erase_partition --partition-name=nvs). It is the reset path for a lost token or a broken configuration.
Still stuck
Capture the serial log of a full boot plus the failing action and open an issue on GitHub with it. The log almost always contains the answer.