fix(led,provision): AP forces WiFi(play) off; LAN uses carrier+operstate
- Monitor: every tick in ap state led.off() so play never stays on with hotspot - hasLanCableCarrier: _ifacePhysicalLinkUp (carrier=1 and operstate not down) - When end0/eth0 exist but link down, return false (no fallback to hasWiredCarrier) - LAN poll 500ms Made-with: Cursor
This commit is contained in:
@@ -19,7 +19,7 @@ const { hasLanCableCarrier } = require('./network');
|
||||
*/
|
||||
|
||||
const BLINK_INTERVAL_MS = 500;
|
||||
const LAN_POLL_MS = 1000;
|
||||
const LAN_POLL_MS = 500;
|
||||
|
||||
const VFD_BASE = process.env.CLAWD_OPENVFD_PATH || '/sys/class/leds/openvfd';
|
||||
|
||||
|
||||
@@ -63,28 +63,47 @@ function hasWiredCarrier() {
|
||||
}
|
||||
|
||||
/**
|
||||
* LAN 面板灯专用:只反映「板载以太网插线」,与 WiFi 无关。
|
||||
* - CLAWD_ETH_IFACE:只用该口 carrier
|
||||
* - 否则每次优先读 end0、eth0(RK 等板型固定名),避免用「扫描到的第一个 carrier 口」
|
||||
* (该口会随 WiFi 断开/连接、NM 重排而变化,导致 LAN 灯跟 WiFi 联动)
|
||||
* - 若无 end0/eth0 节点再退回 hasWiredCarrier()
|
||||
* 物理链路是否 up:carrier + operstate 双读,避免单读 carrier 拔线不更新、或与 WiFi 状态不同步的误判。
|
||||
*/
|
||||
function _ifacePhysicalLinkUp(iface) {
|
||||
try {
|
||||
const base = `/sys/class/net/${iface}`;
|
||||
const carrier = fs.readFileSync(`${base}/carrier`, 'utf8').trim();
|
||||
if (carrier !== '1') return false;
|
||||
let oper = 'unknown';
|
||||
try {
|
||||
oper = fs.readFileSync(`${base}/operstate`, 'utf8').trim();
|
||||
} catch (_) {}
|
||||
if (oper === 'down' || oper === 'lowerlayerdown') return false;
|
||||
return true;
|
||||
} catch (_) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* LAN 面板灯:只反映指定/板载以太网 RJ45 链路,与 WiFi 无关。
|
||||
* - CLAWD_ETH_IFACE:只读该口
|
||||
* - 否则只认 end0、eth0(存在则仅用其 sysfs,链路 down 即灭,不再退回「任一带 carrier 口」以免跟 WiFi 耦合)
|
||||
* - 无 end0/eth0 节点时(开发机)退回 hasWiredCarrier()
|
||||
*/
|
||||
function hasLanCableCarrier() {
|
||||
const explicit = process.env.CLAWD_ETH_IFACE;
|
||||
if (explicit) {
|
||||
try {
|
||||
return fs.readFileSync(`/sys/class/net/${explicit}/carrier`, 'utf8').trim() === '1';
|
||||
return fs.existsSync(`/sys/class/net/${explicit}`) && _ifacePhysicalLinkUp(explicit);
|
||||
} catch (_) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
let hasBoardIface = false;
|
||||
for (const n of ['end0', 'eth0']) {
|
||||
try {
|
||||
if (!fs.existsSync(`/sys/class/net/${n}`)) continue;
|
||||
return fs.readFileSync(`/sys/class/net/${n}/carrier`, 'utf8').trim() === '1';
|
||||
} catch (_) {}
|
||||
hasBoardIface = true;
|
||||
if (_ifacePhysicalLinkUp(n)) return true;
|
||||
}
|
||||
if (hasBoardIface) return false;
|
||||
|
||||
return hasWiredCarrier();
|
||||
}
|
||||
|
||||
@@ -199,15 +199,16 @@ class ProvisionManager extends EventEmitter {
|
||||
this.emit('network-ready');
|
||||
}
|
||||
|
||||
// WiFi 灯:只在 STA 模式下反映互联网连通性;AP 模式下始终熄灭
|
||||
if (this._state === 'sta') {
|
||||
// 产品 WiFi 灯(OpenVFD play):AP 全程强制熄灭,避免与其它逻辑竞态导致误亮
|
||||
if (this._state === 'ap') {
|
||||
led.off();
|
||||
} else if (this._state === 'sta') {
|
||||
if (hasInternet()) {
|
||||
led.on();
|
||||
} else {
|
||||
led.off(); // WiFi 已连接但无互联网
|
||||
led.off(); // STA 已连热点但无互联网
|
||||
}
|
||||
}
|
||||
// AP 模式下 led 已在 _enterAP() 中熄灭,无需重复操作
|
||||
}, MONITOR_INTERVAL_MS);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user