import { writeA7Payload } from '../core/packet' import { waitForProtocolState } from '../core/stateWait' const WIFI_FINAL_STATE_CODES = Object.freeze([1, 2, 3]) /** * 校验 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(';')) } } function requireAuthorized(ble) { const state = ble.getState() if (!state.auth || state.auth.keyMatched !== true) { throw new Error('请先完成密钥鉴权,再发送 WiFi 配置') } } /** * WiFi 配网模块:负责打包发送 ssid|password,并等待 STATE 回执。 */ export function createWifiModule(ble) { async function configureWifi(ssid, password, options = {}) { const profile = ble.getProfile() const targetSsid = String(ssid || '').trim() const targetPass = String(password || '').trim() validateWifi(profile, targetSsid, targetPass) requireAuthorized(ble) const { wifi } = ble.getState().characteristics if (!wifi || !wifi.uuid) { throw new Error('未发现 UUID_WIFI 特征值') } const payload = `${targetSsid}|${targetPass}` // 协议要求 WiFi 参数按 0xA7 分包发送到 UUID_WIFI(F401)。 await writeA7Payload(ble, wifi.uuid, payload, profile.packet, { packetInterval: Number(options.packetInterval) || 0 }) const stateEvent = await waitForProtocolState(ble, { // 仅等待最终态,避免在“连接中(4)”时过早返回导致页面提前结束流程。 allowedCodes: WIFI_FINAL_STATE_CODES, rejectOnUnexpected: false, timeout: options.timeout || 12000, timeoutMessage: '等待 WiFi 状态超时' }) const stateCode = Number(stateEvent.stateCode) return { success: stateCode === 3, stateCode } } return { configureWifi, requireAuthorized } }