diff --git a/hooks/useBluetoothDiscovery.js b/hooks/useBluetoothDiscovery.js
index c21b619..8d2a28f 100644
--- a/hooks/useBluetoothDiscovery.js
+++ b/hooks/useBluetoothDiscovery.js
@@ -798,16 +798,10 @@ export function createBluetoothDiscovery(options = {}) {
* WiFi配置专用流程:连接 -> 发现 -> 订阅 -> 按 MAC+0000 完成鉴权。
*/
async function prepareWifiConfig(deviceId, options = {}) {
+ // 厂家确认:无需鉴权、无需读 MSG。
+ // 流程:连接 → 发现服务特征 → 订阅 F301,完成后即可进入 WiFi 配置。
await connectDevice(deviceId)
-
- // 厂家确认:密钥流程已不启用,写 KEY 后设备不回 STATE,鉴权必然超时。
- // 这里尽力尝试鉴权,失败则忽略并继续,由 WiFi 配网直接走(写 F401 后等 STATE=3)。
- try {
- return await authorizeDeviceByMac(options)
- } catch (error) {
- console.debug('[BLE][AUTH]', '鉴权失败已忽略(密钥流程已废弃)', error?.message || error)
- return { mode: 'AUTH_SKIPPED', error: error?.message || String(error) }
- }
+ return { mode: 'READY', deviceId }
}
async function readDeviceInfo() {
diff --git a/pages/device/config.vue b/pages/device/config.vue
index 30790a5..19906ce 100644
--- a/pages/device/config.vue
+++ b/pages/device/config.vue
@@ -32,12 +32,15 @@
{{ device.deviceId }}
-
- {{ isDevicePreparing(device.deviceId) ? '鉴权中' : '网络配置' }}
+
+ {{ getActionLabel(action, device) }}
- 参数配置
- 服务器配置
@@ -117,6 +120,30 @@ const WIFI_STATE_MESSAGES = Object.freeze({
4: '设备正在连接 WiFi,请稍候'
})
+// 设备型号 → 启用的按钮 key 列表。
+// 后续如需让其他型号裁剪按钮,只需新增映射条目。
+const DEVICE_ACTION_KEYS = Object.freeze({
+ EP832: ['WIFI'],
+ DEFAULT: ['WIFI', 'PARAMS', 'SERVER']
+})
+
+// 按钮注册表:label / 忙态文案 / 点击方法名 / 忙态判定方法名。
+// 仅声明 key 即可被引用,未配置的方法名渲染为不可点击的占位项。
+const ACTION_REGISTRY = Object.freeze({
+ WIFI: {
+ label: '网络配置',
+ busyLabel: '连接中',
+ handler: 'openWifiPanel',
+ isBusy: 'isDevicePreparing'
+ },
+ PARAMS: {
+ label: '参数配置'
+ },
+ SERVER: {
+ label: '服务器配置'
+ }
+})
+
function getErrorMessage(error) {
if (!error) {
return '操作失败,请重试'
@@ -253,6 +280,47 @@ export default {
return Boolean(this.devicePreparingMap[safeDeviceId])
},
+ isEp832(device) {
+ const name = String(device?.showName || device?.name || device?.localName || '').toUpperCase()
+ return name.includes('EP832')
+ },
+
+ /**
+ * 根据设备型号返回该设备可见的操作按钮列表。
+ * 列表中的 action 对象包含 key、label、handler、isBusy 等元数据,
+ * 模板里直接 v-for 渲染。
+ */
+ getDeviceActions(device) {
+ const identifier = this.isEp832(device) ? 'EP832' : 'DEFAULT'
+ const keys = DEVICE_ACTION_KEYS[identifier] || DEVICE_ACTION_KEYS.DEFAULT
+ return keys.map(key => ({ key, ...ACTION_REGISTRY[key] }))
+ },
+
+ isActionBusy(action, device) {
+ if (!action.isBusy) {
+ return false
+ }
+ const checker = this[action.isBusy]
+ return typeof checker === 'function' ? Boolean(checker.call(this, device.deviceId)) : false
+ },
+
+ getActionLabel(action, device) {
+ if (this.isActionBusy(action, device) && action.busyLabel) {
+ return action.busyLabel
+ }
+ return action.label
+ },
+
+ invokeAction(action, device) {
+ if (!action.handler) {
+ return
+ }
+ const handler = this[action.handler]
+ if (typeof handler === 'function') {
+ handler.call(this, device.deviceId)
+ }
+ },
+
getDeviceById(deviceId) {
const safeDeviceId = String(deviceId || '').trim()
if (!safeDeviceId) {
@@ -314,7 +382,7 @@ export default {
}
if (this.activePreparingDeviceId && this.activePreparingDeviceId !== targetDeviceId) {
- showToast('正在为其他设备鉴权,请稍候')
+ showToast('正在为其他设备准备,请稍候')
return
}
@@ -331,27 +399,21 @@ export default {
this.setDevicePreparing(targetDeviceId, true)
uni.showLoading({
- title: '密钥鉴权中',
+ title: '连接设备中',
mask: true
})
- let authError = null
+ let prepError = null
try {
- /**
- * 先按项目固定已知密钥规则(MAC+0000)完成鉴权,成功后再允许进入 WiFi 弹层。
- */
- await this.discoveryController.prepareWifiConfig(targetDeviceId, {
- suffix: '0000',
- timeout: 8000,
- msgTimeout: 4000
- })
+ // 厂家确认流程:连接 → 发现服务特征 → 订阅 F301,无需鉴权/读MSG。
+ await this.discoveryController.prepareWifiConfig(targetDeviceId)
this.wifiPrepared = true
this.wifiPanelVisible = true
// 确保 Vue 完成 DOM 更新后再调原生 toast,避免原生层覆盖 Vue 弹层
await this.$nextTick()
} catch (error) {
- authError = error
+ prepError = error
await this.safeDisconnect()
} finally {
this.setDevicePreparing(targetDeviceId, false)
@@ -362,16 +424,16 @@ export default {
uni.hideLoading()
}
- if (authError) {
- // 鉴权失败用模态弹窗,需用户主动确认,确保错误诊断信息可见可读
+ if (prepError) {
+ // 连接/订阅失败用模态弹窗,需用户主动确认,确保错误诊断信息可见可读
uni.showModal({
- title: '密钥鉴权失败',
- content: getErrorMessage(authError),
+ title: '设备连接失败',
+ content: getErrorMessage(prepError),
showCancel: false,
confirmText: '知道了'
})
} else if (this.wifiPanelVisible) {
- showToast('密钥鉴权成功,请填写WiFi信息')
+ showToast('设备已连接,请填写WiFi信息')
}
},
@@ -463,7 +525,7 @@ export default {
}
if (!this.wifiPrepared) {
- showToast('请先完成密钥鉴权')
+ showToast('设备未连接,请重新配置')
return
}
diff --git a/utils/ble/core/controller.js b/utils/ble/core/controller.js
index 16bc7e7..337bdea 100644
--- a/utils/ble/core/controller.js
+++ b/utils/ble/core/controller.js
@@ -9,42 +9,6 @@ import {
} from '../protocols/profiles';
import { uuidEquals } from '../utils/uuid';
-/**
- * 订阅 F301 前先读一次 UUID_MSG(F501),满足厂家强制时序。
- * 先注册 protocol:msg 监听再触发读取,避免回调早于监听丢失数据。
- */
-async function readMsgOnce(ble, chars, timeout = 4000) {
- if (!chars || !chars.msg || !chars.msg.uuid) {
- console.debug('[BLE][MSG]', 'readMsgOnce skipped: no MSG characteristic');
- return null;
- }
-
- let timer = null;
- let off = null;
- try {
- const payload = await new Promise((resolve, reject) => {
- const finish = (cb) => {
- if (timer) clearTimeout(timer);
- if (off) off();
- cb();
- };
- off = ble.on('protocol:msg', (data) => finish(() => resolve(data)));
- timer = setTimeout(
- () => finish(() => reject(new Error('读取 UUID_MSG 超时'))),
- timeout
- );
- ble.readCharacteristic(chars.msg.uuid).catch((e) => finish(() => reject(e)));
- });
- const info = parseDeviceInfo(payload.value, ble.getProfile().id);
- console.debug('[BLE][MSG]', 'readMsgOnce ok', JSON.stringify(info));
- return info;
- } catch (e) {
- // 读 MSG 失败不阻断后续(仅作时序前置),但记录日志便于排查
- console.debug('[BLE][MSG]', 'readMsgOnce failed', e?.message || e);
- return null;
- }
-}
-
/**
* 创建特征值通知分发器。
* 根据特征UUID将通知分发到对应协议事件:state / msg / radar / raw。
@@ -193,22 +157,17 @@ export function createUnifiedBleController(options = {}) {
}
/**
- * 连接后严格执行协议前置(厂家要求顺序):
+ * 连接后执行协议前置(厂家确认流程):
* 1) 发现服务和特征
- * 2) 先读取 UUID_MSG(F501) —— 必须在订阅 F301 之前
- * 3) 订阅 UUID_STATE(F301) / UUID_RADAR(F302)
+ * 2) 订阅 UUID_STATE(F301) / UUID_RADAR(F302)
*
- * 厂家说明:订阅 F301 前必须先读 F501,否则后续设备不回 STATE 通知,
- * 表现为写 KEY/WIFI 后 F301 零回执、等待超时。
+ * 厂家确认:无需读 MSG、无需鉴权,订阅 F301 后直接写 F401 配网即可。
*/
async function connectAndDiscover(deviceId) {
await ble.connect(deviceId);
await ble.discoverServices(deviceId);
const chars = await ble.discoverCharacteristics();
- // 先读 UUID_MSG(F501),再订阅 F301 —— 厂家强制顺序
- await readMsgOnce(ble, chars);
-
if (chars.state && chars.state.uuid) {
// 打印 STATE 特征属性,区分 notify / indicate,定位通知不投递问题
console.debug('[BLE][SUB]', 'STATE props', JSON.stringify(chars.state.properties || {}));