[AI Generated]: fix(*): 修复乐福SDK二次连接问题,对齐demo挂载顺序并完善页面状态重置
This commit is contained in:
+96
-322
@@ -14,14 +14,17 @@ import type {
|
||||
FirmwareVersion,
|
||||
} from './types'
|
||||
|
||||
/** 顶层加载插件(对齐 demo,requirePlugin 必须在文件顶层调用) */
|
||||
const plugin = requirePlugin('ppScale-plugin') as LeFuPlugin
|
||||
|
||||
/** 乐福 SDK 配置 */
|
||||
const LEFU_CONFIG: LeFuConfig = {
|
||||
key: 'lefudc91611833e18d94',
|
||||
secret: 'eQ50JYimMp0X7uhNLj6D3lTEk4TUUvEG7dvaqKM9t1U=',
|
||||
domain1: 'http://192.168.1.31:8889', // 测试环境(老版本 无鉴权)
|
||||
domain2: 'http://192.168.1.31:8889/weight', // 测试环境(新版本 有鉴权)
|
||||
// domain1: 'http://device.shuziweidao.com:80/gateway', // 正式环境
|
||||
// domain2: 'http://device.shuziweidao.com:80/weight', // 正式环境
|
||||
domain1: 'http://192.168.1.31:8889',
|
||||
domain2: 'http://192.168.1.31:8889/weight',
|
||||
// domain1: 'http://device.shuziweidao.com:80/gateway',
|
||||
// domain2: 'http://device.shuziweidao.com:80/weight',
|
||||
}
|
||||
|
||||
/** 支持的设备型号配置列表(5款) */
|
||||
@@ -71,25 +74,17 @@ const DEVICE_SETTINGS: DeviceSetting[] = [
|
||||
const TAG = '[LeFuService]'
|
||||
|
||||
class LeFuService {
|
||||
private _plugin: LeFuPlugin | null = null
|
||||
/** 设备协议对象,devicesModel 事件返回,用于 WiFi 配网等高级操作 */
|
||||
private _activeProtocol: any = null
|
||||
private _connectState = ''
|
||||
private _deviceInfo: DeviceInfo | null = null
|
||||
private _busSubscribed = false
|
||||
private _intentionalConnect = false
|
||||
|
||||
/** 重连次数 */
|
||||
private _reconnectCount = 0
|
||||
private readonly _maxReconnect = 3
|
||||
private _reconnectTimer: number | null = null
|
||||
|
||||
/** 保活心跳定时器 */
|
||||
private _keepAliveTimer: number | null = null
|
||||
|
||||
/** 连接后从 deviceInfo 事件获取的固件信息 */
|
||||
private _deviceInfo: DeviceInfo | null = null
|
||||
|
||||
/** bus 事件是否已订阅(防止多次 startScan 重复 subscribe 累积) */
|
||||
private _busSubscribed = false
|
||||
|
||||
/** 回调注册(页面通过 on* 方法注册,stopScan 时清空) */
|
||||
private _onDevicesListCb: ((devices: ScannedDevice[]) => void) | null = null
|
||||
private _onConnectStateCb: ((state: string) => void) | null = null
|
||||
private _onDeviceConnectCb: (() => void) | null = null
|
||||
@@ -98,142 +93,63 @@ class LeFuService {
|
||||
private _onDisconnectedCb: (() => void) | null = null
|
||||
private _onDeviceInfoCb: ((info: DeviceInfo) => void) | null = null
|
||||
|
||||
/** 在 app.ts onLaunch 中调用,加载 ppScale-plugin */
|
||||
init(): void {
|
||||
console.log(TAG, 'init() 开始加载插件')
|
||||
this._plugin = requirePlugin('ppScale-plugin') as LeFuPlugin
|
||||
console.log(TAG, 'init() 插件加载完成:', !!this._plugin)
|
||||
}
|
||||
|
||||
/** 获取插件(未初始化时抛出) */
|
||||
private get _p(): LeFuPlugin {
|
||||
if (!this._plugin) throw new Error('[LeFu] 服务未初始化,请先调用 init()')
|
||||
return this._plugin
|
||||
}
|
||||
|
||||
/** 乐福配置(供体成分分析等外部使用) */
|
||||
get config(): LeFuConfig {
|
||||
return LEFU_CONFIG
|
||||
}
|
||||
get config(): LeFuConfig { return LEFU_CONFIG }
|
||||
get isConnected(): boolean { return !!this._activeProtocol }
|
||||
get connectState(): string { return this._connectState }
|
||||
get BLUE_STATE(): Record<string, string> { return plugin.BLUE_STATE ?? {} }
|
||||
get deviceInfo(): DeviceInfo | null { return this._deviceInfo }
|
||||
|
||||
// ─── 回调注册 ─────────────────────────────────
|
||||
|
||||
/** 注册设备列表回调(扫描到设备时触发) */
|
||||
onDevicesList(cb: (devices: ScannedDevice[]) => void): void {
|
||||
console.log(TAG, 'onDevicesList 回调已注册')
|
||||
this._onDevicesListCb = cb
|
||||
}
|
||||
|
||||
/** 注册蓝牙连接状态回调 */
|
||||
onConnectState(cb: (state: string) => void): void {
|
||||
console.log(TAG, 'onConnectState 回调已注册')
|
||||
this._onConnectStateCb = cb
|
||||
}
|
||||
|
||||
/** 注册设备连接就绪回调(activeProtocol 可用时触发) */
|
||||
onDeviceConnect(cb: () => void): void {
|
||||
console.log(TAG, 'onDeviceConnect 回调已注册')
|
||||
this._onDeviceConnectCb = cb
|
||||
}
|
||||
|
||||
/** 当前蓝牙连接状态(connectState bus 事件实时更新) */
|
||||
private _connectState = ''
|
||||
|
||||
/** 设备是否已连接(activeProtocol 就绪) */
|
||||
get isConnected(): boolean {
|
||||
return !!this._activeProtocol
|
||||
}
|
||||
|
||||
/** 当前蓝牙连接状态字符串 */
|
||||
get connectState(): string {
|
||||
return this._connectState
|
||||
}
|
||||
|
||||
/** 插件 BLUE_STATE 常量对象(供页面 wxml 条件判断用) */
|
||||
get BLUE_STATE(): Record<string, string> {
|
||||
return this._plugin?.BLUE_STATE ?? {}
|
||||
}
|
||||
|
||||
/** 连接后从 deviceInfo 事件获取的设备信息(含 modelNumber / serialNumber 等) */
|
||||
get deviceInfo(): DeviceInfo | null {
|
||||
return this._deviceInfo
|
||||
}
|
||||
|
||||
/** 注册实时测量回调(测量过程中多次触发) */
|
||||
onMeasuring(cb: (data: ProgressData) => void): void {
|
||||
this._onProgressCb = cb
|
||||
}
|
||||
|
||||
/** 注册测量完成回调(数据锁定,触发一次) */
|
||||
onLocked(cb: (data: LockData) => void): void {
|
||||
this._onLockedCb = cb
|
||||
}
|
||||
|
||||
/** 注册设备断开回调 */
|
||||
onDisconnected(cb: () => void): void {
|
||||
this._onDisconnectedCb = cb
|
||||
}
|
||||
|
||||
/** 注册 deviceInfo 就绪回调(设备名/固件信息可用时触发) */
|
||||
onDeviceInfo(cb: (info: DeviceInfo) => void): void {
|
||||
this._onDeviceInfoCb = cb
|
||||
}
|
||||
onDevicesList(cb: (devices: ScannedDevice[]) => void): void { this._onDevicesListCb = cb }
|
||||
onConnectState(cb: (state: string) => void): void { this._onConnectStateCb = cb }
|
||||
onDeviceConnect(cb: () => void): void { this._onDeviceConnectCb = cb }
|
||||
onMeasuring(cb: (data: ProgressData) => void): void { this._onProgressCb = cb }
|
||||
onLocked(cb: (data: LockData) => void): void { this._onLockedCb = cb }
|
||||
onDisconnected(cb: () => void): void { this._onDisconnectedCb = cb }
|
||||
onDeviceInfo(cb: (info: DeviceInfo) => void): void { this._onDeviceInfoCb = cb }
|
||||
|
||||
// ─── 扫描与连接 ───────────────────────────────
|
||||
|
||||
/**
|
||||
* 开始蓝牙扫描
|
||||
* 对齐 master:先 setDeviceSetting → start,再 subscribe(master searchDevice.js 顺序)
|
||||
*/
|
||||
startScan(): void {
|
||||
console.log(TAG, 'startScan() 开始,busSubscribed:', this._busSubscribed)
|
||||
const plugin = this._p
|
||||
|
||||
// ① 先设置设备配置并启动扫描(必须在 subscribe 之前,与 master 一致)
|
||||
console.log(TAG, 'startScan()')
|
||||
plugin.Blue.setDeviceSetting(DEVICE_SETTINGS)
|
||||
const deviceNames = DEVICE_SETTINGS.map(s => s.deviceName)
|
||||
console.log(TAG, 'plugin.Blue.start() 调用,设备名称:', deviceNames)
|
||||
plugin.Blue.start(deviceNames, false)
|
||||
this._subscribeBus()
|
||||
plugin.Blue.start(DEVICE_SETTINGS.map(s => s.deviceName), false)
|
||||
}
|
||||
|
||||
// bus 订阅只注册一次,stopScan 时重置,避免多次搜索导致订阅累积
|
||||
private _subscribeBus(): void {
|
||||
if (this._busSubscribed) {
|
||||
console.log(TAG, 'bus 已订阅,跳过重复注册')
|
||||
console.log(TAG, 'bus 已订阅,跳过')
|
||||
return
|
||||
}
|
||||
this._busSubscribed = true
|
||||
|
||||
// ② 启动后再订阅设备列表(master 也是 start 后才 subscribe)
|
||||
plugin.bus.subscribe('devicesList', (devList: RawDevice[]) => {
|
||||
console.log(TAG, 'bus[devicesList] 触发,原始设备数:', devList?.length, devList?.map((d: RawDevice) => d.name || d.deviceName))
|
||||
if (!devList || !devList.length) {
|
||||
console.log(TAG, 'bus[devicesList],设备数:', devList?.length)
|
||||
if (!devList?.length) {
|
||||
this._onDevicesListCb?.([])
|
||||
return
|
||||
}
|
||||
// 直接用原始列表转换,不调用 getDeviceModel(master 也是直接传 res)
|
||||
const devices: ScannedDevice[] = devList.map((item: RawDevice) => ({
|
||||
name: item.name || item.deviceName || '未知设备',
|
||||
raw: item,
|
||||
model: {},
|
||||
}))
|
||||
console.log(TAG, '转换后设备列表:', devices.map(d => d.name))
|
||||
this._onDevicesListCb?.(devices)
|
||||
})
|
||||
|
||||
// 设备模型信息(含 mac 等,仅用于日志/调试)
|
||||
plugin.bus.subscribe('devicesModel', (res: any) => {
|
||||
console.log(TAG, 'bus[devicesModel] 触发,deviceMac:', res?.deviceMac)
|
||||
console.log(TAG, 'bus[devicesModel] 完整数据:', JSON.stringify(res))
|
||||
})
|
||||
|
||||
// 连接成功后获取固件信息(用于后续 OTA 版本比对)
|
||||
plugin.bus.subscribe('deviceInfo', (res: DeviceInfo) => {
|
||||
console.log(TAG, 'bus[deviceInfo] 触发:',res, res?.firmwareRevision, res?.modelNumber)
|
||||
console.log(TAG, 'bus[deviceInfo]:', res?.modelNumber)
|
||||
this._deviceInfo = res
|
||||
this._onDeviceInfoCb?.(res)
|
||||
})
|
||||
|
||||
// 连接建立:从 ScaleAction 获取 activeProtocol,启动数据进度(对齐 master configureDevice.js)
|
||||
plugin.bus.subscribe('deviceConnect', () => {
|
||||
console.log(TAG, 'bus[deviceConnect] 触发,获取 activeProtocol,启动数据进度')
|
||||
console.log(TAG, 'bus[deviceConnect]')
|
||||
this._intentionalConnect = false
|
||||
this._reconnectCount = 0
|
||||
plugin.ScaleAction.startDataProgress(true)
|
||||
this._activeProtocol = plugin.ScaleAction.getActiveProtocol()
|
||||
@@ -241,228 +157,144 @@ class LeFuService {
|
||||
this._onDeviceConnectCb?.()
|
||||
})
|
||||
|
||||
// 连接状态变化:CONNECTSUCCESS 时启动保活,CONNECTFAILED 时重连
|
||||
plugin.bus.subscribe('connectState', (res: string) => {
|
||||
console.log(TAG, 'bus[connectState] 触发:', res)
|
||||
console.log(TAG, 'bus[connectState]:', res)
|
||||
this._connectState = res
|
||||
this._onConnectStateCb?.(res)
|
||||
if (res === plugin.BLUE_STATE.CONNECTSUCCESS) {
|
||||
console.log(TAG, '连接成功,启动保活心跳')
|
||||
this._startKeepAlive()
|
||||
}
|
||||
if (res === plugin.BLUE_STATE.CONNECTFAILED) {
|
||||
console.warn(TAG, '连接失败,触发重连逻辑')
|
||||
this._stopKeepAlive()
|
||||
this._doReconnect()
|
||||
if (!this._intentionalConnect) {
|
||||
this._doReconnect()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// 实时测量数据
|
||||
plugin.bus.subscribe('progressData', (res: ProgressData) => {
|
||||
console.log(TAG, 'bus[progressData] 体重(g):', res?.weight)
|
||||
this._onProgressCb?.(res)
|
||||
})
|
||||
|
||||
// 测量锁定(完成)
|
||||
plugin.bus.subscribe('lockData', (res: LockData) => {
|
||||
console.log(TAG, 'bus[lockData] 测量完成,体重(g):', res?.weight, '阻抗:', res?.resistance)
|
||||
this._onLockedCb?.(res)
|
||||
})
|
||||
|
||||
// 设备自动断开
|
||||
plugin.bus.subscribe('deviceWillDisconnect', () => {
|
||||
console.warn(TAG, 'bus[deviceWillDisconnect] 设备断开,触发重连')
|
||||
console.warn(TAG, 'bus[deviceWillDisconnect],intentionalConnect:', this._intentionalConnect)
|
||||
this._stopKeepAlive()
|
||||
this._onDisconnectedCb?.()
|
||||
this._doReconnect()
|
||||
if (!this._intentionalConnect) {
|
||||
this._doReconnect()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 主动连接指定设备(对齐 master:直接调 createBLEConnection,不判断 deviceConnectType)
|
||||
*/
|
||||
connect(device: ScannedDevice): void {
|
||||
console.log(TAG, 'connect() 设备:', device.name)
|
||||
this._p.Blue.createBLEConnection(device.raw)
|
||||
}
|
||||
|
||||
/** 主动断开当前连接 */
|
||||
disconnect(): void {
|
||||
console.log(TAG, 'disconnect() 主动断开')
|
||||
console.log(TAG, 'connect():', device.name)
|
||||
this._intentionalConnect = true
|
||||
this._stopKeepAlive()
|
||||
this._p.Blue.disconnect()
|
||||
this._stopReconnectTimer()
|
||||
this._activeProtocol = null
|
||||
this._connectState = ''
|
||||
this._deviceInfo = null
|
||||
this._onDeviceInfoCb = null
|
||||
this._onDeviceConnectCb = null
|
||||
plugin.Blue.stopBluetoothDevicesDiscovery()
|
||||
plugin.Blue.createBLEConnection(device.raw)
|
||||
}
|
||||
|
||||
disconnect(): void {
|
||||
console.log(TAG, 'disconnect()')
|
||||
this._stopKeepAlive()
|
||||
plugin.Blue.disconnect()
|
||||
}
|
||||
|
||||
/**
|
||||
* 停止扫描(仅停止设备发现,不清连接态)
|
||||
* connectedDevice onHide / onUnload 时调用
|
||||
*/
|
||||
stopScan(): void {
|
||||
console.log(TAG, 'stopScan() 停止扫描')
|
||||
console.log(TAG, 'stopScan()')
|
||||
this._stopReconnectTimer()
|
||||
this._busSubscribed = false
|
||||
wx.stopBluetoothDevicesDiscovery()
|
||||
this._onDevicesListCb = null
|
||||
this._onDeviceConnectCb = null
|
||||
}
|
||||
|
||||
// ─── WiFi 配网 ────────────────────────────────
|
||||
|
||||
/**
|
||||
* 获取设备上报的 WiFi 列表(需设备已连接)
|
||||
* 内部延迟 2 秒后调用,15 秒超时
|
||||
*/
|
||||
getWifiList(): Promise<LeFuWifiItem[]> {
|
||||
console.log(TAG, 'getWifiList() 开始')
|
||||
console.log(TAG, 'getWifiList()')
|
||||
return new Promise((resolve, reject) => {
|
||||
if (!this._activeProtocol) {
|
||||
reject(new Error('[LeFu] 设备未连接,无法获取 WiFi 列表'))
|
||||
return
|
||||
}
|
||||
|
||||
const timer = setTimeout(() => {
|
||||
reject(new Error('[LeFu] 获取 WiFi 列表超时'))
|
||||
}, 15000)
|
||||
|
||||
// 延迟 2 秒,等待设备就绪后再请求
|
||||
const timer = setTimeout(() => reject(new Error('[LeFu] 获取 WiFi 列表超时')), 15000)
|
||||
setTimeout(() => {
|
||||
this._activeProtocol.dataFindSurroundDevice((res: any[]) => {
|
||||
clearTimeout(timer)
|
||||
console.log(TAG, 'getWifiList 原始结果:', res)
|
||||
if (!res || res.length === 0) {
|
||||
console.log(TAG, 'getWifiList 结果:', res)
|
||||
if (!res?.length) {
|
||||
this._activeProtocol.dataExitWifiConfig(() => {})
|
||||
resolve([])
|
||||
return
|
||||
}
|
||||
const list: LeFuWifiItem[] = res.map((item: any) => ({
|
||||
ssid: item.ssid || item.name || '',
|
||||
signal: item.signal,
|
||||
}))
|
||||
console.log(TAG, 'getWifiList 解析结果:', list.map(w => w.ssid))
|
||||
resolve(list)
|
||||
resolve(res.map((item: any) => ({ ssid: item.ssid || item.name || '', signal: item.signal })))
|
||||
})
|
||||
}, 2000)
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 将 WiFi 配置写入设备
|
||||
* @param ssid WiFi 名称
|
||||
* @param password WiFi 密码
|
||||
* @param version 协议版本:domain1(无鉴权)| domain2(有鉴权)
|
||||
* 返回码 23 = 配网成功
|
||||
*/
|
||||
configWifi(ssid: string, password: string, version: WifiVersion): Promise<void> {
|
||||
console.log(TAG, 'configWifi() ssid:', ssid, 'version:', version)
|
||||
console.log(TAG, 'configWifi():', ssid, version)
|
||||
return new Promise((resolve, reject) => {
|
||||
if (!this._activeProtocol) {
|
||||
reject(new Error('[LeFu] 设备未连接,无法配网'))
|
||||
return
|
||||
}
|
||||
|
||||
const callback = (res: number) => {
|
||||
console.log(TAG, 'configWifi 回调 res:', res)
|
||||
if (res === 23) {
|
||||
console.log(TAG, 'configWifi 成功')
|
||||
resolve()
|
||||
} else {
|
||||
console.error(TAG, 'configWifi 失败,错误码:', res)
|
||||
reject(new Error(`[LeFu] 配网失败,错误码:${res}`))
|
||||
}
|
||||
console.log(TAG, 'configWifi 回调:', res)
|
||||
res === 23 ? resolve() : reject(new Error(`[LeFu] 配网失败,错误码:${res}`))
|
||||
}
|
||||
|
||||
if (version === 'domain1') {
|
||||
this._activeProtocol.dataConfigNetWork(
|
||||
{ domain: LEFU_CONFIG.domain1, ssid, password },
|
||||
callback,
|
||||
)
|
||||
this._activeProtocol.dataConfigNetWork({ domain: LEFU_CONFIG.domain1, ssid, password }, callback)
|
||||
} else {
|
||||
this._activeProtocol.dataConfigUserNetWork(
|
||||
{
|
||||
domain: LEFU_CONFIG.domain2,
|
||||
ssid,
|
||||
password,
|
||||
userName: 'apiUser',
|
||||
userPassword: '3acebb95eb49577e9c2a2082589b9bd6',
|
||||
},
|
||||
{ domain: LEFU_CONFIG.domain2, ssid, password, userName: 'apiUser', userPassword: '3acebb95eb49577e9c2a2082589b9bd6' },
|
||||
callback,
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询设备是否已完成配网
|
||||
* 返回 true = 已配网(0x01),false = 未配网
|
||||
*/
|
||||
checkWifiConfig(): Promise<boolean> {
|
||||
console.log(TAG, 'checkWifiConfig() 查询配网状态')
|
||||
return new Promise((resolve, reject) => {
|
||||
if (!this._activeProtocol) {
|
||||
reject(new Error('[LeFu] 设备未连接'))
|
||||
return
|
||||
}
|
||||
if (!this._activeProtocol) { reject(new Error('[LeFu] 设备未连接')); return }
|
||||
this._activeProtocol.codeFetchWifiConfig((res: number | undefined | null) => {
|
||||
console.log(TAG, 'checkWifiConfig 回调 res:', res, '已配网:', res === 0x01)
|
||||
resolve(res === 0x01)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// ─── OTA 升级 ─────────────────────────────────
|
||||
|
||||
/**
|
||||
* 检查固件版本并按需触发 OTA 升级
|
||||
* @returns true = 已触发升级,false = 无需升级
|
||||
* 调用时机由业务层决定,不自动触发
|
||||
*/
|
||||
checkAndUpgrade(): Promise<boolean> {
|
||||
console.log(TAG, 'checkAndUpgrade() 开始检查固件版本')
|
||||
return new Promise((resolve, reject) => {
|
||||
if (!this._activeProtocol) {
|
||||
reject(new Error('[LeFu] 设备未连接'))
|
||||
return
|
||||
}
|
||||
if (!this._deviceInfo) {
|
||||
reject(new Error('[LeFu] 固件信息未就绪,请稍后重试'))
|
||||
return
|
||||
}
|
||||
if (!this._activeProtocol) { reject(new Error('[LeFu] 设备未连接')); return }
|
||||
if (!this._deviceInfo) { reject(new Error('[LeFu] 固件信息未就绪')); return }
|
||||
|
||||
const { firmwareRevision, modelNumber } = this._deviceInfo
|
||||
console.log(TAG, '当前固件:', firmwareRevision, '型号:', modelNumber)
|
||||
const [mcuVer, bleVer, wifiVer, resVer] = (firmwareRevision || '').split('.')
|
||||
|
||||
// 设备单段版本(如 "006")vs 服务端 x.y.z 格式(如 "0.0.6")比对
|
||||
const isServerNewer = (deviceVer: string, serverVer: string): boolean => {
|
||||
const deviceNum = parseInt(deviceVer, 10)
|
||||
const serverNum = (serverVer || '').split('.').map(v => parseInt(v, 10)).reduce((acc, v) => acc * 1000 + v, 0)
|
||||
return serverNum > deviceNum
|
||||
const isServerNewer = (dv: string, sv: string) => {
|
||||
const dn = parseInt(dv, 10)
|
||||
const sn = (sv || '').split('.').map(v => parseInt(v, 10)).reduce((a, v) => a * 1000 + v, 0)
|
||||
return sn > dn
|
||||
}
|
||||
|
||||
get<FirmwareVersion>('weighingScale/v2/firmware/version', { type: modelNumber }, { loading: false })
|
||||
.then(res => {
|
||||
const { mcuVersion, bleVersion, wifiVersion, resVersion } = res.result
|
||||
console.log(TAG, '服务端固件版本:', { mcuVersion, bleVersion, wifiVersion, resVersion })
|
||||
const needUpdate =
|
||||
isServerNewer(mcuVer, mcuVersion) ||
|
||||
isServerNewer(bleVer, bleVersion) ||
|
||||
isServerNewer(wifiVer, wifiVersion) ||
|
||||
isServerNewer(resVer, resVersion)
|
||||
|
||||
console.log(TAG, '需要 OTA 升级:', needUpdate)
|
||||
if (!needUpdate) {
|
||||
resolve(false)
|
||||
return
|
||||
}
|
||||
|
||||
// status: false = 成功,true = 失败
|
||||
const needUpdate = isServerNewer(mcuVer, mcuVersion) || isServerNewer(bleVer, bleVersion)
|
||||
|| isServerNewer(wifiVer, wifiVersion) || isServerNewer(resVer, resVersion)
|
||||
if (!needUpdate) { resolve(false); return }
|
||||
this._activeProtocol.codeOtaUpdate((status: boolean) => {
|
||||
console.log(TAG, 'OTA 升级回调 status:', status)
|
||||
if (!status) {
|
||||
resolve(true)
|
||||
} else {
|
||||
reject(new Error('[LeFu] OTA 升级失败'))
|
||||
}
|
||||
status ? reject(new Error('[LeFu] OTA 升级失败')) : resolve(true)
|
||||
})
|
||||
})
|
||||
.catch(reject)
|
||||
@@ -470,20 +302,15 @@ class LeFuService {
|
||||
}
|
||||
|
||||
// ─── 私有:保活与重连 ─────────────────────────
|
||||
|
||||
private _startKeepAlive(): void {
|
||||
this._stopKeepAlive()
|
||||
console.log(TAG, '_startKeepAlive 保活心跳启动')
|
||||
this._keepAliveTimer = setInterval(() => {
|
||||
this._activeProtocol?.sendKeepAliveCode?.()
|
||||
}, 15000)
|
||||
this._keepAliveTimer = setInterval(() => { this._activeProtocol?.sendKeepAliveCode?.() }, 15000)
|
||||
}
|
||||
|
||||
private _stopKeepAlive(): void {
|
||||
if (this._keepAliveTimer !== null) {
|
||||
clearInterval(this._keepAliveTimer)
|
||||
this._keepAliveTimer = null
|
||||
console.log(TAG, '_stopKeepAlive 保活心跳停止')
|
||||
}
|
||||
}
|
||||
|
||||
@@ -495,115 +322,62 @@ class LeFuService {
|
||||
this._reconnectCount = 0
|
||||
}
|
||||
|
||||
/** 自动重连,最多 _maxReconnect 次,超限后等待用户手动重试 */
|
||||
private _doReconnect(): void {
|
||||
if (this._reconnectCount >= this._maxReconnect) {
|
||||
console.warn(TAG, '重连次数已达上限:', this._maxReconnect)
|
||||
console.warn(TAG, '重连次数已达上限')
|
||||
return
|
||||
}
|
||||
this._reconnectCount++
|
||||
console.log(TAG, `_doReconnect 第 ${this._reconnectCount} 次重连`)
|
||||
console.log(TAG, `_doReconnect 第 ${this._reconnectCount} 次`)
|
||||
this._stopReconnectTimer()
|
||||
this._reconnectTimer = setTimeout(() => {
|
||||
this._plugin?.Blue?.disconnect((res: any) => {
|
||||
console.log(TAG, '重连 disconnect 回调:', res?.errCode)
|
||||
if (res?.errCode === 0) {
|
||||
this._plugin?.Blue?.startBluetoothDevicesDiscovery()
|
||||
}
|
||||
plugin.Blue.disconnect((res: any) => {
|
||||
if (res?.errCode === 0) plugin.Blue.startBluetoothDevicesDiscovery()
|
||||
})
|
||||
}, 2000)
|
||||
}
|
||||
|
||||
// ─── 成员同步 ─────────────────────────────────
|
||||
|
||||
/**
|
||||
* 全量将成员列表同步到设备
|
||||
* 流程:清除设备成员数据 → 逐个下发(顺序执行)
|
||||
* 每步 15 秒超时保护,失败时自动重试当前成员
|
||||
* @param members 成员列表,必须包含且仅包含一个 isSelf=true 的主用户
|
||||
*/
|
||||
syncMembersToDevice(members: DeviceMember[]): Promise<void> {
|
||||
console.log(TAG, 'syncMembersToDevice() 成员数:', members.length)
|
||||
return new Promise((resolve, reject) => {
|
||||
if (!this._activeProtocol) {
|
||||
reject(new Error('[LeFu] 设备未连接,无法同步成员'))
|
||||
return
|
||||
}
|
||||
|
||||
if (!this._activeProtocol) { reject(new Error('[LeFu] 设备未连接')); return }
|
||||
const mainUser = members.find(m => m.isSelf)
|
||||
if (!mainUser) {
|
||||
reject(new Error('[LeFu] 成员列表中缺少主用户(isSelf=true)'))
|
||||
return
|
||||
}
|
||||
|
||||
// 第一步:清除设备上的所有成员数据("01" 仅清成员,保留历史)
|
||||
const clearTimer = setTimeout(() => {
|
||||
reject(new Error('[LeFu] 清除设备成员超时'))
|
||||
}, 15000)
|
||||
if (!mainUser) { reject(new Error('[LeFu] 缺少主用户')); return }
|
||||
|
||||
const clearTimer = setTimeout(() => reject(new Error('[LeFu] 清除设备成员超时')), 15000)
|
||||
this._activeProtocol.codeClearDeviceData('01', (clearRes: number) => {
|
||||
clearTimeout(clearTimer)
|
||||
console.log(TAG, 'codeClearDeviceData 回调:', clearRes)
|
||||
if (clearRes !== 0x00) {
|
||||
reject(new Error('[LeFu] 清除设备成员失败'))
|
||||
return
|
||||
}
|
||||
if (clearRes !== 0x00) { reject(new Error('[LeFu] 清除设备成员失败')); return }
|
||||
|
||||
// 第二步:逐个下发成员(顺序执行,失败自动重试当前)
|
||||
let index = 0
|
||||
let syncTimer: number | null = null
|
||||
|
||||
const resetTimer = () => {
|
||||
if (syncTimer !== null) clearTimeout(syncTimer)
|
||||
syncTimer = setTimeout(() => {
|
||||
reject(new Error(`[LeFu] 第 ${index + 1} 个成员下发超时`))
|
||||
}, 15000)
|
||||
syncTimer = setTimeout(() => reject(new Error(`[LeFu] 第 ${index + 1} 个成员下发超时`)), 15000)
|
||||
}
|
||||
|
||||
const syncNext = () => {
|
||||
if (index >= members.length) {
|
||||
if (syncTimer !== null) clearTimeout(syncTimer)
|
||||
console.log(TAG, 'syncMembersToDevice 全部同步完成')
|
||||
resolve()
|
||||
return
|
||||
}
|
||||
|
||||
const member = members[index]
|
||||
console.log(TAG, `下发第 ${index + 1}/${members.length} 个成员:`, member.name)
|
||||
resetTimer()
|
||||
|
||||
this._activeProtocol.dataSyncUserInfo(
|
||||
{
|
||||
userID: mainUser.id,
|
||||
userName: member.name,
|
||||
// 主用户 memberID 为空,子用户用自己的 id
|
||||
userID: mainUser.id, userName: member.name,
|
||||
memberID: member.isSelf ? '' : member.id,
|
||||
age: member.age,
|
||||
gender: member.gender,
|
||||
height: member.height,
|
||||
isAthleteMode: 0,
|
||||
deviceHeaderIndex: index,
|
||||
currentWeight: '',
|
||||
targetWeight: '',
|
||||
idealWeight: '',
|
||||
recentData: [],
|
||||
},
|
||||
(res: number) => {
|
||||
console.log(TAG, `第 ${index + 1} 个成员同步回调:`, res)
|
||||
if (res === 0) {
|
||||
index++
|
||||
}
|
||||
// 成功进下一个,失败重试当前(index 不变)
|
||||
syncNext()
|
||||
age: member.age, gender: member.gender, height: member.height,
|
||||
isAthleteMode: 0, deviceHeaderIndex: index,
|
||||
currentWeight: '', targetWeight: '', idealWeight: '', recentData: [],
|
||||
},
|
||||
(res: number) => { if (res === 0) index++; syncNext() },
|
||||
)
|
||||
}
|
||||
|
||||
syncNext()
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/** 全局单例,整个小程序共享同一个蓝牙服务实例 */
|
||||
export const lefuService = new LeFuService()
|
||||
|
||||
Reference in New Issue
Block a user