fix(led): swap WiFi(play)/LAN(wifi+eth), LAN carrier via CLAWD_ETH_IFACE, faster alarm
- WifiLed drives play; LanLed drives wifi+eth pair (matches panel silkscreen) - hasLanCableCarrier(): CLAWD_ETH_IFACE-only carrier when set (reliable unplug) - LAN poll 1s; config.activated persisted for immediate setApps on boot/reconnect - setApps double vfdOn alarm after 50ms for slow OpenVFD - Clear activated + setSetup on credential errors - install.sh env comment for CLAWD_ETH_IFACE Made-with: Cursor
This commit is contained in:
@@ -171,6 +171,8 @@ CLAWD_LOG_FILE=1
|
|||||||
# CLAWD_DISABLE_BT=1
|
# CLAWD_DISABLE_BT=1
|
||||||
# OpenVFD sysfs 根路径(默认 /sys/class/leds/openvfd)
|
# OpenVFD sysfs 根路径(默认 /sys/class/leds/openvfd)
|
||||||
# CLAWD_OPENVFD_PATH=/sys/class/leds/openvfd
|
# CLAWD_OPENVFD_PATH=/sys/class/leds/openvfd
|
||||||
|
# LAN 灯跟 carrier:务必设为实际以太网口(如 end0),拔网线才能可靠熄灭
|
||||||
|
# CLAWD_ETH_IFACE=end0
|
||||||
EOF
|
EOF
|
||||||
info "环境变量文件已创建:$ENV_FILE ✓"
|
info "环境变量文件已创建:$ENV_FILE ✓"
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -83,8 +83,11 @@ class ClawClient {
|
|||||||
async start() {
|
async start() {
|
||||||
log.info('clawd', `启动中... 服务器 = ${this._cfg.server}`);
|
log.info('clawd', `启动中... 服务器 = ${this._cfg.server}`);
|
||||||
|
|
||||||
// 启动时全灭,WS 连接后由 _applyStatus() 按实际状态设置
|
// 启动时关 alarm;若本地已记为已激活,立即亮 pwr(不等首包 connected)
|
||||||
led.status.off();
|
led.status.off();
|
||||||
|
if (this._cfg.activated) {
|
||||||
|
led.status.setApps();
|
||||||
|
}
|
||||||
|
|
||||||
this._startSdNotify();
|
this._startSdNotify();
|
||||||
|
|
||||||
@@ -213,6 +216,9 @@ class ClawClient {
|
|||||||
this._backoff = 1_000;
|
this._backoff = 1_000;
|
||||||
this._wsFailCount = 0; // 连接成功,重置失败计数
|
this._wsFailCount = 0; // 连接成功,重置失败计数
|
||||||
this._hasEverConnected = true; // 标记已成功连接过
|
this._hasEverConnected = true; // 标记已成功连接过
|
||||||
|
if (this._cfg.activated) {
|
||||||
|
led.status.setApps();
|
||||||
|
}
|
||||||
this._sendConnect();
|
this._sendConnect();
|
||||||
this._startPing();
|
this._startPing();
|
||||||
// 显示由 _onConnected 根据 status 设置,不在此处提前 showTime
|
// 显示由 _onConnected 根据 status 设置,不在此处提前 showTime
|
||||||
@@ -332,12 +338,16 @@ class ClawClient {
|
|||||||
log.warn('clawd', '硬件指纹不符,清除凭证重新注册...');
|
log.warn('clawd', '硬件指纹不符,清除凭证重新注册...');
|
||||||
this._cfg.claw_id = null;
|
this._cfg.claw_id = null;
|
||||||
this._cfg.token = null;
|
this._cfg.token = null;
|
||||||
|
this._cfg.activated = false;
|
||||||
config.save(this._cfg);
|
config.save(this._cfg);
|
||||||
|
led.status.setSetup();
|
||||||
} else if (msg.msg && msg.msg.includes('invalid')) {
|
} else if (msg.msg && msg.msg.includes('invalid')) {
|
||||||
log.warn('clawd', '凭证无效,清除凭证重新注册...');
|
log.warn('clawd', '凭证无效,清除凭证重新注册...');
|
||||||
this._cfg.claw_id = null;
|
this._cfg.claw_id = null;
|
||||||
this._cfg.token = null;
|
this._cfg.token = null;
|
||||||
|
this._cfg.activated = false;
|
||||||
config.save(this._cfg);
|
config.save(this._cfg);
|
||||||
|
led.status.setSetup();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@@ -369,6 +379,8 @@ class ClawClient {
|
|||||||
|
|
||||||
_applyStatus(msg) {
|
_applyStatus(msg) {
|
||||||
if (msg.status === 'inactive') {
|
if (msg.status === 'inactive') {
|
||||||
|
this._cfg.activated = false;
|
||||||
|
config.save(this._cfg);
|
||||||
led.status.setSetup();
|
led.status.setSetup();
|
||||||
led.display.showPin(msg.pin);
|
led.display.showPin(msg.pin);
|
||||||
const id = String(this._cfg.claw_id || '').padEnd(6);
|
const id = String(this._cfg.claw_id || '').padEnd(6);
|
||||||
@@ -383,6 +395,8 @@ class ClawClient {
|
|||||||
log.info('clawd', '等待激活,心跳正常运行...');
|
log.info('clawd', '等待激活,心跳正常运行...');
|
||||||
this._updateOpenClawOrigin('0000');
|
this._updateOpenClawOrigin('0000');
|
||||||
} else {
|
} else {
|
||||||
|
this._cfg.activated = true;
|
||||||
|
config.save(this._cfg);
|
||||||
led.status.setApps();
|
led.status.setApps();
|
||||||
led.display.showTime();
|
led.display.showTime();
|
||||||
log.info('clawd', `已激活 claw_id = ${this._cfg.claw_id}`);
|
log.info('clawd', `已激活 claw_id = ${this._cfg.claw_id}`);
|
||||||
|
|||||||
@@ -17,6 +17,8 @@ const DEFAULTS = {
|
|||||||
claw_id: null,
|
claw_id: null,
|
||||||
token: null,
|
token: null,
|
||||||
heartbeat_interval: 30, // 秒
|
heartbeat_interval: 30, // 秒
|
||||||
|
/** 云端已激活:用于启动/重连时立即点亮 alarm(pwr),不等首包 connected */
|
||||||
|
activated: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
function load() {
|
function load() {
|
||||||
|
|||||||
25
lib/led.js
25
lib/led.js
@@ -2,15 +2,15 @@
|
|||||||
|
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const log = require('./logger');
|
const log = require('./logger');
|
||||||
const { hasWiredCarrier } = require('./network');
|
const { hasLanCableCarrier } = require('./network');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* OpenVFD 图标:/sys/class/leds/openvfd/led_on|led_off(写入图标名)。
|
* OpenVFD 图标:/sys/class/leds/openvfd/led_on|led_off(写入图标名)。
|
||||||
*
|
*
|
||||||
* 映射:
|
* 映射(与面板丝印一致:play=WiFi 状态,wifi+eth=有线链路):
|
||||||
* wifi + eth 同亮/同灭 → 产品 WiFi 灯
|
* play → 产品 WiFi 灯(配网逻辑 on/off/blink)
|
||||||
|
* wifi + eth 同亮/同灭 → LAN(有线插拔,见 hasLanCableCarrier / CLAWD_ETH_IFACE)
|
||||||
* alarm → pwr(SETUP=灭 / APPS=亮)
|
* alarm → pwr(SETUP=灭 / APPS=亮)
|
||||||
* play → lan(有线 carrier)
|
|
||||||
* BT → 无 sysfs,仅日志
|
* BT → 无 sysfs,仅日志
|
||||||
*
|
*
|
||||||
* 数码管(AP/Conn/时间等):仍仅 debug 输出,不接 sysfs。
|
* 数码管(AP/Conn/时间等):仍仅 debug 输出,不接 sysfs。
|
||||||
@@ -19,7 +19,7 @@ const { hasWiredCarrier } = require('./network');
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
const BLINK_INTERVAL_MS = 500;
|
const BLINK_INTERVAL_MS = 500;
|
||||||
const LAN_POLL_MS = 3000;
|
const LAN_POLL_MS = 1000;
|
||||||
|
|
||||||
const VFD_BASE = process.env.CLAWD_OPENVFD_PATH || '/sys/class/leds/openvfd';
|
const VFD_BASE = process.env.CLAWD_OPENVFD_PATH || '/sys/class/leds/openvfd';
|
||||||
|
|
||||||
@@ -100,8 +100,9 @@ class WifiLed {
|
|||||||
|
|
||||||
_write(val) {
|
_write(val) {
|
||||||
const on = !!val;
|
const on = !!val;
|
||||||
log.debug('led', `[vfd] WiFi(wifi+eth)<= ${on ? 1 : 0}`);
|
log.debug('led', `[vfd] WiFi(play)<= ${on ? 1 : 0}`);
|
||||||
vfdWifiPair(on);
|
if (on) vfdOn('play');
|
||||||
|
else vfdOff('play');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -231,6 +232,8 @@ class StatusLed {
|
|||||||
|
|
||||||
setApps() {
|
setApps() {
|
||||||
vfdOn('alarm');
|
vfdOn('alarm');
|
||||||
|
// 部分 OpenVFD 驱动单次写入生效慢,短延迟再写一次
|
||||||
|
setTimeout(() => vfdOn('alarm'), 50);
|
||||||
log.debug('led', '[vfd] alarm(pwr)<= 1');
|
log.debug('led', '[vfd] alarm(pwr)<= 1');
|
||||||
log.info('led', '状态灯 → APPS(已激活)');
|
log.info('led', '状态灯 → APPS(已激活)');
|
||||||
}
|
}
|
||||||
@@ -257,20 +260,20 @@ class LanLed {
|
|||||||
clearInterval(this._timer);
|
clearInterval(this._timer);
|
||||||
this._timer = null;
|
this._timer = null;
|
||||||
}
|
}
|
||||||
vfdOff('play');
|
vfdWifiPair(false);
|
||||||
this._current = null;
|
this._current = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
_sync() {
|
_sync() {
|
||||||
const up = hasWiredCarrier();
|
const up = hasLanCableCarrier();
|
||||||
if (up) {
|
if (up) {
|
||||||
if (this._current !== 'on') {
|
if (this._current !== 'on') {
|
||||||
vfdOn('play');
|
vfdWifiPair(true);
|
||||||
this._current = 'on';
|
this._current = 'on';
|
||||||
log.info('led', 'LAN(有线 carrier)→ 亮');
|
log.info('led', 'LAN(有线 carrier)→ 亮');
|
||||||
}
|
}
|
||||||
} else if (this._current !== 'off') {
|
} else if (this._current !== 'off') {
|
||||||
vfdOff('play');
|
vfdWifiPair(false);
|
||||||
this._current = 'off';
|
this._current = 'off';
|
||||||
log.info('led', 'LAN(有线 carrier)→ 灭');
|
log.info('led', 'LAN(有线 carrier)→ 灭');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -62,6 +62,22 @@ function hasWiredCarrier() {
|
|||||||
return getWiredIfaceWithCarrier() !== null;
|
return getWiredIfaceWithCarrier() !== null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* LAN 面板灯专用:若设置 CLAWD_ETH_IFACE,只认该口 carrier(拔网线必灭);
|
||||||
|
* 未设置时退回 hasWiredCarrier()(可能受其它网口影响,建议在 box 上配置 end0 等)。
|
||||||
|
*/
|
||||||
|
function hasLanCableCarrier() {
|
||||||
|
const explicit = process.env.CLAWD_ETH_IFACE;
|
||||||
|
if (explicit) {
|
||||||
|
try {
|
||||||
|
return fs.readFileSync(`/sys/class/net/${explicit}/carrier`, 'utf8').trim() === '1';
|
||||||
|
} catch (_) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return hasWiredCarrier();
|
||||||
|
}
|
||||||
|
|
||||||
function _tryPingInternet() {
|
function _tryPingInternet() {
|
||||||
try {
|
try {
|
||||||
run('ping -c 1 -W 3 8.8.8.8');
|
run('ping -c 1 -W 3 8.8.8.8');
|
||||||
@@ -312,6 +328,7 @@ function getLocalIps() {
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
hasInternet,
|
hasInternet,
|
||||||
hasWiredCarrier,
|
hasWiredCarrier,
|
||||||
|
hasLanCableCarrier,
|
||||||
hasWiredInternetProbe,
|
hasWiredInternetProbe,
|
||||||
getWiredIfaceWithCarrier,
|
getWiredIfaceWithCarrier,
|
||||||
hasSavedWifiConnection,
|
hasSavedWifiConnection,
|
||||||
|
|||||||
Reference in New Issue
Block a user