fix: wait for NM auto-reconnect before starting AP on reboot

After WiFi is configured and device reboots, NetworkManager needs
a few seconds to auto-connect to saved WiFi. Without waiting,
AP starts immediately and occupies wlan0, preventing NM reconnect.

- Add hasSavedWifiConnection() to check for saved WiFi profiles
- Wait up to 20s for NM auto-connect before falling back to AP
- First boot (no saved WiFi) still starts AP immediately

Made-with: Cursor
This commit is contained in:
stswangzhiping
2026-03-16 12:27:25 +08:00
parent b42e59fab8
commit f58db93b64
4 changed files with 89 additions and 23 deletions

View File

@@ -2,16 +2,19 @@
const EventEmitter = require('events');
const log = require('./logger');
const { hasInternet, isWifiStaConnected, startAP, stopAP, connectWifi, AP_IP } = require('./network');
const { hasInternet, hasSavedWifiConnection, isWifiStaConnected, startAP, stopAP, connectWifi, AP_IP } = require('./network');
const { DnsHijack } = require('./dns-hijack');
const { CaptiveServer } = require('./captive-server');
const MONITOR_INTERVAL_MS = 30_000;
const BOOT_WAIT_MAX_MS = 20_000; // 等待 NM 自动连接的最大时间
const BOOT_POLL_MS = 2_000; // 轮询间隔
/**
* AP 常驻配网管理器。
*
* 规则:
* - 启动时:有已保存 WiFi 配置 → 等 NM 自动连接(最多 20 秒)
* - wlan0 没有以 STA 模式连接 WiFi → 开 AP + DNS 劫持 + HTTP 配网页
* - 用户提交 WiFi 凭证 → 关 AP → 尝试连接 → 失败则重新开 AP
* - 运行中 WiFi 断开 → 自动重新开 AP
@@ -27,20 +30,62 @@ class ProvisionManager extends EventEmitter {
this._monitorTimer = null;
}
start() {
async start() {
// WiFi 已连接 → 直接进入 STA 模式
if (isWifiStaConnected()) {
this._state = 'sta';
log.info('provision', 'WiFi STA 已连接AP 不启动');
} else {
this._enterAP();
this._emitNetworkReady();
this._startMonitor();
return;
}
// 有已保存的 WiFi 配置 → 等 NM 自动连接(重启场景)
if (hasSavedWifiConnection()) {
log.info('provision', '发现已保存的 WiFi 配置,等待 NetworkManager 自动连接...');
const connected = await this._waitForWifiConnect();
if (connected) {
this._state = 'sta';
log.info('provision', 'WiFi 自动连接成功AP 不启动');
this._emitNetworkReady();
this._startMonitor();
return;
}
log.warn('provision', 'WiFi 自动连接超时,启动 AP');
}
// 没有已保存 WiFi 或等待超时 → 开 AP
this._enterAP();
this._startMonitor();
if (hasInternet()) {
this.emit('network-ready');
this._emitNetworkReady();
}
}
_emitNetworkReady() {
if (hasInternet()) this.emit('network-ready');
}
/**
* 轮询等待 NM 自动连接 WiFi最多等 BOOT_WAIT_MAX_MS
*/
_waitForWifiConnect() {
return new Promise(resolve => {
let elapsed = 0;
const timer = setInterval(() => {
elapsed += BOOT_POLL_MS;
if (isWifiStaConnected()) {
clearInterval(timer);
resolve(true);
} else if (elapsed >= BOOT_WAIT_MAX_MS) {
clearInterval(timer);
resolve(false);
}
}, BOOT_POLL_MS);
});
}
stop() {
this._stopMonitor();
this._stopAll();