/** * @description 蓝牙数据持久化 */ import { defineStore } from 'pinia' import crc from 'crc' import { sm4 } from 'sm-crypto' import { md5 } from 'js-md5' import { getServerDatetime } from '@/api/check' import { getUserNoListRequest, updateLockUserNoRequest } from '@/api/key' import { updateElectricQuantityRequest } from '@/api/room' import { reportOpenDoorRequest } from '@/api/lockRecords' import { updateTimezoneOffsetRequest } from '@/api/user' import log from '@/utils/log' import { useUserStore } from '@/stores/user' import { getLastRecordTimeRequest, uploadRecordRequest } from '@/api/record' import { transportType } from '@/constant/transportType' import { passthrough } from '@/api/sdk' // 定时器 let timer // 特性值回调 let characteristicValueCallback = null // 搜索次数 let searchNumber = 10 // 搜索提示标志 let searchTipFlag = true // 命令ID const cmdIds = { // 获取公钥 getPublicKey: 0x3090, // 获取私钥 getCommKey: 0x3091, // 获取锁状态 getLockStatus: 0x3040, // 新增用户 addUser: 0x3001, // 开门 openDoor: 0x3005, // 重置设备 resetDevice: 0x3004, // 清理用户 cleanUser: 0x300c, // 扩展命令 expandCmd: 0x3030, // 校准时间 calibrationTime: 0x30f0, // 锁密码列表 lockPasswordList: 0x3021, // 锁卡片列表 lockCardList: 0x3022, // 锁指纹列表 lockFingerprintList: 0x3023, // 锁人脸列表 lockFaceList: 0x3024, // 锁掌静脉列表 lockPalmVeinList: 0x3025, // 锁遥控列表 lockRemoteList: 0x3026, // 锁设置列表 lockSettingList: 0x302a, // 获取Wi-Fi列表 getWifiList: 0x30f6, // Wi-Fi列表 wifiList: 0x30f7, // 配网 distributionNetwork: 0x30f4, // 配网结果 distributionNetworkResult: 0x30f5 } // 子命令ID const subCmdIds = { // 设置开锁密码 setLockPassword: 3, // 重置开锁密码 resetLockPassword: 19, // 注册卡片 registerCard: 24, // 注册卡片确认 registerCardConfirm: 22, // 注册卡片取消 registerCardCancel: 25, // 注册指纹 registerFingerprint: 36, // 注册指纹确认 registerFingerprintConfirm: 32, // 注册指纹取消 registerFingerprintCancel: 37, // 注册指纹过程 registerFingerprintProcess: 33, // 注册人脸 registerFace: 81, // 注册人脸确认 registerFaceConfirm: 82, // 注册人脸取消 registerFaceCancel: 86, // 注册人脸过程 registerFaceProcess: 83, // 注册遥控 registerRemote: 26, // 注册遥控确认 registerRemoteConfirm: 27, // 注册遥控取消 registerRemoteCancel: 28, // 注册掌纹 registerPalmVein: 42, // 注册掌纹确认 registerPalmVeinConfirm: 43, // 注册掌纹取消 registerPalmVeinCancel: 44, // 同步操作记录 syncRecord: 41, // 更新管理员密码 updateAdminPassword: 2, // 修改设置 updateSetting: 70, // 修改设置带参数 updateSettingWithParams: 72, // 微信票据 weChatTickets: 55 } export const useBluetoothStore = defineStore('ble', { state() { return { /* * 蓝牙状态 * -1 未知(初始状态) * 0 正常 * 1 系统蓝牙未打开 * 2 小程序蓝牙功能被禁用 * 3 系统蓝牙未打开且小程序蓝牙功能被禁用 */ bluetoothStatus: -1, // 设备列表 deviceList: [], // 当前锁信息 currentLockInfo: {}, // 当前锁设置信息 currentLockSetting: null, // 当前锁消息设置 currentLockNoticeSetting: null, // 消息序号 messageCount: 1, // 是否初始化蓝牙 isInitBluetooth: false, // 服务器时间 serverTimestamp: 0, // 设备keyID keyId: '0', // 刚绑定的设备名称 bindedDeviceNameList: [] } }, actions: { // 更新锁消息设置 updateCurrentLockNoticeSetting(lockNoticeSetting) { this.currentLockNoticeSetting = { ...this.currentLockNoticeSetting, ...lockNoticeSetting } }, // 保存刚绑定的设备名称 updateBindedDeviceName(name) { if (!this.bindedDeviceNameList.includes(name)) { this.bindedDeviceNameList.push(name) } }, // 更新keyId updateKeyId(keyId) { this.keyId = keyId }, // 二进制转字符串 uint8ArrayToString(uint8Array) { let str = '' for (let i = 0; i < uint8Array.length; i++) { if (uint8Array[i] !== 0) { str += String.fromCharCode(uint8Array[i]) } } return str }, // 更新服务端时间戳 async updateServerTimestamp() { const { code, data, message } = await getServerDatetime({}) let timestamp = new Date().getTime() if (code === 0) { this.serverTimestamp = parseInt(data.date / 1000, 10) timestamp = data.date } return { code, data: { ...data, timestamp }, message } }, // 关闭全部蓝牙监听并关闭蓝牙模拟 closeAllBluetooth() { // #ifdef MP uni.offBluetoothAdapterStateChange() // #endif uni.closeBluetoothAdapter({ success(res) { console.log('关闭蓝牙模块', res) } }) }, // 初始化并监听 async initAndListenBluetooth(tipFlag) { // 初始化蓝牙 const initResult = await this.initBluetooth(tipFlag) if (initResult) { // 更新蓝牙初始化状态 this.updateInitBluetooth(true) // 监听蓝牙连接状态 this.onBluetoothConnectStatus() // 监听设备特征值变化 this.onBluetoothCharacteristicValueChange() return true } return false }, // 更新是否初始化蓝牙字段 updateInitBluetooth(value) { this.isInitBluetooth = value }, // 初始化蓝牙模块 initBluetooth(tipFlag = true) { const that = this // 初始化蓝牙模块 return new Promise(resolve => { uni.openBluetoothAdapter({ success() { that.bluetoothStatus = 0 console.log('蓝牙初始化成功') resolve(true) }, fail(err) { console.log('蓝牙初始化失败', err) // 系统蓝牙未打开 if (err.errCode === 10001 || err.code === 10001) { if (that.bluetoothStatus === 2) { that.bluetoothStatus = 3 } else { that.bluetoothStatus = 1 } } // 小程序蓝牙功能被禁用 if (err.errno === 103) { if (that.bluetoothStatus === 1) { that.bluetoothStatus = 3 } else { that.bluetoothStatus = 2 } } // 蓝牙已经初始化 if (err.errMsg === 'openBluetoothAdapter:fail already opened' || err.code === -1) { resolve(true) return } if (err.errno === 3 && tipFlag) { uni.showModal({ title: '提示', content: '蓝牙功能需要附近设备权限,请前往设置开启微信的附近设备权限后再试', showCancel: false, confirmText: '确定', success(res) { if (res.confirm) { uni.openAppAuthorizeSetting({ success(res) { console.log(res) } }) } } }) } resolve(false) } }) }) }, // 监听蓝牙状态变化 onBluetoothState() { const that = this uni.onBluetoothAdapterStateChange(res => { console.log('蓝牙状态改变', res) if (that.bluetoothStatus === 3 && res.available) { that.bluetoothStatus = 2 } else if (that.bluetoothStatus === 2 && !res.available) { that.bluetoothStatus = 3 } else if (that.bluetoothStatus === 1 && res.available) { that.bluetoothStatus = 0 } else if (that.bluetoothStatus === 0 && !res.available) { that.bluetoothStatus = 1 } else if (that.bluetoothStatus === -1) { if (res.available) { that.bluetoothStatus = 0 } else { that.bluetoothStatus = 1 } } }) }, // 监听蓝牙设备连接状态 onBluetoothConnectStatus() { // 使用箭头函数,直接继承外层的 this(组件实例) uni.onBLEConnectionStateChange(res => { // 直接访问 this.currentLockInfo(最新值) if (res.deviceId === this.currentLockInfo?.deviceId) { console.log('设备连接状态改变', res) // 更新 currentLockInfo(确保是响应式更新) this.updateCurrentLockInfo({ ...this.currentLockInfo, connected: res.connected }) } }) }, // 解析特征值 async parsingCharacteristicValue(binaryData) { const $user = useUserStore() const that = this // 0x20 明文 0x22 SM4(事先约定密钥) 0x23 SM4(设备指定密钥) if (binaryData[7] === 0x20) { if (binaryData[12] * 256 + binaryData[13] === cmdIds.getPublicKey) { if (binaryData[14] === 0) { that.updateCurrentLockInfo({ ...that.currentLockInfo, publicKey: [...binaryData.slice(15, 31)] }) } characteristicValueCallback({ code: binaryData[14] }) } } else if (binaryData[7] === 0x22) { // 截取入参 const cebBinaryData = binaryData.slice(12, binaryData.length - 2) // 解密 const key = new Uint8Array(16) for (let i = 0; i < that.currentLockInfo.name.length; i++) { key[i] = that.currentLockInfo.name.charCodeAt(i) } const decrypted = sm4.decrypt(cebBinaryData, key, { mode: 'ecb', output: 'array' }) console.log('ecb解密后的数据', decrypted) if (decrypted[0] * 256 + decrypted[1] === cmdIds.getCommKey) { if (decrypted[2] === 0) { that.updateCurrentLockInfo({ ...that.currentLockInfo, commKey: decrypted.slice(3, 19), signKey: decrypted.slice(19, 35), pwdTimestamp: this.arrayToTimestamp(decrypted.slice(35, 39)) * 1000 }) console.log('commKey', Array.from(that.currentLockInfo.commKey)) console.log('signKey', Array.from(that.currentLockInfo.signKey)) } characteristicValueCallback({ code: decrypted[2] }) } } else { const cebBinaryData = binaryData.slice(12, binaryData.length - 2) const decrypted = sm4.decrypt(cebBinaryData, that.currentLockInfo.commKey, { mode: 'ecb', output: 'array', padding: 'none' }) const length = binaryData[10] * 256 + binaryData[11] console.log('ecb解密后的数据', decrypted) const cmdId = decrypted[0] * 256 + decrypted[1] switch (cmdId) { case cmdIds.getLockStatus: if (decrypted[2] === 0) { const lockConfig = { vendor: that.uint8ArrayToString(decrypted.slice(3, 23)), product: decrypted[23], model: that.uint8ArrayToString(decrypted.slice(24, 44)), fwVersion: that.uint8ArrayToString(decrypted.slice(44, 64)), hwVersion: that.uint8ArrayToString(decrypted.slice(64, 84)), serialNum0: that.uint8ArrayToString(decrypted.slice(84, 100)), serialNum1: that.uint8ArrayToString(decrypted.slice(100, 116)), btDeviceName: that.uint8ArrayToString(decrypted.slice(116, 132)), electricQuantity: decrypted[132], electricQuantityStandby: decrypted[133], restoreCount: decrypted[134] * 256 + decrypted[135], restoreDate: this.arrayToTimestamp(decrypted.slice(136, 140)), icPartNo: that.uint8ArrayToString(decrypted.slice(140, 150)), indate: this.arrayToTimestamp(decrypted.slice(150, 154)) * 1000, mac: that.uint8ArrayToString(decrypted.slice(154, 174)), timezoneOffset: new Date().getTimezoneOffset() * -60 } that.updateCurrentLockInfo({ ...that.currentLockInfo, featureValue: that.uint8ArrayToString(decrypted.slice(175, 175 + decrypted[174])), featureSettingValue: that.uint8ArrayToString( decrypted.slice( 176 + decrypted[174], 176 + decrypted[174] + decrypted[175 + decrypted[174]] ) ), featureSettingParams: Array.from( decrypted.slice(176 + decrypted[174] + decrypted[175 + decrypted[174]]) ), lockConfig }) characteristicValueCallback({ code: decrypted[2], data: { lockConfig } }) console.log('获取锁状态成功', that.currentLockInfo.lockConfig) } else { characteristicValueCallback({ code: decrypted[2] }) } break case cmdIds.getWifiList: characteristicValueCallback({ code: decrypted[2] }) break case cmdIds.wifiList: const wifiList = [] for (let i = 0; i < decrypted[3]; i++) { wifiList.push({ SSID: that.uint8ArrayToString(decrypted.slice(4 + 33 * i, 4 + 33 * i + 32)), rssi: decrypted[33 + 33 * i] }) } uni.$emit('wifiList', { status: decrypted[2], wifiList }) break case cmdIds.distributionNetwork: characteristicValueCallback({ code: decrypted[2] }) break case cmdIds.distributionNetworkResult: uni.$emit('distributionNetworkResult', { status: decrypted[2] }) break case cmdIds.addUser: that.updateCurrentLockInfo({ ...that.currentLockInfo, token: decrypted.slice(42, 46) }) if (decrypted[46] === 0) { that.updateCurrentLockInfo({ ...that.currentLockInfo, lockUserNo: decrypted[47] * 256 + decrypted[48] }) } console.log('添加用户结果', decrypted[46], that.currentLockInfo.token) characteristicValueCallback({ code: decrypted[46] }) break case cmdIds.expandCmd: const subCmdId = decrypted[3] switch (subCmdId) { case subCmdIds.resetLockPassword: that.updateCurrentLockInfo({ ...that.currentLockInfo, token: decrypted.slice(5, 9) }) characteristicValueCallback({ code: decrypted[2] }) if (decrypted[2] === 0) { that.updateCurrentLockInfo({ ...that.currentLockInfo, encrpyKey: decrypted.slice(9, 17) }) } break case subCmdIds.setLockPassword: that.updateCurrentLockInfo({ ...that.currentLockInfo, token: decrypted.slice(5, 9) }) characteristicValueCallback({ code: decrypted[2], data: { no: decrypted[9] * 256 + decrypted[10], status: decrypted[11] } }) break case subCmdIds.weChatTickets: that.updateCurrentLockInfo({ ...that.currentLockInfo, token: decrypted.slice(5, 9) }) if (decrypted[2] === 0) { characteristicValueCallback({ code: decrypted[9] }) } else { characteristicValueCallback({ code: decrypted[2] }) } break case subCmdIds.registerCard: case subCmdIds.registerRemote: case subCmdIds.registerPalmVein: that.updateCurrentLockInfo({ ...that.currentLockInfo, token: decrypted.slice(5, 9) }) characteristicValueCallback({ code: decrypted[2], data: { status: decrypted[9] } }) break case subCmdIds.registerFingerprint: case subCmdIds.registerFace: that.updateCurrentLockInfo({ ...that.currentLockInfo, token: decrypted.slice(5, 9) }) characteristicValueCallback({ code: decrypted[2], data: { maxProcess: decrypted[11] } }) break case subCmdIds.registerCardConfirm: uni.$emit('registerCardConfirm', { status: decrypted[5], cardNumber: decrypted[6] * 256 + decrypted[7] }) break case subCmdIds.registerFingerprintConfirm: uni.$emit('registerFingerprintConfirm', { status: decrypted[5], fingerprintNumber: decrypted[6] * 256 + decrypted[7] }) break case subCmdIds.registerFaceConfirm: uni.$emit('registerFaceConfirm', { status: decrypted[5], faceNumber: decrypted[6] * 256 + decrypted[7] }) break case subCmdIds.registerRemoteConfirm: uni.$emit('registerRemoteConfirm', { status: decrypted[5], remoteNumber: decrypted[6] * 256 + decrypted[7] }) break case subCmdIds.registerPalmVeinConfirm: uni.$emit('registerPalmVeinConfirm', { status: decrypted[5], palmVeinNumber: decrypted[6] * 256 + decrypted[7] }) break case subCmdIds.registerFingerprintProcess: uni.$emit('registerFingerprintProcess', { status: decrypted[5], process: decrypted[6] }) break case subCmdIds.registerFaceProcess: uni.$emit('registerFaceProcess', { status: decrypted[5], process: decrypted[6] }) break case subCmdIds.syncRecord: if (decrypted[2] === 0 && decrypted[6] > 0) { const records = [] const count = decrypted[6] || 0 for (let i = 0; i < count; i++) { let password = decrypted.slice(14 + 17 * i, 14 + 17 * i + 10) if (password.every(item => item === 0)) { password = null } else { password = this.uint8ArrayToString(password) } const record = { type: decrypted[7 + 17 * i], user: decrypted[8 + 17 * i] * 256 + decrypted[9 + 17 * i], date: this.arrayToTimestamp(decrypted.slice(10 + 17 * i, 14 + 17 * i)) * 1000, success: 1, password } records.push(record) } const { code, message } = await uploadRecordRequest({ records, lockId: this.currentLockInfo.lockId }) characteristicValueCallback({ code, data: { count }, message }) } else { characteristicValueCallback({ code: decrypted[2] }) } break case subCmdIds.updateAdminPassword: that.updateCurrentLockInfo({ ...that.currentLockInfo, token: decrypted.slice(5, 9) }) characteristicValueCallback({ code: decrypted[2] }) break case subCmdIds.updateSetting: // that.updateCurrentLockInfo({ // ...that.currentLockInfo, // token: decrypted.slice(5, 9) // }) characteristicValueCallback({ code: decrypted[2] }) break case subCmdIds.updateSettingWithParams: that.updateCurrentLockInfo({ ...that.currentLockInfo, token: decrypted.slice(5, 9) }) characteristicValueCallback({ code: decrypted[2] }) break default: break } break case cmdIds.openDoor: that.updateCurrentLockInfo({ ...that.currentLockInfo, token: decrypted.slice(2, 6), electricQuantity: decrypted[7], electricQuantityStandby: decrypted[9] }) console.log('开门', decrypted[6], that.currentLockInfo.token) log.info({ code: decrypted[6], message: `锁端返回状态码`, data: { lockName: this.currentLockInfo.name, lockId: this.currentLockInfo.lockId, uid: $user.userInfo.uid, nickname: $user.userInfo.nickname, mobile: $user.userInfo.mobile, email: $user.userInfo.email } }) characteristicValueCallback({ code: decrypted[6] }) if (decrypted[6] === 0) { log.info({ code: decrypted[6], message: `开门成功`, data: { lockName: this.currentLockInfo.name, lockId: this.currentLockInfo.lockId, uid: $user.userInfo.uid, nickname: $user.userInfo.nickname, mobile: $user.userInfo.mobile, email: $user.userInfo.email } }) updateElectricQuantityRequest({ lockId: that.currentLockInfo.lockId, electricQuantity: decrypted[7], electricQuantityStandby: decrypted[9] }).then(res => { if (res.code === 0) { that.updateCurrentLockInfo({ ...that.currentLockInfo, electricQuantityDate: res.data.electricQuantityDate }) } }) reportOpenDoorRequest({ lockId: that.currentLockInfo.lockId, keyId: that.keyId }).then(res => { console.log('上报开门结果', res) }) updateTimezoneOffsetRequest({ timezoneOffset: new Date().getTimezoneOffset() * 60 }).then(res => { console.log('上报时区结果', res) }) } break case cmdIds.calibrationTime: characteristicValueCallback({ code: decrypted[2] }) break case cmdIds.lockPasswordList: case cmdIds.lockCardList: case cmdIds.lockFingerprintList: case cmdIds.lockFaceList: case cmdIds.lockPalmVeinList: case cmdIds.lockRemoteList: case cmdIds.lockSettingList: that.updateCurrentLockInfo({ ...that.currentLockInfo, token: decrypted.slice(3, 7) }) let data if (cmdId === cmdIds.lockSettingList) { data = { list: decrypted.slice(7, length) } } else { data = { page: decrypted[7], size: decrypted[8], list: decrypted.slice(9, length) } } characteristicValueCallback({ code: decrypted[2], data }) break default: that.updateCurrentLockInfo({ ...that.currentLockInfo, token: decrypted.slice(2, 6) }) console.log('默认结果', decrypted[6], that.currentLockInfo.token) characteristicValueCallback({ code: decrypted[6] }) break } } }, // 监听蓝牙设备特征值改变 onBluetoothCharacteristicValueChange() { const that = this // 完整数据 let completeArray // 完整内容数据长度 let length console.log('开始监听特征值改变') uni.onBLECharacteristicValueChange(function (res) { if (res.deviceId === that.currentLockInfo.deviceId) { let binaryData = new Uint8Array(res.value) if ( binaryData[0] === 0xef && binaryData[1] === 0x01 && binaryData[2] === 0xee && binaryData[3] === 0x02 ) { length = binaryData[8] * 256 + binaryData[9] if (length + 14 > binaryData.length) { completeArray = binaryData } else { that.parsingCharacteristicValue(binaryData) } } else if (completeArray) { const combinedArray = new Uint8Array(completeArray.length + binaryData.length) combinedArray.set(completeArray, 0) combinedArray.set(binaryData, completeArray.length) completeArray = combinedArray if (length + 14 === completeArray.length) { that.parsingCharacteristicValue(completeArray) completeArray = null } } } }) }, // 开始搜索蓝牙设备 getBluetoothDevices() { const that = this if (this.bluetoothStatus !== 0) { console.log('搜索未执行', this.bluetoothStatus) this.getBluetoothStatus() return } this.deviceList = [] uni.startBluetoothDevicesDiscovery({ success() { setTimeout(() => { that.searchBluetoothDevices() }, 300) }, async fail(res) { console.log('开始搜索失败', res) if (res.errno === 1509008) { uni.showModal({ title: '提示', content: '安卓手机蓝牙功能需要定位权限,请前往设置开启微信的定位权限后再试', showCancel: false, success(res) { if (res.confirm) { uni.openAppAuthorizeSetting({ success(res) { console.log(res) } }) } uni.navigateBack() } }) } if (res.errCode === 10000) { // 重新初始化蓝牙适配器 await that.initBluetooth() that.getBluetoothDevices() } } }) }, // 定时查询蓝牙设备 searchBluetoothDevices() { const that = this if (this.bluetoothStatus !== 0) { console.log('搜索未执行', this.bluetoothStatus) this.getBluetoothStatus() return } timer = setInterval(() => { uni.getBluetoothDevices({ success(res) { searchNumber-- if (searchNumber === 0 && searchTipFlag) { uni.showModal({ title: '提示', content: '长时间未搜索到任何设备,请确认微信的附近设备权限开启后再试(鸿蒙系统在设置-隐私-定位服务中开启位置信息权限)', showCancel: false, success() { uni.openAppAuthorizeSetting({ success(res) { console.log(res) } }) uni.navigateBack() } }) } const deviceList = res.devices if (deviceList.length !== 0) { searchTipFlag = false } that.deviceList = [] for (let i = 0; i < deviceList.length; i++) { if (deviceList[i]?.advertisServiceUUIDs) { const uuid = deviceList[i]?.advertisServiceUUIDs[0] if (uuid && uuid.slice(2, 8) === '758824' && uuid.slice(30, 32) === '00') { that.deviceList.push(deviceList[i]) } if (uuid && uuid.slice(0, 2) === '75' && uuid.slice(4, 6) === '00') { that.deviceList.push(deviceList[i]) } } } // console.log('设备列表', that.deviceList) }, async fail(res) { console.log('获取设备列表失败', res) if (res.errCode === 10000) { // 重新初始化蓝牙适配器 await that.initBluetooth() } } }) }, 1000) }, // 停止搜索蓝牙设备 stopGetBluetoothDevices() { searchNumber = 10 searchTipFlag = true clearInterval(timer) uni.stopBluetoothDevicesDiscovery() }, // 蓝牙状态提示 async getBluetoothStatus() { if (this.bluetoothStatus === 1) { const initResult = await this.initBluetooth() if (!initResult) { // #ifdef MP-WEIXIN uni.showModal({ title: '提示', content: '蓝牙尚未打开,请先打开蓝牙', showCancel: false, success(res) { if (res.confirm) { wx.openSystemBluetoothSetting({ success(res) { console.log(res) } }) } } }) // #endif // #ifdef APP-PLUS uni.showModal({ title: '提示', content: '蓝牙尚未打开,请先打开蓝牙', showCancel: false, success(res) { if (res.confirm) { // #ifdef APP-ANDROID const main = plus.android.runtimeMainActivity() const Intent = plus.android.importClass('android.content.Intent') const BluetoothAdapter = plus.android.importClass( 'android.bluetooth.BluetoothAdapter' ) const intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE) main.startActivity(intent) // #endif } } }) // #endif } } else if (this.bluetoothStatus === 2 || this.bluetoothStatus === 3) { uni.showModal({ title: '提示', content: '小程序蓝牙功能被禁用,请打开小程序蓝牙权限', showCancel: false, confirmText: '去设置', success(res) { if (res.confirm) { uni.openSetting() } } }) } }, // 检查小程序设置 checkSetting() { const that = this return new Promise(resolve => { // #ifdef MP-WEIXIN uni.getSetting({ async success(res) { const bluetooth = res.authSetting['scope.bluetooth'] if (that.bluetoothStatus === -1) { if (bluetooth !== false) { that.bluetoothStatus = 0 } else { that.bluetoothStatus = 2 } } else if (that.bluetoothStatus === 0 && bluetooth === false) { that.bluetoothStatus = 2 } else if (that.bluetoothStatus === 1 && bluetooth === false) { that.bluetoothStatus = 3 } else if (that.bluetoothStatus === 2 && bluetooth !== false) { that.bluetoothStatus = 0 await that.initBluetooth() } else if (that.bluetoothStatus === 3 && bluetooth !== false) { that.bluetoothStatus = 1 } console.log('蓝牙权限', bluetooth, that.bluetoothStatus) resolve(bluetooth) }, fail() { resolve(false) } }) // #endif // #ifdef APP-PLUS resolve(true) // #endif resolve(false) }) }, // 连接蓝牙设备+获取设备服务+获取设备特征值 connectBluetoothDevice(number = 0) { const that = this return new Promise(resolve => { if (that.bluetoothStatus !== 0) { console.log('连接未执行', that.bluetoothStatus) that.getBluetoothStatus() resolve(false) return } uni.createBLEConnection({ deviceId: that.currentLockInfo.deviceId, timeout: 10000, success(res) { console.log('连接成功', res) // 获取设备服务 const executeBluetoothOperation = () => { uni.getBLEDeviceServices({ deviceId: that.currentLockInfo.deviceId, success(res) { let serviceId for (let i = 0; i < res.services.length; i++) { if (res.services[i].uuid.indexOf('FFF0') !== -1) { serviceId = res.services[i].uuid } } // 获取设备对应服务的特征值 uni.getBLEDeviceCharacteristics({ deviceId: that.currentLockInfo.deviceId, serviceId, success(res) { let notifyCharacteristicId let writeCharacteristicId for (let i = 0; i < res.characteristics.length; i++) { const characteristic = res.characteristics[i] if (characteristic.properties.notify) { notifyCharacteristicId = characteristic.uuid } if (characteristic.properties.write) { writeCharacteristicId = characteristic.uuid } } that.updateCurrentLockInfo({ ...that.currentLockInfo, serviceId, notifyCharacteristicId, writeCharacteristicId }) that.notifyBluetoothCharacteristicValueChange() resolve(true) }, fail(res) { if (res.errCode === 10006) { uni.showToast({ title: '连接失败,请靠近设备并保持设备处于唤醒状态1', icon: 'none' }) } console.log('获取设备特征值失败', res) resolve(false) } }) }, fail(res) { if (res.errCode === 10006) { uni.showToast({ title: '连接失败,请靠近设备并保持设备处于唤醒状态2', icon: 'none' }) } console.log('获取设备服务失败', res) resolve(false) } }) } // #ifdef APP-PLUS setTimeout(executeBluetoothOperation, 800) // #endif // #ifdef MP executeBluetoothOperation() // #endif }, async fail(res) { console.log('连接失败', res) if (res.errno === 1509007) { resolve(true) return } // #ifdef MP if (res.errno === 1509001 && number < 1) { // 超时直接返回 resolve(false) return } // #endif // #ifdef APP-PLUS if (res.code === 10012 && number < 1) { // 超时直接返回 resolve(false) return } // #endif if (number < 1) { // 重新连接 resolve(await that.connectBluetoothDevice(number + 1)) } } }) }) }, // 更新当前锁信息 updateCurrentLockInfo(lockInfo) { console.log('更新当前锁信息', lockInfo) this.currentLockInfo = lockInfo }, // 更新当前锁设置信息 updateCurrentLockSetting(lockSetting) { console.log('更新当前锁设置信息', lockSetting) this.currentLockSetting = lockSetting }, // 订阅设备特征值改变 notifyBluetoothCharacteristicValueChange() { const that = this uni.notifyBLECharacteristicValueChange({ state: true, deviceId: that.currentLockInfo.deviceId, serviceId: that.currentLockInfo.serviceId, characteristicId: that.currentLockInfo.notifyCharacteristicId, success(res) { console.log('订阅成功', res) }, fail(res) { console.log('订阅失败', res) } }) }, // 断开蓝牙连接 closeBluetoothConnection() { const that = this if (that.currentLockInfo.transportType !== transportType.TRANSPORT_TENCENT_YUN) { uni.closeBLEConnection({ deviceId: that.currentLockInfo.deviceId, success(res) { console.log('断开连接成功', res) }, fail(res) { console.log('断开连接失败', res) } }) } }, // 周数组转换 convertWeekdaysToNumber(weekDay) { let weekStr = '00000000' // eslint-disable-next-line no-restricted-syntax for (const day of weekDay) { const index = day % 7 // 将周日的索引转换为0 weekStr = weekStr.substring(0, index) + '1' + weekStr.substring(index + 1) } // 倒序 weekStr weekStr = weekStr.split('').reverse().join('') return parseInt(weekStr, 2) }, // 查找设备并连接 async searchAndConnectDevice() { const that = this let timer1 let timer2 return new Promise(resolve => { uni.startBluetoothDevicesDiscovery({ success() { let searchFlag = false timer2 = setTimeout(async () => { uni.stopBluetoothDevicesDiscovery() clearInterval(timer1) if (!searchFlag) { uni.showModal({ title: '提示', content: '长时间未搜索到任何设备,请确认微信的附近设备权限开启后再试(鸿蒙系统在设置-隐私-定位服务中开启位置信息权限)', showCancel: false, success() { uni.openAppAuthorizeSetting({ success(res) { console.log(res) } }) } }) resolve({ code: -22 }) } else { resolve({ code: -4 }) } }, 10500) timer1 = setInterval(() => { uni.getBluetoothDevices({ success(res) { const deviceList = res.devices if (searchFlag === false && res.devices.length > 0) { searchFlag = true } for (let i = 0; i < deviceList.length; i++) { if (deviceList[i]?.name === that.currentLockInfo.name) { const uuid = deviceList[i]?.advertisServiceUUIDs[0] if (uuid && uuid.slice(2, 8) === '758824') { console.log('设备UUID', uuid, uuid.slice(2, 8), uuid.slice(30, 32)) } else if (uuid && uuid.slice(0, 2) === '75') { console.log('设备UUID', uuid, uuid.slice(2, 8), uuid.slice(4, 6)) } if ( uuid && uuid.slice(2, 8) === '758824' && (uuid.slice(30, 32) === '01' || uuid.slice(30, 32) === '03' || that.bindedDeviceNameList.includes(that.currentLockInfo.name)) ) { uni.stopBluetoothDevicesDiscovery() clearTimeout(timer2) clearInterval(timer1) resolve({ code: 0, data: { deviceId: deviceList[i].deviceId } }) break } else if ( uuid && uuid.slice(2, 8) === '758824' && uuid.slice(30, 32) === '00' ) { uni.stopBluetoothDevicesDiscovery() clearTimeout(timer2) clearInterval(timer1) uni.hideLoading() uni.showToast({ title: '锁已被重置,请重新绑定', icon: 'none' }) resolve({ code: -2 }) break } else if (uuid && uuid.slice(0, 2) === '75' && uuid.slice(4, 6) === '01') { uni.stopBluetoothDevicesDiscovery() clearTimeout(timer2) clearInterval(timer1) resolve({ code: 0, data: { deviceId: deviceList[i].deviceId } }) break } else if (uuid && uuid.slice(0, 2) === '75' && uuid.slice(4, 6) === '00') { uni.stopBluetoothDevicesDiscovery() clearTimeout(timer2) clearInterval(timer1) uni.hideLoading() uni.showToast({ title: '锁已被重置,请重新绑定', icon: 'none' }) resolve({ code: -2 }) break } else { uni.stopBluetoothDevicesDiscovery() clearTimeout(timer2) clearInterval(timer1) resolve({ code: -3 }) break } } } }, async fail(res) { console.log('获取设备列表失败', res) if (res.errCode === 10000) { // 重新初始化蓝牙适配器 await that.initBluetooth() } } }) }, 1000) }, async fail(res) { console.log('开始搜索失败', res) if (res.errCode === 10000) { // 重新初始化蓝牙适配器 await that.initBluetooth() that.searchAndConnectDevice() } else if (res.errno === 1509008) { uni.showModal({ title: '提示', content: '安卓手机蓝牙功能需要定位权限,请前往设置开启微信的定位权限后再试', showCancel: false, success(res) { if (res.confirm) { uni.openAppAuthorizeSetting({ success(res) { console.log(res) } }) } } }) resolve({ code: -23 }) } else { resolve({ code: -1 }) } } }) }) }, // 检查是否已添加为用户 async checkLockUser(flag = false) { console.log('检查是否已添加为用户', this.currentLockInfo.lockUserNo) if (this.currentLockInfo.lockUserNo === 0 || flag) { const timestamp = parseInt(new Date().getTime() / 1000, 10) const password = (Math.floor(Math.random() * 900000) + 100000).toString() console.log('用户未添加,开始添加用户') const addUserParams = { name: this.currentLockInfo.name, keyId: this.keyId, authUid: this.currentLockInfo.senderUserId.toString(), uid: this.currentLockInfo.uid.toString(), openMode: 1, keyType: 0, startDate: this.currentLockInfo.startDate === 0 ? timestamp : parseInt(this.currentLockInfo.startDate / 1000, 10), expireDate: this.currentLockInfo.endDate === 0 ? 0xffffffff : parseInt(this.currentLockInfo.endDate / 1000, 10), useCountLimit: this.currentLockInfo.keyType === 3 ? 1 : 0xffff, isRound: this.currentLockInfo.keyType === 4 ? 1 : 0, weekRound: this.currentLockInfo.keyType === 4 ? this.convertWeekdaysToNumber(this.currentLockInfo.weekDays) : 0, startHour: this.currentLockInfo.keyType === 4 ? new Date(this.currentLockInfo.startDate).getHours() : 0, startMin: this.currentLockInfo.keyType === 4 ? new Date(this.currentLockInfo.startDate).getMinutes() : 0, endHour: this.currentLockInfo.keyType === 4 ? new Date(this.currentLockInfo.endDate).getHours() : 0, endMin: this.currentLockInfo.keyType === 4 ? new Date(this.currentLockInfo.endDate).getMinutes() : 0, role: Number(this.currentLockInfo.keyRight), password } const { code: addUserCode } = await this.addLockUser(addUserParams) console.log('添加用户蓝牙结果', addUserCode, addUserParams) if (addUserCode === 0) { const { code } = await updateLockUserNoRequest({ keyId: this.keyId, lockUserNo: this.currentLockInfo.lockUserNo }) console.log('添加用户请求结果', code) return true } if (addUserCode === 0x0c) { console.log('用户达上限,开始清理用户') const { code: requestCode, data: requestData } = await getUserNoListRequest({ lockId: this.currentLockInfo.lockId }) console.log('获取用户列表请求结果', requestCode, requestData) if (requestCode !== 0) return false const userNoList = requestData.userNos const { code: cleanCode } = await this.cleanLockUser({ name: this.currentLockInfo.name, keyId: this.keyId, authUid: this.currentLockInfo.senderUserId.toString(), uid: this.currentLockInfo.uid.toString(), userNoList }) console.log('清理用户蓝牙结果', cleanCode) if (cleanCode === 0) { return await this.checkLockUser() } return false } return addUserCode === 0x0f } return true }, uint8ArrayToHex(uint8Array) { return Array.from(uint8Array) .map(b => b.toString(16).padStart(2, '0')) .join('') }, hexToArray(hexString) { const result = [] for (let i = 0; i < hexString.length; i += 2) { result.push(parseInt(hexString.slice(i, i + 2), 16)) } return result }, // 写入特征值 async transportMessage(binaryData) { const that = this if (that.currentLockInfo.transportType === transportType.TRANSPORT_TENCENT_YUN) { const content = that.uint8ArrayToHex(binaryData) const { code, data, message } = await passthrough({ request_method: 'POST', request_uri: '/api/v1/tencentYun/CallDeviceActionSync', post_args: { lockId: that.currentLockInfo.lockId, actionId: 'starcloud_action', len: content.length, content } }) if (code === 0) { if (data.Status === 'action execute success!') { if (data.OutputParams.result === '') { characteristicValueCallback({ code: 0, message: `成功,${data.Status}` }) } else { const params = that.hexToArray(data.OutputParams.result) console.log('转换后的数据', params) that.parsingCharacteristicValue(params) } } else { uni.showToast({ title: `命令下发失败,${data.Status}`, icon: 'none' }) characteristicValueCallback({ code: -10, message: `命令下发失败,${data.Status}` }) } } else { characteristicValueCallback({ code, message }) } } else { console.log( '设备ID:', that.currentLockInfo.deviceId, '设备名称:', that.currentLockInfo.name, '私钥:', that.currentLockInfo.commKey ) console.log('设备写入数据:', Array.from(binaryData)) // 次数 const count = Math.ceil(binaryData.length / 20) for (let i = 0; i < count; i++) { const writeData = binaryData.slice( i * 20, i === count - 1 ? binaryData.length : (i + 1) * 20 ) // #ifdef APP-PLUS setTimeout(() => { uni.writeBLECharacteristicValue({ deviceId: that.currentLockInfo.deviceId, serviceId: that.currentLockInfo.serviceId, characteristicId: that.currentLockInfo.writeCharacteristicId, value: writeData.buffer, fail(res) { console.log('写入失败', res) } }) }, (i + 1) * 250) // #endif // #ifdef MP uni.writeBLECharacteristicValue({ deviceId: that.currentLockInfo.deviceId, serviceId: that.currentLockInfo.serviceId, characteristicId: that.currentLockInfo.writeCharacteristicId, value: writeData.buffer, fail(res) { console.log('写入失败', res) } }) // #endif } } }, /* * 生成包头 * encryptionType 加密类型 0:明文,1:AES128,2:SM4(事先约定密钥),3:SM4(设备指定密钥) * originalLength 原始数据长度 * */ createPackageHeader(encryptionType, originalLength) { // 头部数据 let headArray = new Uint8Array(12) // 固定包头 headArray[0] = 0xef headArray[1] = 0x01 headArray[2] = 0xee headArray[3] = 0x02 // 包类型 发送 headArray[4] = 0x01 // 包序号 headArray[5] = this.messageCount / 256 headArray[6] = this.messageCount % 256 this.messageCount++ // 包标识 if (encryptionType === 0) { headArray[7] = 0x20 } else if (encryptionType === 2) { headArray[7] = 0x22 } else { headArray[7] = 0x23 } console.log('包标识', headArray[7]) // 数据长度 if (encryptionType === 0) { headArray[8] = originalLength / 256 headArray[9] = originalLength % 256 } else { const length = Math.ceil(originalLength / 16) * 16 headArray[8] = length / 256 headArray[9] = length % 256 } headArray[10] = originalLength / 256 headArray[11] = originalLength % 256 return headArray }, // 生成包尾 头部数据+内容数据 createPackageEnd(headArray, contentArray) { // 拼接头部和内容 let mergerArray = new Uint8Array(headArray.length + contentArray.length) mergerArray.set(headArray) mergerArray.set(contentArray, headArray.length) // crc加密 const crcResult = crc.crc16kermit(mergerArray) // 拼接crc let newArray = new Uint8Array(mergerArray.length + 2) newArray.set(mergerArray) newArray.set([crcResult / 256, crcResult % 256], mergerArray.length) return newArray }, // 获取公钥 async getPublicKey(name) { // 确认蓝牙状态正常 if (this.bluetoothStatus !== 0) { console.log('写入未执行', this.bluetoothStatus) this.getBluetoothStatus() return { code: -1 } } // 确认设备连接正常 if (!this.currentLockInfo.connected) { const searchResult = await this.searchAndConnectDevice() if (searchResult.code !== 0) { return searchResult } this.updateCurrentLockInfo({ ...this.currentLockInfo, deviceId: searchResult.data.deviceId }) console.log('设备ID:', this.currentLockInfo.deviceId) const result = await this.connectBluetoothDevice() console.log('连接结果', result) if (!result) { return { code: -1 } } } const headArray = this.createPackageHeader(0, 42) const contentArray = new Uint8Array(42) contentArray[0] = cmdIds.getPublicKey / 256 contentArray[1] = cmdIds.getPublicKey % 256 for (let i = 0; i < name.length; i++) { contentArray[i + 2] = name.charCodeAt(i) } const packageArray = this.createPackageEnd(headArray, contentArray) this.transportMessage(packageArray) return this.getResult() }, // 获取私钥 async getCommKey(name, keyId, authUid, nowTime) { // 确认蓝牙状态正常 if (this.bluetoothStatus !== 0) { console.log('写入未执行', this.bluetoothStatus) this.getBluetoothStatus() return { code: -1 } } // 确认设备连接正常 if (!this.currentLockInfo.connected) { const searchResult = await this.searchAndConnectDevice() if (searchResult.code !== 0) { return searchResult } this.updateCurrentLockInfo({ ...this.currentLockInfo, deviceId: searchResult.data.deviceId }) console.log('设备ID:', this.currentLockInfo.deviceId) const result = await this.connectBluetoothDevice() console.log('连接结果', result) if (!result) { return { code: -1 } } } const length = 2 + 40 + 40 + 20 + 4 + 1 + 16 const headArray = this.createPackageHeader(2, length) const contentArray = new Uint8Array(length) contentArray[0] = cmdIds.getCommKey / 256 contentArray[1] = cmdIds.getCommKey % 256 for (let i = 0; i < name.length; i++) { contentArray[i + 2] = name.charCodeAt(i) } for (let i = 0; i < keyId.length; i++) { contentArray[i + 42] = keyId.charCodeAt(i) } for (let i = 0; i < authUid.length; i++) { contentArray[i + 82] = authUid.charCodeAt(i) } contentArray.set(this.timestampToArray(nowTime), 102) contentArray[106] = 16 const md5Array = this.md5Encrypte( authUid + keyId, contentArray.slice(102, 106), this.currentLockInfo.publicKey ) contentArray.set(md5Array, 107) const cebArray = sm4.encrypt(contentArray, contentArray.slice(2, 18), { mode: 'ecb', output: 'array' }) const packageArray = this.createPackageEnd(headArray, cebArray) this.transportMessage(packageArray) return this.getResult() }, // md5加密 md5Encrypte(text, token, key) { const length = text.length + 4 + 16 const md5Array = new Uint8Array(length) for (let i = 0; i < text.length; i++) { md5Array[i] = text.charCodeAt(i) } md5Array.set(token, text.length) md5Array.set(key, text.length + 4) const md5Text = md5(md5Array) return new Uint8Array(md5Text.match(/.{1,2}/g).map(byte => parseInt(byte, 16))) }, // 获取锁状态 async getLockStatus(data) { // 确认蓝牙状态正常 if ( this.bluetoothStatus !== 0 && this.currentLockInfo.transportType !== transportType.TRANSPORT_TENCENT_YUN ) { console.log('写入未执行', this.bluetoothStatus) this.getBluetoothStatus() return { code: -1 } } // 确认设备连接正常 if ( !this.currentLockInfo.connected && this.currentLockInfo.transportType !== transportType.TRANSPORT_TENCENT_YUN ) { const searchResult = await this.searchAndConnectDevice() if (searchResult.code !== 0) { return searchResult } this.updateCurrentLockInfo({ ...this.currentLockInfo, deviceId: searchResult.data.deviceId }) console.log('设备ID:', this.currentLockInfo.deviceId) const result = await this.connectBluetoothDevice() console.log('连接结果', result) if (!result) { return { code: -1 } } } const { name, uid, nowTime, localTime } = data const length = 2 + 40 + 20 + 4 + 4 const headArray = this.createPackageHeader(3, length) const contentArray = new Uint8Array(length) contentArray[0] = cmdIds.getLockStatus / 256 contentArray[1] = cmdIds.getLockStatus % 256 for (let i = 0; i < name.length; i++) { contentArray[i + 2] = name.charCodeAt(i) } for (let i = 0; i < uid.length; i++) { contentArray[i + 42] = uid.charCodeAt(i) } contentArray.set(this.timestampToArray(nowTime), 62) contentArray.set(this.timestampToArray(localTime), 66) const cebArray = sm4.encrypt(contentArray, this.currentLockInfo.commKey, { mode: 'ecb', output: 'array' }) const packageArray = this.createPackageEnd(headArray, cebArray) this.transportMessage(packageArray) return this.getResult(this.getLockStatus, data) }, // 获取锁状态 async getLockStatusInfo(data) { // 确认蓝牙状态正常 if (this.bluetoothStatus !== 0) { console.log('写入未执行', this.bluetoothStatus) this.getBluetoothStatus() return { code: -1 } } // 确认设备连接正常 if (!this.currentLockInfo.connected) { const searchResult = await this.searchAndConnectDevice() if (searchResult.code !== 0) { return searchResult } this.updateCurrentLockInfo({ ...this.currentLockInfo, deviceId: searchResult.data.deviceId }) console.log('设备ID:', this.currentLockInfo.deviceId) const result = await this.connectBluetoothDevice() console.log('连接结果', result) if (!result) { return { code: -1 } } } const { name, uid, nowTime, localTime } = data const length = 2 + 40 + 20 + 4 + 4 const headArray = this.createPackageHeader(3, length) const contentArray = new Uint8Array(length) contentArray[0] = cmdIds.getLockStatus / 256 contentArray[1] = cmdIds.getLockStatus % 256 for (let i = 0; i < name.length; i++) { contentArray[i + 2] = name.charCodeAt(i) } for (let i = 0; i < uid.length; i++) { contentArray[i + 42] = uid.charCodeAt(i) } contentArray.set(this.timestampToArray(nowTime), 62) contentArray.set(this.timestampToArray(localTime), 66) const cebArray = sm4.encrypt(contentArray, this.currentLockInfo.commKey, { mode: 'ecb', output: 'array' }) const packageArray = this.createPackageEnd(headArray, cebArray) this.transportMessage(packageArray) return this.getResult(this.getLockStatusInfo, data) }, // 获取Wi-Fi列表 async getWifiList(data) { // 确认蓝牙状态正常 if (this.bluetoothStatus !== 0) { console.log('写入未执行', this.bluetoothStatus) this.getBluetoothStatus() return { code: -1 } } // 确认设备连接正常 if (!this.currentLockInfo.connected) { const searchResult = await this.searchAndConnectDevice() if (searchResult.code !== 0) { return searchResult } this.updateCurrentLockInfo({ ...this.currentLockInfo, deviceId: searchResult.data.deviceId }) console.log('设备ID:', this.currentLockInfo.deviceId) const result = await this.connectBluetoothDevice() console.log('连接结果', result) if (!result) { return { code: -1 } } } const { uid } = data const length = 2 + 20 const headArray = this.createPackageHeader(3, length) const contentArray = new Uint8Array(length) contentArray[0] = cmdIds.getWifiList / 256 contentArray[1] = cmdIds.getWifiList % 256 for (let i = 0; i < uid.length; i++) { contentArray[i + 2] = uid.charCodeAt(i) } const cebArray = sm4.encrypt(contentArray, this.currentLockInfo.commKey, { mode: 'ecb', output: 'array' }) const packageArray = this.createPackageEnd(headArray, cebArray) this.transportMessage(packageArray) return this.getResult(this.getWifiList, data) }, // 配网 async distributionNetwork(data) { // 确认蓝牙状态正常 if (this.bluetoothStatus !== 0) { console.log('写入未执行', this.bluetoothStatus) this.getBluetoothStatus() return { code: -1 } } // 确认设备连接正常 if (!this.currentLockInfo.connected) { const searchResult = await this.searchAndConnectDevice() if (searchResult.code !== 0) { return searchResult } this.updateCurrentLockInfo({ ...this.currentLockInfo, deviceId: searchResult.data.deviceId }) console.log('设备ID:', this.currentLockInfo.deviceId) const result = await this.connectBluetoothDevice() console.log('连接结果', result) if (!result) { return { code: -1 } } } const { SSID, password, json } = data const length = 2 + 30 + 20 + 2 + json.length const headArray = this.createPackageHeader(3, length) const contentArray = new Uint8Array(length) contentArray[0] = cmdIds.distributionNetwork / 256 contentArray[1] = cmdIds.distributionNetwork % 256 for (let i = 0; i < SSID.length; i++) { contentArray[i + 2] = SSID.charCodeAt(i) } for (let i = 0; i < password.length; i++) { contentArray[i + 32] = password.charCodeAt(i) } contentArray[52] = json.length / 256 contentArray[53] = json.length % 256 for (let i = 0; i < json.length; i++) { contentArray[i + 54] = json.charCodeAt(i) } const cebArray = sm4.encrypt(contentArray, this.currentLockInfo.commKey, { mode: 'ecb', output: 'array', padding: length % 16 === 0 ? 'none' : 'pkcs#5' }) const packageArray = this.createPackageEnd(headArray, cebArray) this.transportMessage(packageArray) return this.getResult(this.distributionNetwork, data) }, // 时间戳转二进制 timestampToArray(timestamp) { const array = new Uint8Array(4) array[0] = (timestamp & 0xff000000) >> 24 array[1] = (timestamp & 0xff0000) >> 16 array[2] = (timestamp & 0xff00) >> 8 array[3] = timestamp & 0xff return array }, // 二进制转时间戳 arrayToTimestamp(array) { const timestamp = (array[0] << 24) | (array[1] << 16) | (array[2] << 8) | array[3] return timestamp >>> 0 }, // 添加用户 async addLockUser(data) { // 确认蓝牙状态正常 if ( this.bluetoothStatus !== 0 && this.currentLockInfo.transportType !== transportType.TRANSPORT_TENCENT_YUN ) { console.log('写入未执行', this.bluetoothStatus) this.getBluetoothStatus() return { code: -1 } } // 确认设备连接正常 if ( !this.currentLockInfo.connected && this.currentLockInfo.transportType !== transportType.TRANSPORT_TENCENT_YUN ) { const searchResult = await this.searchAndConnectDevice() if (searchResult.code !== 0) { return searchResult } this.updateCurrentLockInfo({ ...this.currentLockInfo, deviceId: searchResult.data.deviceId }) console.log('设备ID:', this.currentLockInfo.deviceId) const result = await this.connectBluetoothDevice() console.log('连接结果', result) if (!result) { return { code: -1 } } } const { name, authUid, uid, keyId, openMode, keyType, startDate, expireDate, useCountLimit, isRound, weekRound, startHour, startMin, endHour, endMin, role, password } = data const length = 2 + 40 + 20 + 40 + 20 + 1 + 1 + 4 + 4 + 2 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 20 + 4 + 1 + 16 const headArray = this.createPackageHeader(3, length) const contentArray = new Uint8Array(length) contentArray[0] = cmdIds.addUser / 256 contentArray[1] = cmdIds.addUser % 256 for (let i = 0; i < name.length; i++) { contentArray[i + 2] = name.charCodeAt(i) } for (let i = 0; i < authUid.length; i++) { contentArray[i + 42] = authUid.charCodeAt(i) } for (let i = 0; i < keyId.length; i++) { contentArray[i + 62] = keyId.charCodeAt(i) } for (let i = 0; i < uid.length; i++) { contentArray[i + 102] = uid.charCodeAt(i) } contentArray[122] = openMode contentArray[123] = keyType contentArray.set(this.timestampToArray(startDate), 124) contentArray.set(this.timestampToArray(expireDate), 128) contentArray[132] = useCountLimit / 256 contentArray[133] = useCountLimit % 256 contentArray[134] = isRound contentArray[135] = weekRound contentArray[136] = startHour contentArray[137] = startMin contentArray[138] = endHour contentArray[139] = endMin contentArray[140] = role for (let i = 0; i < password.length; i++) { contentArray[i + 141] = password.charCodeAt(i) } contentArray.set(this.currentLockInfo.token || this.timestampToArray(startDate), 161) contentArray[165] = 16 const md5Array = this.md5Encrypte( authUid + keyId, this.currentLockInfo.token || this.timestampToArray(startDate), this.currentLockInfo.publicKey ) contentArray.set(md5Array, 166) const cebArray = sm4.encrypt(contentArray, this.currentLockInfo.commKey, { mode: 'ecb', output: 'array' }) const packageArray = this.createPackageEnd(headArray, cebArray) this.transportMessage(packageArray, false) return this.getResult(this.addLockUser, data) }, // 添加用户 async bindLock(data) { // 确认蓝牙状态正常 if (this.bluetoothStatus !== 0) { console.log('写入未执行', this.bluetoothStatus) this.getBluetoothStatus() return { code: -1 } } // 确认设备连接正常 if (!this.currentLockInfo.connected) { const searchResult = await this.searchAndConnectDevice() if (searchResult.code !== 0) { return searchResult } this.updateCurrentLockInfo({ ...this.currentLockInfo, deviceId: searchResult.data.deviceId }) console.log('设备ID:', this.currentLockInfo.deviceId) const result = await this.connectBluetoothDevice() console.log('连接结果', result) if (!result) { return { code: -1 } } } const { name, authUid, uid, keyId, openMode, keyType, startDate, expireDate, useCountLimit, isRound, weekRound, startHour, startMin, endHour, endMin, role, password } = data const length = 2 + 40 + 20 + 40 + 20 + 1 + 1 + 4 + 4 + 2 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 20 + 4 + 1 + 16 const headArray = this.createPackageHeader(3, length) const contentArray = new Uint8Array(length) contentArray[0] = cmdIds.addUser / 256 contentArray[1] = cmdIds.addUser % 256 for (let i = 0; i < name.length; i++) { contentArray[i + 2] = name.charCodeAt(i) } for (let i = 0; i < authUid.length; i++) { contentArray[i + 42] = authUid.charCodeAt(i) } for (let i = 0; i < keyId.length; i++) { contentArray[i + 62] = keyId.charCodeAt(i) } for (let i = 0; i < uid.length; i++) { contentArray[i + 102] = uid.charCodeAt(i) } contentArray[122] = openMode contentArray[123] = keyType contentArray.set(this.timestampToArray(startDate), 124) contentArray.set(this.timestampToArray(expireDate), 128) contentArray[132] = useCountLimit / 256 contentArray[133] = useCountLimit % 256 contentArray[134] = isRound contentArray[135] = weekRound contentArray[136] = startHour contentArray[137] = startMin contentArray[138] = endHour contentArray[139] = endMin contentArray[140] = role for (let i = 0; i < password.length; i++) { contentArray[i + 141] = password.charCodeAt(i) } contentArray.set(this.currentLockInfo.token || this.timestampToArray(startDate), 161) contentArray[165] = 16 const md5Array = this.md5Encrypte( authUid + keyId, this.currentLockInfo.token || this.timestampToArray(startDate), this.currentLockInfo.publicKey ) contentArray.set(md5Array, 166) const cebArray = sm4.encrypt(contentArray, this.currentLockInfo.commKey, { mode: 'ecb', output: 'array' }) const packageArray = this.createPackageEnd(headArray, cebArray) this.transportMessage(packageArray, false) return this.getResult(this.bindLock, data) }, // 获取写入结果 getResult(request, params) { const $user = useUserStore() return new Promise(resolve => { const getResultTimer = setTimeout(() => { log.info({ code: -1, message: `操作失败,蓝牙操作超时`, data: { lockName: this.currentLockInfo.name, lockId: this.currentLockInfo.lockId, uid: $user.userInfo.uid, nickname: $user.userInfo.nickname, mobile: $user.userInfo.mobile, email: $user.userInfo.email } }) resolve({ code: -1 }) }, 20000) characteristicValueCallback = async data => { // code 6 token过期,重新获取 if (data.code === 6) { log.info({ code: 0, message: `开门中,更换过期token,开始重试`, data: { lockName: this.currentLockInfo.name, lockId: this.currentLockInfo.lockId, uid: $user.userInfo.uid, nickname: $user.userInfo.nickname, mobile: $user.userInfo.mobile, email: $user.userInfo.email } }) clearTimeout(getResultTimer) resolve(await request(params)) } else { clearTimeout(getResultTimer) resolve(data) } } }) }, // 开门 async openDoor(data) { const $user = useUserStore() try { log.info({ code: 0, message: `开始开门`, data: { lockName: this.currentLockInfo.name, lockId: this.currentLockInfo.lockId, uid: $user.userInfo.uid, nickname: $user.userInfo.nickname, mobile: $user.userInfo.mobile, email: $user.userInfo.email } }) // 确认蓝牙状态正常 if ( this.bluetoothStatus !== 0 && this.currentLockInfo.transportType !== transportType.TRANSPORT_TENCENT_YUN ) { console.log('写入未执行', this.bluetoothStatus) this.getBluetoothStatus() if (this.bluetoothStatus === -1) { log.info({ code: -25, message: `开门失败,未知蓝牙状态, ${this.bluetoothStatus}`, data: { lockName: this.currentLockInfo.name, lockId: this.currentLockInfo.lockId, uid: $user.userInfo.uid, nickname: $user.userInfo.nickname, mobile: $user.userInfo.mobile, email: $user.userInfo.email } }) } else if (this.bluetoothStatus === 1) { log.info({ code: -20, message: `开门失败,蓝牙未开启, ${this.bluetoothStatus}`, data: { lockName: this.currentLockInfo.name, lockId: this.currentLockInfo.lockId, uid: $user.userInfo.uid, nickname: $user.userInfo.nickname, mobile: $user.userInfo.mobile, email: $user.userInfo.email } }) } else if (this.bluetoothStatus === 2) { log.info({ code: -21, message: `开门失败,小程序蓝牙权限被禁用, ${this.bluetoothStatus}`, data: { lockName: this.currentLockInfo.name, lockId: this.currentLockInfo.lockId, uid: $user.userInfo.uid, nickname: $user.userInfo.nickname, mobile: $user.userInfo.mobile, email: $user.userInfo.email } }) } else if (this.bluetoothStatus === 3) { log.info({ code: -26, message: `开门失败,蓝牙未开启且小程序蓝牙功能被禁用, ${this.bluetoothStatus}`, data: { lockName: this.currentLockInfo.name, lockId: this.currentLockInfo.lockId, uid: $user.userInfo.uid, nickname: $user.userInfo.nickname, mobile: $user.userInfo.mobile, email: $user.userInfo.email } }) } return { code: -1 } } log.info({ code: 0, message: `开门中,蓝牙权限正常, ${this.bluetoothStatus}`, data: { lockName: this.currentLockInfo.name, lockId: this.currentLockInfo.lockId, uid: $user.userInfo.uid, nickname: $user.userInfo.nickname, mobile: $user.userInfo.mobile, email: $user.userInfo.email } }) // 确认设备连接正常 if ( !this.currentLockInfo.connected && this.currentLockInfo.transportType !== transportType.TRANSPORT_TENCENT_YUN ) { const searchResult = await this.searchAndConnectDevice() console.log('searchResult', searchResult) if (searchResult.code === 0) { log.info({ code: searchResult.code, message: `开门中,已搜索到设备`, data: { lockName: this.currentLockInfo.name, lockId: this.currentLockInfo.lockId, uid: $user.userInfo.uid, nickname: $user.userInfo.nickname, mobile: $user.userInfo.mobile, email: $user.userInfo.email } }) } else if (searchResult.code === -1) { log.info({ code: searchResult.code, message: `开门失败,搜索失败`, data: { lockName: this.currentLockInfo.name, lockId: this.currentLockInfo.lockId, uid: $user.userInfo.uid, nickname: $user.userInfo.nickname, mobile: $user.userInfo.mobile, email: $user.userInfo.email } }) } else if (searchResult.code === -2) { log.info({ code: searchResult.code, message: `开门失败,锁已被重置`, data: { lockName: this.currentLockInfo.name, lockId: this.currentLockInfo.lockId, uid: $user.userInfo.uid, nickname: $user.userInfo.nickname, mobile: $user.userInfo.mobile, email: $user.userInfo.email } }) } else if (searchResult.code === -3) { log.info({ code: searchResult.code, message: `开门失败,设备已找到但uuid异常`, data: { lockName: this.currentLockInfo.name, lockId: this.currentLockInfo.lockId, uid: $user.userInfo.uid, nickname: $user.userInfo.nickname, mobile: $user.userInfo.mobile, email: $user.userInfo.email } }) } else if (searchResult.code === -4) { log.info({ code: searchResult.code, message: `开门失败,未搜索到操作设备`, data: { lockName: this.currentLockInfo.name, lockId: this.currentLockInfo.lockId, uid: $user.userInfo.uid, nickname: $user.userInfo.nickname, mobile: $user.userInfo.mobile, email: $user.userInfo.email } }) } else if (searchResult.code === -22) { log.info({ code: searchResult.code, message: `开门失败,微信附近设备权限未开启`, data: { lockName: this.currentLockInfo.name, lockId: this.currentLockInfo.lockId, uid: $user.userInfo.uid, nickname: $user.userInfo.nickname, mobile: $user.userInfo.mobile, email: $user.userInfo.email } }) } else if (searchResult.code === -23) { log.info({ code: searchResult.code, message: `开门失败,微信定位权限未开启`, data: { lockName: this.currentLockInfo.name, lockId: this.currentLockInfo.lockId, uid: $user.userInfo.uid, nickname: $user.userInfo.nickname, mobile: $user.userInfo.mobile, email: $user.userInfo.email } }) } if (searchResult.code !== 0) { return { code: -1 } } this.updateCurrentLockInfo({ ...this.currentLockInfo, deviceId: searchResult.data.deviceId }) console.log('设备ID:', this.currentLockInfo.deviceId) const result = await this.connectBluetoothDevice() if (result) { log.info({ code: 0, message: `开门中,设备连接成功`, data: { lockName: this.currentLockInfo.name, lockId: this.currentLockInfo.lockId, uid: $user.userInfo.uid, nickname: $user.userInfo.nickname, mobile: $user.userInfo.mobile, email: $user.userInfo.email } }) } else { log.info({ code: -1, message: `开门失败,设备连接失败`, data: { lockName: this.currentLockInfo.name, lockId: this.currentLockInfo.lockId, uid: $user.userInfo.uid, nickname: $user.userInfo.nickname, mobile: $user.userInfo.mobile, email: $user.userInfo.email } }) } console.log('连接结果', result) if (!result) { return { code: -1 } } } log.info({ code: 0, message: `开门中,设备已连接`, data: { lockName: this.currentLockInfo.name, lockId: this.currentLockInfo.lockId, uid: $user.userInfo.uid, nickname: $user.userInfo.nickname, mobile: $user.userInfo.mobile, email: $user.userInfo.email } }) // 检查是否已添加为用户 const checkResult = await this.checkLockUser() if (!checkResult) { log.info({ code: -1, message: `开门失败,用户添加失败`, data: { lockName: this.currentLockInfo.name, lockId: this.currentLockInfo.lockId, uid: $user.userInfo.uid, nickname: $user.userInfo.nickname, mobile: $user.userInfo.mobile, email: $user.userInfo.email } }) return { code: -1 } } log.info({ code: 0, message: `开门中,用户已添加`, data: { lockName: this.currentLockInfo.name, lockId: this.currentLockInfo.lockId, uid: $user.userInfo.uid, nickname: $user.userInfo.nickname, mobile: $user.userInfo.mobile, email: $user.userInfo.email } }) const { name, uid, openMode, openTime, onlineToken } = data const length = 2 + 40 + 20 + 1 + 4 + 4 + 1 + 16 + 16 const headArray = this.createPackageHeader(3, length) const contentArray = new Uint8Array(length) contentArray[0] = cmdIds.openDoor / 256 contentArray[1] = cmdIds.openDoor % 256 for (let i = 0; i < name.length; i++) { contentArray[i + 2] = name.charCodeAt(i) } for (let i = 0; i < uid.length; i++) { contentArray[i + 42] = uid.charCodeAt(i) } contentArray[62] = openMode contentArray.set(this.timestampToArray(openTime), 63) console.log('开门时token', this.currentLockInfo.token) contentArray.set(this.currentLockInfo.token || this.timestampToArray(openTime), 67) contentArray[71] = 16 const md5Array = this.md5Encrypte( name + uid, this.currentLockInfo.token || this.timestampToArray(openTime), this.currentLockInfo.signKey ) contentArray.set(md5Array, 72) for (let i = 0; i < onlineToken.length; i++) { contentArray[i + 88] = onlineToken.charCodeAt(i) } const cebArray = sm4.encrypt(contentArray, this.currentLockInfo.commKey, { mode: 'ecb', output: 'array' }) const packageArray = this.createPackageEnd(headArray, cebArray) log.info({ code: 0, message: `开门中,开始写入`, data: { lockName: this.currentLockInfo.name, lockId: this.currentLockInfo.lockId, uid: $user.userInfo.uid, nickname: $user.userInfo.nickname, mobile: $user.userInfo.mobile, email: $user.userInfo.email } }) this.transportMessage(packageArray) return this.getResult(this.openDoor, data) } catch (e) { log.error({ code: -1, error: e, message: `开门失败,未知错误` }) return { code: -1 } } }, // 清理用户 async cleanLockUser(data) { // 确认蓝牙状态正常 if ( this.bluetoothStatus !== 0 && this.currentLockInfo.transportType !== transportType.TRANSPORT_TENCENT_YUN ) { console.log('写入未执行', this.bluetoothStatus) this.getBluetoothStatus() return { code: -1 } } // 确认设备连接正常 if ( !this.currentLockInfo.connected && this.currentLockInfo.transportType !== transportType.TRANSPORT_TENCENT_YUN ) { const searchResult = await this.searchAndConnectDevice() if (searchResult.code !== 0) { return searchResult } this.updateCurrentLockInfo({ ...this.currentLockInfo, deviceId: searchResult.data.deviceId }) console.log('设备ID:', this.currentLockInfo.deviceId) const result = await this.connectBluetoothDevice() console.log('连接结果', result) if (!result) { return { code: -1 } } } const { name, authUid, keyId, uid, userNoList } = data const length = 2 + 40 + 20 + 40 + 20 + 2 + userNoList.length + 4 + 1 + 16 const headArray = this.createPackageHeader(3, length) const contentArray = new Uint8Array(length) contentArray[0] = cmdIds.cleanUser / 256 contentArray[1] = cmdIds.cleanUser % 256 for (let i = 0; i < name.length; i++) { contentArray[i + 2] = name.charCodeAt(i) } for (let i = 0; i < authUid.length; i++) { contentArray[i + 42] = authUid.charCodeAt(i) } for (let i = 0; i < keyId.length; i++) { contentArray[i + 62] = keyId.charCodeAt(i) } for (let i = 0; i < uid.length; i++) { contentArray[i + 102] = uid.charCodeAt(i) } contentArray[122] = userNoList.length / 256 contentArray[123] = userNoList.length % 256 for (let i = 0; i < userNoList.length; i++) { contentArray[i + 124] = userNoList[i] } contentArray.set( this.currentLockInfo.token || new Uint8Array([0, 0, 0, 0]), 124 + userNoList.length ) contentArray[128 + userNoList.length] = 16 const md5Array = this.md5Encrypte( authUid + keyId, this.currentLockInfo.token || new Uint8Array([0, 0, 0, 0]), this.currentLockInfo.publicKey ) contentArray.set(md5Array, 129 + userNoList.length) const cebArray = sm4.encrypt(contentArray, this.currentLockInfo.commKey, { mode: 'ecb', output: 'array' }) const packageArray = this.createPackageEnd(headArray, cebArray) this.transportMessage(packageArray) return this.getResult(this.cleanLockUser, data) }, // 恢复出厂设置 async resetDevice(data) { // 确认蓝牙状态正常 if ( this.bluetoothStatus !== 0 && this.currentLockInfo.transportType !== transportType.TRANSPORT_TENCENT_YUN ) { console.log('写入未执行', this.bluetoothStatus) this.getBluetoothStatus() return { code: -1 } } // 确认设备连接正常 if ( !this.currentLockInfo.connected && this.currentLockInfo.transportType !== transportType.TRANSPORT_TENCENT_YUN ) { const searchResult = await this.searchAndConnectDevice() if (searchResult.code !== 0) { return searchResult } this.updateCurrentLockInfo({ ...this.currentLockInfo, deviceId: searchResult.data.deviceId }) console.log('设备ID:', this.currentLockInfo.deviceId) const result = await this.connectBluetoothDevice() console.log('连接结果', result) if (!result) { return { code: -1 } } } // 检查是否已添加为用户 const checkResult = await this.checkLockUser() if (!checkResult) { return { code: -1 } } const { name, authUid } = data const length = 2 + 40 + 20 + 4 + 1 + 16 const headArray = this.createPackageHeader(3, length) const contentArray = new Uint8Array(length) contentArray[0] = cmdIds.resetDevice / 256 contentArray[1] = cmdIds.resetDevice % 256 for (let i = 0; i < name.length; i++) { contentArray[i + 2] = name.charCodeAt(i) } for (let i = 0; i < authUid.length; i++) { contentArray[i + 42] = authUid.charCodeAt(i) } contentArray.set(this.currentLockInfo.token || new Uint8Array([0, 0, 0, 0]), 62) contentArray[66] = 16 const md5Array = this.md5Encrypte( name, this.currentLockInfo.token || new Uint8Array([0, 0, 0, 0]), this.currentLockInfo.publicKey ) contentArray.set(md5Array, 67) const cebArray = sm4.encrypt(contentArray, this.currentLockInfo.commKey, { mode: 'ecb', output: 'array' }) const packageArray = this.createPackageEnd(headArray, cebArray) this.transportMessage(packageArray) return this.getResult(this.resetDevice, data) }, // 重置开锁密码 async resetLockPassword(data) { // 确认蓝牙状态正常 if ( this.bluetoothStatus !== 0 && this.currentLockInfo.transportType !== transportType.TRANSPORT_TENCENT_YUN ) { console.log('写入未执行', this.bluetoothStatus) this.getBluetoothStatus() return { code: -1 } } // 确认设备连接正常 if ( !this.currentLockInfo.connected && this.currentLockInfo.transportType !== transportType.TRANSPORT_TENCENT_YUN ) { const searchResult = await this.searchAndConnectDevice() if (searchResult.code !== 0) { return searchResult } this.updateCurrentLockInfo({ ...this.currentLockInfo, deviceId: searchResult.data.deviceId }) console.log('设备ID:', this.currentLockInfo.deviceId) const result = await this.connectBluetoothDevice() console.log('连接结果', result) if (!result) { return { code: -1 } } } // 检查是否已添加为用户 const checkResult = await this.checkLockUser() if (!checkResult) { return { code: -1 } } const { keyId, uid } = data const length = 2 + 1 + 1 + 40 + 20 + 4 + 1 + 16 const headArray = this.createPackageHeader(3, length) const contentArray = new Uint8Array(length) contentArray[0] = cmdIds.expandCmd / 256 contentArray[1] = cmdIds.expandCmd % 256 // 子命令 contentArray[2] = subCmdIds.resetLockPassword contentArray[3] = length - 4 for (let i = 0; i < keyId.length; i++) { contentArray[i + 4] = keyId.charCodeAt(i) } for (let i = 0; i < uid.length; i++) { contentArray[i + 44] = uid.charCodeAt(i) } contentArray.set(this.currentLockInfo.token || new Uint8Array([0, 0, 0, 0]), 64) contentArray[68] = 16 const md5Array = this.md5Encrypte( keyId + uid, this.currentLockInfo.token || new Uint8Array([0, 0, 0, 0]), this.currentLockInfo.signKey ) contentArray.set(md5Array, 69) const cebArray = sm4.encrypt(contentArray, this.currentLockInfo.commKey, { mode: 'ecb', output: 'array' }) const packageArray = this.createPackageEnd(headArray, cebArray) this.transportMessage(packageArray) return this.getResult(this.resetLockPassword, data) }, // 设置密码 async setLockPassword(data) { // 确认蓝牙状态正常 if ( this.bluetoothStatus !== 0 && this.currentLockInfo.transportType !== transportType.TRANSPORT_TENCENT_YUN ) { console.log('写入未执行', this.bluetoothStatus) this.getBluetoothStatus() return { code: -1 } } // 确认设备连接正常 if ( !this.currentLockInfo.connected && this.currentLockInfo.transportType !== transportType.TRANSPORT_TENCENT_YUN ) { const searchResult = await this.searchAndConnectDevice() if (searchResult.code !== 0) { return searchResult } this.updateCurrentLockInfo({ ...this.currentLockInfo, deviceId: searchResult.data.deviceId }) console.log('设备ID:', this.currentLockInfo.deviceId) const result = await this.connectBluetoothDevice() console.log('连接结果', result) if (!result) { return { code: -1 } } } // 检查是否已添加为用户 const checkResult = await this.checkLockUser() if (!checkResult) { return { code: -1 } } const { keyId, uid, pwdNo, operate, isAdmin, pwd, userCountLimit, startTime, endTime } = data const length = 2 + 1 + 1 + 40 + 20 + 2 + 1 + 1 + 20 + 2 + 4 + 4 + 4 + 1 + 16 const headArray = this.createPackageHeader(3, length) const contentArray = new Uint8Array(length) contentArray[0] = cmdIds.expandCmd / 256 contentArray[1] = cmdIds.expandCmd % 256 // 子命令 contentArray[2] = subCmdIds.setLockPassword contentArray[3] = length - 3 for (let i = 0; i < keyId.length; i++) { contentArray[i + 4] = keyId.charCodeAt(i) } for (let i = 0; i < uid.length; i++) { contentArray[i + 44] = uid.charCodeAt(i) } contentArray[64] = pwdNo / 256 contentArray[65] = pwdNo % 256 contentArray[66] = operate contentArray[67] = isAdmin for (let i = 0; i < pwd.length; i++) { contentArray[i + 68] = pwd.charCodeAt(i) } contentArray[88] = userCountLimit / 256 contentArray[89] = userCountLimit % 256 contentArray.set(this.currentLockInfo.token || new Uint8Array([0, 0, 0, 0]), 90) contentArray.set(this.timestampToArray(startTime), 94) contentArray.set(this.timestampToArray(endTime), 98) contentArray[102] = 16 const md5Array = this.md5Encrypte( keyId + uid, this.currentLockInfo.token || new Uint8Array([0, 0, 0, 0]), this.currentLockInfo.signKey ) contentArray.set(md5Array, 103) const cebArray = sm4.encrypt(contentArray, this.currentLockInfo.commKey, { mode: 'ecb', output: 'array' }) const packageArray = this.createPackageEnd(headArray, cebArray) this.transportMessage(packageArray) return this.getResult(this.setLockPassword, data) }, // 微信票据 async weChatTickets(data) { // 确认蓝牙状态正常 if ( this.bluetoothStatus !== 0 && this.currentLockInfo.transportType !== transportType.TRANSPORT_TENCENT_YUN ) { console.log('写入未执行', this.bluetoothStatus) this.getBluetoothStatus() return { code: -1 } } // 确认设备连接正常 if ( !this.currentLockInfo.connected && this.currentLockInfo.transportType !== transportType.TRANSPORT_TENCENT_YUN ) { const searchResult = await this.searchAndConnectDevice() if (searchResult.code !== 0) { return searchResult } this.updateCurrentLockInfo({ ...this.currentLockInfo, deviceId: searchResult.data.deviceId }) console.log('设备ID:', this.currentLockInfo.deviceId) const result = await this.connectBluetoothDevice() console.log('连接结果', result) if (!result) { return { code: -1 } } } // 检查是否已添加为用户 const checkResult = await this.checkLockUser() if (!checkResult) { return { code: -1 } } const { keyId, uid, openId, snTicket } = data const length = 2 + 1 + 1 + 40 + 20 + 4 + 2 + openId.length + 2 + snTicket.length + 1 + 16 const headArray = this.createPackageHeader(3, length) const contentArray = new Uint8Array(length) contentArray[0] = cmdIds.expandCmd / 256 contentArray[1] = cmdIds.expandCmd % 256 contentArray[2] = subCmdIds.weChatTickets contentArray[3] = length - 3 for (let i = 0; i < keyId.length; i++) { contentArray[i + 4] = keyId.charCodeAt(i) } for (let i = 0; i < uid.length; i++) { contentArray[i + 44] = uid.charCodeAt(i) } contentArray.set(this.currentLockInfo.token || new Uint8Array([0, 0, 0, 0]), 64) contentArray[68] = openId.length / 256 contentArray[69] = openId.length % 256 for (let i = 0; i < openId.length; i++) { contentArray[i + 70] = openId.charCodeAt(i) } contentArray[70 + openId.length] = snTicket.length / 256 contentArray[71 + openId.length] = snTicket.length % 256 for (let i = 0; i < snTicket.length; i++) { contentArray[i + 72 + openId.length] = snTicket.charCodeAt(i) } contentArray[72 + openId.length + snTicket.length] = 16 const md5Array = this.md5Encrypte( keyId + uid, this.currentLockInfo.token || new Uint8Array([0, 0, 0, 0]), this.currentLockInfo.signKey ) contentArray.set(md5Array, 73 + openId.length + snTicket.length) const cebArray = sm4.encrypt(contentArray, this.currentLockInfo.commKey, { mode: 'ecb', output: 'array' }) const packageArray = this.createPackageEnd(headArray, cebArray) this.transportMessage(packageArray) return this.getResult(this.weChatTickets, data) }, parseTimeToList(timeString) { let timeList = [0, 0, 0, 0] if (timeString.includes(':')) { let timeParts = timeString.split(':') timeList[2] = parseInt(timeParts[0], 10) timeList[3] = parseInt(timeParts[1], 10) } return new Uint8Array(timeList) }, // 注册身份认证 async registerAuthentication(data) { // 确认蓝牙状态正常 if ( this.bluetoothStatus !== 0 && this.currentLockInfo.transportType !== transportType.TRANSPORT_TENCENT_YUN ) { console.log('写入未执行', this.bluetoothStatus) this.getBluetoothStatus() return { code: -21 } } // 确认设备连接正常 if ( !this.currentLockInfo.connected && this.currentLockInfo.transportType !== transportType.TRANSPORT_TENCENT_YUN ) { const searchResult = await this.searchAndConnectDevice() if (searchResult.code !== 0) { return searchResult } this.updateCurrentLockInfo({ ...this.currentLockInfo, deviceId: searchResult.data.deviceId }) console.log('设备ID:', this.currentLockInfo.deviceId) const result = await this.connectBluetoothDevice() console.log('连接结果', result) if (!result) { return { code: -1 } } } // 检查是否已添加为用户 const checkResult = await this.checkLockUser() if (!checkResult) { return { code: -1 } } let { type, keyId, uid, no, operate, isAdmin, userCountLimit, isForce, isRound, weekDays, startDate, endDate, startTime, endTime } = data startDate = Math.floor(startDate / 1000) endDate = Math.floor(endDate / 1000) const length = 2 + 1 + 1 + 40 + 20 + 2 + 2 + 1 + 1 + 1 + 4 + 1 + 1 + 4 + 4 + 4 + 4 + 1 + 16 const headArray = this.createPackageHeader(3, length) const contentArray = new Uint8Array(length) contentArray[0] = cmdIds.expandCmd / 256 contentArray[1] = cmdIds.expandCmd % 256 // 子命令 if (type === 'card') { contentArray[2] = subCmdIds.registerCard } else if (type === 'fingerprint') { contentArray[2] = subCmdIds.registerFingerprint } else if (type === 'face') { contentArray[2] = subCmdIds.registerFace } else if (type === 'remote') { contentArray[2] = subCmdIds.registerRemote } else if (type === 'palmVein') { contentArray[2] = subCmdIds.registerPalmVein } contentArray[3] = length - 3 for (let i = 0; i < keyId.length; i++) { contentArray[i + 4] = keyId.charCodeAt(i) } for (let i = 0; i < uid.length; i++) { contentArray[i + 44] = uid.charCodeAt(i) } contentArray[64] = (no || 0) / 256 contentArray[65] = (no || 0) % 256 contentArray[66] = (userCountLimit || 0xffff) / 256 contentArray[67] = (userCountLimit || 0xffff) % 256 contentArray[68] = operate contentArray[69] = isAdmin || 0 contentArray[70] = isForce || 0 contentArray.set(this.currentLockInfo.token || new Uint8Array([0, 0, 0, 0]), 71) contentArray[75] = isRound contentArray[76] = this.convertWeekdaysToNumber(weekDays) contentArray.set(this.timestampToArray(startDate), 77) contentArray.set(this.timestampToArray(endDate), 81) if (isRound) { contentArray.set(this.parseTimeToList(startTime), 85) contentArray.set(this.parseTimeToList(endTime), 89) } else { contentArray.set(new Uint8Array([0, 0, 0, 0]), 85) contentArray.set(new Uint8Array([0, 0, 0, 0]), 89) } contentArray[93] = 16 const md5Array = this.md5Encrypte( keyId + uid, this.currentLockInfo.token || new Uint8Array([0, 0, 0, 0]), this.currentLockInfo.signKey ) contentArray.set(md5Array, 94) const cebArray = sm4.encrypt(contentArray, this.currentLockInfo.commKey, { mode: 'ecb', output: 'array' }) const packageArray = this.createPackageEnd(headArray, cebArray) this.transportMessage(packageArray) return this.getResult(this.registerAuthentication, data) }, // 注册身份认证取消 async registerAuthenticationCancel(data) { const { type, keyId, uid } = data const length = 2 + 1 + 1 + 40 + 20 + 4 + 1 + 16 const headArray = this.createPackageHeader(3, length) const contentArray = new Uint8Array(length) contentArray[0] = cmdIds.expandCmd / 256 contentArray[1] = cmdIds.expandCmd % 256 // 子命令 if (type === 'card') { contentArray[2] = subCmdIds.registerCardCancel } else if (type === 'fingerprint') { contentArray[2] = subCmdIds.registerFingerprintCancel } else if (type === 'face') { contentArray[2] = subCmdIds.registerFaceCancel } else if (type === 'remote') { contentArray[2] = subCmdIds.registerRemoteCancel } else if (type === 'palmVein') { contentArray[2] = subCmdIds.registerPalmVeinCancel } contentArray[3] = length - 3 for (let i = 0; i < keyId.length; i++) { contentArray[i + 4] = keyId.charCodeAt(i) } for (let i = 0; i < uid.length; i++) { contentArray[i + 44] = uid.charCodeAt(i) } contentArray.set(this.currentLockInfo.token || new Uint8Array([0, 0, 0, 0]), 64) contentArray[68] = 16 const md5Array = this.md5Encrypte( keyId + uid, this.currentLockInfo.token || new Uint8Array([0, 0, 0, 0]), this.currentLockInfo.signKey ) contentArray.set(md5Array, 69) const cebArray = sm4.encrypt(contentArray, this.currentLockInfo.commKey, { mode: 'ecb', output: 'array' }) const packageArray = this.createPackageEnd(headArray, cebArray) this.transportMessage(packageArray) return this.getResult(this.registerAuthenticationCancel, data) }, // 获取操作记录 async syncRecord(params) { // 确认蓝牙状态正常 if ( this.bluetoothStatus !== 0 && this.currentLockInfo.transportType !== transportType.TRANSPORT_TENCENT_YUN ) { console.log('写入未执行', this.bluetoothStatus) this.getBluetoothStatus() return { code: -1 } } // 确认设备连接正常 if ( !this.currentLockInfo.connected && this.currentLockInfo.transportType !== transportType.TRANSPORT_TENCENT_YUN ) { const searchResult = await this.searchAndConnectDevice() if (searchResult.code !== 0) { return searchResult } this.updateCurrentLockInfo({ ...this.currentLockInfo, deviceId: searchResult.data.deviceId }) console.log('设备ID:', this.currentLockInfo.deviceId) const result = await this.connectBluetoothDevice() console.log('连接结果', result) if (!result) { return { code: -1 } } } // 检查是否已添加为用户 const checkResult = await this.checkLockUser() if (!checkResult) { return { code: -1 } } const { uid, keyId } = params const { code, data, message } = await this.syncSingleRecord({ uid, keyId }) if (code === 0) { if (data?.count === 10) { return await this.syncSingleRecord({ uid, keyId }) } return { code, data, message } } return { code, data, message } }, // 获取单次操作记录 async syncSingleRecord(data) { const { keyId, uid } = data const logsCount = 10 const timeResult = await getLastRecordTimeRequest({ lockId: this.currentLockInfo.lockId }) if (timeResult.code !== 0) { return timeResult } const operateDate = Math.ceil(timeResult.data.operateDate / 1000) const currentDate = Math.ceil(timeResult.data.currentDate / 1000) const length = 2 + 1 + 1 + 40 + 20 + 2 + 4 + 4 + 1 + 16 const headArray = this.createPackageHeader(3, length) const contentArray = new Uint8Array(length) contentArray[0] = cmdIds.expandCmd / 256 contentArray[1] = cmdIds.expandCmd % 256 // 子命令 contentArray[2] = subCmdIds.syncRecord contentArray[3] = length - 3 for (let i = 0; i < keyId.length; i++) { contentArray[i + 4] = keyId.charCodeAt(i) } for (let i = 0; i < uid.length; i++) { contentArray[i + 44] = uid.charCodeAt(i) } contentArray[64] = logsCount / 256 contentArray[65] = logsCount % 256 contentArray.set(this.timestampToArray(operateDate), 66) contentArray.set(this.timestampToArray(currentDate), 70) contentArray[74] = 16 const md5Array = this.md5Encrypte( uid + keyId, this.currentLockInfo.token || new Uint8Array([0, 0, 0, 0]), this.currentLockInfo.publicKey ) contentArray.set(md5Array, 75) const cebArray = sm4.encrypt(contentArray, this.currentLockInfo.commKey, { mode: 'ecb', output: 'array' }) const packageArray = this.createPackageEnd(headArray, cebArray) this.transportMessage(packageArray) return this.getResult(this.syncSingleRecord, data) }, // 更新管理员密码 async updateAdminPassword(data) { // 确认蓝牙状态正常 if ( this.bluetoothStatus !== 0 && this.currentLockInfo.transportType !== transportType.TRANSPORT_TENCENT_YUN ) { console.log('写入未执行', this.bluetoothStatus) this.getBluetoothStatus() return { code: -21 } } // 确认设备连接正常 if ( !this.currentLockInfo.connected && this.currentLockInfo.transportType !== transportType.TRANSPORT_TENCENT_YUN ) { const searchResult = await this.searchAndConnectDevice() if (searchResult.code !== 0) { return searchResult } this.updateCurrentLockInfo({ ...this.currentLockInfo, deviceId: searchResult.data.deviceId }) console.log('设备ID:', this.currentLockInfo.deviceId) const result = await this.connectBluetoothDevice() console.log('连接结果', result) if (!result) { return { code: -1 } } } // 检查是否已添加为用户 const checkResult = await this.checkLockUser() if (!checkResult) { return { code: -1 } } let { keyId, uid, adminPwd, userCountLimit, startDate, endDate } = data const length = 2 + 1 + 1 + 40 + 20 + 2 + 20 + 2 + 4 + 4 + 4 + 1 + 16 const headArray = this.createPackageHeader(3, length) const contentArray = new Uint8Array(length) contentArray[0] = cmdIds.expandCmd / 256 contentArray[1] = cmdIds.expandCmd % 256 contentArray[2] = subCmdIds.updateAdminPassword contentArray[3] = length - 3 for (let i = 0; i < keyId.length; i++) { contentArray[i + 4] = keyId.charCodeAt(i) } for (let i = 0; i < uid.length; i++) { contentArray[i + 44] = uid.charCodeAt(i) } contentArray[64] = 1 / 256 contentArray[65] = 1 % 256 for (let i = 0; i < adminPwd.length; i++) { contentArray[i + 66] = adminPwd.charCodeAt(i) } contentArray[86] = (userCountLimit || 0xffff) / 256 contentArray[87] = (userCountLimit || 0xffff) % 256 contentArray.set(this.currentLockInfo.token || new Uint8Array([0, 0, 0, 0]), 88) contentArray.set(this.timestampToArray(startDate), 92) contentArray.set(this.timestampToArray(endDate), 96) contentArray[100] = 16 const md5Array = this.md5Encrypte( keyId + uid, this.currentLockInfo.token || new Uint8Array([0, 0, 0, 0]), this.currentLockInfo.signKey ) contentArray.set(md5Array, 101) const cebArray = sm4.encrypt(contentArray, this.currentLockInfo.commKey, { mode: 'ecb', output: 'array' }) const packageArray = this.createPackageEnd(headArray, cebArray) this.transportMessage(packageArray) return this.getResult(this.updateAdminPassword, data) }, // 更新设置 async updateSetting(data) { // 确认蓝牙状态正常 if ( this.bluetoothStatus !== 0 && this.currentLockInfo.transportType !== transportType.TRANSPORT_TENCENT_YUN ) { console.log('写入未执行', this.bluetoothStatus) this.getBluetoothStatus() return { code: -21 } } // 确认设备连接正常 if ( !this.currentLockInfo.connected && this.currentLockInfo.transportType !== transportType.TRANSPORT_TENCENT_YUN ) { const searchResult = await this.searchAndConnectDevice() if (searchResult.code !== 0) { return searchResult } this.updateCurrentLockInfo({ ...this.currentLockInfo, deviceId: searchResult.data.deviceId }) console.log('设备ID:', this.currentLockInfo.deviceId) const result = await this.connectBluetoothDevice() console.log('连接结果', result) if (!result) { return { code: -1 } } } // 检查是否已添加为用户 const checkResult = await this.checkLockUser() if (!checkResult) { return { code: -1 } } let { keyId, uid, featureBit, featureEnable, withParams, params } = data let length = 2 + 1 + 1 + 40 + 20 + 4 + 1 + 16 if (withParams) { length += 2 + params.length } else { length += 2 } const headArray = this.createPackageHeader(3, length) const contentArray = new Uint8Array(length) contentArray[0] = cmdIds.expandCmd / 256 contentArray[1] = cmdIds.expandCmd % 256 contentArray[2] = withParams ? subCmdIds.updateSettingWithParams : subCmdIds.updateSetting contentArray[3] = length - 3 for (let i = 0; i < keyId.length; i++) { contentArray[i + 4] = keyId.charCodeAt(i) } for (let i = 0; i < uid.length; i++) { contentArray[i + 44] = uid.charCodeAt(i) } contentArray[64] = featureBit if (withParams) { contentArray[65] = params.length contentArray.set(new Uint8Array(params), 66) } else { contentArray[65] = featureEnable } contentArray.set( this.currentLockInfo.token || new Uint8Array([0, 0, 0, 0]), withParams ? 66 + params.length : 66 ) contentArray[withParams ? 70 + params.length : 70] = 16 const md5Array = this.md5Encrypte( keyId + uid, this.currentLockInfo.token || new Uint8Array([0, 0, 0, 0]), this.currentLockInfo.signKey ) contentArray.set(md5Array, withParams ? 71 + params.length : 71) console.log('加密前:', Array.from(contentArray)) const cebArray = sm4.encrypt(contentArray, this.currentLockInfo.commKey, { mode: 'ecb', output: 'array' }) const packageArray = this.createPackageEnd(headArray, cebArray) this.transportMessage(packageArray) return this.getResult(this.updateSetting, data) }, // 校准时间 async calibrationTime(data) { // 确认蓝牙状态正常 if ( this.bluetoothStatus !== 0 && this.currentLockInfo.transportType !== transportType.TRANSPORT_TENCENT_YUN ) { console.log('写入未执行', this.bluetoothStatus) this.getBluetoothStatus() return { code: -1 } } // 确认设备连接正常 if ( !this.currentLockInfo.connected && this.currentLockInfo.transportType !== transportType.TRANSPORT_TENCENT_YUN ) { const searchResult = await this.searchAndConnectDevice() if (searchResult.code !== 0) { return searchResult } this.updateCurrentLockInfo({ ...this.currentLockInfo, deviceId: searchResult.data.deviceId }) console.log('设备ID:', this.currentLockInfo.deviceId) const result = await this.connectBluetoothDevice() console.log('连接结果', result) if (!result) { return { code: -1 } } } // 检查是否已添加为用户 const checkResult = await this.checkLockUser() if (!checkResult) { return { code: -1 } } let { lockId, uid, nowTime } = data const length = 2 + 40 + 20 + 4 + 4 + 1 + 16 const headArray = this.createPackageHeader(3, length) const contentArray = new Uint8Array(length) contentArray[0] = cmdIds.calibrationTime / 256 contentArray[1] = cmdIds.calibrationTime % 256 for (let i = 0; i < lockId.length; i++) { contentArray[i + 2] = lockId.charCodeAt(i) } for (let i = 0; i < uid.length; i++) { contentArray[i + 42] = uid.charCodeAt(i) } contentArray.set(this.timestampToArray(nowTime), 62) contentArray.set(this.currentLockInfo.token || new Uint8Array([0, 0, 0, 0]), 66) contentArray[70] = 16 const md5Array = this.md5Encrypte( lockId + uid, this.currentLockInfo.token || new Uint8Array([0, 0, 0, 0]), this.currentLockInfo.signKey ) contentArray.set(md5Array, 71) const cebArray = sm4.encrypt(contentArray, this.currentLockInfo.commKey, { mode: 'ecb', output: 'array' }) const packageArray = this.createPackageEnd(headArray, cebArray) this.transportMessage(packageArray) return this.getResult(this.calibrationTime, data) }, // 获取锁数据列表 async getLockDataList(data) { // 确认蓝牙状态正常 if ( this.bluetoothStatus !== 0 && this.currentLockInfo.transportType !== transportType.TRANSPORT_TENCENT_YUN ) { console.log('写入未执行', this.bluetoothStatus) this.getBluetoothStatus() return { code: -21 } } // 确认设备连接正常 if ( !this.currentLockInfo.connected && this.currentLockInfo.transportType !== transportType.TRANSPORT_TENCENT_YUN ) { const searchResult = await this.searchAndConnectDevice() if (searchResult.code !== 0) { return searchResult } this.updateCurrentLockInfo({ ...this.currentLockInfo, deviceId: searchResult.data.deviceId }) console.log('设备ID:', this.currentLockInfo.deviceId) const result = await this.connectBluetoothDevice() console.log('连接结果', result) if (!result) { return { code: -1 } } } // 检查是否已添加为用户 const checkResult = await this.checkLockUser() if (!checkResult) { return { code: -1 } } let { lockId, uid, page, countReq, type } = data let length = 2 + 40 + 20 + 4 + 1 + 16 if (type !== 'setting') { length += 2 } const headArray = this.createPackageHeader(3, length) const contentArray = new Uint8Array(length) let id if (type === 'password') { id = cmdIds.lockPasswordList } else if (type === 'card') { id = cmdIds.lockCardList } else if (type === 'fingerprint') { id = cmdIds.lockFingerprintList } else if (type === 'face') { id = cmdIds.lockFaceList } else if (type === 'remote') { id = cmdIds.lockRemoteList } else if (type === 'palmVein') { id = cmdIds.lockPalmVeinList } else if (type === 'setting') { id = cmdIds.lockSettingList } contentArray[0] = id / 256 contentArray[1] = id % 256 for (let i = 0; i < lockId.length; i++) { contentArray[i + 2] = lockId.charCodeAt(i) } for (let i = 0; i < uid.length; i++) { contentArray[i + 42] = uid.charCodeAt(i) } if (type !== 'setting') { contentArray[62] = page contentArray[63] = countReq contentArray.set(this.currentLockInfo.token || new Uint8Array([0, 0, 0, 0]), 64) contentArray[68] = 16 const md5Array = this.md5Encrypte( lockId + uid, this.currentLockInfo.token || new Uint8Array([0, 0, 0, 0]), this.currentLockInfo.signKey ) contentArray.set(md5Array, 69) } else { contentArray.set(this.currentLockInfo.token || new Uint8Array([0, 0, 0, 0]), 62) contentArray[66] = 16 const md5Array = this.md5Encrypte( lockId + uid, this.currentLockInfo.token || new Uint8Array([0, 0, 0, 0]), this.currentLockInfo.signKey ) contentArray.set(md5Array, 67) } const cebArray = sm4.encrypt(contentArray, this.currentLockInfo.commKey, { mode: 'ecb', output: 'array' }) const packageArray = this.createPackageEnd(headArray, cebArray) this.transportMessage(packageArray) return this.getResult(this.getLockDataList, data) } } })