SEC_Warehouse/utils/ble/modules/wifi.js

131 lines
4.9 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { writeA7Payload } from '../core/packet'
import { waitForProtocolState } from '../core/stateWait'
const WIFI_FINAL_STATE_CODES = Object.freeze([1, 2, 3])
// STATE=4 为 WiFi 连接中中间态,收到后用于刷新等待窗口
const WIFI_CONNECTING_STATE_CODES = Object.freeze([4])
// 总等待上限:覆盖弱信号/5G/企业级路由真实 DHCP 时长
const WIFI_TOTAL_TIMEOUT_MS = 60000
// 收到 STATE=4 后的单次刷新窗口
const WIFI_REFRESH_TIMEOUT_MS = 30000
// ED713 分包写入间隔:连续 writeWithoutResponse 易丢包,固件需留处理时间
const ED713_PACKET_INTERVAL_MS = 50
/**
* 校验 WiFi 入参,规则来源于 profile.wifi。
*/
function validateWifi(profile, ssid, password) {
const errors = []
if (!ssid || ssid.length > profile.wifi.maxSsidLength) {
errors.push(`SSID 长度需在 1-${profile.wifi.maxSsidLength} 之间`)
}
if (password.length < profile.wifi.minPasswordLength || password.length > profile.wifi.maxPasswordLength) {
errors.push(`密码长度需在 ${profile.wifi.minPasswordLength}-${profile.wifi.maxPasswordLength} 之间`)
}
const invalidChars = profile.wifi.invalidChars || []
if (invalidChars.some((char) => ssid.includes(char))) {
errors.push(`SSID 不能包含特殊字符: ${invalidChars.join(' ')}`)
}
if (errors.length) {
throw new Error(errors.join(''))
}
}
/**
* 校验鉴权状态。
* 厂家确认密钥流程已不启用,此处仅记录未鉴权状态,不阻断 WiFi 配置。
*/
function requireAuthorized(ble) {
const state = ble.getState()
if (!state.auth || state.auth.keyMatched !== true) {
console.debug('[BLE][WiFi]', '密钥未匹配(密钥流程已废弃,继续配网)')
}
}
/**
* WiFi 配网模块:负责打包发送 ssid|password并等待 STATE 回执。
* 使用前必须先完成密钥鉴权。
* @param {object} ble createBleCore 实例
*/
export function createWifiModule(ble) {
function delay(ms) {
return new Promise((resolve) => setTimeout(resolve, Number(ms) || 0))
}
const log = (...args) => { try { console.debug('[BLE][WiFi]', ...args) } catch (e) {} }
/**
* 发送WiFi配网指令。
* 将 ssid|password 按 A7 分包写入 UUID_WIFI等待 STATE 回执判定结果。
* @param {string} ssid WiFi名称
* @param {string} password WiFi密码
* @param {object} options
* @param {number} options.timeout 等待状态回执总超时(ms)默认60000
* @param {number} options.preDelayMs 写入前延迟(ms)ED713 默认120ms
* @param {number} options.packetInterval 分包写入间隔(ms)
* @returns {{ success: boolean, stateCode: number }} stateCode=3 表示连接成功
*/
async function configureWifi(ssid, password, options = {}) {
const profile = ble.getProfile()
const s = String(ssid || '').trim()
const p = String(password || '').trim()
validateWifi(profile, s, p)
requireAuthorized(ble)
const { wifi } = ble.getState().characteristics
if (!wifi || !wifi.uuid) {
throw new Error('未发现 UUID_WIFI 特征值')
}
const totalTimeout = options.timeout || WIFI_TOTAL_TIMEOUT_MS
// 先注册 STATE 等待,再写入,确保不漏回执
// 收到 STATE=4(连接中) 时刷新窗口,避免固定上限短于真实 DHCP 时长误判超时
const waitPromise = waitForProtocolState(ble, {
allowedCodes: WIFI_FINAL_STATE_CODES,
rejectOnUnexpected: false,
timeout: totalTimeout,
timeoutMessage: '等待 WiFi 状态超时',
refreshOnCodes: WIFI_CONNECTING_STATE_CODES,
refreshTimeout: WIFI_REFRESH_TIMEOUT_MS
})
// ED713 固件需要写入前延迟,否则可能丢包
const pre = options.preDelayMs ?? (profile.id === 'ED713' ? 120 : 0)
if (pre) {
log('preDelay before WiFi write(ms)=', pre)
await delay(pre)
}
log('write WiFi start', { service: ble.getState().serviceId, char: wifi.uuid })
const packetInterval = Number(options.packetInterval) || (profile.id === 'ED713' ? ED713_PACKET_INTERVAL_MS : 0)
const sent = await writeA7Payload(ble, wifi.uuid, `${s}|${p}`, profile.packet, {
packetInterval
})
log('write WiFi done, packets=', sent, 'interval=', packetInterval)
let code
try {
code = Number((await waitPromise).stateCode)
} catch (error) {
// 超时时带上设备最后上报的 STATE 码,便于区分"设备未响应"与"设备回了非预期态"
const lastState = ble.getState().auth?.lastStateCode
const hint = (lastState === undefined || lastState === null)
? '(设备未上报任何 STATE可能 WiFi 分包写入丢失或固件未处理)'
: `(设备最后上报 STATE=${lastState},未收到最终态 1/2/3`
throw new Error(`${error.message}${hint}`)
}
log('STATE(final) received for WiFi=', code)
// STATE=3 表示 WiFi 连接成功
return { success: code === 3, stateCode: code }
}
return { configureWifi, requireAuthorized }
}