import { sm4 } from 'sm-crypto' import { arrayToTimestamp, convertWeekdaysToNumber, createPackageEnd, md5Encrypt, timestampToArray, uint8ArrayToString } from './format' import { configs } from './env' import { cmdIds, Result, subCmdIds } from './constant' import { closeBLEConnection, searchAndConnectDevice, writeBLECharacteristicValue } from './uni/basic' import { addCustomPasswordRequest, changeAdminKeyboardPwdRequest, deleteLockRequest, deletePasswordRequest, getLastRecordTimeRequest, getLockNetTokenRequest, getStarCloudToken, getUserNoListRequest, updateElectricQuantityRequest, updateLockUserNoRequest, updatePasswordRequest, uploadRecordRequest } from './api' import { buildNumber, getStorage, setStorage, version } from './export' import log from './log' /** * 同步开门记录 * @param params * @param {Number} [params.uid] 用户ID * @param {Boolean} [params.disconnect] 操作后是否断开连接, 默认断开 * @returns {Promise} */ export async function syncOpenRecord(params) { // 设置执行账号 const result = await this.login(params.uid) if (result.code !== Result.Success.code) { return result } // 确认设备连接正常 if (!params.connected) { const searchResult = await searchAndConnectDevice(this.lockInfo.bluetooth.bluetoothDeviceName) if (searchResult.code !== Result.Success.code) { return searchResult } this.updateLockInfo(searchResult.data) } // 检查是否已添加为用户 const checkResult = await this.checkLockUser() if (checkResult.code !== Result.Success.code) { return checkResult } const uid = this.lockInfo.uid.toString() const keyId = this.lockInfo.keyId.toString() const logsCount = 10 const timeResult = await getLastRecordTimeRequest({ lockId: this.lockInfo.lockId }) if (timeResult.code !== Result.Success.code) { 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.syncOpenRecord 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(timestampToArray(operateDate), 66) contentArray.set(timestampToArray(currentDate), 70) contentArray[74] = 16 const md5Array = md5Encrypt( uid + keyId, this.lockInfo.token || new Uint8Array([0, 0, 0, 0]), this.lockInfo.bluetooth.publicKey ) contentArray.set(md5Array, 75) const cebArray = sm4.encrypt(contentArray, this.lockInfo.bluetooth.privateKey, { mode: 'ecb', output: 'array' }) const packageArray = createPackageEnd(headArray, cebArray) const writeResult = await writeBLECharacteristicValue( this.lockInfo.deviceId, this.lockInfo.serviceId, this.lockInfo.writeCharacteristicId, packageArray ) if (writeResult.code !== Result.Success.code) { return writeResult } return this.getWriteResult(this.syncOpenRecord, params) } /** * 清理用户 * @returns {Promise} */ export async function cleanLockUser() { // 确认设备连接正常 const searchResult = await searchAndConnectDevice(this.lockInfo.bluetooth.bluetoothDeviceName) if (searchResult.code !== Result.Success.code) { return searchResult } this.updateLockInfo(searchResult.data) // 获取并处理锁信息 let { uid: authUid, keyId, token, bluetooth } = this.lockInfo let { uid } = this.userInfo authUid = authUid.toString() uid = uid.toString() keyId = keyId.toString() const name = bluetooth.bluetoothDeviceName // 获取用户列表 const { code: requestCode, data: requestData } = await getUserNoListRequest({ lockId: this.lockInfo.lockId }) console.log('获取用户列表请求结果', requestCode, requestData) if (requestCode !== 0) return Result.Fail const userNoList = requestData.userNos // 组装发送数据 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(token || new Uint8Array([0, 0, 0, 0]), 124 + userNoList.length) contentArray[128 + userNoList.length] = 16 const md5Array = md5Encrypt( authUid + keyId, token || new Uint8Array([0, 0, 0, 0]), bluetooth.publicKey ) contentArray.set(md5Array, 129 + userNoList.length) const cebArray = sm4.encrypt(contentArray, bluetooth.privateKey, { mode: 'ecb', output: 'array' }) const packageArray = createPackageEnd(headArray, cebArray) const writeResult = await writeBLECharacteristicValue( this.lockInfo.deviceId, this.lockInfo.serviceId, this.lockInfo.writeCharacteristicId, packageArray ) if (writeResult.code !== Result.Success.code) { return writeResult } return this.getWriteResult(this.cleanLockUser, { disconnect: false }) } /** * 登录星云 * @param {Number} [uid] 用户ID * @returns Result */ export async function login(uid) { let accounts = getStorage('starCloudAccount') let userInfos = getStorage('starCloudUser') if (!accounts) { accounts = {} } if (!userInfos) { userInfos = {} } const id = uid || this.accounts[0].uid this.accountInfo = accounts[id] if (this.accountInfo) { if (this.accountInfo.token) { this.userInfo = userInfos[id] setStorage('starCloudToken', this.accountInfo.token) return Result.Success } const { code, data: userInfo, message } = await getStarCloudToken({ username: this.accountInfo.username, password: this.accountInfo.password, clientId: this.clientId, clientSecret: this.clientSecret }) if (code === Result.Success.code) { this.userInfo = userInfo this.accountInfo = { username: this.accountInfo.username, password: this.accountInfo.password, token: userInfo.access_token, uid: userInfo.uid } setStorage('starCloudToken', userInfo.access_token) accounts[userInfo.uid] = { uid: userInfo.uid, username: this.accountInfo.username, password: this.accountInfo.password, token: userInfo.access_token } setStorage('starCloudAccount', accounts) userInfos[userInfo.uid] = userInfo setStorage('starCloudUser', userInfos) } return new Result(code, {}, message) } return Result.Fail } // 获取公钥 export async function getPublicKey() { const headArray = this.createPackageHeader(0, 42) const contentArray = new Uint8Array(42) contentArray[0] = cmdIds.getPublicKey / 256 contentArray[1] = cmdIds.getPublicKey % 256 const name = this.lockInfo.bluetooth.bluetoothDeviceName for (let i = 0; i < name.length; i++) { contentArray[i + 2] = name.charCodeAt(i) } const packageArray = createPackageEnd(headArray, contentArray) const writeResult = await writeBLECharacteristicValue( this.lockInfo.deviceId, this.lockInfo.serviceId, this.lockInfo.writeCharacteristicId, packageArray ) if (writeResult.code !== Result.Success.code) { return writeResult } return this.getWriteResult(this.getPublicKey, { disconnect: false }) } // 获取私钥 export async function getCommKey() { 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 const name = this.lockInfo.bluetooth.bluetoothDeviceName const keyId = '0' const authUid = this.accountInfo.uid.toString() await this.getServerTimestamp() const nowTime = this.serverTimestamp 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(timestampToArray(nowTime), 102) contentArray[106] = 16 const md5Array = md5Encrypt( authUid + keyId, contentArray.slice(102, 106), this.lockInfo.bluetooth.publicKey ) contentArray.set(md5Array, 107) const cebArray = sm4.encrypt(contentArray, contentArray.slice(2, 18), { mode: 'ecb', output: 'array' }) const packageArray = createPackageEnd(headArray, cebArray) const writeResult = await writeBLECharacteristicValue( this.lockInfo.deviceId, this.lockInfo.serviceId, this.lockInfo.writeCharacteristicId, packageArray ) if (writeResult.code !== Result.Success.code) { return writeResult } return this.getWriteResult(this.getCommKey, { disconnect: false }) } // 获取锁状态 export async function getLockStatus() { 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 const name = this.lockInfo.bluetooth.bluetoothDeviceName const uid = this.accountInfo.uid.toString() await this.getServerTimestamp() const nowTime = this.serverTimestamp const date = new Date() const localTime = this.serverTimestamp - date.getTimezoneOffset() * 60 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(timestampToArray(nowTime), 62) contentArray.set(timestampToArray(localTime), 66) const cebArray = sm4.encrypt(contentArray, this.lockInfo.bluetooth.privateKey, { mode: 'ecb', output: 'array' }) const packageArray = createPackageEnd(headArray, cebArray) const writeResult = await writeBLECharacteristicValue( this.lockInfo.deviceId, this.lockInfo.serviceId, this.lockInfo.writeCharacteristicId, packageArray ) if (writeResult.code !== Result.Success.code) { return writeResult } return this.getWriteResult(this.getLockStatus, { disconnect: false }) } // 获取联网token export async function getNetToken() { const { code, data, message } = await getLockNetTokenRequest({ lockId: this.lockInfo.lockId }) return new Result(code, data, message) } // 添加用户 export async function addLockUser(params) { const { params: data } = params // 确认设备连接正常 if (!params.connected) { const searchResult = await searchAndConnectDevice( this.lockInfo.bluetooth.bluetoothDeviceName, data.role !== 0xff ) if (searchResult.code !== Result.Success.code) { return searchResult } this.updateLockInfo(searchResult.data) } 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(timestampToArray(startDate), 124) contentArray.set(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.lockInfo.token || timestampToArray(startDate), 161) contentArray[165] = 16 const md5Array = md5Encrypt( authUid + keyId, this.lockInfo.token || timestampToArray(startDate), this.lockInfo.bluetooth.publicKey ) contentArray.set(md5Array, 166) const cebArray = sm4.encrypt(contentArray, this.lockInfo.bluetooth.privateKey, { mode: 'ecb', output: 'array' }) const packageArray = createPackageEnd(headArray, cebArray) const writeResult = await writeBLECharacteristicValue( this.lockInfo.deviceId, this.lockInfo.serviceId, this.lockInfo.writeCharacteristicId, packageArray ) if (writeResult.code !== Result.Success.code) { return writeResult } return this.getWriteResult(this.addLockUser, params) } // 获取写入结果 export function getWriteResult(request, params) { return new Promise(resolve => { const getWriteResultTimer = setTimeout(() => { resolve(Result.Fail) }, 20000) this.characteristicValueCallback = async data => { // code 6 token过期,重新获取 if (data.code === Result.NotTokenLock.code) { log.info({ ...new Result( data.code, { lockName: this.lockInfo.bluetooth.bluetoothDeviceName, lockId: this.lockInfo.lockId, time: new Date().getTime() }, `token过期:${data.message}` ), name: 'openDoor' }) resolve(await request.call(this, { ...params, connected: true })) } else if (data.code === Result.NotRegisteredLock.code) { const checkResult = await this.checkLockUser(true) if (checkResult.code === Result.Success.code) { resolve(await request.call(this, { ...params, connected: true })) } else { clearTimeout(getWriteResultTimer) resolve(checkResult) } } else { clearTimeout(getWriteResultTimer) if (params.disconnect !== false) { await this.disconnectDevice() } console.log('写入结果', data, request, params) log.info({ ...new Result( data.code, { lockName: this.lockInfo.bluetooth.bluetoothDeviceName, lockId: this.lockInfo.lockId, time: new Date().getTime() }, `开门结果:${data.message}` ), name: 'openDoor' }) resolve(data) } } }) } // 检查是否已添加为用户 export async function checkLockUser(forceAdd = false) { if (this.lockInfo.lockUserNo === 0 || forceAdd) { const timestamp = Math.floor(new Date().getTime() / 1000) const password = (Math.floor(Math.random() * 900000) + 100000).toString() console.log('用户未添加,开始添加用户') const addUserParams = { name: this.lockInfo.bluetooth.bluetoothDeviceName, keyId: this.lockInfo.keyId.toString(), authUid: this.lockInfo.uid.toString(), uid: this.accountInfo.uid.toString(), openMode: 1, keyType: 0, startDate: this.lockInfo.startDate === 0 ? timestamp : Math.floor(this.lockInfo.startDate / 1000), expireDate: this.lockInfo.endDate === 0 ? 0xffffffff : Math.floor(this.lockInfo.endDate / 1000), useCountLimit: this.lockInfo.keyType === 3 ? 1 : 0xffff, isRound: this.lockInfo.keyType === 4 ? 1 : 0, weekRound: this.lockInfo.keyType === 4 ? convertWeekdaysToNumber(this.lockInfo.weekDays) : 0, startHour: this.lockInfo.keyType === 4 ? new Date(this.lockInfo.startDate).getHours() : 0, startMin: this.lockInfo.keyType === 4 ? new Date(this.lockInfo.startDate).getMinutes() : 0, endHour: this.lockInfo.keyType === 4 ? new Date(this.lockInfo.endDate).getHours() : 0, endMin: this.lockInfo.keyType === 4 ? new Date(this.lockInfo.endDate).getMinutes() : 0, role: 0, password } const addUserResult = await this.addLockUser({ params: addUserParams, disconnect: false }) console.log('添加用户蓝牙结果', addUserResult) if (addUserResult.code === Result.Success.code) { const { code } = await updateLockUserNoRequest({ keyId: this.lockInfo.keyId, lockUserNo: this.lockInfo.lockUserNo }) console.log('添加用户请求结果', code) return Result.Success } if (addUserResult.code === Result.NotMoreKeyLock.code) { console.log('用户达上限,开始清理用户') const { code: cleanCode } = await this.cleanLockUser() console.log('清理用户蓝牙结果', cleanCode) if (cleanCode === Result.Success.code) { return await this.checkLockUser() } return Result.Fail } if (addUserResult.code === Result.ReadyHasKeyLock.code) { return Result.Success } return Result.Fail } return Result.Success } // 更新锁信息 export function updateLockInfo(lockInfo) { this.lockInfo = { ...this.lockInfo, ...lockInfo } const lockList = getStorage('starLockList') if (lockList[this.accountInfo.uid]) { const index = lockList[this.accountInfo.uid].findIndex( item => item.lockId === this.lockInfo.lockId ) if (index !== -1) { lockList[this.accountInfo.uid][index] = this.lockInfo } setStorage('starLockList', lockList) } } // 特征值变化回调 export function listenCharacteristicValue(res) { if (res.deviceId === this.lockInfo.deviceId) { let binaryData = new Uint8Array(res.value) if ( binaryData[0] === 0xef && binaryData[1] === 0x01 && binaryData[2] === 0xee && binaryData[3] === 0x02 ) { this.length = binaryData[8] * 256 + binaryData[9] if (this.length + 14 > binaryData.length) { this.completeArray = binaryData } else { this.parsingCharacteristicValue(binaryData).then(() => {}) } } else if (this.completeArray) { const combinedArray = new Uint8Array(this.completeArray.length + binaryData.length) combinedArray.set(this.completeArray, 0) combinedArray.set(binaryData, this.completeArray.length) this.completeArray = combinedArray if (this.length + 14 === this.completeArray.length) { this.parsingCharacteristicValue(this.completeArray).then(() => {}) this.completeArray = null } } } } // 解析特征值 export async function parsingCharacteristicValue(binaryData) { // 0x20 明文 0x22 SM4(事先约定密钥) 0x23 SM4(设备指定密钥) if (binaryData[7] === 0x20) { if (binaryData[12] * 256 + binaryData[13] === cmdIds.getPublicKey) { if (binaryData[14] === Result.Success.code) { this.updateLockInfo({ bluetooth: { ...this.lockInfo.bluetooth, publicKey: [...binaryData.slice(15, 31)] } }) } this.characteristicValueCallback(new Result(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 < this.lockInfo.bluetooth.bluetoothDeviceName.length; i++) { key[i] = this.lockInfo.bluetooth.bluetoothDeviceName.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] === Result.Success.code) { this.updateLockInfo({ bluetooth: { ...this.lockInfo.bluetooth, privateKey: decrypted.slice(3, 19), signKey: decrypted.slice(19, 35) }, pwdTimestamp: arrayToTimestamp(decrypted.slice(35, 39)) * 1000 }) console.log('privateKey', Array.from(this.lockInfo.bluetooth.privateKey)) console.log('signKey', Array.from(this.lockInfo.bluetooth.signKey)) } this.characteristicValueCallback(new Result(decrypted[2])) } } else { const cebBinaryData = binaryData.slice(12, binaryData.length - 2) const decrypted = sm4.decrypt(cebBinaryData, this.lockInfo.bluetooth.privateKey, { mode: 'ecb', output: 'array' }) console.log('ecb解密后的数据', decrypted) const cmdId = decrypted[0] * 256 + decrypted[1] switch (cmdId) { case cmdIds.getLockStatus: if (decrypted[2] === Result.Success.code) { const lockConfig = { vendor: uint8ArrayToString(decrypted.slice(3, 23)), product: decrypted[23], model: uint8ArrayToString(decrypted.slice(24, 44)), fwVersion: uint8ArrayToString(decrypted.slice(44, 64)), hwVersion: uint8ArrayToString(decrypted.slice(64, 84)), serialNum0: uint8ArrayToString(decrypted.slice(84, 100)), serialNum1: uint8ArrayToString(decrypted.slice(100, 116)), btDeviceName: uint8ArrayToString(decrypted.slice(116, 132)), electricQuantity: decrypted[132], electricQuantityStandby: decrypted[133], restoreCount: decrypted[134] * 256 + decrypted[135], restoreDate: arrayToTimestamp(decrypted.slice(136, 140)), icPartNo: uint8ArrayToString(decrypted.slice(140, 150)), indate: arrayToTimestamp(decrypted.slice(150, 154)), mac: uint8ArrayToString(decrypted.slice(154, 174)), timezoneOffset: new Date().getTimezoneOffset() * 60 } this.updateLockInfo({ featureValue: uint8ArrayToString(decrypted.slice(175, 175 + decrypted[174])), featureSettingValue: 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 }) console.log('获取锁状态成功', this.lockInfo.lockConfig) } this.characteristicValueCallback(new Result(decrypted[2])) break case cmdIds.addUser: this.updateLockInfo({ token: decrypted.slice(42, 46) }) if (decrypted[46] === Result.Success.code) { this.updateLockInfo({ lockUserNo: decrypted[47] * 256 + decrypted[48] }) } console.log('添加用户结果', decrypted[46], this.lockInfo.lockUserNo) this.characteristicValueCallback(new Result(decrypted[46])) break case cmdIds.expandCmd: const subCmdId = decrypted[3] switch (subCmdId) { case subCmdIds.updateAdminPassword: this.updateLockInfo({ token: decrypted.slice(5, 9) }) if (decrypted[2] === Result.Success.code) { const result = await changeAdminKeyboardPwdRequest({ password: this.requestParams.adminPwd, lockId: this.lockInfo.lockId }) return this.characteristicValueCallback(new Result(result.code)) } this.characteristicValueCallback(new Result(decrypted[2])) break case subCmdIds.resetLockPassword: this.updateLockInfo({ token: decrypted.slice(5, 9) }) this.characteristicValueCallback(new Result(decrypted[4])) break case subCmdIds.setLockPassword: this.updateLockInfo({ token: decrypted.slice(5, 9) }) if (decrypted[2] === Result.Success.code) { if (decrypted[11] === Result.Success.code) { const pwdNo = decrypted[9] * 256 + decrypted[10] if (this.requestParams.operate === 0) { const addResult = await addCustomPasswordRequest({ ...this.requestParams, pwdUserNo: pwdNo, lockId: this.lockInfo.lockId }) if (addResult.code === Result.Success.code) { this.characteristicValueCallback( new Result(addResult.code, { pwdNo, keyboardPwdId: addResult.data.keyboardPwdId, keyboardPwd: addResult.data.keyboardPwd, keyboardPwdStatus: addResult.data.keyboardPwdStatus, pwdUserNo: pwdNo }) ) } else { this.characteristicValueCallback( new Result(addResult.code, addResult.data, addResult.message) ) } } else if (this.requestParams.operate === 1) { const updateResult = await updatePasswordRequest(this.requestParams) if (updateResult.code === Result.Success.code) { this.characteristicValueCallback(new Result(updateResult.code)) } else { this.characteristicValueCallback( new Result(updateResult.code, updateResult.data, updateResult.message) ) } } else if (this.requestParams.operate === 3) { const deleteResult = await deletePasswordRequest(this.requestParams) if (deleteResult.code === Result.Success.code) { this.characteristicValueCallback(new Result(deleteResult.code)) } else { this.characteristicValueCallback( new Result(deleteResult.code, deleteResult.data, deleteResult.message) ) } } } else { this.characteristicValueCallback(new Result(decrypted[11])) } } else { this.characteristicValueCallback(new Result(decrypted[2])) } break case subCmdIds.syncOpenRecord: if (decrypted[2] === Result.Success.code && 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 = uint8ArrayToString(password) } const record = { type: decrypted[7 + 17 * i], user: decrypted[8 + 17 * i] * 256 + decrypted[9 + 17 * i], date: arrayToTimestamp(decrypted.slice(10 + 17 * i, 14 + 17 * i)) * 1000, success: 1, password } records.push(record) } const { code, message } = await uploadRecordRequest({ records, lockId: this.lockInfo.lockId }) this.characteristicValueCallback( new Result( code, { count }, message ) ) } else { this.characteristicValueCallback(new Result(decrypted[2])) } break default: break } break case cmdIds.openDoor: this.updateLockInfo({ token: decrypted.slice(2, 6), electricQuantity: decrypted[7], electricQuantityStandby: decrypted[9] }) if (decrypted[6] === Result.Success.code) { updateElectricQuantityRequest({ lockId: this.lockInfo.lockId, electricQuantity: decrypted[7], electricQuantityStandby: decrypted[9] }).then(() => {}) } this.characteristicValueCallback(new Result(decrypted[6], { lock: this.lockInfo })) break case cmdIds.resetDevice: this.updateLockInfo({ token: decrypted.slice(2, 6) }) if (decrypted[6] === Result.Success.code) { const { code, message } = await deleteLockRequest({ lockId: this.lockInfo.lockId }) if (code === Result.Success.code) { const lockList = getStorage('starLockList') if (lockList[this.accountInfo.uid]) { const index = lockList[this.accountInfo.uid].findIndex( item => item.lockId === this.lockInfo.lockId ) if (index !== -1) { lockList[this.accountInfo.uid].splice(index, 1) } setStorage('starLockList', lockList) } } this.characteristicValueCallback(new Result(code, {}, message)) } else { this.characteristicValueCallback(new Result(decrypted[6])) } break default: this.updateLockInfo({ token: decrypted.slice(2, 6) }) console.log('默认结果', decrypted[6], this.lockInfo.token) this.characteristicValueCallback(new Result(decrypted[6])) break } } } // 获取配置 export function getConfig() { let config = {} if (this.env === "LOCAL"){ config = { name: 'LOCAL', baseUrl: this.url } }else{ config = configs[this.env] } return { ...config, version, buildNumber } } /* * 生成包头 * encryptionType 加密类型 0:明文,1:AES128,2:SM4(事先约定密钥),3:SM4(设备指定密钥) * originalLength 原始数据长度 * */ export function 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 } // 数据长度 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 } // 断开与设备的连接 export async function disconnectDevice() { return await closeBLEConnection(this.lockInfo.deviceId) }