import {sm4} from 'sm-crypto' import {cmdIds, Result} from '../constant' import {searchAndConnectDevice, writeBLECharacteristicValue} from '../uni/basic' import {createPackageEnd, md5Encrypt, timestampToArray, checkRequiredFields} from '../format' import {getLockDetailRequest, getLockSettingDataRequest, getUserLockListRequest, remoteUnLockRequest} from '../api' import {getStorage, setStorage} from '../export' import log from '../log' /** * 选择锁 * @param params * @param {Number} [params.uid] 用户ID * @param {Number} params.lockId 锁ID * @returns {Promise} */ export async function selectLock(params) { const {lockId} = params const result = await this.login(params.uid) if (result.code !== Result.Success.code) { return result } const {code, data, message} = await getLockDetailRequest({ lockId }) if (code === Result.Success.code) { this.lockInfo = data let lockList = getStorage('starLockList') if (!lockList) { lockList = {} } if (lockList[this.accountInfo.uid]) { const index = lockList[this.accountInfo.uid].findIndex(item => item.lockId === lockId) if (index === -1) { lockList[this.accountInfo.uid].push(this.lockInfo) } else { this.lockInfo.token = lockList[this.accountInfo.uid][index].token lockList[this.accountInfo.uid][index] = this.lockInfo } setStorage('starLockList', lockList) } else { lockList[this.accountInfo.uid] = [this.lockInfo] setStorage('starLockList', lockList) } } else if (code === Result.Fail.code) { const lockList = getStorage('starLockList') if (lockList[this.accountInfo.uid]) { const index = lockList[this.accountInfo.uid].findIndex(item => item.lockId === lockId) if (index !== -1) { this.lockInfo = lockList[this.accountInfo.uid][index] return new Result(Result.Success.code, this.lockInfo) } } } return new Result(code, data, message) } /** * 开门 * @param params * @param {Number} [params.uid] 用户ID * @param {String} params.type 开门方式 close: 关门 open: 开门 * @param {Boolean} [params.disconnect] 操作后是否断开连接,默认断开 * @returns {Promise} */ export async function openDoor(params) { const {type} = params // ⏱️ 记录开始时间 const startTime = Date.now(); log.info({ ...new Result( Result.Success.code, { lockName: this.lockInfo.bluetooth.bluetoothDeviceName, lockId: this.lockInfo.lockId, uid: params.uid, time: new Date().getTime() }, `开始开门` ), name: 'openDoor' }) // 设置执行账号 const result = await this.login(params.uid) if (result.code !== Result.Success.code) { return result } log.info({ ...new Result( result.code, { lockName: this.lockInfo.bluetooth.bluetoothDeviceName, lockId: this.lockInfo.lockId, uid: this.accountInfo.uid, time: new Date().getTime() }, `登录星云账号: ${result.message}` ), name: 'openDoor' }) // 确认设备连接正常 if (!params.connected) { const searchResult = await searchAndConnectDevice(this.lockInfo.bluetooth.bluetoothDeviceName, true, this.lockInfo.bluetooth.bluetoothDeviceId) log.info({ ...new Result( searchResult.code, { lockName: this.lockInfo.bluetooth.bluetoothDeviceName, lockId: this.lockInfo.lockId, uid: this.accountInfo.uid, time: new Date().getTime() }, `连接设备: ${searchResult.message}` ), name: 'openDoor' }) 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 } log.info({ ...new Result( checkResult.code, { lockName: this.lockInfo.bluetooth.bluetoothDeviceName, lockId: this.lockInfo.lockId, uid: this.accountInfo.uid, time: new Date().getTime() }, `确认是否为锁用户: ${checkResult.message}` ), name: 'openDoor' }) // 是否需要联网 let onlineToken = '' if (this.lockInfo.lockSetting.appUnlockOnline) { const result = await this.getNetToken() if (result.code === Result.Success.code) { onlineToken = result.data.token } else { return result } } log.info({ ...new Result( checkResult.code, { lockName: this.lockInfo.bluetooth.bluetoothDeviceName, lockId: this.lockInfo.lockId, uid: this.accountInfo.uid, time: new Date().getTime() }, `判断是否需要联网token: ${this.lockInfo.lockSetting.appUnlockOnline}` ), name: 'openDoor' }) // 开门方式 let openMode if (type === 'close') { openMode = this.lockInfo.lockSetting.appUnlockOnline ? 33 : 32 } else { openMode = this.lockInfo.lockSetting.appUnlockOnline ? 1 : 0 } const name = this.lockInfo.bluetooth.bluetoothDeviceName const uid = this.accountInfo.uid.toString() if (this.timeDifference === null || this.timeDifference === undefined) { this.timeDifference = 0; } const openTime = Math.ceil(new Date().getTime() / 1000) + this.timeDifference 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(timestampToArray(openTime), 63) console.log('开门时token', this.lockInfo.token) console.log('开门时同步的时间', Array.from(timestampToArray(openTime)), openTime) contentArray.set(this.lockInfo.token || timestampToArray(openTime), 67) contentArray[71] = 16 const md5Array = md5Encrypt( name + uid, this.lockInfo.token || timestampToArray(openTime), this.lockInfo.bluetooth.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.lockInfo.bluetooth.privateKey, { mode: 'ecb', output: 'array' }) const packageArray = createPackageEnd(headArray, cebArray) log.info({ ...new Result( Result.Success.code, { lockName: this.lockInfo.bluetooth.bluetoothDeviceName, lockId: this.lockInfo.lockId, uid: this.accountInfo.uid, time: new Date().getTime() }, `开始写入` ), name: 'openDoor' }) const writeResult = await writeBLECharacteristicValue( this.lockInfo.deviceId, this.lockInfo.serviceId, this.lockInfo.writeCharacteristicId, packageArray ) if (writeResult.code !== Result.Success.code) { return writeResult } log.info({ ...new Result( writeResult.code, { lockName: this.lockInfo.bluetooth.bluetoothDeviceName, lockId: this.lockInfo.lockId, uid: this.accountInfo.uid, time: new Date().getTime() }, `写入完成:${writeResult.message}` ), name: 'openDoor' }) // 获取最终结果 const finalResult = this.getWriteResult(this.openDoor, params); // ⏱️ 计算耗时 const endTime = Date.now(); const duration = endTime - startTime; console.log(`开门耗时:${duration}`) return finalResult; } /** * 删除锁 * @param params * @param {Number} [params.uid] 用户ID */ export async function deleteLock(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 { token, bluetooth: {publicKey, privateKey} } = this.lockInfo const authUid = this.lockInfo.uid.toString() const name = this.lockInfo.bluetooth.bluetoothDeviceName 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(token || new Uint8Array([0, 0, 0, 0]), 62) contentArray[66] = 16 const md5Array = md5Encrypt(name, token || new Uint8Array([0, 0, 0, 0]), publicKey) contentArray.set(md5Array, 67) const cebArray = sm4.encrypt(contentArray, 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.deleteLock, params) } /** * 获取锁支持项 * @param params * @param {Number} [params.uid] 用户ID * @param {Number} params.lockId 锁 Id * @returns {Promise} */ export async function getLockSupportFeatures(params) { const {lockId} = params // 设置执行账号 const result = await this.login(params.uid) if (result.code !== Result.Success.code) { return result } const {code, data, message} = await getLockSettingDataRequest({ lockId }) if (code === Result.Success.code) { return new Result(code, {...data.lockFeature}, message) } return new Result(code, data, message) } /** * 远程开锁 * @param params * @param {Number} params.uid uid * @param {Number} params.lockId 锁 Id * @returns {Promise} */ export async function remoteUnLock(params) { const cardRequiredFields = ['uid', 'lockId']; const missingField = checkRequiredFields(params, cardRequiredFields); if (missingField) { return new Result(Result.codes.NotMoreData, null, `参数信息不完整: ${missingField}`); } // 设置执行账号 const result = await this.login(params.uid) if (result.code !== Result.Success.code) { return result } return await remoteUnLockRequest({ lockId: params.lockId, }) } /** * 获取名下锁列表 * @param params * @returns {Promise<*>} */ export async function getLockList(params) { // 设置执行账号 const result = await this.login(params.uid) if (result.code !== Result.Success.code) { return result } return await getUserLockListRequest(params); }