import {createBleCore} from './bleCore' import {createAuthModule} from '../modules/auth' import {createWifiModule} from '../modules/wifi' import {createRadarModule} from '../modules/radar' import {parseStateCode, parseDeviceInfo} from '../parsers' import {DEVICE_PROFILE, guessProfileByRadarFrame} from '../protocols/profiles' import {uuidEquals} from '../utils/uuid' /** * 创建特征值通知分发器。 * 根据特征UUID将通知分发到对应协议事件:state / msg / radar / raw。 * 雷达帧还能自动推断设备 profile(ED713/ED719)。 */ function createCharacteristicDispatcher(ble) { return (event) => { const state = ble.getState() const profile = ble.getProfile() const current = state.characteristics if (current.state && uuidEquals(event.characteristicId, current.state.uuid)) { const stateCode = parseStateCode(event.value) ble.setAuthState({ lastStateCode: stateCode, keyMatched: stateCode === 7 || stateCode === 5 || state.auth.keyMatched }) ble.emit('protocol:state', { ...event, profileId: profile.id, stateCode }) return } if (current.msg && uuidEquals(event.characteristicId, current.msg.uuid)) { ble.emit('protocol:msg', { ...event, profileId: profile.id, deviceInfo: parseDeviceInfo(event.value, profile.id) }) return } if (current.radar && uuidEquals(event.characteristicId, current.radar.uuid)) { const guessed = guessProfileByRadarFrame(event.value) if (state.profileId === DEVICE_PROFILE.UNKNOWN && guessed !== DEVICE_PROFILE.UNKNOWN) { ble.setProfile(guessed) } ble.emit('protocol:radar', { ...event, profileId: ble.getProfile().id }) return } ble.emit('protocol:raw', { ...event, profileId: profile.id }) } } /** * 统一BLE控制器:整合核心能力 + 认证/WiFi/雷达三大业务模块。 * 页面层应通过此控制器编排完整业务流程。 * @param {object} options 透传给 createBleCore 的配置(重试策略/日志/profileId等) */ export function createUnifiedBleController(options = {}) { const ble = createBleCore(options) const auth = createAuthModule(ble) const wifi = createWifiModule(ble) const radar = createRadarModule(ble) const characteristicDispatcher = createCharacteristicDispatcher(ble) let offCharacteristic = null /** 绑定特征值分发器到 ble 事件总线。 */ function bindDispatcher() { if (offCharacteristic) { return } offCharacteristic = ble.on('characteristic:value', characteristicDispatcher) } /** 解绑特征值分发器。 */ function unbindDispatcher() { if (!offCharacteristic) { return } offCharacteristic() offCharacteristic = null } /** 初始化蓝牙适配器并注册所有监听(适配器状态/连接/特征值/分发器)。 */ async function init() { await ble.openAdapter() ble.watchAdapterState() ble.watchConnectionChange() ble.watchCharacteristicValue() bindDispatcher() } /** * 扫描并选取目标设备。 * 先按服务UUID过滤扫描,无结果时可退化为无过滤扫描。 * @param {object} params * @param {string} params.serviceUuid 目标服务UUID,默认取 profile 配置 * @param {number} params.scanDuration 扫描时长(ms),默认5000 * @param {boolean} params.fallbackWithoutFilter 首次无结果时是否退化为无过滤扫描,默认true * @returns {object|null} 匹配到的设备对象,未找到返回 null */ async function scanAndPickDevice({ serviceUuid, scanDuration = 5000, fallbackWithoutFilter = true } = {}) { const profile = ble.getProfile() const targetService = serviceUuid || profile.uuids.service ble.watchDeviceFound() await ble.startDiscovery({services: [targetService]}) await new Promise((resolve) => setTimeout(resolve, scanDuration)) await ble.stopDiscovery() let selected = ble.pickDeviceByService(targetService) if (!selected && fallbackWithoutFilter) { await ble.startDiscovery({services: []}) await new Promise((resolve) => setTimeout(resolve, scanDuration)) await ble.stopDiscovery() selected = ble.pickDeviceByService(targetService) || ble.listDiscoveredDevices()[0] || null } return selected } /** * 连接后严格执行协议前置: * - 发现服务和特征 * - 订阅 UUID_STATE / UUID_RADAR */ async function connectAndDiscover(deviceId) { await ble.connect(deviceId) await ble.discoverServices(deviceId) const chars = await ble.discoverCharacteristics() if (chars.state && chars.state.uuid) { try { await ble.notifyCharacteristic(chars.state.uuid, true); console.debug('[BLE][SUB]', 'notify STATE ok', chars.state.uuid) } catch (e) { console.debug('[BLE][SUB]', 'notify STATE fail', e?.message || e) } } if (chars.radar && chars.radar.uuid) { try { await ble.notifyCharacteristic(chars.radar.uuid, true); console.debug('[BLE][SUB]', 'notify RADAR ok', chars.radar.uuid) } catch (e) { console.debug('[BLE][SUB]', 'notify RADAR fail', e?.message || e) } } return chars } /** * 标准流程:连接 -> 订阅 -> 鉴权。 * 鉴权内部会按 bindStatus 分支处理绑定/匹配。 */ async function standardConnectFlow({deviceId, key}) { await init() let targetDeviceId = deviceId if (!targetDeviceId) { const device = await scanAndPickDevice() if (!device) { throw new Error('未找到可连接设备') } targetDeviceId = device.deviceId } await connectAndDiscover(targetDeviceId) const authResult = await auth.ensureAuthorized(key) return { deviceId: targetDeviceId, authResult, state: ble.getState(), profile: ble.getProfile() } } /** 释放所有资源:解绑分发器 + 清理核心BLE(停扫描/断连接/移监听/关适配器)。 */ async function cleanup() { unbindDispatcher() await ble.cleanup() } return { ble, auth, wifi, radar, init, scanAndPickDevice, connectAndDiscover, standardConnectFlow, cleanup } }