diff --git a/install.sh b/install.sh index 134cac8..ef721b3 100644 --- a/install.sh +++ b/install.sh @@ -171,6 +171,8 @@ CLAWD_LOG_FILE=1 # CLAWD_DISABLE_BT=1 # OpenVFD sysfs 根路径(默认 /sys/class/leds/openvfd) # CLAWD_OPENVFD_PATH=/sys/class/leds/openvfd +# LAN 灯跟 carrier:务必设为实际以太网口(如 end0),拔网线才能可靠熄灭 +# CLAWD_ETH_IFACE=end0 EOF info "环境变量文件已创建:$ENV_FILE ✓" fi diff --git a/lib/client.js b/lib/client.js index c77a300..4257d97 100644 --- a/lib/client.js +++ b/lib/client.js @@ -83,8 +83,11 @@ class ClawClient { async start() { log.info('clawd', `启动中... 服务器 = ${this._cfg.server}`); - // 启动时全灭,WS 连接后由 _applyStatus() 按实际状态设置 + // 启动时关 alarm;若本地已记为已激活,立即亮 pwr(不等首包 connected) led.status.off(); + if (this._cfg.activated) { + led.status.setApps(); + } this._startSdNotify(); @@ -213,6 +216,9 @@ class ClawClient { this._backoff = 1_000; this._wsFailCount = 0; // 连接成功,重置失败计数 this._hasEverConnected = true; // 标记已成功连接过 + if (this._cfg.activated) { + led.status.setApps(); + } this._sendConnect(); this._startPing(); // 显示由 _onConnected 根据 status 设置,不在此处提前 showTime @@ -332,12 +338,16 @@ class ClawClient { log.warn('clawd', '硬件指纹不符,清除凭证重新注册...'); this._cfg.claw_id = null; this._cfg.token = null; + this._cfg.activated = false; config.save(this._cfg); + led.status.setSetup(); } else if (msg.msg && msg.msg.includes('invalid')) { log.warn('clawd', '凭证无效,清除凭证重新注册...'); this._cfg.claw_id = null; this._cfg.token = null; + this._cfg.activated = false; config.save(this._cfg); + led.status.setSetup(); } break; default: @@ -369,6 +379,8 @@ class ClawClient { _applyStatus(msg) { if (msg.status === 'inactive') { + this._cfg.activated = false; + config.save(this._cfg); led.status.setSetup(); led.display.showPin(msg.pin); const id = String(this._cfg.claw_id || '').padEnd(6); @@ -383,6 +395,8 @@ class ClawClient { log.info('clawd', '等待激活,心跳正常运行...'); this._updateOpenClawOrigin('0000'); } else { + this._cfg.activated = true; + config.save(this._cfg); led.status.setApps(); led.display.showTime(); log.info('clawd', `已激活 claw_id = ${this._cfg.claw_id}`); diff --git a/lib/config.js b/lib/config.js index 7ceea14..536e6ad 100644 --- a/lib/config.js +++ b/lib/config.js @@ -17,6 +17,8 @@ const DEFAULTS = { claw_id: null, token: null, heartbeat_interval: 30, // 秒 + /** 云端已激活:用于启动/重连时立即点亮 alarm(pwr),不等首包 connected */ + activated: false, }; function load() { diff --git a/lib/led.js b/lib/led.js index 6294594..ea71fbb 100644 --- a/lib/led.js +++ b/lib/led.js @@ -2,15 +2,15 @@ const fs = require('fs'); const log = require('./logger'); -const { hasWiredCarrier } = require('./network'); +const { hasLanCableCarrier } = require('./network'); /** * OpenVFD 图标:/sys/class/leds/openvfd/led_on|led_off(写入图标名)。 * - * 映射: - * wifi + eth 同亮/同灭 → 产品 WiFi 灯 + * 映射(与面板丝印一致:play=WiFi 状态,wifi+eth=有线链路): + * play → 产品 WiFi 灯(配网逻辑 on/off/blink) + * wifi + eth 同亮/同灭 → LAN(有线插拔,见 hasLanCableCarrier / CLAWD_ETH_IFACE) * alarm → pwr(SETUP=灭 / APPS=亮) - * play → lan(有线 carrier) * BT → 无 sysfs,仅日志 * * 数码管(AP/Conn/时间等):仍仅 debug 输出,不接 sysfs。 @@ -19,7 +19,7 @@ const { hasWiredCarrier } = require('./network'); */ 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'; @@ -100,8 +100,9 @@ class WifiLed { _write(val) { const on = !!val; - log.debug('led', `[vfd] WiFi(wifi+eth)<= ${on ? 1 : 0}`); - vfdWifiPair(on); + log.debug('led', `[vfd] WiFi(play)<= ${on ? 1 : 0}`); + if (on) vfdOn('play'); + else vfdOff('play'); } } @@ -231,6 +232,8 @@ class StatusLed { setApps() { vfdOn('alarm'); + // 部分 OpenVFD 驱动单次写入生效慢,短延迟再写一次 + setTimeout(() => vfdOn('alarm'), 50); log.debug('led', '[vfd] alarm(pwr)<= 1'); log.info('led', '状态灯 → APPS(已激活)'); } @@ -257,20 +260,20 @@ class LanLed { clearInterval(this._timer); this._timer = null; } - vfdOff('play'); + vfdWifiPair(false); this._current = null; } _sync() { - const up = hasWiredCarrier(); + const up = hasLanCableCarrier(); if (up) { if (this._current !== 'on') { - vfdOn('play'); + vfdWifiPair(true); this._current = 'on'; log.info('led', 'LAN(有线 carrier)→ 亮'); } } else if (this._current !== 'off') { - vfdOff('play'); + vfdWifiPair(false); this._current = 'off'; log.info('led', 'LAN(有线 carrier)→ 灭'); } diff --git a/lib/network.js b/lib/network.js index a93e441..f9f58f1 100644 --- a/lib/network.js +++ b/lib/network.js @@ -62,6 +62,22 @@ function hasWiredCarrier() { 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() { try { run('ping -c 1 -W 3 8.8.8.8'); @@ -312,6 +328,7 @@ function getLocalIps() { module.exports = { hasInternet, hasWiredCarrier, + hasLanCableCarrier, hasWiredInternetProbe, getWiredIfaceWithCarrier, hasSavedWifiConnection,