feat: 添加蓝牙指示灯(b6)控制
led.js: 新增 BtLed 类,路径 /sys/devices/platform/openvfd/attr/b6 - blink() AP 配网进行中 - on() 配网成功 / WiFi 已连接 - off() 蓝牙不工作 / 初始/停止状态 provisioning.js: 各配网状态同步驱动 BT 灯 - AP 模式 / 等待自动重连 → 闪烁 - WiFi 连接成功 → 常亮 - stop() → 熄灭 Made-with: Cursor
This commit is contained in:
83
lib/led.js
83
lib/led.js
@@ -12,15 +12,21 @@ const log = require('./logger');
|
||||
* - WiFi 连接中(正在尝试) → 闪烁
|
||||
* - WiFi 未连接 / 无互联网 → 熄灭
|
||||
*
|
||||
* BT 灯 (b6): 1 = 亮, 0 = 灭(正逻辑)
|
||||
* - BLE 配网进行中 → 闪烁
|
||||
* - BLE 配网成功 → 常亮
|
||||
* - 蓝牙不工作 → 熄灭
|
||||
*
|
||||
* SETUP 灯 (b2): 0 = 亮, 1 = 灭(反逻辑,与 APPS 互斥)
|
||||
* APPS 灯 (b1): 0 = 亮, 1 = 灭(反逻辑,与 SETUP 互斥)
|
||||
* - claw 未激活 → SETUP 亮,APPS 灭
|
||||
* - claw 已激活 → APPS 亮,SETUP 灭
|
||||
*/
|
||||
|
||||
const LED_PATH = process.env.CLAWD_LED_PATH || '/sys/devices/platform/openvfd/attr/b5';
|
||||
const SETUP_LED_PATH = '/sys/devices/platform/openvfd/attr/b1'; // 物理 SETUP 灯
|
||||
const APPS_LED_PATH = '/sys/devices/platform/openvfd/attr/b2'; // 物理 APPS 灯
|
||||
const LED_PATH = process.env.CLAWD_LED_PATH || '/sys/devices/platform/openvfd/attr/b5';
|
||||
const BT_LED_PATH = process.env.CLAWD_BT_LED_PATH || '/sys/devices/platform/openvfd/attr/b6';
|
||||
const SETUP_LED_PATH = '/sys/devices/platform/openvfd/attr/b1'; // 物理 SETUP 灯
|
||||
const APPS_LED_PATH = '/sys/devices/platform/openvfd/attr/b2'; // 物理 APPS 灯
|
||||
const BLINK_INTERVAL_MS = 500; // 闪烁间隔(ms)
|
||||
|
||||
class WifiLed {
|
||||
@@ -87,6 +93,76 @@ class WifiLed {
|
||||
}
|
||||
}
|
||||
|
||||
// ── 蓝牙指示灯 ───────────────────────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
* BT 指示灯(b6)正逻辑:1 = 亮,0 = 灭。
|
||||
* blink() — BLE 配网进行中
|
||||
* on() — BLE 配网成功 / 蓝牙功能正常
|
||||
* off() — 蓝牙不工作
|
||||
*/
|
||||
class BtLed {
|
||||
constructor() {
|
||||
this._blinkTimer = null;
|
||||
this._blinkState = false;
|
||||
this._current = null; // 'on' | 'off' | 'blink'
|
||||
}
|
||||
|
||||
/** 常亮(配网成功) */
|
||||
on() {
|
||||
if (this._current === 'on') return;
|
||||
this._stopBlink();
|
||||
this._write(1);
|
||||
this._current = 'on';
|
||||
log.info('led', 'BT 指示灯 → 常亮');
|
||||
}
|
||||
|
||||
/** 熄灭(蓝牙不工作) */
|
||||
off() {
|
||||
if (this._current === 'off') return;
|
||||
this._stopBlink();
|
||||
this._write(0);
|
||||
this._current = 'off';
|
||||
log.info('led', 'BT 指示灯 → 熄灭');
|
||||
}
|
||||
|
||||
/** 闪烁(BLE 配网进行中) */
|
||||
blink(intervalMs = BLINK_INTERVAL_MS) {
|
||||
if (this._current === 'blink') return;
|
||||
this._stopBlink();
|
||||
this._blinkState = true;
|
||||
this._write(1);
|
||||
this._blinkTimer = setInterval(() => {
|
||||
this._blinkState = !this._blinkState;
|
||||
this._write(this._blinkState ? 1 : 0);
|
||||
}, intervalMs);
|
||||
this._current = 'blink';
|
||||
log.info('led', 'BT 指示灯 → 闪烁');
|
||||
}
|
||||
|
||||
/** 释放资源,关灯 */
|
||||
destroy() {
|
||||
this._stopBlink();
|
||||
this._write(0);
|
||||
this._current = 'off';
|
||||
}
|
||||
|
||||
_stopBlink() {
|
||||
if (this._blinkTimer) {
|
||||
clearInterval(this._blinkTimer);
|
||||
this._blinkTimer = null;
|
||||
}
|
||||
}
|
||||
|
||||
_write(val) {
|
||||
try {
|
||||
fs.writeFileSync(BT_LED_PATH, String(val));
|
||||
} catch (e) {
|
||||
log.warn('led', `写入失败 (${BT_LED_PATH}): ${e.message}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ── VFD 显示屏 ────────────────────────────────────────────────────────────────
|
||||
|
||||
const DISPLAY_PATH = '/sys/devices/platform/openvfd/attr/led';
|
||||
@@ -207,5 +283,6 @@ class StatusLed {
|
||||
|
||||
// 全局单例,整个进程共用
|
||||
module.exports = new WifiLed();
|
||||
module.exports.bt = new BtLed();
|
||||
module.exports.status = new StatusLed();
|
||||
module.exports.display = new Display();
|
||||
|
||||
@@ -35,12 +35,14 @@ class ProvisionManager extends EventEmitter {
|
||||
isApMode() { return this._state === 'ap'; }
|
||||
|
||||
async start() {
|
||||
led.off(); // 初始状态:灭灯
|
||||
led.off(); // WiFi 灯初始状态:熄灭
|
||||
led.bt.off(); // BT 灯初始状态:熄灭
|
||||
|
||||
// WiFi STA 已连接 → 直接进入 STA 模式
|
||||
if (isWifiStaConnected()) {
|
||||
this._state = 'sta';
|
||||
log.info('provision', 'WiFi STA 已连接,AP 不启动');
|
||||
led.bt.on(); // 已配网,BT 灯常亮
|
||||
this._emitNetworkReady();
|
||||
this._startMonitor();
|
||||
return;
|
||||
@@ -60,11 +62,13 @@ class ProvisionManager extends EventEmitter {
|
||||
// 无网:有已保存的 WiFi 配置 → 等 NM 自动连接(重启场景)
|
||||
if (hasSavedWifiConnection()) {
|
||||
log.info('provision', '发现已保存的 WiFi 配置,等待 NetworkManager 自动连接...');
|
||||
led.blink(); // 等待自动重连期间闪烁
|
||||
led.blink(); // WiFi 灯:等待自动重连期间闪烁
|
||||
led.bt.blink(); // BT 灯:等待配网期间闪烁
|
||||
const connected = await this._waitForWifiConnect();
|
||||
if (connected) {
|
||||
this._state = 'sta';
|
||||
log.info('provision', 'WiFi 自动连接成功,AP 不启动');
|
||||
led.bt.on(); // 自动重连成功,BT 灯常亮
|
||||
this._emitNetworkReady();
|
||||
this._startMonitor();
|
||||
return;
|
||||
@@ -114,7 +118,8 @@ class ProvisionManager extends EventEmitter {
|
||||
this._stopMonitor();
|
||||
this._stopAll();
|
||||
this._state = 'idle';
|
||||
led.destroy(); // 停止时关灯、释放闪烁定时器
|
||||
led.destroy(); // WiFi 灯:停止时关灯、释放闪烁定时器
|
||||
led.bt.destroy(); // BT 灯:停止时关灯
|
||||
}
|
||||
|
||||
// ── 进入 AP 模式 ─────────────────────────────────────────────────────────
|
||||
@@ -122,7 +127,8 @@ class ProvisionManager extends EventEmitter {
|
||||
_enterAP() {
|
||||
if (this._state === 'ap') return;
|
||||
|
||||
led.off(); // AP 模式:WiFi 未连接,灭灯
|
||||
led.off(); // AP 模式:WiFi 未连接,WiFi 灯熄灭
|
||||
led.bt.blink(); // AP 模式:BLE 配网进行中,BT 灯闪烁
|
||||
if (!hasInternet()) led.display.showAP(); // 无网时立即显示 AP,有线时等 WS 连接后再定
|
||||
|
||||
try {
|
||||
@@ -165,16 +171,17 @@ class ProvisionManager extends EventEmitter {
|
||||
|
||||
const result = connectWifi(ssid, password);
|
||||
|
||||
if (result.success) {
|
||||
if (result.success) {
|
||||
this._state = 'sta';
|
||||
log.info('provision', `WiFi 已连接: ${ssid}`);
|
||||
led.on(); // 连接成功 → 常亮
|
||||
led.on(); // WiFi 灯:连接成功 → 常亮
|
||||
led.bt.on(); // BT 灯:配网成功 → 常亮
|
||||
this.emit('network-ready');
|
||||
return result;
|
||||
}
|
||||
|
||||
log.warn('provision', `WiFi 连接失败: ${result.error},重新启动 AP`);
|
||||
this._enterAP(); // _enterAP 内部会调用 led.off()
|
||||
this._enterAP(); // _enterAP 内部会调用 led.off() / led.bt.blink()
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -196,6 +203,7 @@ class ProvisionManager extends EventEmitter {
|
||||
log.info('provision', 'WiFi 已外部连接,关闭 AP');
|
||||
this._stopAPServices();
|
||||
this._state = 'sta';
|
||||
led.bt.on(); // 外部连接成功,BT 灯常亮
|
||||
this.emit('network-ready');
|
||||
}
|
||||
|
||||
@@ -203,11 +211,13 @@ class ProvisionManager extends EventEmitter {
|
||||
if (this._state === 'sta') {
|
||||
if (hasInternet()) {
|
||||
led.on();
|
||||
led.bt.on(); // 有网 → BT 灯常亮
|
||||
} else {
|
||||
led.off(); // WiFi 已连接但无互联网
|
||||
led.off(); // WiFi 已连接但无互联网
|
||||
led.bt.off(); // 无互联网时 BT 灯也熄灭
|
||||
}
|
||||
}
|
||||
// AP 模式下 led 已在 _enterAP() 中熄灭,无需重复操作
|
||||
// AP 模式下 led/bt 已在 _enterAP() 中设置,无需重复操作
|
||||
}, MONITOR_INTERVAL_MS);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user