Skip to content

Fix WiFi TCP/HTTP services not starting without USB serial connected#10460

Merged
thebentern merged 1 commit into
meshtastic:developfrom
tanrax:fix/wifi-race-no-usb-serial
May 13, 2026
Merged

Fix WiFi TCP/HTTP services not starting without USB serial connected#10460
thebentern merged 1 commit into
meshtastic:developfrom
tanrax:fix/wifi-race-no-usb-serial

Conversation

@tanrax

@tanrax tanrax commented May 12, 2026

Copy link
Copy Markdown
Contributor

Fixes a race condition in initWifi() that prevents onNetworkConnected() from ever being called when the device boots without a USB serial connection. This causes the TCP API server (port 4403) and HTTP API handlers to never initialize, even though WiFi connects successfully.

In initWifi(), WiFi.onEvent(WiFiEvent) is registered after createSSLCert(). The createSSLCert() function blocks with yield() calls while generating/loading the SSL certificate.

Without USB serial, the SerialConsole constructor delays boot by up to 5 seconds (while (!Port) timeout). By the time initWifi() runs, the ESP32 WiFi subsystem has had time to auto-reconnect using credentials stored in NVS. During createSSLCert()'s yield() calls, WiFi fires ARDUINO_EVENT_WIFI_STA_GOT_IP, but the event handler isn't registered yet, so the event is lost. onNetworkConnected() never runs, and the web/TCP services never start.

With USB serial connected, the serial port becomes ready immediately (no 5-second timeout), so initWifi() runs earlier and WiFi.onEvent() is registered before WiFi can auto-reconnect.

Two changes in WiFiAPClient.cpp:

  1. Move WiFi.onEvent(WiFiEvent) before createSSLCert() so the event handler is ready before any blocking call that could allow WiFi to reconnect.

  2. Call onNetworkConnected() from reconnectWiFi() on all platforms (not just RP2040) as a safety net. The function is already guarded by APStartupComplete so it only runs once.

Tested on Heltec V3 (ESP32-S3) with firmware 2.7.23:

  • 3 consecutive reboots without USB serial: TCP 4403 open on all
  • Web API returns correct JSON responses
  • MeshMonitor (TCP client) reconnects successfully after each reboot
  • Heap stable at ~58100 bytes across reboots

Possibly related issues

Reports describing the same end-user symptom (WiFi connects and the device gets an IP, but no client can connect because TCP/HTTP services never come up) that this PR may fix. I do not own these specific boards, so confirmation from affected users would be appreciated:

🤝 Attestations

  • I have tested that my proposed changes behave as described.
  • I have tested that my proposed changes do not cause any obvious regressions on the following devices:
    • Heltec (Lora32) V3
    • LilyGo T-Deck
    • LilyGo T-Beam
    • RAK WisBlock 4631
    • Seeed Studio T-1000E tracker card
    • Other (please specify below)

@CLAassistant

CLAassistant commented May 12, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

@CLAassistant

Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR addresses an ESP32 boot-time race in initWifi() where WiFi can auto-reconnect (and emit ARDUINO_EVENT_WIFI_STA_GOT_IP) before the firmware registers its WiFi event handler, preventing onNetworkConnected() from running and leaving TCP/HTTP services uninitialized.

Changes:

  • Registers the ESP32 WiFi event handler earlier (before SSL cert creation) to avoid missing GOT_IP during boot.
  • Calls onNetworkConnected() from reconnectWiFi() on all platforms as a one-time safety net for bringing up network services.
  • Moves createSSLCert() later in the initWifi() flow to occur after event registration.

Comment on lines +368 to 372
// Register WiFi event handler BEFORE createSSLCert() to prevent race condition:
// Without this, WiFi can auto-reconnect during cert generation and fire GOT_IP
// before the handler is registered, causing onNetworkConnected() to never run.
WiFi.onEvent(WiFiEvent);
WiFi.setAutoReconnect(true);
@tanrax

tanrax commented May 12, 2026

Copy link
Copy Markdown
Contributor Author

Good catch, but this is safe in practice for two reasons:

When the cert is already cached in NVS (every boot after the first), createSSLCert() completes in under a second. WiFi reconnection takes 5 to 10 seconds. So the cert is always ready before GOT_IP fires.

Even on a cold first boot (no cached cert), the cert generation task assigns the global cert pointer and sets isCertReady = true before the busy wait exits. The main thread is blocked in createSSLCert() during this time, so initWebServer() cannot be called concurrently from the same thread. onNetworkConnected() would queue behind it.

The second change (calling onNetworkConnected from reconnectWiFi) provides an additional safety net: if the event is ever missed for any reason, the next periodic check picks it up. The function is guarded by APStartupComplete so it only runs once.

Tested with 3 consecutive cold reboots without USB serial on Heltec V3. TCP 4403 and web API came up correctly every time.

Move WiFi.onEvent(WiFiEvent) registration before createSSLCert() to
prevent a race where the ESP32 auto-reconnects during cert generation
and fires GOT_IP before the handler is attached, causing
onNetworkConnected() to never run and the TCP/HTTP API services to
never initialize when booting without USB serial.

Also call onNetworkConnected() from reconnectWiFi() on all platforms
(not just RP2040) as a safety net; it is already guarded by
APStartupComplete so it only runs once.
@caveman99 caveman99 force-pushed the fix/wifi-race-no-usb-serial branch from 3402787 to dca50c5 Compare May 13, 2026 09:09
@caveman99 caveman99 added triaged Reviewed by the team, has enough information and ready to work on now. cleanup Code cleanup or refactor labels May 13, 2026
@thebentern thebentern merged commit 039ad42 into meshtastic:develop May 13, 2026
81 of 82 checks passed
thebentern pushed a commit that referenced this pull request May 13, 2026
…10460)

Move WiFi.onEvent(WiFiEvent) registration before createSSLCert() to
prevent a race where the ESP32 auto-reconnects during cert generation
and fires GOT_IP before the handler is attached, causing
onNetworkConnected() to never run and the TCP/HTTP API services to
never initialize when booting without USB serial.

Also call onNetworkConnected() from reconnectWiFi() on all platforms
(not just RP2040) as a safety net; it is already guarded by
APStartupComplete so it only runs once.
suntrackspb pushed a commit to suntrackspb/firmware-ru that referenced this pull request May 23, 2026
Что вошло из апстрима (40 коммитов):
- Position precision security fix: утечка координат через PRIMARY канал (meshtastic#10509)
- T-Echo-Card поддержка + OLED_TINY guard для компаса
- ThinkNode M7, Station G3 варианты
- SX_LNA_EN включён по умолчанию (meshtastic#10469)
- WiFi TCP/HTTP fix при отсутствии USB serial (meshtastic#10460)
- Rework clock renderer (70% max)
- Обновлены protobufs → 59cb394

Конфликты разрешены:
- UIRenderer.cpp: взята версия апстрима (OLED_TINY) вместо 2.8-ветки
- PositionPrecision.{cpp,h}: взят upstream security fix (meshtastic#10509)
- admin.pb.h, cardputer variant.cpp, test_position_precision: взят апстрим
- protobufs submodule: обновлён до 59cb394

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Evil8it pushed a commit to Evil8it/ME4TACTNK that referenced this pull request Jun 10, 2026
…eshtastic#10460)

Move WiFi.onEvent(WiFiEvent) registration before createSSLCert() to
prevent a race where the ESP32 auto-reconnects during cert generation
and fires GOT_IP before the handler is attached, causing
onNetworkConnected() to never run and the TCP/HTTP API services to
never initialize when booting without USB serial.

Also call onNetworkConnected() from reconnectWiFi() on all platforms
(not just RP2040) as a safety net; it is already guarded by
APStartupComplete so it only runs once.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bugfix Pull request that fixes bugs cleanup Code cleanup or refactor triaged Reviewed by the team, has enough information and ready to work on now.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: network connection with t-deck [Bug]: Configuring wifi on LILYGO T-LoRa V2.1-1.6 makes node unreachable for clients

5 participants