Skip to content

Thermal + WiFi reliability changes - #39

Open
webdevbrian wants to merge 2 commits into
EyeTrackVR:mainfrom
webdevbrian:fix/wifi-tx-power-and-mesh-scan
Open

Thermal + WiFi reliability changes#39
webdevbrian wants to merge 2 commits into
EyeTrackVR:mainfrom
webdevbrian:fix/wifi-tx-power-and-mesh-scan

Conversation

@webdevbrian

@webdevbrian webdevbrian commented Aug 3, 2026

Copy link
Copy Markdown

Thermal + WiFi reliability changes

The following changes have been proven to locally drop temperatures (camera OV3660 and ESP monitored) from 155F+ to 110F, still with amazing performance and reliability with no visual degradation in tracking under same real-world scenarios locally

IMG_2441

Summary

Changes aimed at reducing heat and making WiFi association deterministic on mesh networks.

Two of these are bugs where an existing setting silently did nothing:

  • esp_wifi_set_max_tx_power() is never called anywhere in the firmware, so every board has always transmitted at the PHY default of 20 dBm — even though WiFiTxPower_t already loads a 13 dBm default from NVS, saves it, and exposes it through get_config. Both getWiFiTxPowerConfig() and setWiFiTxPower() had zero callers.
  • CONFIG_CAMERA_WIFI_XCLK_FREQ is dead on any build with UVC compiled in, because the camera clock was selected with #if at compile time rather than from the mode the device actually runs in.
File Affects
components/wifiManager/wifiManager/wifiManager.cpp All boards
components/wifiManager/wifiManager/wifiManager.hpp All boards
components/CameraManager/CameraManager/CameraManager.cpp All boards with UVC compiled in
boards/seed_studio/xiao_esp32s3 XIAO ESP32S3 only

Changes

1. Apply the configured WiFi TX power

Adds WiFiManager::ApplyTxPower(), called after each esp_wifi_start() on the station paths. It must come after start — calling it earlier is silently ignored by the driver. The value is clamped to the driver's valid 8–84 range (0.25 dBm units) and the applied result is read back and logged.

20 dBm → 13 dBm is a 7 dB cut: roughly 5× less radiated power and a substantial reduction in PA dissipation.

AP mode is deliberately left at full power — it's the setup-fallback hotspot where range matters, and it doesn't run in steady state.

2. WIFI_FAST_SCANWIFI_ALL_CHANNEL_SCAN

SetCredentials() sets sort_method = WIFI_CONNECT_AP_BY_SIGNAL with the comment "Connect to strongest signal" — but scan_method was WIFI_FAST_SCAN. Per the IDF header:

WIFI_FAST_SCAN = 0,      /**< Do fast scan, scan will end after find SSID match AP */
WIFI_ALL_CHANNEL_SCAN,   /**< All channel scan, scan will end after scan all the channel */

Fast scan stops at the first SSID match, so there's no scan list left to sort and sort_method is a no-op. On mesh/repeater networks the device associates with whichever node answers the probe first, which varies between boots. On my test network the same SSID was visible at −50 dBm and −84 dBm; landing on the far node makes association unreliable.

Costs ~1–2 s more at boot.

3. Retry budget and timeouts

  • EXAMPLE_ESP_MAXIMUM_RETRY 3 → 5
  • New WIFI_RETRY_BACKOFF_MS = 300 ms between attempts (previously all retries could fire inside a second, which isn't a real attempt)
  • Connect wait timeouts 8 s / 10 s → 18 s

Important

Changes 2 and 3 are coupled — please don't merge one without the other. An all-channel scan costs ~2–3 s per attempt, so keeping the old 8 s/10 s windows would expire mid-retry and fall through to AP-mode fallback sooner than before the change.

4. Select camera XCLK from the runtime mode, not the compile flag

setupCameraPinout() chose the sensor clock like this:

int xclk_freq_hz = CONFIG_CAMERA_WIFI_XCLK_FREQ;
#if CONFIG_GENERAL_INCLUDE_UVC_MODE
    xclk_freq_hz = CONFIG_CAMERA_USB_XCLK_FREQ;   // compile-time, always wins
#endif

Because that's #if rather than a runtime check, any build with UVC support compiled in ran the sensor at the USB clock even while the device was in WiFi mode. CONFIG_CAMERA_WIFI_XCLK_FREQ was effectively unreachable on those builds, and boards paid the higher sensor clock — and the resulting heat — for a mode they weren't in.

Now checks the stored device mode. Mode is loaded before the camera is set up, and switching modes already requires a reboot, so it's settled by then. The selected frequency is also logged, since previously there was no way to confirm from outside what the sensor was actually running at.

5. XIAO ESP32S3: CPU 240 MHz → 160 MHz

Scoped to boards/seed_studio/xiao_esp32s3, so only that board's artifact changes.

Worth flagging for anyone editing board files later — the obvious one-line edit does not work:

-CONFIG_ESP32S3_DEFAULT_CPU_FREQ_240=y
+CONFIG_ESP32S3_DEFAULT_CPU_FREQ_160=y

That still builds at 240 MHz, because:

  1. CONFIG_ESP32S3_DEFAULT_CPU_FREQ_* is a legacy alias; the authoritative symbols are CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ*, and setting the alias doesn't propagate.
  2. switchBoardType.py merges with {**base, **board} — a dict merge by exact key. ..._240 and ..._160 are different keys, so setting _160=y leaves base_defaults' _240=y in place.

Both _240 symbols therefore have to be explicitly =n. That's the six lines in the diff, with a comment in the board file explaining why.


Testing

Verified on Seeed XIAO ESP32S3 Sense (OV3660), ESP-IDF v5.4.4, against a mesh network (two APs, same SSID, −50 dBm and −84 dBm).

WiFi

Boot log confirms TX power now applies and the device still associates fine at reduced power:

I (3348) [WIFI_MANAGER]: TX power set to 52 (13.00 dBm)
I (6876) [WIFI_MANAGER]: got ip:192.168.1.85
I (6880) [WIFI_MANAGER]: connected to ap SSID:<redacted>

Reset-to-connected soak, 8/8 cycles connected, ~9 s each with no variance:

t=3.1s  initialized
t=6.2s  connecting
t=9.3s  connected

Camera XCLK

In WiFi mode the sensor clock drops from 23 MHz to 16.5 MHz:

I (2238) [CAMERA_MANAGER]: [Camera]: XCLK set to 16500000 Hz

I built a control image without this change and compared cam_hal warnings on the same hardware across repeated boots:

XCLK NO-SOI FB-OVF
Without change 23 MHz
With change 16.5 MHz 0

So frame corruption decreases — the lower pixel clock leaves more DMA headroom, which is why the frame-buffer overflows disappear entirely.

CPU frequency

Verified against the compiled output rather than sdkconfig, since confgen has the final say:

build/config/sdkconfig.h:605:#define CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ 160

Review notes

Behaviour change for existing users (TX power). Anyone with a stored txpower value will now actually get it, defaulting to 13 dBm instead of the current effective 20 dBm. That's the intent, but it is a change in shipped behaviour. The value is already runtime-configurable — only the plumbing is new. Happy to change the default if 13 dBm is considered too aggressive.

Behaviour change for OV2640 boards (camera XCLK). On boards with UVC compiled in, WiFi mode now runs the sensor at CAMERA_WIFI_XCLK_FREQ (16.5 MHz by default) instead of the USB value. That's what the config was always meant to do, but it may reduce achievable framerate on OV2640 hardware. I only have an OV3660 to test on. If a lower clock proves too slow for some board, the right fix is raising that board's CAMERA_WIFI_XCLK_FREQ rather than reverting to the compile-time behaviour.

Only hardware-tested on esp32s3. These changes compile-affect all 12 boards in the CI matrix, including the three esp32 targets, which I have no hardware for. Relying on CI for those.

No baseline for change 2. I did not capture a failure rate with WIFI_FAST_SCAN before making the change, so this isn't proven to fix a specific field report. The defect is confirmed against the IDF header; the improvement is reasoned rather than measured. Post-change is 8/8 as above.


Not included

HIL harness defaults produce phantom failures. tests/.env.example ships SWITCH_MODE_REBOOT_TIME=5; USB re-enumeration alone measured 2.8 s, and the board isn't responsive for several seconds after that because the serial task runs at priority 1 and gets starved during WiFi association. Compounding it, OpenIrisDeviceManager.get_device() silently returns a stale dead handle when the port changes instead of raising or retrying, so one timing miss cascades. Raising the default to 8 took a run from 43 failed / 17 passed to 60 passed / 1 skipped with no firmware change.

webdevbrian and others added 2 commits August 3, 2026 11:07
esp_wifi_set_max_tx_power() was never called anywhere in the firmware, so the
radio always ran at the PHY default of 20 dBm - despite WiFiTxPower_t storing a
13 dBm default in NVS and exposing it through get_config. Both
getWiFiTxPowerConfig() and setWiFiTxPower() had zero callers.

Add WiFiManager::ApplyTxPower(), called after esp_wifi_start() on the station
paths; calling it before start is silently ignored by the driver. AP mode is
left at full power since it is the setup-fallback hotspot where range matters.

Switch scan_method to WIFI_ALL_CHANNEL_SCAN. The existing
sort_method = WIFI_CONNECT_AP_BY_SIGNAL was a no-op under WIFI_FAST_SCAN, which
ends at the first SSID match - on a mesh network that means associating with
whichever node answers first regardless of signal strength.

The all-channel scan costs ~2-3s per attempt, so raise the retry budget (3 -> 5,
plus a 300ms backoff) and the connect timeouts (8s/10s -> 18s) to match. Without
that the old windows would expire mid-retry and fall through to AP-mode fallback
sooner than before the change.

Drop the XIAO ESP32S3 to 160 MHz. CONFIG_ESP32S3_DEFAULT_CPU_FREQ_* is a legacy
alias and switchBoardType.py merges base and board configs by exact key, so the
240 symbols have to be explicitly disabled rather than just omitted.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
setupCameraPinout() picked the XCLK frequency with `#if
CONFIG_GENERAL_INCLUDE_UVC_MODE`, so any build with UVC support compiled in ran
the sensor at CAMERA_USB_XCLK_FREQ even when the device was actually running in
WiFi mode. CAMERA_WIFI_XCLK_FREQ was therefore dead on those builds, and boards
paid the higher sensor clock - and the extra heat - for a mode they were not in.

Check the stored device mode instead. Mode is loaded before the camera is set up,
and switching modes already requires a reboot, so it is settled by then.

Also log the selected frequency, since the value that ends up in use was
previously impossible to confirm from the outside.

Measured on a XIAO ESP32S3 Sense (OV3660) in WiFi mode: XCLK drops 23MHz -> 16.5MHz.
Frame corruption warnings from cam_hal also decreased - 2x NO-SOI plus 4x FB-OVF
before, consistently 1x NO-SOI after, across repeated boots.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant